This Python code is based on my old adminKI contribution The Sky Blender. These are instructions to properly implement it into an age.
The Python method PtFogSetDefColor() has a low performance footprint (as opposed to animating objects with Python).
Those who are familiar with the old adminKI code may worry about the strain this would put on the server. However, that only happened because we had to push the changes to the other clients. With this new multiplayer compatibility all clients handle the changes internally and they only need to sync themselves occasionally.
Multiplayer compatibility: Color states are periodically written to SDL variables by only one player who is the game owner. The game owner is usually the first player who arrives in the age.
Players who link in will retrieve the SDL variables and their loop will start from the current values. Age players are synced to the game owner every 30 seconds. If the game owner links out (or crashes!) another age player becomes the game owner.
The game owner mechanism: All you have to do is check the isLocallyOwned() property of an object in your age. If this check returns True then you are the game owner. This test object does not have to be a special object, just pick one at random. Uru usually puts the test object in a PythonFileMod but it works just as well with PtFindSceneobject(), which is much easier to implement. Thanks to a'moaca' for pointing out this mechanism.
SDL Variables: Add these variables to SDL file for your age. Replace the words between ### to match your age.
- Code: Select all
#
# State Description Language for ###YourAgeName###
#
STATEDESC ###YourAgeName###
{
VERSION 1
VAR FLOAT CurrColR[1] DEFAULT=0.5
VAR FLOAT CurrColG[1] DEFAULT=0.5
VAR FLOAT CurrColB[1] DEFAULT=0.5
VAR BOOL ColStateR[1] DEFAULT=1
VAR BOOL ColStateG[1] DEFAULT=1
VAR BOOL ColStateB[1] DEFAULT=1
}
Python Code: Add the Python code to your main Python agehook file (or create a custom PythonFileMod for it if you want). Adjust the ColRate, CurrCol and kLoopTime settings to get different effects.
Make sure to turn on fog in the *.fni file for your age. If you don't have fog you will not see anything! Or you can uncomment the line PtFogSetDefLinear(-50, 600, 1) to add a Kadish Tolesa type fog to the age.
Optional: Match the ClearColor. This option is off by default but the effect generally looks better when it is on. Calling the function with self.ColorBlender(ColRate, 1) turns it on.
Replace the words between ### to match your age.
- Code: Select all
##################################
# #
# Dynamic Fog Color by D'Lanor #
# #
##################################
from Plasma import *
from PlasmaTypes import *
ColState = [1, 1, 1]
CurrCol = [0.5, 0.5, 0.5]
ColRate = [0.3, 0.6, 0.9]
LoopState = 0
kLoopTime = 0.5
kLoopID = 1
DoUpdate = 0
kUpdateTime = 30
kUpdateID = 2
testObj = None
class ###YourAgeName###(ptResponder,):
def __init__(self):
ptResponder.__init__(self)
self.version = '###Your Version Number###'
print ('__init__%s v.%s' % (self.__class__.__name__,
self.version))
def OnFirstUpdate(self):
print ('%s: OnFirstUpdate called' % self.__class__.__name__)
#PtFogSetDefLinear(-50, 600, 1)
def OnServerInitComplete(self):
global LoopState
global DoUpdate
global testObj
print ('%s: OnServerInitComplete called' % self.__class__.__name__)
try:
testObj = PtFindSceneobject('###YourObjectName###', PtGetAgeName())
except:
print 'ERROR: Missing test object'
return
ageSDL = PtGetAgeSDL()
if (ageSDL == None):
print 'ERROR: Missing SDL'
return
ageSDL.sendToClients('CurrColR')
ageSDL.sendToClients('CurrColG')
ageSDL.sendToClients('CurrColB')
ageSDL.sendToClients('ColStateR')
ageSDL.sendToClients('ColStateG')
ageSDL.sendToClients('ColStateB')
ageSDL.setFlags('CurrColR', 1, 1)
ageSDL.setFlags('CurrColG', 1, 1)
ageSDL.setFlags('CurrColB', 1, 1)
ageSDL.setFlags('ColStateR', 1, 1)
ageSDL.setFlags('ColStateG', 1, 1)
ageSDL.setFlags('ColStateB', 1, 1)
ageSDL.setNotify(self.key, 'CurrColR', 0.0)
ageSDL.setNotify(self.key, 'CurrColG', 0.0)
ageSDL.setNotify(self.key, 'CurrColB', 0.0)
ageSDL.setNotify(self.key, 'ColStateR', 0.0)
ageSDL.setNotify(self.key, 'ColStateG', 0.0)
ageSDL.setNotify(self.key, 'ColStateB', 0.0)
CurrCol[0] = ageSDL['CurrColR'][0]
CurrCol[1] = ageSDL['CurrColG'][0]
CurrCol[2] = ageSDL['CurrColB'][0]
ColState[0] = ageSDL['ColStateR'][0]
ColState[1] = ageSDL['ColStateG'][0]
ColState[2] = ageSDL['ColStateB'][0]
LoopState = 1
DoUpdate = 1
PtAtTimeCallback(self.key, kLoopTime, kLoopID)
PtAtTimeCallback(self.key, kUpdateTime, kUpdateID)
def BeginAgeUnLoad(self, avatar):
global LoopState
global DoUpdate
print ('%s: BeginAgeUnLoad called' % self.__class__.__name__)
try:
LocAvi = PtGetLocalAvatar()
except:
print 'ERROR: Local avatar has left the building'
return
if (LocAvi == avatar):
LoopState = 0
DoUpdate = 0
def OnSDLNotify(self, VARname, SDLname, playerID, tag):
print ('%s: OnSDLNotify: Varname = %s, playerID = %d' % (self.__class__.__name__,
VARname, playerID))
if (playerID != PtGetLocalPlayer().getPlayerID()):
print 'Syncing color state to SDL'
ageSDL = PtGetAgeSDL()
if (VARname == 'CurrColR'):
CurrCol[0] = ageSDL['CurrColR'][0]
elif (VARname == 'CurrColG'):
CurrCol[1] = ageSDL['CurrColG'][0]
elif (VARname == 'CurrColB'):
CurrCol[2] = ageSDL['CurrColB'][0]
elif (VARname == 'ColStateR'):
ColState[0] = ageSDL['ColStateR'][0]
elif (VARname == 'ColStateG'):
ColState[1] = ageSDL['ColStateG'][0]
elif (VARname == 'ColStateB'):
ColState[2] = ageSDL['ColStateB'][0]
def OnTimer(self, id):
if (id == kLoopID):
if (not LoopState):
print 'Stop color blender'
return
self.ColorBlender(ColRate, 1)
if (id == kUpdateID):
if (not DoUpdate):
print 'Stop updating color state'
return
ageSDL = PtGetAgeSDL()
if testObj.isLocallyOwned():
print 'I am game owner. Updating color state'
ageSDL['CurrColR'] = (CurrCol[0],)
ageSDL['CurrColG'] = (CurrCol[1],)
ageSDL['CurrColB'] = (CurrCol[2],)
ageSDL['ColStateR'] = (ColState[0],)
ageSDL['ColStateG'] = (ColState[1],)
ageSDL['ColStateB'] = (ColState[2],)
PtAtTimeCallback(self.key, kUpdateTime, kUpdateID)
def ColorBlender(self, ColRate, MatchClear = 0):
global LoopState
try:
ColRateR = abs(ColRate[0])
ColRateG = abs(ColRate[1])
ColRateB = abs(ColRate[2])
except:
PtDebugPrint('Invalid color value', level=kDebugDumpLevel)
LoopState = 0
return
if ((ColRateR >= 100) or ((ColRateG >= 100) or (ColRateB >= 100))):
PtDebugPrint('Value must be lower than 100', level=kDebugDumpLevel)
LoopState = 0
return
if (ColState[0] == 0):
ColRateR = (ColRateR * -1)
if (ColState[1] == 0):
ColRateG = (ColRateG * -1)
if (ColState[2] == 0):
ColRateB = (ColRateB * -1)
CurrCol[0] = (CurrCol[0] + ((ColRateR / 100) * CurrCol[0]))
CurrCol[1] = (CurrCol[1] + ((ColRateG / 100) * CurrCol[1]))
CurrCol[2] = (CurrCol[2] + ((ColRateB / 100) * CurrCol[2]))
if (CurrCol[0] >= 1):
CurrCol[0] = 1.0
ColState[0] = 0
elif (CurrCol[0] < 0.01):
ColState[0] = 1
if (CurrCol[1] >= 1):
CurrCol[1] = 1.0
ColState[1] = 0
elif (CurrCol[1] < 0.01):
ColState[1] = 1
if (CurrCol[2] >= 1):
CurrCol[2] = 1.0
ColState[2] = 0
elif (CurrCol[2] < 0.01):
ColState[2] = 1
try:
ColNew = ptColor(CurrCol[0], CurrCol[1], CurrCol[2], 1.0)
PtFogSetDefColor(ColNew)
if MatchClear:
PtSetClearColor(CurrCol[0], CurrCol[1], CurrCol[2])
PtAtTimeCallback(self.key, kLoopTime, kLoopID)
except:
PtDebugPrint('Something terribly has gone wrong, stop the loop!', level=kDebugDumpLevel)
LoopState = 0
Example of the code in action: http://www.youtube.com/watch?v=vFopU-h9tUg
Feel free to use and adapt for your age creations.
D'Lanor