Last Update: 15.05.2007. By kerim in game development | python | snipplet
Ever tried to create names for Roleplaying Games (and other things) ?
In the process of implementing an MMORPG i asked myself how that could be done. Might be usefull for NPCs for example.
I found a nice article here about the topic but sadly the code didn’t work anymore.
So i made a small implementation in python that does the job.
It works so i will implement it in java later.
Anyway .. here is the code along with some explanations ....
As a reference we use the following definition file for our names.
NameData.xml
I think its rather self explanatory.
We have two lists here. One for the templates and one for the phonemes.
Templates
Each templates has a name to be more desscriptive for the user (you might want to give them a dialog for choosing the template they want) and a list of phonemic parts that make up a name.
The phonemic parts contain information about the writing (e.g. capitalized or normal) and the name of the phoneme to use.
Which brings us to the list of …
Phonemes
Each phoneme has (you guessed it) a name (which is referenced in the template) and a list of letters that fit that phoneme.
As example : the phoneme “Vowels” contains the letters “a,e,i,o,u”
That was the short introduction.
You might wish to go to the article i mentioned above for a better introductino to phonetics. I will concentrate only on the code.
#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-
import xml.dom.minidom, random
from xml.sax.saxutils import escape
#----classes to store the objcts contained in the xml
class TemplatePart:
def __init__(self,aType,aPart):
self.type=aType
self.phonemePart=aPart
def __repr__(self):
return "<TemplatePart %s , %s>" % (self.type, self.phonemePart)
class Template:
def __init__(self,aName,aPartsList):
self.name=aName
self.partsList=aPartsList
def __repr__(self):
return "<Template %s , %s>" % (self.name, self.partsList)
class Phoneme:
def __init__(self,aName,aPartList):
self.name=aName
self.parts=aPartList
#class reading in the xml file and generating names
class NameGenerator:
def __init__(self):
self.phonemeList=[]
self.templateList=[]
def loadXMLDefinitions(self,xmlString):
dom = xml.dom.minidom.parseString(xmlString)
templates = dom.getElementsByTagName("NameTemplate")
phonemes=dom.getElementsByTagName("Phoneme")
assert len(templates)>0
assert len(phonemes)>0
self.loadTemplates(templates)
self.loadPhonemes(phonemes)
def loadPhonemes(self,phonemes):
for i in range (0,len (phonemes)):
name=phonemes[i].getAttribute("Name")
pList=phonemes[i].getElementsByTagName("Part")
partsList=[]
for y in range (0,len(pList)):
partsList.append(pList[y]._get_firstChild().nodeValue)
#print partsList
#print "----"
phoneme=Phoneme(name,partsList)
self.phonemeList.append(phoneme)
def loadTemplates(self,templates):
for i in range (0,len (templates)):
name=templates[i].getAttribute("Name")
pList=templates[i].getElementsByTagName("Part")
partsList=[]
for y in range (0,len(pList)):
type=pList[y].getAttribute("Type")
content=pList[y]._get_firstChild().nodeValue
templatePart=TemplatePart(type,content)
partsList.append(templatePart)
#print partsList
#print "----"
template=Template(name,partsList)
self.templateList.append(template)
def loadFile(self, xmlFileName):
fd = open(xmlFileName, "r")
xmlString = fd.read()
fd.close()
return xmlString
# creates a name following the rules in template templateNo
def generateName(self, templateNo):
name=""
template=self.templateList[templateNo]
parts=template.partsList
for y in range(0,len(parts)):
tpart=parts[y]
type=tpart.type
for z in range (0,len(self.phonemeList)):
phoneme=self.phonemeList[z]
if phoneme.name==tpart.phonemePart:
letter=phoneme.parts[random.randint(0,len(phoneme.parts)-1)]
if type=="Cap":
letter=letter.capitalize()
name=name+letter
return name
def main():
ng= NameGenerator()
xmlString = ng.loadFile("NameData.xml")
ng.loadXMLDefinitions(xmlString)
#print ng.templateList
#print ("testing with some names")
templateNo=4
print "creating names accoring to template %s" %(ng.templateList[templateNo].name)
for i in range (0,10):
print ng.generateName(templateNo)
if __name__ == "__main__":
main()
This is not really the best and most elegant way to parse it … but it works and is self explanatory ;-)
As an addition you might want to change the main method and allow for parameters (command line) or show a gui for the user.
I think the xml could use some additions because the names that are generated here could be more diverse.
If you happen to use that code (and the xml) and make modifications i would be glad for any email at kmansourATwebDOTde.