Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def __init__(self):
self.activateAutoExpedition = None
self.activateAutoColonization = None
self.activatePickingOfficers = None
self.activateAllianceScan = None
self.robotRatio = None
self.robotStartingLevel = None
self.customBuildOrdersDirectoryName = None
Expand All @@ -27,11 +28,14 @@ def __init__(self):
self.minimumSpottingTime = None
self.launchExpeditionSeparately = None
self.officersPickingOrderFile = None
self.shrib = None
self.shribCookie = None
self.watchdogDelay = None
self.watchdogExceptionDelay = None
self.watchdogEarlyDelay = None
self.watchdogWakeDuration = None

@staticmethod
def load():
config = Config()
config.loadFromFile("defaultConfig.txt")
Expand Down Expand Up @@ -70,6 +74,8 @@ def loadFromFile(self, filePath):
self.activateAutoColonization = value == "True"
elif key == "activatePickingOfficers":
self.activatePickingOfficers = value == "True"
elif key == "activateAllianceScan":
self.activateAllianceScan = value == "True"
elif key == "robotRatio":
self.robotRatio = int(value)
elif key == "robotStartingLevel":
Expand Down Expand Up @@ -98,6 +104,10 @@ def loadFromFile(self, filePath):
self.officersPickingOrderFile = value
elif key == "launchExpeditionSeparately":
self.launchExpeditionSeparately = value == "True"
elif key == "shrib":
self.shrib = value
elif key == "shribCookie":
self.shribCookie = value
elif key == "watchdogDelay":
self.watchdogDelay = int(value)
elif key == "watchdogExceptionDelay":
Expand Down Expand Up @@ -129,6 +139,10 @@ def getError(self):
return "Defender ping is activated but the user id to ping isn't configurated !"
if self.activatePickingOfficers and self.officersPickingOrderFile is None:
return "Officer picking is activated but the order isn't configurated !"
if self.activateAllianceScan and (self.shrib is None or self.shribCookie is None):
return "You need to have a shrib and a cookie !"
if self.activateAllianceScan and not self.activateAutoFleetScan:
return "Alliance scan is activated but not auto fleet scan !"
if self.watchdogDelay is None:
return "watchdogDelay isn't defined"
if self.watchdogDelay <= 0:
Expand Down
2 changes: 1 addition & 1 deletion PickOrder.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ def nextItem(self, idToItem):
levelToGet = itemsAtThisStep.get(itemId, 0) + 1 #the level it should be after getting it
itemsAtThisStep[itemId] = levelToGet
currentItem = idToItem(itemId)
if currentItem is not None and levelToGet > currentItem.level:
if currentItem is None or levelToGet > currentItem.level:
return currentItem
return None
2 changes: 1 addition & 1 deletion Planet.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def planHangarsInstead(self, b):
return buildingId

def upgradableBuildings(self, ressources):
return [bat for bat in self.batimens if bat.upgradable(ressources)]
return [bat for bat in self.batiments if bat.upgradable(ressources)]

def scan(self):
reqB = Request(self.player.ia.buildingPage + "&cp=" + str(self.id), {})
Expand Down
77 changes: 72 additions & 5 deletions Player.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,16 @@ def extractInfos(self, request=None, darkMatter=False, planets=True):
self.planets.append(pl)
pl.scan()

def getFleets(self):
techEspionageLevel = self.getTechLevel(106)
fleets = {}
def getFleets(self, page=None):
overviewRequest = Request(self.ia.overviewPage, {})
self.ia.execRequest(overviewRequest)
soup = BeautifulSoup(overviewRequest.response.content, "html.parser")
#parse all available buildings
self.getFleetsFromString(overviewRequest.response.content)

def getFleetsFromString(self, string):
techEspionageLevel = self.getTechLevel(106)
fleets = {}
soup = BeautifulSoup(string, "html.parser")
#parse all fleets
fleetsTd = soup.find_all("td", class_="fleets")
for fleetTd in fleetsTd[::-1]: #invert the list so the smallest eta overrides the latest
etaStr = fleetTd.attrs["data-fleet-end-time"]
Expand Down Expand Up @@ -134,6 +137,70 @@ def getFleets(self):
fleets[fleet.id] = fleet
self.fleets = fleets

def getFleetsFromStringFromAlliance(self, string):
techEspionageLevel = self.getTechLevel(106)
fleets = {}
soup = BeautifulSoup(string.replace("\\", ""), "html.parser")
#parse all fleets
table = soup.find_all("table", class_="table519")[0]
trs = table.find_all("tr", recursive=False)
currentPseudo = ""
currentThIndex = -1
fleetsTd = []
for tr in trs:
tds = tr.find_all("td", recursive=False)
ths = tr.find_all("th", recursive=False)
if len(ths):
currentThIndex += 1
if currentThIndex == 1: # if this is an "event" tr
if len(tds) == 1: # this is a pseudo
currentPseudo = tds[0].text
elif len(tds) == 2 and currentPseudo == self.pseudo: # this is a fleet tr and it is concerning us
fleetsTd.append(tds[0]) # yes it's hacky, but should work
for fleetTd in fleetsTd[::-1]: #invert the list so the smallest eta overrides the latest
etaStr = fleetTd.attrs["data-fleet-end-time"]
eta = float(etaStr)
id = fleetTd.attrs["id"].split(etaStr)[1] #The etaStr is appended at the end of the id
secondTd = fleetTd.parent.findAll("td")[1]
fleetsSpans = secondTd.findAll("span", recursive=False) #can be more than 1 if grouped attack
typeList = fleetsSpans[-1].attrs["class"] #the last one has the type
isGoing = (typeList[0] == "flight")
type = typeList[1]
aList = fleetsSpans[-1].findAll("a", class_=type)
ships = {}
for fleetSpan in fleetsSpans:
shipsA = fleetSpan.find("a", class_="tooltip")
if shipsA is not None and techEspionageLevel >= 8:
shipsSoup = BeautifulSoup(shipsA.attrs["data-tooltip-content"], "html.parser")
for tr in shipsSoup.findAll("tr"):
tds = tr.findAll("td")
shipType = Codes.strToId[tds[0].text[:-1]]
shipAmount = int(tds[1].text.replace(".", ""))
ships[shipType] = ships.get(shipType, 0) + shipAmount
aList = [a for a in aList if not "tooltip" in a.attrs["class"]]
originA = aList[0]
targetA = aList[1]
origin = [int(x) for x in originA.text[1:-1].split(":")]
if "Lune" in originA.previous:
origin.append(3)
elif "CDR" in originA.previous:
origin.append(2)
else:
origin.append(1)
target = [int(x) for x in targetA.text[1:-1].split(":")]
if "Lune" in targetA.previous:
target.append(3)
elif "CDR" in targetA.previous:
target.append(2)
else:
target.append(1)
fleet = Fleet(self, id, ships, origin, target, eta, type, isGoing)
ancientFleet = self.fleets.get(fleet.id)
if ancientFleet is not None:
fleet.firstSpotted = ancientFleet.firstSpotted
fleets[fleet.id] = fleet
self.fleets = fleets

def getOwnPlanetByPosition(self, position):
for p in self.planets:
if p.pos == position:
Expand Down
3 changes: 3 additions & 0 deletions buildOrders/Graviton.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#This is a comment
#If all buildings listed here are built, should the ai use it's own build logic ?
useDefaultBuildPlanWhenEmpty=False
1 change: 1 addition & 0 deletions customBuildOrdersPairingFile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
Main Planet=Mother
Colony=Colony
Colonie=Colony
Coloniee=Graviton
6 changes: 6 additions & 0 deletions defaultConfig.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ activateAutoEvasion=False
activateAutoExpedition=False
activateAutoColonization=False
activatePickingOfficers=False
activateAllianceScan=False

## AutoBuild Settings
# Ratio that will determine the level of your robot factory based on the level of your metal mine.
Expand Down Expand Up @@ -55,6 +56,11 @@ launchExpeditionSeparately=True
##Getting Officers settings
officersPickingOrderFile=officersPickingOrder.txt

##Alliance scan
#Put your url, but don't disclose it to anyone other than your alliance member
shrib=AAAAAAAAAA
shribCookie=AAAAAAAAAA

## Watchdog
# The default delay in seconds between each reinitialization of the AI
watchdogDelay=1800
Expand Down
51 changes: 50 additions & 1 deletion risistar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import heapq
import math
import random
import re
import sys
import threading
Expand Down Expand Up @@ -51,6 +52,9 @@ class IA:
battleRapportPage = "https://" + domain + "/game.php?page=raport&raport="
achievementsPage = "https://" + domain + "/game.php?page=achievements"
galaxyPage = "https://" + domain + "/game.php?page=galaxy"
alliancePage = "https://" + domain + "/game.php?page=alliance"
shribPage = "https://shrib.com/zuex/api.php"
shribCookiePage = "https://shrib.com/zuex/api."

planetNameParser = re.compile(r'>(.*) \[(.*)\]')
buildingNameParser = re.compile(r'\A([^\(]+)(?:\(.* (\d*))?')
Expand All @@ -60,6 +64,7 @@ class IA:
deutProductionParser = re.compile(r'production: ((?:\d|\.)+),\s+valueElem: "current_deuterium"')
ressourcesParser = re.compile(r'(\d+) (\w+);')
energyParser = re.compile(r'(-?\d+)./.(\d+)')
shribParser = re.compile(r'"text":"(.*)","date_save"', re.DOTALL)

def __init__(self, pseudo=None, password=None, lastCookie=None):
self.watchdog = None
Expand All @@ -71,6 +76,7 @@ def __init__(self, pseudo=None, password=None, lastCookie=None):
self.tasks = {}
self.customBuildOrderDict = {}
self._stop = False
self.lastShrib = ""
self.initialize()

def initialize(self):
Expand All @@ -80,7 +86,7 @@ def initialize(self):
self.session.headers.update({'User-Agent': self.config.userAgent})
if self.lastCookie is not None:
self.changeCookie(self.lastCookie)
self.player = Player(self.pseudo, self.password, "Risistar", self)
self.player = Player(self.pseudo, self.password, "1", self)
self.player.connexion()
self.player.extractInfos(planets=True, darkMatter=True)
self.player.scanTechs()
Expand All @@ -90,6 +96,7 @@ def initialize(self):
self.tasks[Task.highPrio ] = [] #evading ennemy fleet
self.customBuildOrderDict = {}
self._stop = False
self.lastShrib = ""
self.addTask(CheckAchievementsTask(time.time(), self.player))
if self.config.activateAutoBuild:
self.loadCustomBuildOrders()
Expand All @@ -105,6 +112,10 @@ def initialize(self):
self.addTask(PickOfficerTask(time.time(), self.player))
if self.config.activateAutoColonization:
self.addTask(ColonizeTask(time.time(), self.player))
if self.config.activateAllianceScan: # get the cookie
url = self.shribCookiePage + str(random.random()) + ".svg"
req = Request(url, {})
req.connect(self.session)

def loadCustomBuildOrders(self):
buildOrderDirectory = os.path.join(os.path.dirname(os.path.abspath(IA._file)), self.config.customBuildOrdersDirectoryName)
Expand Down Expand Up @@ -238,6 +249,44 @@ def pingUser(self, message=""):
data["content"] = "<@" + self.config.idToPing + "> " + message
self.session.post(self.config.webhookUrl, data)

def retrieveShrib(self):
if not "guetsli" in self.session.cookies.keys():
self.session.cookies["guetsli"] = self.config.shribCookie
payload = { "action": "init", "l": "", "qll": "none", "note": self.config.shrib }
req = Request(self.shribPage, payload)
req.connect(self.session)
string = req.response.content.decode('unicode_escape')
self.lastShrib = self.shribParser.findall(string)[0]

def storeShrib(self, text):
if not "guetsli" in self.session.cookies.keys():
self.session.cookies["guetsli"] = self.config.shribCookie
payload = { "ssc": "1", "note": self.config.shrib, "text": text }
req = Request(self.shribPage, payload)
req.connect(self.session)
# print(req)

def decodeShrib(self):
""" First line pseudo of current scanner
Second line until when it scans
Third line when it will scan next
Fourth line and more : content of the scan"""
lines = self.lastShrib.splitlines()
if len(lines) < 4:
return None, None, None, None
pseudo = lines[0]
stopScan = lines[1]
nextScan = lines[2]
content = "".join(lines[3:])
return pseudo, float(stopScan), float(nextScan), content

def encodeShrib(self, pseudo, stopScan, nextScan, content):
""" First line pseudo of current scanner
Second line until when it scans
Third line when it will scan next
Fourth line and more : content of the scan"""
return "%s\n%s\n%s\n%s" % (pseudo, str(stopScan), str(nextScan), content)

def simulateCombat(self, fleet1, fleet2, bonus1=[0, 0, 0], bonus2=[0, 0, 0], ressources=[0, 0, 0]):
payload = {}
payload["battleinput[0][1][901]"] = ressources[0]
Expand Down
2 changes: 1 addition & 1 deletion tasks/PickTechTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def execute(self):
# We need a bigger lab that isn't upgrading. So just wait for the next building to end.
nextBuildingTask = self.player.ia.getNextTaskOfType(PlanningTask)
if nextBuildingTask is None: # Shouldn't happen
newTaskTime = time.time() + 30
newTaskTime = time.time() + 90
else:
newTaskTime = nextBuildingTask.t + 1
newTask = PickTechTask(newTaskTime, self.player)
Expand Down
54 changes: 52 additions & 2 deletions tasks/ScanFleetsTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from tasks.Task import Task
from tasks.SendExpeditionTask import SendExpeditionTask
from Fleet import Fleet
from Request import Request
from UtilitiesFunctions import log

class ScanFleetsTask(Task):
Expand All @@ -15,7 +16,35 @@ def __init__(self, t, player, randomAdditionnalWait=None):

def execute(self):
ia = self.player.ia #just to make the lines smaller
self.player.getFleets()
if ia.config.activateAllianceScan:
ia.retrieveShrib()
pseudo, stopScan, nextScan, content = ia.decodeShrib()
willLead = False
# if there is currently no one scanning
willLead = willLead or (pseudo is None)
# or it is us
willLead = willLead or (pseudo == self.player.pseudo)
# or it is someone else that wants to stop
willLead = willLead or (pseudo != self.player.pseudo and stopScan < time.time())
# or it is someone else that slept for too long (crash?)
willLead = willLead or (pseudo != self.player.pseudo and nextScan < time.time())
if willLead: # We are the scanner => we should scan
if pseudo is None:
log(None, "Shrib empty, we will take the scan lead")
elif pseudo == self.player.pseudo:
log(None, "We are the alliance scanner for %s" % str(stopScan - time.time()))
elif pseudo != self.player.pseudo and stopScan < time.time():
log(None, "Current scanner wants to stop, we will take the scan lead")
elif pseudo != self.player.pseudo and nextScan < time.time():
log(None, "Current scanner didn't scan, we will take the scan lead")
allianceRequest = Request(ia.alliancePage, {})
ia.execRequest(allianceRequest)
self.player.getFleetsFromStringFromAlliance(allianceRequest.content)
else: # there was a scan (probably)
log(None, "We are getting scans from %s" % pseudo)
self.player.getFleetsFromStringFromAlliance(content)
else:
self.player.getFleets()
log(None, "Scanned fleets")
ennemyFleetInc = False
discordMessageToSend = ""
Expand All @@ -41,7 +70,7 @@ def execute(self):
targetPlanet.scanShips()
log(None, "Simulating combat")
rapport = self.player.ia.simulateCombat(fleet.ships, targetPlanet.ships) #TODO add defense
if rapport.combatResult == 1 or (rapport.combatResult == 0 and not fleet.isDestroy()):
if self.player.getTechLevel(106) < 8 or rapport.combatResult == 1 or (rapport.combatResult == 0 and not fleet.isDestroy()):
#if we (the defender) loose, or if it's a tie and it's not a moon destruction mission
log(None, "The incoming battle isn't in our favor, initiating evasion")
if targetPlanet.ships: #if there are some ships to send
Expand Down Expand Up @@ -86,4 +115,25 @@ def execute(self):
newExpeditionTask = SendExpeditionTask(time.time(), self.player)
ia.addTask(newExpeditionTask)
newTask = ScanFleetsTask(time.time() + ia.config.minimumTimeBetweenScans, self.player)
if ia.config.activateAllianceScan:
pseudo, stopScan, nextScan, content = ia.decodeShrib()
willTakeLead = False
# if there is currently no one scanning
willTakeLead = willTakeLead or (pseudo is None)
# or it is someone else that wants to stop
willTakeLead = willTakeLead or (pseudo != self.player.pseudo and stopScan < time.time())
# or it is someone else that slept for too long (crash?)
willTakeLead = willTakeLead or (pseudo != self.player.pseudo and nextScan < time.time())
if willTakeLead: # we begin to scan for 2 to 6 hours
log(None, "We are taking the lead for scanning for the alliance")
ia.storeShrib(ia.encodeShrib(self.player.pseudo, time.time() + 4*3600*(0.5+random.random()), newTask.t, self.player.lastRequest.content))
elif (pseudo == self.player.pseudo) : # We are the scanner => we should publish
# even if we wanted to stop, we publish with the expired stopScan time
# that way if there are others that can scan, they will probably take the lead
# and if for some reason they can't, then we are still scanning for them
log(None, "Giving other members the scans")
ia.storeShrib(ia.encodeShrib(self.player.pseudo, stopScan, newTask.t, self.player.lastRequest.content))
else:
# someone else is scanning, we wait for their scan
newTask = ScanFleetsTask(nextScan + 30, self.player, randomAdditionnalWait=0)
ia.addTask(newTask)