Browse Source

Merge pull request #124 from Deledrius/MultiStageBeh

Add MultiStageBehMod Node.
pull/162/head
Adam Johnson 5 years ago committed by GitHub
parent
commit
f016eea84c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 382
      korman/nodes/node_avatar.py
  2. 1
      korman/nodes/node_python.py

382
korman/nodes/node_avatar.py

@ -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 = 100 bl_width_default = 120
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")

1
korman/nodes/node_python.py

@ -862,6 +862,7 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ
_attrib_colors = { _attrib_colors = {
"ptAttribActivator": (0.188, 0.086, 0.349, 1.0), "ptAttribActivator": (0.188, 0.086, 0.349, 1.0),
"ptAttribActivatorList": (0.188, 0.086, 0.349, 1.0), "ptAttribActivatorList": (0.188, 0.086, 0.349, 1.0),
"ptAttribBehavior": (0.348, 0.186, 0.349, 1.0),
"ptAttribBoolean": (0.71, 0.706, 0.655, 1.0), "ptAttribBoolean": (0.71, 0.706, 0.655, 1.0),
"ptAttribExcludeRegion": (0.031, 0.110, 0.290, 1.0), "ptAttribExcludeRegion": (0.031, 0.110, 0.290, 1.0),
"ptAttribDropDownList": (0.475, 0.459, 0.494, 1.0), "ptAttribDropDownList": (0.475, 0.459, 0.494, 1.0),

Loading…
Cancel
Save