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") boyTitles = [] girlTitles = [] neutralTitles = [] boyFirsts = [] girlFirsts = [] neutralFirsts = [] capPrefixes = [] lastPrefixes = [] lastSuffixes = [] 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 = [] self.boyFirsts = [] self.girlFirsts = [] self.neutralFirsts = [] self.capPrefixes = [] 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')) currentLine = input.readline() 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): # 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 getAllNameParts(self): return self._getNameParts({0: 0, 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: newtu[0] = (8, name) for tu in list(self.nameDictionary.items()): for g in newtu: if tu[1] == g: return tu[0] return -1 def findWidestInList(self, text, nameList): maxWidth = 0 maxName = "" for name in nameList: width = text.calcWidth(name) if width > maxWidth: maxWidth = text.calcWidth(name) maxName = name 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]) 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]) def findWidestTitle(self): 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) return widestFirst def findWidestLastName(self): 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()]) return widestWord def findWidestNameWidth(self): name = self.findWidestName() return self.text.calcWidth(name) def printWidestName(self): name = self.findWidestName() width = self.text.calcWidth(name) widthStr = str(width) 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)")) 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): # Randomly pick the name sex boy = random.choice([0, 1]) girl = not boy # 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")): titleFlag = 1 firstFlag = 0 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") ): lastFlag = 1 retString = "" if titleFlag: # Shallow copy, since we will be altering the list titleList = self.neutralTitles[:] 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[:] 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 += " " 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): """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")): titleFlag = 1 firstFlag = 0 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")): lastFlag = 1 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 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] + " " if firstFlag: retString += uberReturn[4] # Put a space if there is going to be a last name. if lastFlag: retString += " " if lastFlag: retString += uberReturn[5] + uberReturn[6] uberReturn.append(retString) return uberReturn def printRandomNames(self, boy=0, girl=0, total=1): i = 0 origBoy = boy origGirl = girl while i < total: 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) if boy: print("Boy: " + name + " (" + widthStr + " units)") if girl: print("Girl: " + name + " (" + widthStr + " units)") i += 1 def percentOver(self, limit=9.0, samples=1000): i = 0 over = 0 while i < samples: name = self.randomName() width = self.text.calcWidth(name) if width > limit: over += 1 i += 1 percent = (float(over) / float(samples)) * 100 print(("Samples: " + str(samples) + " Over: " + str(over) + " Percent: " + str(percent))) def totalNames(self): # 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)) # 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)) # 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)) # 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)) # 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)) # Total totalNames = (firsts + lasts + totalTitleFirsts + totalTitleLasts + totalFirstLasts + totalTitleFirstLasts) print("Total Names: " + str(totalNames))