Piloter les workers
Un script peut allumer et éteindre les automatismes du robot, et demander lequel tourne. C'est la seule famille qui agit sur le robot lui-même et non sur le jeu.
Ce que ces fonctions font vraiment
Elles reproduisent le clic de l'interface, pas un démarrage en mémoire. Le réglage est enregistré, il survit à un redémarrage du bot, et la règle d'exclusivité des outils s'applique comme si vous aviez coché la case vous-même.
C'est une différence qui compte. Un basculement qui ne vivrait qu'en mémoire serait défait au prochain lancement, sans que rien ne le signale : votre script aurait allumé le pillage, et vous retrouveriez le compte inerte le lendemain sans comprendre pourquoi.
Les Start… et les Stop… rendent une erreur, nil quand le geste a eu lieu. Les IsRunning… rendent un booléen.
L'erreur est un ajout de Kepler : l'outil de référence ne rend rien. Un script recopié appelle ces fonctions comme des instructions et ne lit aucun retour, donc rien ne casse ; un script écrit pour Kepler, lui, peut vérifier.
Pour les lectures, false veut dire « je n'ai pas pu lire » autant que « le worker est éteint ». La panne part au journal, jamais en silence.
Allumer et éteindre
| Fonction | Rend | |
|---|---|---|
StartBrain() / StopBrain() | 1 : une erreur | Le Brain. Files de construction et recherches. |
StartScanner() / StopScanner() | 1 : une erreur | Le scanner. Balayage des systèmes. |
StartHunter() / StopHunter() | 1 : une erreur | Le chasseur. Traque des cibles. |
StartSleepMode() / StopSleepMode() | 1 : une erreur | La veille. Voir l'avertissement plus bas. |
StartFarmingBot() / StopFarmingBot() | 1 : une erreur | Le pillage. StartFarmingBot() donne une campagne au Pillage s'il n'en a pas. |
StartFarmSession(campagne) | 1 : une erreur | Lance une campagne désignée, comme le ▶ de sa ligne. |
StartExpeditionsBot() / StopExpeditionsBot() | 1 : une erreur | Les expéditions. |
StartColonizerBot() / StopColonizerBot() | 1 : une erreur | Le colonisateur. |
StartDiscoveryBot() / StopDiscoveryBot() | 1 : une erreur | Le découvreur. |
StartDefenderBot() / StopDefenderBot() | 1 : une erreur | La défense. |
err = StopFarmingBot()
if err != nil { LogError("pillage :", err) }
StartExpeditionsBot()
StartBrain()
StopBrain()
StartScanner()
StopScanner()
StartHunter()
StopHunter()
StartColonizerBot()
StopColonizerBot()
StartDiscoveryBot()
StopDiscoveryBot()
StartDefenderBot()
StopDefenderBot()
StopExpeditionsBot()
Un worker peut refuser de s'allumer, et il dit pourquoi
Testez l'erreur. Elle ne dit pas seulement « ça n'a pas marché » : elle dit ce qui manque, et c'est le plus souvent un réglage.
err = StartWorker("timer")
if err != nil {
LogWarn("le minuteur ne démarre pas :", err)
// mettez un webhook Discord ou cochez Telegram, ici ou dans les
// réglages du robot : sans canal, la surveillance ne préviendrait
// personne
}
Relevé en jouant ce script sur un vrai compte : le minuteur exige un canal d'alerte, le Colonisateur un point de départ, et ainsi de suite. Un script qui ignorerait ce retour croirait avoir allumé un worker qui n'a jamais démarré.
Un nom de worker inconnu est refusé aussi, en le nommant : unknown worker "cephalopode".
Demander lequel tourne
| Fonction | Rend | |
|---|---|---|
IsRunningBrainBot() | 1 : un booléen | Vrai si le Brain est allumé. |
IsRunningFarmingBot() | 1 : un booléen | Vrai si le pillage est allumé. |
IsRunningExpeditionsBot() | 1 : un booléen | |
IsRunningColonizerBot() | 1 : un booléen | |
IsRunningDiscoveryBot() | 1 : un booléen | |
IsRunningDefenderBot() | 1 : un booléen |
if IsRunningFarmingBot() {
Print("le pillage tourne")
}
Print(IsRunningBrainBot(), IsRunningExpeditionsBot(), IsRunningColonizerBot())
Print(IsRunningDiscoveryBot(), IsRunningDefenderBot())
Il n'existe pas de IsRunning pour le scanner, le chasseur ni la veille : l'outil de référence n'en donne pas, et on n'invente pas de nom qu'aucun script recopié n'appellera. La forme générale ci-dessous les couvre.
La forme générale
Kepler a des workers que l'outil de référence n'a pas : le rapatriement, l'espionnage, la phalange, la surveillance des champs de ruines, le minuteur. Trois fonctions prennent le nom du worker et les couvrent tous.
| Fonction | Rend | |
|---|---|---|
StartWorker(nom) | 1 : une erreur | Allume le worker nommé. |
StopWorker(nom) | 1 : une erreur | L'éteint. |
IsWorkerRunning(nom) | 1 : un booléen | Dit s'il est allumé. |
ListWorkers() | 1 : une liste | Les noms acceptés, en anglais. |
L'arrêt d'urgence
Un seul appel fait taire le robot : la session se ferme, les workers sont suspendus, les autres scripts du compte sont mis en pause, et tout appel de jeu échoue tant que la pause dure.
C'est le filet du script oublié. Une boucle restée active qui interroge le serveur ne fait plus une seule requête : ses appels échouent sur « compte non connecté », donc des erreurs dans votre console au lieu d'un bannissement.
| Fonction | Rend | Ce qu'elle fait |
|---|---|---|
PauseBot() | 1 : une erreur | Coupe toute communication avec le jeu. |
ResumeBot() | 1 : une erreur | La rend. |
IsBotPaused() | 1 : un booléen | Dit où l'on en est. |
LogOut() | 1 : une erreur | Alias de PauseBot, pour les scripts venus de Ninja. |
Login() | 1 : une erreur | Alias de ResumeBot. |
Le script qui appelle PauseBot n'est jamais mis en pause lui-même, sinon il ne pourrait plus jamais appeler ResumeBot et le compte resterait muet.
Un compte en pause n'est plus défendu. Le Defender ne surveille plus, comme pendant une veille. C'est une mise à l'abri de votre compte contre vos propres scripts, pas contre un attaquant.
Si le script se termine sans lever la pause, le bouton « Réveiller » de la carte du compte la lève aussi. Vous n'êtes jamais bloqué.
if MesRaisons() {
PauseBot()
SleepMin(30)
ResumeBot()
}
for nom in ListWorkers() {
Print(nom, IsWorkerRunning(nom))
}
err = StartWorker("repatriate")
if err != nil { LogError("rapatriement :", err) }
StopWorker("spyer")
Les noms sont en minuscules et sans accent : brain, defender, expeditions, sleep, scanner, farmer, colonizer, repatriate, supply, hunter, discovery, spyer, phalanx, militarydebris, colonywatch, timer, scheduledflights. Un nom inconnu rend une erreur qui le nomme, plutôt que de ne rien faire.
supply est l'alimentation des planètes du Brain depuis des banques. Elle se règle dans l'onglet Ravitaillement de la page Construction, et s'arrête sans arrêter les constructions : le Brain continue, il attend simplement sa production.
L'inverse ne vaut pas : la Construction éteinte met supply en pause. Rien n'est livré tant qu'elle reste éteinte, et les livraisons reprennent seules au rallumage, sur des besoins recalculés. IsWorkerRunning("supply") rend toujours l'interrupteur : il peut répondre vrai pendant cette pause, et une plage du Planning qui allume supply Construction éteinte ne fait rien partir.
Le rapatriement épargne une planète qui attend une livraison. Il ne le fait plus quand la Construction est éteinte ou supply arrêté : aucune livraison ne viendra, et la planète ne doit pas rester à découvert.
colonywatch n'est pas le colonisateur. colonizer fonde des planètes ; colonywatch surveille l'apparition de colonies autour des joueurs suivis.
Composer une campagne de pillage
| Fonction | Rend | |
|---|---|---|
NewFarmSession() | 1 : un constructeur | À enchaîner, puis BuildFarmSession(). |
Le constructeur se règle méthode par méthode, puis BuildFarmSession() enregistre la campagne et la rend active, comme le bouton « Lancer » de l'interface. Il rend deux valeurs : la campagne créée et une erreur.
Il n'allume pas le Pillage pour autant : c'est StartFarmingBot() qui le fait. Séparer les deux laisse préparer une campagne sans la faire partir tout de suite.
Ce que StartFarmingBot() choisit de mener
Il n'allume pas seulement l'interrupteur : il donne une campagne au Pillage quand celui-ci n'en a aucune, dans cet ordre.
1. Une campagne active : il se contente de l'allumer. C'est le cas du script qui vient de la créer. 2. Une campagne en pause : il la reprend où elle s'est arrêtée. N'importe quelle autre repartirait du premier système. 3. Ce qui attend en file, dans l'ordre où les campagnes y sont entrées. 4. Sinon, la première campagne enregistrée, dans son ordre de création. 5. Aucune campagne du tout : il rend une erreur et ne fait rien. Un Pillage allumé sans rien à mener est exactement ce qu'on veut éviter.
StartFarmSession(campagne) sert quand ce choix ne suffit pas : il lance celle qu'on lui nomme, comme le ▶ de sa ligne dans l'onglet Pillage.
campagne, err = f.BuildFarmSession()
StartFarmSession(campagne.ID)
origine = GetCachedCelestials()[0]
f = NewFarmSession()
f.SetName("tour de garde")
f.SetOrigin(origine)
f.SetRangeAroundOrigin(30)
f.SetMinimumResourcesToAttack(300000)
f.SetAdditionalCargo(10)
f.SetAttackDelay(2, 5)
f.SetPriorityRatio(1, 1.5, 2)
f.SetUsePathfinders(false)
f.SetIgnoreActivity(true)
f.SetFastAttacking(true)
campagne, err = f.BuildFarmSession()
if err != nil { LogError("campagne :", err) }
Print("campagne", campagne.ID, "portée", campagne.Range)
StartFarmingBot()
Les réglages qui portent
SetOrigin, SetOriginCoord, SetRange, SetGalaxyRange, SetRangeAroundOrigin, SetName, SetMinimumResourcesToAttack, SetAdditionalCargo, SetMinimumPlayerRank, SetUsePathfinders, SetIgnoreActivity, SetFastAttacking, SetSmallCargosFirst, SetPriorityRatio, SetAttackDelay.
Trois méritent un mot.
SetRange(galaxie, systèmeDe, systèmeÀ) garde vos bornes, comprises, et la galaxie que vous demandez. Elle a longtemps approximé - la demi-largeur de l'intervalle devenait une portée autour de l'origine - puis elle a gardé les systèmes mais refusé toute galaxie autre que celle de l'origine, faute de savoir balayer ailleurs. La campagne sait désormais traverser les galaxies, et ce refus a disparu.
Une galaxie nulle veut dire « toutes ». Sur un univers circulaire, une plage qui commence après sa fin passe par le bord : SetRange(1, 480, 20) traite 480 à 499 puis 1 à 20.
SetGalaxyRange(de, à) est un extra de Kepler, sans équivalent chez l'outil de référence, qui ne borne qu'une galaxie à la fois. SetGalaxyRange(1, 4) avec SetRange(0, 200, 350) balaie les systèmes 200 à 350 des galaxies 1 à 4. Zéro veut dire « toutes » des deux côtés - et sans bornes de systèmes, ce sont des galaxies ENTIÈRES : quatre d'entre elles font près de deux mille systèmes, et une campagne y passe des jours.
SetRangeAroundOrigin(portée) reste là pour qui préfère un rayon. Elle ramène la campagne en mode automatique et efface les quatre bornes : le dernier appel gagne, dans les deux sens.
SetOriginCoord(galaxie, système, position, type) ne demande pas la session. SetOrigin doit résoudre un céleste, donc attendre la connexion ; celle-ci nomme la coordonnée directement. Le type est "planet" ou "moon", tout autre mot est refusé plutôt que deviné.
SetMinimumPlayerRank ne veut pas dire ce qu'on croit. Le rang 1 est le meilleur joueur : « jusqu'à 5000 » garde donc les cinq mille premiers et écarte les autres. Zéro les prend tous.
SetFastAttacking ne veut pas dire la même chose que chez Ninja. Là-bas, la case « Fast attacking » fait partir les raids dès que les rapports d'espionnage arrivent, pendant que l'espionnage continue. Chez Kepler, SetFastAttacking(true) choisit la stratégie « Ne jamais attendre (dangereux) » : chaque slot repart dès qu'il se libère, au lieu d'attendre le retour de toute la vague. Un script venu de Ninja qui l'appelle change donc de stratégie, pas de façon d'espionner. Le comportement de Ninja existe dans Kepler sous le nom « Raids dès les premiers rapports » : une case de la fenêtre de campagne, décochée par défaut, qu'aucune fonction de script ne pose encore.
Les réglages venus de Ninja
SetProbes, SetFarmSpeed, SetMinimumDefensesToIgnore, SetAttackPlayersWithDefenses, SetMinimumStorageToIgnore, SetEspionageProbeRaids, SetDeleteCombatReports.
Ils ont tous leur contrôle dans l'écran de campagne depuis le 18/09/2026. Ces fonctions restent le chemin des scripts vers les mêmes champs : un script et un clic posent la même chose, et la fenêtre reporte ce qu'elle n'affiche pas plutôt que de l'effacer.
Chacun vaut par défaut ce que le bot faisait avant qu'il existe : une campagne réglée à la main ne change pas.
SetProbes(n) fixe les sondes par espionnage, à l'aller comme au réespionnage. Sans elle, le nombre réglé dans le compte OGame.
SetFarmSpeed(allure) règle la vitesse des raids, avec les constantes de pourcentage : SetFarmSpeed(FIFTY_PERCENT). Sans elle, la vitesse pleine. Une valeur hors des bornes est refusée plutôt que ramenée en silence.
SetMinimumDefensesToIgnore(n) accepte une cible dont la défense vue est strictement inférieure à n. Le nom vient de Ninja et se lit dans l'autre sens : c'est la défense à partir de laquelle on ignore la cible. Avec 1, on retrouve donc la règle par défaut de Kepler, qui n'accepte aucune défense.
SetAttackPlayersWithDefenses(false) referme ce seuil, quel que soit l'ordre des appels. À vrai, elle ne fait rien : c'est le seuil qui décide.
SetDeleteCombatReports(true) met à la corbeille le rapport de combat de chaque raid, une fois son butin compté.
La messagerie du jeu se bloque entièrement quand trop de messages s'accumulent, boîte et corbeille cumulées, et plus rien n'y est possible. Une campagne en fabrique un par raid : sans ce réglage, un pillage qui tourne des nuits finit par bloquer la messagerie de son propre joueur.
Quatre conditions avant d'effacer, et aucune n'est décorative : le rapport doit porter l'identifiant de la flotte que nous avons envoyée, cet identifiant ne doit pas être nul, le rapport doit avoir un numéro, et sa cible doit être celle que nous visions. Un rapport d'attaque subie est donc hors d'atteinte.
Le geste du jeu déplace vers la corbeille et ne détruit pas ; Kepler fait donc les deux, l'effacement puis la purge de la corbeille de l'onglet. Effacer sans purger ne ferait que remplir l'autre moitié du compteur qui bloque la messagerie.
SetMinimumStorageToIgnore(métal, cristal, deut) écarte les cibles dont les hangars sont trop petits : en dessous de ces niveaux, la position n'est pas attaquée. Le nom vient de Ninja et se lit dans ce sens - le minimum en dessous duquel on ignore. SetMinimumStorageToIgnore(4, 0, 0) demande un hangar de métal de niveau 4 au moins et ne dit rien des deux autres. Zéro ne demande rien.
Une planète aux petits hangars ne peut rien accumuler : on la vide une fois, et y revenir ne rapporte plus.
Ce réglage coûte des requêtes. Les niveaux de hangar ne sont pas dans la liste des messages, seulement dans le détail de chaque rapport : les demander, c'est une requête par cible retenue là où la campagne n'en fait qu'une pour toutes. Rien n'est lu tant que les trois valeurs sont nulles, et seules les cibles qui ont passé tous les autres filtres sont ouvertes.
Une cible qu'on n'a pas vue est écartée. Un rapport pris avec trop peu de sondes ne montre pas les bâtiments : il ne dit pas que les hangars sont petits, il dit qu'on n'a pas assez regardé. Même règle que pour la défense.
SetEspionageProbeRaids(true) fait porter le butin par les sondes d'espionnage plutôt que par les transporteurs.
Elles sont le vaisseau le plus rapide du jeu et ne coûtent que du cristal, mais ne portent que cinq unités chacune : le pillage aux sondes se joue sur le nombre. Sur un butin qu'un voisin convoite aussi, c'est la vitesse qui décide, et en perdre ne coûte rien à côté d'un transporteur.
L'univers a le dernier mot. Là où le pillage aux sondes est refusé, la soute d'une sonde vaut zéro : Kepler le demande au jeu et reprend les transporteurs, plutôt que de laisser une campagne réglée dessus ne jamais partir.
Ce qu'il faut pour espionner reste au port. La campagne garde de côté ce que sa dernière passe d'espionnage a réellement consommé - autant de sondes par cible, autant de cibles qu'elle en a visées - et ne pille qu'avec le surplus. Sans surplus, elle reprend les transporteurs. Sans cette réserve, la ronde suivante n'aurait plus rien pour regarder et attaquerait sur des rapports périmés.
Deux refus ne se desserrent jamais. Une flotte posée sur la cible refuse toujours - elle tire en retour, et elle vaut plus cher que de la défense. Et un rapport qui n'a pas pu établir le chiffre, faute de sondes, refuse toujours aussi : il ne dit pas que la planète est vide, il dit qu'on n'a pas assez regardé.
Partir du céleste le plus proche
SetAttackFromNearestPlanet(vrai) et SetAttackFromNearestMoon(vrai) font la même chose chez nous, et il vaut mieux le dire que laisser croire à deux réglages : l'outil de référence sépare la planète et la lune, Kepler prend le mieux placé des deux et met la lune devant sa planète à distance égale. Elle porte la même flotte sans rien annoncer au voisinage, et ce qui en part ne laisse pas la planète nue. SetStartFromNearest(vrai) est le nom Kepler de la même chose.
L'une des deux suffit à l'allumer, et false ne l'éteint que si rien ne l'a demandé par ailleurs : un script qui écrit SetAttackFromNearestPlanet(true) puis SetAttackFromNearestMoon(false) veut manifestement le mode.
SONDES ET PILLAGES PARTENT DU MÊME ENDROIT, jamais l'un sans l'autre. Un « au plus proche » qui ne déplacerait que les sondes serait exactement le défaut qu'on reproche ailleurs.
Une galaxie où le compte n'a rien est sautée. Le calcul refuse de traverser une galaxie : un vol qui le fait se remarque, et le jeu le facture des heures. La campagne l'écrit au journal plutôt que de balayer dans le vide. C'est ce qui rend SetGalaxyRange utilisable : sans lui, une plage de quatre galaxies depuis une origine fixe ferait voler les sondes une demi-heure par sortie.
SetOrigin devient facultative. En plage automatique, la portée s'applique alors autour de chacun des célestes du compte, et les zones qui se recouvrent ne sont balayées qu'une fois.
Les réglages sans équivalent
Un seul réglage de Ninja n'existe pas dans la campagne de Kepler. Il est accepté sans rien faire, pour qu'un script recopié ne s'arrête pas, et BuildFarmSession() le nomme dans le journal du bot ainsi que dans le champ Ignored de ce qu'elle rend.
SetIgnoreSleepMode. Il ne partira pas de cette liste : percer une exception dans la veille rouvrirait la partie qui a coûté le plus de défauts.
Print("ignorés :", len(campagne.Ignored))
Une seule campagne à la fois, les autres en file
Le Pillage n'en mène qu'une : deux se disputeraient les slots et les sondes. Mais BuildFarmSession() ne refuse plus quand une campagne tourne - elle met la nouvelle en file, et rend son identifiant comme d'habitude.
Et elle le dit, par deux champs de la campagne rendue : Queued vaut vrai quand elle attend, QueueRank donne sa place à partir de 1. Sans eux, les deux cas se ressemblaient trait pour trait, et un script ne pouvait pas savoir que sa campagne attendait au lieu de partir.
campagne, err = f.BuildFarmSession()
if campagne.Queued {
LogInfo("elle attend son tour, place", campagne.QueueRank)
}
Un script peut donc en monter treize d'affilée : la première devient active, les douze autres attendent leur tour dans l'ordre où vous les avez créées. Quand une campagne se termine, le Pillage prend la suivante tout seul. L'onglet Pillage les affiche « en file - 3 sur 12 ».
Trois choses à savoir :
- arrêter ou abandonner vide la file, et le journal dit combien de campagnes y attendaient.
AbortAllFarmingSessions()fait de même, et retire en plus toutes les campagnes ; - la pause la garde : une campagne suspendue reprend où elle en était, et ce qui la suivait la suit toujours ;
- si le Planning pilote aussi le Pillage, son programme passe devant : la file d'une plage s'épuise avant celle des scripts.
Le bouton ▶ d'une ligne refuse toujours une seconde campagne : il lance celle que vous désignez, et la mettre en file serait une surprise. C'est à ça que sert le bouton + posé à côté : + pour attendre son tour, ▶ pour partir tout de suite.
La file de l'écran et celle des scripts sont la même. Les douze campagnes qu'un script met en file s'affichent dans le panneau « File d'attente », en bas de l'onglet Pillage : on y voit l'ordre de passage, on peut en retirer une - la campagne n'est pas supprimée - et lancer la première d'un clic. Une campagne supprimée alors qu'elle attendait est écartée sans bruit : le tour passe à la suivante.
La stratégie des expéditions
| Fonction | Rend | |
|---|---|---|
GetExpeditionsStrategy() | 1 : un texte | "majority", "all" ou "never". |
SetExpeditionsStrategy(nom) | 1 : une erreur | La change, réglage enregistré. |
C'est le menu « Stratégie » des expéditions dans l'interface : "majority" attend que la plupart des slots d'expédition soient revenus avant la salve suivante, "all" les attend tous, "never" n'attend pas. Le réglage est enregistré comme le menu et vaut dès la salve suivante.
Tout autre nom est refusé, et l'erreur donne les trois. Un nom mal écrit, ramené en silence à "majority", laisserait croire au script qu'il a obtenu ce qu'il demandait.
if GetExpeditionsStrategy() != "all" {
err = SetExpeditionsStrategy("all")
if err != nil { LogError("stratégie :", err) }
}
La réserve d'emplacements de flotte
| Fonction | Rend | |
|---|---|---|
GetFleetSlotsReserved() | 1 : un entier | Le nombre d'emplacements laissés libres. |
SetFleetSlotsReserved(n) | 1 : une erreur | Change ce nombre, réglage enregistré. |
Ce chiffre garde au Defender de quoi esquiver. Une esquive est un envoi de flotte : sans emplacement libre, elle n'a pas lieu, et l'attaque tombe sur une planète pleine. Tout ce qui vole chez Kepler respecte cette réserve — la sortie de nuit, les vols programmés, le sondage de riposte, l'Expédition de forme de vie. Votre script est le seul à pouvoir la manger sans s'en apercevoir.
libres = GetSlots()
garde = GetFleetSlotsReserved()
if libres.Total - libres.InUse <= garde {
LogInfo("on laisse la place au Defender")
return
}
SetFleetSlotsReserved enregistre, comme le champ de l'interface : le réglage survit au redémarrage. Zéro est accepté — c'est « je gère mes esquives moi-même » — un nombre négatif est refusé.
Épargner des joueurs, des positions, des alliances
Le Pillage n'attaque que des inactifs, ce qui règle déjà le voisin avec qui l'on s'entend : un joueur qui joue n'est jamais attaqué. Reste ce que le robot ne peut pas deviner — l'inactif de votre propre alliance, l'ami qui a arrêté, la position sur laquelle vous vous êtes brûlé une fois.
Cette liste vit en base et appartient au compte, pas à une campagne : elle vaut donc pour tous vos robots sur ce compte, et elle survit à l'arrêt comme au redémarrage.
Elle se règle dans les Paramètres du compte, onglet « Joueurs épargnés », ou par script. Les fonctions ci-dessous lisent et écrivent la même liste que l'écran.
| Fonction | Rend | |
|---|---|---|
IgnorePlayer(joueur) | 1 : une erreur | Épargne un joueur. Son nom ou son identifiant. |
IgnorePlanet(coord) | 1 : une erreur | Épargne une position, la lune comprise. |
IgnoreAlliance(tag) | 1 : une erreur | Épargne tous les membres connus d'une alliance. |
UnignorePlayer(joueur) | 1 : une erreur | Le retire de la liste. |
UnignorePlanet(coord) | 1 : une erreur | |
UnignoreAlliance(tag) | 1 : une erreur | |
IsPlayerIgnored(joueur) | 1 : un booléen | Dit s'il est dans la liste. |
IsPlanetIgnored(coord) | 1 : un booléen | |
IsAllianceIgnored(tag) | 1 : un booléen | |
GetIgnored() | 2 : la liste et une erreur | Toute la liste, les trois genres mêlés. |
IgnorePlayer("Xylo") // par son nom, comme à l'écran
IgnorePlayer(4242) // ou par son identifiant
IgnorePlanet("1:42:8") // la planète ET sa lune
IgnoreAlliance("SLD") // tous ses membres que le Scanner a vus
if IsPlayerIgnored("Xylo") {
Print("il est tranquille")
}
liste, err = GetIgnored()
for e in liste {
// e.Kind vaut « player », « planet » ou « alliance ».
// e.Key porte l'identifiant, la coordonnée ou le tag ; e.Label s'affiche.
Printf("%s : %s", e.Kind, e.Label)
}
Ce que le Pillage en fait, et à quel moment
Deux filtres, pas un. Le premier écarte la position en lisant la galaxie, avant la moindre sonde. Le second écarte le rapport au moment de choisir les attaques — et c'est le plus important des deux : une campagne reprise en phase d'attaque ne relit pas la galaxie, et les rapports qu'elle exploite sont ceux de la boîte de réception entière, y compris ceux qu'un autre outil a laissés.
Le journal dit cible épargnée quand cela se produit. Les autres motifs d'écartement, eux, sont muets.
Qui respecte la liste, et qui ne la respecte pas
Ce qui la respecte : le Pillage, en galaxie *et* au moment de choisir ses attaques ; le spyer, parce que sonder laisse une trace exactement comme attaquer ; et FindInactivePlanetWithMinimumTravelTime, seule des quatre recherches à désigner un joueur.
Ce qui ne la respecte pas, et c'est voulu : l'écran Galaxie, où vous devez continuer à voir ce que vous épargnez, et la sortie de flotte de nuit — où poser sa flotte n'a rien à voir avec qui l'on pille.
Le bouton d'espionnage du chasseur avertit au journal, et envoie quand même.
Le bouton du chasseur est un geste délibéré sur des joueurs que vous avez nommés à la main : vous refuser l'envoi en silence vous retirerait un choix que vous venez de faire. La contradiction est signalée, pas arbitrée.
Cette liste n'est pas non plus la liste blanche du Defender, qui dit l'inverse : « ceux contre qui je ne me défends pas ». Épargner une alliance de deux cents membres ne doit surtout pas empêcher d'esquiver leurs attaques.
Deux signatures diffèrent de la documentation de référence
Elle prend un int64 partout. Nous ne pouvons pas la suivre sur deux points, et ces deux fonctions refusent un nombre plutôt que de l'accepter en silence :
IgnorePlanetattend une coordonnée, pas un identifiant de planète. Le jeu donne bien cet identifiant en galaxie, mais le relevé n'en garde que la coordonnée : un identifiant serait rangé et n'attraperait jamais rien.IgnoreAllianceattend le tag, pas un identifiant d'alliance. La v13 n'en donne aucun dans les données de galaxie.
Un tag se compare sans casse ni espaces. Il peut changer du jour au lendemain, là où un identifiant de joueur ne bouge jamais : c'est la limite de la notion.
Un joueur absent des relevés est refusé
Comme pour la surveillance : IgnorePlayer résout le nom depuis les relevés du Scanner, et refuse ce qu'il n'y trouve pas. Enregistrer une entrée qui n'attraperait jamais personne ferait croire au script qu'il épargne quelqu'un.
Une alliance, elle, s'ajoute même si le Scanner n'est pas encore passé : ses membres seront reconnus au fur et à mesure des relevés.
La liste noire du Pillage
Ce que le Pillage ne sonde plus et n'attaque plus. Elle n'a pas le même rôle que la liste des épargnés : celle-ci protège des amis, et vaut aussi pour l'espionnage ; la liste noire écarte des cibles qui ne produisent plus, et ne vaut que pour le Pillage.
Une position y entre d'elle-même quand trois rapports de suite montrent exactement les mêmes ressources, sous le butin minimal de la campagne : la planète ne produit plus, ses hangars sont pleins mais petits. Un rapport qui bouge ou qui vaut le détour remet son compte à zéro, et l'en fait sortir si elle y était entrée d'elle-même. Cette entrée ne vaut que pour le joueur qui possédait la planète : reprise par un autre, elle est de nouveau sondée, et n'est écartée qu'après trois rapports pareils chez lui. Elle n'écarte que la planète, pas sa lune. Une position ajoutée à la main, elle, écarte les deux et ne sort jamais d'elle-même.
Elle se voit et se règle dans l'onglet « Liste noire » de la page Pillage, ou par script. Les ajouts et les retraits valent dès la passe suivante du Pillage.
| Fonction | Rend | |
|---|---|---|
GetFarmBlacklist() | 2 : la liste et une erreur | Toute la liste, joueurs et positions mêlés. |
AddToFarmBlacklist(cible) | 1 : une erreur | Un joueur, par son nom ou son identifiant, ou une position. |
RemoveFromFarmBlacklist(cible) | 1 : une erreur | Retirer ce qui n'y est pas n'est pas une erreur ; un nom que rien ne connaît en est une. |
ClearFarmBlacklist() | 1 : une erreur | Tout vider, entrées d'office comprises. |
AddToFarmBlacklist("1:42:8") // à la main : la planète ET sa lune
AddToFarmBlacklist("Xylo") // un joueur, par son nom
AddToFarmBlacklist(4242) // ou par son identifiant
liste, err = GetFarmBlacklist()
for e in liste {
// e.Kind vaut « player » ou « planet », comme pour GetIgnored ;
// e.Source vaut « auto » ou « manual ».
// e.Key porte l'identifiant ou la coordonnée ; e.Label s'affiche.
if e.Source == "auto" {
RemoveFromFarmBlacklist(e.Key) // ne rendre que les entrées d'office
}
}
ClearFarmBlacklist()
Une position se désigne sans son type : "M:1:42:8" et "1:42:8" sont la même entrée. Un joueur absent des relevés du Scanner est refusé à l'ajout, mais se retire toujours : par son identifiant, par le nom affiché dans la liste, ou par e.Key tel que GetFarmBlacklist le rend.
Retirer une position, ou vider la liste, remet aussi son compte de rapports identiques à zéro : elle n'y revient qu'après trois nouveaux rapports pareils, pas au premier.
Composer une liste de surveillance
StartHunter() allume la surveillance. Elle ne dit pas qui surveiller : cette liste vit en base et se modifie au fil du jeu. Allumer le chasseur sur une liste vide ne relève rien.
| Fonction | Rend | |
|---|---|---|
GetHunterTargets() | 2 : la liste et une erreur | Les joueurs sous surveillance. |
AddHunterTarget(joueur) | 1 : une erreur | Met un joueur sous surveillance. |
RemoveHunterTarget(joueur) | 1 : une erreur | Le retire, avec son historique. |
PauseHunterTarget(joueur, suspendu) | 1 : une erreur | Le suspend sans perdre son historique. |
AddHunterTarget("Xylo") // par son nom, comme à l'écran
AddHunterTarget(4242) // ou par son identifiant
StartHunter()
cibles, err = GetHunterTargets()
for c in cibles {
Printf("%s : %d positions, activité %d", c.PlayerName, c.Positions, c.Activity)
}
Le nom marche autant que l'identifiant. La doc de référence ne prend que l'identifiant ; le nom est ce que vous lisez à l'écran, et c'est donc ce qu'un script écrit le plus souvent. Les deux écritures mènent à la même cible : le robot résout le nom depuis ses relevés de galaxie, une fois, à l'ajout — parce qu'un joueur peut se renommer, son identifiant non.
Ajouter deux fois le même joueur ne le double pas. La liste est tenue par identifiant.
Un joueur absent des relevés est refusé
err = AddHunterTarget(999999)
// joueur n° 999999 introuvable dans les relevés :
// le Scanner est-il passé chez lui ?
C'est notre second écart avec la doc de référence, qui accepte n'importe quel identifiant. La surveillance travaille sur les positions connues : elle relève, à chaque passe, les célestes que le Scanner a vus. Une cible dont on ne connaît aucune position ne rendrait donc jamais rien, et votre script croirait surveiller quelqu'un.
Le refus vous dit quoi faire : laissez le Scanner couvrir la zone du joueur, puis rappelez AddHunterTarget.
Ce que porte une cible
| Champ | |
|---|---|
PlayerID, PlayerName, Alliance, Rank | Qui il est. |
Positions | Combien de célestes lui sont connus. |
Activity | Le dernier relevé de toutes ses positions : 15 quand l'une est active à l'instant, sinon le plus court minuteur trouvé, 0 quand il n'y a rien nulle part. |
Paused | La surveillance est suspendue. |
NotifyTimer | Une alerte est armée sur son retour. |
LastCheck, AddedAt | Des dates Unix, 0 si jamais relevé. |
Suspendre plutôt que retirer
RemoveHunterTarget efface aussi l'historique d'activité du joueur, qui est le seul intérêt d'une surveillance ancienne. PauseHunterTarget(joueur, true) arrête les relevés et garde la série : c'est ce qu'on veut pendant les vacances d'une cible.
Deux pièges
La veille n'est pas un worker comme les autres. StartSleepMode() n'endort pas le compte sur-le-champ : elle allume le worker, qui suivra ensuite le planning réglé dans le panneau. Si le mode n'est pas automatique et qu'aucune veille manuelle n'est posée, il ne se passera rien du tout.
En revanche, quand la fenêtre de veille s'ouvre pour de bon, la session se ferme et votre script cesse de tourner avec les autres workers. Un script qui allume la veille peut donc s'arrêter lui-même plus tard, à une heure qu'il n'a pas choisie.
Allumer un outil éteint le reste. La phalange, la surveillance des champs de ruines et les autres outils sont exclusifs : le robot n'en fait tourner qu'un, et allumer l'un éteint les workers ordinaires. C'est la règle de l'interface, et elle s'applique ici aussi. Un StartWorker("phalanx") peut donc arrêter votre pillage sans que vous l'ayez demandé.
Un script qui en pilote d'autres
| Fonction | Rend | |
|---|---|---|
GetScripts() | 1 : une liste de noms | Tous les scripts du compte. |
GetRunningScripts() | 1 : une liste de noms | Ceux qui tournent en ce moment. |
IsScriptRunning(nom) | 1 : un booléen | Celui-là tourne-t-il. |
IsPausedScript(nom) | 1 : un booléen | Celui-là est-il en pause. |
StartScript(nom) | 1 : une erreur | Le lance et rend la main aussitôt. |
StopScript(nom) | 1 : une erreur | L'arrête. |
PauseScript(nom) | 1 : une erreur | Le suspend. |
ResumeScript(nom) | 1 : une erreur | Le reprend là où il en était. |
À quoi ça sert. Un script tourne d'un bout à l'autre dans un seul fil : ce qu'il fait, il le fait à la suite. Un compte qui veut une garde de nuit, un pillage et un rapport quotidien a donc trois scripts — et quelque chose doit décider lequel tourne quand. C'est le rôle d'un script chef d'orchestre : il n'agit pas sur le jeu, il allume et éteint les autres.
// Le chef d'orchestre : la garde la nuit, le rapport le matin.
CronExec("@22h00", func() {
StartScript("garde-de-nuit")
})
CronExec("@08h00", func() {
StopScript("garde-de-nuit")
StartScript("rapport")
})
Le suffixe .ank est facultatif. StartScript("garde") et StartScript("garde.ank") désignent le même script : le stockage ajoute le suffixe tout seul, et exiger de le taper ferait échouer la moitié des appels sur un script bien présent.
StartScript rend la main aussitôt, elle n'attend pas la fin du lancé. Et le script lancé ne meurt pas avec celui qui l'a lancé : les deux sont indépendants une fois partis.
Trois refus qu'il vaut mieux connaître.
- Un script ne se relance pas lui-même : cela ne veut rien dire.
- Un script ne se met pas en pause lui-même. Ce serait un blocage définitif : plus personne ne tourne pour le reprendre, et le compte garde un script figé qui a l'air vivant.
- Un script peut s'arrêter lui-même, et c'est une sortie propre. Le geste ne bloque pas : il annule, et le script s'arrête à l'instruction suivante.
Exit()fait la même chose sous un autre nom.
« En pause » n'est pas « arrêté ». Un script en pause ne figure pas dans GetRunningScripts, mais le relancer le ferait repartir de sa première ligne. IsPausedScript est là pour cette distinction : lisez-la avant de décider entre StartScript et ResumeScript.
Savoir ce que fait le Pillage
| Fonction | Rend | |
|---|---|---|
IsFarmSessionOngoing() | 1 : un booléen | Une campagne travaille-t-elle en ce moment. |
IsPausedFarmingBot() | 1 : un booléen | Une campagne est-elle en pause. |
FarmingBotSessionsCount() | 1 : un entier | Combien de campagnes tournent. |
PauseFarmingBot() | 1 : une erreur | Suspend la campagne en cours. |
ResumeFarmingBot() | 1 : une erreur | La reprend où elle s'est arrêtée. |
AbortAllFarmingSessions() | 1 : une erreur | Arrête tout et retire toutes les campagnes, celle qui tourne et celles de l'onglet Pillage comprises. |
Une campagne en pause rend false à IsFarmSessionOngoing : elle ne travaille pas. La distinction compte — un script qui attend la fin d'une campagne pour lancer autre chose attendrait sinon indéfiniment devant une campagne que personne ne reprendra.
Écart avec Ninja, et il vaut mieux le lire ici qu'en jeu. L'outil de référence mène plusieurs campagnes de front ; Kepler n'en mène qu'une à la fois, parce que deux se disputeraient les emplacements et les sondes et que l'on ne saurait plus laquelle a vidé quoi. FarmingBotSessionsCount vaut donc zéro ou un, jamais davantage : un script recopié qui le compare à trois ne trouvera jamais son compte.
Rapatrier tout de suite
| Fonction | Rend | |
|---|---|---|
RepatriateNow() | 1 : une erreur | Lance une passe de rapatriement sans attendre. |
Le worker dort entre deux passes. Un script qui vient de vider une planète veut que les ressources partent maintenant, pas au prochain réveil.
Elle ne règle rien : les destinations, les seuils et les vaisseaux restent ceux de la page. Elle ne fait qu'avancer l'heure. Le worker doit être allumé — déclencher un worker éteint ne ferait rien, et l'erreur le dit.
Rassembler tout au même endroit
| Fonction | Rend | |
|---|---|---|
RepatriateSetAllDestinations(céleste) | 1 : une erreur | Ce céleste reçoit, tous les autres l'alimentent. |
Lisez le nom jusqu'au bout : « All ». Le céleste donné devient la destination, et tous les autres deviennent des origines. Le réglage précédent des origines est REMPLACÉ, pas complété : une colonie que vous aviez mise de côté — le temps d'y construire — y revient.
Les autres destinations sont effacées. La page en accepte plusieurs, et chaque céleste rapatrie vers la plus proche ; cet appel n'en laisse qu'une, la vôtre. C'est ce que le nom promet, mais un compte à trois banques n'en a plus qu'une après l'appel.
Elle ne lance rien : c'est RepatriateNow qui déclenche une passe.
RepatriateSetAllDestinations("1:64:8")
RepatriateNow()
La file de la Construction
| Fonction | Rend | |
|---|---|---|
ClearAllConstructionQueues() | 1 : une erreur | Vide la file de chaque céleste en mode File. |
AddItemToQueue(céleste, quoi, nombre) | 1 : une erreur | Pose une ligne au bout de la file d'un céleste. |
Les deux écrivent la file que la Construction lit, exactement comme la page Construction : elles ne lancent rien dans le jeu. C'est la Construction qui bâtit ensuite, à sa passe, si elle est allumée (StartBrain()).
Une ligne de Kepler est un niveau à atteindre, pas une action. Chez l'outil de référence, AddItemToQueue(c, SOLARPLANT, 0) veut dire « un niveau de plus ». Ici, la ligne posée vise le niveau suivant de ce qui est déjà bâti, en chantier ou déjà demandé dans la file : deux appels d'affilée demandent donc bien deux niveaux, et la centrale dont le 11 monte reçoit la ligne « centrale 12 ». Le niveau actuel et le chantier se lisent dans le jeu à l'appel, deux ou trois requêtes.
- Bâtiment, recherche, forme de vie : le nombre est ignoré, sauf
-1. - Vaisseau, défense : le nombre est une quantité, au moins une.
AddItemToQueue(c, BOMBER, 0)rend une erreur. -1, démolir, n'est pas pris en charge et rend une erreur qui le dit : la file ne sait pas descendre un niveau.TearDowndémolit tout de suite.- Une forme de vie qui n'est pas de l'espèce du céleste est refusée : sa page ne la montre pas, et son niveau ne se lit pas.
- Ce que la page Construction ne propose pas est refusé : la foreuse, une mine ou une recherche sur une lune, une forme de vie sur une lune. La ligne serait morte.
- Un vaisseau réservé à une autre classe est refusé : le Faucheur hors Général, l'Éclaireur hors Explorateur. Le jeu ne le construirait pas.
Un céleste éteint à la file vide passe en mode File : une ligne posée dans une file que personne ne lit ne ferait rien. Un céleste éteint qui garde une file est refusé, sans rien toucher : le rallumer bâtirait aussi ses anciennes lignes. Un céleste en mode IA est refusé de même : le passer en File jetterait son plan. Dans les deux cas, c'est à vous de le décider sur la page.
ClearAllConstructionQueues ne vide que les célestes en mode File. La file gardée par un céleste en mode IA ou éteint reste telle quelle, comme avec le bouton « Vider toutes les files » de la page.
Pendant le mode manuel du navigateur, ClearAllConstructionQueues passe tout de suite : elle ne touche qu'à la file du robot, sans rien demander au jeu. AddItemToQueue, elle, attend la fin du mode, puisqu'elle peut avoir à lire le niveau du céleste dans le jeu.
ClearAllConstructionQueues()
c = GetCachedCelestial("1:2:3")
err = AddItemToQueue(c.GetID(), METALMINE, 0)
if err != nil { LogError("file :", err) }
AddItemToQueue(c.GetID(), METALMINE, 0) // un niveau de plus encore
AddItemToQueue(c.GetID(), BOMBER, 5)
Ce que le robot fait de ce compte
| Fonction | Rend | |
|---|---|---|
IsStarted() | 1 : un booléen | Le robot tourne-t-il pour ce compte. |
IsActive() | 1 : un booléen | Le redémarrera-t-il au prochain lancement. |
Les deux questions se ressemblent et n'ont pas la même réponse. IsActive lit la CASE du compte : un compte actif mais arrêté repartira, un compte inactif ne repartira pas. IsStarted lit l'état vivant.
Vue de l'intérieur d'un script, IsStarted est toujours vraie — un script ne tourne pas sur un robot arrêté. Elle sert après une longue attente : entre-temps, la session a pu se fermer.
La veille, et la cadence du Defender
| Fonction | Rend | |
|---|---|---|
GetNextSleepTime() | 1 : une heure, ou nil | Le prochain coucher. |
GetNextWakeTime() | 1 : une heure, ou nil | Le prochain réveil. |
SetDefenderCheckInterval(min, max) | 1 : une erreur | La cadence de la ronde, en secondes. |
TriggerFleetSave() | 1 : une erreur | Sort la flotte maintenant, avec les réglages du mode veille. |
Les deux heures sont celles qui auront vraiment lieu, tirage au sort compris. Le robot décale ses couchers de quelques minutes pour ne pas s'éteindre chaque soir à la seconde ronde ; un script qui se fierait à l'heure saisie dans la page se ferait couper au milieu d'un geste.
fin = GetNextSleepTime()
if fin != nil && fin.Sub(Now()).Minutes() < 10 {
LogInfo("le compte s'endort bientôt, on ne lance pas la campagne")
return
}
nil veut dire quelque chose : la veille n'est pas automatique, ou la session n'est pas ouverte. C'est pour cela que ces deux-là rendent un pointeur et non une date — une date nulle se lirait comme l'an 1, et un script qui compare des heures y verrait un coucher déjà passé.
SetDefenderCheckInterval prend DEUX bornes, en secondes, et le robot tire au hasard entre elles à chaque tour : une cadence fixe se reconnaît d'en face, c'est tout l'intérêt d'en avoir deux. Le réglage est enregistré, comme les champs de l'interface. Une borne nulle ou à l'envers est refusée plutôt que corrigée en silence.
TriggerFleetSave sort la flotte maintenant, avec les célestes cochés dans le mode veille, leurs destinations et leur découpage. Elle ne règle rien : un script qui veut envoyer autre chose compose son vol avec SendFleet.
Elle marche même quand la veille est éteinte, et c'est voulu. La sortie de flotte se règle sous la veille, mais celui qui ne se sert pas de la veille est justement celui à qui le geste sert le plus.
Elle attend la fin. Plusieurs célestes qui découpent leur flotte se comptent en dizaines de minutes ; le script reprend la main quand tout est parti, ce qui est le seul moyen d'écrire « je sors la flotte PUIS j'éteins tout ». Arrêter le script arrête la sortie.
L'erreur ne se lève que si RIEN n'est parti - session fermée, aucun céleste coché, version sans sortie de flotte. Un départ partiel ne la lève pas : il va au journal et en avertissement plein écran, comme quand on clique le bouton, parce que c'est le joueur qui peut y faire quelque chose, pas le script. La documentation de référence, elle, ne rend rien du tout ; un TriggerFleetSave() recopié tel quel marche donc aussi ici.
err = TriggerFleetSave()
if err != nil {
LogWarn("rien n'est sorti : " + err.Error())
}
Pause et arrêt ne sont pas la même chose, et c'est ce qui justifie deux fonctions plutôt qu'une. PauseFarmingBot garde l'avancement : la reprise repart du système atteint. StopFarmingBot l'efface : la campagne repartira du premier. Sur une campagne de trois cents systèmes, c'est une nuit de travail.
if IsFarmSessionOngoing() {
PauseFarmingBot() // on rend les slots au Defender
SleepMin(30)
ResumeFarmingBot() // et on repart là où on s'était arrêté
}
ResumeFarmingBot trouve seule laquelle reprendre : une seule campagne à la fois peut être en pause. Sans campagne en pause, elle rend une erreur plutôt que de relancer celle qu'elle trouve — la relancer la ferait repartir du premier système, ce qui est exactement ce qu'on cherchait à éviter.
AbortAllFarmingSessions est le geste de « on repart de zéro », et il fait exactement comme chez Ninja : il retire toutes les campagnes, quel que soit leur état - en cours, en pause, en file ou terminée -, celles de vos scripts comme celles de l'onglet Pillage. Un script qui abandonne le soir et recompose le matin depuis le céleste où sa flotte a dormi ne retrouve donc plus les campagnes de la veille sous les neuves.
AbortAllFarmingSessions() // le soir : plus rien ne tourne, plus rien d'hier
Pendant le mode manuel du navigateur, AbortAllFarmingSessions passe tout de suite : elle ne fait que retirer des campagnes, sans rien demander au jeu.
Celles de l'onglet Pillage partent aussi, même celle qui tourne. Un Planning qui nommait une campagne retirée le dit à son bord suivant, comme pour une campagne supprimée à la main : il garde celle qui tourne s'il y en a une, et sinon laisse le Pillage éteint plutôt que de l'allumer sur rien. Le bouton « Tout arrêter » de l'écran, lui, ne retire rien.
Les raids déjà en vol ne sont pas rappelés : ils rentrent normalement, et rien ne relance une campagne retirée - ni leur retour, ni la file, ni un redémarrage du robot, ni un onglet de Kepler resté ouvert depuis la veille, quelle que soit sa page.
L'historique du butin par journée est tenu par compte, pas par campagne : retirer une campagne n'en efface rien. Mais le butin d'une vague qui vole encore au moment de l'abandon n'y entre pas, et celui des vagues rentrées mais pas encore comptées n'y entre qu'au prochain allumage du Pillage, si le robot n'a pas redémarré entre-temps. C'est aussi vrai de « Tout arrêter ».
Appelez StartFarmingBot() après avoir composé les campagnes du jour : juste après l'abandon, il n'y a plus rien à lancer et il rend une erreur ; et si une campagne a été composée entre-temps, à l'écran par exemple, il lance celle-là et les neuves se rangent en file derrière elle.