Пример #1
0
def extendedActionCommand(commandSegments: list[str]) -> CommandResponse:
    if len(commandSegments) < 2:
        return CommandResponse(gcs(
            flavor.getFlavourTextForMissingParamError()))

    #dicePool
    poolMatch = re.search("^(\d+)([\+-]\d+)?$", commandSegments[1])
    if poolMatch:
        basePool = int(poolMatch.group(1))
        mod = 0
        if poolMatch.group(2) != None:
            mod = int(poolMatch.group(2))

        #additional arguments
        rote = False
        explodeThres = 10
        fumbleMod = 0
        patientMod = 0
        for i in range(len(commandSegments)):
            segment = commandSegments[i].lower()
            if (segment == 'rote' or segment == 'r'):
                rote = True

            elif (segment == 'no10' or segment == 'no10again'
                  or segment == 'no10-again' or segment == 'no-10-again'):
                explodeThres = 11

            else:
                # x-again (e.g. 9again)
                againMatch = re.search("^(\d+)a(gain)?$", segment)
                if againMatch:
                    newThres = int(againMatch.group(1))
                    if newThres > 7 and newThres < 11:
                        explodeThres = newThres

                patientMatch = re.search("^p(atient)?(?P<n>[\+-]?\d+)?$",
                                         segment)
                if patientMatch:
                    customN = patientMatch.groupdict()["n"]
                    if customN != None:
                        patientMod = int(customN)
                    else:
                        patientMod = 2

                fumbleMatch = re.search("^f(umble)?(?P<n>[\+-]?\d+)$", segment)
                if fumbleMatch:
                    fumbleMod = int(fumbleMatch.groupdict()["n"])

        return CommandResponse(
            gcs(
                extendedActionAnalyzer.
                getExtendedActionSuccessProbabilitiesString(
                    basePool, mod, explodeThres, rote, fumbleMod, patientMod)))
Пример #2
0
async def cleanupCommand(commandSegments: list[str],
                         channel: discord.TextChannel) -> CommandResponse:
    if len(commandSegments) != 2:
        return CommandResponse(gcs(
            flavor.getFlavourTextForMissingParamError()))

    #check how much history we should erase
    LengthToEraseMinutes = 0
    currentValue = 0
    for char in commandSegments[1].lower():
        if char.isnumeric():
            currentValue *= 10
            currentValue += int(char)
        else:
            if char == 'w':
                LengthToEraseMinutes += currentValue * 10080
            elif char == "d":
                LengthToEraseMinutes += currentValue * 1440
            elif char == "h":
                LengthToEraseMinutes += currentValue * 60
            elif char == "m":
                LengthToEraseMinutes += currentValue
            elif char == "s":
                LengthToEraseMinutes += currentValue / 60
            else:
                return CommandResponse(
                    gcs("Unrecognized history length time denotion '") + char +
                    gcs("' out of ") + commandSegments[1])
            currentValue = 0

    #do the actual erasing
    CutoffTime = datetime.datetime.now() - datetime.timedelta(
        minutes=LengthToEraseMinutes)
    deletedCounter = 0
    if channel != None:  # pragma: no cover
        if type(channel) == discord.TextChannel:
            messages = await channel.history(after=CutoffTime).flatten()
            deletedCounter = len(messages)
            await channel.delete_messages(messages)
            return CommandResponse(
                gcs("deleted ") + str(deletedCounter) +
                gcs(" sent by this bot over the last ") +
                str(LengthToEraseMinutes) + gcs(" minutes."))
        else:
            return CommandResponse(
                gcs("Cannot delete messages from DM channel"))
    else:
        return CommandResponse(
            gcs("no messages deleted, no channel argument provided."))
Пример #3
0
def setCorruptionCommand(commandSegments: list[str]) -> CommandResponse:
    global corruptionFraction
    if len(commandSegments) == 1:
        return CommandResponse(gcs(
            flavor.getFlavourTextForMissingParamError()))
    try:
        newCorruption = float(commandSegments[1])
    except:
        return CommandResponse(
            gcs(flavor.getFlavourTextForWrongParamError() %
                commandSegments[1]))
    if newCorruption < 0 or newCorruption > 1:
        return CommandResponse(
            gcs("Corruption must be set to a value between 0 and 1, not ",
                False) + str(newCorruption))
    else:
        corruptionFraction = newCorruption
        return CommandResponse(
            gcs("Corruption succesfully set to %.2f", False) % newCorruption)
Пример #4
0
def rollInitiativeCommand(remainingCommandSegments: list[str],
                          authorName: str):
    global recentInitList
    global recentInitStaleTime

    initiativeStat = None
    modifier = None
    insertValue = None
    cleanupIfStale = True
    includeSummary = True
    characterName = authorName

    modifierIndex = -1
    characterNameOverrideIndex = -1
    insertOverrideIndex = -1

    #parse params
    for i in range(len(remainingCommandSegments)):
        currentSegmentRaw = remainingCommandSegments[i]
        currentSegment = currentSegmentRaw.lower()
        #check for custom inputs first
        if i == characterNameOverrideIndex:
            characterName = currentSegmentRaw

        elif i == modifierIndex:
            try:
                modifier = int(currentSegment)
            except ValueError:
                return CommandResponse(
                    gcs(flavor.getFlavourTextForWrongParamError()) %
                    currentSegmentRaw)

        elif (i == insertOverrideIndex):
            try:
                insertValue = int(currentSegment)
            except ValueError:
                return CommandResponse(
                    gcs(flavor.getFlavourTextForWrongParamError()) +
                    currentSegmentRaw)

        elif (currentSegment == "character" or currentSegment == "char"
              or currentSegment == "c"):
            characterNameOverrideIndex = i + 1

        elif currentSegment == "nosummary":
            includeSummary = False

        elif currentSegment == "mod":
            modifierIndex = i + 1

        elif (currentSegment == "noclean" or currentSegment == "nocleanup"):
            cleanupIfStale = False

        elif currentSegment == "insert":
            insertOverrideIndex = i + 1

        elif (currentSegment == "review" or currentSegment == "summary"):
            return CommandResponse(getInitSummaryString())

        elif (currentSegment == "clear" or currentSegment == "cleanup"):
            recentInitList = {}
            return CommandResponse(gcs("_Purging combat..._"))

        elif (currentSegment == "help"):
            return CommandResponse(
                gcs("Followed by a number stating you standard initiative modifier, this parameter is not required if a mod argument was used"
                    + "\n**__Possible Parameters:__**" +
                    "\n**character/char/c/:** followed by a charactername." +
                    "\n**nosummary:** additional parameter to supress the normal initiative order summary."
                    +
                    "\n**mod:** followed by a number, set an initiative modifier for yourself (like for weapons), either included in the roll or modified on your previously rolled initiative."
                    +
                    "\n**insert:** instead of rolling for initiative, insert into the initiative at the given initiative number."
                    +
                    "\n**review/summary:** shows the current initiative order, no other arguments required, no initiative rolled."
                    +
                    "\n**clear/cleanup:** clears the current initiative order, no other arguments required, no initiative rolled."
                    +
                    "\n\n__Example:__*\\init 5 char Thug1 mod -2* (rolls initiative for Thug1, who has a initiative modifier of 5, wielding a weapon that modifies it with -2)"
                    ))

        else:
            #set init stat
            modMatch = re.search("^\+?(\d+)$", currentSegment)
            if modMatch:
                newInit = int(modMatch.group(1))
                if initiativeStat == None:
                    initiativeStat = newInit
                else:
                    return CommandResponse(
                        gcs("initiative modifier is being set multiple times (from"
                            + str(initiativeStat) + " to " + str(newInit)))
            else:
                return CommandResponse(
                    gcs(flavor.getFlavourTextForWrongParamError()) %
                    currentSegment)

    #parameter parsing done, process result
    if (initiativeStat == None and modifier == None and insertValue == None):
        #no instruction parameters given
        return CommandResponse(gcs(
            flavor.getFlavourTextForMissingParamError()))
    else:
        replyStringSuffix = ""
        unmodifiedInitiative = 0

        #get the unmodified initiative
        if (initiativeStat == None and insertValue == None):
            #we have nothing to base our unmodified Initiative on, search for it in the recent list
            cleanupIfStale = False
            if characterName in recentInitList:
                unmodifiedInitiative = recentInitList[characterName][
                    "unmodified"]
            else:
                return CommandResponse(gcs(flavor.getFlavourTextForError()))

        elif insertValue != None:
            #we have an insert value, use that
            unmodifiedInitiative = insertValue
        else:
            #we're rolling initiative for this character
            roll = 0
            rolls = 0
            while roll == 0 or roll == 10:
                roll = random.randint(1, 10)
                rolls += 1
                unmodifiedInitiative += roll
            unmodifiedInitiative += initiativeStat
            if rolls == 2:
                replyStringSuffix += gcs(" (rerolled 1 time)")
            elif rolls > 2:
                replyStringSuffix += gcs(" (rerolled ") + str(rolls - 1) + gcs(
                    " times)")

        if modifier == None:
            modifier = 0

        totalInitiative = unmodifiedInitiative + modifier

        if includeSummary:
            if cleanupIfStale and recentInitStaleTime < datetime.datetime.now(
            ):
                recentInitList = {}
            recentInitStaleTime = datetime.datetime.now() + datetime.timedelta(
                minutes=recentInitResetTimeMinutes)
            recentInitList[characterName] = {
                "name": characterName,
                "total": totalInitiative,
                "unmodified": unmodifiedInitiative,
                "tieBreaker": random.random()
            }
            replyStringSuffix += "\r\n" + getInitSummaryString()

        return CommandResponse(
            gcs(characterName, False) + gcs(" initiative: ") +
            str(totalInitiative) + replyStringSuffix)
Пример #5
0
def rollCommand(commandSegments: list[str],
                authorName: str) -> CommandResponse:
    #handle rolling for initiative
    if (len(commandSegments) >= 3
            and (commandSegments[1].lower() == 'init'
                 or commandSegments[1].lower() == 'i'
                 or commandSegments[1].lower() == 'initiative')):
        return rollInitiativeCommand(authorName, commandSegments[2:])

    # special cases:
    #custom rolls
    if len(commandSegments) >= 2:
        #percentage roll
        if (commandSegments[1].lower() == '%'):
            percentage = random.randint(1, 100)
            return CommandResponse(gcs("result: ") + str(percentage))

        #tarot card draw
        if (commandSegments[1].lower() == 'tarot'):
            return tarotCommand()

        #tarot card draw
        if (commandSegments[1].lower() == 'alphabet'
                or commandSegments[1].lower() == 'letter'):
            return CommandResponse(
                gcs("result: ") + random.choice(string.ascii_letters))

        #coin flip
        if (commandSegments[1].lower() == 'coin'):
            return coinFlipCommand()

        #custom dice
        diceMatch = re.search("^(\d*)d(\d+)(([\+\-])([\+\d\-d]+))?$",
                              commandSegments[1])
        if diceMatch:
            return parseDiceString(commandSegments[1], True, 0, "", "", True)

    #typical roll:
    rollAmount = -1
    rote = False
    blessed = False
    blighted = False
    explodeThres = 10
    exceptionalThres = 5
    for i in range(len(commandSegments)):
        segment = commandSegments[i].lower()
        if i == 1:
            if segment.isdigit():
                rollAmount = int(segment)
            else:
                if (segment == 'chance'):
                    rollAmount = 0
        elif (segment == 'rote' or segment == 'r'):
            rote = True
        elif (segment == 'adv' or segment == 'advanced'
              or segment == 'blessed'):
            blessed = True
        elif (segment == 'blighted'):
            blighted = True
        elif (segment == 'no10' or segment == 'no10again'
              or segment == 'no10-again' or segment == 'no-10-again'):
            explodeThres = 11
        else:
            # x-again (e.g. 9again)
            againMatch = re.search("^(\d+)a(gain)?$", segment)
            if againMatch:
                newThres = int(againMatch.group(1))
                if newThres > 7 and newThres < 11:
                    explodeThres = newThres
            # exceptional at x successes
            exceptionalMatch = re.search("^(\d+)e(xceptional)?$", segment)
            if exceptionalMatch:
                newThres = int(exceptionalMatch.group(1))
                if newThres > 0:
                    exceptionalThres = newThres

    if rollAmount < 0:
        #no second parameter given
        return CommandResponse(gcs(
            flavor.getFlavourTextForMissingParamError()))
    else:
        rollResults1 = roll(rollAmount, rote, explodeThres)
        rollResults2 = None
        if blessed or blighted:
            advancedRollResults = roll(rollAmount, rote, explodeThres)
            if (advancedRollResults.successes >
                    rollResults1.successes) == blessed:
                rollResults2 = rollResults1
                rollResults1 = advancedRollResults
            else:
                rollResults2 = advancedRollResults
        return CommandResponse(
            getRollReturnMessage(rollAmount, rote, explodeThres,
                                 exceptionalThres, rollResults1, rollResults2))
Пример #6
0
async def processCommand(command :CommandPrompt) -> commands.CommandResponse:
	global clientShouldShutdown
	commandSegments = [x for x in command.command.split(' ') if len(x) > 0]
	commandID = commandSegments[0].lower()
	response = None

	if (commandID == '/roll'
		or commandID == 'roll'
		or commandID == '/r'):
		response = commands.rollCommand(commandSegments, command.authorName)
	
	elif (commandID == '/init'
		or commandID == '/initiative'):
		if len(commandSegments) >= 2:
			response =  commands.rollInitiativeCommand(commandSegments[1:], command.authorName)
		else :
			response = commands.CommandResponse(commands.gcs("_Initiative is taken, not given._"))
	
	elif commandID == '/tarot':
		response = commands.tarotCommand()
	
	elif commandID == '/coinflip':
		response = commands.coinFlipCommand()

	elif (commandID == '/choose'
		or commandID == '/choice'):
		if len(commandSegments) >= 2:
			response = commands.CommandResponse(commands.gcs("Result: " + random.choice(commandSegments[1:])))
		else :
			response = commands.CommandResponse(commands.gcs(flavor.getFlavourTextForMissingParamError()))
	
	elif commandID == "/test":
		if command.adminAuthor:
			response = commands.CommandResponse(commands.gcs("_I'm back, bitches_"))
		else :
			response = commands.CommandResponse(commands.gcs("_what, exactly?_"))
	
	elif commandID == '/refuse':
		response = commands.CommandResponse(commands.gcs("_The pawn can refuse as much as it wants, it changes nothing._"))
	
	elif commandID == '/pass':
		response = commands.CommandResponse(commands.gcs("_Apathy is the default state of being, to pass on an opportunity is to reject what little influence you have._"))
	
	elif commandID == '/impossible':
		response = commands.CommandResponse(commands.gcs("_The pawn is correct, impossiblility is a constant._"))
	
	elif commandID == '/care':
		response = commands.CommandResponse(commands.gcs("_Interesting, apathy has already set in for the subject._"))
	
	elif commandID == '/cleanup':
		if command.adminAuthor:
			response = await commands.cleanupCommand(commandSegments, command.channel)
		else:
			response = commands.CommandResponse(commands.gcs(flavor.getFlavourTextForPermissionError()))

	elif commandID == '/stop':
		response = commands.stopSound()
	
	elif (commandID == '/extend'
		or commandID == '/extended'):
		response = commands.extendedActionCommand(commandSegments)
	
	elif ("<@!" + str(client.user.id if client.user else "") + ">" in command.command
		and "SITREP" in command.command) :
		if command.adminAuthor:
			response = commands.CommandResponse(commands.gcs("_All systems nominal, ready for operations._"))
		else:
			response = commands.CommandResponse(commands.gcs(flavor.getFlavourTextForPermissionError()))
	
	elif (commandID == '/corrupt'
		or commandID == '/corruption'):
		if command.adminAuthor:
			response = commands.setCorruptionCommand(commandSegments)
		else:
			response = commands.CommandResponse(commands.gcs(flavor.getFlavourTextForPermissionError()))
	
	elif commandID == '/echo':
		response = commands.CommandResponse(commands.gcs(command.command[len(commandID)+1:].strip()))
	elif commandID == '/echosoft':
		response = commands.CommandResponse(commands.gcs(command.command[len(commandID)+1:].strip(), False))
	
	elif commandID == '/soundlist':
		response = commands.trySoundListCommand()

	elif commandID == "/shutdown":
		if command.adminAuthor:
			response = commands.CommandResponse(commands.gcs("_Affirmative, shutting down._"))
			if client.is_ready():
				clientShouldShutdown = True # pragma: no cover
			else:
				await client.shutdownGracefully()
		else:
			response = commands.CommandResponse(commands.gcs("_Threat detected, defense mechanisms active._"))
	
	else:
		#custom responses
		if commandID.startswith('/'):
			response = await commands.trySoundCommand(commandID[1:], command.member)

		if response == None:
			response = commands.handleCustomCommands(commandSegments)

	return response