@ -20,12 +20,13 @@ from PyHSPlasma import *
from . node_core import PlasmaNodeBase , PlasmaNodeSocketBase
from . node_core import PlasmaNodeBase , PlasmaNodeSocketBase
from . . properties . modifiers . avatar import sitting_approach_flags
from . . properties . modifiers . avatar import sitting_approach_flags
from . . exporter . explosions import ExportError
class PlasmaSittingBehaviorNode ( PlasmaNodeBase , bpy . types . Node ) :
class PlasmaSittingBehaviorNode ( PlasmaNodeBase , bpy . types . Node ) :
bl_category = " AVATAR "
bl_category = " AVATAR "
bl_idname = " PlasmaSittingBehaviorNode "
bl_idname = " PlasmaSittingBehaviorNode "
bl_label = " Sitting Behavior "
bl_label = " Sitting Behavior "
bl_default_width = 10 0
bl_width_ default = 12 0
approach = EnumProperty ( name = " Approach " ,
approach = EnumProperty ( name = " Approach " ,
description = " Directions an avatar can approach the seat from " ,
description = " Directions an avatar can approach the seat from " ,
@ -71,3 +72,382 @@ class PlasmaSittingBehaviorNode(PlasmaNodeBase, bpy.types.Node):
@property
@property
def requires_actor ( self ) :
def requires_actor ( self ) :
return True
return True
class PlasmaAnimStageAdvanceSocketIn ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.412 , 0.2 , 0.055 , 1.0 )
auto_advance = BoolProperty ( name = " Advance to Next Stage " ,
description = " Automatically advance to the next stage when the animation completes instead of halting " ,
default = True )
def draw_content ( self , context , layout , node , text ) :
if not self . is_linked :
layout . prop ( self , " auto_advance " )
else :
if self . links [ 0 ] . from_node . stage_id is not None :
layout . label ( " {} {} " . format ( text , self . links [ 0 ] . from_node . stage_id ) )
else :
layout . label ( text )
class PlasmaAnimStageRegressSocketIn ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.412 , 0.2 , 0.055 , 1.0 )
auto_regress = BoolProperty ( name = " Regress to Previous Stage " ,
description = " Automatically regress to the previous stage when the animation completes instead of halting " ,
default = True )
def draw_content ( self , context , layout , node , text ) :
if not self . is_linked :
layout . prop ( self , " auto_regress " )
else :
if self . links [ 0 ] . from_node . stage_id is not None :
layout . label ( " {} {} " . format ( text , self . links [ 0 ] . from_node . stage_id ) )
else :
layout . label ( text )
class PlasmaAnimStageOrderSocketOut ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.412 , 0.2 , 0.055 , 1.0 )
anim_play_flags = [ ( " kPlayNone " , " None " , " " ) ,
( " kPlayKey " , " Keyboard " , " " ) ,
( " kPlayAuto " , " Automatic " , " " ) ]
anim_stage_flags = [ ( " kAdvanceNone " , " None " , " " ) ,
( " kAdvanceOnMove " , " Movement " , " " ) ,
( " kAdvanceAuto " , " Automatic " , " " ) ,
( " kAdvanceOnAnyKey " , " Any Keypress " , " " ) ]
class PlasmaAnimStageSettingsSocket ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.412 , 0.0 , 0.055 , 1.0 )
class PlasmaAnimStageSettingsNode ( PlasmaNodeBase , bpy . types . Node ) :
bl_category = " AVATAR "
bl_idname = " PlasmaAnimStageSettingsNode "
bl_label = " Animation Stage Settings "
bl_width_default = 325
forward = EnumProperty ( name = " Forward " ,
description = " " ,
items = anim_play_flags ,
default = " kPlayNone " )
backward = EnumProperty ( name = " Backward " ,
description = " " ,
items = anim_play_flags ,
default = " kPlayNone " )
stage_advance = EnumProperty ( name = " Stage Advance " ,
description = " " ,
items = anim_stage_flags ,
default = " kAdvanceNone " )
stage_regress = EnumProperty ( name = " Stage Regress " ,
description = " " ,
items = anim_stage_flags ,
default = " kAdvanceNone " )
notify_on = EnumProperty ( name = " Notify " ,
description = " Which events should send notifications " ,
items = [
( " kNotifyEnter " , " Enter " ,
" Send notification when animation first begins to play " ) ,
( " kNotifyLoop " , " Loop " ,
" Send notification when animation starts a loop " ) ,
( " kNotifyAdvance " , " Advance " ,
" Send notification when animation is advanced " ) ,
( " kNotifyRegress " , " Regress " ,
" Send notification when animation is regressed " )
] ,
default = { " kNotifyEnter " } ,
options = { " ENUM_FLAG " } )
input_sockets = OrderedDict ( [
( " advance_to " , {
" text " : " Advance to Stage " ,
" type " : " PlasmaAnimStageAdvanceSocketIn " ,
" valid_link_nodes " : " PlasmaAnimStageNode " ,
" valid_link_sockets " : " PlasmaAnimStageOrderSocketOut " ,
" link_limit " : 1 ,
} ) ,
( " regress_to " , {
" text " : " Regress to Stage " ,
" type " : " PlasmaAnimStageRegressSocketIn " ,
" valid_link_nodes " : " PlasmaAnimStageNode " ,
" valid_link_sockets " : " PlasmaAnimStageOrderSocketOut " ,
" link_limit " : 1 ,
} ) ,
] )
output_sockets = OrderedDict ( [
( " stage " , {
" text " : " Stage " ,
" type " : " PlasmaAnimStageSettingsSocket " ,
" valid_link_nodes " : " PlasmaAnimStageNode " ,
" valid_link_sockets " : " PlasmaAnimStageSettingsSocket " ,
} ) ,
] )
def draw_buttons ( self , context , layout ) :
layout . prop ( self , " forward " )
layout . prop ( self , " backward " )
layout . prop ( self , " stage_advance " )
layout . prop ( self , " stage_regress " )
layout . separator ( )
layout . label ( " Notify On: " )
row = layout . row ( )
row . prop ( self , " notify_on " )
layout . separator ( )
class PlasmaAnimStageNode ( PlasmaNodeBase , bpy . types . Node ) :
bl_category = " AVATAR "
bl_idname = " PlasmaAnimStageNode "
bl_label = " Animation Stage "
bl_width_default = 325
pl_attrib = ( " ptAttribAnimation " )
anim_name = StringProperty ( name = " Animation Name " ,
description = " Name of animation to play " )
loop_option = EnumProperty ( name = " Looping " ,
description = " Loop options for animation playback " ,
items = [ ( " kDontLoop " , " Don ' t Loop " , " Don ' t loop the animation " ) ,
( " kLoop " , " Loop " , " Loop the animation a finite number of times " ) ,
( " kLoopForever " , " Loop Forever " , " Continue playing animation indefinitely " ) ] ,
default = " kDontLoop " )
num_loops = IntProperty ( name = " Num Loops " ,
description = " Number of times to loop animation " ,
default = 0 )
input_sockets = OrderedDict ( [
( " stage_settings " , {
" text " : " Stage Settings " ,
" type " : " PlasmaAnimStageSettingsSocket " ,
" valid_link_nodes " : " PlasmaAnimStageSettingsNode " ,
" valid_link_sockets " : " PlasmaAnimStageSettingsSocket " ,
" link_limit " : 1 ,
} ) ,
] )
output_sockets = OrderedDict ( [
( " stage " , {
" text " : " Behavior " ,
" type " : " PlasmaAnimStageRefSocket " ,
" valid_link_nodes " : " PlasmaMultiStageBehaviorNode " ,
" valid_link_sockets " : " PlasmaAnimStageRefSocket " ,
} ) ,
( " stage_reference " , {
" text " : " Stage Progression " ,
" type " : " PlasmaAnimStageOrderSocketOut " ,
" valid_link_nodes " : " PlasmaAnimStageSettingsNode " ,
" valid_link_sockets " : { " PlasmaAnimStageAdvanceSocketIn " , " PlasmaAnimStageRegressSocketIn " } ,
} ) ,
] )
def draw_buttons ( self , context , layout ) :
layout . prop ( self , " anim_name " )
row = layout . row ( )
row . prop ( self , " loop_option " )
if self . loop_option == " kLoop " :
row = layout . row ( )
row . prop ( self , " num_loops " )
@property
def stage_id ( self ) :
idx = None
stage_socket = self . find_output_socket ( " stage " )
if stage_socket . is_linked :
msbmod = stage_socket . links [ 0 ] . to_node
idx = next ( ( idx for idx , socket in enumerate ( msbmod . find_input_sockets ( " stage_refs " ) ) if socket . is_linked and socket . links [ 0 ] . from_node == self ) )
return idx
class PlasmaBehaviorSocket ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.348 , 0.186 , 0.349 , 1.0 )
class PlasmaMultiStageBehaviorNode ( PlasmaNodeBase , bpy . types . Node ) :
bl_category = " AVATAR "
bl_idname = " PlasmaMultiStageBehaviorNode "
bl_label = " Multistage Behavior "
bl_width_default = 200
pl_attrib = ( " ptAttribBehavior " )
freeze_phys = BoolProperty ( name = " Freeze Physical " ,
description = " Freeze physical at end " ,
default = False )
reverse_control = BoolProperty ( name = " Reverse Controls " ,
description = " Reverse forward/back controls at end " ,
default = False )
input_sockets = OrderedDict ( [
( " seek_target " , {
" text " : " Seek Target " ,
" type " : " PlasmaSeekTargetSocketIn " ,
" valid_link_sockets " : " PlasmaSeekTargetSocketOut " ,
} ) ,
( " stage_refs " , {
" text " : " Stage " ,
" type " : " PlasmaAnimStageRefSocket " ,
" valid_link_nodes " : " PlasmaAnimStageNode " ,
" valid_link_sockets " : " PlasmaAnimStageRefSocket " ,
" link_limit " : 1 ,
" spawn_empty " : True ,
} ) ,
] )
output_sockets = OrderedDict ( [
( " hosts " , {
" text " : " Host Script " ,
" type " : " PlasmaBehaviorSocket " ,
" valid_link_nodes " : { " PlasmaPythonFileNode " } ,
" spawn_empty " : True ,
} )
] )
def draw_buttons ( self , context , layout ) :
layout . prop ( self , " freeze_phys " )
layout . prop ( self , " reverse_control " )
def get_key ( self , exporter , so ) :
seek_socket = self . find_input_socket ( " seek_target " )
if seek_socket . is_linked :
seek_target = seek_socket . links [ 0 ] . from_node . target
if seek_target is not None :
seek_object = exporter . mgr . find_create_object ( plSceneObject , bl = seek_target )
else :
raise ExportError ( " ' {} ' : MultiStage Behavior ' s seek point object is invalid " . format ( self . _find_create_key ( plMultistageBehMod , exporter , so = so ) . name ) )
else :
seek_object = so
return self . _find_create_key ( plMultistageBehMod , exporter , so = seek_object )
def export ( self , exporter , bo , so ) :
seek_socket = self . find_input_socket ( " seek_target " )
msbmod = self . get_key ( exporter , so ) . object
msbmod . smartSeek = True if seek_socket . is_linked or seek_socket . auto_target else False
msbmod . freezePhys = self . freeze_phys
msbmod . reverseFBControlsOnRelease = self . reverse_control
for stage in self . find_inputs ( " stage_refs " ) :
animstage = plAnimStage ( )
animstage . animName = stage . anim_name
if stage . loop_option == " kLoopForever " :
animstage . loops = - 1
elif stage . loop_option == " kLoop " :
animstage . loops = stage . num_loops
# Harvest additional AnimStage Settings, if available
settings = stage . find_input ( " stage_settings " )
if settings :
animstage . forwardType = getattr ( plAnimStage , settings . forward )
animstage . backType = getattr ( plAnimStage , settings . backward )
animstage . advanceType = getattr ( plAnimStage , settings . stage_advance )
animstage . regressType = getattr ( plAnimStage , settings . stage_regress )
for flag in settings . notify_on :
animstage . notify | = getattr ( plAnimStage , flag )
advance_to = settings . find_input_socket ( " advance_to " )
if advance_to . is_linked :
# Auto-Advance to specific stage
animstage . advanceTo = advance_to . links [ 0 ] . from_node . stage_id
elif advance_to . auto_advance :
# Auto-Advance
animstage . advanceTo = None
else :
# Don't Auto-Advance, just stop!
animstage . advanceTo = - 1
regress_to = settings . find_input_socket ( " regress_to " )
if regress_to . is_linked :
# Auto-Regress to specific stage
animstage . regressTo = regress_to . links [ 0 ] . from_node . stage_id
elif regress_to . auto_regress :
# Auto-Regress
animstage . regressTo = None
else :
# Don't Auto-Regress, just stop!
animstage . regressTo = - 1
msbmod . addStage ( animstage )
@property
def requires_actor ( self ) :
return not self . find_input_socket ( " seek_target " ) . is_linked
@property
def export_once ( self ) :
return self . find_input_socket ( " seek_target " ) . is_linked
def harvest_actors ( self ) :
seek_socket = self . find_input_socket ( " seek_target " )
if seek_socket . is_linked and seek_socket . links [ 0 ] . from_node . target is not None :
yield seek_socket . links [ 0 ] . from_node . target . name
class PlasmaAnimStageRefSocket ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.188 , 0.186 , 0.349 , 1.0 )
def draw_content ( self , context , layout , node , text ) :
if isinstance ( node , PlasmaMultiStageBehaviorNode ) :
try :
idx = next ( ( idx for idx , socket in enumerate ( node . find_input_sockets ( " stage_refs " ) ) if socket == self ) )
except StopIteration :
layout . label ( text )
else :
layout . label ( " Stage (ID: {} ) " . format ( idx ) )
else :
layout . label ( text )
class PlasmaSeekTargetSocketIn ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.180 , 0.350 , 0.180 , 1.0 )
auto_target = BoolProperty ( name = " Auto Smart Seek " ,
description = " Smart Seek causes the avatar to seek to the provided position before starting the behavior ( ' auto ' will use the current object as the seek point) " ,
default = False )
def draw_content ( self , context , layout , node , text ) :
if not self . is_linked :
layout . prop ( self , " auto_target " )
else :
target = self . links [ 0 ] . from_node . target
if target :
layout . label ( " Smart Seek Target: {} " . format ( target . name ) )
else :
layout . label ( " Smart Seek Target " )
class PlasmaSeekTargetSocketOut ( PlasmaNodeSocketBase , bpy . types . NodeSocket ) :
bl_color = ( 0.180 , 0.350 , 0.180 , 1.0 )
class PlasmaSeekTargetNode ( PlasmaNodeBase , bpy . types . Node ) :
bl_category = " AVATAR "
bl_idname = " PlasmaSeekTargetNode "
bl_label = " Seek Target "
bl_width_default = 200
target = PointerProperty ( name = " Position " ,
description = " Object defining the Seek Point ' s position " ,
type = bpy . types . Object )
output_sockets = OrderedDict ( [
( " seekers " , {
" text " : " Seekers " ,
" type " : " PlasmaSeekTargetSocketOut " ,
" valid_link_nodes " : { " PlasmaMultiStageBehaviorNode " , " PlasmaOneShotMsgNode " } ,
" valid_link_sockets " : { " PlasmaSeekTargetSocketIn " } ,
} )
] )
def draw_buttons ( self , context , layout ) :
col = layout . column ( )
col . prop ( self , " target " , icon = " EMPTY_DATA " )