Dynamic Book Template (version 2.1)

Help bring our custom Ages to life! Share tips and tricks, as well as code samples with other developers.

Dynamic Book Template (version 2.1)

Postby D'Lanor » Fri Feb 01, 2008 1:22 pm

Here is a new version of my book template. It can be used for both linking books and journals. The first version of this template was included in my test age Prad which was released for a short period through UAM in 2005. Since then I have been adding bits to it from time to time.

Since this is a template all you have to do is define your variables and it will automagically generate the pages of the book. You can mix and match multiple linking pages and journals into the same book in any order you like. There is also support for multiple books (clickable objects). If you set up your variables correctly the template will make sure that the links point to the right age.

For each Python file you have to replace *YourAge* in the filename and in the code with the actual name of your age. I left comments in the code to explain why I did things the way I did.


*YourAge*BookGUI.py
This is the file that the PythonFileMod for your clickable object points to. The variables to adapt here are: ageBooks, bookPages and optionally the IConvertAgeInstanceName function (see comments).

Code: Select all
###########################################
#                                         #
#  Dynamic Book Template v2.1 by D'Lanor  #
#                                         #
###########################################

# For each occurance of *YourAge* you have to replace this with the actual name of your age.

from Plasma import *
from PlasmaTypes import *
from PlasmaKITypes import *
from PlasmaNetConstants import *
import xLinkingBookDefs
import *YourAge*PageDefs
actClickableObject = ptAttribActivator(1, 'Act: Clickable Object')
ObjectMsg = ptAttribString(2, 'Object String')

### DO NOT CHANGE THESE ###
ourBook = None
bkLinks = []

### CHANGE THE GLOBAL CONSTANTS BELOW TO FIT YOUR AGE ######################################
#                                                                                          #
# 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.                          #
#             Please keep the nesting structure [square brackets] intact!                  #
#                                                                                          #
# 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.                                  #
############################################################################################

ageBooks = ['Journal', 'OtherJournal']
bookPages = [['PradJournal', 'CleftDrop'], ['FontTest']]

class *YourAge*BookGUI(ptModifier,):

    def __init__(self):
        ptModifier.__init__(self)
        self.version = '2'
        print ('__init__%s v.%s' % (self.__class__.__name__, self.version))



    def OnNotify(self, state, id, events):
        global ourBook
        global bkLinks
        print ('%s: OnNotify called' % self.__class__.__name__)
        if ((id == actClickableObject.id) and state):
            print ('Someone clicked on object %s' % ObjectMsg.value)
            if (PtWasLocallyNotified(self.key)):
                print 'It was you'
                for a, b in zip(ageBooks, bookPages):
                    print ('Try book %s with page(s) %s' % (a, b))
                    if (ObjectMsg.value == a):
                        print 'Match found! start opening...'
                        self.IOpenBook(a, b)
                        break

        else:
            for event in events:
                if (event[0] == PtEventType.kBook) and (PtWasLocallyNotified(self.key)):
                    print('BookNotify  event=%d, id=%d' % (event[1], event[2]))
                    if (event[1] == PtBookEventTypes.kNotifyImageLink):
                        if (event[2] >= xLinkingBookDefs.kFirstLinkPanelID):
                            print('BookNotify: hit linking panel %s' % event[2])
                            ourBook.hide()
                            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])
                                    except Exception, detail:
                                        print('ERROR: Unable to initialize link - %s' % (detail))
                                    break
                    elif (event[1] == PtBookEventTypes.kNotifyShow):
                        print('Show Book')
                        PtSendKIMessage(kDisableKIandBB, 0)
                    elif (event[1] == PtBookEventTypes.kNotifyHide):
                        print('Hide Book')
                        PtSendKIMessage(kEnableKIandBB, 0)
                    elif (event[1] == PtBookEventTypes.kNotifyNextPage):
                        print('To Next Page %d' % (ourBook.getCurrentPage()))
                    elif (event[1] == PtBookEventTypes.kNotifyPreviousPage):
                        print('To Previous Page %d' % (ourBook.getCurrentPage()))
                    elif (event[1] == PtBookEventTypes.kNotifyCheckUnchecked):
                        print('Relto Page Toggled')
                    elif (event[1] == PtBookEventTypes.kNotifyClose):
                        print('Close Book')



    def IOpenBook(self, ageBook, bkPages = None):
        global ourBook
        global bkLinks
        print ('%s: IOpenBook: Page request for %s' % (self.__class__.__name__, bkPages))
        if (type(bkPages) == type(None)):
            print 'ERROR: no pages defined'
            return
        if (not ageBook in *YourAge*PageDefs.AgeBooks):
            print ('ERROR: Definition %s does not exist' % ageBook)
            return
        bkParams = *YourAge*PageDefs.AgeBooks[ageBook]
        (bkCover, bkFont, startOpen, forceOwned,) = 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 *YourAge*PageDefs.LinkDestinations):
                print ('Skipping %s because definition does not exist' % bkPage)
                continue
            pgParams = *YourAge*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 page for %s' % bkAge)
                if (type(bkAge) != type(None)):
                    t = (PageCount, bkAge, spawnPoint, spTitle, linkRule)
                    bkLinks.append(t)
                    PageDef = PageDef + *YourAge*PageDefs.BookPages[bkPage] % (PageCount) + '<pb>'
                else:
                    PageDef = PageDef + *YourAge*PageDefs.BookPages[bkPage] + '<pb>'
                PageCount = PageCount + 1
            else:
                print ('No %s book on your shelf so we are not showing the link' % bkAge)
        if (PageCount == xLinkingBookDefs.kFirstLinkPanelID):
            print 'No pages created...'
            return
        print ('Linking pages created: %d' % (len(bkLinks)))
        PageDef = PageDef[:-4]
        ourBook = ptBook(PageDef, self.key)
        ourBook.setSize(1.0, 1.0)
        ourBook.setGUI('BkBook')
        ourBook.show(startOpen)



    def IsThereACover(self, bookHtml):
        idx = bookHtml.find('<cover')
        if (idx >= 0):
            return 1
        return 0



    def IlinkToAge(self, ageName, spawnPoint, theTitle = None, linkRule = PtLinkingRules.kBasicLink):
        print ('%s: ILinkToAge: Link request for age %s' % (self.__class__.__name__, ageName))
        als = ptAgeLinkStruct()
        ainfo = ptAgeInfoStruct()
        ainfo.setAgeFilename(ageName)
        ainfo.setAgeInstanceName(self.IConvertAgeInstanceName(ageName))
        als.setAgeInfo(ainfo)
        if (type(theTitle) != type(None)):
            spTitle = theTitle
        else:
            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 'Empty spawnpoint title not allowed, check your linking page definitions!'
                    return
            else:
                print 'Empty spawnpoint title allowed, continue linking'
                spTitle = ''
        als.setLinkingRules(linkRule)
        spPoint = ptSpawnPointInfo(spTitle, spawnPoint)
        als.setSpawnPoint(spPoint)
        linkMgr = ptNetLinkingMgr()
        linkMgr.linkToAge(als)
        print ('Linking to age %s, spawnpoint %s with title %s, using linkingrule %d' % (ageName, spawnPoint, spTitle, linkRule))



    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. #
    # Ahra Pahts and Relto are used here only as examples.                                                                  #
    # Some 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 same as the age name.                                                         #
    # btw, if you plan to link to Cyan ages you should set the correct age instance name here. Correct? You figure it out!  #
    #########################################################################################################################
        if (ageName == 'Personal'):
            return 'Relto'
        if (ageName == 'Pahts'):
            return 'Ahra Pahts'
        return ageName



# Insert the standard GLUE section for your Uru version here. You can copy this from another Python file.



*YourAge*PageDefs.py
This is the file that contains the definitions for your books and pages. You will do most of your editing here. *YourAge*PageDefs.py is imported into *YourAge*BookGUI.py. There are 4 sections: General layout elements, AgeBooks, BookPages and LinkDestinations. Replace the examples with your own definitions.

Code: Select all
# For each occurance of *YourAge* and *YourTexture* you have to replace this with
# the actual name of your age and your textures.

from Plasma import *
from PlasmaNetConstants import *
# Due to their length journal texts are usually stored in external Python files.
# The line below imports them. Remove this line if you do not use external journals.
from *YourAge*Journals import *

# General layout elements that can be used in BookPages:
plyrName = PtGetLocalPlayer().getPlayerName() # Retrieves local player name in case you want to fake a "personal" note
PageStart = '<pb>'
ImgStart = '<img src="'
TransImgStart = '<img opacity=0.7 src="'
ImgEnd = '" align=center link=%d blend=alpha>'
ImgEndNoLink = '" align=center blend=alpha>'
AlignCenter = '<p align=center>'
AlignLeft = '<p align=left>'
AlignRight = '<p align=right>'

###############################################################################
# AgeBooks Dictionary Section:                                                #
# 1 =    same names as the clickable book objects!                            #                     
# 2 =    book cover and margin                                                #
# 3 =    main font                                                            #
# 4 =    start book open or closed. 0 closed book, 1 open book                #
# 5 =    force owned setting. 0 off, 1 on                                     #
#                                                                             #
# Notes: - The cover can have the same texture as the book object itself.     #
#        - You can set the book cover to an empty string if startOpen is 1.   #
#        - The main font can be changed later in the BookPages definition.    #
#          If you don't need a main font (because you are changing it later), #
#          you can set an empty string.                                       #
#        - force owned: If set to 1 the code checks if the original book has  #
#          been found. A player who does not own the age will not see the     #
#          linking panel. If you need this restriction set force owned to 1.  #
###############################################################################

AgeBooks = {'Journal': ('<cover src="*YourTexture*"><margin right=32 left=32>', '<font size=12 face=Arial color=000000>', 0, 0),
 'OtherJournal': ('', '', 1, 0)}

###############################################################################################
# BookPages Dictionary Section:                                                               #
# 1 =    Same names as used under link destinations!                                          #
# 2 =    The page layout: for linking books insert the name of your linking panel image here. #
#        This can be a seperate texture in your age prp file not used by a Blender object     #
#        (not sure if Blender handles that: use PRP Explorer).                                #
#        Once you get the hang of this you can mix and match layouts into your pages.         #
#                                                                                             #
# Notes: - AlignCenter is used to center text, for example to place below a linking panel.    #
###############################################################################################

BookPages = {'BevinBalcony01': (PageStart + ImgStart + 'xLinkPanelBevinBalc01*1#0.hsm' + ImgEnd + AlignCenter),
 'CleftDefault': (PageStart + ImgStart + 'xLinkPanelCleftDesert*1#0.hsm' + ImgEnd + AlignCenter),
 'CleftDrop': (PageStart + ImgStart + 'xLinkPanelTomahnaDesert*1#0.hsm' + ImgEnd + '<font size=26 face=Uru color=221166>' + AlignCenter + 'Don\'t even think about it'),
 'KadishPyramid': (PageStart + ImgStart + 'xLinkPanelKadishGlowBalc*1#0.hsm' + ImgEnd + AlignCenter),
 'FontTest': (PageStart + DefFontTest),
 'PradJournal': (PageStart + (DefPradJournal % plyrName))}

###############################################################################
# LinkDestinations Dictionary Section:                                        #
# 1 =    any name (this is used to call the definitions)                      #
# 2 =    age name                                                             #
# 3 =    spawnpoint                                                           #
# 4 =    spawnpoint title                                                     #
# 5 =    linkingrule                                                          #
#                                                                             #
# Notes: - Variables for journals are dummies and must be set to None.        #
#        - Spawnpoint title None is only allowed for LinkInPointDefault       #
#          (although it would be better to set it to 'Default' in that case). #
#        - CleftDrop in this example will deliberately fail (see above).      #
###############################################################################

LinkDestinations = {'BevinBalcony01': ('Neighborhood', 'LinkInPointBevinBalcony01', 'nb01BevinBalcony01', PtLinkingRules.kOriginalBook),
 'CleftDefault': ('Cleft', 'LinkInPointDefault', None, PtLinkingRules.kOriginalBook),
 'CleftDrop': ('Cleft', 'LinkInPointFissureDrop', None, PtLinkingRules.kOriginalBook),
 'KadishPyramid': ('Kadish', 'LinkInPointGlowRmBalcony', 'kdshGlowRmBalcony', PtLinkingRules.kOwnedBook),
 'FontTest': (None, None, None, None),
 'PradJournal': (None, None, None, None)}


*YourAge*Journals.py
Optional. A file that contains journal texts. Journal texts are written in PBML. Since journal texts are usually rather long we can store them in one or more external files which are imported into *YourAge*PageDefs.py. Replace the examples with your own texts. Note: The entire book content must be placed on a single line.

Code: Select all
# Examples of journals. DefFontTest shows the fonts available in the offline Uru version.
DefFontTest = '<font size=24 face=Courier><p align=center>Journal Test\n\n<font size=20 face=Atrus color=800000><p align=left>ATRUS\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=20 face=Uru color=008000><p align=left>URU\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=14 face=Nick color=000080><p align=left>NICK\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=14 face=Sam color=808000><p align=left>SAM\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=14 face=Tricia color=008080><p align=left>TRICIA\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=14 face=Michelle color=800080><p align=left>MICHELLE\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=12 face=DniFontDniHand color=000000><p align=left>DNI HAND\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9\n\n<font size=18 face=Yeesha color=404040><p align=left>YEESHA\nThe quick brown fox jumped over the lazy dog.\n0 1 2 3 4 5 6 7 8 9'
DefPradJournal = '<font size=24 face=Uru color=221166><p align=left>Shorah %s,\n\nAn example which shows how to address players by their own names in a journal.'


dynamic_books_source.zip
Last edited by D'Lanor on Sun Feb 17, 2008 11:05 am, edited 2 times in total.
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Re: Dynamic Book Template (version 2)

Postby Chacal » Fri Feb 01, 2008 5:15 pm

*bows* I think you have created a classic.
Chacal


"The weak can never forgive. Forgiveness is an attribute of the strong."
-- Mahatma Gandhi
User avatar
Chacal
 
Posts: 2515
Joined: Tue Nov 06, 2007 2:45 pm
Location: Quebec, Canada

Re: Dynamic Book Template (version 2)

Postby boblishman » Sat Feb 02, 2008 11:37 am

Whooo HOOO... I have a working Journal! THANK'S D'LANOR

Note: I had to delete % plyrName from the BookPages section of the *YourAge*PageDefs.py code (I'm not a programmer but I'm guessing it should read " ... + plyrName" (instead of % ) ... I dont want to use that variable at the moment, but if anyone else does, they may have problems with the present coding..

Now ... let's see if I can get a linking book to work ... :D


EDIT: DOES A VERY HAPPY DANCE ... :D ... yes! ... I have a linking book that actually works!!
This script is SO clever ... letting you have multiple books and journals with different covers etc., ... very impressive!

Now, I have two questions I wonder if anyone can help me with:

1) How do I create (and then find the filename - presumably with that *1#0.hms at the end -) for a personalised linking panel image ?
(is it like journal sketches where you assign it to a mesh/material and hide it in the age, and if so, is it just the filename with that strange extention?)

2) I have been trying to add a sketch (alpha transparent image) to a journal with no luck whatsoever. I've tried using an uncompressed file, using the filename with the *1#0.hsm extention, all kinds of things but with no luck whatsoever... :cry:
It must be possible because I was able to make them using an early version of the plugin ... however, that system doesn't seem to work anymore .... any ideas?
when it comes to Age creation ... "DOH" seems to be my middle name...
User avatar
boblishman
 
Posts: 882
Joined: Fri Oct 05, 2007 4:47 pm
Location: Spain

Re: Dynamic Book Template (version 2)

Postby D'Lanor » Sat Feb 02, 2008 3:23 pm

Yes, you should delete % plyrName if you are not using it. That is the correct syntax since it is replacing a string in the text indicated by %s.

Code: Select all
input: 'Shorah %s' % plyrName
output: Shorah D'Lanor


For personalized linking images the journal sketch method should work. There is no need to use that extension.

Perhaps PyPRP now assigns new names to texture files with alpha transparency? You could check your texture names with PRP Explorer or Plasmashop.
"It is in self-limitation that a master first shows himself." - Goethe
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Re: Dynamic Book Template (version 2)

Postby Trylon » Sat Feb 02, 2008 3:32 pm

Did you try unchecking the "INTERPOL" button in the texture panel?

That's what disables compression of textures nowadays....
One day I ran through the cleft for the fiftieth time, and found that uru held no peace for me anymore.
User avatar
Trylon
 
Posts: 1446
Joined: Fri Sep 28, 2007 11:08 pm
Location: Gone from Uru

Re: Dynamic Book Template (version 2)

Postby boblishman » Sat Feb 02, 2008 3:38 pm

Trylon wrote:Did you try unchecking the "INTERPOL" button in the texture panel?

That's what disables compression of textures nowadays....


Yes... I tried that ... but no joy ... it seems to me (and this is only a guess) that when I was able to make it work before was when the textures were NOT resized on export (old plugin, Export as a Full Age - no compression) ... and I cant find a way to stop the plugin resizing the image when it exports. Is there a way?
when it comes to Age creation ... "DOH" seems to be my middle name...
User avatar
boblishman
 
Posts: 882
Joined: Fri Oct 05, 2007 4:47 pm
Location: Spain

Re: Dynamic Book Template (version 2)

Postby Grogyan » Sat Feb 02, 2008 4:10 pm

Perhaps its something to fix for the next version of the plugin
Better to have loved and lost than never to have loved at all
User avatar
Grogyan
 
Posts: 1203
Joined: Thu Oct 11, 2007 1:27 am

Re: Dynamic Book Template (version 2)

Postby boblishman » Sun Feb 03, 2008 2:21 am

D'Lanor wrote: For personalized linking images the journal sketch method should work. There is no need to use that extension.


Yes indeed, personalised panels do work in the same way as journals ...

Make sure your panel texture is 512 x 256 pixels with a transparent border as follows:

linking panel template.png
linking panel template.png (71.96 KiB) Viewed 6397 times


(You will need to stretch your screenshot from your age to fit into the non transparent part of the image and use the Texture tab setting shown in the next post (journal sketches) )

Here's a working linking book that goes to CampBravo ... :)

Show Spoiler


Andy, you just have to use this new template, it's fantastic!
Last edited by boblishman on Sun Feb 03, 2008 4:26 am, edited 2 times in total.
when it comes to Age creation ... "DOH" seems to be my middle name...
User avatar
boblishman
 
Posts: 882
Joined: Fri Oct 05, 2007 4:47 pm
Location: Spain

Re: Dynamic Book Template (version 2)

Postby boblishman » Sun Feb 03, 2008 3:43 am

EDIT: 4th FEB 00.20am: The new version of the plugin (v.1.2.1) now fixes all the issues described in the following posts: see the TUTORIAL for the latest method of creating sketches


------------------------------------------------------------------------------------------------------------------------------------


WHHHOOOO HOOOOO ... :) :) :)

EDIT: THIS tutorial explains the proceedure in full when using the GowPyprp plugin v1.2.1 (released Feb 4th 2008) or later

OK, I figured out how to make real sketches (images with alpha transparancy) to go into your journals with the new plugin...

This is what I found works so far: (obviously there may be other ways too... but using this method definately works! :) )

1) Images: pixel size must be a 512 (wide) x 256 (high) and a .png with full transparancy
EDIT: Using the GoWPyprp plugin version 1.2.1 or later means you can use ANY size image

2) Set the Texure Buttons (F6) as follows:

Image

2) Method:
(i) UV Map the image onto a flat plane and hide it inside another mesh (to get the texture file into the .prp file)
(ii) Journal code: <img src="yourfilename" align=center resize=no blend=alpha> , where yourfilename is the texture filename without the extention.

Here's the result:
Show Spoiler


have fun!
Last edited by boblishman on Sun Feb 03, 2008 6:15 pm, edited 4 times in total.
when it comes to Age creation ... "DOH" seems to be my middle name...
User avatar
boblishman
 
Posts: 882
Joined: Fri Oct 05, 2007 4:47 pm
Location: Spain

Re: Dynamic Book Template (version 2)

Postby andylegate » Sun Feb 03, 2008 8:13 am

oooooooo.........

Look! Someone used a pic of my Age!

I'm flattered! Thanks!
"I'm still trying to find the plKey for Crud!"
Image
Blender Age Creation Tutorials
3DS Max Age Creation Tutorials
User avatar
andylegate
 
Posts: 2348
Joined: Mon Oct 01, 2007 7:47 am

Next

Return to Scripting

Who is online

Users browsing this forum: No registered users and 0 guests