Add distributed-builder.ank
This commit is contained in:
parent
11afcc4162
commit
91829b2e8e
440
distributed-builder.ank
Normal file
440
distributed-builder.ank
Normal file
@ -0,0 +1,440 @@
|
||||
// =============================================================================
|
||||
// OGame Ninja Multi-Planet Ship Builder Script
|
||||
// =============================================================================
|
||||
// This script automates building ships on multiple planets, importing resources
|
||||
// from a master planet when needed, and parking ships on the main planet.
|
||||
// =============================================================================
|
||||
|
||||
// ========================= CONFIGURATION =========================
|
||||
|
||||
// Target ship quantities - using NewShipsInfos() and Set() method
|
||||
TARGET_SHIPS = NewShipsInfos()
|
||||
TARGET_SHIPS.Set(LIGHTFIGHTER, 20000) // Light Fighters
|
||||
TARGET_SHIPS.Set(HEAVYFIGHTER, 15000) // Heavy Fighters
|
||||
TARGET_SHIPS.Set(CRUISER, 2000) // Cruisers
|
||||
TARGET_SHIPS.Set(BATTLESHIP, 1000) // Battleships
|
||||
TARGET_SHIPS.Set(LARGECARGO, 3000) // Large Cargo
|
||||
TARGET_SHIPS.Set(SMALLCARGO, 3000) // Small Cargo
|
||||
TARGET_SHIPS.Set(RECYCLER, 500) // Recyclers
|
||||
TARGET_SHIPS.Set(ESPIONAGEPROBE, 0) // Espionage Probes
|
||||
|
||||
// List of planets to build ships on
|
||||
BUILDER_PLANETS = ["1:2:1", "1:2:2", "1:2:3", "1:2:4", "1:2:5", "1:2:6", "1:2:7"]
|
||||
|
||||
// *** FIX: Manually define an array of ship IDs to iterate over ***
|
||||
SHIP_IDS_TO_BUILD = [LIGHTFIGHTER, HEAVYFIGHTER, CRUISER, BATTLESHIP, LARGECARGO, SMALLCARGO, RECYCLER, ESPIONAGEPROBE]
|
||||
|
||||
// Master planet for resource imports
|
||||
MASTER_PLANET = "2:2:14"
|
||||
|
||||
// Main planet where to park all ships
|
||||
MAIN_PLANET = "2:2:14"
|
||||
|
||||
// Resource threshold - minimum resources to keep on master planet
|
||||
RESOURCE_THRESHOLD = NewResources(1000000, 500000, 100000)
|
||||
|
||||
// Minimum resources needed before attempting ship building
|
||||
MIN_RESOURCES_TO_BUILD = NewResources(100000, 50000, 10000)
|
||||
|
||||
// Building check interval (milliseconds)
|
||||
CHECK_INTERVAL = 5 * 60 * 1000
|
||||
|
||||
// Fleet parking interval (milliseconds)
|
||||
PARKING_INTERVAL = 30 * 60 * 1000
|
||||
|
||||
// Transport fleet configuration
|
||||
TRANSPORT_SHIPS = NewShipsInfos()
|
||||
TRANSPORT_SHIPS.Set(LARGECARGO, 100)
|
||||
|
||||
// ========================= GLOBAL VARIABLES =========================
|
||||
|
||||
lastParkingCheck = 0
|
||||
|
||||
// ========================= MAIN FUNCTIONS =========================
|
||||
|
||||
func main() {
|
||||
LogInfo("=== Multi-Planet Ship Builder Started ===")
|
||||
LogInfof("Builder planets count: %d", len(BUILDER_PLANETS))
|
||||
LogInfof("Master planet: %s", MASTER_PLANET)
|
||||
LogInfof("Main planet: %s", MAIN_PLANET)
|
||||
|
||||
// Main loop
|
||||
for {
|
||||
LogInfo("--- Starting build cycle ---")
|
||||
|
||||
// Check each builder planet
|
||||
for i = 0; i < len(BUILDER_PLANETS); i++ {
|
||||
planetCoord = BUILDER_PLANETS[i]
|
||||
processPlanet(planetCoord)
|
||||
Sleep(Random(2000, 5000))
|
||||
}
|
||||
|
||||
// Check if it's time to park fleets
|
||||
currentTime = GetTimestamp()
|
||||
if currentTime - lastParkingCheck > PARKING_INTERVAL / 1000 {
|
||||
parkAllFleets()
|
||||
lastParkingCheck = currentTime
|
||||
}
|
||||
|
||||
// Print status at the end of each cycle
|
||||
printStatus()
|
||||
|
||||
LogInfo("--- Build cycle complete, sleeping ---")
|
||||
Sleep(CHECK_INTERVAL)
|
||||
}
|
||||
}
|
||||
|
||||
func processPlanet(planetCoord) {
|
||||
LogInfof("Processing planet: %s", planetCoord)
|
||||
|
||||
planet, _ = GetPlanet(planetCoord)
|
||||
if planet == nil {
|
||||
LogErrorf("Could not get planet %s", planetCoord)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if planet has shipyard
|
||||
facilities, _ = planet.GetFacilities()
|
||||
if facilities.Shipyard == 0 {
|
||||
LogWarnf("Planet %s has no shipyard", planetCoord)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if shipyard is busy with buildings or ships
|
||||
bldgID, shipsCount, _ = planet.GetProduction()
|
||||
if bldgID != 0 {
|
||||
LogInfof("Shipyard is blocked by building construction on %s", planetCoord)
|
||||
return
|
||||
}
|
||||
if shipsCount > 0 {
|
||||
LogInfof("Shipyard already building ships on %s", planetCoord)
|
||||
return
|
||||
}
|
||||
|
||||
// Get current ships on planet
|
||||
currentShips, _ = planet.GetShips()
|
||||
|
||||
// Check what ships need to be built
|
||||
shipsToBuild = calculateShipsNeeded(currentShips)
|
||||
|
||||
// Check if any ships are needed
|
||||
totalNeeded = 0
|
||||
for i = 0; i < len(SHIP_IDS_TO_BUILD); i++ {
|
||||
shipID = SHIP_IDS_TO_BUILD[i]
|
||||
totalNeeded = totalNeeded + shipsToBuild.ByID(shipID)
|
||||
}
|
||||
|
||||
if totalNeeded == 0 {
|
||||
LogInfof("Planet %s - No ships needed", planetCoord)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if we have enough resources
|
||||
resources, _ = planet.GetResources()
|
||||
requiredResources = calculateRequiredResources(shipsToBuild)
|
||||
|
||||
neededMetal = 0
|
||||
neededCrystal = 0
|
||||
neededDeut = 0
|
||||
if requiredResources.Metal > resources.Metal { neededMetal = requiredResources.Metal - resources.Metal }
|
||||
if requiredResources.Crystal > resources.Crystal { neededCrystal = requiredResources.Crystal - resources.Crystal }
|
||||
if requiredResources.Deuterium > resources.Deuterium { neededDeut = requiredResources.Deuterium - resources.Deuterium }
|
||||
|
||||
// If we need resources, our only job this cycle is to try and get them.
|
||||
if neededMetal > 0 || neededCrystal > 0 || neededDeut > 0 {
|
||||
LogInfof("Planet %s needs resources. Required: M:%d C:%d D:%d", planetCoord, neededMetal, neededCrystal, neededDeut)
|
||||
|
||||
fleets, slots = GetFleets()
|
||||
isReceivingTransport = false
|
||||
for i = 0; i < len(fleets); i++ {
|
||||
f = fleets[i]
|
||||
if f.Mission == TRANSPORT && f.Destination.String() == planetCoord {
|
||||
isReceivingTransport = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isReceivingTransport {
|
||||
LogInfof("Waiting for incoming resources on %s.", planetCoord)
|
||||
} else {
|
||||
if len(fleets) >= slots.Total {
|
||||
LogWarnf("No free fleet slot to import resources to %s.", planetCoord)
|
||||
} else {
|
||||
missingResources = NewResources(neededMetal, neededCrystal, neededDeut)
|
||||
LogInfo("Requesting resource import from master planet.")
|
||||
importResources(planetCoord, missingResources)
|
||||
}
|
||||
}
|
||||
return // End this planet's turn. We either sent res, are waiting, or couldn't send.
|
||||
}
|
||||
|
||||
// If we've reached this point, we have enough resources and can try to build.
|
||||
LogInfo("Sufficient resources found. Attempting to build ships.")
|
||||
buildShips(planet, shipsToBuild, resources)
|
||||
}
|
||||
|
||||
func calculateShipsNeeded(currentShips) {
|
||||
needed = NewShipsInfos()
|
||||
for i = 0; i < len(SHIP_IDS_TO_BUILD); i++ {
|
||||
shipID = SHIP_IDS_TO_BUILD[i]
|
||||
targetAmount = TARGET_SHIPS.ByID(shipID)
|
||||
currentAmount = currentShips.ByID(shipID)
|
||||
if currentAmount < targetAmount {
|
||||
stillNeeded = targetAmount - currentAmount
|
||||
buildBatch = getBuildBatchSize(shipID, stillNeeded)
|
||||
if buildBatch > 0 {
|
||||
needed.Set(shipID, buildBatch)
|
||||
}
|
||||
}
|
||||
}
|
||||
return needed
|
||||
}
|
||||
|
||||
func getBuildBatchSize(shipID, stillNeeded) {
|
||||
batchSize = 0
|
||||
switch shipID {
|
||||
case LIGHTFIGHTER:
|
||||
batchSize = 200
|
||||
case HEAVYFIGHTER:
|
||||
batchSize = 150
|
||||
case CRUISER:
|
||||
batchSize = 50
|
||||
case BATTLESHIP:
|
||||
batchSize = 25
|
||||
case LARGECARGO:
|
||||
batchSize = 100
|
||||
case SMALLCARGO:
|
||||
batchSize = 100
|
||||
case RECYCLER:
|
||||
batchSize = 20
|
||||
case ESPIONAGEPROBE:
|
||||
batchSize = 0
|
||||
default:
|
||||
batchSize = 10
|
||||
}
|
||||
|
||||
if stillNeeded < batchSize {
|
||||
return stillNeeded
|
||||
}
|
||||
return batchSize
|
||||
}
|
||||
|
||||
func calculateRequiredResources(ships) {
|
||||
totalMetal = 0
|
||||
totalCrystal = 0
|
||||
totalDeut = 0
|
||||
for i = 0; i < len(SHIP_IDS_TO_BUILD); i++ {
|
||||
shipID = SHIP_IDS_TO_BUILD[i]
|
||||
quantity = ships.ByID(shipID)
|
||||
if quantity > 0 {
|
||||
cost = GetPrice(shipID, quantity)
|
||||
totalMetal += cost.Metal
|
||||
totalCrystal += cost.Crystal
|
||||
totalDeut += cost.Deuterium
|
||||
}
|
||||
}
|
||||
return NewResources(totalMetal, totalCrystal, totalDeut)
|
||||
}
|
||||
|
||||
func importResources(targetPlanetCoord, neededResources) {
|
||||
LogInfof("Importing resources to %s", targetPlanetCoord)
|
||||
masterPlanet, _ = GetPlanet(MASTER_PLANET)
|
||||
if masterPlanet == nil {
|
||||
LogErrorf("Could not get master planet %s", MASTER_PLANET)
|
||||
return
|
||||
}
|
||||
masterResources, _ = masterPlanet.GetResources()
|
||||
|
||||
availableMetal = 0
|
||||
availableCrystal = 0
|
||||
availableDeut = 0
|
||||
if masterResources.Metal > RESOURCE_THRESHOLD.Metal { availableMetal = masterResources.Metal - RESOURCE_THRESHOLD.Metal }
|
||||
if masterResources.Crystal > RESOURCE_THRESHOLD.Crystal { availableCrystal = masterResources.Crystal - RESOURCE_THRESHOLD.Crystal }
|
||||
if masterResources.Deuterium > RESOURCE_THRESHOLD.Deuterium { availableDeut = masterResources.Deuterium - RESOURCE_THRESHOLD.Deuterium }
|
||||
|
||||
toSendMetal = neededResources.Metal
|
||||
toSendCrystal = neededResources.Crystal
|
||||
toSendDeut = neededResources.Deuterium
|
||||
if toSendMetal > availableMetal { toSendMetal = availableMetal }
|
||||
if toSendCrystal > availableCrystal { toSendCrystal = availableCrystal }
|
||||
if toSendDeut > availableDeut { toSendDeut = availableDeut }
|
||||
|
||||
if toSendMetal <= 0 && toSendCrystal <= 0 && toSendDeut <= 0 {
|
||||
LogInfo("Master planet doesn't have enough resources to send")
|
||||
return
|
||||
}
|
||||
|
||||
LogInfof("Sending: M:%d C:%d D:%d", toSendMetal, toSendCrystal, toSendDeut)
|
||||
fleet = NewFleet()
|
||||
fleet.SetOrigin(MASTER_PLANET)
|
||||
fleet.SetDestination(targetPlanetCoord)
|
||||
fleet.SetSpeed(HUNDRED_PERCENT)
|
||||
fleet.SetMission(TRANSPORT)
|
||||
fleet.SetShips(*TRANSPORT_SHIPS)
|
||||
fleet.SetResources(NewResources(toSendMetal, toSendCrystal, toSendDeut))
|
||||
_, err = fleet.SendNow()
|
||||
if err != nil {
|
||||
LogErrorf("Failed to send transport: %s", err)
|
||||
} else {
|
||||
LogInfof("Transport sent to %s", targetPlanetCoord)
|
||||
}
|
||||
}
|
||||
|
||||
func buildShips(planet, shipsToBuild, resources) {
|
||||
coordinate, _ = planet.GetCoordinate()
|
||||
LogInfof("Building ships on %s", coordinate)
|
||||
|
||||
availableMetal = resources.Metal
|
||||
availableCrystal = resources.Crystal
|
||||
availableDeuterium = resources.Deuterium
|
||||
|
||||
priorityOrder = [LARGECARGO, LIGHTFIGHTER, HEAVYFIGHTER, CRUISER, BATTLESHIP, SMALLCARGO, RECYCLER]
|
||||
for i = 0; i < len(priorityOrder); i++ {
|
||||
shipID = priorityOrder[i]
|
||||
quantity = shipsToBuild.ByID(shipID)
|
||||
if quantity > 0 {
|
||||
cost = GetPrice(shipID, quantity)
|
||||
if availableMetal >= cost.Metal && availableCrystal >= cost.Crystal && availableDeuterium >= cost.Deuterium {
|
||||
err = planet.BuildShips(shipID, quantity)
|
||||
if err != nil {
|
||||
LogErrorf("Failed to build ships: %s", err)
|
||||
} else {
|
||||
LogInfof("Building %d %s", quantity, ID2Str(shipID))
|
||||
availableMetal -= cost.Metal
|
||||
availableCrystal -= cost.Crystal
|
||||
availableDeuterium -= cost.Deuterium
|
||||
}
|
||||
} else {
|
||||
LogInfof("Not enough resources for %d %s", quantity, ID2Str(shipID))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parkAllFleets() {
|
||||
LogInfo("=== Parking fleets on main planet ===")
|
||||
for i = 0; i < len(BUILDER_PLANETS); i++ {
|
||||
planetCoord = BUILDER_PLANETS[i]
|
||||
if planetCoord == MAIN_PLANET { continue }
|
||||
planet, _ = GetPlanet(planetCoord)
|
||||
if planet == nil { continue }
|
||||
ships, _ = planet.GetShips()
|
||||
|
||||
shipsToPark = NewShipsInfos()
|
||||
if ships.ByID(LIGHTFIGHTER) > 100 { shipsToPark.Set(LIGHTFIGHTER, ships.ByID(LIGHTFIGHTER) - 100) }
|
||||
if ships.ByID(HEAVYFIGHTER) > 50 { shipsToPark.Set(HEAVYFIGHTER, ships.ByID(HEAVYFIGHTER) - 50) }
|
||||
if ships.ByID(CRUISER) > 0 { shipsToPark.Set(CRUISER, ships.ByID(CRUISER)) }
|
||||
if ships.ByID(BATTLESHIP) > 0 { shipsToPark.Set(BATTLESHIP, ships.ByID(BATTLESHIP)) }
|
||||
if ships.ByID(LARGECARGO) > 20 { shipsToPark.Set(LARGECARGO, ships.ByID(LARGECARGO) - 20) }
|
||||
if ships.ByID(SMALLCARGO) > 20 { shipsToPark.Set(SMALLCARGO, ships.ByID(SMALLCARGO) - 20) }
|
||||
if ships.ByID(RECYCLER) > 5 { shipsToPark.Set(RECYCLER, ships.ByID(RECYCLER) - 5) }
|
||||
|
||||
totalToPark = 0
|
||||
for j = 0; j < len(SHIP_IDS_TO_BUILD); j++ {
|
||||
shipID = SHIP_IDS_TO_BUILD[j]
|
||||
totalToPark += shipsToPark.ByID(shipID)
|
||||
}
|
||||
|
||||
if totalToPark > 0 {
|
||||
fleets, slots = GetFleets()
|
||||
if len(fleets) >= slots.Total {
|
||||
LogWarnf("No free fleet slots to park ships from %s. Skipping.", planetCoord)
|
||||
continue
|
||||
}
|
||||
LogInfof("Parking %d ships from %s", totalToPark, planetCoord)
|
||||
fleet = NewFleet()
|
||||
fleet.SetOrigin(planetCoord)
|
||||
fleet.SetDestination(MAIN_PLANET)
|
||||
fleet.SetSpeed(HUNDRED_PERCENT)
|
||||
fleet.SetMission(PARK)
|
||||
fleet.SetShips(*shipsToPark)
|
||||
_, err = fleet.SendNow()
|
||||
if err != nil {
|
||||
LogErrorf("Failed to park fleet: %s", err)
|
||||
} else {
|
||||
LogInfof("Fleet sent to main planet from %s", planetCoord)
|
||||
}
|
||||
} else {
|
||||
LogInfof("No ships to park from %s", planetCoord)
|
||||
}
|
||||
Sleep(Random(2000, 5000))
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= MONITORING FUNCTIONS =========================
|
||||
|
||||
func printStatus() {
|
||||
LogInfo("=== Current Status ===")
|
||||
totalShips = NewShipsInfos()
|
||||
uniquePlanets = []
|
||||
uniquePlanets = uniquePlanets + [MAIN_PLANET] // FIX: Use + operator instead of append
|
||||
for i = 0; i < len(BUILDER_PLANETS); i++ {
|
||||
planetCoord = BUILDER_PLANETS[i]
|
||||
isAlreadyInList = false
|
||||
for j = 0; j < len(uniquePlanets); j++ {
|
||||
if planetCoord == uniquePlanets[j] {
|
||||
isAlreadyInList = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAlreadyInList {
|
||||
uniquePlanets = uniquePlanets + [planetCoord] // FIX: Use + operator instead of append
|
||||
}
|
||||
}
|
||||
|
||||
for i = 0; i < len(uniquePlanets); i++ {
|
||||
planetCoord = uniquePlanets[i]
|
||||
planet, _ = GetPlanet(planetCoord)
|
||||
if planet == nil { continue }
|
||||
ships, _ = planet.GetShips()
|
||||
LogInfof("Planet %s: LF:%d HF:%d CR:%d BS:%d LC:%d SC:%d Rec:%d",
|
||||
planetCoord, ships.ByID(LIGHTFIGHTER), ships.ByID(HEAVYFIGHTER),
|
||||
ships.ByID(CRUISER), ships.ByID(BATTLESHIP), ships.ByID(LARGECARGO),
|
||||
ships.ByID(SMALLCARGO), ships.ByID(RECYCLER))
|
||||
totalShips.Add(ships)
|
||||
}
|
||||
|
||||
LogInfo("---")
|
||||
LogInfo("Total ships across all planets:")
|
||||
LogInfof("Light Fighters: %d/%d", totalShips.ByID(LIGHTFIGHTER), TARGET_SHIPS.ByID(LIGHTFIGHTER))
|
||||
LogInfof("Heavy Fighters: %d/%d", totalShips.ByID(HEAVYFIGHTER), TARGET_SHIPS.ByID(HEAVYFIGHTER))
|
||||
LogInfof("Cruisers: %d/%d", totalShips.ByID(CRUISER), TARGET_SHIPS.ByID(CRUISER))
|
||||
LogInfof("Battleships: %d/%d", totalShips.ByID(BATTLESHIP), TARGET_SHIPS.ByID(BATTLESHIP))
|
||||
LogInfof("Large Cargo: %d/%d", totalShips.ByID(LARGECARGO), TARGET_SHIPS.ByID(LARGECARGO))
|
||||
LogInfof("Small Cargo: %d/%d", totalShips.ByID(SMALLCARGO), TARGET_SHIPS.ByID(SMALLCARGO))
|
||||
LogInfof("Recyclers: %d/%d", totalShips.ByID(RECYCLER), TARGET_SHIPS.ByID(RECYCLER))
|
||||
LogInfo("---")
|
||||
}
|
||||
|
||||
func forceResourceImport() {
|
||||
LogInfo("=== Forcing resource import to all planets ===")
|
||||
for i = 0; i < len(BUILDER_PLANETS); i++ {
|
||||
planetCoord = BUILDER_PLANETS[i]
|
||||
if planetCoord != MASTER_PLANET {
|
||||
importResources(planetCoord, NewResources(500000, 250000, 50000))
|
||||
Sleep(5000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func forceParkAll() {
|
||||
LogInfo("=== Forcing fleet parking ===")
|
||||
parkAllFleets()
|
||||
}
|
||||
|
||||
func showProgress() {
|
||||
printStatus()
|
||||
}
|
||||
|
||||
// ========================= STARTUP =========================
|
||||
|
||||
CronExec("0 0 * * * *", func() { printStatus() })
|
||||
CronExec("0 0 */2 * * *", func() { parkAllFleets() })
|
||||
|
||||
LogInfo("Starting Multi-Planet Ship Builder...")
|
||||
LogInfo("Commands available:")
|
||||
LogInfo(" showProgress() - Display current status")
|
||||
LogInfo(" forceResourceImport() - Manually import resources")
|
||||
LogInfo(" forceParkAll() - Manually park all fleets")
|
||||
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user