Basically, it's much easier to debug, modify, and make complex Python scripts, so when possible, it may be better to do as much in Python as possible.
To that end, here are some (no doubt imperfect) things Wodan and I used in the present working version of Oolbahnneea. (It originated as a modified Boblishman script, so some of the names reflect that.)
The Alcscipt for two (for brevity) of the twelve buttons and the door that is to be opened.
- Code: Select all
SWDoorButDec:
animations:
- name: SWdoorbutdec
autostart: 0
loop: 0
Button1Oneshot:
logic:
actions:
- type: oneshot
name: Button1Oneshot
oneshot:
animation: DoorButtonTouch
Button1:
animations:
- name: button1click
autostart: 0
loop: 0
logic:
modifiers:
- tag: AutoClick
cursor: poised
flags:
- localelement
activators:
- type: objectinvolume
remote: Button1swing
triggers:
- any
conditions:
- type: activator
activators:
- type: picking
- type: objectinbox
satisfied: true
actions:
- type: pythonfile
ref: $BoolToggle
- type: responder
ref: $But1resp
actions:
- type: pythonfile
tag: BoolToggle
pythonfile:
file: oolbPuzz2Click
parameters:
- type: activator
ref: logicmod:$AutoClick
- type: string
value: puzzle2button1
- type: pythonfile
tag: BoolRespond
pythonfile:
file: xAgeSDLBoolRespond
parameters:
- type: string
value: VerandaTuerLinks
- type: responder
ref: :Door_2Open
- type: responder
ref: :Door_2Close
- type: bool
value: false
- type: bool
value: true
- type: responder
tag: But1resp
responder:
states:
- cmds:
- type: oneshotmsg
params:
receivers:
- oneshotmod:Button1Oneshot
#callbacks:
# - marker: "DoorButtonTouch"
# receiver: respondermod:Door_2Open
# user: 0
waiton: -1
nextstate: 1
waittocmd: 0
curstate: 0
flags:
- detecttrigger
Button2Oneshot:
logic:
actions:
- type: oneshot
name: Button2Oneshot
oneshot:
animation: DoorButtonTouch
Button2:
animations:
- name: button2click
autostart: 0
loop: 0
logic:
modifiers:
- tag: AutoClick
cursor: poised
flags:
- localelement
activators:
- type: objectinvolume
remote: Button2swing
triggers:
- any
conditions:
- type: activator
activators:
- type: picking
- type: objectinbox
satisfied: true
actions:
- type: pythonfile
ref: $BoolToggle
- type: responder
ref: $But2resp
actions:
- type: pythonfile
tag: BoolToggle
pythonfile:
file: oolbPuzz2Click
parameters:
- type: activator
ref: logicmod:$AutoClick
- type: string
value: puzzle2button2
- type: responder
tag: But2resp
responder:
states:
- cmds:
- type: oneshotmsg
params:
receivers:
- oneshotmod:Button2Oneshot
#callbacks:
# - marker: "DoorButtonTouch"
# receiver: respondermod:Door_2Open
# user: 0
waiton: -1
nextstate: 1
waittocmd: 0
curstate: 0
flags:
- detecttrigger
Door_2:
animations:
- name: Door_2Open1
autostart: 0
loop: 0
logic:
actions:
- type: responder
name: Door_2Open
responder:
states:
- cmds:
#- type: oneshotmsg
# params:
# receivers:
# - oneshotmod:Button1Oneshot
# callbacks:
# - marker: "DoorButtonTouch"
# receiver: respondermod:Door_2Open
# user: 0
# waiton: -1
- type: animcmdmsg
params:
receivers:
- 006D:Door_2
animname: Door_2Open1
cmds:
- setforewards
- continue
waiton: -1
#- type: animcmdmsg
# params:
# receivers:
# - 006D:Button1
# animname: button1click
# cmds:
# - setforewards
# - continue
# waiton: 0
- type: animcmdmsg
params:
receivers:
- 006D:SWDoorButDec
animname: SWdoorbutdec
cmds:
- setforewards
- continue
waiton: -1
nextstate: 1
waittocmd: 0
curstate: 0
flags:
- detecttrigger
- type: responder
name: Door_2Close
responder:
states:
- cmds:
#- type: oneshotmsg
# params:
# receivers:
# - oneshotmod:Button1Oneshot
# callbacks:
# - marker: "DoorButtonTouch"
# receiver: respondermod:Door_2Close
# user: 0
# waiton: -1
- type: animcmdmsg
params:
receivers:
- 006D:Door_2
animname: Door_2Open1
cmds:
- setbackwards
- continue
waiton: -1
#- type: animcmdmsg
# params:
# receivers:
# - 006D:Button1
# animname: button1click
# cmds:
# - setforewards
# - continue
# waiton: 0
- type: animcmdmsg
params:
receivers:
- 006D:SWDoorButDec
animname: SWdoorbutdec
cmds:
- setforewards
- continue
waiton: -1
nextstate: 0
waittocmd: 0
curstate: 0
flags:
- detecttrigger
The Python file that does all the logic:
- Code: Select all
# emacs-mode: -*- python-*-
from Plasma import *
from PlasmaTypes import *
import string
actTrigger = ptAttribActivator(1, 'Activator')
buttonName = ptAttribString(2,'Button Name')
extraArgument = ptAttribString(3,'Extra Argument')
#actTrigger = ptAttribActivator(1, 'Activator')
#stringVarName = ptAttribString(2, 'Age SDL Var Name')
#stringInfo = ptAttribString(5, 'Extra info to pass along')
#boolCurrentValue = false
AgeStartedIn = None
class oolbPuzz2Click(ptResponder,):
__module__ = __name__
def __init__(self):
ptResponder.__init__(self)
self.id = 15073
self.version = 1
def OnFirstUpdate(self):
print 'oolb.onfirstupdate'
global AgeStartedIn
AgeStartedIn = PtGetAgeName()
if (not ((type(buttonName.value) == type('')) and (buttonName.value != ''))):
PtDebugPrint('ERROR: oolbPuzz2Click.OnFirstUpdate():\tERROR: missing SDL var name')
def OnServerInitComplete(self):
print 'oolb.onserverinitcomplete'
global boolCurrentValue
if (AgeStartedIn == PtGetAgeName()):
ageSDL = PtGetAgeSDL()
if ((type(buttonName.value) == type('')) and (buttonName.value != '')):
sdlname = 'VerandaTuerLinks'
ageSDL.setNotify(self.key, sdlname, 0.0)
ageSDL.setFlags(sdlname, 1, 1)
ageSDL.sendToClients(sdlname)
#try:
# boolCurrentValue = ageSDL[buttonName.value][0]
#except:
# PtDebugPrint('ERROR: xAgeSDLBoolToggle.OnServerInitComplete():\tERROR reading age SDL')
#PtDebugPrint(('DEBUG: xAgeSDLBoolToggle.OnServerInitComplete():\t%s = %d' % (stringVarName.value,
# boolCurrentValue)))
else:
PtDebugPrint('ERROR: oolbPuzz2Click.OnServerInitComplete():\tERROR: missing SDL var name')
def OnNotify(self, state, id, events):
#global boolCurrentValue
print 'oolbPuzz2Click.OnNotify'
#print 'state: '+`state`
#print 'id: '+`id`
#print 'actTrigger.id: '+`actTrigger.id`
#if not state:
# print 'not state'
# return
if ((not state) or (id != actTrigger.id)):
#if ((not state)):
print ' ignoring because of state or actTrigger'
return
#print 'skipping PtWasLocallyNotified for some reason.'
if (not PtWasLocallyNotified(self.key)):
return
#print '2'
if ((type(actTrigger.value) == type([])) and (len(actTrigger.value) > 0)):
PtDebugPrint((' DEBUG: oolbPuzz2Click.OnNotify():\t local player requesting %s change via %s' % (buttonName.value,
actTrigger.value[0].getName())))
if ((type(buttonName.value) != type('')) or (buttonName.value == '')):
PtDebugPrint(' ERROR: oolbPuzz2Click.OnNotify():\tERROR: missing SDL var name')
return
#print '3'
if (AgeStartedIn == PtGetAgeName()):
#solution: 12, 10, 8, 7.
ageSDL = PtGetAgeSDL()
button = buttonName.value
print ' button clicked!: '+`button`
if button.startsWith('puzzle2'):
count = ageSDL['Puzzle2CorrectCount'][0]
print ' count: '+`count`
#if ((button=='puzzle2button12') and (count==0)):
if ((button=='puzzle2button12')):
print ' first button...'
ageSDL['Puzzle2CorrectCount'] = (1,)
ageSDL['VerandaTuerLinks'] = (0,)
elif ((button=='puzzle2button10') and (count==1)):
print ' second button...'
ageSDL['Puzzle2CorrectCount'] = (2,)
ageSDL['VerandaTuerLinks'] = (0,)
elif ((button=='puzzle2button8') and (count==2)):
print ' third button...'
ageSDL['Puzzle2CorrectCount'] = (3,)
ageSDL['VerandaTuerLinks'] = (0,)
elif ((button=='puzzle2button7') and (count==3)):
print ' forth button...'
PtAtTimeCallback(self.key, 3.0, 1)
#ageSDL['Puzzle2CorrectCount'] = (4,)
ageSDL['Puzzle2CorrectCount'] = (0,)
#ageSDL['VerandaTuerLinks'] = (1,)
else:
print ' wrong button...'
ageSDL['Puzzle2CorrectCount'] = (0,)
ageSDL['VerandaTuerLinks'] = (0,)
elif button.startsWith('puzzle3'):
print 'Puzzle3 button clicked!'
print ' done!'
def OnTimer(self, id):
if(id==1):
print 'Opening door...'
ageSDL = PtGetAgeSDL()
ageSDL['VerandaTuerLinks'] = (1,)
def OnSDLNotify(self, VARname, SDLname, playerID, tag):
#global boolCurrentValue
print 'oolbPuzz2Click.OnSDLNotify'
if (AgeStartedIn == PtGetAgeName()):
ageSDL = PtGetAgeSDL()
#if (VARname == stringVarName.value):
# PtDebugPrint(('DEBUG: xAgeSDLBoolToggle.OnSDLNotify():\t VARname:%s, SDLname:%s, tag:%s, value:%d' % (VARname,
# SDLname,
# tag,
# ageSDL[stringVarName.value][0])))
# boolCurrentValue = ageSDL[stringVarName.value][0]
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
# local variables:
# tab-width: 4
Now then, Button1Oneshot is the avatar's hand animation, and Button1 is the clickable itself. Note that here we simultaneously call the BoolToogle and But1resp actions when it is clicked. The But1resp action is the avatar animation, and the BoolToggle calls our Python file. (BoolToggle is only called that for historic reasons.) We also have the (uncalled) BoolRespond action in the first button (it doesn't actually matter what object we stick it on, since it is only called at initialisation.) This ties the door's animation to sdl in the usual way, which may be useful because we can then control the door animation in Python via SDL and have it network-synched.
As for the Python code: firstly, ignore the OnServerInitComplete and OnSDLNotify functions. OnNotify is what is called when a button is clicked. The starting stuff checks the state (to make sure the button was going down, not up). In this case, the logic really begins with the "if button.startsWith('puzzle2'):" line. And from here, it is easy to add/modify logic since it is in pure Python!
I hope this may help someone is some way, and feel free to ask questions or recommend simplifications!