Kepler. Documentation · Scripts 325 functions available right now Français

Constants and values

What the engine places in your script before its first line. These are not functions: you read them, you do not call them, and none of them returns an error.

Some are real and useful. Others exist only so that a script coming from Ninja does not stop on an unknown symbol, and are worth nothing. The last section says which ones, because mixing them up is expensive.

The four id arrays

ValueHolds
ShipsArr16 idsThe ships, from the small cargo to the pathfinder.
DefencesArr10 idsThe defences, both missiles included.
TechnologiesArr16 idsThe researches, in the order of the game's tree.
BuildingsArr23 idsThe buildings, planet and moon alike.

The order is guaranteed and does not change from one start to the next. So you can index into them, build a parallel array, or print a report always in the same order.

for id in ShipsArr {
	Print(id)          // prints "SmallCargo", not 202
}

An id prints as its name, and that name is in English whatever the language of your universe: it is hard-coded into the game library, not read from your pages. ID2Str(id) does the same thing explicitly, and returns Invalid(99999) for a number it does not know, rather than nothing at all.

SOLARSATELLITE is in BuildingsArr, not in ShipsArr. It is built at the shipyard, but the game counts it among the buildings, so a loop reading a planet's levels has to expect to find it there.

Each script gets its own copy of the four arrays. Sorting ShipsArr therefore disturbs no other script on the account. That said, you really are sorting your ShipsArr, for the whole life of your script.

sort = import("sort")
arr = ShipsArr                 // arr refers to the same array, not a copy
sort.Slice(arr, func(i, j) { return arr[i] < arr[j] })
// ShipsArr is sorted too, until this script ends.

The derived arrays do not exist. PlanetBuildingsArr, MoonBuildingsArr, LfTechnologiesArr and the lifeform lists are missing: a script that names them stops on undefined symbol. Filter BuildingsArr yourself.

The id names

Every id in the four arrays has its named constant, and the other way round. They are written in upper case.

// Ships
SMALLCARGO   LARGECARGO   LIGHTFIGHTER   HEAVYFIGHTER   CRUISER
BATTLESHIP   COLONYSHIP   RECYCLER       ESPIONAGEPROBE BOMBER
DESTROYER    DEATHSTAR    BATTLECRUISER  CRAWLER        REAPER
PATHFINDER

// Defences
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

// Buildings
METALMINE        CRYSTALMINE       DEUTERIUMSYNTHESIZER  SOLARPLANT
FUSIONREACTOR    SOLARSATELLITE    METALSTORAGE          CRYSTALSTORAGE
DEUTERIUMTANK    SHIELDEDMETALDEN  UNDERGROUNDCRYSTALDEN SEABEDDEUTERIUMDEN
ALLIANCEDEPOT    ROBOTICSFACTORY   SHIPYARD              RESEARCHLAB
MISSILESILO      NANITEFACTORY     TERRAFORMER           SPACEDOCK
LUNARBASE        SENSORPHALANX     JUMPGATE

Anywhere a function expects an id, the raw number works too: ID2Str(204) and ID2Str(LIGHTFIGHTER) give the same result.

Missions

ConstantValue
ATTACK1
GROUPEDATTACK2
TRANSPORT3
PARK4Park on a position of your own.
PARKINTHATALLY5Park at an ally's.
SPY6
COLONIZE7
RECYCLEDEBRISFIELD8
DESTROY9Moon destruction.
MISSILEATTACK10
EXPEDITION15
SEARCHFORLIFEFORMS18Displays as "SearchForLifeform", singular.

Like the ids, a mission prints as its name: Print(EXPEDITION) prints "Expedition", not 15.

Speeds

Twenty steps in all. The ten whole ones run from TEN_PERCENT (value 1) to HUNDRED_PERCENT (value 10). The ten half steps slot in between: FIVE_PERCENT is 0.5, FIFTEEN_PERCENT is 1.5, and so on up to NINETY_FIVE_PERCENT, which is 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

The half steps are only offered in game to the General class. Kepler exposes them to everyone so that a script written for another account does not stop on them. A General account sends them as they are; an account of another class flies at the whole step below, and never under 10 % (FIFTY_FIVE_PERCENT flies at 50 %, FIVE_PERCENT at 10 %). FlightTime, GetDepartureTime and LowestSpeed compute that step, and SetSpeed on a NewFleet() keeps it: the calculation and the flight agree.

They are decimal numbers, and that is exactly what the speed parameter of FlightTime expects.

Celestial types, lifeforms, classes

ConstantValue
PLANET_TYPE1
DEBRIS_TYPE2The debris field of a position.
MOON_TYPE3
NONE_LF_TYPE HUMANS ROCKTAL MECHAS KAELESH0 to 4Lifeforms.
NO_CLASS COLLECTOR GENERAL DISCOVERER0 to 3Player class.
NO_ALLIANCE_CLASS WARRIOR TRADER RESEARCHER0 to 3Alliance class.

The three celestial types are genuinely useful: NewCoordinate(4, 128, 6, MOON_TYPE) and GetEmpire(PLANET_TYPE) expect them.

The lifeforms and the classes are not. No function returns these values yet: nothing gives you a planet's lifeform, nor your player class, nor your alliance's, and the lifeform functions are missing (see the table of gaps in the introduction). So today these thirteen constants only serve to keep a script that names them from failing.

The dimensions of the universe

ValueHolds
GALAXIESan integerThe number of galaxies in your universe.
SYSTEMSan integerThe number of systems per galaxy.

These two values are read from your universe's record, but only if the session is open at the moment the script starts. With no session, they are 9 and 499, which are the usual dimensions and not yours.

They are frozen when the script starts. A script launched before login will keep 9 and 499 for its whole life, even once the account is logged in. No function returns these two numbers on the fly: the only cure is to restart the script once logged in.

// Sweep a whole galaxy without hard-coding 499.
for sys = 1; sys <= SYSTEMS; sys++ {
	infos, err = GalaxyInfos(4, sys)
	if err != nil { LogWarn(err); continue }
	SleepRandMs(400, 900)
}

The file, the server, the version

ValueHolds
FILE __FILE__a stringThe name of the current script, extension included: ma-ronde.ank.
OGAME_SERVERa recordThe server: .Name, .Number, .Language, and .Settings. Fields empty with no session.
VERSION __VERSION__a stringLiterally Kepler 0.1. See the warning further down.

OGAME_SERVER is not a string, it is a record, as in Ninja. The name of the universe reads OGAME_SERVER.Name.

Printf("%s (s%d-%s)", OGAME_SERVER.Name, OGAME_SERVER.Number, OGAME_SERVER.Language)
Print("economy speed:", OGAME_SERVER.Settings.EconomySpeed)

The available fields are Name, Number, Language, PlayerCount, PlayersOnline, Opened, StartDate, ServerClosed, Prefered, SignupClosed, and Settings. That last one carries the universe settings: EconomySpeed, FleetSpeedWar, FleetSpeedPeaceful, FleetSpeedHolding, UniverseSize, PlanetFields, DebrisFieldFactorShips, DebrisFieldFactorDefence, ResearchDurationDivisor, EspionageProbeRaids, WreckField, AKS, ServerLabel, ServerCategory, PremiumValidationGift.

EconomySpeed is not always a number. Depending on the universe, the game puts 8 or "x8" in it. Test before you count with it.

FILE is not there to separate your storage keys. Each script already has its own memory: two scripts storing the key last.system do not tread on each other, and prefixing protects nothing. FILE is there to name yourself, in an alert or a log line.

SendDiscord(MY_WEBHOOK, FILE + ": debris at " + coord)

In !global.ank, FILE is always !global.ank. A function defined over there reads the symbols of the environment where it was written, not of the one calling it: it will name itself !global.ank even when called from ma-ronde.ank.

OGAME_SERVER holds neither the address, nor the number, nor the language of the server, only the name of the universe. It is frozen when the script starts, like GALAXIES and SYSTEMS: a script launched before login will see it empty forever. To get the up-to-date value at the moment you need it, call the functions. GetUniverseName(), GetServerNumber() and GetLang() return a single value, empty or zero with no session. ServerURL() returns two: the address and an error.

VERSION does not follow Kepler's versions. It is a fixed piece of text, written once into the program, that does not change when you update the bot. So a version guard copied from an existing script does not do what it says:

// ✗ Always true here, whatever your version.
if VersionCompare(VERSION, "0.91.8") == -1 {
	Print("bot too old")
	Exit()
}

VersionCompare keeps only the numbers of a string: from Kepler 0.1 it reads 0 then 1, compares them against 0 then 91, and concludes that your bot is older. The script stops even though there is nothing wrong with your install. Delete tests of that kind.

Waiting for the stop: OnQuitCh

ValueHolds
OnQuitCha channelCloses when the script stops.

It is the only event channel available. Its normal use is to keep a script alive after it has scheduled its tasks: without it, the script reaches the end of its text, finishes, and takes its ExecAt and its CronExec with it.

CronExec("0 3 * * *", func() { Print("it is three in the morning") })
<-OnQuitCh                       // blocks until the script stops

It closes on Exit(), on Terminate(), on the Stop button, and when the bot shuts down. Ninja only fires it on Exit; here, every stop closes it.

Two precautions:

  • The lines that follow <-OnQuitCh do not run. The channel only releases once the stop is under way, and the engine then refuses the next instruction. Write your farewell line before it, or in an OnExit function, which the bot calls afterwards, with its own grace period.
  • Never use it in !global.ank. That file defines the shared environment, its channel never closes, and the wait would block the loading of the shared definitions for all your other scripts.

The stub values

The seven values that follow exist for one reason only: so that a script coming from Ninja does not stop on undefined symbol. They are wired to nothing. They read neither your settings, nor your licence, nor your hosting mode.

Six of them carry two names. Ninja writes them wrapped in double underscores, __IS_CLOUD__ rather than IS_CLOUD, and that is the form scripts from there use to read them. Both forms work here and give the same value.

ValueAlwaysWhat that implies
LICENSE_UUID __LICENSE_UUID__the empty string
LICENSE_USERNAME __LICENSE_USERNAME__the empty string
LICENSE_EMAIL __LICENSE_EMAIL__the empty string
LICENSE_BOTS_ALLOWED __LICENSE_BOTS_ALLOWED__0Does not mean "no bot allowed".
IS_CLOUD __IS_CLOUD__falseFalse even on a cloud instance.
IS_SELF_HOST __IS_SELF_HOST__trueTrue even when it is not the case.
CookieDomainthe empty stringIn Ninja, a cloud instance carries its subdomain there.

DISCORD_WEBHOOK and TELEGRAM_CHAT_ID are not stubs: they carry what you filled in on the Notifications page, and SendDiscord(DISCORD_WEBHOOK, msg) goes out as is, with nothing more to configure. See notifications.

ValueHoldsWhat that implies
DISCORD_WEBHOOKthe Discord webhook from the Notifications pageEmpty if none is set: SendDiscord then returns an error.
TELEGRAM_CHAT_IDthe Telegram chat from the Notifications pageZero if none is set.

The costliest trap is elsewhere: if IS_CLOUD { ... } will never run, and a test on LICENSE_BOTS_ALLOWED will always read zero. Remove those branches rather than leave them lying to you in silence.