@ -21,8 +21,9 @@ from PyHSPlasma import *
import uuid
import uuid
from . node_core import *
from . node_core import *
from . node_deprecated import PlasmaVersionedNode
class PlasmaResponderNode ( PlasmaNodeBas e , bpy . types . Node ) :
class PlasmaResponderNode ( PlasmaVersioned Node , bpy . types . Node ) :
bl_category = " LOGIC "
bl_category = " LOGIC "
bl_idname = " PlasmaResponderNode "
bl_idname = " PlasmaResponderNode "
bl_label = " Responder "
bl_label = " Responder "
@ -40,6 +41,8 @@ class PlasmaResponderNode(PlasmaNodeBase, bpy.types.Node):
no_ff_sounds = BoolProperty ( name = " Don ' t F-Fwd Sounds " ,
no_ff_sounds = BoolProperty ( name = " Don ' t F-Fwd Sounds " ,
description = " When fast-forwarding, play sound effects " ,
description = " When fast-forwarding, play sound effects " ,
default = False )
default = False )
default_state = IntProperty ( name = " Default State Index " ,
options = set ( ) )
input_sockets = OrderedDict ( [
input_sockets = OrderedDict ( [
( " condition " , {
( " condition " , {
@ -55,9 +58,22 @@ class PlasmaResponderNode(PlasmaNodeBase, bpy.types.Node):
" type " : " PlasmaPythonReferenceNodeSocket " ,
" type " : " PlasmaPythonReferenceNodeSocket " ,
" valid_link_nodes " : { " PlasmaPythonFileNode " } ,
" valid_link_nodes " : { " PlasmaPythonFileNode " } ,
} ) ,
} ) ,
( " state_refs " , {
" text " : " State " ,
" type " : " PlasmaRespStateRefSocket " ,
" valid_link_nodes " : " PlasmaResponderStateNode " ,
" valid_link_sockets " : " PlasmaRespStateRefSocket " ,
" link_limit " : 1 ,
" spawn_empty " : True ,
} ) ,
# This version of the states socket has been deprecated.
# We need to be able to track 1 socket -> 1 state to manage
# responder state IDs
( " states " , {
( " states " , {
" text " : " States " ,
" text " : " States " ,
" type " : " PlasmaRespStateSocket " ,
" type " : " PlasmaRespStateSocket " ,
" hidden " : True ,
} ) ,
} ) ,
] )
] )
@ -80,6 +96,7 @@ class PlasmaResponderNode(PlasmaNodeBase, bpy.types.Node):
responder . flags | = plResponderModifier . kDetectUnTrigger
responder . flags | = plResponderModifier . kDetectUnTrigger
if self . no_ff_sounds :
if self . no_ff_sounds :
responder . flags | = plResponderModifier . kSkipFFSound
responder . flags | = plResponderModifier . kSkipFFSound
responder . curState = self . default_state
class ResponderStateMgr :
class ResponderStateMgr :
def __init__ ( self , respNode , respMod ) :
def __init__ ( self , respNode , respMod ) :
@ -87,25 +104,58 @@ class PlasmaResponderNode(PlasmaNodeBase, bpy.types.Node):
self . parent = respNode
self . parent = respNode
self . responder = respMod
self . responder = respMod
def convert_states ( self , exporter , so ) :
# This could implicitly export more states...
i = 0
while i < len ( self . states ) :
node , state = self . states [ i ]
node . convert_state ( exporter , so , state , i , self )
i + = 1
resp = self . responder
resp . clearStates ( )
for node , state in self . states :
resp . addState ( state )
def get_state ( self , node ) :
def get_state ( self , node ) :
for idx , ( theNode , theState ) in enumerate ( self . states ) :
for idx , ( theNode , theState ) in enumerate ( self . states ) :
if theNode == node :
if theNode == node :
return ( idx , theState , True )
return ( idx , theState )
state = plResponderModifier_State ( )
state = plResponderModifier_State ( )
self . states . append ( ( node , state ) )
self . states . append ( ( node , state ) )
return ( len ( self . states ) - 1 , state , False )
return ( len ( self . states ) - 1 , state )
def save ( self ) :
def register_state ( self , node ) :
resp = self . responder
self . states . append ( ( node , plResponderModifier_State ( ) ) )
resp . clearStates ( )
for node , state in self . states :
resp . addState ( state )
# Convert the Responder states
# Convert the Responder states
stateMgr = ResponderStateMgr ( self , responder )
stateMgr = ResponderStateMgr ( self , responder )
for stateNode in self . find_outputs ( " states " , " PlasmaResponderStateNode " ) :
for stateNode in self . find_outputs ( " state_refs " , " PlasmaResponderStateNode " ) :
stateNode . convert_state ( exporter , so , stateMgr )
stateMgr . register_state ( stateNode )
stateMgr . save ( )
stateMgr . convert_states ( exporter , so )
def upgrade ( self ) :
# In version 1 responder nodes, responder states could be linked to the responder
# or to subsequent responder state nodes and be exported. The problem with this
# is that to use responder states in Python attributes, we need to be able to
# inform the user as to what the ID of the responder state will be.
# Version 2 make it slightly more mandatory that states be linked to a responder
# and will display the ID of each state linked to the responder. Any states only
# linked to other states will be converted at the end of the list.
if self . version == 1 :
states = set ( )
def _link_states ( state ) :
if state in states :
return
states . add ( state )
self . link_output ( state , " state_refs " , " resp " )
goto = state . find_output ( " gotostate " )
if goto is not None :
_link_states ( goto )
for i in self . find_outputs ( " states " ) :
_link_states ( i )
self . unlink_outputs ( " states " , " socket deprecated (upgrade complete) " )
self . version = 2
class PlasmaResponderStateNode ( PlasmaNodeBase , bpy . types . Node ) :
class PlasmaResponderStateNode ( PlasmaNodeBase , bpy . types . Node ) :
@ -113,16 +163,45 @@ class PlasmaResponderStateNode(PlasmaNodeBase, bpy.types.Node):
bl_idname = " PlasmaResponderStateNode "
bl_idname = " PlasmaResponderStateNode "
bl_label = " Responder State "
bl_label = " Responder State "
def _get_default_state ( self ) :
resp_node = self . find_input ( " resp " )
if resp_node is not None :
try :
state_idx = next ( ( idx for idx , node in enumerate ( resp_node . find_outputs ( " state_refs " ) ) if node == self ) )
except StopIteration :
return False
else :
return resp_node . default_state == state_idx
return False
def _set_default_state ( self , value ) :
if value :
resp_node = self . find_input ( " resp " )
if resp_node is not None :
try :
state_idx = next ( ( idx for idx , node in enumerate ( resp_node . find_outputs ( " state_refs " ) ) if node == self ) )
except StopIteration :
self . _whine ( " unable to set default state on responder " )
else :
resp_node . default_state = state_idx
default_state = BoolProperty ( name = " Default State " ,
default_state = BoolProperty ( name = " Default State " ,
description = " This state is the responder ' s default " ,
description = " This state is the responder ' s default " ,
default = False )
get = _get_default_state ,
set = _set_default_state ,
options = set ( ) )
input_sockets = OrderedDict ( [
input_sockets = OrderedDict ( [
( " condition " , {
( " condition " , {
" text " : " Condition " ,
" text " : " Triggers State " ,
" type " : " PlasmaRespStateSocket " ,
" type " : " PlasmaRespStateSocket " ,
" spawn_empty " : True ,
" spawn_empty " : True ,
} ) ,
} ) ,
( " resp " , {
" text " : " Responder " ,
" type " : " PlasmaRespStateRefSocket " ,
" valid_link_nodes " : " PlasmaResponderNode " ,
" valid_link_sockets " : " PlasmaRespStateRefSocket " ,
} ) ,
] )
] )
output_sockets = OrderedDict ( [
output_sockets = OrderedDict ( [
@ -141,30 +220,23 @@ class PlasmaResponderStateNode(PlasmaNodeBase, bpy.types.Node):
} ) ,
} ) ,
( " gotostate " , {
( " gotostate " , {
" link_limit " : 1 ,
" link_limit " : 1 ,
" text " : " Trigger " ,
" text " : " Triggers State " ,
" type " : " PlasmaRespStateSocket " ,
" type " : " PlasmaRespStateSocket " ,
} ) ,
} ) ,
] )
] )
def draw_buttons ( self , context , layout ) :
def draw_buttons ( self , context , layout ) :
layout . active = self . find_input ( " resp " ) is not None
layout . prop ( self , " default_state " )
layout . prop ( self , " default_state " )
def convert_state ( self , exporter , so , stateMgr ) :
def convert_state ( self , exporter , so , state , idx , stateMgr ) :
idx , state , converted = stateMgr . get_state ( self )
# No sanity checking here. Hopefully nothing crazy has happened in the UI.
if self . default_state :
stateMgr . responder . curState = idx
# Where do we go from heah?
# Where do we go from heah?
toStateNode = self . find_output ( " gotostate " , " PlasmaResponderStateNode " )
toStateNode = self . find_output ( " gotostate " , " PlasmaResponderStateNode " )
if toStateNode is None :
if toStateNode is None :
state . switchToState = idx
state . switchToState = idx
else :
else :
toIdx , toState , converted = stateMgr . get_state ( toStateNode )
toIdx , toState = stateMgr . get_state ( toStateNode )
state . switchToState = toIdx
state . switchToState = toIdx
if not converted :
toStateNode . convert_state ( exporter , so , stateMgr )
class CommandMgr :
class CommandMgr :
def __init__ ( self ) :
def __init__ ( self ) :
@ -229,15 +301,21 @@ class PlasmaResponderStateNode(PlasmaNodeBase, bpy.types.Node):
for i in msgNode . find_outputs ( " msgs " ) :
for i in msgNode . find_outputs ( " msgs " ) :
self . _generate_command ( exporter , so , responder , commandMgr , i , childWaitOn )
self . _generate_command ( exporter , so , responder , commandMgr , i , childWaitOn )
def update ( self ) :
super ( ) . update ( )
# Check to see if we're the default state
if not self . default_state :
inputs = list ( self . find_input_sockets ( " condition " , " PlasmaResponderNode " ) )
if len ( inputs ) == 1 :
self . default_state = True
class PlasmaRespStateSocket ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
class PlasmaRespStateSocket ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.388 , 0.78 , 0.388 , 1.0 )
bl_color = ( 0.388 , 0.78 , 0.388 , 1.0 )
class PlasmaRespStateRefSocket ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 1.00 , 0.980 , 0.322 , 1.0 )
def draw ( self , context , layout , node , text ) :
if isinstance ( node , PlasmaResponderNode ) :
try :
idx = next ( ( idx for idx , socket in enumerate ( node . find_output_sockets ( " state_refs " ) ) if socket == self ) )
except StopIteration :
layout . label ( text )
else :
layout . label ( " State (ID: {} ) " . format ( idx ) )
else :
layout . label ( text )