diff --git a/toontown/makeatoon/BodyShop.py b/toontown/makeatoon/BodyShop.py index 39a634d..7e18328 100644 --- a/toontown/makeatoon/BodyShop.py +++ b/toontown/makeatoon/BodyShop.py @@ -48,10 +48,10 @@ class BodyShop(StateData.StateData): self.__swapHead(0) self.__swapTorso(0) self.__swapLegs(0) - choicePool = [ToonDNA.toonHeadTypes, torsoPool, ToonDNA.toonLegTypes] + self.__swapEyelashes(0) + choicePool = [ToonDNA.toonHeadTypes, torsoPool, ToonDNA.toonLegTypes, [0, 1]] self.shuffleButton.setChoicePool(choicePool) self.accept(self.shuffleFetchMsg, self.changeBody) - self.acceptOnce('last', self.__handleBackward) self.accept('next', self.__handleForward) self.acceptOnce('MAT-newToonCreated', self.shuffleButton.cleanHistory) self.restrictHeadType(self.dna.head) @@ -131,6 +131,44 @@ class BodyShop(StateData.StateData): shuffleArrowDown, shuffleArrowRollover, shuffleArrowDisabled), image_scale=halfButtonInvertScale, image1_scale=halfButtonInvertHoverScale, image2_scale=halfButtonInvertHoverScale, pos=(0.2, 0, 0), command=self.__swapLegs, extraArgs=[1]) + # Creates the eyelashes frame + self.eyelashesFrame = DirectFrame( + parent=self.parentFrame, + image=shuffleFrame, + image_scale=halfButtonInvertScale, + relief=None, + pos=(0, 0, -0.9), + hpr=(0, 0, 3), + scale=0.9, + frameColor=(1, 1, 1, 1), + text=TTLocalizer.BodyShopEyelashes, + text_scale=0.0625, + text_pos=(-0.001, -0.015), + text_fg=(1, 1, 1, 1), + ) + + self.eyelashesLButton = DirectButton( + parent=self.eyelashesFrame, + relief=None, + image=(shuffleArrowUp, shuffleArrowDown, shuffleArrowRollover, shuffleArrowDisabled), + image_scale=halfButtonScale, + image1_scale=halfButtonHoverScale, + image2_scale=halfButtonHoverScale, + pos=(-0.2, 0, 0), + command=self.__swapEyelashes, + extraArgs=[-1], + ) + self.eyelashesRButton = DirectButton( + parent=self.eyelashesFrame, + relief=None, + image=(shuffleArrowUp, shuffleArrowDown, shuffleArrowRollover, shuffleArrowDisabled), + image_scale=halfButtonInvertScale, + image1_scale=halfButtonInvertHoverScale, + image2_scale=halfButtonInvertHoverScale, + pos=(0.2, 0, 0), + command=self.__swapEyelashes, + extraArgs=[1], + ) self.memberButton = DirectButton(relief=None, image=(upsellTex, upsellTex, upsellTex, @@ -151,6 +189,7 @@ class BodyShop(StateData.StateData): self.headFrame.destroy() self.bodyFrame.destroy() self.legsFrame.destroy() + self.eyelashesFrame.destroy() self.speciesLButton.destroy() self.speciesRButton.destroy() self.headLButton.destroy() @@ -159,12 +198,15 @@ class BodyShop(StateData.StateData): self.torsoRButton.destroy() self.legLButton.destroy() self.legRButton.destroy() + self.eyelashesLButton.destroy() + self.eyelashesRButton.destroy() self.memberButton.destroy() del self.parentFrame del self.speciesFrame del self.headFrame del self.bodyFrame del self.legsFrame + del self.eyelashesFrame del self.speciesLButton del self.speciesRButton del self.headLButton @@ -173,6 +215,8 @@ class BodyShop(StateData.StateData): del self.torsoRButton del self.legLButton del self.legRButton + del self.eyelashesLButton + del self.eyelashesRButton del self.memberButton self.shuffleButton.unload() self.ignore('MAT-newToonCreated') @@ -258,20 +302,22 @@ class BodyShop(StateData.StateData): self.toon.swapToonColor(self.dna) self.restrictHeadType(newHead) - def __swapEyelashes(self, offset): + def __swapEyelashes(self, offset): length = len([0,1]) self.eyelashesChoice = (self.eyelashesChoice + offset ) % length self.__updateScrollButtons(self.eyelashesChoice, length, self.eyelashesStart, - self.eyelashesLButton, self.eyelashesRButton) + self.eyelashesLButton, self.eyelashesRButton) self.eyelashes = [0, 1][self.eyelashesChoice] self.__updateEyelashes() def __updateEyelashes(self): - return - #WIP - #TODO figure out what toggles eyelashes and use the model head based on if they want eyelashes or not self.__updateScrollButtons(self.eyelashesChoice, len([0, 1]), self.eyelashesStart, self.eyelashesLButton, self.eyelashesRButton) + eyelashesIndex = self.eyelashesChoice + self.dna.eyelashes = eyelashesIndex + self.toon.setEyelashes(eyelashesIndex) + self.toon.setupEyelashes(self.dna) + self.toon.loop("neutral", 0) def __updateScrollButtons(self, choice, length, start, lButton, rButton): if choice == (start - 1) % length: rButton['state'] = DGG.DISABLED @@ -301,9 +347,7 @@ class BodyShop(StateData.StateData): self.doneStatus = 'next' messenger.send(self.doneEvent) - def __handleBackward(self): - self.doneStatus = 'last' - messenger.send(self.doneEvent) + def restrictHeadType(self, head): if not base.cr.isPaid(): @@ -322,15 +366,18 @@ class BodyShop(StateData.StateData): newHeadIndex = ToonDNA.toonHeadTypes.index(newHead) - ToonDNA.getHeadStartIndex(ToonDNA.getSpecies(newHead)) newTorsoIndex = ToonDNA.toonTorsoTypes.index(newChoice[1]) newLegsIndex = ToonDNA.toonLegTypes.index(newChoice[2]) + newEyelashesIndex = random.randint(0,1) oldHead = self.toon.style.head oldSpeciesIndex = ToonDNA.toonSpeciesTypes.index(ToonDNA.getSpecies(oldHead)) oldHeadIndex = ToonDNA.toonHeadTypes.index(oldHead) - ToonDNA.getHeadStartIndex(ToonDNA.getSpecies(oldHead)) oldTorsoIndex = ToonDNA.toonTorsoTypes.index(self.toon.style.torso) oldLegsIndex = ToonDNA.toonLegTypes.index(self.toon.style.legs) + oldEyelashesIndex = self.toon.style.eyelashes self.__swapSpecies(newSpeciesIndex - oldSpeciesIndex) self.__swapHead(newHeadIndex - oldHeadIndex) self.__swapTorso(newTorsoIndex - oldTorsoIndex) self.__swapLegs(newLegsIndex - oldLegsIndex) + self.__swapEyelashes(newEyelashesIndex - oldEyelashesIndex) def getCurrToonSetting(self): return [self.toon.style.head, self.toon.style.torso, self.toon.style.legs] diff --git a/toontown/makeatoon/MakeAToon.py b/toontown/makeatoon/MakeAToon.py index 15efa06..07eb853 100644 --- a/toontown/makeatoon/MakeAToon.py +++ b/toontown/makeatoon/MakeAToon.py @@ -395,24 +395,56 @@ class MakeAToon(StateData.StateData): def bodyShopOpening(self): self.bs.showButtons() self.guiNextButton.show() - self.guiLastButton.show() self.rotateLeftButton.show() self.rotateRightButton.show() + + def enterBodyShop(self): + if hasattr(self, 'toon'): + if self.toon: + self.toon.show() + + else: + self.dna = ToonDNA.ToonDNA() + # stage = 1 is MAKE_A_TOON + self.dna.newToonRandom(eyelashes=random.randint(0, 1), stage=1) + + self.toon = Toon.Toon() + self.toon.setDNA(self.dna) + # make sure the avatar uses its highest LOD + self.toon.useLOD(1000) + # make sure his name doesn't show up + self.toon.setNameVisible(0) + self.toon.startBlink() + self.toon.startLookAround() + self.toon.reparentTo(render) + self.toon.setPos(self.toonPosition) + self.toon.setHpr(self.toonHpr) + self.toon.setScale(self.toonScale) + self.toon.loop("neutral") + self.setNextButtonState(DGG.NORMAL) + self.setToon(self.toon) + messenger.send("MAT-newToonCreated") base.cr.centralLogger.writeClientEvent('MAT - enteringBodyShop') - self.toon.show() + if self.toon: + self.toon.show() self.shop = BODYSHOP self.guiTopBar['text'] = TTLocalizer.ShapeYourToonTitle self.guiTopBar['text_fg'] = (0.0, 0.98, 0.5, 1) self.guiTopBar['text_scale'] = TTLocalizer.MATenterBodyShop - self.accept('BodyShop-done', self.__handleBodyShopDone) + self.accept("BodyShop-done", self.__handleBodyShopDone) self.dropRoom(self.bodyWalls, self.bodyProps) + + # we need to do this first for setup... self.bs.enter(self.toon, self.shopsVisited) - if BODYSHOP not in self.shopsVisited: + + if (BODYSHOP not in self.shopsVisited): self.shopsVisited.append(BODYSHOP) + self.bodyShopOpening() + def exitBodyShop(self): self.squishRoom(self.bodyWalls) self.squishProp(self.bodyProps) diff --git a/toontown/makeatoon/MakeClothesGUI.py b/toontown/makeatoon/MakeClothesGUI.py index 378e25e..5744e49 100644 --- a/toontown/makeatoon/MakeClothesGUI.py +++ b/toontown/makeatoon/MakeClothesGUI.py @@ -9,6 +9,10 @@ class MakeClothesGUI(ClothesGUI.ClothesGUI): def setupScrollInterface(self): self.dna = self.toon.getStyle() + self.tops = ToonDNA.getRandomizedTops(tailorId = ToonDNA.MAKE_A_TOON) + self.bottoms = ToonDNA.getRandomizedBottoms(tailorId = ToonDNA.MAKE_A_TOON) + self.topChoice = 0 + self.bottomChoice = 0 self.setupButtons() def setupButtons(self): diff --git a/toontown/makeatoon/NameGenerator.py b/toontown/makeatoon/NameGenerator.py index 0607e96..dd40596 100644 --- a/toontown/makeatoon/NameGenerator.py +++ b/toontown/makeatoon/NameGenerator.py @@ -1,16 +1,22 @@ -from panda3d.core import * +from pandac.PandaModules import * import random import string import copy from toontown.toonbase import ToontownGlobals from toontown.toonbase import TTLocalizer import os +from direct.showbase import AppRunnerGlobal from direct.directnotify import DirectNotifyGlobal + class NameGenerator: + + # A TextNode we will use to measure the lengths of names text = TextNode('text') text.setFont(ToontownGlobals.getInterfaceFont()) - notify = DirectNotifyGlobal.directNotify.newCategory('NameGenerator') + + notify = DirectNotifyGlobal.directNotify.newCategory("NameGenerator") + boyTitles = [] girlTitles = [] neutralTitles = [] @@ -23,8 +29,13 @@ class NameGenerator: def __init__(self): self.generateLists() + return def generateLists(self): + """ This method looks in a text file specified in the localizer and loads + in all the names into the 8 lists as well as populating self.nameDictionary + which has uniqueIDs mapped to a tuple of category and name + """ self.boyTitles = [] self.girlTitles = [] self.neutralTitles = [] @@ -35,91 +46,92 @@ class NameGenerator: self.lastPrefixes = [] self.lastSuffixes = [] self.nameDictionary = {} + + # Look for the name master file and read it in. searchPath = DSearchPath() if __debug__: searchPath.appendDirectory(Filename('resources/phase_3/etc')) + if AppRunnerGlobal.appRunner: + # In the web-publish runtime, it will always be here: + searchPath.appendDirectory(Filename.expandFrom('$TT_3_ROOT/phase_3/etc')) + else: + # In other environments, including the dev environment, look here: + searchPath.appendDirectory(Filename('phase_3/etc')) + base = os.path.expandvars('$TOONTOWN') or './toontown' + searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars(base + '/src/configfiles'))) + # RobotToonManager needs to look for file in current directory + searchPath.appendDirectory(Filename('.')) + filename = Filename(TTLocalizer.NameShopNameMaster) found = vfs.resolveFilename(filename, searchPath) + if not found: self.notify.error("NameGenerator: Error opening name list text file '%s.'" % TTLocalizer.NameShopNameMaster) + input = StreamReader(vfs.openReadFile(filename, 1), 1) + currentLine = input.readline() while currentLine: if currentLine.lstrip()[0:1] != b'#': a1 = currentLine.find(b'*') a2 = currentLine.find(b'*', a1 + 1) - self.nameDictionary[int(currentLine[0:a1])] = (int(currentLine[a1 + 1:a2]), currentLine[a2 + 1:].rstrip().decode('utf-8')) + self.nameDictionary[int(currentLine[0:a1])] = (int(currentLine[a1 + 1:a2]), + currentLine[a2 + 1:].rstrip().decode('utf-8')) currentLine = input.readline() - masterList = [self.boyTitles, - self.girlTitles, - self.neutralTitles, - self.boyFirsts, - self.girlFirsts, - self.neutralFirsts, - self.capPrefixes, - self.lastPrefixes, - self.lastSuffixes] + masterList = [self.boyTitles, self.girlTitles, self.neutralTitles, + self.boyFirsts, self.girlFirsts, self.neutralFirsts, + self.capPrefixes, self.lastPrefixes, self.lastSuffixes] for tu in list(self.nameDictionary.values()): masterList[tu[0]].append(tu[1]) - return 1 def _getNameParts(self, cat2part): - nameParts = [{}, - {}, - {}, - {}] + # returns list of dict of string->index, one dict per name part + nameParts = [{}, {}, {}, {}] + # cat2part is mapping of NameMasterEnglish.txt category -> namePart index for id, tpl in self.nameDictionary.items(): cat, str = tpl if cat in cat2part: nameParts[cat2part[cat]][str] = id - return nameParts - def getMaleNameParts(self): - return self._getNameParts({0: 0, - 2: 0, - 3: 1, - 5: 1, - 6: 2, - 7: 2, - 8: 3}) - - def getFemaleNameParts(self): - return self._getNameParts({1: 0, - 2: 0, - 4: 1, - 5: 1, - 6: 2, - 7: 2, - 8: 3}) - def getAllNameParts(self): return self._getNameParts({0: 0, - 1: 0, - 2: 0, - 3: 1, - 4: 1, - 5: 1, - 6: 2, - 7: 2, - 8: 3}) + 1: 0, + 2: 0, + 3: 1, + 4: 1, + 5: 1, + 6: 2, + 7: 2, + 8: 3, + }) + + def getLastNamePrefixesCapped(self): return self.capPrefixes def returnUniqueID(self, name, listnumber): + """ This is a helper function which accepts a name string, and a listnumber of + type 0 = title, 1 = firstname, 2 = prefix, 3 = suffix + It then makes a list of search tuples newtu and searches nameDictionary. + If successful it returns the uniqueID, if not then -1 + """ newtu = [(), (), ()] if listnumber == 0: + # Looking for a title newtu[0] = (0, name) newtu[1] = (1, name) newtu[2] = (2, name) elif listnumber == 1: + # Looking for a first name newtu[0] = (3, name) newtu[1] = (4, name) newtu[2] = (5, name) elif listnumber == 2: + # Looking for a prefix newtu[0] = (6, name) newtu[1] = (7, name) else: @@ -128,60 +140,99 @@ class NameGenerator: for g in newtu: if tu[1] == g: return tu[0] - return -1 def findWidestInList(self, text, nameList): maxWidth = 0 - maxName = '' + maxName = "" for name in nameList: width = text.calcWidth(name) if width > maxWidth: maxWidth = text.calcWidth(name) maxName = name - - print(maxName + ' ' + str(maxWidth)) + print(maxName + " " + str(maxWidth)) return maxName def findWidestName(self): - longestBoyTitle = self.findWidestInList(self.text, self.boyTitles + self.neutralTitles) - longestGirlTitle = self.findWidestInList(self.text, self.girlTitles + self.neutralTitles) - longestBoyFirst = self.findWidestInList(self.text, self.boyFirsts + self.neutralFirsts) - longestGirlFirst = self.findWidestInList(self.text, self.girlFirsts + self.neutralFirsts) - longestLastPrefix = self.findWidestInList(self.text, self.lastPrefixes) - longestLastSuffix = self.findWidestInList(self.text, self.lastSuffixes) - longestBoyFront = self.findWidestInList(self.text, [longestBoyTitle, longestBoyFirst]) - longestGirlFront = self.findWidestInList(self.text, [longestGirlTitle, longestGirlFirst]) - longestBoyName = longestBoyTitle + ' ' + longestBoyFirst + ' ' + longestLastPrefix + longestLastSuffix - longestGirlName = longestGirlTitle + ' ' + longestGirlFirst + ' ' + longestLastPrefix + longestLastSuffix - longestName = self.findWidestInList(self.text, [longestBoyName, longestGirlName]) + longestBoyTitle = self.findWidestInList(self.text, + self.boyTitles + + self.neutralTitles) + longestGirlTitle = self.findWidestInList(self.text, + self.girlTitles + + self.neutralTitles) + longestBoyFirst = self.findWidestInList(self.text, + self.boyFirsts + + self.neutralFirsts) + longestGirlFirst = self.findWidestInList(self.text, + self.girlFirsts + + self.neutralFirsts) + longestLastPrefix = self.findWidestInList(self.text, + self.lastPrefixes) + longestLastSuffix = self.findWidestInList(self.text, + self.lastSuffixes) + + longestBoyFront = self.findWidestInList(self.text, + [longestBoyTitle, + longestBoyFirst]) + + longestGirlFront = self.findWidestInList(self.text, + [longestGirlTitle, + longestGirlFirst]) + + longestBoyName = (longestBoyTitle + " " + longestBoyFirst + " " + + longestLastPrefix + longestLastSuffix) + longestGirlName = (longestGirlTitle + " " + longestGirlFirst + " " + + longestLastPrefix + longestLastSuffix) + longestName = self.findWidestInList(self.text, + [longestBoyName, longestGirlName]) return longestName def findWidestTitleFirst(self): - longestBoyTitle = self.findWidestInList(self.text, self.boyTitles + self.neutralTitles) - longestGirlTitle = self.findWidestInList(self.text, self.girlTitles + self.neutralTitles) - longestBoyFirst = self.findWidestInList(self.text, self.boyFirsts + self.neutralFirsts) - longestGirlFirst = self.findWidestInList(self.text, self.girlFirsts + self.neutralFirsts) - longestBoyName = longestBoyTitle + ' ' + longestBoyFirst - longestGirlName = longestGirlTitle + ' ' + longestGirlFirst - longestName = self.findWidestInList(self.text, [longestBoyName, longestGirlName]) + longestBoyTitle = self.findWidestInList(self.text, + self.boyTitles + + self.neutralTitles) + longestGirlTitle = self.findWidestInList(self.text, + self.girlTitles + + self.neutralTitles) + longestBoyFirst = self.findWidestInList(self.text, + self.boyFirsts + + self.neutralFirsts) + longestGirlFirst = self.findWidestInList(self.text, + self.girlFirsts + + self.neutralFirsts) + longestBoyName = (longestBoyTitle + " " + longestBoyFirst) + longestGirlName = (longestGirlTitle + " " + longestGirlFirst) + + longestName = self.findWidestInList(self.text, + [longestBoyName, longestGirlName]) def findWidestTitle(self): - widestTitle = self.findWidestInList(self.text, self.neutralTitles + self.boyTitles + self.girlTitles) + widestTitle = self.findWidestInList(self.text, + self.neutralTitles + + self.boyTitles + + self.girlTitles) return widestTitle def findWidestFirstName(self): - widestFirst = self.findWidestInList(self.text, self.neutralFirsts + self.boyFirsts + self.girlFirsts) + widestFirst = self.findWidestInList(self.text, + self.neutralFirsts + + self.boyFirsts + + self.girlFirsts) return widestFirst def findWidestLastName(self): - longestLastPrefix = self.findWidestInList(self.text, self.lastPrefixes) - longestLastSuffix = self.findWidestInList(self.text, self.lastSuffixes) + longestLastPrefix = self.findWidestInList(self.text, + self.lastPrefixes) + longestLastSuffix = self.findWidestInList(self.text, + self.lastSuffixes) longestLastName = longestLastPrefix + longestLastSuffix return longestLastName def findWidestNameWord(self): - widestWord = self.findWidestInList(self.text, [self.findWidestTitle(), self.findWidestFirstName(), self.findWidestLastName()]) + widestWord = self.findWidestInList(self.text, + [self.findWidestTitle(), + self.findWidestFirstName(), + self.findWidestLastName()]) return widestWord def findWidestNameWidth(self): @@ -192,125 +243,192 @@ class NameGenerator: name = self.findWidestName() width = self.text.calcWidth(name) widthStr = str(width) - print('The widest name is: ' + name + ' (' + widthStr + ' units)') + print(("The widest name is: " + name + " (" + + widthStr + " units)")) def printWidestLastName(self): name = self.findWidestLastName() width = self.text.calcWidth(name) widthStr = str(width) - print('The widest last name is: ' + name + ' (' + widthStr + ' units)') + print(("The widest last name is: " + name + " (" + + widthStr + " units)")) - def randomName(self, boy = 0, girl = 0): + def randomName(self, boy=0, girl=0): + """ This method is outdated for current uses in Toontown, but good for + general debugging. You probably want to use randomNameMoreinfo + """ if boy and girl: self.error("A name can't be both boy and girl!") - if not boy and not girl: + + if (not boy) and (not girl): + # Randomly pick the name sex boy = random.choice([0, 1]) girl = not boy - uberFlag = random.choice(['title-first', - 'title-last', - 'first', - 'last', - 'first-last', - 'title-first-last']) + + # Five types of name combos + uberFlag = random.choice(["title-first", "title-last", + "first", "last", "first-last", "title-first-last"]) titleFlag = 0 - if uberFlag == 'title-first' or uberFlag == 'title-last' or uberFlag == 'title-first-last': + if ((uberFlag == "title-first") or + (uberFlag == "title-last") or + (uberFlag == "title-first-last")): titleFlag = 1 + firstFlag = 0 - if uberFlag == 'title-first' or uberFlag == 'first' or uberFlag == 'first-last' or uberFlag == 'title-first-last': + if ((uberFlag == "title-first") or + (uberFlag == "first") or + (uberFlag == "first-last") or + (uberFlag == "title-first-last")): firstFlag = 1 + lastFlag = 0 - if uberFlag == 'title-last' or uberFlag == 'last' or uberFlag == 'first-last' or uberFlag == 'title-first-last': + if ((uberFlag == "title-last") or + (uberFlag == "last") or + (uberFlag == "first-last") or + (uberFlag == "title-first-last") + ): lastFlag = 1 - retString = '' + + retString = "" + if titleFlag: + # Shallow copy, since we will be altering the list titleList = self.neutralTitles[:] - titleList += self.boyTitles - titleList += self.girlTitles - retString += random.choice(titleList) + ' ' + if boy: + titleList += self.boyTitles + elif girl: + titleList += self.girlTitles + else: + self.error("Must be boy or girl.") + + # Put a space because there will surely be another name. + retString += random.choice(titleList) + " " + if firstFlag: + # Shallow copy, since we will be altering the list firstList = self.neutralFirsts[:] - firstList += self.boyFirsts - firstList += self.girlFirsts + if boy: + firstList += self.boyFirsts + elif girl: + firstList += self.girlFirsts + else: + self.error("Must be boy or girl.") + retString += random.choice(firstList) + # Put a space if there is going to be a last name. if lastFlag: - retString += ' ' + retString += " " + if lastFlag: lastPrefix = random.choice(self.lastPrefixes) lastSuffix = random.choice(self.lastSuffixes) if lastPrefix in self.capPrefixes: lastSuffix = lastSuffix.capitalize() retString += lastPrefix + lastSuffix + return retString def randomNameMoreinfo(self): - uberFlag = random.choice(['title-first', - 'title-last', - 'first', - 'last', - 'first-last', - 'title-first-last']) + """This is just like randomName only it returns a list where the first three + values are titleFlag, firstFlag, and lastFlag and the next four values are + the title, firstname, and lastname (if applicable, '' if not) + """ + + # Five types of name combos + uberFlag = random.choice(["title-first", "title-last", + "first", "last", "first-last", "title-first-last"]) + titleFlag = 0 - if uberFlag == 'title-first' or uberFlag == 'title-last' or uberFlag == 'title-first-last': + if ((uberFlag == "title-first") or + (uberFlag == "title-last") or + (uberFlag == "title-first-last")): titleFlag = 1 + firstFlag = 0 - if uberFlag == 'title-first' or uberFlag == 'first' or uberFlag == 'first-last' or uberFlag == 'title-first-last': + if ((uberFlag == "title-first") or + (uberFlag == "first") or + (uberFlag == "first-last") or + (uberFlag == "title-first-last")): firstFlag = 1 + lastFlag = 0 - if uberFlag == 'title-last' or uberFlag == 'last' or uberFlag == 'first-last' or uberFlag == 'title-first-last': + if ((uberFlag == "title-last") or + (uberFlag == "last") or + (uberFlag == "first-last") or + (uberFlag == "title-first-last")): lastFlag = 1 - retString = '' - uberReturn = [0, - 0, - 0, - '', - '', - '', - ''] + + retString = "" + uberReturn = [0, 0, 0, '', '', '', ''] + uberReturn[0] = titleFlag uberReturn[1] = firstFlag uberReturn[2] = lastFlag + + # Choose random names in each slot even if we won't be using + # them. That way, if the user activates a previously deactive + # slot, s/he'll start at a random point in the list instead of + # always at the top. + + # Shallow copy, since we will be altering the list titleList = self.neutralTitles[:] titleList += self.boyTitles + titleList += self.girlTitles - else: - self.error('Must be boy or girl.') + uberReturn[3] = random.choice(titleList) + + # Shallow copy, since we will be altering the list firstList = self.neutralFirsts[:] firstList += self.boyFirsts firstList += self.girlFirsts + uberReturn[4] = random.choice(firstList) + lastPrefix = random.choice(self.lastPrefixes) lastSuffix = random.choice(self.lastSuffixes) if lastPrefix in self.capPrefixes: lastSuffix = lastSuffix.capitalize() uberReturn[5] = lastPrefix uberReturn[6] = lastSuffix + + # Put a space because there will surely be another name. if titleFlag: - retString += uberReturn[3] + ' ' + retString += uberReturn[3] + " " + if firstFlag: retString += uberReturn[4] + # Put a space if there is going to be a last name. if lastFlag: - retString += ' ' + retString += " " + if lastFlag: retString += uberReturn[5] + uberReturn[6] + uberReturn.append(retString) return uberReturn - def printRandomNames(self, boy = 0, girl = 0, total = 1): + def printRandomNames(self, boy=0, girl=0, total=1): i = 0 origBoy = boy origGirl = girl while i < total: - if not origBoy and not origGirl: + if (not origBoy) and (not origGirl): + # Randomly pick the name sex boy = random.choice([0, 1]) girl = not boy + name = self.randomName(boy, girl) width = self.text.calcWidth(name) widthStr = str(width) - print(name + ' (' + widthStr + ' units)') + if boy: + print("Boy: " + name + " (" + widthStr + " units)") + if girl: + print("Girl: " + name + " (" + widthStr + " units)") + i += 1 - def percentOver(self, limit = 9.0, samples = 1000): + def percentOver(self, limit=9.0, samples=1000): i = 0 over = 0 while i < samples: @@ -319,34 +437,60 @@ class NameGenerator: if width > limit: over += 1 i += 1 - - percent = float(over) / float(samples) * 100 - print('Samples: ' + str(samples) + ' Over: ' + str(over) + ' Percent: ' + str(percent)) + percent = (float(over) / float(samples)) * 100 + print(("Samples: " + str(samples) + " Over: " + + str(over) + " Percent: " + str(percent))) def totalNames(self): - firsts = len(self.boyFirsts) + len(self.girlFirsts) + len(self.neutralFirsts) - print('Total firsts: ' + str(firsts)) + # Firsts only + firsts = (len(self.boyFirsts) + len(self.girlFirsts) + + len(self.neutralFirsts)) + print("Total firsts: " + str(firsts)) + + # Lasts only lasts = len(self.lastPrefixes) * len(self.lastSuffixes) - print('Total lasts: ' + str(lasts)) + print("Total lasts: " + str(lasts)) + + # Title plus first neutralTitleFirsts = len(self.neutralTitles) * len(self.neutralFirsts) - boyTitleFirsts = len(self.boyTitles) * (len(self.neutralFirsts) + len(self.boyFirsts)) + len(self.neutralTitles) * len(self.boyFirsts) - girlTitleFirsts = len(self.girlTitles) * (len(self.neutralFirsts) + len(self.girlFirsts)) + len(self.neutralTitles) * len(self.girlFirsts) - totalTitleFirsts = neutralTitleFirsts + boyTitleFirsts + girlTitleFirsts - print('Total title firsts: ' + str(totalTitleFirsts)) + boyTitleFirsts = ((len(self.boyTitles) * + (len(self.neutralFirsts) + len(self.boyFirsts))) + + ((len(self.neutralTitles) * + len(self.boyFirsts)))) + girlTitleFirsts = ((len(self.girlTitles) * + (len(self.neutralFirsts) + len(self.girlFirsts))) + + ((len(self.neutralTitles) * + len(self.girlFirsts)))) + totalTitleFirsts = (neutralTitleFirsts + boyTitleFirsts + + girlTitleFirsts) + print("Total title firsts: " + str(totalTitleFirsts)) + + # Title plus last neutralTitleLasts = len(self.neutralTitles) * lasts - boyTitleLasts = len(self.boyTitles) * lasts - girlTitleLasts = len(self.girlTitles) * lasts - totalTitleLasts = neutralTitleLasts + boyTitleFirsts + girlTitleLasts - print('Total title lasts: ' + str(totalTitleLasts)) + boyTitleLasts = (len(self.boyTitles) * + lasts) + girlTitleLasts = (len(self.girlTitles) * + lasts) + totalTitleLasts = (neutralTitleLasts + boyTitleFirsts + + girlTitleLasts) + print("Total title lasts: " + str(totalTitleLasts)) + + # First plus last neutralFirstLasts = len(self.neutralFirsts) * lasts boyFirstLasts = len(self.boyFirsts) * lasts girlFirstLasts = len(self.girlFirsts) * lasts - totalFirstLasts = neutralFirstLasts + boyFirstLasts + girlFirstLasts - print('Total first lasts: ' + str(totalFirstLasts)) + totalFirstLasts = (neutralFirstLasts + boyFirstLasts + + girlFirstLasts) + print("Total first lasts: " + str(totalFirstLasts)) + + # Title plus first plus last neutralTitleFirstLasts = neutralTitleFirsts * lasts boyTitleFirstLasts = boyTitleFirsts * lasts girlTitleFirstLasts = girlTitleFirsts * lasts - totalTitleFirstLasts = neutralTitleFirstLasts + boyTitleFirstLasts + girlTitleFirstLasts - print('Total title first lasts: ' + str(totalTitleFirstLasts)) - totalNames = firsts + lasts + totalTitleFirsts + totalTitleLasts + totalFirstLasts + totalTitleFirstLasts - print('Total Names: ' + str(totalNames)) + totalTitleFirstLasts = (neutralTitleFirstLasts + boyTitleFirstLasts + girlTitleFirstLasts) + print("Total title first lasts: " + str(totalTitleFirstLasts)) + + # Total + totalNames = (firsts + lasts + totalTitleFirsts + + totalTitleLasts + totalFirstLasts + totalTitleFirstLasts) + print("Total Names: " + str(totalNames)) \ No newline at end of file diff --git a/toontown/makeatoon/NameShop.py b/toontown/makeatoon/NameShop.py index 17ba441..50371dc 100644 --- a/toontown/makeatoon/NameShop.py +++ b/toontown/makeatoon/NameShop.py @@ -1,4 +1,5 @@ -from panda3d.core import * +"""NameShop module: contains the NameShop class""" + from toontown.toonbase.ToontownGlobals import * from direct.task.TaskManagerGlobal import * from direct.gui.DirectGui import * @@ -13,6 +14,7 @@ from direct.fsm import ClassicFSM, State from direct.fsm import State from toontown.toontowngui import TTDialog import re +import string from toontown.toonbase import TTLocalizer from . import NameGenerator import random @@ -25,89 +27,160 @@ from toontown.toon import NPCToons from direct.task import Task from toontown.makeatoon.TTPickANamePattern import TTPickANamePattern from panda3d.core import TextEncoder + MAX_NAME_WIDTH = TTLocalizer.NSmaxNameWidth + ServerDialogTimeout = 3.0 + class NameShop(StateData.StateData): - notify = DirectNotifyGlobal.directNotify.newCategory('NameShop') + """NameShop class: contains methods for setting the Avatar's + name via user input""" + + notify = DirectNotifyGlobal.directNotify.newCategory("NameShop") + # notify.setDebug(True) def __init__(self, makeAToon, doneEvent, avList, index, isPaid): + """__init__(self, ClassicFSM, Event) + Set-up the name shop interface to pick a name for the given toon + """ StateData.StateData.__init__(self, doneEvent) + self.makeAToon = makeAToon - self.isPaid = isPaid + self.isPaid = 1 + self.avList = avList self.index = index self.shopsVisited = [] self.avId = -1 + # test self.avExists = 0 - self.names = ['', - '', - '', - ''] + + # names is a list of the toon's name, wantName, approvedName, and + # rejectedName + # name is distributed while the other three are specialized for + # makeatoon process + self.names = ["", "", "", ""] self.toon = None + self.allTitles = [] self.allFirsts = [] self.allPrefixes = [] self.allSuffixes = [] + self.titleIndex = 0 self.firstIndex = 0 self.prefixIndex = 0 self.suffixIndex = 0 + self.titleActive = 0 self.firstActive = 0 self.lastActive = 0 + self.quickFind = 0 self.listsLoaded = 0 - self.addedGenderSpecific = 0 - self.chastise = 0 - self.nameIndices = [-1, - -1, - -1, - -1] - self.nameFlags = [1, - 1, - 1, - 0] + self.chastise = 0 # If this is 1 or 2, mickey has chastised you! + self.nameIndices = [-1, -1, -1, -1] + self.nameFlags = [1, 1, 1, 0] self.dummyReturn = 2 + + # nameAction tells makeAToon what is expected of it: + # 0 - No payment/pending approval/accepted, + # 1 - Indices given self.nameAction = 0 + self.pickANameGUIElements = [] self.typeANameGUIElements = [] + self.textRolloverColor = Vec4(1, 1, 0, 1) self.textDownColor = Vec4(0.5, 0.9, 1, 1) self.textDisabledColor = Vec4(0.4, 0.8, 0.4, 1) - self.fsm = ClassicFSM.ClassicFSM('NameShop', [State.State('Init', self.enterInit, self.exitInit, ['PayState']), - State.State('PayState', self.enterPayState, self.exitPayState, ['PickAName']), - State.State('PickAName', self.enterPickANameState, self.exitPickANameState, ['TypeAName', 'Done']), - State.State('TypeAName', self.enterTypeANameState, self.exitTypeANameState, ['PickAName', - 'Approval', - 'Accepted', - 'Rejected']), - State.State('Approval', self.enterApprovalState, self.exitApprovalState, ['PickAName', 'ApprovalAccepted']), - State.State('ApprovalAccepted', self.enterApprovalAcceptedState, self.exitApprovalAcceptedState, ['Done']), - State.State('Accepted', self.enterAcceptedState, self.exitAcceptedState, ['Done']), - State.State('Rejected', self.enterRejectedState, self.exitRejectedState, ['TypeAName']), - State.State('Done', self.enterDone, self.exitDone, ['Init'])], 'Init', 'Done') + + # Add an fsm to NameShop to handle PayState, PickAName, TypeAName, + # NameAccepted, NameRejected, and ToonCouncil + self.fsm = ClassicFSM.ClassicFSM('NameShop', + [State.State('Init', + self.enterInit, + self.exitInit, + ['PayState']), + State.State('PayState', + self.enterPayState, + self.exitPayState, + ['PickAName']), + State.State('PickAName', + self.enterPickANameState, + self.exitPickANameState, + ['TypeAName', 'Done']), + State.State('TypeAName', + self.enterTypeANameState, + self.exitTypeANameState, + ['PickAName', 'Approval', + 'Accepted', 'Rejected']), + State.State('Approval', + self.enterApprovalState, + self.exitApprovalState, + ['PickAName', 'ApprovalAccepted']), + State.State('ApprovalAccepted', + self.enterApprovalAcceptedState, + self.exitApprovalAcceptedState, + ['Done']), + State.State('Accepted', + self.enterAcceptedState, + self.exitAcceptedState, + ['Done']), + State.State('Rejected', + self.enterRejectedState, + self.exitRejectedState, + ['TypeAName']), + State.State('Done', + self.enterDone, + self.exitDone, + ['Init'])], + # Initial state + 'Init', + # Final state + 'Done', + ) + self.parentFSM = makeAToon.fsm self.parentFSM.getStateNamed('NameShop').addChild(self.fsm) + + # Random name generator self.nameGen = NameGenerator.NameGenerator() + self.fsm.enterInitialState() self.requestingSkipTutorial = False - return + self.namePanel = None + return None def makeLabel(self, te, index, others): + """Used to create the frames for names in all 4 scrolled lists + """ alig = others[0] listName = others[1] + if alig == TextNode.ARight: - newpos = (0.44, 0, 0) + newpos = (.44, 0, 0) elif alig == TextNode.ALeft: newpos = (0, 0, 0) else: - newpos = (0.2, 0, 0) - df = DirectFrame(state='normal', relief=None, text=te, text_scale=TTLocalizer.NSmakeLabel, text_pos=newpos, text_align=alig, textMayChange=0) - df.bind(DGG.B1PRESS, lambda x, df = df: self.nameClickedOn(listName, index)) + newpos = (.2, 0, 0) + df = DirectFrame( + state='normal', + relief=None, + text=te, + text_scale=TTLocalizer.NSmakeLabel, + text_pos=newpos, + text_align=alig, + textMayChange=0, + ) + df.bind(DGG.B1PRESS, lambda x, df=df: self.nameClickedOn(listName, index)) return df def nameClickedOn(self, listType, index): + """If a name in one of the scrolled lists is clicked on, + snap it to center + """ if listType == 'title': self.titleIndex = index elif listType == 'first': @@ -116,10 +189,13 @@ class NameShop(StateData.StateData): self.prefixIndex = index else: self.suffixIndex = index + self.updateLists() self.__listsChanged() def enter(self, toon, usedNames, warp): + """enter(self, toon) + """ self.notify.debug('enter') self.newwarp = warp self.avExists = warp @@ -128,123 +204,208 @@ class NameShop(StateData.StateData): if g.position == self.index: self.avId = g.id - if toon == None: - return + if toon is None: + return None else: self.toon = toon - self.usedNames = usedNames - if not self.addedGenderSpecific: - self.listsLoaded = 0 - self.allTitles = [' '] + [' '] + self.nameGen.boyTitles + self.nameGen.girlTitles + self.nameGen.neutralTitles - self.allTitles.sort() - self.allTitles += [' '] + [' '] - self.allFirsts = [' '] + [' '] + self.nameGen.boyFirsts + self.nameGen.girlFirsts + self.nameGen.neutralFirsts - self.allFirsts.sort() - self.allFirsts += [' '] + [' '] - try: - k = self.allFirsts.index('Von') - self.allFirsts[k] = 'von' - except: - print("NameShop: Couldn't find von") + # if (self.toon.style.gender == 'm'): + # self.boy = 1 + # self.girl = 0 + # else: + #self.boy = 0 + #self.girl = 1 - if not self.addedGenderSpecific: - nameShopGui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_nameShop') - self.namePanel = DirectFrame(parent=aspect2d, image=None, relief='flat', state='disabled', pos=(-0.42, 0, -0.15), image_pos=(0, 0, 0.025), frameColor=(1, 1, 1, 0.3)) - panel = nameShopGui.find('**/tt_t_gui_mat_namePanel') - self.panelFrame = DirectFrame(image=panel, scale=(0.75, 0.7, 0.7), relief='flat', frameColor=(1, 1, 1, 0), pos=(-0.0163, 0, 0.1199)) - self.panelFrame.reparentTo(self.namePanel, sort=1) - self.pickANameGUIElements.append(self.namePanel) - self.pickANameGUIElements.append(self.panelFrame) - self.nameResult.reparentTo(self.namePanel, sort=2) - self.circle = nameShopGui.find('**/tt_t_gui_mat_namePanelCircle') - self.titleCheck = self.makeCheckBox((-0.615, 0, 0.371), TTLocalizer.TitleCheckBox, (0, 0.25, 0.5, 1), self.titleToggle) - self.firstCheck = self.makeCheckBox((-0.2193, 0, 0.371), TTLocalizer.FirstCheckBox, (0, 0.25, 0.5, 1), self.firstToggle) - self.lastCheck = self.makeCheckBox((0.3886, 0, 0.371), TTLocalizer.LastCheckBox, (0, 0.25, 0.5, 1), self.lastToggle) - del self.circle - self.pickANameGUIElements.append(self.titleCheck) - self.pickANameGUIElements.append(self.firstCheck) - self.pickANameGUIElements.append(self.lastCheck) - self.titleCheck.reparentTo(self.namePanel, sort=2) - self.firstCheck.reparentTo(self.namePanel, sort=2) - self.lastCheck.reparentTo(self.namePanel, sort=2) - nameShopGui.removeNode() - self.lastprefixScrollList.reparentTo(self.namePanel) - self.lastprefixScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) - self.lastprefixScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) - self.lastsuffixScrollList.reparentTo(self.namePanel) - self.lastsuffixScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) - self.lastsuffixScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) - self.titleHigh.reparentTo(self.namePanel) - self.prefixHigh.reparentTo(self.namePanel) - self.firstHigh.reparentTo(self.namePanel) - self.suffixHigh.reparentTo(self.namePanel) - self.randomButton.reparentTo(self.namePanel, sort=2) - self.typeANameButton.reparentTo(self.namePanel, sort=2) - self.pickANameGUIElements.remove(self.titleScrollList) - self.pickANameGUIElements.remove(self.firstnameScrollList) - self.titleScrollList.destroy() - self.firstnameScrollList.destroy() - self.titleScrollList = self.makeScrollList(None, (-0.6, 0, 0.202), (1, 0.8, 0.8, 1), self.allTitles, self.makeLabel, [TextNode.ACenter, 'title']) - self.firstnameScrollList = self.makeScrollList(None, (-0.2, 0, 0.202), (0.8, 1, 0.8, 1), self.allFirsts, self.makeLabel, [TextNode.ACenter, 'first']) - self.pickANameGUIElements.append(self.titleScrollList) - self.pickANameGUIElements.append(self.firstnameScrollList) - self.titleScrollList.reparentTo(self.namePanel, sort=-1) - self.titleScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) - self.titleScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) - self.firstnameScrollList.reparentTo(self.namePanel, sort=-1) - self.firstnameScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) - self.firstnameScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) - self.listsLoaded = 1 - self.addedGenderSpecific = 1 - self.__randomName() + self.usedNames = usedNames + + # We were able to add last names in the load function but to add + # titles and first names I needed to know gender + # Also, run again if gender has changed + # self.oldBoy = self.boy + self.listsLoaded = 0 + + # Fill titleScrollList + self.allTitles = [" "] + [" "] + self.nameGen.boyTitles + \ + self.nameGen.girlTitles + \ + self.nameGen.neutralTitles + self.allTitles.sort() + self.allTitles += [" "] + [" "] + + # Fill firstnameScrollList + self.allFirsts = [" "] + [" "] + self.nameGen.boyFirsts + \ + self.nameGen.girlFirsts + \ + self.nameGen.neutralFirsts + self.allFirsts.sort() + self.allFirsts += [" "] + [" "] + try: + k = self.allFirsts.index("Von") + self.allFirsts[k] = "von" + except BaseException: + print("NameShop: Couldn't find von") + + nameShopGui = loader.loadModel("phase_3/models/gui/tt_m_gui_mat_nameShop") + self.namePanel = DirectFrame( + parent=aspect2d, + image=None, + relief='flat', + state='disabled', + pos=(-0.42, 0, -0.15), + image_pos=(0, 0, 0.025), + frameColor=(1, 1, 1, 0.3), + ) + + panel = nameShopGui.find("**/tt_t_gui_mat_namePanel") + self.panelFrame = DirectFrame( + image=panel, + scale=(.75, .7, .7), + relief='flat', + frameColor=(1, 1, 1, 0), + pos=(-0.0163, 0, 0.1199) + ) + self.panelFrame.reparentTo(self.namePanel, sort=1) + + self.pickANameGUIElements.append(self.namePanel) + self.pickANameGUIElements.append(self.panelFrame) + self.nameResult.reparentTo(self.namePanel, sort=2) + + # Add check boxes! + self.circle = nameShopGui.find("**/tt_t_gui_mat_namePanelCircle") + self.titleCheck = self.makeCheckBox( + (-0.615, 0, 0.371), TTLocalizer.TitleCheckBox, + (0, 0.25, 0.5, 1), self.titleToggle) + self.firstCheck = self.makeCheckBox( + (-0.2193, 0, 0.371), TTLocalizer.FirstCheckBox, + (0, 0.25, 0.5, 1), self.firstToggle) + self.lastCheck = self.makeCheckBox( + (0.3886, 0, 0.371), TTLocalizer.LastCheckBox, + (0, 0.25, 0.5, 1), self.lastToggle) + + # Don't attempt to remove the circle, since it's just a + # reference to a node within the nameShopGui hierarchy. + # self.circle.removeNode() + del self.circle + + # Make the check buttons pretty + self.pickANameGUIElements.append(self.titleCheck) + self.pickANameGUIElements.append(self.firstCheck) + self.pickANameGUIElements.append(self.lastCheck) + self.titleCheck.reparentTo(self.namePanel, sort=2) + self.firstCheck.reparentTo(self.namePanel, sort=2) + self.lastCheck.reparentTo(self.namePanel, sort=2) + + nameShopGui.removeNode() + + self.lastprefixScrollList.reparentTo(self.namePanel) + self.lastprefixScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) + self.lastprefixScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) + self.lastsuffixScrollList.reparentTo(self.namePanel) + self.lastsuffixScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) + self.lastsuffixScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) + + self.titleHigh.reparentTo(self.namePanel) + self.prefixHigh.reparentTo(self.namePanel) + self.firstHigh.reparentTo(self.namePanel) + self.suffixHigh.reparentTo(self.namePanel) + + self.randomButton.reparentTo(self.namePanel, sort=2) + self.typeANameButton.reparentTo(self.namePanel, sort=2) + + self.pickANameGUIElements.remove(self.titleScrollList) + self.pickANameGUIElements.remove(self.firstnameScrollList) + self.titleScrollList.destroy() + self.firstnameScrollList.destroy() + + self.titleScrollList = self.makeScrollList( + None, (-0.6, 0, 0.202), + (1, 0.80, .80, 1), self.allTitles, + self.makeLabel, + [TextNode.ACenter, 'title']) + self.firstnameScrollList = self.makeScrollList( + None, (-0.2, 0, 0.202), + (0.80, 1, .80, 1), self.allFirsts, + self.makeLabel, + [TextNode.ACenter, 'first']) + self.pickANameGUIElements.append(self.titleScrollList) + self.pickANameGUIElements.append(self.firstnameScrollList) + + self.titleScrollList.reparentTo(self.namePanel, sort=-1) + self.titleScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) + self.titleScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) + self.firstnameScrollList.reparentTo(self.namePanel, sort=-1) + self.firstnameScrollList.decButton.wrtReparentTo(self.namePanel, sort=2) + self.firstnameScrollList.incButton.wrtReparentTo(self.namePanel, sort=2) + + # If you're doing this you'd better make the highlights + # again so they're on top + self.listsLoaded = 1 + self.__randomName() + + # if we have re-entered make sure the Type/Pick button is labelled correctly self.typeANameButton['text'] = TTLocalizer.TypeANameButton + if self.isLoaded == 0: self.load() + self.ubershow(self.pickANameGUIElements) - self.acceptOnce('next', self.__handleDone) - self.acceptOnce('last', self.__handleBackward) - self.acceptOnce('skipTutorial', self.__handleSkipTutorial) + + # set up the "done" button + self.acceptOnce("next", self.__handleDone) + self.acceptOnce("last", self.__handleBackward) + self.acceptOnce("skipTutorial", self.__handleSkipTutorial) + self.__listsChanged() - self.fsm.request('PayState') - return + + self.fsm.request("PayState") + return None def __overflowNameInput(self): self.rejectName(TTLocalizer.NameTooLong) def exit(self): + """exit(self) + Remove events and restore display + """ self.notify.debug('exit') if self.isLoaded == 0: return None - self.ignore('next') - self.ignore('last') - self.ignore('skipTutorial') + + self.ignore("next") + self.ignore("last") + self.ignore("skipTutorial") + self.hideAll() return None def __listsChanged(self): - newname = '' + """Called if a scroll list or checkbox is changed, or a name clicked + Updates the nameResult with the current status of the four lists + """ + + newname = "" if self.listsLoaded: if self.titleActive: self.showList(self.titleScrollList) self.titleHigh.show() - newtitle = self.titleScrollList['items'][self.titleScrollList.index + 2]['text'] + newtitle = self.titleScrollList['items'][ + self.titleScrollList.index + 2]['text'] self.nameIndices[0] = self.nameGen.returnUniqueID(newtitle, 0) - newname += newtitle + ' ' + newname += newtitle + " " else: self.nameIndices[0] = -1 self.stealth(self.titleScrollList) self.titleHigh.hide() + if self.firstActive: self.showList(self.firstnameScrollList) self.firstHigh.show() - newfirst = self.firstnameScrollList['items'][self.firstnameScrollList.index + 2]['text'] - if newfirst == 'von': - nt = 'Von' + newfirst = self.firstnameScrollList['items'][ + self.firstnameScrollList.index + 2]['text'] + if newfirst == "von": + nt = "Von" else: nt = newfirst self.nameIndices[1] = self.nameGen.returnUniqueID(nt, 1) if not self.titleActive and newfirst == 'von': - newfirst = 'Von' + newfirst = "Von" newname += newfirst else: newname += newfirst @@ -253,18 +414,22 @@ class NameShop(StateData.StateData): else: self.nameFlags[1] = 1 if self.lastActive: - newname += ' ' + newname += " " + else: self.firstHigh.hide() self.stealth(self.firstnameScrollList) self.nameIndices[1] = -1 + if self.lastActive: self.showList(self.lastprefixScrollList) self.showList(self.lastsuffixScrollList) self.prefixHigh.show() self.suffixHigh.show() - lp = self.lastprefixScrollList['items'][self.lastprefixScrollList.index + 2]['text'] - ls = self.lastsuffixScrollList['items'][self.lastsuffixScrollList.index + 2]['text'] + lp = self.lastprefixScrollList['items'][ + self.lastprefixScrollList.index + 2]['text'] + ls = self.lastsuffixScrollList['items'][ + self.lastsuffixScrollList.index + 2]['text'] self.nameIndices[2] = self.nameGen.returnUniqueID(lp, 2) self.nameIndices[3] = self.nameGen.returnUniqueID(ls, 3) newname += lp @@ -281,38 +446,97 @@ class NameShop(StateData.StateData): self.suffixHigh.hide() self.nameIndices[2] = -1 self.nameIndices[3] = -1 + self.titleIndex = self.titleScrollList.index + 2 self.firstIndex = self.firstnameScrollList.index + 2 self.prefixIndex = self.lastprefixScrollList.index + 2 self.suffixIndex = self.lastsuffixScrollList.index + 2 + self.nameResult['text'] = newname self.names[0] = newname - def makeScrollList(self, gui, ipos, mcolor, nitems, nitemMakeFunction, nitemMakeExtraArgs): - self.notify.debug('makeScrollList') + def makeScrollList(self, gui, ipos, mcolor, nitems, + nitemMakeFunction, nitemMakeExtraArgs): + self.notify.debug("makeScrollList") + #self.notify.debug("makeScrollList - items %s" % str(nitems)) + """Creates a scrolled list at position ipos and with color mcolor + """ it = nitems[:] - ds = DirectScrolledList(items=it, itemMakeFunction=nitemMakeFunction, itemMakeExtraArgs=nitemMakeExtraArgs, parent=aspect2d, relief=None, command=self.__listsChanged, pos=ipos, scale=0.6, incButton_image=(self.arrowUp, - self.arrowDown, - self.arrowHover, - self.arrowUp), incButton_relief=None, incButton_scale=(1.2, 1.2, -1.2), incButton_pos=(0.0189, 0, -0.5335), incButton_image0_color=mcolor, incButton_image1_color=mcolor, incButton_image2_color=mcolor, incButton_image3_color=Vec4(1, 1, 1, 0), decButton_image=(self.arrowUp, - self.arrowDown, - self.arrowHover, - self.arrowUp), decButton_relief=None, decButton_scale=(1.2, 1.2, 1.2), decButton_pos=(0.0195, 0, 0.1779), decButton_image0_color=mcolor, decButton_image1_color=mcolor, decButton_image2_color=mcolor, decButton_image3_color=Vec4(1, 1, 1, 0), itemFrame_pos=(-.2, 0, 0.028), itemFrame_scale=1.0, itemFrame_relief=DGG.RAISED, itemFrame_frameSize=(-0.07, - 0.5, - -0.52, - 0.12), itemFrame_frameColor=mcolor, itemFrame_borderWidth=(0.01, 0.01), numItemsVisible=5, forceHeight=TTLocalizer.NSdirectScrolleList) + ds = DirectScrolledList( + items=it, + itemMakeFunction=nitemMakeFunction, + itemMakeExtraArgs=nitemMakeExtraArgs, + parent=aspect2d, + relief=None, + command=self.__listsChanged, + pos=ipos, + scale=(.6), + # inc and dec are DirectButtons + incButton_image=(self.arrowUp, self.arrowDown, self.arrowHover, self.arrowUp), + incButton_relief=None, + incButton_scale=(1.2, 1.2, -1.2), + incButton_pos=(0.0189, 0, -0.5335), + incButton_image0_color=mcolor, + incButton_image1_color=mcolor, + incButton_image2_color=mcolor, + # Make the disabled button fade out + incButton_image3_color=Vec4(1, 1, 1, 0), + decButton_image=(self.arrowUp, self.arrowDown, self.arrowHover, self.arrowUp), + decButton_relief=None, + decButton_scale=(1.2, 1.2, 1.2), + decButton_pos=(0.0195, 0, 0.1779), + decButton_image0_color=mcolor, + decButton_image1_color=mcolor, + decButton_image2_color=mcolor, + # Make the disabled button fade out + decButton_image3_color=Vec4(1, 1, 1, 0), + # itemFrame is a DirectFrame used to hold all the items + itemFrame_pos=(-.2, 0, 0.028), + itemFrame_scale=1.0, + itemFrame_relief=DGG.RAISED, + itemFrame_frameSize=(-0.07, 0.5, -0.52, 0.12), + itemFrame_frameColor=mcolor, + itemFrame_borderWidth=(0.01, 0.01), + numItemsVisible=5, + ) return ds def makeCheckBox(self, npos, ntex, ntexcolor, comm): - return DirectCheckButton(parent=aspect2d, relief=None, scale=0.1, boxBorder=0.08, boxImage=self.circle, boxImageScale=4, boxImageColor=VBase4(0, 0.25, 0.5, 1), boxRelief=None, pos=npos, text=ntex, text_fg=ntexcolor, text_scale=TTLocalizer.NSmakeCheckBox, text_pos=(0.2, 0), indicator_pos=(-0.566667, 0, -0.045), indicator_image_pos=(-0.26, 0, 0.075), command=comm, text_align=TextNode.ALeft) + return DirectCheckButton( + parent=aspect2d, + relief=None, + scale=.1, + boxBorder=0.08, + boxImage=self.circle, + boxImageScale=4, + boxImageColor=VBase4(0, 0.25, 0.5, 1), + boxRelief=None, + pos=npos, + text=ntex, + text_fg=ntexcolor, + text_scale=TTLocalizer.NSmakeCheckBox, + text_pos=(0.2, 0), + indicator_pos=(-0.566667, 0, -0.045), + indicator_image_pos=(-0.26, 0, 0.075), + command=comm, + text_align=TextNode.ALeft, + ) def makeHighlight(self, npos): - return DirectFrame(parent=aspect2d, relief='flat', scale=(0.552, 0, 0.11), state='disabled', frameSize=(-0.07, - 0.52, - -0.5, - 0.1), borderWidth=(0.01, 0.01), pos=npos, frameColor=(1, 0, 1, 0.4)) + return DirectFrame( + parent=aspect2d, + relief='flat', + scale=(.552, 0, .11), + state='disabled', + frameSize=(-0.07, 0.52, -0.5, 0.1), + borderWidth=(0.01, 0.01), + pos=npos, + frameColor=(1, 0, 1, .4), + ) def titleToggle(self, value): + """ Toggles titleCheck + """ self.titleActive = self.titleCheck['indicatorValue'] if not (self.titleActive or self.firstActive or self.lastActive): self.titleActive = 1 @@ -322,13 +546,19 @@ class NameShop(StateData.StateData): self.updateCheckBoxes() def firstToggle(self, value): + """ Toggles firstCheck making sure lastCheck is active + """ self.firstActive = self.firstCheck['indicatorValue'] if self.chastise == 2: - messenger.send('NameShop-mickeyChange', [[TTLocalizer.ApprovalForName1, TTLocalizer.ApprovalForName2]]) + messenger.send("NameShop-mickeyChange", + [[TTLocalizer.ApprovalForName1, + TTLocalizer.ApprovalForName2]]) self.chastise = 0 - if not self.firstActive and not self.lastActive: + if not (self.firstActive or self.lastActive): self.firstActive = 1 - messenger.send('NameShop-mickeyChange', [[TTLocalizer.MustHaveAFirstOrLast1, TTLocalizer.MustHaveAFirstOrLast2]]) + messenger.send("NameShop-mickeyChange", + [[TTLocalizer.MustHaveAFirstOrLast1, + TTLocalizer.MustHaveAFirstOrLast2]]) self.chastise = 1 self.__listsChanged() if self.firstActive: @@ -336,13 +566,19 @@ class NameShop(StateData.StateData): self.updateCheckBoxes() def lastToggle(self, value): + """ Toggles lastCheck making sure firstCheck is active + """ self.lastActive = self.lastCheck['indicatorValue'] if self.chastise == 1: - messenger.send('NameShop-mickeyChange', [[TTLocalizer.ApprovalForName1, TTLocalizer.ApprovalForName2]]) + messenger.send("NameShop-mickeyChange", + [[TTLocalizer.ApprovalForName1, + TTLocalizer.ApprovalForName2]]) self.chastise = 0 - if not self.firstActive and not self.lastActive: + if not (self.firstActive or self.lastActive): self.lastActive = 1 - messenger.send('NameShop-mickeyChange', [[TTLocalizer.MustHaveAFirstOrLast1, TTLocalizer.MustHaveAFirstOrLast2]]) + messenger.send("NameShop-mickeyChange", + [[TTLocalizer.MustHaveAFirstOrLast1, + TTLocalizer.MustHaveAFirstOrLast2]]) self.chastise = 2 self.__listsChanged() if self.lastActive: @@ -359,72 +595,183 @@ class NameShop(StateData.StateData): self.lastCheck.setIndicatorValue() def load(self): + """load(self) + """ self.notify.debug('load') if self.isLoaded == 1: return None - nameBalloon = loader.loadModel('phase_3/models/props/chatbox_input') - guiButton = loader.loadModel('phase_3/models/gui/quit_button') - gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_nameShop') + + # set-up name selector + nameBalloon = loader.loadModel( + "phase_3/models/props/chatbox_input") + guiButton = loader.loadModel("phase_3/models/gui/quit_button") + gui = loader.loadModel("phase_3/models/gui/tt_m_gui_mat_nameShop") self.arrowUp = gui.find('**/tt_t_gui_mat_namePanelArrowUp') self.arrowDown = gui.find('**/tt_t_gui_mat_namePanelArrowDown') self.arrowHover = gui.find('**/tt_t_gui_mat_namePanelArrowHover') self.squareUp = gui.find('**/tt_t_gui_mat_namePanelSquareUp') self.squareDown = gui.find('**/tt_t_gui_mat_namePanelSquareDown') self.squareHover = gui.find('**/tt_t_gui_mat_namePanelSquareHover') - typePanel = gui.find('**/tt_t_gui_mat_typeNamePanel') - self.typeNamePanel = DirectFrame(parent=aspect2d, image=None, relief='flat', scale=(0.75, 0.7, 0.7), state='disabled', pos=(-0.0163333, 0, 0.075), image_pos=(0, 0, 0.025), frameColor=(1, 1, 1, 0)) - self.typePanelFrame = DirectFrame(image=typePanel, relief='flat', frameColor=(1, 1, 1, 0), pos=(-0.008, 0, 0.019)) + + typePanel = gui.find("**/tt_t_gui_mat_typeNamePanel") + self.typeNamePanel = DirectFrame( + parent=aspect2d, + image=None, + relief='flat', + scale=(.75, .7, .7), + state='disabled', + pos=(-0.0163333, 0, 0.075), + image_pos=(0, 0, 0.025), + frameColor=(1, 1, 1, 0), + ) + self.typePanelFrame = DirectFrame( + image=typePanel, + relief='flat', + frameColor=(1, 1, 1, 0), + pos=(-0.008, 0, 0.019) + ) self.typePanelFrame.reparentTo(self.typeNamePanel, sort=1) + self.typeANameGUIElements.append(self.typeNamePanel) self.typeANameGUIElements.append(self.typePanelFrame) - self.nameLabel = OnscreenText.OnscreenText(TTLocalizer.PleaseTypeName, parent=aspect2d, style=OnscreenText.ScreenPrompt, scale=TTLocalizer.NSnameLabel, pos=(-0.0163333, 0.53)) + self.nameLabel = OnscreenText.OnscreenText( + TTLocalizer.PleaseTypeName, + parent=aspect2d, + style=OnscreenText.ScreenPrompt, + scale=TTLocalizer.NSnameLabel, + pos=(-0.0163333, 0.53)) self.nameLabel.wrtReparentTo(self.typeNamePanel, sort=2) self.typeANameGUIElements.append(self.nameLabel) - self.typeNotification = OnscreenText.OnscreenText(TTLocalizer.AllNewNames, parent=aspect2d, style=OnscreenText.ScreenPrompt, scale=TTLocalizer.NStypeNotification, pos=(-0.0163333, 0.15)) + + self.typeNotification = OnscreenText.OnscreenText( + TTLocalizer.AllNewNames, + parent=aspect2d, + style=OnscreenText.ScreenPrompt, + scale=TTLocalizer.NStypeNotification, + pos=(-0.0163333, 0.15)) self.typeNotification.wrtReparentTo(self.typeNamePanel, sort=2) self.typeANameGUIElements.append(self.typeNotification) - self.nameMessages = OnscreenText.OnscreenText(TTLocalizer.NameMessages, parent=aspect2d, style=OnscreenText.ScreenPrompt, scale=0.06, pos=(-0.0163333, -0.05)) + + self.nameMessages = OnscreenText.OnscreenText( + TTLocalizer.NameMessages, + parent=aspect2d, + style=OnscreenText.ScreenPrompt, + scale=0.06, + pos=(-0.0163333, -0.05)) self.nameMessages.wrtReparentTo(self.typeNamePanel, sort=2) self.typeANameGUIElements.append(self.nameMessages) - self.nameEntry = DirectEntry(parent=aspect2d, relief=None, scale=TTLocalizer.NSnameEntry, entryFont=getToonFont(), width=MAX_NAME_WIDTH, numLines=2, focus=0, cursorKeys=1, pos=(0.0, 0.0, 0.39), text_align=TextNode.ACenter, command=self.__typedAName, autoCapitalize=1) + + self.nameEntry = DirectEntry( + parent=aspect2d, + relief=None, + scale=TTLocalizer.NSnameEntry, + entryFont=getToonFont(), + width=MAX_NAME_WIDTH, + numLines=2, + focus=0, + cursorKeys=1, + pos=(0.0, 0.0, 0.39), + text_align=TextNode.ACenter, + command=self.__typedAName, + autoCapitalize=1, + ) self.nameEntry.wrtReparentTo(self.typeNamePanel, sort=2) self.typeANameGUIElements.append(self.nameEntry) - self.submitButton = DirectButton(parent=aspect2d, relief=None, image=(self.squareUp, - self.squareDown, - self.squareHover, - self.squareUp), image_scale=(1.2, 0, 1.1), pos=(-0.01, 0, -0.25), text=TTLocalizer.NameShopSubmitButton, text_scale=0.06, text_pos=(0, -0.02), command=self.__typedAName) + self.submitButton = DirectButton( + parent=aspect2d, + relief=None, + image=(self.squareUp, self.squareDown, self.squareHover, self.squareUp), + image_scale=(1.2, 0, 1.1), + pos=(-0.01, 0, -0.25), + text=TTLocalizer.NameShopSubmitButton, + text_scale=0.06, + text_pos=(0, -0.02), + command=self.__typedAName, + ) + self.submitButton.wrtReparentTo(self.typeNamePanel, sort=2) self.typeNamePanel.setPos(-0.42, 0, -0.078) + self.typeANameGUIElements.append(self.submitButton) - self.randomButton = DirectButton(parent=aspect2d, relief=None, image=(self.squareUp, - self.squareDown, - self.squareHover, - self.squareUp), image_scale=(1.15, 1.1, 1.1), scale=(1.05, 1, 1), pos=(0, 0, -0.25), text=TTLocalizer.ShuffleButton, text_scale=0.06, text_pos=(0, -0.02), command=self.__randomName) + + # GUI Elements for PickAName + self.randomButton = DirectButton( + parent=aspect2d, + relief=None, + image=(self.squareUp, self.squareDown, self.squareHover, self.squareUp), + image_scale=(1.15, 1.1, 1.1), + scale=(1.05, 1, 1), + pos=(0, 0, -0.25), + text=TTLocalizer.ShuffleButton, + text_scale=0.06, + text_pos=(0, -0.02), + command=self.__randomName, + ) self.pickANameGUIElements.append(self.randomButton) - self.typeANameButton = DirectButton(parent=aspect2d, relief=None, image=(self.squareUp, - self.squareDown, - self.squareHover, - self.squareUp), image_scale=(1, 1.1, 0.9), pos=(0.0033, 0, -.38833), scale=(1.2, 1, 1.2), text=TTLocalizer.TypeANameButton, text_scale=TTLocalizer.NStypeANameButton, text_pos=TTLocalizer.NStypeANameButtonPos, command=self.__typeAName) + self.typeANameButton = DirectButton( + parent=aspect2d, + relief=None, + image=(self.squareUp, self.squareDown, self.squareHover, self.squareUp), + image_scale=(1, 1.1, 0.9), + pos=(0.0033, 0, -.38833), + scale=(1.2, 1, 1.2), + text=TTLocalizer.TypeANameButton, + text_scale=TTLocalizer.NStypeANameButton, + text_pos=TTLocalizer.NStypeANameButtonPos, + command=self.__typeAName, + ) + #self.printTypeANameInfo("after constructor in DirectButton") + if base.cr.productName in ['DE', 'BR']: + # No type-a-name for DE (German) and BR (Brazil) self.typeANameButton.hide() self.pickANameGUIElements.append(self.typeANameButton) - self.nameResult = DirectLabel(parent=aspect2d, relief=None, scale=TTLocalizer.NSnameResult, pos=(0.005, 0, 0.585), text=' \n ', text_scale=0.8, text_align=TextNode.ACenter, text_wordwrap=MAX_NAME_WIDTH) + + # nameResult is a label where the current name combo will be displayed + self.nameResult = DirectLabel( + parent=aspect2d, + relief=None, + scale=TTLocalizer.NSnameResult, + pos=(0.005, 0, 0.585), + text=" \n ", + text_scale=0.8, + text_align=TextNode.ACenter, + text_wordwrap=MAX_NAME_WIDTH, + ) self.pickANameGUIElements.append(self.nameResult) + self.allPrefixes = self.nameGen.lastPrefixes[:] self.allSuffixes = self.nameGen.lastSuffixes[:] self.allPrefixes.sort() self.allSuffixes.sort() - self.allPrefixes = [' '] + [' '] + self.allPrefixes + [' '] + [' '] - self.allSuffixes = [' '] + [' '] + self.allSuffixes + [' '] + [' '] - self.titleScrollList = self.makeScrollList(gui, (-0.6, 0, 0.202), (1, 0.8, 0.8, 1), self.allTitles, self.makeLabel, [TextNode.ACenter, 'title']) - self.firstnameScrollList = self.makeScrollList(gui, (-0.2, 0, 0.202), (0.8, 1, 0.8, 1), self.allFirsts, self.makeLabel, [TextNode.ACenter, 'first']) - self.lastprefixScrollList = self.makeScrollList(gui, (0.2, 0, 0.202), (0.8, 0.8, 1, 1), self.allPrefixes, self.makeLabel, [TextNode.ARight, 'prefix']) - self.lastsuffixScrollList = self.makeScrollList(gui, (0.55, 0, 0.202), (0.8, 0.8, 1, 1), self.allSuffixes, self.makeLabel, [TextNode.ALeft, 'suffix']) + self.allPrefixes = [" "] + [" "] + self.allPrefixes + [" "] + [" "] + self.allSuffixes = [" "] + [" "] + self.allSuffixes + [" "] + [" "] + + # Create 4 scrolled lists with different colors + self.titleScrollList = self.makeScrollList( + gui, (-0.6, 0, 0.202), + (1, 0.80, .80, 1), self.allTitles, + self.makeLabel, [TextNode.ACenter, 'title']) + self.firstnameScrollList = self.makeScrollList( + gui, (-0.2, 0, 0.202), + (0.80, 1, .80, 1), self.allFirsts, + self.makeLabel, [TextNode.ACenter, 'first']) + self.lastprefixScrollList = self.makeScrollList( + gui, (0.2, 0, 0.202), + (0.80, 0.80, 1, 1), self.allPrefixes, + self.makeLabel, [TextNode.ARight, 'prefix']) + self.lastsuffixScrollList = self.makeScrollList( + gui, (0.55, 0, 0.202), + (0.80, 0.80, 1, 1), self.allSuffixes, + self.makeLabel, [TextNode.ALeft, 'suffix']) + gui.removeNode() self.pickANameGUIElements.append(self.lastprefixScrollList) self.pickANameGUIElements.append(self.lastsuffixScrollList) self.pickANameGUIElements.append(self.titleScrollList) self.pickANameGUIElements.append(self.firstnameScrollList) + + # Make four highlights for each scroll List self.titleHigh = self.makeHighlight((-0.710367, 0.0, 0.122967)) self.firstHigh = self.makeHighlight((-0.310367, 0.0, 0.122967)) self.pickANameGUIElements.append(self.titleHigh) @@ -433,44 +780,79 @@ class NameShop(StateData.StateData): self.suffixHigh = self.makeHighlight((0.44, 0.0, 0.122967)) self.pickANameGUIElements.append(self.prefixHigh) self.pickANameGUIElements.append(self.suffixHigh) + nameBalloon.removeNode() - imageList = (guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')) + + # GUI elements for PayState + imageList = (guiButton.find("**/QuitBtn_UP"), + guiButton.find("**/QuitBtn_DN"), + guiButton.find("**/QuitBtn_RLVR"), + ) buttonImage = [imageList, imageList] buttonText = [TTLocalizer.NameShopPay, TTLocalizer.NameShopPlay] - self.payDialog = DirectDialog(dialogName='paystate', topPad=0, fadeScreen=0.2, pos=(0, 0.1, 0.1), button_relief=None, text_align=TextNode.ACenter, text=TTLocalizer.NameShopOnlyPaid, buttonTextList=buttonText, buttonImageList=buttonImage, image_color=GlobalDialogColor, buttonValueList=[1, 0], command=self.payAction) + + self.payDialog = DirectDialog(dialogName="paystate", + topPad=0, + fadeScreen=0.2, + pos=(0, .1, .1), + button_relief=None, + text_align=TextNode.ACenter, + text=TTLocalizer.NameShopOnlyPaid, + buttonTextList=buttonText, + buttonImageList=buttonImage, + image_color=GlobalDialogColor, + buttonValueList=[1, 0], + command=self.payAction) self.payDialog.buttonList[0].setPos(0, 0, -.27) self.payDialog.buttonList[1].setPos(0, 0, -.4) self.payDialog.buttonList[0]['image_scale'] = (1.2, 1, 1.1) self.payDialog.buttonList[1]['image_scale'] = (1.2, 1, 1.1) - self.payDialog['image_scale'] = (0.8, 1, 0.77) + self.payDialog['image_scale'] = (.8, 1, .77) self.payDialog.buttonList[0]['text_pos'] = (0, -.02) self.payDialog.buttonList[1]['text_pos'] = (0, -.02) self.payDialog.hide() + buttonText = [TTLocalizer.NameShopContinueSubmission, TTLocalizer.NameShopChooseAnother] - self.approvalDialog = DirectDialog(dialogName='approvalstate', topPad=0, fadeScreen=0.2, pos=(0, 0.1, 0.1), button_relief=None, image_color=GlobalDialogColor, text_align=TextNode.ACenter, text=TTLocalizer.NameShopToonCouncil, buttonTextList=buttonText, buttonImageList=buttonImage, buttonValueList=[1, 0], command=self.approvalAction) + + self.approvalDialog = DirectDialog(dialogName="approvalstate", + topPad=0, + fadeScreen=0.2, + pos=(0, .1, .1), + button_relief=None, + image_color=GlobalDialogColor, + text_align=TextNode.ACenter, + text=TTLocalizer.NameShopToonCouncil, + buttonTextList=buttonText, + buttonImageList=buttonImage, + buttonValueList=[1, 0], + command=self.approvalAction) self.approvalDialog.buttonList[0].setPos(0, 0, -.3) self.approvalDialog.buttonList[1].setPos(0, 0, -.43) - self.approvalDialog['image_scale'] = (0.8, 1, 0.77) + self.approvalDialog['image_scale'] = (.8, 1, .77) for x in range(0, 2): self.approvalDialog.buttonList[x]['text_pos'] = (0, -.01) - self.approvalDialog.buttonList[x]['text_scale'] = (0.04, 0.05999) + self.approvalDialog.buttonList[x]['text_scale'] = (.04, .05999) self.approvalDialog.buttonList[x].setScale(1.2, 1, 1) self.approvalDialog.hide() guiButton.removeNode() + self.uberhide(self.typeANameGUIElements) self.uberhide(self.pickANameGUIElements) + self.isLoaded = 1 + return None def ubershow(self, guiObjectsToShow): - self.notify.debug('ubershow %s' % str(guiObjectsToShow)) + self.notify.debug("ubershow %s" % str(guiObjectsToShow)) for x in guiObjectsToShow: try: x.show() - except: - print('NameShop: Tried to show already removed object') + except BaseException: + print("NameShop: Tried to show already removed object") if base.cr.productName in ['DE', 'BR']: + # No type-a-name for DE (German) and BR (Brazil) self.typeANameButton.hide() def hideAll(self): @@ -478,57 +860,77 @@ class NameShop(StateData.StateData): self.uberhide(self.typeANameGUIElements) def uberhide(self, guiObjectsToHide): - self.notify.debug('uberhide %s' % str(guiObjectsToHide)) + self.notify.debug("uberhide %s" % str(guiObjectsToHide)) for x in guiObjectsToHide: try: x.hide() - except: - print('NameShop: Tried to hide already removed object') + except BaseException: + print("NameShop: Tried to hide already removed object") def uberdestroy(self, guiObjectsToDestroy): - self.notify.debug('uberdestroy %s' % str(guiObjectsToDestroy)) + self.notify.debug("uberdestroy %s" % str(guiObjectsToDestroy)) for x in guiObjectsToDestroy: + # This is sloppy, it's causing a C++ exception at the end of + # make-a-toon. We should bullet-proof destroy() so that it + # doesn't do Bad Stuff when it's called more than once, or + # check to see if the object has already been destroyed. try: x.destroy() del x - except: - print('NameShop: Tried to destroy already removed object') + except BaseException: + print("NameShop: Tried to destroy already removed object") def getNameIndices(self): + """getNameIndices(self) + """ return self.nameIndices def getNameFlags(self): + """getNameFlags(self) + """ return self.nameFlags def getNameAction(self): + """getNameAction(self) + """ return self.nameAction def unload(self): + """unload(self) + """ self.notify.debug('unload') if self.isLoaded == 0: return None + self.exit() - cleanupDialog('globalDialog') + # make sure any dialog panels are closed + cleanupDialog("globalDialog") + self.uberdestroy(self.pickANameGUIElements) self.uberdestroy(self.typeANameGUIElements) + del self.toon + self.payDialog.cleanup() self.approvalDialog.cleanup() del self.payDialog del self.approvalDialog + self.parentFSM.getStateNamed('NameShop').removeChild(self.fsm) del self.parentFSM del self.fsm + self.ignoreAll() self.isLoaded = 0 self.makeAToon = None + return None def _checkNpcNames(self, name): - - def match(npcName, name = name): + def match(npcName, name=name): + # TextEncoder.upper requires encoded strings name = TextEncoder().encodeWtext(name) name = name.strip() - return TextEncoder.upper(npcName) == TextEncoder.upper(name.decode('utf-8')) + return (TextEncoder.upper(npcName) == TextEncoder.upper(name.decode())) for npcId in list(NPCToons.NPCToonDict.keys()): npcName = NPCToons.NPCToonDict[npcId][1] @@ -537,21 +939,37 @@ class NameShop(StateData.StateData): return TTLocalizer.NCGeneric def nameIsValid(self, name): + """nameIsValid(self, string name) + Checks the name for legitimacy according to our various + Toontown rules. If it violates any of those rules, returns a + string explaining the objection; otherwise, returns None + indicating the name is acceptable. + """ self.notify.debug('nameIsValid') - if name in self.usedNames: - return TTLocalizer.ToonAlreadyExists % name - problem = NameCheck.checkName(name, [self._checkNpcNames], font=self.nameEntry.getFont()) + if (name in self.usedNames): + return TTLocalizer.ToonAlreadyExists % (name) + + problem = NameCheck.checkName(name, [self._checkNpcNames], + font=self.nameEntry.getFont()) if problem: return problem + + # name has passed local checks return None + # event handlers + def setShopsVisited(self, list): + """setShopsVisited(self, int[]) + We must know what shops are visited so we can place the done button + """ self.shopsVisited = list def __handleDone(self): if self.fsm.getCurrentState().getName() == 'TypeAName': self.__typedAName() else: + # self.__createAvatar() self.__isFirstTime() def __handleSkipTutorial(self): @@ -564,42 +982,55 @@ class NameShop(StateData.StateData): def __handleChastised(self): self.chastiseDialog.cleanup() - def __createAvatar(self, skipTutorial = False, *args): + def __createAvatar(self, skipTutorial=False, *args): + """__createAvatar(self) + Create the avatar if needed, then check name + """ self.notify.debug('__createAvatar') + # If you're in typeAName then you can't click done! if self.fsm.getCurrentState().getName() == 'TypeAName': self.__typedAName() return - if not self.avExists or self.avExists and self.avId == 'deleteMe': + + if not self.avExists or (self.avExists and self.avId == 'deleteMe'): self.serverCreateAvatar(skipTutorial) - elif self.names[0] == '': - self.rejectName(TTLocalizer.EmptyNameError) else: - rejectReason = self.nameIsValid(self.names[0]) - if rejectReason != None: - self.rejectName(rejectReason) + if (self.names[0] == ""): + # No empty names + self.rejectName(TTLocalizer.EmptyNameError) else: - self.checkNamePattern() - return + rejectReason = self.nameIsValid(self.names[0]) + if rejectReason is not None: + self.rejectName(rejectReason) + else: + self.checkNamePattern() def acceptName(self): self.notify.debug('acceptName') + # The name was accepted by the server + # Set our Toon name self.toon.setName(self.names[0]) - self.doneStatus = 'done' + # Send our done event + self.doneStatus = "done" self.storeSkipTutorialRequest() messenger.send(self.doneEvent) def rejectName(self, str): self.notify.debug('rejectName') - self.names[0] = '' - self.rejectDialog = TTDialog.TTGlobalDialog(doneEvent='rejectDone', message=str, style=TTDialog.Acknowledge) + self.names[0] = "" + self.rejectDialog = TTDialog.TTGlobalDialog( + doneEvent="rejectDone", + message=str, + style=TTDialog.Acknowledge) self.rejectDialog.show() - self.acceptOnce('rejectDone', self.__handleReject) + self.acceptOnce("rejectDone", self.__handleReject) def __handleReject(self): self.rejectDialog.cleanup() self.nameEntry['focus'] = 1 self.typeANameButton.show() - self.acceptOnce('next', self.__handleDone) + # enable the done button again + self.acceptOnce("next", self.__handleDone) def restoreIndexes(self, oi): self.titleIndex = oi[0] @@ -620,10 +1051,10 @@ class NameShop(StateData.StateData): listToDo.incButton['state'] = 'normal' def updateLists(self): - oldindex = [self.titleIndex, - self.firstIndex, - self.prefixIndex, - self.suffixIndex] + """Scroll lists to the newly changed indices + """ + oldindex = [self.titleIndex, self.firstIndex, + self.prefixIndex, self.suffixIndex] self.titleScrollList.scrollTo(self.titleIndex - 2) self.restoreIndexes(oldindex) self.firstnameScrollList.scrollTo(self.firstIndex - 2) @@ -634,7 +1065,9 @@ class NameShop(StateData.StateData): self.restoreIndexes(oldindex) def __randomName(self): - self.notify.debug('Finding random name') + self.notify.debug("Finding random name") + # Create a random name using the new function which returns + # more information uberReturn = self.nameGen.randomNameMoreinfo() flags = uberReturn[:3] names = uberReturn[3:7] @@ -642,70 +1075,106 @@ class NameShop(StateData.StateData): self._updateGuiWithPickAName(flags, names, fullName) def _updateGuiWithPickAName(self, flags, names, fullName): + # flags are 'active' boolean for (title, first, last) + # names are strings or '' for (title, first, lastPrefix, lastSuffix) + # fullName is full name string + # format the data to work with the code below uberReturn = flags + names + [fullName] + self.names[0] = uberReturn[len(uberReturn) - 1] self.titleActive = 0 self.firstActive = 0 self.lastActive = 0 + + # If there was a title used (the first item in return list + # is titleFlag) if uberReturn[0]: self.titleActive = 1 + + # If a first name is used (the second item in returned list + # is firstFlag) if uberReturn[1]: self.firstActive = 1 + if uberReturn[2]: self.lastActive = 1 + + # Now look up each name in each list, even if we're not using + # the list (that is, even if the flag above is set false for + # the given list). We do this so that if the user activates a + # new slot that was previously deactive, it will start the + # user in the middle of the list instead of necessarily at the + # top. + try: + # Find position in scrolledList of the title used self.titleIndex = self.allTitles.index(uberReturn[3]) self.nameIndices[0] = self.nameGen.returnUniqueID(uberReturn[3], 0) self.nameFlags[0] = 1 - except: - print('NameShop : Should have found title, uh oh!') + except BaseException: + print("NameShop : Should have found title, uh oh!") print(uberReturn) try: + # Find position in scrolledList of the firstname used self.firstIndex = self.allFirsts.index(uberReturn[4]) self.nameIndices[1] = self.nameGen.returnUniqueID(uberReturn[4], 1) self.nameFlags[1] = 1 - except: - print('NameShop : Should have found first name, uh oh!') + except BaseException: + print("NameShop : Should have found first name, uh oh!") print(uberReturn) + # If there was a last name used (you get it...) try: + # Find position in scrolledList of the prefix and suffix used self.prefixIndex = self.allPrefixes.index(uberReturn[5]) - self.suffixIndex = self.allSuffixes.index(uberReturn[6].lower()) - self.nameIndices[2] = self.nameGen.returnUniqueID(uberReturn[5], 2) - self.nameIndices[3] = self.nameGen.returnUniqueID(uberReturn[6].lower(), 3) + self.suffixIndex = self.allSuffixes.index((uberReturn[6].lower())) + self.nameIndices[2] = self.nameGen.returnUniqueID( + uberReturn[5], 2) + self.nameIndices[3] = self.nameGen.returnUniqueID( + uberReturn[6].lower(), 3) if uberReturn[5] in self.nameGen.capPrefixes: self.nameFlags[3] = 1 else: self.nameFlags[3] = 0 - except: - print('NameShop : Some part of last name not found, uh oh!') + except BaseException: + print("NameShop : Some part of last name not found, uh oh!") print(uberReturn) self.updateCheckBoxes() self.updateLists() + + # Put the name in the result label self.nameResult['text'] = self.names[0] def findTempName(self): colorstring = TTLocalizer.NumToColor[self.toon.style.headColor] animaltype = TTLocalizer.AnimalToSpecies[self.toon.style.getAnimal()] - tempname = colorstring + ' ' + animaltype - if not TTLocalizer.NScolorPrecede: - tempname = animaltype + ' ' + colorstring + tempname = colorstring + " " + \ + animaltype + if not TTLocalizer.NScolorPrecede: # fix for French grammar + tempname = animaltype + " " + \ + colorstring self.names[0] = tempname tempname = '"' + tempname + '"' return tempname + # Specific State functions + # Init state def enterInit(self): self.notify.debug('enterInit') def exitInit(self): pass + # PayState State def enterPayState(self): self.notify.debug('enterPayState') - if base.cr.allowFreeNames() or self.isPaid: - self.fsm.request('PickAName') + + # If we are allowing free names, or this person is paid + # let them name their toon + if (base.cr.allowFreeNames() or self.isPaid): + self.fsm.request("PickAName") else: tempname = self.findTempName() self.payDialog['text'] = TTLocalizer.NameShopOnlyPaid + tempname @@ -718,12 +1187,14 @@ class NameShop(StateData.StateData): self.notify.debug('payAction') self.payDialog.hide() if value: - self.doneStatus = 'paynow' + self.doneStatus = "paynow" messenger.send(self.doneEvent) + # self.fsm.request("PickAName") else: self.nameAction = 0 self.__createAvatar() + # PickAName state def enterPickANameState(self): self.notify.debug('enterPickANameState') self.ubershow(self.pickANameGUIElements) @@ -733,51 +1204,67 @@ class NameShop(StateData.StateData): def exitPickANameState(self): self.uberhide(self.pickANameGUIElements) + # TypeAName state def enterTypeANameState(self): self.notify.debug('enterTypeANameState') self.ubershow(self.typeANameGUIElements) self.typeANameButton.show() self.typeANameButton.wrtReparentTo(aspect2d, sort=2) - self.nameEntry.set('') + self.nameEntry.set("") self.nameEntry['focus'] = 1 def __typeAName(self): - if base.cr.productName in ['JP', - 'DE', - 'BR', - 'FR']: + if base.cr.productName in ['JP', 'DE', 'BR', 'FR']: + # for INTL users, if it not paid, it is not allowed to type their name if base.restrictTrialers: if not base.cr.isPaid(): + # don't allow trialers to type in a name dialog = TeaserPanel.TeaserPanel(pageName='typeAName') return if self.fsm.getCurrentState().getName() == 'TypeAName': self.typeANameButton['text'] = TTLocalizer.TypeANameButton self.typeANameButton.wrtReparentTo(self.namePanel, sort=2) - self.fsm.request('PickAName') + #self.printTypeANameInfo("in __typeAName, after reparent to self.namePanel") + self.fsm.request("PickAName") else: self.typeANameButton['text'] = TTLocalizer.PickANameButton self.typeANameButton.wrtReparentTo(aspect2d, sort=2) + #self.printTypeANameInfo("in __typeAName, after reparent to aspect2d") self.typeANameButton.show() - self.fsm.request('TypeAName') + self.fsm.request("TypeAName") def __typedAName(self, *args): self.notify.debug('__typedAName') + self.nameEntry['focus'] = 0 + + # strip leading/trailing whitespace name = self.nameEntry.get() - name = TextEncoder().decodeText(name.encode('utf-8')) + # make sure we're able to recognize unicode whitespace + name = TextEncoder().decodeText(name.encode()) name = name.strip() name = TextEncoder().encodeWtext(name) - self.nameEntry.enterText(name.decode('utf-8')) + + # put the processed name back into the GUI + self.nameEntry.enterText(name.decode()) + + # do local name checks first problem = self.nameIsValid(self.nameEntry.get()) if problem: self.rejectName(problem) return + + # check to see if the server would reject this name before + # actually submitting the name for the new avatar self.checkNameTyped(justCheck=True) def exitTypeANameState(self): + # fix type a name button shifting self.typeANameButton.wrtReparentTo(self.namePanel, sort=2) + #self.printTypeANameInfo("after reparent to self.namePanel") self.uberhide(self.typeANameGUIElements) + # Approval state def enterApprovalState(self): self.notify.debug('enterApprovalState') tempname = self.findTempName() @@ -788,6 +1275,7 @@ class NameShop(StateData.StateData): self.notify.debug('approvalAction') self.approvalDialog.hide() if value: + # user approves of temp name. continue with the process, create the avatar self.nameAction = 2 if not self.makeAToon.warp: self.__isFirstTime() @@ -795,48 +1283,61 @@ class NameShop(StateData.StateData): self.serverCreateAvatar() else: self.typeANameButton['text'] = TTLocalizer.TypeANameButton - self.fsm.request('PickAName') + self.fsm.request("PickAName") def exitApprovalState(self): pass + # ApprovalAccepted state def enterApprovalAcceptedState(self): self.notify.debug('enterApprovalAcceptedState') - self.doneStatus = 'done' + # user has accepted a temporary name, and has been notified that they will have + # to wait for their name to be approved + self.doneStatus = "done" self.storeSkipTutorialRequest() messenger.send(self.doneEvent) def exitApprovalAcceptedState(self): pass + # Accepted state def enterAcceptedState(self): self.notify.debug('enterAcceptedState') - self.acceptedDialog = TTDialog.TTGlobalDialog(doneEvent='acceptedDone', message=TTLocalizer.NameShopNameAccepted, style=TTDialog.Acknowledge) + self.acceptedDialog = TTDialog.TTGlobalDialog( + doneEvent="acceptedDone", + message=TTLocalizer.NameShopNameAccepted, + style=TTDialog.Acknowledge) self.acceptedDialog.show() - self.acceptOnce('acceptedDone', self.__handleAccepted) + self.acceptOnce("acceptedDone", self.__handleAccepted) def __handleAccepted(self): self.acceptedDialog.cleanup() - self.doneStatus = 'done' + # Everything is cool, send our done event + self.doneStatus = "done" self.storeSkipTutorialRequest() messenger.send(self.doneEvent) def exitAcceptedState(self): pass + # Rejected state def enterRejectedState(self): self.notify.debug('enterRejectedState') - self.rejectedDialog = TTDialog.TTGlobalDialog(doneEvent='rejectedDone', message=TTLocalizer.NameShopNameRejected, style=TTDialog.Acknowledge) + self.rejectedDialog = TTDialog.TTGlobalDialog( + doneEvent="rejectedDone", + message=TTLocalizer.NameShopNameRejected, + style=TTDialog.Acknowledge) self.rejectedDialog.show() - self.acceptOnce('rejectedDone', self.__handleRejected) + self.acceptOnce("rejectedDone", self.__handleRejected) def __handleRejected(self): self.rejectedDialog.cleanup() - self.fsm.request('TypeAName') + self.fsm.request("TypeAName") def exitRejectedState(self): pass + # Done state def enterDone(self): self.notify.debug('enterDone') return None @@ -844,6 +1345,7 @@ class NameShop(StateData.StateData): def exitDone(self): return None + # Sending and Receiving wit da Server def nameShopHandler(self, msgType, di): self.notify.debug('nameShopHandler') if msgType == CLIENT_CREATE_AVATAR_RESP: @@ -856,349 +1358,304 @@ class NameShop(StateData.StateData): def checkNamePattern(self): self.notify.debug('checkNamePattern') - if __astron__: - base.cr.astronLoginManager.sendSetNamePattern(self.avId, - self.nameIndices[0], self.nameFlags[0], - self.nameIndices[1], self.nameFlags[1], - self.nameIndices[2], self.nameFlags[2], - self.nameIndices[3], self.nameFlags[3], - self.handleSetNamePatternAnswerMsg) - else: - datagram = PyDatagram() - datagram.addUint16(CLIENT_SET_NAME_PATTERN) - datagram.addUint32(self.avId) - datagram.addInt16(self.nameIndices[0]) - datagram.addInt16(self.nameFlags[0]) - datagram.addInt16(self.nameIndices[1]) - datagram.addInt16(self.nameFlags[1]) - datagram.addInt16(self.nameIndices[2]) - datagram.addInt16(self.nameFlags[2]) - datagram.addInt16(self.nameIndices[3]) - datagram.addInt16(self.nameFlags[3]) - messenger.send('nameShopPost', [datagram]) + + base.cr.astronLoginManager.sendSetNamePattern(self.avId, self.nameIndices[0], self.nameFlags[0], + self.nameIndices[1], self.nameFlags[1], + self.nameIndices[2], self.nameFlags[2], + self.nameIndices[3], self.nameFlags[3], + self.handleSetNamePatternAnswerMsg) + + # let the user know we are waiting to hear back self.waitForServer() - if not __astron__: - def handleSetNamePatternAnswerMsg(self, di): - self.notify.debug('handleSetNamePatternAnswerMsg') - self.cleanupWaitForServer() - newavId = di.getUint32() - if newavId != self.avId: - self.notify.debug("doid's don't match up!") - self.rejectName(TTLocalizer.NameError) - returnCode = di.getUint8() - if returnCode == 0: - style = self.toon.getStyle() - avDNA = style.makeNetString() - self.notify.debug('pattern name accepted') - newPotAv = PotentialAvatar.PotentialAvatar(newavId, self.names, avDNA, self.index, 0) - self.avList.append(newPotAv) - self.doneStatus = 'done' - self.storeSkipTutorialRequest() - messenger.send(self.doneEvent) - else: - self.notify.debug('name pattern rejected') - self.rejectName(TTLocalizer.NameError) - return None - else: - def handleSetNamePatternAnswerMsg(self, newavId, returnCode): - self.notify.debug('handleSetNamePatternAnswerMsg') - self.cleanupWaitForServer() - if newavId != self.avId: - self.notify.debug("doid's don't match up!") - self.rejectName(TTLocalizer.NameError) - if returnCode == 1: - style = self.toon.getStyle() - avDNA = style.makeNetString() - self.notify.debug('pattern name accepted') - newPotAv = PotentialAvatar.PotentialAvatar(newavId, self.names, avDNA, self.index, 0) - self.avList.append(newPotAv) - self.doneStatus = 'done' - self.storeSkipTutorialRequest() - messenger.send(self.doneEvent) - else: - self.notify.debug('name pattern rejected') - self.rejectName(TTLocalizer.NameError) - return None + def handleSetNamePatternAnswerMsg(self, newavId, returnCode): + self.notify.debug('handleSetNamePatternAnswerMsg') + + # remove the wait msg + self.cleanupWaitForServer() + + # Get return code + if newavId != self.avId: + # Big trouble in little nameshop + self.notify.debug("doid's don't match up!") + self.rejectName(TTLocalizer.NameError) + pass + + if returnCode == 1: + style = self.toon.getStyle() + avDNA = style.makeNetString() + self.notify.debug("pattern name accepted") + # add the new potential avatar to the list + newPotAv = PotentialAvatar.PotentialAvatar(newavId, + self.names, + avDNA, + self.index, + 0) + self.avList.append(newPotAv) + # Everything is cool, send our done event + self.doneStatus = "done" + self.storeSkipTutorialRequest() + messenger.send(self.doneEvent) + else: + # name creation was rejected by server + self.notify.debug("name pattern rejected") + self.rejectName(TTLocalizer.NameError) + + return None def _submitTypeANameAsPickAName(self): - pnp = TTPickANamePattern(self.nameEntry.get(), self.toon.style.gender) + pnp = TTPickANamePattern(self.nameEntry.get()) if pnp.hasNamePattern(): + # submit the name as a pick-a-name + # manipulate the GUI elements to pick up NameShop GUI-related code pattern = pnp.getNamePattern() self.fsm.request('PickAName') - flags = [pattern[0] != -1, pattern[1] != -1, pattern[2] != -1] + flags = [pattern[0] != -1, pattern[1] != -1, pattern[2] != -1, ] names = [] for i in range(len(pattern)): if pattern[i] != -1: - names.append(pnp.getNamePartString(self.toon.style.gender, i, pattern[i])) + names.append(pnp.getNamePartString(i, pattern[i])) else: names.append('') - - fullName = pnp.getNameString(pattern, self.toon.style.gender) + fullName = pnp.getNameString(pattern) self._updateGuiWithPickAName(flags, names, fullName) + # now that the gui has been set to the new name, submit it self.__handleDone() return True return False - def checkNameTyped(self, justCheck = False): + def checkNameTyped(self, justCheck=False): self.notify.debug('checkNameTyped') + + # if it can be submitted as a pick-a-name, don't bother checking with the server if self._submitTypeANameAsPickAName(): return - if not __astron__: - datagram = PyDatagram() - datagram.addUint16(CLIENT_SET_WISHNAME) + if justCheck: + # just have the server check the name, don't assign it to + # any avatar avId = 0 else: avId = self.avId - if not __astron__: - datagram.addUint32(avId) - datagram.addString(self.nameEntry.get()) - messenger.send('nameShopPost', [datagram]) - else: - base.cr.astronLoginManager.sendSetNameTyped(avId, self.nameEntry.get(), self.handleSetNameTypedAnswerMsg) + + base.cr.astronLoginManager.sendSetNameTyped(avId, self.nameEntry.get(), self.handleSetNameTypedAnswerMsg) + + # let the user know we are waiting to hear back self.waitForServer() - if not __astron__: - def handleSetNameTypedAnswerMsg(self, di): - self.notify.debug('handleSetNameTypedAnswerMsg') - self.cleanupWaitForServer() - newavId = di.getUint32() - if newavId and newavId != self.avId: - self.notify.debug("doid's don't match up!") - self.rejectName(TTLocalizer.NameError) - returnCode = di.getUint16() - if newavId == 0: - if returnCode == 0: - pendingname = di.getString() - approvedname = di.getString() - rejectedname = di.getString() - if pendingname != '': - self.notify.debug('name check pending') - self.fsm.request('Approval') - elif approvedname != '': - self.notify.debug('name check accepted') - self.nameAction = 2 - self.serverCreateAvatar() - elif rejectedname != '': - self.notify.debug('name check rejected') - self.fsm.request('TypeAName') - self.rejectName(TTLocalizer.NameError) - else: - self.notify.debug('typed name response did not contain any return fields') - self.rejectName(TTLocalizer.NameError) - elif returnCode == 0: - wishname = di.getString() - approvedname = di.getString() - rejectedname = di.getString() - if approvedname != '': - style = self.toon.getStyle() - avDNA = style.makeNetString() - self.names[0] = self.nameEntry.get() - self.notify.debug('typed name accepted') - newPotAv = PotentialAvatar.PotentialAvatar(newavId, self.names, avDNA, self.index, 0) - self.avList.append(newPotAv) - self.fsm.request('Accepted') - elif wishname != '': - style = self.toon.getStyle() - avDNA = style.makeNetString() - self.names[1] = self.nameEntry.get() - self.notify.debug('typed name needs approval') - newPotAv = PotentialAvatar.PotentialAvatar(newavId, self.names, avDNA, self.index, 1) - if not self.newwarp: - self.avList.append(newPotAv) - self.fsm.request('ApprovalAccepted') - elif rejectedname != '': - self.fsm.request('Rejected') - else: - self.notify.debug("name typed accepted but didn't fill any return fields") - self.rejectName(TTLocalizer.NameError) - else: - self.notify.debug('name typed rejected') - self.rejectName(TTLocalizer.NameError) - return None - else: - def handleSetNameTypedAnswerMsg(self, newavId, returnCode): - self.notify.debug('handleSetNameTypedAnswerMsg') - self.cleanupWaitForServer() - if newavId and newavId != self.avId: - self.notify.debug("doid's don't match up!") - self.rejectName(TTLocalizer.NameError) - if newavId == 0: - if returnCode == 1: - self.notify.debug('name check pending') - self.fsm.request('Approval') - elif returnCode == 2: - self.notify.debug('name check accepted') - self.nameAction = 2 - self.serverCreateAvatar() - elif returnCode == 0: - self.notify.debug('name check rejected') - self.fsm.request('TypeAName') - self.rejectName(TTLocalizer.NameError) - else: - self.notify.debug('typed name response did not contain any return fields') - self.rejectName(TTLocalizer.NameError) - else: - if returnCode == 2: - style = self.toon.getStyle() - avDNA = style.makeNetString() - self.names[0] = self.nameEntry.get() - self.notify.debug('typed name accepted') - newPotAv = PotentialAvatar.PotentialAvatar(newavId, self.names, avDNA, self.index, 0) - self.avList.append(newPotAv) - self.fsm.request('Accepted') - elif returnCode == 1: - style = self.toon.getStyle() - avDNA = style.makeNetString() - self.names[1] = self.nameEntry.get() - self.notify.debug('typed name needs approval') - newPotAv = PotentialAvatar.PotentialAvatar(newavId, self.names, avDNA, self.index, 1) - if not self.newwarp: - self.avList.append(newPotAv) - self.fsm.request('ApprovalAccepted') - elif returnCode == 0: - self.fsm.request('Rejected') - else: - self.notify.debug("name typed accepted but didn't fill any return fields") - self.rejectName(TTLocalizer.NameError) + def handleSetNameTypedAnswerMsg(self, newavId, returnCode): + self.notify.debug('handleSetNameTypedAnswerMsg') - def serverCreateAvatar(self, skipTutorial = False): + # remove the wait msg + self.cleanupWaitForServer() + + # avId is 0 if we just wanted to check the name + if newavId and newavId != self.avId: + # Big trouble in little nameshop + self.notify.debug("doid's don't match up!") + self.rejectName(TTLocalizer.NameError) + pass + + if (newavId == 0): + # we were just checking the name to see if it would be rejected + if returnCode == 1: + # name will need to be approved by a human + self.notify.debug("name check pending") + self.fsm.request("Approval") + elif returnCode == 2: + # it was accepted. continue with the process, create the avatar + self.notify.debug("name check accepted") + self.nameAction = 2 + self.serverCreateAvatar() + elif returnCode == 0: + # it was rejected. + self.notify.debug("name check rejected") + self.fsm.request('TypeAName') + self.rejectName(TTLocalizer.NameError) + else: + # Something went wrong! + self.notify.debug( + "typed name response did not contain any return fields") + self.rejectName(TTLocalizer.NameError) + + else: + if returnCode == 2: + style = self.toon.getStyle() + avDNA = style.makeNetString() + self.names[0] = self.nameEntry.get() + self.notify.debug("typed name accepted") + # add the new potential avatar to the list + newPotAv = PotentialAvatar.PotentialAvatar(newavId, + self.names, + avDNA, + self.index, + 0) + self.avList.append(newPotAv) + self.fsm.request("Accepted") + + if returnCode == 1: + style = self.toon.getStyle() + avDNA = style.makeNetString() + self.names[1] = self.nameEntry.get() + self.notify.debug("typed name needs approval") + # add the new potential avatar to the list + newPotAv = PotentialAvatar.PotentialAvatar(newavId, + self.names, + avDNA, + self.index, + 1) + if not self.newwarp: + self.avList.append(newPotAv) + self.fsm.request("ApprovalAccepted") + elif returnCode == 0: + self.fsm.request("Rejected") + else: + # Something went wrong! + self.notify.debug( + "name typed accepted but didn't fill any return fields") + self.rejectName(TTLocalizer.NameError) + + return None + + def serverCreateAvatar(self, skipTutorial=False): self.notify.debug('serverCreateAvatar') + style = self.toon.getStyle() self.newDNA = style.makeNetString() if skipTutorial: self.requestingSkipTutorial = True else: self.requestingSkipTutorial = False - if not self.avExists or self.avExists and self.avId == 'deleteMe': - messenger.send('nameShopCreateAvatar', [style, '', self.index]) - if __astron__: - self.accept('nameShopCreateAvatarDone', self.handleCreateAvatarResponseMsg) + + # if the avatar doesn't exist, or exists and we want to delete it + if not self.avExists or (self.avExists and self.avId == 'deleteMe'): + messenger.send("nameShopCreateAvatar", [style, "", self.index]) + self.accept('nameShopCreateAvatarDone', self.handleCreateAvatarResponseMsg) else: + # otherwise, just set the new name self.checkNameTyped() + self.notify.debug('Ending Make A Toon: %s' % self.toon.style) base.cr.centralLogger.writeClientEvent('MAT - endingMakeAToon: %s' % self.toon.style) - if not __astron__: - def handleCreateAvatarResponseMsg(self, di): - self.notify.debug('handleCreateAvatarResponseMsg') - echoContext = di.getUint16() - returnCode = di.getUint8() - if returnCode == 0: - self.notify.debug('avatar with default name accepted') - self.avId = di.getUint32() - self.avExists = 1 - self.logAvatarCreation() - if self.nameAction == 0: - self.toon.setName(self.names[0]) - newPotAv = PotentialAvatar.PotentialAvatar(self.avId, self.names, self.newDNA, self.index, 1) - self.avList.append(newPotAv) - self.doneStatus = 'done' - self.storeSkipTutorialRequest() - messenger.send(self.doneEvent) - elif self.nameAction == 1: - self.checkNamePattern() - elif self.nameAction == 2: - self.checkNameTyped() - else: - self.notify.debug('avatar invalid nameAction') - self.rejectName(TTLocalizer.NameError) - else: - self.notify.debug('avatar rejected') - self.rejectName(TTLocalizer.NameError) - return None - else: - def handleCreateAvatarResponseMsg(self, avId): - self.notify.debug('handleCreateAvatarResponseMsg') - self.notify.debug('avatar with default name accepted') + def handleCreateAvatarResponseMsg(self, avId): + self.notify.debug('handleCreateAvatarResponseMsg') + # Unnecessary echo context + echoContext = 0 + # Get return code + returnCode = 0 + if returnCode == 0: + self.notify.debug("avatar with default name accepted") self.avId = avId self.avExists = 1 - self.logAvatarCreation() + # If they just want 'blue duck' if self.nameAction == 0: self.toon.setName(self.names[0]) - newPotAv = PotentialAvatar.PotentialAvatar(self.avId, self.names, self.newDNA, self.index, 1) + # add the new potential avatar to the list + newPotAv = PotentialAvatar.PotentialAvatar(self.avId, + self.names, + self.newDNA, + self.index, + 1) self.avList.append(newPotAv) - self.doneStatus = 'done' + + # Send our done event + self.doneStatus = "done" self.storeSkipTutorialRequest() messenger.send(self.doneEvent) + # If they used pickAName and there are indices to send elif self.nameAction == 1: self.checkNamePattern() + # If they used typeAName and there is a name to send elif self.nameAction == 2: self.checkNameTyped() else: - self.notify.debug('avatar invalid nameAction') + # Trouble, reject anyway + self.notify.debug("avatar invalid nameAction") self.rejectName(TTLocalizer.NameError) + else: + + # create was rejected by server + self.notify.debug("avatar rejected") + self.rejectName(TTLocalizer.NameError) + + return None def waitForServer(self): - self.waitForServerDialog = TTDialog.TTDialog(text=TTLocalizer.WaitingForNameSubmission, style=TTDialog.NoButtons) + # let the user know we are waiting to hear back from server (in case it hangs) + self.waitForServerDialog = TTDialog.TTDialog( + text=TTLocalizer.WaitingForNameSubmission, + style=TTDialog.NoButtons) self.waitForServerDialog.show() def cleanupWaitForServer(self): - if self.waitForServerDialog != None: + if self.waitForServerDialog is not None: self.waitForServerDialog.cleanup() self.waitForServerDialog = None - return def printTypeANameInfo(self, str): sourceFilename, lineNumber, functionName = PythonUtil.stackEntryInfo(1) - self.notify.debug('========================================\n%s : %s : %s' % (sourceFilename, lineNumber, functionName)) + self.notify.debug("========================================\n" + "%s : %s : %s" % (sourceFilename, lineNumber, functionName)) self.notify.debug(str) + # return curPos = self.typeANameButton.getPos() - self.notify.debug('Pos = %.2f %.2f %.2f' % (curPos[0], curPos[1], curPos[2])) + self.notify.debug("Pos = %.2f %.2f %.2f" % (curPos[0], curPos[1], curPos[2])) parent = self.typeANameButton.getParent() parentPos = parent.getPos() - self.notify.debug('Parent = %s' % parent) - self.notify.debug('ParentPos = %.2f %.2f %.2f' % (parentPos[0], parentPos[1], parentPos[2])) + self.notify.debug("Parent = %s" % parent) + self.notify.debug("ParentPos = %.2f %.2f %.2f" % (parentPos[0], parentPos[1], parentPos[2])) def storeSkipTutorialRequest(self): + """Store our skip tutorial request in cr, as NameShop gets deleted. + Also check the config variable if we want the tutorial or not.""" base.cr.skipTutorialRequest = self.requestingSkipTutorial + def __isFirstTime(self): + """ + Determines whether this is the first time make a toon experience for the player. + Prompt the skip tutorial if this not the first time experience. + """ + # Go Straight to create avatar (don't pop up the skip tutorial prompt) + # if it's the player's first MAT experience or + # if the player has come into MAT in the warp mode, ie just to name his toon. if not self.makeAToon.nameList or self.makeAToon.warp: self.__createAvatar() else: self.promptTutorial() def promptTutorial(self): - self.promptTutorialDialog = TTDialog.TTDialog(parent=aspect2dp, text=TTLocalizer.PromptTutorial, text_scale=0.06, text_align=TextNode.ACenter, text_wordwrap=22, command=self.__openTutorialDialog, fadeScreen=0.5, style=TTDialog.TwoChoice, buttonTextList=[TTLocalizer.MakeAToonEnterTutorial, TTLocalizer.MakeAToonSkipTutorial], button_text_scale=0.06, buttonPadSF=5.5, sortOrder=DGG.NO_FADE_SORT_INDEX) + """ + This brings up a pop up window which prompts the player if they want to + go to the tutorial or skip it. + """ + self.promptTutorialDialog = TTDialog.TTDialog( + ## doneEvent = "exitMAT", + parent=aspect2dp, + text=TTLocalizer.PromptTutorial, + text_scale=0.06, + text_align=TextNode.ACenter, + text_wordwrap=22, + ## topPad = -0.05, + ## midPad = 1.25, + ## sidePad = 0.0, + command=self.__openTutorialDialog, + fadeScreen=.5, + style=TTDialog.TwoChoice, + ## style = TTDialog.Acknowledge, + buttonTextList=[TTLocalizer.MakeAToonEnterTutorial, TTLocalizer.MakeAToonSkipTutorial], + button_text_scale=0.06, + buttonPadSF=5.5, + sortOrder=DGG.NO_FADE_SORT_INDEX, + ) self.promptTutorialDialog.show() - def __openTutorialDialog(self, choice = 0): + def __openTutorialDialog(self, choice=0): if choice == 1: self.notify.debug('enterTutorial') - if base.config.GetBool('want-qa-regression', 0): - self.notify.info('QA-REGRESSION: ENTERTUTORIAL: Enter Tutorial') self.__createAvatar() else: self.notify.debug('skipTutorial') - if base.config.GetBool('want-qa-regression', 0): - self.notify.info('QA-REGRESSION: SKIPTUTORIAL: Skip Tutorial') self.__handleSkipTutorial() - self.promptTutorialDialog.destroy() - - def logAvatarCreation(self): - dislId = 0 - try: - dislId = launcher.getValue('GAME_DISL_ID') - except: - pass - - if not dislId: - self.notify.warning('No dislId, using 0') - dislId = 0 - gameSource = '0' - try: - gameSource = launcher.getValue('GAME_SOURCE') - except: - pass - - if not gameSource: - gameSource = '0' - else: - self.notify.info('got GAME_SOURCE=%s' % gameSource) - if self.avId > 0: - base.cr.centralLogger.writeClientEvent('createAvatar %s-%s-%s' % (self.avId, dislId, gameSource)) - self.notify.debug('createAvatar %s-%s-%s' % (self.avId, dislId, gameSource)) - else: - self.notify.warning('logAvatarCreation got self.avId =%s' % self.avId) + self.promptTutorialDialog.destroy() \ No newline at end of file diff --git a/toontown/makeatoon/ShuffleButton.py b/toontown/makeatoon/ShuffleButton.py index dd19b97..4cc39e3 100644 --- a/toontown/makeatoon/ShuffleButton.py +++ b/toontown/makeatoon/ShuffleButton.py @@ -28,7 +28,7 @@ class ShuffleButton: shuffleArrowDisabled = gui.find('**/tt_t_gui_mat_shuffleArrowDisabled') gui.removeNode() del gui - self.parentFrame = DirectFrame(parent=self.parent.parentFrame, relief=DGG.RAISED, pos=(0, 0, -1), frameColor=(1, 0, 0, 0)) + self.parentFrame = DirectFrame(parent=self.parent.parentFrame, relief=DGG.RAISED, pos=(0, 0, -1.1), frameColor=(1, 0, 0, 0)) self.shuffleFrame = DirectFrame(parent=self.parentFrame, image=shuffleFrame, image_scale=halfButtonInvertScale, relief=None, frameColor=(1, 1, 1, 1)) self.shuffleFrame.hide() self.shuffleBtn = DirectButton(parent=self.parentFrame, relief=None, image=(shuffleUp, shuffleDown, shuffleUp), image_scale=halfButtonInvertScale, image1_scale=(-0.63, 0.6, 0.6), image2_scale=(-0.63, 0.6, 0.6), text=(TTLocalizer.ShuffleButton, diff --git a/toontown/makeatoon/TTPickANamePattern.py b/toontown/makeatoon/TTPickANamePattern.py index d5df1b3..85679aa 100644 --- a/toontown/makeatoon/TTPickANamePattern.py +++ b/toontown/makeatoon/TTPickANamePattern.py @@ -11,8 +11,6 @@ class TTPickANamePattern(PickANamePatternTwoPartLastName): if TTPickANamePattern.NameParts is None: TTPickANamePattern.NameParts = {} ng = NameGenerator() - TTPickANamePattern.NameParts['m'] = ng.getMaleNameParts() - TTPickANamePattern.NameParts['f'] = ng.getFemaleNameParts() TTPickANamePattern.NameParts['n'] = ng.getAllNameParts() return TTPickANamePattern.NameParts['n'] diff --git a/toontown/quest/QuestParser.py b/toontown/quest/QuestParser.py index d728ae9..79ce5b7 100644 --- a/toontown/quest/QuestParser.py +++ b/toontown/quest/QuestParser.py @@ -486,9 +486,53 @@ class NPCMoviePlayer(DirectObject.DirectObject): self.setVar(varName, dialogue) return + def parseLoadCCDialogue(self, line): + token, varName, filenameTemplate = line + # TODO figure out the option for ppl who want minnie to show them around + classicChar = 'mickey' + + filename = filenameTemplate % classicChar + if base.config.GetString('language', 'english') == 'japanese': + dialogue = base.loader.loadSfx(filename) + else: + dialogue = None + self.setVar(varName, dialogue) + return + def parseLoadChar(self, line): + token, name, charType = line + char = Char.Char() + dna = CharDNA.CharDNA() + dna.newChar(charType) + char.setDNA(dna) + if charType == 'mk' or charType == 'mn': + char.startEarTask() + char.nametag.manage(base.marginManager) + char.addActive() + char.hideName() + self.setVar(name, char) - + def parseLoadClassicChar(self, line): + token, name = line + char = Char.Char() + dna = CharDNA.CharDNA() + charType = 'mk' + dna.newChar(charType) + char.setDNA(dna) + char.startEarTask() + char.nametag.manage(base.marginManager) + char.addActive() + char.hideName() + self.setVar(name, char) + self.chars.append(char) + + def parseUnloadChar(self, line): + token, name = line + char = self.getVar(name) + track = Sequence() + track.append(Func(self.__unloadChar, char)) + track.append(Func(self.delVar, name)) + return track def parseLoadSuit(self, line): diff --git a/toontown/suit/DistributedBossbotBoss.py b/toontown/suit/DistributedBossbotBoss.py index d2edfb5..9a375fc 100644 --- a/toontown/suit/DistributedBossbotBoss.py +++ b/toontown/suit/DistributedBossbotBoss.py @@ -195,7 +195,7 @@ class DistributedBossbotBoss(DistributedBossCog.DistributedBossCog, FSM.FSM): npc.setPickable(0) npc.setPlayerType(NametagGroup.CCNonPlayer) dna = ToonDNA.ToonDNA() - dna.newToonRandom(335933, 'm', 1) + dna.newToonRandom(335933, 1, 1) dna.head = 'sls' npc.setDNAString(dna.makeNetString()) npc.animFSM.request('neutral') diff --git a/toontown/suit/DistributedCashbotBoss.py b/toontown/suit/DistributedCashbotBoss.py index b4cdfce..640ead4 100644 --- a/toontown/suit/DistributedCashbotBoss.py +++ b/toontown/suit/DistributedCashbotBoss.py @@ -103,7 +103,7 @@ class DistributedCashbotBoss(DistributedBossCog.DistributedBossCog, FSM.FSM): npc.setPickable(0) npc.setPlayerType(NametagGroup.CCNonPlayer) dna = ToonDNA.ToonDNA() - dna.newToonRandom(146392, 'f', 1) + dna.newToonRandom(146392, 0, 1) dna.head = 'pls' npc.setDNAString(dna.makeNetString()) npc.animFSM.request('neutral') diff --git a/toontown/toon/NPCFriendPanel.py b/toontown/toon/NPCFriendPanel.py index b4f4904..4b8af4b 100644 --- a/toontown/toon/NPCFriendPanel.py +++ b/toontown/toon/NPCFriendPanel.py @@ -209,10 +209,14 @@ class NPCFriendCard(DirectFrame): NPCInfo = NPCToons.NPCToonDict[NPCID] dnaList = NPCInfo[2] eyelashes = NPCInfo[3] + if eyelashes == 'm': + eyelashes = 0 + elif eyelashes == 'f': + eyelashes = 1 if dnaList == 'r': dnaList = NPCToons.getRandomDNA(NPCID, eyelashes) dna = ToonDNA.ToonDNA() - dna.newToonFromProperties(*dnaList) + dna.newToonFromProperties(*dnaList, isNPC=True) head = ToonHead.ToonHead() head.setupHead(dna, forGui=1) self.fitGeometry(head, fFlip=1, dimension=dimension) diff --git a/toontown/toon/NPCToons.py b/toontown/toon/NPCToons.py index bd2bccf..b55aa75 100644 --- a/toontown/toon/NPCToons.py +++ b/toontown/toon/NPCToons.py @@ -63,6 +63,7 @@ TAILOR_COUNTDOWN_TIME = 300 RTDNAFile = '/RTDNAFile.txt' saveDNA = False + def getRandomDNA(seed, eyelashes): randomDNA = ToonDNA.ToonDNA() randomDNA.newToonRandom(seed, eyelashes, 1) @@ -139,7 +140,8 @@ def createNPC(air, npcId, desc, zoneId, posIndex = 0, questCallback = None): rtDnaFile = open(RTDNAFile, 'w') rtDnaFile.writelines(rtDNA) rtDnaFile.close() - dna.newToonFromProperties(*dnaList) + + dna.newToonFromProperties(*dnaList, isNPC=True) npc.setDNAString(dna.makeNetString()) npc.setHp(15) npc.setMaxHp(15) @@ -179,7 +181,7 @@ def createLocalNPC(npcId): dnaList = getRandomDNA(npcId, eyelashes) else: dnaList = dnaType - dna.newToonFromProperties(*dnaList) + dna.newToonFromProperties(*dnaList, isNPC=True) npc.setDNAString(dna.makeNetString()) npc.animFSM.request('neutral') return npc diff --git a/toontown/toon/Toon.py b/toontown/toon/Toon.py index 1d22027..e21484d 100644 --- a/toontown/toon/Toon.py +++ b/toontown/toon/Toon.py @@ -501,6 +501,7 @@ class Toon(Avatar.Avatar, ToonHead): self.shoes = (0, 0, 0) self.isStunned = 0 self.isDisguised = 0 + self.eyelashes = 0 self.defaultColorScale = None self.jar = None self.setTag('pieCode', str(ToontownGlobals.PieCodeToon)) @@ -3033,6 +3034,9 @@ class Toon(Avatar.Avatar, ToonHead): def exitScientistPlay(self): self.stop() + def setEyelashes(self, eyelashes): + self.eyelashes = eyelashes + loadModels() compileGlobalAnimList() diff --git a/toontown/toon/ToonDNA.py b/toontown/toon/ToonDNA.py index e6aeba3..75d2080 100644 --- a/toontown/toon/ToonDNA.py +++ b/toontown/toon/ToonDNA.py @@ -643,21 +643,41 @@ GirlBottoms = [('phase_3/maps/desat_skirt_1.png', SKIRT), Bottoms = GirlBottoms -# cycle through boyshorts if any any of them are not in girlbottoms add them to bottoms -for pair in BoyShorts: - if pair[0] not in Bottoms: - Bottoms.append((pair, SHORTS)) +# add all shorts in BoyShorts to Bottoms +for short in BoyShorts: + Bottoms.append((short, SHORTS)) -# a function to convert old male bottoms id to new bottoms id -def convertBoyShorts(oldId): - # go through boyshorts and bottoms - for pair in BoyShorts: - # if the old id is in boyshorts return the new id - if oldId == pair[0]: - return Bottoms.index(pair) +# remove any duplicates +for bottom in Bottoms: + if Bottoms.count(bottom) > 1: + Bottoms.remove(bottom) + + + + + +# a function to convert old NPC bottom id to new bottoms id +def convertNPCSBottoms(oldId, kind): + if kind == 'm': + for index, short in enumerate(BoyShorts): + if index == oldId: + return Bottoms.index((short, SHORTS)) + elif kind == 'f': + for index, bottom in enumerate(GirlBottoms): + if index == oldId: + if bottom[1] == SKIRT: + return Bottoms.index((bottom[0], SKIRT)) + else: + return Bottoms.index((bottom[0], SHORTS)) return oldId + + + + + + ClothesColors = [VBase4(0.933594, 0.265625, 0.28125, 1.0), VBase4(0.863281, 0.40625, 0.417969, 1.0), VBase4(0.710938, 0.234375, 0.4375, 1.0), @@ -2085,7 +2105,16 @@ class ToonDNA(AvatarDNA.AvatarDNA): notify.error("tuple must be in format ('%s', '%s', '%s', '%s')") return - def newToonFromProperties(self, head, torso, legs, eyelashes, armColor, gloveColor, legColor, headColor, topTexture, topTextureColor, sleeveTexture, sleeveTextureColor, bottomTexture, bottomTextureColor): + def newToonFromProperties(self, head, torso, legs, eyelashes, armColor, gloveColor, legColor, headColor, topTexture, topTextureColor, sleeveTexture, sleeveTextureColor, bottomTexture, bottomTextureColor, isNPC=0): + if eyelashes == 'm': + eyelashes = 1 + kind = 'm' + elif eyelashes == 'f': + eyelashes = 0 + kind = 'f' + if isNPC: + # convert the old bottom id to the new one + bottomTexture = convertNPCSBottoms(bottomTexture, kind) self.type = 't' self.head = head self.torso = torso diff --git a/toontown/toonbase/TTLocalizerEnglish.py b/toontown/toonbase/TTLocalizerEnglish.py index 2416935..b1ee4a1 100644 --- a/toontown/toonbase/TTLocalizerEnglish.py +++ b/toontown/toonbase/TTLocalizerEnglish.py @@ -5381,6 +5381,7 @@ GenderShopGirlButtonText = 'Girl' BodyShopHead = 'Head' BodyShopBody = 'Body' BodyShopLegs = 'Legs' +BodyShopEyelashes = 'Eyelashes' ColorShopToon = 'Toon Color' ColorShopHead = 'Head' ColorShopBody = 'Body'