# python imports import string import time import random import datetime # panda3d imports from pandac.PandaModules import * from direct.showbase import PythonUtil from direct.task import Task # toontown imports from otp.ai.AIBaseGlobal import * from otp.ai.AIZoneData import AIZoneData from direct.distributed import DistributedObjectAI from direct.directnotify import DirectNotifyGlobal from toontown.toon import InventoryBase from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownBattleGlobals from toontown.suit import DistributedSuitPlannerAI from toontown.battle import DistributedBattleBaseAI from toontown.toon import DistributedToonAI from . import WelcomeValleyManagerAI from toontown.hood import ZoneUtil from toontown.battle import SuitBattleGlobals from toontown.quest import Quests from toontown.minigame import MinigameCreatorAI from toontown.estate import DistributedPhoneAI from toontown.suit import DistributedBossCogAI from toontown.suit import DistributedSellbotBossAI from toontown.suit import DistributedCashbotBossAI from toontown.suit import DistributedLawbotBossAI from toontown.suit import DistributedBossbotBossAI from toontown.catalog import CatalogItemList from toontown.pets import PetTricks from toontown.suit import SuitDNA from toontown.toon import ToonDNA from toontown.toonbase import TTLocalizer from otp.ai import MagicWordManagerAI from toontown.estate import GardenGlobals from otp.otpbase import OTPGlobals from toontown.golf import GolfManagerAI from toontown.golf import GolfGlobals from toontown.parties import PartyGlobals from toontown.parties import PartyUtils from toontown.uberdog.DataStoreAIClient import DataStoreAIClient from toontown.uberdog import DataStoreGlobals if (simbase.wantKarts): from toontown.racing.KartDNA import * class ToontownMagicWordManagerAI(MagicWordManagerAI.MagicWordManagerAI): notify = DirectNotifyGlobal.directNotify.newCategory("ToontownMagicWordManagerAI") GameAvatarClass = DistributedToonAI.DistributedToonAI # is it a safezone? Str2szId = { 'ttc': ToontownGlobals.ToontownCentral, 'tt': ToontownGlobals.ToontownCentral, 'tc': ToontownGlobals.ToontownCentral, 'dd': ToontownGlobals.DonaldsDock, 'dg': ToontownGlobals.DaisyGardens, 'mml': ToontownGlobals.MinniesMelodyland, 'mm': ToontownGlobals.MinniesMelodyland, 'br': ToontownGlobals.TheBrrrgh, 'ddl': ToontownGlobals.DonaldsDreamland, 'dl': ToontownGlobals.DonaldsDreamland, } def __init__(self, air): MagicWordManagerAI.MagicWordManagerAI.__init__(self, air) self.__bossBattleZoneId = [None, None, None, None] self.__bossCog = [None, None, None, None] def doMagicWord(self, word, av, zoneId, senderId): def wordIs(w, word=word): return word[:(len(w)+1)] == ('%s ' % w) or word == w if (MagicWordManagerAI.MagicWordManagerAI.doMagicWord(self, word, av, zoneId, senderId) == 1): pass elif word == "~allstuff": av.inventory.maxOutInv() av.d_setInventory(av.inventory.makeNetString()) self.notify.debug("Maxing out inventory for " + av.name) elif word == "~nostuff": av.inventory.zeroInv(1) av.d_setInventory(av.inventory.makeNetString()) self.notify.debug("Zeroing inventory for " + av.name) elif word == "~restock": av.doRestock(1) elif word == "~restockUber": av.doRestock(0) elif word == "~rich": av.b_setMoney(av.maxMoney) av.b_setBankMoney(av.maxBankMoney) self.notify.debug(av.name + " is now rich") elif word == "~poor": av.b_setMoney(0) av.b_setBankMoney(0) self.notify.debug(av.name + " is now poor") elif wordIs("~jelly"): args = word.split() if len(args) > 1: count = int(args[1]) # this will just fill up the pocketbook, # but wont add to the bank av.b_setMoney(min(count, av.getMaxMoney())) else: av.b_setMoney(av.getMaxMoney()) elif wordIs("~bank"): args = word.split() if len(args) > 1: count = int(args[1]) av.b_setBankMoney(count) else: av.b_setBankMoney(av.getMaxBankMoney()) elif wordIs("~maxBankMoney"): args = word.split() if len(args) > 1: count = int(args[1]) av.b_setMaxBankMoney(count) response = "Max bank money set to %s" % (av.getMaxBankMoney()) self.down_setMagicWordResponse(senderId, response) else: response = "Max bank money is %s" % (av.getMaxBankMoney()) self.down_setMagicWordResponse(senderId, response) elif wordIs("~pie"): # Give ourselves a pie. Or four. count = 0 type = None args = word.split() if len(args) == 1: count = 1 for arg in args[1:]: from toontown.toonbase import ToontownBattleGlobals if arg in ToontownBattleGlobals.pieNames: type = ToontownBattleGlobals.pieNames.index(arg) else: try: count = int(arg) except: response = "Invalid pie argument: %s" % (arg) self.down_setMagicWordResponse(senderId, response) return if type != None: av.b_setPieType(type) av.b_setNumPies(av.numPies + count) elif word == "~amateur": av.b_setTrackAccess([0, 0, 0, 0, 1, 1, 0]) av.b_setMaxCarry(20) av.b_setQuestCarryLimit(1) av.experience.zeroOutExp() av.d_setExperience(av.experience.makeNetString()) av.b_setMaxHp(15) av.b_setHp(15) newInv = InventoryBase.InventoryBase(av) newInv.maxOutInv() av.inventory.setToMin(newInv.inventory) av.d_setInventory(av.inventory.makeNetString()) self.notify.debug("Default exp for " + av.name) elif word == "~amateur+": av.experience.setAllExp(9) av.d_setExperience(av.experience.makeNetString()) av.b_setMaxHp(30) av.b_setHp(30) # make sure we're not over maxProps too newInv = InventoryBase.InventoryBase(av) newInv.maxOutInv() av.inventory.setToMin(newInv.inventory) av.d_setInventory(av.inventory.makeNetString()) self.notify.debug("Setting exp to 9 for " + av.name) elif word == "~professional": av.b_setTrackAccess([1, 1, 1, 1, 1, 1, 1]) av.b_setMaxCarry(ToontownGlobals.MaxCarryLimit) av.b_setQuestCarryLimit(ToontownGlobals.MaxQuestCarryLimit) av.experience.maxOutExp() av.d_setExperience(av.experience.makeNetString()) av.b_setMaxHp(ToontownGlobals.MaxHpLimit) av.b_setHp(ToontownGlobals.MaxHpLimit) self.notify.debug("Max exp for " + av.name) elif word == "~professional--": av.b_setTrackAccess([1, 1, 1, 1, 1, 1, 1]) av.b_setMaxCarry(ToontownGlobals.MaxCarryLimit) av.b_setQuestCarryLimit(ToontownGlobals.MaxQuestCarryLimit) av.experience.makeExpHigh() av.d_setExperience(av.experience.makeNetString()) av.b_setMaxHp(ToontownGlobals.MaxHpLimit-15) av.b_setHp(ToontownGlobals.MaxHpLimit-15) self.notify.debug("High exp for " + av.name) elif word == "~regularToon": pickTrack = ([1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 0, 1, 1, 1], [0, 1, 1, 1, 1, 1, 1], [1, 0, 1, 1, 1, 1, 1]) av.b_setTrackAccess(random.choice(pickTrack)) av.b_setMaxCarry(ToontownGlobals.MaxCarryLimit) av.b_setQuestCarryLimit(ToontownGlobals.MaxQuestCarryLimit) av.experience.makeExpRegular() av.d_setExperience(av.experience.makeNetString()) laughminus = int(random.random() * 20.0) + 10.0 av.b_setMaxHp(ToontownGlobals.MaxHpLimit-laughminus) av.b_setHp(ToontownGlobals.MaxHpLimit-laughminus) self.notify.debug("regular exp for " + av.name) elif word == "~maxexp--": av.b_setTrackAccess([1, 1, 1, 1, 1, 1, 1]) av.b_setMaxCarry(ToontownGlobals.MaxCarryLimit) av.b_setQuestCarryLimit(ToontownGlobals.MaxQuestCarryLimit) av.experience.maxOutExpMinusOne() av.d_setExperience(av.experience.makeNetString()) av.b_setMaxHp(ToontownGlobals.MaxHpLimit) av.b_setHp(ToontownGlobals.MaxHpLimit) self.notify.debug("Max exp-- for " + av.name) elif wordIs('~mintRaider'): av.experience.maxOutExp() av.d_setExperience(av.experience.makeNetString()) av.b_setQuestHistory([]) av.b_setRewardHistory(Quests.DL_TIER+2, []) av.fixAvatar() # 7LP for fishing, + 5LP for SellbotHQ, /2 av.b_setMaxHp(av.getMaxHp()+6) av.b_setHp(av.getMaxHp()) trackAccess = [1, 1, 1, 1, 1, 1, 1] trackAccess[random.choice((0, 1, 2, 3, 6))] = 0 av.b_setTrackAccess(trackAccess) elif word[:4] == "~exp": self.doExp(word, av, zoneId, senderId) elif word[:7] == "~trophy": self.doTrophy(word, av, zoneId, senderId) elif word == "~trophies": # Report the top 10 trophy holders. scores = self.air.trophyMgr.getSortedScores() response = '' for i in range(min(len(scores), 10)): score, avId = scores[i] av = self.air.doId2do.get(avId, None) if av: avName = av.name else: avName = avId response += '%s %s\n' % (score, avName) self.down_setMagicWordResponse(senderId, response) elif word[:8] == "~effect ": # Apply a cheesy rendering effect. self.doCheesyEffect(word, av, zoneId, senderId) elif word[:12] == "~cogTakeOver": self.doCogTakeOver(word, av, zoneId, senderId) elif wordIs("~cogdoTakeOver"): if simbase.air.wantCogdominiums: self.doCogdoTakeOver(word, av, zoneId, senderId) elif word[:13] == "~toonTakeOver": self.doToonTakeOver(word, av, zoneId, senderId) elif word[:8] == "~welcome": self.doWelcome(word, av, zoneId, senderId) elif word == "~finishTutorial": av.b_setTutorialAck(1) av.b_setQuests([]) av.b_setQuestHistory([]) av.b_setRewardHistory(2, []) av.fixAvatar() self.down_setMagicWordResponse(senderId, "Finished tutorial.") elif word == "~finishQuests": self.air.questManager.completeAllQuestsMagically(av) self.down_setMagicWordResponse(senderId, "Finished quests.") elif word[:12] == "~finishQuest": args = word.split() index = int(args[1]) result = self.air.questManager.completeQuestMagically(av, index) if result: self.down_setMagicWordResponse(senderId, ("Finished quest %s." % (index))) else: self.down_setMagicWordResponse(senderId, ("Quest %s not found." % (index))) elif word == "~clearQuests": # Reset all quest fields as if this were a new toon av.b_setQuests([]) av.b_setQuestHistory([]) currentTier = av.getRewardTier() av.b_setRewardHistory(currentTier, []) self.down_setMagicWordResponse(senderId, "Cleared quests.") elif word == "~getQuestTier": # Report the current quest tier response = "tier %d" % (av.getRewardTier()) self.down_setMagicWordResponse(senderId, response) elif word[:13] == "~setQuestTier": # Sets reward tier and optionally index args = word.split() tier = int(args[1]) tier = min(tier, Quests.getNumTiers()) av.b_setQuestHistory([]) av.b_setRewardHistory(tier, []) av.fixAvatar() elif word[:12] == "~assignQuest": # Intelligently assigns a quest args = word.split() questId = int(args[1]) # Make sure this quest exists questDesc = Quests.QuestDict.get(questId) if questDesc is None: self.down_setMagicWordResponse(senderId, "Quest %s not found" % (questId)) return # Make sure the av is in that tier avTier = av.getRewardTier() tier = questDesc[Quests.QuestDictTierIndex] if tier != avTier: self.down_setMagicWordResponse(senderId, "Avatar not in that tier: %s. You can ~setQuestTier %s, if you want." % (tier, tier)) return # Make sure the av has room for this quest if not self.air.questManager.needsQuest(av): self.down_setMagicWordResponse(senderId, "Quests are already full") return # Make sure the av does not already have this quest for questDesc in av.quests: if questId == questDesc[0]: self.down_setMagicWordResponse(senderId, "Already has quest: %s" % (questId)) return # Should we check your reward history too? fromNpcId = Quests.ToonHQ # A reasonable default rewardId = Quests.getQuestReward(questId, av) # Some quests do not have a reward specified. Instead they have # the keyword which tells the quest system to try to # match something up. In our case, we are not going through # normal channels, so just pick some reward so things do not # crash. How about some jellybeans? if rewardId == Quests.Any: # Just give 100 jellybeans (rewardId = 604 from Quests.py) rewardId = 604 toNpcId = Quests.getQuestToNpcId(questId) # Account for some trickery in the quest description # If the toNpcId is marked or let's just use ToonHQ if toNpcId == Quests.Any: toNpcId = Quests.ToonHQ elif toNpcId == Quests.Same: toNpcId = Quests.ToonHQ startingQuest = Quests.isStartingQuest(questId) self.air.questManager.assignQuest(av.doId, fromNpcId, questId, rewardId, toNpcId, startingQuest, ) self.down_setMagicWordResponse(senderId, "Quest %s assigned" % (questId)) elif wordIs("~nextQuest"): # forces NPCs to offer you a particular quest args = word.split() if len(args) == 1: # clear any existing request questId = self.air.questManager.cancelNextQuest(av.doId) if questId: self.down_setMagicWordResponse( senderId, "Cancelled request for quest %s" % (questId)) return questId = int(args[1]) # Make sure this quest exists questDesc = Quests.QuestDict.get(questId) if questDesc is None: self.down_setMagicWordResponse( senderId, "Quest %s not found" % (questId)) return # Make sure the av is in that tier avTier = av.getRewardTier() tier = questDesc[Quests.QuestDictTierIndex] if tier != avTier: self.down_setMagicWordResponse(senderId, "Avatar not in that tier: %s. You can ~setQuestTier %s, if you want." % (tier, tier)) return # Make sure the av does not already have this quest for questDesc in av.quests: if questId == questDesc[0]: self.down_setMagicWordResponse( senderId, "Already has quest: %s" % (questId)) return self.air.questManager.setNextQuest(av.doId, questId) self.down_setMagicWordResponse(senderId, "Quest %s queued" % (questId)) elif word == "~visitHQ": # Sets quests to return to HQ Officer instead of whomever. # Saves walking all over the map to test quests. for quest in av.quests: quest[2] = Quests.ToonHQ av.b_setQuests(av.quests) elif wordIs('~teleportAll'): av.b_setHoodsVisited(ToontownGlobals.HoodsForTeleportAll) av.b_setTeleportAccess(ToontownGlobals.HoodsForTeleportAll) elif word[:10] == "~buildings": self.doBuildings(word, av, zoneId, senderId) elif word[:16] == "~buildingPercent": self.doBuildingPercent(word, av, zoneId, senderId) elif wordIs('~call'): self.doCall(word, av, zoneId, senderId) elif wordIs('~battle'): self.doBattle(word, av, zoneId, senderId) elif word[:5] == "~cogs": self.doCogs(word, av, zoneId, senderId) # Suit Invasions elif word[:12] == "~getInvasion": self.getCogInvasion(word, av, zoneId, senderId) elif word[:14] == "~startInvasion": self.doCogInvasion(word, av, zoneId, senderId) elif word[:13] == "~stopInvasion": self.stopCogInvasion(word, av, zoneId, senderId) # Fireworks elif word[:18] == "~startAllFireworks": self.startAllFireworks(word, av, zoneId, senderId) elif word[:15] == "~startFireworks": self.startFireworks(word, av, zoneId, senderId) elif word[:14] == "~stopFireworks": self.stopFireworks(word, av, zoneId, senderId) elif word[:17] == "~stopAllFireworks": self.stopAllFireworks(word, av, zoneId, senderId) elif word == "~save": # Save the AI state. Presently, this is just the set of # buildings. self.air.saveBuildings() response = "Building state saved." self.down_setMagicWordResponse(senderId, response) elif word[:9] == "~minigame": self.doMinigame(word, av, zoneId, senderId) elif wordIs('~factory'): # select which factory to enter # AI-global for now from toontown.coghq import FactoryManagerAI args = word.split() if len(args) == 1: # no arguments given if FactoryManagerAI.FactoryManagerAI.factoryId is None: self.down_setMagicWordResponse( senderId, "usage: ~factory [id]") else: fId = FactoryManagerAI.FactoryManagerAI.factoryId FactoryManagerAI.FactoryManagerAI.factoryId = None self.down_setMagicWordResponse( senderId, "cancelled request for factory %s" % fId) else: factoryId = int(args[1]) if not factoryId in ToontownGlobals.factoryId2factoryType: self.down_setMagicWordResponse( senderId, "unknown factory '%s'" % factoryId) else: FactoryManagerAI.FactoryManagerAI.factoryId = factoryId self.down_setMagicWordResponse( senderId, "selected factory %s" % factoryId) elif wordIs('~mintId'): args = word.split() postName = 'mintId-%s' % av.doId if len(args) < 2: if bboard.has(postName): bboard.remove(postName) response = 'cleared mint request' else: response = '~mintId id' else: try: id = int(args[1]) # make sure it's a valid id foo = ToontownGlobals.MintNumRooms[id] except: response = 'bad mint id: %s' % args[1] else: bboard.post(postName, id) response = 'selected mint %s' % id self.down_setMagicWordResponse(senderId, response) elif wordIs('~mintFloor'): args = word.split() postName = 'mintFloor-%s' % av.doId if len(args) < 2: if bboard.has(postName): bboard.remove(postName) response = 'cleared mint floor request' else: response = '~mintFloor num' else: try: floor = int(args[1]) except: response = 'bad floor index: %s' % args[1] else: bboard.post(postName, floor) response = 'selected floor %s' % floor self.down_setMagicWordResponse(senderId, response) elif wordIs('~mintRoom'): args = word.split() postName = 'mintRoom-%s' % av.doId if len(args) < 2: if bboard.has(postName): bboard.remove(postName) response = 'cleared mint room request' else: response = '~mintRoom ' else: from toontown.coghq import MintRoomSpecs id = None name = None try: id = int(args[1]) name = MintRoomSpecs.CashbotMintRoomId2RoomName[id] except: if args[1] in MintRoomSpecs.CashbotMintRoomName2RoomId: name = args[1] id = MintRoomSpecs.CashbotMintRoomName2RoomId[name] else: response = 'invalid room: %s' % args[1] bboard.post(postName, id) response = 'selected mint room %s: %s' % (id, name) self.down_setMagicWordResponse(senderId, response) elif wordIs('~stageRoom'): args = word.split() postName = 'stageRoom-%s' % av.doId if len(args) < 2: if bboard.has(postName): bboard.remove(postName) response = 'cleared stage room request' else: response = '~stageRoom ' else: from toontown.coghq import StageRoomSpecs id = None name = None try: id = int(args[1]) name = StageRoomSpecs.CashbotStageRoomId2RoomName[id] except: if args[1] in StageRoomSpecs.CashbotStageRoomName2RoomId: name = args[1] id = StageRoomSpecs.CashbotStageRoomName2RoomId[name] else: response = 'invalid room: %s' % args[1] bboard.post(postName, id) response = 'selected stage room %s: %s' % (id, name) self.down_setMagicWordResponse(senderId, response) elif wordIs("~autoRestock"): args = word.split() postName = 'autoRestock-%s' % av.doId enable = not bboard.get(postName, 0) # are they explicitly setting the state? if len(args) > 1: try: enable = int(args[1]) except: self.down_setMagicWordResponse(senderId, 'invalid state flag: %s' % args[1]) return if enable: state = 'ON' bboard.post(postName, 1) else: state = 'OFF' bboard.remove(postName) self.down_setMagicWordResponse(senderId, 'autoRestock %s' % state) elif wordIs("~resistanceRestock"): from toontown.chat import ResistanceChat args = word.split() if len(args) < 2: charges = 10 else: charges = int(args[1]) msgs = [] for menuIndex in ResistanceChat.resistanceMenu: for itemIndex in ResistanceChat.getItems(menuIndex): textId = ResistanceChat.encodeId(menuIndex, itemIndex) msgs.append([textId, charges]) av.b_setResistanceMessages(msgs) response = 'Resistance phrases restocked - %d charges' % charges self.down_setMagicWordResponse(senderId, response) elif wordIs("~restockSummons"): numSuits = len(SuitDNA.suitHeadTypes) fullSetForSuit = 0x01 | 0x02 | 0x04 allSummons = numSuits * [fullSetForSuit] av.b_setCogSummonsEarned(allSummons) self.down_setMagicWordResponse(senderId, "Summons restocked") elif wordIs("~clearSummons"): numSuits = len(SuitDNA.suitHeadTypes) allSummons = numSuits * [0] av.b_setCogSummonsEarned(allSummons) self.down_setMagicWordResponse(senderId, "Summons emptied") elif wordIs("~newSummons"): args = word.split() level = None if len(args) > 1: level = int(args[1]) if level and (level < 0 or level >= SuitDNA.suitsPerDept): self.down_setMagicWordResponse( senderId, "usage: ~newSummons [level:0-11]") else: (suitIndex, type) = av.assignNewCogSummons(level) suitName = SuitDNA.suitHeadTypes[suitIndex] suitFullName = SuitBattleGlobals.SuitAttributes[suitName]['name'] self.down_setMagicWordResponse( senderId, "%s summons added for %s" % (type, suitFullName)) elif wordIs("~treasures"): self.doTreasures(word, av, zoneId, senderId) elif wordIs("~emote"): self.doEmotes(word, av, zoneId, senderId) elif wordIs("~catalog"): self.doCatalog(word, av, zoneId, senderId) elif word == "~resetFurniture": house = None if av.houseId: house = self.air.doId2do.get(av.houseId) if house: house.setInitialFurniture() house.resetFurniture() response = "Furniture reset." else: response = "Could not find house." self.down_setMagicWordResponse(senderId, response) # Fishing elif word == "~clearFishTank": av.b_setFishTank([], [], []) self.down_setMagicWordResponse(senderId, "Cleared fish tank.") elif word == "~sellFishTank": # Add up the total value of all the fish totalValue = 0 totalValue = av.fishTank.getTotalValue() # Credit the money av.addMoney(totalValue) # Clear the fish tank av.b_setFishTank([], [], []) # Feedback to sender self.down_setMagicWordResponse(senderId, ("Sold fish in tank for %s jellbeans." % totalValue)) elif word == "~clearFishCollection": av.b_setFishCollection([], [], []) av.b_setFishingTrophies([]) self.down_setMagicWordResponse(senderId, "Cleared fish collection.") elif word == "~completeFishCollection": from toontown.fishing import FishGlobals genusList = [] speciesList = [] weightList = [] for genus in FishGlobals.getGenera(): numSpecies = len(FishGlobals.getSpecies(genus)) for species in range(numSpecies): weight = FishGlobals.getRandomWeight(genus, species) genusList.append(genus) speciesList.append(species) weightList.append(weight) av.b_setFishCollection(genusList, speciesList, weightList) self.down_setMagicWordResponse(senderId, "Complete fish collection.") elif word == "~randomFishTank": av.makeRandomFishTank() self.down_setMagicWordResponse(senderId, "Created random fishtank") elif word == "~allFishingTrophies": from toontown.fishing import FishGlobals allTrophyList = FishGlobals.TrophyDict.keys() av.b_setFishingTrophies(allTrophyList) self.down_setMagicWordResponse(senderId, "All fishing trophies") elif word[:4] == "~rod": from toontown.fishing import FishGlobals # Sets reward tier and optionally index args = word.split() rodId = int(args[1]) if ((rodId > FishGlobals.MaxRodId) or (rodId < 0)): self.down_setMagicWordResponse(senderId, ("Invalid rod: %s" % (rodId))) else: av.b_setFishingRod(rodId) self.down_setMagicWordResponse(senderId, ("New fishing rod: %s" % (rodId))) elif wordIs('~inGameEdit'): # edit a level in the game engine # Note - do not call this as a toon - call ~edit instead. That # will automatically append your level doId so the AI knows # which one you want to edit, along with your edit username # make sure this AI is set up for editing if not __dev__: self.down_setMagicWordResponse(senderId, "AI not running in dev mode") return from otp.level import EditorGlobals msg = EditorGlobals.checkNotReadyToEdit() if msg is not None: self.down_setMagicWordResponse(senderId, msg) return args = word.split() levelDoId = int(args[1]) editUsername = args[2] level = self.air.doId2do.get(levelDoId) if not level: self.down_setMagicWordResponse( senderId, ("Level %s not found" % levelDoId)) return from toontown.coghq import DistributedInGameEditorAI editor = DistributedInGameEditorAI.DistributedInGameEditorAI( self.air, level, senderId, editUsername) self.down_setMagicWordResponse( senderId, ("Editing level %s as %s" % ( levelDoId, editUsername))) elif word[:13] == "~setNPCFriend": args = word.split() npcId = int(args[1]) numCalls = int(args[2]) if self.doNpcFriend(av, npcId, numCalls): self.down_setMagicWordResponse(senderId, "added NPC friend") else: self.down_setMagicWordResponse(senderId, "invalid NPC name") elif wordIs("~pianos"): if self.doNpcFriend(av, 1116, 100): self.down_setMagicWordResponse(senderId, "got pianos") else: self.down_setMagicWordResponse(senderId, "error getting pianos") elif wordIs("~resetNPCFriendsDict"): av.resetNPCFriendsDict() self.down_setMagicWordResponse(senderId, "Reset NPC Friends Dict") elif wordIs('~uberDrop'): from toontown.toon import NPCToons if (av.attemptAddNPCFriend( 1116, DistributedToonAI.DistributedToonAI.maxCallsPerNPC ) == 1): self.down_setMagicWordResponse(senderId, "added NPC friend") else: self.down_setMagicWordResponse(senderId, "failed") elif wordIs("~bossBattle"): self.doBossBattle(word, av, zoneId, senderId) elif wordIs('~disguisePage'): args = word.split() flag = 1 if len(args) >= 2: flag = int(args[1]) av.b_setDisguisePageFlag(flag) self.down_setMagicWordResponse(senderId, "Disguise page = %s" % (flag)) elif wordIs("~allParts"): from toontown.coghq import CogDisguiseGlobals args = word.split() for dept in self.getDepts(args): parts = av.getCogParts() parts[dept] = CogDisguiseGlobals.PartsPerSuitBitmasks[dept] av.b_setCogParts(parts) self.down_setMagicWordResponse(senderId, "Set cog parts: %s" % (parts)) elif wordIs("~noParts"): args = word.split() for dept in self.getDepts(args): parts = av.getCogParts() parts[dept] = 0 av.b_setCogParts(parts) self.down_setMagicWordResponse(senderId, "Set cog parts: %s" % (parts)) elif wordIs("~part"): args = word.split() depts = self.getDepts(args) if len(args) > 1: # trust that user typed the factory type correctly... factoryType = args[1] else: factoryType = ToontownGlobals.FT_FullSuit for dept in depts: av.giveGenericCogPart(factoryType, dept) self.down_setMagicWordResponse(senderId, "Set cog parts: %s" % (av.getCogParts())) elif wordIs("~merits"): args = word.split() depts = self.getDepts(args) if len(args) > 1: numMerits = int(args[1]) if numMerits > 32767: numMerits = 32767 else: self.down_setMagicWordResponse(senderId, "Specify number of merits to set.") return merits = av.getCogMerits()[:] for dept in depts: merits[dept] = numMerits av.b_setCogMerits(merits) self.down_setMagicWordResponse(senderId, "Set cog merits: %s" % (merits)) elif wordIs("~promote"): args = word.split() depts = self.getDepts(args) for dept in depts: av.b_promote(dept) self.down_setMagicWordResponse(senderId, "Set cogTypes: %s and cogLevels: %s" % (av.getCogTypes(), av.getCogLevels())) elif wordIs("~cogSuit"): args = word.split() if len(args) > 1: cogType = args[1] else: self.down_setMagicWordResponse(senderId, "Specify cog type, or 'clear'.") return if cogType == 'clear': av.b_setCogTypes([0, 0, 0, 0]) av.b_setCogLevels([0, 0, 0, 0]) elif cogType == 'on': if len(args) > 2 and args[2] in SuitDNA.suitDepts: dept = SuitDNA.suitDepts.index(args[2]) av.b_setCogIndex(dept) else: self.down_setMagicWordResponse(senderId, "Specify dept.") return elif cogType == 'off': av.b_setCogIndex(-1) return else: dept = SuitDNA.getSuitDept(cogType) if dept == None: self.down_setMagicWordResponse(senderId, "Unknown cog type: %s" % (cogType)) return deptIndex = SuitDNA.suitDepts.index(dept) type = SuitDNA.getSuitType(cogType) minLevel = SuitBattleGlobals.SuitAttributes[cogType]['level'] # determine max level (usually minLevel + 4, but 50 for last cog) if type >= (SuitDNA.suitsPerDept - 1): maxLevel = ToontownGlobals.MaxCogSuitLevel + 1 else: maxLevel = minLevel + 4 if len(args) > 2: level = int(args[2]) - 1 if level < minLevel or level > maxLevel: self.down_setMagicWordResponse(senderId, "Invalid level for %s (should be %s to %s)" % (cogType, minLevel + 1, minLevel + 5)) return else: level = minLevel cogTypes = av.getCogTypes()[:] cogLevels = av.getCogLevels()[:] cogTypes[deptIndex] = type - 1 cogLevels[deptIndex] = level av.b_setCogTypes(cogTypes) av.b_setCogLevels(cogLevels) self.down_setMagicWordResponse(senderId, "Set cogTypes: %s and cogLevels: %s" % (av.getCogTypes(), av.getCogLevels())) elif wordIs("~pinkSlips"): args = word.split() depts = self.getDepts(args) if len(args) > 1: numSlips = int(args[1]) if numSlips > 255: numSlips = 255 else: self.down_setMagicWordResponse(senderId, "Specify number of pinkSlips to set.") return av.b_setPinkSlips(numSlips) self.down_setMagicWordResponse(senderId, "Set PinkSlips: %s" % (numSlips)) elif wordIs("~setPaid"): args = word.split() depts = self.getDepts(args) if len(args) > 1: paid = int(args[1]) if paid: paid = 1 av.b_setAccess(OTPGlobals.AccessFull) else: paid = 0 av.b_setAccess(OTPGlobals.AccessVelvetRope) else: self.down_setMagicWordResponse(senderId, "0 for unpaid 1 for paid") return self.down_setMagicWordResponse(senderId, "setPaid: %s" % (paid)) elif wordIs("~holiday"): # Start or stop a holiday holiday = 5 fStart = 1 args = word.split() if len(args) == 1: self.down_setMagicWordResponse( senderId, "Usage:\n~holiday id\n~holiday id start\n~holiday id end\n~holiday list") return elif len(args) > 1: if args[1] == 'list': self.down_setMagicWordResponse( senderId, "1: July 4\n2: New Years\n3: Halloween\n4: Winter Decorations\n5: Skelecog Invades\n6: Mr. Holly Invades\n7: Fish Bingo\n8: Species Election\n9: Black Cat\n10: Resistance Event\n11: Reset Daily Recs\n12: Reset Weekly Recs\n13: Trick-or-Treat\n14: Grand Prix\n17: Trolley Metagame") return else: holiday = int(args[1]) doPhase = None stopForever = False if len(args) > 2: if args[2] == 'start': fStart = 1 elif args[2] == 'end': fStart = 0 if len(args) > 3: if args[3] == 'forever': stopForever = True elif args[2] == 'phase': if len(args) >3 : doPhase = args[3] else: self.down_setMagicWordResponce(senderId,"need a number after phase") else: self.down_setMagicWordResponse( senderId, 'Arg 2 should be "start" or "end" or "end forever" or "phase"') return if doPhase: result = self.air.holidayManager.forcePhase(holiday, doPhase) self.down_setMagicWordResponse(senderId, "succeeded=%s forcing holiday %d to phase %s" %(result,holiday,doPhase)) elif fStart: self.down_setMagicWordResponse( senderId, "Starting holiday %d" % holiday) self.air.holidayManager.startHoliday(holiday) else: self.down_setMagicWordResponse( senderId, "Ending holiday %d stopForever=%s" % (holiday, stopForever)) self.air.holidayManager.endHoliday(holiday, stopForever) elif wordIs('~pet') and simbase.wantPets: def summonPet(petId, callback=None, zoneId=zoneId): def handleGetPet(success, pet, petId=petId, zoneId=zoneId): if success: pet.generateWithRequiredAndId(petId, self.air.districtId, zoneId) if callback is not None: callback(success, pet) self.air.petMgr.getPetObject(petId, handleGetPet) petId = av.getPetId() if petId == 0: def handleCreate(success, petId, zoneId=zoneId): if success: self.air.petMgr.assignPetToToon(petId, av.doId) def handlePetGenerated(success, pet, avId=av.doId, zoneId=zoneId): if success: pet._initDBVals( avId, traitSeed=PythonUtil.randUint31()) pet.sendSetZone(zoneId) pet.delete() # since this is the first time the pet is being # created, and we're going to be setting properties # on the pet, generate it in the Quiet zone first, # then move it to the requested zone. summonPet(petId, callback=handlePetGenerated, zoneId=ToontownGlobals.QuietZone) self.air.petMgr.createNewPetObject(handleCreate) response = 'creating new pet...' else: if petId in self.air.doId2do: response = 'pet %s already active' % petId else: summonPet(petId) response = 'summoning pet %s...' % petId self.down_setMagicWordResponse(senderId, response) elif wordIs('~dismiss') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.requestDelete() response = "pet %s dismissed" % pet.doId self.down_setMagicWordResponse(senderId, response) elif wordIs('~deletePet') and simbase.wantPets: petId = av.getPetId() if petId == 0: response = "don't have a pet" else: # if the pet is active, dismiss it pet = self.air.doId2do.get(petId) if pet is not None: pet.requestDelete() self.air.petMgr.deleteToonsPet(av.doId) response = "deleted pet %s" % petId self.down_setMagicWordResponse(senderId, response) elif wordIs('~petName') and simbase.wantPets: pet, response = self.getPet(av) if pet: args = word.split() if len(args) < 2: response = "~petName name" else: pet.b_setPetName(args[1]) response = 'name changed' self.down_setMagicWordResponse(senderId, response) elif wordIs('~feed') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.feed(av) response = "fed pet" self.down_setMagicWordResponse(senderId, response) elif wordIs('~attend') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.scratch(av) response = "attended pet" self.down_setMagicWordResponse(senderId, response) elif wordIs('~callPet') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.call(av) response = "called pet" self.down_setMagicWordResponse(senderId, response) elif wordIs('~stay') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.handleStay(av) response = "Stay, %s." % pet.getPetName() self.down_setMagicWordResponse(senderId, response) elif wordIs('~shoo') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.handleShoo(av) response = "Shoo, %s." % pet.getPetName() self.down_setMagicWordResponse(senderId, response) elif wordIs('~maxMood') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.maxMood() response = "pet mood maxed" self.down_setMagicWordResponse(senderId, response) elif wordIs('~minMood') and simbase.wantPets: pet, response = self.getPet(av) if pet: pet.minMood() response = "pet mood minimized" self.down_setMagicWordResponse(senderId, response) elif wordIs('~petMood') and simbase.wantPets: pet, response = self.getPet(av) if pet: args = word.split() if len(args) < 3: response = '~petMood component value' else: from toontown.pets import PetMood comp = args[1] value = float(args[2]) if comp not in PetMood.PetMood.Components: response = "unknown mood '%s'" % comp else: pet.mood.setComponent(comp, value) response = "mood set" self.down_setMagicWordResponse(senderId, response) elif wordIs('~moodTimescale') and simbase.wantPets: pet, response = self.getPet(av) if pet: args = word.split() if len(args) < 2: response = '~moodTimescale timescale' else: simbase.petMoodTimescale = float(args[1]) # make the new timescale take effect immediately pet.mood._driftMoodTask() response = 'pet mood timescale = %s' % args[1] self.down_setMagicWordResponse(senderId, response) elif wordIs('~typicalTraits') and simbase.wantPets: szId = None args = word.split() if len(args) > 1: szId = self.Str2szId.get(args[1]) if szId == None: szId = ToontownGlobals.ToontownCentral pet, response = self.getPet(av) if pet: pet._setTypicalTraits(szId) # delete him to make sure we don't have a pet whose # internal state is out-of-sync pet.requestDelete() response = 'set typical traits for %s' % szId self.down_setMagicWordResponse(senderId, response) elif wordIs('~medianTraits') and simbase.wantPets: szId = None args = word.split() if len(args) > 1: szId = self.Str2szId.get(args[1]) if szId == None: szId = ToontownGlobals.ToontownCentral pet, response = self.getPet(av) if pet: pet._setMedianTraits(szId) # delete him to make sure we don't have a pet whose # internal state is out-of-sync pet.requestDelete() response = 'set median traits for %s' % szId self.down_setMagicWordResponse(senderId, response) elif wordIs('~lowTraits') and simbase.wantPets: szId = None args = word.split() if len(args) > 1: szId = self.Str2szId.get(args[1]) if szId == None: szId = ToontownGlobals.ToontownCentral pet, response = self.getPet(av) if pet: pet._setLowTraits(szId) # delete him to make sure we don't have a pet whose # internal state is out-of-sync pet.requestDelete() response = 'set low traits for %s' % szId self.down_setMagicWordResponse(senderId, response) elif wordIs('~highTraits') and simbase.wantPets: szId = None args = word.split() if len(args) > 1: szId = self.Str2szId.get(args[1]) if szId == None: szId = ToontownGlobals.ToontownCentral pet, response = self.getPet(av) if pet: pet._setHighTraits(szId) # delete him to make sure we don't have a pet whose # internal state is out-of-sync pet.requestDelete() response = 'set high traits for %s' % szId self.down_setMagicWordResponse(senderId, response) elif wordIs('~leash') and simbase.wantPets: pet, response = self.getPet(av) if pet: response = pet.toggleLeash(av.doId) self.down_setMagicWordResponse(senderId, response) elif wordIs('~lockPet') and simbase.wantPets: pet, response = self.getPet(av) if pet: if pet.isLockedDown(): response = 'pet already locked down' else: pet.lockPet() response = 'pet locked down' self.down_setMagicWordResponse(senderId, response) elif wordIs('~unlockPet') and simbase.wantPets: pet, response = self.getPet(av) if pet: if not pet.isLockedDown(): response = 'pet already not locked down' else: pet.unlockPet() response = 'pet no longer locked down' self.down_setMagicWordResponse(senderId, response) elif wordIs('~attendPet') and simbase.wantPets: pet, response = self.getPet(av) if pet: response = 'attendPet' pet.handleAvPetInteraction(4, av.getDoId()) self.down_setMagicWordResponse(senderId, response) elif wordIs('~feedPet') and simbase.wantPets: pet, response = self.getPet(av) if pet: response = 'feedPet' pet.handleAvPetInteraction(3, av.getDoId()) self.down_setMagicWordResponse(senderId, response) elif wordIs('~petStress') and simbase.wantPets: from toontown.pets import DistributedPetAI args = word.split() numPets = 56 # 50 friends, six Toons/acct #100 * 3 # 500 toons, 100 at estate, 3 pets per if len(args) > 1: numPets = int(args[1]) for i in xrange(numPets): pet = DistributedPetAI.DistributedPetAI(self.air) # make up a fake owner doId pet._initFakePet(100+i, 'StressPet%s' % i) pet.generateWithRequired(zoneId) pet.setPos(randFloat(-30, 30), randFloat(-30, 30), 0) pet.b_setParent(ToontownGlobals.SPRender) elif wordIs('~petTricks') and simbase.wantPets: from toontown.pets import PetConstants, PetTricks args = word.split() trickIds = [] invalid = 0 for num in args[1:]: id = int(num) if id not in PetTricks.Tricks: invalid = 1 response = 'invalid trick ID: %s' % id break trickIds.append(id) if not invalid: av.b_setPetTrickPhrases(trickIds) response = 'set pet trick phrases: %s' % trickIds self.down_setMagicWordResponse(senderId, response) elif wordIs('~trickAptitude') and simbase.wantPets: pet, response = self.getPet(av) if pet: args = word.split() if len(args) < 2: response = '~trickAptitude aptitude' else: from toontown.pets import PetTricks pet.b_setTrickAptitudes([float(args[1])] * (len(PetTricks.Tricks)-1)) response = 'trick aptitude = %s' % args[1] self.down_setMagicWordResponse(senderId, response) elif wordIs('~spamTrick'): # spam the nearby pets with N commands to do the 'jump' trick from toontown.pets import PetObserve for i in xrange(20): PetObserve.send(av.zoneId, PetObserve.getSCObserve(21200, av.doId)) elif wordIs('~blackCat'): response = 'done' error = av.makeBlackCat() if error: response = error self.down_setMagicWordResponse(senderId, response) elif wordIs('~bingoCheat') and simbase.wantBingo: av.bingoCheat = not av.bingoCheat if av.bingoCheat: response = "Bingo cheating turned on. You will always catch boots." else: response = "Bingo cheating turned off" self.down_setMagicWordResponse(senderId, response) elif __dev__ and wordIs('~airender'): showZone = zoneId args = word.split() if len(args) > 1: showZone = int(args[1]) from otp.ai import ShowBaseAI base = ShowBaseAI.ShowBaseAI('zone %s' % showZone) base.zoneData = AIZoneData(self.air.districtId, showZone) render = base.zoneData.getRender() base.camNode.setScene(render) base.camera.reparentTo(render) render.showCS() axis = loader.loadModel('models/misc/xyzAxis') axis.reparentTo(render) axis.setPosHpr(render, 0, 0, 0, 0, 0, 0) self.down_setMagicWordResponse( senderId, 'rendering AI zone %s' % showZone) elif __dev__ and wordIs("~aics"): showZone = zoneId args = word.split() if len(args) > 1: showZone = int(args[1]) zoneData = AIZoneData(self.air.districtId, showZone) render = zoneData.getRender(showZone) csVisible = 0 if hasattr(render, 'csVisible'): csVisible = render.csVisible if csVisible: render.hideCS() action = 'hidden' else: render.showCS() action = 'shown' render.csVisible = not csVisible self.down_setMagicWordResponse( senderId, 'collisions %s for %s' % (action, showZone)) ### Karting ### elif(word[:8] == '~BuyKart'): if (simbase.wantKarts): accList = av.getKartAccessoriesOwned() #accList[-1] = getDefaultColor() accList[-2] = getDefaultRim() response = "Av %s now owns accessories: %s" % (av.getDoId(), accList) av.b_setKartAccessoriesOwned(accList) self.down_setMagicWordResponse(senderId, response) elif(word[:13] == '~BuyAccessory'): if (simbase.wantKarts): response = "Av %s attempting to buy accessory %s" % (av.getDoId(), word[14:]) av.addOwnedAccessory(int(word[14:])) self.down_setMagicWordResponse(senderId, response) elif(word[:8] == '~Tickets'): if (simbase.wantKarts): response = "Av %s now has %s tickets" % (av.getDoId(), word[9:]) av.b_setTickets(int(word[9:])) self.down_setMagicWordResponse(senderId, response) elif wordIs('~allowSoloRace'): if (simbase.wantKarts): av.setAllowSoloRace(not av.allowSoloRace) if av.allowSoloRace: response = "Av %s can now race solo" % (av.getDoId()) else: response = "Av %s can no longer Race solo" % (av.getDoId()) self.down_setMagicWordResponse(senderId, response) elif wordIs('~allowRaceTimeout'): if (simbase.wantKarts): av.setAllowRaceTimeout(not av.allowRaceTimeout) if av.allowRaceTimeout: response = "Av %s can timeout of races" % (av.getDoId()) else: response = "Av %s can not timeout of races" % (av.getDoId()) self.down_setMagicWordResponse(senderId, response) elif wordIs('~drive'): # Execute an arbitrary Python command on the AI. av.takeOutKart() self.down_setMagicWordResponse( senderId, "I feel the need... the need for SPEED!") # Golf elif wordIs("~golf"): self.doGolf(word, av, zoneId, senderId) # Mail elif wordIs("~mail"): self.doMail(word, av, zoneId, senderId) # Parties elif wordIs("~party"): self.doParty(word, av, zoneId, senderId) #Gardening elif wordIs("~garden"): self.doGarden(word, av, zoneId, senderId) elif word == "~clearGardenSpecials": newWord = '~garden clearCarriedSpecials' self.doGarden(newWord, av, zoneId, senderId) elif word == "~clearFlowerCollection": newWord = '~garden clearCollection' self.doGarden(newWord, av, zoneId, senderId) elif word == "~completeFlowerCollection": newWord = '~garden completeCollection' self.doGarden(newWord, av, zoneId, senderId) elif wordIs('~startGarden'): newWord = '~garden start' self.doGarden(newWord, av, zoneId, senderId) elif wordIs('~clearGarden'): newWord = '~garden clear' self.doGarden(newWord, av, zoneId, senderId) elif wordIs('~cannons'): sender = simbase.air.doId2do.get(senderId) if sender: zoneId = sender.zoneId estateOwnerDoId = simbase.air.estateMgr.zone2owner.get(zoneId) estate = simbase.air.estateMgr.estate.get(estateOwnerDoId) if hasattr(estate, "cannonFlag"): if estate.cannonFlag: estate.endCannons() response = "Cannons Ended" else: estate.startCannons() response = "Cannons Started" elif wordIs('~gameTable'): sender = simbase.air.doId2do.get(senderId) if sender: zoneId = sender.zoneId estateOwnerDoId = simbase.air.estateMgr.zone2owner.get(zoneId) estate = simbase.air.estateMgr.estate.get(estateOwnerDoId) if hasattr(estate, 'gameTableFlag'): if estate.gameTableFlag: estate.endGameTable() response = 'Game Table Ended' else: estate.startGameTable() response = 'Game Table Started' elif wordIs('~plantGarden'): newWord = '~garden plant' args = word.split() for i in range(1, len(args)): newWord += ' ' newWord += args[i] self.doGarden(newWord, av, zoneId, senderId) elif wordIs('~trialerCount'): total = 0 trialer =0 paid = 0 unknown = 0 allToons = simbase.air.doFindAll('DistributedToonAI') for toon in allToons: total += 1 if toon.getGameAccess() == ToontownGlobals.AccessFull: paid += 1 elif toon.getGameAccess() == ToontownGlobals.AccessVelvetRope: trialer += 1 else: unknown += 1 response = "%d trialers, %d paid, %d total" % (trialer, paid, total) if unknown: response += "%d unknown" % unknown self.down_setMagicWordResponse(senderId, response) elif wordIs('~deleteBackupStores'): storeClient = DataStoreAIClient(self.air, DataStoreGlobals.GEN, None) storeClient.deleteBackupStores() storeClient.closeStore() elif wordIs("~autoRich"): # Available only __dev__ and GMs. Guard against hacked clients sending this. If a non-GM # needs to do this on LIVE, simply use ~rich instead. if __dev__ or av.hasGMName(): # Basically this is a signal that a GM has logged in. if av.hasGMName(): self.air.writeServerEvent('GM', av.doId, 'GM %s used auto-rich' % av.getName()) assert self.notify.debug('GM %s %s used auto-rich' % (av.doId, av.getName())) args = word.split() postName = 'autoRich-%s' % av.doId enable = not bboard.get(postName, 0) # are they explicitly setting the state? if len(args) > 1: try: enable = int(args[1]) except: self.down_setMagicWordResponse(senderId, 'invalid state flag: %s' % args[1]) return if enable: state = 'ON' av.b_setMoney(av.maxMoney) av.b_setBankMoney(av.maxBankMoney) bboard.post(postName, 1) else: state = 'OFF' bboard.remove(postName) self.down_setMagicWordResponse(senderId, 'autoRich %s' % state) else: self.air.writeServerEvent('suspicious', av.doId, 'non-GM toon with name %s using ~autoRich' % av.getName()) else: # The word is not an AI-side magic word. If the sender is # different than the target avatar, then pass the magic # word down to the target client-side MagicWordManager to # execute a client-side magic word. if (senderId != av.doId): self.sendUpdateToAvatarId(av.doId, 'setMagicWord', [word, av.doId, zoneId]) def doNpcFriend(self, av, npcId, numCalls): return av.attemptAddNPCFriend(npcId, numCalls) == 1 def getDepts(self, args): # Returns a list of the dept indices specified by args[1], or # all depts if nothing is specified. If a dept is specified, # args[1] is removed from the list. depts = [] if len(args) > 1: if args[1] == 'all': depts = [0, 1, 2, 3] del args[1] else: allLettersGood = 1 for letter in args[1]: if letter in SuitDNA.suitDepts: dept = SuitDNA.suitDepts.index(letter) depts.append(dept) else: allLettersGood = 0 break if allLettersGood: del args[1] else: depts = [] if depts: return depts else: return [0, 1, 2, 3] def doExp(self, word, av, zoneId, senderId): """Handle the ~exp magic word.""" track = None args=word.split() trackIndex = -1 increment = 0 gotIncrement = 0 if len(args) > 1: trackStr = args[1] if trackStr != "all": trackIndex = ToontownBattleGlobals.Tracks.index(trackStr) if len(args) > 2: increment = int(args[2]) gotIncrement = 1 if trackIndex == -1: for trackIndex in range(ToontownBattleGlobals.MAX_TRACK_INDEX + 1): if av.hasTrackAccess(trackIndex): if not gotIncrement: # No increment specified; the default is whatever # it takes to get to the next track. increment = av.experience.getNextExpValue(trackIndex) - av.experience.getExp(trackIndex) self.notify.debug("Adding %d to %s track for %s." % (increment, ToontownBattleGlobals.Tracks[trackIndex], av.name)) av.experience.addExp(trackIndex, increment) else: if not gotIncrement: # No increment specified; the default is whatever # it takes to get to the next track. increment = av.experience.getNextExpValue(trackIndex) - av.experience.getExp(trackIndex) self.notify.debug("Adding %d to %s track for %s." % (increment, ToontownBattleGlobals.Tracks[trackIndex], av.name)) av.experience.addExp(trackIndex, increment) av.d_setExperience(av.experience.makeNetString()) def doTrophy(self, word, av, zoneId, senderId): """Handle the ~trophy magic word: artificially set (or restore) the trophy score.""" args = word.split() if len(args) > 1: score = int(args[1]) response = "Set trophy score to %s." % (score) self.down_setMagicWordResponse(senderId, response) else: # No score specified; restore the actual trophy score. score = self.air.trophyMgr.getTrophyScore(av.doId) response = "Trophy score is %s." % (score) self.down_setMagicWordResponse(senderId, response) av.d_setTrophyScore(score) def doCheesyEffect(self, word, av, zoneId, senderId): effect = None if zoneId >= ToontownGlobals.DynamicZonesBegin: hoodId = 1 else: hoodId = ZoneUtil.getCanonicalHoodId(zoneId) timeLimit = 10 args = word.split() try: effect = eval("ToontownGlobals.CE" + args[1]) except: try: effect = eval(args[1]) except: effect = None if effect == None: self.down_setMagicWordResponse(senderId, "Unknown effect %s." % (args[1])) return if len(args) > 2: timeLimit = int(args[2]) # Let it expire in timeLimit minutes. expireTime = (int)(time.time() / 60 + 0.5) + timeLimit av.b_setCheesyEffect(effect, hoodId, expireTime) def doCogTakeOver(self, word, av, zoneId, senderId): """Handle the ~cogTakeOver magic word.""" track = None level = None streetId = ZoneUtil.getBranchZone(zoneId) args = word.split() now = args.count("now") if now: args.remove("now") slow = args.count("slow") if slow: args.remove("slow") if len(args)>1: track=args[1] if track == 'x': track = None if len(args)>2: if args[2] != 'x': level=int(args[2]) level = max(min(level, 9), 1) if len(args)>4: if args[4] == 'all': streetId = 'all' else: streetId=int(args[4]) if not self.air.suitPlanners.has_key(streetId): response = "Street %d is not known." % (streetId) self.down_setMagicWordResponse(senderId, response) return if streetId == 'all': # All buildings, everywhere. blockMap = {} for sp in self.air.suitPlanners.values(): if sp.buildingMgr: blockMap[sp.buildingMgr] = sp.buildingMgr.getToonBlocks() else: # Just the buildings on this street. sp = self.air.suitPlanners[streetId] bm = sp.buildingMgr blocks = None if len(args)>3: if (args[3] == "all"): blocks = bm.getToonBlocks() elif (args[3] == "this"): blocks = None else: blocks=[int(args[3])] if blocks == None: # Try to figure out what doors we're standing in front # of. blocks = [] for i in bm.getToonBlocks(): building = bm.getBuilding(i) if hasattr(building, "door"): if building.door.zoneId == zoneId: blocks.append(i) blockMap = { bm: blocks } points = sp.streetPointList[:] failureCount = 0 minPathLen = 2 maxPathLen = 10 if slow: minPathLen = None maxPathLen = None total = 0 for bm, blocks in blockMap.items(): total += len(blocks) for i in blocks: if now: # Take over the building immediately. level, type, track = \ sp.pickLevelTypeAndTrack(level, None, track) building = bm.getBuilding(i) building.suitTakeOver(track, level - 1, None) else: # Dispatch a suit to take over the building. if not slow: # Let the suit take its time. points = sp.getStreetPointsForBuilding(i) suit = None retryCount = 0 while suit == None and len(points) > 0 and retryCount < 20: suit = sp.createNewSuit([], points, suitTrack = track, suitLevel = level, toonBlockTakeover = i, minPathLen = minPathLen, maxPathLen = maxPathLen) retryCount += 1 if suit == None: failureCount += 1 self.notify.debug("cogTakeOver %s %s %d %d" % (track, level, i, zoneId)) response = "%d buildings." % (total) if (failureCount > 0): response += " %d failed." % (failureCount) self.down_setMagicWordResponse(senderId, response) def doCogdoTakeOver(self, word, av, zoneId, senderId): """Handle the ~cogdoTakeOver magic word.""" level = None streetId = ZoneUtil.getBranchZone(zoneId) args = word.split() now = args.count("now") if now: args.remove("now") slow = args.count("slow") if slow: args.remove("slow") if len(args)>1: if args[1] != 'x': level=int(args[2]) level = max(min(level, 9), 1) if len(args)>4: if args[4] == 'all': streetId = 'all' else: streetId=int(args[4]) if not self.air.suitPlanners.has_key(streetId): response = "Street %d is not known." % (streetId) self.down_setMagicWordResponse(senderId, response) return if streetId == 'all': # All buildings, everywhere. blockMap = {} for sp in self.air.suitPlanners.values(): if sp.buildingMgr: blockMap[sp.buildingMgr] = sp.buildingMgr.getToonBlocks() else: # Just the buildings on this street. sp = self.air.suitPlanners[streetId] bm = sp.buildingMgr blocks = None if len(args)>3: if (args[3] == "all"): blocks = bm.getToonBlocks() elif (args[3] == "this"): blocks = None else: blocks=[int(args[3])] if blocks == None: # Try to figure out what doors we're standing in front # of. blocks = [] for i in bm.getToonBlocks(): building = bm.getBuilding(i) if hasattr(building, "door"): if building.door.zoneId == zoneId: blocks.append(i) blockMap = { bm: blocks } points = sp.streetPointList[:] failureCount = 0 minPathLen = 2 maxPathLen = 10 if slow: minPathLen = None maxPathLen = None total = 0 for bm, blocks in blockMap.items(): total += len(blocks) for i in blocks: if now: # Take over the building immediately. level, type, track = \ sp.pickLevelTypeAndTrack(level, None, track) building = bm.getBuilding(i) building.cogdoTakeOver(level - 1, None) else: # Dispatch a suit to take over the building. if not slow: # Let the suit take its time. points = sp.getStreetPointsForBuilding(i) suit = None retryCount = 0 while suit == None and len(points) > 0 and retryCount < 20: track = random.choice(SuitDNA.suitDepts) suit = sp.createNewSuit([], points, suitTrack = track, suitLevel = level, toonBlockTakeover = i, cogdoTakeover = True, minPathLen = minPathLen, maxPathLen = maxPathLen) retryCount += 1 if suit == None: failureCount += 1 self.notify.debug("cogdoTakeOver %s %s %d %d" % (track, level, i, zoneId)) response = "%d cogdos." % (total) if (failureCount > 0): response += " %d failed." % (failureCount) self.down_setMagicWordResponse(senderId, response) def doToonTakeOver(self, word, av, zoneId, senderId): """Handle the ~toonTakeOver magic word.""" streetId = ZoneUtil.getBranchZone(zoneId) args=word.split() if len(args)>2: if args[2] == 'all': streetId = 'all' else: streetId=int(args[2]) if not self.air.suitPlanners.has_key(streetId): response = "Street %d is not known." % (streetId) self.down_setMagicWordResponse(senderId, response) return if streetId == 'all': # All buildings, everywhere. blockMap = {} for sp in self.air.suitPlanners.values(): if sp.buildingMgr: blockMap[sp.buildingMgr] = sp.buildingMgr.getSuitBlocks() else: # Just the buildings on this street. bm=self.air.buildingManagers[streetId] blocks = None if len(args)>1: if (args[1] == "all"): blocks = bm.getSuitBlocks() elif (args[1] == "this"): blocks = None else: blocks=[int(args[1])] if blocks == None: # Try to figure out what doors we're standing in front # of. blocks = [] for i in bm.getSuitBlocks(): building = bm.getBuilding(i) if hasattr(building, "elevator"): if building.elevator.zoneId == zoneId and \ building.elevator.fsm.getCurrentState().getName() == 'waitEmpty': blocks.append(i) blockMap = { bm: blocks } total = 0 for bm, blocks in blockMap.items(): total += len(blocks) for i in blocks: building = bm.getBuilding(i) building.b_setVictorList([0, 0, 0, 0]) building.updateSavedBy([(av.doId, av.name, av.dna.asTuple())]) building.toonTakeOver() self.notify.debug("Toon take over %s %s" % (i, streetId)) response = "%d buildings." % (total) self.down_setMagicWordResponse(senderId, response) def formatWelcomeValley(self, hood): mgr = self.air.welcomeValleyManager if hood == mgr.newHood: return "%s N" % (hood[0].zoneId) elif hood in mgr.removingHoods: return "%s R" % (hood[0].zoneId) else: return "%s" % (hood[0].zoneId) def doWelcome(self, word, av, zoneId, senderId): """Handle the ~welcome magic word, for managing Welcome Valley.""" args = word.split() hoodId = ZoneUtil.getHoodId(zoneId) mgr = self.air.welcomeValleyManager # if this is a GS hoodId, just grab the TT hood if (hoodId % 2000) < 1000: hood = mgr.welcomeValleys.get(hoodId) else: hood = mgr.welcomeValleys.get(hoodId - 1000) if len(args) == 1: # No parameter: report the current zone and population. if hood == None: response = "Not in Welcome Valley." else: response = "%s, pg = %s, hood = %s" % ( self.formatWelcomeValley(hood), hood[0].getPgPopulation(), hood[0].getHoodPopulation()) elif args[1] == "pg": # ~welcome pg: list the playground population of all # Welcome Valleys. response = "" hoodIds = mgr.welcomeValleys.keys() hoodIds.sort() for hoodId in hoodIds: hood = mgr.welcomeValleys[hoodId] response += "\n%s %s" % ( self.formatWelcomeValley(hood), hood[0].getPgPopulation()) if response == "": response = "No Welcome Valleys." else: response = response[1:] elif args[1] == "hood": # ~welcome hood: list the hood population of all # Welcome Valleys. response = "" hoodIds = mgr.welcomeValleys.keys() hoodIds.sort() for hoodId in hoodIds: hood = mgr.welcomeValleys[hoodId] response += "\n%s %s" % ( self.formatWelcomeValley(hood), hood[0].getHoodPopulation()) if response == "": response = "No Welcome Valleys." else: response = response[1:] elif args[1] == "login": # ~welcome login avId: simulate a new player logging in. # avId is an arbitrary number which should probably not # match any real avatars. avId = int(args[2]) zoneId = mgr.avatarRequestZone(avId, ToontownGlobals.WelcomeValleyToken) response = "%s assigned to %s." % (avId, zoneId) elif args[1] == "logout": # ~welcome logout avId: simulate a player logging out. # avId is an arbitrary number which should probably not # match any real avatars. avId = int(args[2]) avZoneId = mgr.avatarZones.get(avId) if avZoneId: mgr.avatarLogout(avId) response = "%s logged out from %s." % (avId, avZoneId) else: response = "%s is unknown." % (avId) elif args[1] == "zone": # ~welcome zone avId [zoneId]: simulate a player switching # zones. avId is an arbitrary number which should # probably not match any real avatars. avId = int(args[2]) if len(args) > 3: newZoneId = int(args[3]) else: newZoneId = zoneId zoneId = mgr.avatarRequestZone(avId, newZoneId) response = "%s redirected to %s." % (avId, zoneId) elif args[1] == "new": # ~welcome new [hoodId]: immediately move the indicated # (or current) hood to the New pool. if len(args) > 2: hoodId = int(args[2]) else: hoodId = zoneId response = mgr.makeNew(hoodId) elif args[1] == "stable": # ~welcome stable [hoodId]: immediately move the indicated # (or current) hood to the Stable pool. if len(args) > 2: hoodId = int(args[2]) else: hoodId = zoneId response = mgr.makeStable(hoodId) elif args[1] == "remove": # ~welcome remove [hoodId]: immediately move the indicated # (or current) hood to the Removing pool. if len(args) > 2: hoodId = int(args[2]) else: hoodId = zoneId response = mgr.makeRemoving(hoodId) elif args[1] == "check": # ~welcome check: check that our record logged-in avatars # are actually real avatars; logs out any others. removed = mgr.checkAvatars() if removed: response = "Logged out %s phony avatars." % (len(removed)) else: response = "All avatars real." elif args[1] == "parms": # ~welcome parms [min stable max]: report or adjust the # balancing parameters. if len(args) == 5: PGminimum = int(args[2]) PGstable = int(args[3]) PGmaximum = int(args[4]) WelcomeValleyManagerAI.PGminimum = PGminimum WelcomeValleyManagerAI.PGstable = PGstable WelcomeValleyManagerAI.PGmaximum = PGmaximum response = "min = %s, stable = %s, max = %s" % ( WelcomeValleyManagerAI.PGminimum, WelcomeValleyManagerAI.PGstable, WelcomeValleyManagerAI.PGmaximum) else: response = "Invalid welcome command: %s" % (args[1]) self.down_setMagicWordResponse(senderId, response) def __sortBuildingDist(self, a, b): return a[0] - b[0] def doBuildings(self, word, av, zoneId, senderId): """Handle the ~buildings magic word.""" streetId = ZoneUtil.getBranchZone(zoneId) if word == "~buildings where": # "~buildings where": report the distribution of buildings. dist = {} for sp in self.air.suitPlanners.values(): if sp.buildingMgr: numActual = len(sp.buildingMgr.getSuitBlocks()) if not dist.has_key(numActual): dist[numActual] = [] dist[numActual].append(sp.zoneId) # Sort the distribution by number of buildings. sorted = [] for tuple in dist.items(): sorted.append(tuple) sorted.sort(self.__sortBuildingDist) # Now format the distribution into a text response. response = "" for numActual, zones in sorted: if numActual != 0: response += "\n%s: %d" % (zones, numActual) if response == "": response = "No cog buildings." else: response = response[1:] else: # "~buildings zoneId" or "~buildings all" args=word.split() if len(args) > 1: if args[1] == "all": streetId = "all" else: streetId = int(args[1]) if streetId == "all": numTarget = 0 numActual = 0 numTotalBuildings = 0 numAttempting = 0 numPerTrack = {} numPerHeight = {} for sp in self.air.suitPlanners.values(): numTarget += sp.targetNumSuitBuildings if sp.buildingMgr: numActual += len(sp.buildingMgr.getSuitBlocks()) numTotalBuildings += len(sp.frontdoorPointList) numAttempting += sp.numAttemptingTakeover sp.countNumBuildingsPerTrack(numPerTrack) sp.countNumBuildingsPerHeight(numPerHeight) response = "Overall, %d cog buildings (%s, %s) out of %d; target is %d. %d cogs are attempting takeover." % ( numActual, sp.formatNumSuitsPerTrack(numPerTrack), sp.formatNumSuitsPerTrack(numPerHeight), numTotalBuildings, numTarget, numAttempting) elif not self.air.suitPlanners.has_key(streetId): response = "Street %d is not known." % (streetId) else: sp = self.air.suitPlanners[streetId] numTarget = sp.targetNumSuitBuildings if sp.buildingMgr: numActual = len(sp.buildingMgr.getSuitBlocks()) else: numActual = 0 numTotalBuildings = len(sp.frontdoorPointList) numAttempting = sp.numAttemptingTakeover numPerTrack = {} numPerHeight = {} sp.countNumBuildingsPerTrack(numPerTrack) sp.countNumBuildingsPerHeight(numPerHeight) response = "Street %d has %d cog buildings (%s, %s) out of %d; target is %d. %d cogs are attempting takeover." % ( streetId, numActual, sp.formatNumSuitsPerTrack(numPerTrack), sp.formatNumSuitsPerTrack(numPerHeight), numTotalBuildings, numTarget, numAttempting) self.down_setMagicWordResponse(senderId, response) def doBuildingPercent(self, word, av, zoneId, senderId): """Handle the ~buildingPercent magic word.""" percent = None args=word.split() if len(args) > 1: percent = int(args[1]) if percent == None: response = "Suit building target percentage is %d" % (DistributedSuitPlannerAI.DistributedSuitPlannerAI.TOTAL_SUIT_BUILDING_PCT) else: DistributedSuitPlannerAI.DistributedSuitPlannerAI.TOTAL_SUIT_BUILDING_PCT = percent sp = self.air.suitPlanners.values()[0] sp.assignInitialSuitBuildings() response = "Reset target percentage to %d" % (percent) self.down_setMagicWordResponse(senderId, response) def doCall(self, word, av, zoneId, senderId): """Handle the ~call magic word.""" streetId = ZoneUtil.getBranchZone(zoneId) args=word.split() name = None level = None skelecog = None revives = None if len(args) > 1: name = args[1] if name == 'x': name = None if len(args) > 2: level = int(args[2]) if len(args) > 3: skelecog = int(args[3]) if len(args) > 4: revives = int(args[4]) if not self.air.suitPlanners.has_key(streetId): response = "Street %d is not known." % (streetId) else: sp = self.air.suitPlanners[streetId] map = sp.getZoneIdToPointMap() canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId) if not map.has_key(canonicalZoneId): response = "Zone %d isn't near a suit point." % (canonicalZoneId) else: points = map[canonicalZoneId][:] suit = sp.createNewSuit([], points, suitName = name, suitLevel = level, skelecog = skelecog, revives = revives) if suit: response = "Here comes %s." % (SuitBattleGlobals.SuitAttributes[suit.dna.name]['name']) else: response = "Could not create suit." self.down_setMagicWordResponse(senderId, response) def doBattle(self, word, av, zoneId, senderId): """Handle the ~battle magic word.""" # There's no easy way to find the battle that the caller is # near or involved in. We'll have to walk through all the # battles currently in the doId2do map. battle = self.__findInvolvedBattle(av.doId) if battle == None: battle = self.__findBattleInZone(zoneId) if battle == None: response = "No battle in zone %s." % (zoneId) else: args = word.split() if len(args) < 2: response = "Battle %s in state %s" % (battle.doId, battle.fsm.getCurrentState().getName()) elif args[1] == 'abort': battle.abortBattle() response = "Battle %s aborted." % (battle.doId) else: response = "Uknown battle command %s" % (args[1]) self.down_setMagicWordResponse(senderId, response) def __findInvolvedBattle(self, avId): """Returns the battle, if any, in which the indicated avatar is a participant, or None if the avatar is not involved in any battles.""" for dobj in self.air.doId2do.values(): if (isinstance(dobj, DistributedBattleBaseAI.DistributedBattleBaseAI)): if avId in dobj.toons: return dobj def __findBattleInZone(self, zoneId): """Returns the battle, if any, in the indicated zoneId, or None if no battle is occurring in the indicated zone.""" for dobj in self.air.doId2do.values(): if (isinstance(dobj, DistributedBattleBaseAI.DistributedBattleBaseAI)): if dobj.zoneId == zoneId: return dobj def doCogInvasion(self, word, av, zoneId, senderId): """Handle the ~invasion magic word.""" invMgr = self.air.suitInvasionManager if invMgr.getInvading(): cogType = invMgr.getCogType() numRemaining = invMgr.getNumCogsRemaining() cogName = SuitBattleGlobals.SuitAttributes[cogType[0]]['name'] response = ("Invasion already in progress: %s, %s" % (cogName, numRemaining)) else: args=word.split() if len(args) < 3 or len(args) > 4: response = "Error: Must specify cogType and numCogs" else: cogType = args[1] numCogs = int(args[2]) if len(args) == 4: skeleton = int(args[3]) else: skeleton = 0 cogNameDict = SuitBattleGlobals.SuitAttributes.get(cogType) if cogNameDict: cogName = cogNameDict['name'] if skeleton: cogName = TTLocalizer.Skeleton + " " + cogName if invMgr.startInvasion(cogType, numCogs, skeleton): response = ("Invasion started: %s, %s" % (cogName, numCogs)) else: response = ("Invasion failed: %s, %s" % (cogName, numCogs)) else: response = ("Unknown cogType: %s" % (cogType)) self.down_setMagicWordResponse(senderId, response) def stopCogInvasion(self, word, av, zoneId, senderId): invMgr = self.air.suitInvasionManager if invMgr.getInvading(): self.air.suitInvasionManager.stopInvasion() response = ("Invasion stopped.") else: response = ("No invasion found.") self.down_setMagicWordResponse(senderId, response) def getCogInvasion(self, word, av, zoneId, senderId): invMgr = self.air.suitInvasionManager if invMgr.getInvading(): cogType, skeleton = invMgr.getCogType() numRemaining = invMgr.getNumCogsRemaining() cogName = SuitBattleGlobals.SuitAttributes[cogType]['name'] if skeleton: cogName = TTLocalizer.Skeleton + " " + cogName response = ("Invasion is in progress: %s, %s remaining" % (cogName, numRemaining)) else: response = ("No invasion found.") self.down_setMagicWordResponse(senderId, response) def startAllFireworks(self, word, av, zoneId, senderId): fMgr = self.air.fireworkManager fMgr.stopAllShows() fMgr.startAllShows(None) response = "Shows started in all hoods." self.down_setMagicWordResponse(senderId, response) def startFireworks(self, word, av, zoneId, senderId): fMgr = self.air.fireworkManager if fMgr.isShowRunning(zoneId): response = ("Show already running in zone: %s" % (zoneId)) else: args=word.split() if len(args) == 2: showType = int(args[1]) if fMgr.startShow(zoneId, showType, 1): response = ("Show started, showType: %s" % showType) else: response = ("Show failed, showType: %s" % showType) else: # Default to showType 0 response = (TTLocalizer.startFireworksResponse \ %( ToontownGlobals.NEWYEARS_FIREWORKS, \ PartyGlobals.FireworkShows.Summer, \ ToontownGlobals.JULY4_FIREWORKS)) self.down_setMagicWordResponse(senderId, response) def stopFireworks(self, word, av, zoneId, senderId): if self.air.fireworkManager.stopShow(zoneId): response = ("Show stopped, zoneId: %s" % zoneId) else: response = ("Show stop failed, zoneId: %s" % zoneId) self.down_setMagicWordResponse(senderId, response) def stopAllFireworks(self, word, av, zoneId, senderId): numStopped = self.air.fireworkManager.stopAllShows() response = ("Stopped %s firework show(s)" % (numStopped)) self.down_setMagicWordResponse(senderId, response) def doCogs(self, word, av, zoneId, senderId): """Handle the ~cogs magic word.""" streetId = ZoneUtil.getBranchZone(zoneId) args=word.split() firstKeyword = 1 sync = 0 fly = 0 count = -1 if len(args) > 1: if args[1] == "all": streetId = "all" firstKeyword = 2 else: try: streetId = int(args[1]) firstKeyword = 2 except: pass # Check for extra keywords. for k in range(firstKeyword, len(args)): word = args[k] if word == "sync": sync = 1 elif word == "fly": fly = 1 elif word == "count=x": count = None elif word[:6] == "count=": count = int(word[6:]) else: self.down_setMagicWordResponse(senderId, "invalid keyword %s" % (word)) return if streetId == "all": numTarget = 0 numActual = 0 numPerTrack = {} sp = None for sp in self.air.suitPlanners.values(): numTarget += sp.calcDesiredNumFlyInSuits() + sp.calcDesiredNumBuildingSuits() numActual += sp.numFlyInSuits + sp.numBuildingSuits sp.countNumSuitsPerTrack(numPerTrack) if sync: sp.resyncSuits() if fly: sp.flySuits() if count != -1: sp.currDesired = count if sp == None: response = "No cogs active." else: response = "Overall, %d cogs (%s); target is %d." % ( numActual, sp.formatNumSuitsPerTrack(numPerTrack), numTarget) elif not self.air.suitPlanners.has_key(streetId): response = "Street %d is not known." % (streetId) else: sp = self.air.suitPlanners[streetId] numTarget = sp.calcDesiredNumFlyInSuits() + sp.calcDesiredNumBuildingSuits() numActual = sp.numFlyInSuits + sp.numBuildingSuits numPerTrack = {} sp.countNumSuitsPerTrack(numPerTrack) if sync: sp.resyncSuits() if fly: sp.flySuits() if count != -1: sp.currDesired = count response = "Street %d has %d cogs (%s); target is %d." % ( streetId, numActual, sp.formatNumSuitsPerTrack(numPerTrack), numTarget) self.down_setMagicWordResponse(senderId, response) def doMinigame(self, word, av, zoneId, senderId): """Handle the ~minigame magic word: request a particular minigame.""" args = word.split() if len(args) == 1: # No minigame parameter specified: clear the request. mgRequest = MinigameCreatorAI.RequestMinigame.get(av.doId) if mgRequest != None: mgId = mgRequest[0] del MinigameCreatorAI.RequestMinigame[av.doId] response = "Request for minigame %d cleared." % (mgId) else: response = "Usage: ~minigame [ [difficulty] [safezone]]" else: # Try to determine the minigame id, keep flag, and the difficulty # and safezone overrides, if any name = args[1] mgId = None mgKeep = 0 mgDiff = None mgSzId = None try: mgId = int(name) numMgs = len(ToontownGlobals.MinigameIDs) if mgId < 1 or mgId > numMgs or mgId not in ToontownGlobals.MinigameIDs: response = "minigame ID '%s' is out of range" % mgId mgId = None except: name = string.lower(name) if name[-4:] == "game": name = name[:-4] if name[:11] == "distributed": name = name[11:] mgId = ToontownGlobals.MinigameNames.get(name) if mgId == None: response = "Unknown minigame '%s'." % (name) argIndex = 2 while argIndex < len(args): arg = args[argIndex] arg = string.lower(arg) argIndex += 1 # it's either a difficulty (float), 'keep', # or a safezone (string) # is it 'keep'? if arg == 'keep': mgKeep = 1 continue # is it a difficulty? try: mgDiff = float(arg) continue except: pass mgSzId = self.Str2szId.get(arg) if mgSzId is not None: continue # it's a string, but it's not a safezone. response = ("unknown safezone '%s'; use " "tt, dd, dg, mm, br, dl" % arg) mgId = None break if mgId != None: # mdId must be the first element MinigameCreatorAI.RequestMinigame[av.doId] = ( mgId, mgKeep, mgDiff, mgSzId) response = "Selected minigame %d" % mgId if mgDiff is not None: response += ", difficulty %s" % mgDiff if mgSzId is not None: response += ", safezone %s" % mgSzId if mgKeep: response += ", keep=true" self.down_setMagicWordResponse(senderId, response) def doTreasures(self, word, av, zoneId, senderId): """Handle the ~treasures magic word: fill up the safezone with treasures.""" args = word.split() hood = None for h in self.air.hoods: if h.zoneId == zoneId: hood = h break if hood == None or hood.treasurePlanner == None: self.down_setMagicWordResponse(senderId, "Not in a safezone.") return tp = hood.treasurePlanner if len(args) == 1: # No parameter: report the current treasure count. response = "%s treasures." % (tp.numTreasures()) elif args[1] == "all": # ~treasures all: fill up all available treasures. tp.placeAllTreasures() response = "now %s treasures." % (tp.numTreasures()) else: response = "Invalid treasures command: %s" % (args[1]) self.down_setMagicWordResponse(senderId, response) def doEmotes(self, word, av, zoneId, senderId): """Handle the ~emote magic word: turns on/off the specified emotion""" args = word.split() if len(args) == 1: # No parameter specified: clear the request. response = "No emote specified." elif len(args) == 2: # No parameter specified: clear the request. response = "Need to specify 0 or 1." else: emoteId = int(args[1]) on = int(args[2]) if emoteId > len(av.emoteAccess) or emoteId < 0: response = "Not a valid emote" elif on not in [0, 1]: response = "Not a valid bit" else: av.setEmoteAccessId(emoteId, on) if on: response = "Emote %d enabled" % emoteId else: response = "Emote %d disabled" % emoteId self.down_setMagicWordResponse(senderId, response) def doCatalog(self, word, av, zoneId, senderId): """Handle the ~catalog magic word: manage catalogs""" now = time.time() args = word.split() # There may be an optional "after" parameter on many of these # commands, which specifies the number of minutes to delay # before doing the action. afterMinutes = 0 if "after" in args: a = args.index("after") afterMinutes = int(args[a + 1]) del args[a + 1] del args[a] if len(args) == 1: # No parameter: report the current catalog. duration = (av.catalogScheduleNextTime * 60) - time.time() response = "Week %d, next catalog in %s." % \ (av.catalogScheduleCurrentWeek, PythonUtil.formatElapsedSeconds(duration)) elif args[1] == "next": # ~catalog next: advance to the next catalog. week = av.catalogScheduleCurrentWeek + 1 self.air.catalogManager.forceCatalog(av, week, afterMinutes) response = "Issued catalog for week %s." % (week) elif args[1] == "week": # ~catalog week n: force to the catalog of the nth week. # Note: need to have catalog-skip-seeks set to true to jump # more than one week week = int(args[2]) if week > 0: self.air.catalogManager.forceCatalog(av, week, afterMinutes) response = "Forced to catalog week %s." % (week) else: response = "Invalid catalog week %s." % (week) elif args[1] == "season": # ~catalog season mm/dd: regenerate the monthly catalog # items as if it were the indicated month and day. if len(args) == 3: mmdd = args[2].split('/') mm = int(mmdd[0]) dd = int(mmdd[1]) else: mm = int(args[2]) dd = int(args[3]) self.air.catalogManager.forceMonthlyCatalog(av, mm, dd) response = "%s items for %d/%0d." % (len(av.monthlyCatalog), mm, dd) elif (args[1] == "clear") or (args[1] == "reset"): # ~catalog clear: reset the catalog (and the back catalog) # to its initial state. av.b_setCatalog(CatalogItemList.CatalogItemList(), CatalogItemList.CatalogItemList(), CatalogItemList.CatalogItemList()) av.catalogScheduleCurrentWeek = 0 av.catalogScheduleNextTime = 0 self.air.catalogManager.deliverCatalogFor(av) response = "Catalog reset." elif args[1] == "deliver": # ~catalog deliver: force the immediate delivery of all # of the on-order item(s). now = (int)(time.time() / 60 + 0.5) deliveryTime = now + afterMinutes for item in av.onOrder: item.deliveryDate = deliveryTime av.onOrder.markDirty() av.b_setDeliverySchedule(av.onOrder) response = "Delivered %s item(s)." % (len(av.onOrder)) elif args[1] in ["reload", "dump"]: # These commands are handled by the client; we ignore them. return else: response = "Invalid catalog command: %s" % (args[1]) self.down_setMagicWordResponse(senderId, response) def doDna(self, word, av, zoneId, senderId): """Handle the ~dna magic word: change your dna""" # Strip of the "~dna" part; everything else is parameters to # AvatarDNA.updateToonProperties. parms = string.strip(word[4:]) # Get a copy of the avatar's current DNA. dna = ToonDNA.ToonDNA(av.dna.makeNetString()) # Modify it according to the user's parameter selection. eval("dna.updateToonProperties(%s)" % (parms)) av.b_setDNAString(dna.makeNetString()) response = "%s" % (dna.asTuple(),) self.down_setMagicWordResponse(senderId, response) def getPet(self, av): response = None pet = None petId = av.getPetId() if petId == 0: response = "don't have a pet" else: pet = self.air.doId2do.get(petId) if pet is None: response = "pet not active, use ~pet" return pet, response def doBossBattle(self, word, av, zoneId, senderId): """Handle the ~bossBattle magic word: manage a final boss battle.""" args = word.split() # Find the particular Boss Cog that's in the same zone with # the avatar. bossCog = None for distObj in self.air.doId2do.values(): if isinstance(distObj, DistributedBossCogAI.DistributedBossCogAI): if distObj.zoneId == zoneId: bossCog = distObj break if bossCog == None: # The caller isn't in a zone with a Boss Cog; use the # default Boss zone. # In this case, we must accept a dept indicator. if len(args) < 2 or args[1] not in SuitDNA.suitDepts: response = "Error: Must specify boss dept: s, m, l, c" self.down_setMagicWordResponse(senderId, response) return dept = args[1] del args[1] deptIndex = SuitDNA.suitDepts.index(dept) if self.__bossBattleZoneId[deptIndex] == None: # Make up a new zone for the battle. zoneId = self.air.allocateZone() self.__bossBattleZoneId[deptIndex] = zoneId bossCog = self.makeBossCog(dept, zoneId) bossCog.b_setState('Frolic') self.__bossCog[deptIndex] = bossCog else: bossCog = self.__bossCog[deptIndex] response = None if len(args) == 1: # No parameter: send the avatar to the battle zone. self.sendUpdateToAvatarId(av.doId, 'requestTeleport', ["cogHQLoader", "cogHQBossBattle", bossCog.getHoodId(), bossCog.zoneId, 0]) elif args[1] == "list": # ~bossBattle [smlc] list: list the current boss battles # underway for the indicated type of suit. response = "" for bc in DistributedBossCogAI.AllBossCogs: if bc.dept == bossCog.dept and bc != bossCog: response += ", %s %s %s" % (bc.zoneId, bc.state, len(bc.involvedToons)) if response: response = response[2:] else: response = "No boss battles." elif args[1] == "spy": # ~bossBattle spy [smlc] : go visit the indicated # boss battle in ghost mode. zoneId = int(args[2]) bc = bossCog for bc in DistributedBossCogAI.AllBossCogs: if bc.zoneId == zoneId: break if bc.zoneId == zoneId: self.sendUpdateToAvatarId(av.doId, 'requestTeleport', ["cogHQLoader", "cogHQBossBattle", bc.getHoodId(), bc.zoneId, 0]) av.b_setGhostMode(2) else: response = "No boss battle in zone %s" % (zoneId) elif args[1] == "start": # ~bossBattle start: restart the boss battle. if not bossCog.hasToons(): response = "No toons." else: response = "Elevator started." bossCog.acceptNewToons() bossCog.b_setState('WaitForToons') elif args[1] == "one": # ~bossBattle one: straight to battle one. if not bossCog.hasToons(): response = "No toons." else: response = "Battle one started." bossCog.acceptNewToons() bossCog.makeBattleOneBattles() bossCog.b_setState('BattleOne') elif args[1] == "preTwo": # ~bossBattle preTwo: preview to battle two. if not bossCog.hasToons(): response = "No toons." elif not hasattr(bossCog, 'enterRollToBattleTwo'): response = "Battle two preview." bossCog.acceptNewToons() bossCog.b_setState('PrepareBattleTwo') else: response = "Battle two preview." bossCog.acceptNewToons() bossCog.b_setState('RollToBattleTwo') elif args[1] == "two": # ~bossBattle two: straight to battle two. if not bossCog.hasToons(): response = "No toons." else: response = "Battle two started." bossCog.acceptNewToons() if hasattr(bossCog, 'makeBattleTwoBattles'): bossCog.makeBattleTwoBattles() bossCog.b_setState('BattleTwo') elif args[1] == "preThree": # ~bossBattle preThree: preview to battle three. if not bossCog.hasToons(): response = "No toons." else: response = "Battle three preview." bossCog.acceptNewToons() bossCog.b_setState('PrepareBattleThree') elif args[1] == "three": # ~bossBattle three: straight to battle three. if not bossCog.hasToons(): response = "No toons." else: response = "Battle three started." bossCog.acceptNewToons() bossCog.b_setState('BattleThree') elif args[1] == "preFour": # ~bossBattle preFour: preview to battle four. if not bossCog.hasToons(): response = "No toons." else: response = "Battle four preview." bossCog.acceptNewToons() bossCog.b_setState('PrepareBattleFour') elif args[1] == "four": # ~bossBattle four: straight to battle four. if not bossCog.hasToons(): response = "No toons." else: response = "Battle four started." bossCog.acceptNewToons() bossCog.b_setState('BattleFour') elif args[1] == "victory": # ~bossBattle victory: straight to the victory sequence. if not bossCog.hasToons(): response = "No toons." else: response = "Victory sequence started." bossCog.acceptNewToons() bossCog.b_setState('Victory') elif args[1] == "fsm": # ~bossBattle fsm state: directly to named state. if len(args) <= 2: response = "No state specified." else: response = "Requested state %s." % (args[2]) bossCog.b_setState(args[2]) elif args[1] == "stop": # ~bossBattle start: stop the boss battle. response = "Battle stopped." bossCog.acceptNewToons() bossCog.b_setState('Frolic') elif args[1] == "hit": # ~bossBattle hit [damage]: hit the boss cog during the # pie scene. This will make him dizzy first if he is not # already dizzy (as if we successfully lobbed a pie into # the undercarriage) and then applies the indicated damage # (as if we hit his upper body the indicated number of # times). if len(args) <= 2: damage = 1 else: damage = int(args[2]) ## ## this is very suspect .. it is reasigning a internal var(msgSender).. ## it is trying to make the message look like it came from a difrent avatarID ## to other areas of the code .. ??? self.air.msgSender = av.doId bossCog.magicWordHit(damage, av.doId) elif args[1] == "safe": # ~bossBattle safe: Ignore hits to the toon during the pie # scene. This magic word is handled by the client. pass elif args[1] == "avatarEnter": # ~bossBattle avatarEnter: Force a call to d_avatarEnter #This magic word is handled by the client. pass elif args[1] == "stun": # ~bossBattle stun: stun all of the goons in the CFO # battle. This magic word is handled by the client. pass elif args[1] == "destroy": # ~bossBattle destroy: destroy all of the goons in the CFO # battle. This magic word is handled by the client. pass elif args[1] == "reset": # ~bossBattle reset: reset all of the goons, cranes, and # safes in the CFO sequence. bossCog.magicWordReset() elif args[1] == "goons": # ~bossBattle goons [num]: reset all of the goons and set # the number to the indicated value. if len(args) > 2: bossCog.maxGoons = int(args[2]) bossCog.magicWordResetGoons() elif args[1] == "toggleMove": # make the ceo toggle doing move attacks if hasattr(bossCog, 'toggleMove'): doingMoveAttack = bossCog.toggleMove() response = "doing move attack = %s" % doingMoveAttack else: response = "toggleMove is only for CEO" else: response = "Invalid bossBattle command: %s" % (args[1]) if response: self.down_setMagicWordResponse(senderId, response) def makeBossCog(self, dept, zoneId): bossCog = None if dept == 's': bossCog = DistributedSellbotBossAI.DistributedSellbotBossAI(self.air) bossCog.generateWithRequired(zoneId) bossCog.b_setState('Frolic') elif dept == 'm': bossCog = DistributedCashbotBossAI.DistributedCashbotBossAI(self.air) bossCog.generateWithRequired(zoneId) elif dept == 'l': bossCog = DistributedLawbotBossAI.DistributedLawbotBossAI(self.air) bossCog.generateWithRequired(zoneId) bossCog.b_setState('Frolic') elif dept == 'c': bossCog = DistributedBossbotBossAI.DistributedBossbotBossAI(self.air) bossCog.generateWithRequired(zoneId) bossCog.b_setState('Frolic') else: raise StandardError('Not implemented: boss cog %s' % (dept)) return bossCog def doGarden(self, word, av, zoneId, senderId): """Handle the ~garden magic worde.""" args = word.split() response = None action = None if len(args) == 1: # No parameter: change it to usage self.down_setMagicWordResponse( senderId, "Usage:\n~garden action \n'~garden help' for more info ") return action = args[1] if action == 'help': response = 'start\nclear\nwilt \nunwilt \nplant \nclearCarriedSpecials\nclearCollection\ncompleteCollection\nwater \nshovel <0-3> \nrandomBasket\nnuke\nepoch \nwateringCan <0-3> ' elif action == 'start': messenger.send("gardenTest", [senderId]) response = "Test Garden Planted" elif action == 'clear': messenger.send("gardenClear", [senderId]) response = "Garden Cleared" elif action == 'nuke': #clear the garden and remove the planters #clear the garden started flag messenger.send("gardenNuke", [senderId]) av.b_setGardenStarted(False) response = "Garden Nuked" elif action == 'specials': #messenger.send("gardenSpecials", [senderId]) receiver = self.air.doId2do.get(senderId) if receiver: receiver.giveMeSpecials() response = "Garden Specials Added" elif action == 'wilt': if len(args) >= 3: messenger.send("wiltGarden", [senderId, int(args[2])] ) else: messenger.send("wiltGarden", [senderId]) response = "Garden wilted" elif action == 'unwilt': if len(args) >= 3: messenger.send("unwiltGarden", [senderId, int(args[2])] ) else: messenger.send("unwiltGarden", [senderId]) response = "Garden unwilted" elif action == 'water': waterLevel = 1 if len(args) > 2: waterLevel = int(args[2]) specificHardPoint = -1 if len(args) > 3: specificHardPoint = int(args[3]) messenger.send("waterGarden", [senderId, waterLevel, specificHardPoint] ) response = "water level changed to %d" % waterLevel elif action == 'growth': waterLevel = 1 if len(args) > 2: waterLevel = int(args[2]) specificHardPoint = -1 if len(args) > 3: specificHardPoint = int(args[3]) messenger.send("growthGarden", [senderId, waterLevel, specificHardPoint] ) response = "growth level changed to %d" % waterLevel elif action == 'plant': type = 0 plot = 0 water = 0 growth = 1 variety = 0 if len(args) > 2: type = int(args[2]) if len(args) > 3: plot = int(args[3]) if len(args) > 4: water = int(args[4]) if len(args) > 5: growth = int(args[5]) if len(args) > 6: variety = int(args[6]) response = "Planting type=%d plot=%d water=%d growth=%d" % (type,plot,water,growth) messenger.send("gardenPlant", [senderId, type, plot, water, growth, variety]) elif action == 'clearCarriedSpecials': av.b_setGardenSpecials( []) response = "Cleared garden specials carried by toon" elif action == 'clearCollection': av.b_setFlowerCollection( [], []) response = "Cleared flower collection." elif action == 'completeCollection': #from toontown.estate import GardenGlobals varietyList = [] speciesList = [] flowerSpecies = GardenGlobals.getFlowerSpecies() for species in flowerSpecies: numVarieties = len(GardenGlobals.getFlowerVarieties(species)) for variety in range(numVarieties): speciesList.append(species) varietyList.append(variety) av.b_setFlowerCollection( speciesList, varietyList) av.b_setGardenTrophies([]) response = "Complete flower collection." elif action == 'epoch': numEpoch = 1 if len(args) > 2: numEpoch = int(args[2]) messenger.send("epochGarden", [senderId, numEpoch]) response = "%d garden epoch has been run" % numEpoch elif action == 'shovel': if len(args) < 3: response = "specify a shovel (0-3)" else: shovel = 0 passedShovel = int(args[2]) if passedShovel >= 0 and \ passedShovel < GardenGlobals.MAX_SHOVELS: shovel = passedShovel skill =0 if len(args) >= 4: passedSkill = int(args[3]) skill = min (passedSkill, GardenGlobals.ShovelAttributes[shovel]['skillPts'] - 1) skill = max (skill, 0) av.b_setShovel(shovel) av.b_setShovelSkill(skill) response = "Set shovel=%d shovelSkill=%d" % (shovel,skill) elif action == 'wateringCan': if len(args) < 3: response = "specify a watering can (0-3)" else: wateringCan = 0 passedWateringCan = int(args[2]) if passedWateringCan >= 0 and \ passedWateringCan < GardenGlobals.MAX_WATERING_CANS: wateringCan = passedWateringCan skill =0 if len(args) >= 4: passedSkill = int(args[3]) skill = min (passedSkill, GardenGlobals.WateringCanAttributes[wateringCan]['skillPts'] - 1) skill = max (skill, 0) av.b_setWateringCan(wateringCan) av.b_setWateringCanSkill(skill) response = "Set wateringCan=%d wateringCanSkill=%d" % (wateringCan,skill) elif action == 'randomBasket': av.makeRandomFlowerBasket() self.down_setMagicWordResponse(senderId, "Created random flower basket") elif action == "allTrophies": allTrophyList = GardenGlobals.TrophyDict.keys() av.b_setGardenTrophies(allTrophyList) self.down_setMagicWordResponse(senderId, "All garden trophies") else: response = 'Invalid garden command.' if response: self.down_setMagicWordResponse(senderId, response) def doGolf(self, word, av, zoneId, senderId): """Handle the ~golf magic words.""" args = word.split() response = None action = None if len(args) == 1: # No parameter: change it to usage self.down_setMagicWordResponse( senderId, "Usage:\n~golf action \n'~golf help' for more info ") return action = args[1] if action == 'help': response = 'endHole\nendcourse\ntest\nclearHistory\nMaxHistory' elif action == 'drive': course = GolfManagerAI.GolfManagerAI().findGolfCourse(senderId) response = "drive failed." if course: result = course.toggleDrivePermission(senderId) if result: response = "Press up, down, left&right simultaneously to drive." else: response = "Toon is no longer driving." elif action == 'endhole' or action == 'endHole': course = GolfManagerAI.GolfManagerAI().findGolfCourse(senderId) if course: holeId, holeDoId = course.abortCurrentHole() response = "Aborting holeId %d, doId=%d" % (holeId, holeDoId) else: response = "Couldn't find golf course" elif action == 'endcourse' or action == 'endCourse': course = GolfManagerAI.GolfManagerAI().findGolfCourse(senderId) if course: course.setCourseAbort() response = "Aborting course %d" % course.doId else: response = "Couldn't find golf course" elif action == 'test': #messenger.send("gardenTest", [senderId]) response = "golf test" avList = [senderId]; args = word.split() import string for i in range(2, len(args)): avList.append(string.atoi(args[i])) manager = GolfManagerAI.GolfManagerAI() #simbase.golfGoer.generateWithRequired(OTPGlobals.UberZone) courseId = 0 zoneId = manager.readyGolfCourse(avList, courseId) for avId in avList: golfer = simbase.air.doId2do.get(avId) if golfer: golfer.sendUpdate("sendToGolfCourse", [zoneId]) response = 'sending to golf course %d courseId=%d' % \ (zoneId, courseId) elif action == 'clearBest': response = 'clearBest failed' av = simbase.air.doId2do.get(senderId) if av: emptyHoleBest = [0] * 18 av.b_setGolfHoleBest(emptyHoleBest) emptyCourseBest = [0] * 3 av.b_setGolfCourseBest(emptyCourseBest) response = 'golf best cleared' elif action == 'maxBest': response = 'maxBest failed' av = simbase.air.doId2do.get(senderId) if av: emptyHoleBest = [1] * 18 av.b_setGolfHoleBest(emptyHoleBest) emptyCourseBest = [1] * 3 av.b_setGolfCourseBest(emptyCourseBest) response = 'golf best maxed' elif action == 'clearHistory': response = 'clearHistory failed' emptyHistory = [0] * 18 av = simbase.air.doId2do.get(senderId) if av: av.b_setGolfHistory(emptyHistory) response = 'golf history cleared' elif action == 'maxHistory': response = 'maxHistory failed' maxHistory = [600] * 18 av = simbase.air.doId2do.get(senderId) if av: av.b_setGolfHistory(maxHistory) response = 'golf history maxeded' elif action == 'midHistory': # set it up so that we just need one more course complete to get a cup response = 'midHistory failed' midHistory = [0] * 18 midHistory[GolfGlobals.CoursesCompleted] = GolfGlobals.TrophyRequirements[GolfGlobals.CoursesCompleted][1] - 1 #midHistory = [GolfGlobals.CoursesUnderPar] = GolfGlobals.TrophyRequirements[GolfGlobals.CoursesUnderPar][0] midHistory[GolfGlobals.HoleInOneShots] = GolfGlobals.TrophyRequirements[GolfGlobals.HoleInOneShots][0] midHistory[GolfGlobals.EagleOrBetterShots] = GolfGlobals.TrophyRequirements[GolfGlobals.EagleOrBetterShots][0] midHistory[GolfGlobals.BirdieOrBetterShots] = GolfGlobals.TrophyRequirements[GolfGlobals.BirdieOrBetterShots][0] midHistory[GolfGlobals.ParOrBetterShots] = GolfGlobals.TrophyRequirements[GolfGlobals.ParOrBetterShots][0] midHistory[GolfGlobals.MultiPlayerCoursesCompleted] = GolfGlobals.TrophyRequirements[GolfGlobals.MultiPlayerCoursesCompleted][0] midHistory[GolfGlobals.CourseZeroWins] = GolfGlobals.TrophyRequirements[GolfGlobals.CourseZeroWins][0] midHistory[GolfGlobals.CourseOneWins] = GolfGlobals.TrophyRequirements[GolfGlobals.CourseOneWins][0] midHistory[GolfGlobals.CourseTwoWins] = GolfGlobals.TrophyRequirements[GolfGlobals.CourseTwoWins][0] av = simbase.air.doId2do.get(senderId) if av: av.b_setGolfHistory(midHistory) response = 'golf history midded' elif action == 'unlimitedSwing' or action == "us": av.b_setUnlimitedSwing(not av.getUnlimitedSwing()) if av.getUnlimitedSwing(): response = "Av %s has an unlimited swing" % (av.getDoId()) else: response = "Av %s does NOT have unlimited swings" % (av.getDoId()) elif action == 'hole': import string manager = GolfManagerAI.GolfManagerAI() if len(args) <= 2: # No minigame parameter specified: clear the request. holeRequest = GolfManagerAI.RequestHole.get(av.doId) if holeRequest != None: holeId = holeRequest[0] del GolfManagerAI.RequestHole[av.doId] response = "Request for hole %d cleared." % (holeId) else: response = "Usage: ~golf hole []" else: holeId = None holeKeep = 0 name = args[2] try: holeId = int(name) if holeId not in GolfGlobals.HoleInfo: response = "hole ID '%s' is out of range" % holeId holeId = None except: #name = string.lower(name) #for testHoleId in GolfGlobals.HoleInfo: # holeName = string.lower(GolfGlobals.getHoleName(testHoleId)) # if name == holeName: # holeId = testHoleId # break; if holeId == None: response = "Unknown hole '%s'." % (name) argIndex = 2 while argIndex < len(args): arg = args[argIndex] arg = string.lower(arg) argIndex += 1 # it's either a difficulty (float), 'keep', # or a safezone (string) # is it 'keep'? if arg == 'keep': holeKeep = 1 continue if holeId != None: # hoId must be the first element GolfManagerAI.RequestHole[av.doId] = ( holeId, holeKeep) response = "Selected hole %d as 1st hole" % holeId if holeKeep: response += ", keep=true" if response: self.down_setMagicWordResponse(senderId, response) def doMail(self,word, av, zoneId, senderId): """Handle mail magic words.""" args = word.split() response = None action = None if len(args) == 1: # No parameter: change it to usage self.down_setMagicWordResponse( senderId, "Usage:\n~mail action \n'~mail help' for more info ") return action = args[1] if action == 'simple': if len(args) < 4: response = "~mail simple 'text'" else: recipient = int(args[2]) text = args[3] for i in xrange(4, len(args)): text += ' ' + args[i] self.air.mailManager.sendSimpleMail( senderId, recipient, text) if response: self.down_setMagicWordResponse(senderId, response) def doParty(self,word, av, zoneId, senderId): """Handle mail magic words.""" args = word.split() response = None action = None if len(args) == 1: # No parameter: change it to usage self.down_setMagicWordResponse( senderId, "Available commands: plan, new, update, checkStart, end, debugGrid") return action = args[1] if action == 'new': if len(args) < 2: response = "~party new ... " else: invitees = [] for i in xrange(2, len(args)): invitees.append( int(args[i])) # start the party 1 minute from now startTime = datetime.datetime.now(self.air.toontownTimeManager.serverTimeZone) + datetime.timedelta(minutes=-1) endTime = startTime + datetime.timedelta(hours=PartyGlobals.DefaultPartyDuration) from toontown.parties.PartyEditorGrid import PartyEditorGrid # Make the avatar rich. av.b_setMaxBankMoney(5000) av.b_setMoney(av.maxMoney) av.b_setBankMoney(av.maxBankMoney) gridEditor = PartyEditorGrid(None) # Flip on the Y so it matches the grid in-game. gridEditor.grid.reverse() # Given a center coord (x or y) and a size (w or h), returns a list of indices in # in the grid on that axis. (WARNING: Can return invalid indices.) def gridComputeRange(centerGrid, size): result = [] if size == 1: result = [centerGrid] else: # Need to round with negative values otherwise for center=0, size=3, the # result will be [1, 0] when we expect [1, 0, -1]. # The range without rounding: range(int(1.5), int(-1.5), -1) # The range with rounding: range(int(1.5), int(-2), -1) # Not a problem with center>=2 in this example: # The range without rounding: range(int(3.5), int(0.5), -1) # The range with rounding: range(int(3.5), int(0), -1) result = range(int(centerGrid + size/2.0), int(centerGrid - round(size/2.0)), -1) # The result list should be the same size as given. assert len(result) == size, "Bad result range: c=%s s=%s result=%s" % (centerGrid, size, result) return result # Returns true if the given space is available centered at x,y with dims w,h. def gridIsAvailable(x, y, w, h): for j in gridComputeRange(y, h): if 0 > j or j >= len(gridEditor.grid): return False for i in gridComputeRange(x, w): if 0 > i or i >= len(gridEditor.grid[0]): return False if gridEditor.grid[j][i] == None: return False #print("grid available: xy(%s %s) wh(%s %s)" % (x, y, w, h)) return True # Returns the first x,y (centered) that has space for w,h. def gridGetAvailable(w, h): for y in range(len(gridEditor.grid)): for x in range(len(gridEditor.grid[0])): if gridIsAvailable(x, y, w, h): return x, y return None, None # Returns True and an x,y (centered) coord for the given space. Marks that space used. def gridTryPlace(w, h): x, y = gridGetAvailable(w, h) if not x == None: for j in gridComputeRange(y, h): for i in gridComputeRange(x, w): gridEditor.grid[j][i] = None return True, x, y else: return False, None, None actualActIdsToAdd = [ #PartyGlobals.ActivityIds.PartyJukebox, # mut.ex: PartyJukebox40 PartyGlobals.ActivityIds.PartyCannon, #PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityIds.PartyCatch, #PartyGlobals.ActivityIds.PartyDance, # mut.ex: PartyDance20 PartyGlobals.ActivityIds.PartyTugOfWar, PartyGlobals.ActivityIds.PartyFireworks, PartyGlobals.ActivityIds.PartyClock, PartyGlobals.ActivityIds.PartyJukebox40, PartyGlobals.ActivityIds.PartyDance20, PartyGlobals.ActivityIds.PartyCog, PartyGlobals.ActivityIds.PartyVictoryTrampoline, # victory party ] actualDecorIdsToAdd = [ PartyGlobals.DecorationIds.BalloonAnvil, PartyGlobals.DecorationIds.BalloonStage, PartyGlobals.DecorationIds.Bow, PartyGlobals.DecorationIds.Cake, PartyGlobals.DecorationIds.Castle, PartyGlobals.DecorationIds.GiftPile, PartyGlobals.DecorationIds.Horn, PartyGlobals.DecorationIds.MardiGras, PartyGlobals.DecorationIds.NoiseMakers, PartyGlobals.DecorationIds.Pinwheel, PartyGlobals.DecorationIds.GagGlobe, #PartyGlobals.DecorationIds.BannerJellyBean, PartyGlobals.DecorationIds.CakeTower, #PartyGlobals.DecorationIds.HeartTarget, # valentoons #PartyGlobals.DecorationIds.HeartBanner, # valentoons #PartyGlobals.DecorationIds.FlyingHeart, # valentoons PartyGlobals.DecorationIds.Hydra, # 16: victory party PartyGlobals.DecorationIds.BannerVictory, # 17: victory party PartyGlobals.DecorationIds.CannonVictory, # 18: victory party PartyGlobals.DecorationIds.CogStatueVictory, # 19: victory party PartyGlobals.DecorationIds.TubeCogVictory, # 20: victory party PartyGlobals.DecorationIds.cogIceCreamVictory, # 21: victory party ] activities = [] for itemId in actualActIdsToAdd: item = PartyGlobals.ActivityInformationDict[itemId] success, x, y = gridTryPlace(*item['gridsize']) if success: print("~party new ADDED: Activity %s %s at %s, %s" % (itemId, str(item['gridsize']), x, y)) # item index, grid x, grid y, heading partyItem = (itemId, x, y, 0) activities.append(partyItem) else: print("~party new SKIPPED: No room for activity %s" % itemId) decorations = [] for itemId in actualDecorIdsToAdd: item = PartyGlobals.DecorationInformationDict[itemId] success, x, y = gridTryPlace(*item['gridsize']) if success: print("~party new ADDED: Decoration %s %s at %s, %s" % (itemId, str(item['gridsize']), x, y)) # item index, grid x, grid y, heading partyItem = (itemId, x, y, 0) decorations.append(partyItem) else: print("~party new SKIPPED: No room for decoration %s" % itemId) isPrivate = False inviteTheme = PartyGlobals.InviteTheme.Birthday self.air.partyManager.addPartyRequest( senderId, startTime.strftime("%Y-%m-%d %H:%M:%S"), endTime.strftime("%Y-%m-%d %H:%M:%S"), isPrivate, inviteTheme, activities, decorations, invitees, ) # force an immediate check of which parties can start self.air.partyManager.forceCheckStart() elif action == 'update': # simulate this avatarLogging in, which forces invites # and party updates from the dbs self.air.partyManager.partyUpdate(senderId) elif action == 'checkStart': # force an immediate check of which parties can start self.air.partyManager.forceCheckStart() elif action == 'unreleasedServer': newVal = self.air.partyManager.toggleAllowUnreleasedServer() response = "Allow Unreleased Server= %s" % newVal elif action == 'canBuy': newVal = self.air.partyManager.toggleCanBuyParties() response = "can buy parties= %s" % newVal elif action == 'end': response = self.air.partyManager.magicWordEnd(senderId) elif action == 'plan': response = "Going to party grounds to plan" # hoodId determines the loading hoodId = ToontownGlobals.PartyHood self.sendUpdateToAvatarId(av.doId, 'requestTeleport', ["safeZoneLoader", "party", hoodId, 0, 0]) if response: self.down_setMagicWordResponse(senderId, response)