Code: Select all
###########################################
# #
# Dynamic Book Template v4.1 by D'Lanor #
# #
###########################################
# Change each occurrence of *YourAge* to the actual name of your age.
# Do the same with the file names.
from Plasma import *
from PlasmaTypes import *
from PlasmaKITypes import *
from PlasmaNetConstants import *
import xLinkingBookDefs
actClickableObject = ptAttribActivator(1, 'Act: Clickable Object')
strObject = ptAttribString(2, 'Object String')
Behavior = ptAttribBehavior(3, 'Avatar link animation (optional)')
### DO NOT CHANGE THESE VARIABLES/CONSTANTS! ###
ourBook = None
bkLinks = []
ageLinkStruct = None
kLinkID = 1
publicAges = []
kPublicAgeLink = 6
kPublicAgesMOUL = ['city',
'Neighborhood',
'Neighborhood02',
'GreatTreePub',
'GuildPub-Cartographers',
'GuildPub-Greeters',
'GuildPub-Maintainers',
'GuildPub-Messengers',
'GuildPub-Writers',
'philRelto',
'Kveer']
### CHANGE THE GLOBAL CONSTANTS BELOW TO FIT YOUR AGE ######################################
# #
# modPageDefs: Replace *YourAge*PageDefs with the name of the module that contains your #
# page definitions. #
# ageBooks These are your clickable objects. They must be defined in *YourAge*PageDefs #
# in the AgeBooks Dictionary Section by the same name(s). #
# bookPages Names in bookPages must be defined in the *YourAge*PageDefs file under #
# BookPages. An ageBook can have multiple bookPages as long as they are #
# enclosed together between the same square brackets. #
# Always keep the nesting structure [[double square brackets]] intact! #
# parentAge If you are using the kChildAgeBook linking rule you can set a parent age. #
# Child ages are only useful for ages which have multiple owners (currently #
# only Neighborhood!). All parent age owners share the same instance of the #
# child age. Using any other parent age than Neighborhood makes no sense. #
# kLinkDelay Delay for the optional avatar link animation to finish. You may have to #
# tweak it since 3.5 is an estimate. #
# vOpenSource For future Uru Open Source support. For now keep this set to false. #
# #
# If there are multiple books in an age the code will find the right one automagically. #
# You can add as many books as you like. Just define them in the global variables ageBooks #
# and bookPages. The order is important here. The first book will be matched to the first #
# page list, the second book to the second page list etc. #
############################################################################################
modPageDefs = 's122PageDefs'
ageBooks = ['122Journal01','122BookLink01']
bookPages = [['Journal01'],['ShipHanger']]
parentAge = 'Neighborhood'
kLinkDelay = 3.5
vOpenSource = false
class s122BookGUI(ptModifier,):
def __init__(self):
ptModifier.__init__(self)
self.version = '4.1'
self.me = self.__class__.__name__
self.PageDefs = __import__(modPageDefs)
print ('__init__%s v.%s' % (self.me, self.version))
def OnNotify(self, state, id, events):
if ((id == actClickableObject.id) and state):
print ('%s: OnNotify: Someone clicked on object %s' % (self.me, strObject.value))
if PtWasLocallyNotified(self.key):
print 'It was you'
for (a, b,) in zip(ageBooks, bookPages):
print ('Trying book %s with page(s) %s' % (a, b))
if (strObject.value == a):
print 'Match found! Start opening book...'
self.IOpenBook(a, b)
break
else:
print 'No match'
else:
for event in events:
if ((event[0] == PtEventType.kBook) and PtWasLocallyNotified(self.key)):
if (event[1] == PtBookEventTypes.kNotifyImageLink):
print ('BookNotify: Linking panel id=%d, event=%d' % (event[2], event[1]))
ourBook.hide()
if (event[2] == 0):
print 'Warning: No link id, define proper link destination or use non-clickable image'
elif (event[2] >= xLinkingBookDefs.kFirstLinkPanelID):
for i in range(0, len(bkLinks)):
if (event[2] == bkLinks[i][0]):
try:
self.IlinkToAge(bkLinks[i][1], bkLinks[i][2], bkLinks[i][3], bkLinks[i][4], bkLinks[i][5])
except Exception, detail:
print ('ERROR: Unable to initialize link - %s' % detail)
break
elif (event[1] == PtBookEventTypes.kNotifyShow):
print ('BookNotify: Show book, event=%d' % event[1])
PtToggleAvatarClickability(0)
elif (event[1] == PtBookEventTypes.kNotifyHide):
print ('BookNotify: Hide book, event=%d' % event[1])
PtToggleAvatarClickability(1)
elif (event[1] == PtBookEventTypes.kNotifyNextPage):
print ('BookNotify: To next page %d, event=%d' % (ourBook.getCurrentPage(), event[1]))
elif (event[1] == PtBookEventTypes.kNotifyPreviousPage):
print ('BookNotify: To previous page %d, event=%d' % (ourBook.getCurrentPage(), event[1]))
elif (event[1] == PtBookEventTypes.kNotifyCheckUnchecked):
print ('BookNotify: Relto page toggle, event=%d' % event[1])
elif (event[1] == PtBookEventTypes.kNotifyClose):
print ('BookNotify: Close book, event=%d' % event[1])
elif (event[0] == kVariableEvent):
AvatarID = int(event[3])
Avatar = ptSceneobject(PtGetAvatarKeyFromClientID(AvatarID), self.key)
print ('Notify: Avatar %d started to link, show animation' % AvatarID)
Behavior.run(Avatar)
def OnTimer(self, id):
if (id == kLinkID):
if (type(ageLinkStruct) != type(None)):
print ('%s: OnTimer: Really linking now...' % self.me)
linkMgr = ptNetLinkingMgr()
linkMgr.linkToAge(ageLinkStruct)
def gotPublicAgeList(self, ages):
global publicAges
try:
for age in ages:
publicAges.append(age[0])
except IndexError:
pass
def IOpenBook(self, ageBook, bkPages = None):
global ourBook
global bkLinks
print ('%s: IOpenBook: Page(s) requested %s' % (self.me, bkPages))
if (type(bkPages) == type(None)):
print 'ERROR: no pages defined'
return
if (not (ageBook in self.PageDefs.AgeBooks)):
print ('ERROR: Definition %s does not exist in AgeBooks' % ageBook)
return
bkParams = self.PageDefs.AgeBooks[ageBook]
(bkCover, bkFont, startOpen, forceOwned, bookGUI, width, height,) = bkParams
PageDef = (bkCover + bkFont)
if (not startOpen):
if (not self.IsThereACover(PageDef)):
print 'Warning: Missing cover, forcing book open'
startOpen = 1
PageCount = xLinkingBookDefs.kFirstLinkPanelID
bkLinks = []
for bkPage in bkPages:
if (not (bkPage in self.PageDefs.LinkDestinations)):
print ('Warning: %s skipped, definition does not exist in LinkDestinations' % bkPage)
continue
pgParams = self.PageDefs.LinkDestinations[bkPage]
(bkAge, spawnPoint, spTitle, linkRule,) = pgParams
alink = 1
if ((type(bkAge) != type(None)) and forceOwned):
print ('Ownership check for %s book' % bkAge)
vault = ptVault()
ainfo = ptAgeInfoStruct()
ainfo.setAgeFilename(bkAge)
alink = vault.getOwnedAgeLink(ainfo)
if alink:
print ('Showing %s, link destination %s' % (bkPage, bkAge))
if (type(bkAge) != type(None)):
t = (PageCount, bkPage, bkAge, spawnPoint, spTitle, linkRule)
bkLinks.append(t)
PageDef = ((PageDef + (self.PageDefs.BookPages[bkPage] % PageCount)) + '<pb>')
else:
PageDef = ((PageDef + self.PageDefs.BookPages[bkPage]) + '<pb>')
PageCount = (PageCount + 1)
else:
print ('No owner of age %s so we are not showing %s' % (bkAge, bkPage))
if (PageCount == xLinkingBookDefs.kFirstLinkPanelID):
print 'No pages created...'
return
else:
TotalCount = (PageCount - xLinkingBookDefs.kFirstLinkPanelID)
print ('%d item(s) created, linking page(s): %d' % (TotalCount, len(bkLinks)))
PageDef = PageDef[:-4]
ourBook = ptBook(PageDef, self.key)
ourBook.setSize(width, height)
ourBook.setGUI(bookGUI)
ourBook.show(startOpen)
if len(bkLinks):
ageList = []
for i in range(0, len(bkLinks)):
if (bkLinks[i][5] == kPublicAgeLink):
ageList.append(bkLinks[i][2])
if len(ageList):
self.IGetPublicAges(ageList)
def IsThereACover(self, bookHtml):
idx = bookHtml.find('<cover')
if (idx >= 0):
return 1
return 0
def IlinkToAge(self, bookPage, ageName, spawnPoint, spTitle, linkRule = PtLinkingRules.kBasicLink):
global ageLinkStruct
print ('%s: ILinkToAge: Link request from page %s to age %s' % (self.me, bookPage, ageName))
if ((type(ageName) == type(None)) or (len(ageName) == 0)):
print 'ERROR: Cannot link to age without name'
return
if ((type(spawnPoint) == type(None)) or (len(spawnPoint) == 0)):
print 'No spawnpoint defined, checking special actions...'
self.IDoSpecialAction(bookPage)
return
als = ptAgeLinkStruct()
ainfo = ptAgeInfoStruct()
ainfo.setAgeFilename(ageName)
ainfo.setAgeInstanceName(self.IConvertAgeInstanceName(ageName))
als.setAgeInfo(ainfo)
if ((type(spTitle) == type(None)) or (len(spTitle) == 0)):
if ((linkRule == PtLinkingRules.kOriginalBook) or PtIsSinglePlayerMode()):
#################################################################################
# Linkingrule kOriginalBook writes spawnpoint and title to the agelink node, #
# so we must make absolutely sure that a proper title is given! #
# In singleplayer mode all linkingrules behave like kOriginalBook, no matter #
# which linkingrule is set in the definition. #
#################################################################################
if (spawnPoint == 'LinkInPointDefault'):
spTitle = 'Default'
#################################################################################
# We did not define a spawnpoint title, but since the spawnpoint is the default #
# it is safe to continue and write it to the agelink node with default title. #
#################################################################################
else:
print 'Warning: Empty spawnpoint title not allowed, check your link destinations!'
return
else:
print 'Empty spawnpoint title allowed, continue linking'
spTitle = ''
if (linkRule == PtLinkingRules.kChildAgeBook):
als.setParentAgeFilename(parentAge)
elif (linkRule == kPublicAgeLink):
if (not PtIsSinglePlayerMode()):
if (not len(publicAges)):
print 'No public ages found, link aborted'
return
# remove and completely replace the current age link structure
als = None
# make new list without any other ages
ageInstances = []
for i in range(0, len(publicAges)):
if (publicAges[i].getAgeFilename() == ageName):
ageInstances.append(publicAges[i])
# get age link structure from remaining age instance(s)
if len(ageInstances):
als = self.IGetPublicLink(ageInstances)
if (type(als) == type(None)):
print 'Missing age link structure, link aborted'
return
# put back the proper linking rule: never pass kPublicAgeLink to the server!
linkRule = PtLinkingRules.kBasicLink
als.setLinkingRules(linkRule)
spPoint = ptSpawnPointInfo(spTitle, spawnPoint)
als.setSpawnPoint(spPoint)
ageLinkStruct = als
print ('Linking to age %s, spawnpoint %s with title %s, using linkingrule %d' % (ageName, spawnPoint, spTitle, linkRule))
if (ageName == PtGetAgeName()):
# Linking within the same age - use the fake link
spawnPointObject = PtFindSceneobject(spawnPoint,ageName)
PtFakeLinkAvatarToObject(PtGetLocalAvatar().getKey(),spawnPointObject.getKey())
elif (type(Behavior.value) != type(None)):
# workaround... why doesn't netForce work here?
myID = PtGetClientIDFromAvatarKey(PtGetLocalAvatar().getKey())
note = ptNotify(self.key)
note.clearReceivers()
note.addReceiver(self.key)
note.setActivate(1)
note.addVarNumber('Avatar', myID)
note.send()
PtAtTimeCallback(self.key, kLinkDelay, kLinkID)
else:
PtAtTimeCallback(self.key, 0.1, kLinkID)
def IGetPublicAges(self, ageList):
global publicAges
print ('%s: IGetPublicAges: %s' % (self.me, ageList))
publicAges = []
if (not self.HasPublicAges()):
print 'ERROR: Public ages not supported in this Uru version!'
return
if vOpenSource:
################################################################################
# Technically only city, Neighborhood02 and GreatTreePub were true public ages #
# in MOUL (apart from public neighborhoods). The others had hard coded GUIDs! #
# These are: GuildPub-Cartographers, GuildPub-Greeters, GuildPub-Maintainers, #
# GuildPub-Messengers, GuildPub-Writers, philRelto and Kveer. #
# GUIDs are normally generated by the vault. This means that for Open Source #
# the hard coded stuff will have to be ditched in favor of public ages. #
# #
# Kveer and city also had child age instances. Use the kChildAgeBook rule to #
# link to a child age. #
################################################################################
for age in ageList:
PtGetPublicAgeList(age, self)
if (age not in kPublicAgesMOUL):
print ('Warning: Age %s is usually not public in MOUL Open Source' % age)
else:
for age in ageList:
PtGetPublicAgeList(age, self)
if ((age != 'city') and (age != 'Neighborhood')):
print ('Warning: Age %s is usually not public in UU' % age)
def IGetPublicLink(self, instances, highest = 0):
############################################################################
# If there are multiple public instances get the one with the lowest GUID! #
# This is important to make everyone end up in the same instance. #
# In UU for example the city had 5 public instances. The lowest was the #
# Nexus city instance. Most ages have a single public instance though. #
# This function can also get the highest GUID but we won't use that here. #
############################################################################
curGUID = instances[0].getAgeInstanceGuid()
curInstance = 0
if (not highest):
for i in range(0, len(instances)):
if (instances[i].getAgeInstanceGuid() < curGUID):
curGUID = instances[i].getAgeInstanceGuid()
curInstance = i
else:
for i in range(0, len(instances)):
if (instances[i].getAgeInstanceGuid() > curGUID):
curGUID = instances[i].getAgeInstanceGuid()
curInstance = i
try:
als = ptAgeLinkStruct()
als.getAgeInfo().copyFrom(instances[curInstance])
print ('%s: IGetPublicLink: Age link structure found' % self.me)
return als
except Exception, detail:
print ('%s: IGetPublicLink: Age link structure not found - %s' % (self.me, detail))
return None
def IConvertAgeInstanceName(self, ageName):
###############################################################################
# Optional: You can add a friendly name to this list for the age you link to. #
# This is the name that shows up in the KI. Most Cyan age names are converted #
# to friendly names in the KI but we cannot expect the KI to do that for user #
# ages. #
# Beware: Age instance names are written to the vault if the kOriginalBook #
# rule is used. That will happen whether you set a name here or not. And it #
# would happen regardless of this function. #
# By default the age instance name is the age name. However, an age instance #
# name does not have to be unique (Ae'gura). #
# If you plan to link to Cyan ages you must at least keep the age instance #
# names provided under ABM and TPOTS! #
###############################################################################
# ABM (UU)
if (ageName == 'Personal'):
return 'Relto'
if (ageName == 'Cleft'):
return "D'ni-Riltagamin"
if (ageName == 'BahroCave'):
return "D'ni-Rudenna"
if (ageName == 'BaronCityOffice'):
return "Ae'gura"
if (ageName == 'city'):
return "Ae'gura"
if (ageName == 'Garden'):
return 'Eder Kemo'
if (ageName == 'Gira'):
return 'Eder Gira'
if (ageName == 'Garrison'):
return 'Gahreesen'
# TPOTS (Alcugs)
if (ageName == 'Neighborhood02'):
return 'DRC Neighborhood'
if (ageName == 'RestorationGuild'):
return "Watcher's Guild"
if (ageName == 'AhnySphere01'):
return 'Sphere 1'
if (ageName == 'AhnySphere02'):
return 'Sphere 2'
if (ageName == 'AhnySphere03'):
return 'Sphere 3'
if (ageName == 'AhnySphere04'):
return 'Sphere 4'
# The KI always tried to convert this incorrectly from "Shaft"
if (ageName == 'Descent'):
return "D'ni-Tiwah"
# missing KI conversions (probably better to add this in the KI)
if (ageName == 'EderDelin'):
return 'Eder Delin'
if (ageName == 'EderTsogal'):
return 'Eder Tsogal'
if (ageName == 'GreatTreePub'):
return "The Watcher's Pub"
if (ageName == 'Ercana'):
return "Er'cana"
# fan ages examples
if (ageName == 'Pahts'):
return 'Ahra Pahts'
if (ageName == 'Andy_Nexus'):
return "Andy's Nexus"
if (ageName == 'Dots_Office'):
return "Dot's Office"
if (ageName == 'The_Company_Nexus'):
return 'The Company Nexus'
# Drizzle examples
if (ageName == 'KveerMOUL'):
return "K'veer"
if (ageName == 'KirelMOUL'):
return 'Kirel'
if (ageName == 'AhnonayMOUL'):
return 'Ahnonay'
if (ageName == 'MystMystV'):
return 'Myst'
if (ageName == 'MarshScene'):
return 'Great Marsh'
if (ageName == 'MountainScene'):
return 'Rowan Green'
return ageName
def HasPublicAges(self):
if vOpenSource:
print 'HasPublicAges: Open Source = true'
return true
if PtIsSinglePlayerMode():
print 'HasPublicAges: Offline = false'
return false
try:
PtForceCursorShown()
except:
print 'HasPublicAges: UU = true'
return true
print 'HasPublicAges: Alcugs = false'
return false
def IDoSpecialAction(self, bookPage):
###########################################################
# Replace 'CleftSpecial' with your bookPage that contains #
# the clickable image triggering the special action. #
###########################################################
if (bookPage == 'CleftSpecial'):
print ('Special action found for %s' % bookPage)
# Do some special action here
else:
print ('No special action for %s' % bookPage)
glue_cl = None
glue_inst = None
glue_params = None
glue_paramKeys = None
try:
x = glue_verbose
except NameError:
glue_verbose = 0
def glue_getClass():
global glue_cl
if (glue_cl == None):
try:
cl = eval(glue_name)
if issubclass(cl, ptModifier):
glue_cl = cl
elif glue_verbose:
print ('Class %s is not derived from modifier' % cl.__name__)
except NameError:
if glue_verbose:
try:
print ('Could not find class %s' % glue_name)
except NameError:
print 'Filename/classname not set!'
return glue_cl
def glue_getInst():
global glue_inst
if (type(glue_inst) == type(None)):
cl = glue_getClass()
if (cl != None):
glue_inst = cl()
return glue_inst
def glue_delInst():
global glue_inst
global glue_cl
global glue_paramKeys
global glue_params
if (type(glue_inst) != type(None)):
del glue_inst
glue_cl = None
glue_params = None
glue_paramKeys = None
def glue_getVersion():
inst = glue_getInst()
ver = inst.version
glue_delInst()
return ver
def glue_findAndAddAttribs(obj, glue_params):
if isinstance(obj, ptAttribute):
if glue_params.has_key(obj.id):
if glue_verbose:
print 'WARNING: Duplicate attribute ids!'
print ('%s has id %d which is already defined in %s' % (obj.name,
obj.id,
glue_params[obj.id].name))
else:
glue_params[obj.id] = obj
elif (type(obj) == type([])):
for o in obj:
glue_findAndAddAttribs(o, glue_params)
elif (type(obj) == type({})):
for o in obj.values():
glue_findAndAddAttribs(o, glue_params)
elif (type(obj) == type(())):
for o in obj:
glue_findAndAddAttribs(o, glue_params)
def glue_getParamDict():
global glue_paramKeys
global glue_params
if (type(glue_params) == type(None)):
glue_params = {}
gd = globals()
for obj in gd.values():
glue_findAndAddAttribs(obj, glue_params)
glue_paramKeys = glue_params.keys()
glue_paramKeys.sort()
glue_paramKeys.reverse()
return glue_params
def glue_getClassName():
cl = glue_getClass()
if (cl != None):
return cl.__name__
if glue_verbose:
print ('Class not found in %s.py' % glue_name)
return None
def glue_getBlockID():
inst = glue_getInst()
if (inst != None):
return inst.id
if glue_verbose:
print ('Instance could not be created in %s.py' % glue_name)
return None
def glue_getNumParams():
pd = glue_getParamDict()
if (pd != None):
return len(pd)
if glue_verbose:
print ('No attributes found in %s.py' % glue_name)
return 0
def glue_getParam(number):
pd = glue_getParamDict()
if (pd != None):
if (type(glue_paramKeys) == type([])):
if ((number >= 0) and (number < len(glue_paramKeys))):
return pd[glue_paramKeys[number]].getdef()
else:
print ('glue_getParam: Error! %d out of range of attribute list' % number)
else:
pl = pd.values()
if ((number >= 0) and (number < len(pl))):
return pl[number].getdef()
elif glue_verbose:
print ('glue_getParam: Error! %d out of range of attribute list' % number)
if glue_verbose:
print 'GLUE: Attribute list error'
return None
def glue_setParam(id, value):
pd = glue_getParamDict()
if (pd != None):
if pd.has_key(id):
try:
pd[id].__setvalue__(value)
except AttributeError:
if isinstance(pd[id], ptAttributeList):
try:
if (type(pd[id].value) != type([])):
pd[id].value = []
except AttributeError:
pd[id].value = []
pd[id].value.append(value)
else:
pd[id].value = value
elif glue_verbose:
print "setParam: can't find id=",
print id
else:
print 'setParma: Something terribly has gone wrong. Head for the cover.'
def glue_isNamedAttribute(id):
pd = glue_getParamDict()
if (pd != None):
try:
if isinstance(pd[id], ptAttribNamedActivator):
return 1
if isinstance(pd[id], ptAttribNamedResponder):
return 2
except KeyError:
if glue_verbose:
print ('Could not find id=%d attribute' % id)
return 0
def glue_isMultiModifier():
inst = glue_getInst()
if isinstance(inst, ptMultiModifier):
return 1
return 0
def glue_getVisInfo(number):
pd = glue_getParamDict()
if (pd != None):
if (type(glue_paramKeys) == type([])):
if ((number >= 0) and (number < len(glue_paramKeys))):
return pd[glue_paramKeys[number]].getVisInfo()
else:
print ('glue_getVisInfo: Error! %d out of range of attribute list' % number)
else:
pl = pd.values()
if ((number >= 0) and (number < len(pl))):
return pl[number].getVisInfo()
elif glue_verbose:
print ('glue_getVisInfo: Error! %d out of range of attribute list' % number)
if glue_verbose:
print 'GLUE: Attribute list error'
return None