You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

171 lines
7.5 KiB

# This file is part of Korman.
#
# Korman is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Korman is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bpy.props import *
import mathutils
from PyHSPlasma import *
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
from ...exporter.explosions import ExportError
from ...helpers import find_modifier
from ... import idprops
class PlasmaLadderModifier(PlasmaModifierProperties):
pl_id = "laddermod"
bl_category = "Avatar"
bl_label = "Ladder"
bl_description = "Climbable Ladder"
bl_icon = "COLLAPSEMENU"
is_enabled = BoolProperty(name="Enabled",
description="Ladder enabled by default at Age start",
default=True)
direction = EnumProperty(name="Direction",
description="Direction of climb",
items=[("UP", "Up", "The avatar will mount the ladder and climb upward"),
("DOWN", "Down", "The avatar will mount the ladder and climb downward"),],
default="DOWN")
num_loops = IntProperty(name="Loops",
description="How many full animation loops after the first to play before dismounting",
min=0, default=4)
facing_object = PointerProperty(name="Facing Object",
description="Target object the avatar must be facing through this region to trigger climb (optional)",
type=bpy.types.Object,
poll=idprops.poll_mesh_objects)
def export(self, exporter, bo, so):
# Create the ladder modifier
mod = exporter.mgr.find_create_object(plAvLadderMod, so=so, name=self.key_name)
mod.type = plAvLadderMod.kBig
mod.loops = self.num_loops
mod.enabled = self.is_enabled
mod.goingUp = self.direction == "UP"
# Create vector pointing from the Facing Object to the Detector.
# Animation only activates if the avatar is facing it within
# engine-defined (45 degree) tolerance
if self.facing_object is not None:
# Use object if one has been selected
ladderVec = self.facing_object.matrix_world.translation - bo.matrix_world.translation
else:
# Make our own artificial target -1.0 units back on the local Y axis.
ladderVec = mathutils.Vector((0, -1, 0)) * bo.matrix_world.inverted()
mod.ladderView = hsVector3(ladderVec.x, ladderVec.y, 0.0)
mod.ladderView.normalize()
# Generate the detector's physical bounds
bounds = "hull" if not bo.plasma_modifiers.collision.enabled else bo.plasma_modifiers.collision.bounds
exporter.physics.generate_physical(bo, so, bounds=bounds, member_group="kGroupDetector",
report_groups=["kGroupAvatar"], properties=["kPinned"])
@property
def requires_actor(self):
return True
sitting_approach_flags = [("kApproachFront", "Front", "Approach from the font"),
("kApproachLeft", "Left", "Approach from the left"),
("kApproachRight", "Right", "Approach from the right"),
("kApproachRear", "Rear", "Approach from the rear guard")]
class PlasmaSittingBehavior(idprops.IDPropObjectMixin, PlasmaModifierProperties, PlasmaModifierLogicWiz):
pl_id = "sittingmod"
bl_category = "Avatar"
bl_label = "Sitting Behavior"
bl_description = "Avatar sitting position"
approach = EnumProperty(name="Approach",
description="Directions an avatar can approach the seat from",
items=sitting_approach_flags,
default={"kApproachFront", "kApproachLeft", "kApproachRight"},
options={"ENUM_FLAG"})
clickable_object = PointerProperty(name="Clickable",
description="Object that defines the clickable area",
type=bpy.types.Object,
poll=idprops.poll_mesh_objects)
region_object = PointerProperty(name="Region",
description="Object that defines the region mesh",
type=bpy.types.Object,
poll=idprops.poll_mesh_objects)
facing_enabled = BoolProperty(name="Avatar Facing",
description="The avatar must be facing the clickable's Y-axis",
default=True)
facing_degrees = IntProperty(name="Tolerance",
description="How far away we will tolerate the avatar facing the clickable",
min=-180, max=180, default=45)
def harvest_actors(self):
if self.facing_enabled:
yield self.clickable_object.name
def logicwiz(self, bo, tree):
nodes = tree.nodes
# Sitting Modifier
sittingmod = nodes.new("PlasmaSittingBehaviorNode")
sittingmod.approach = self.approach
sittingmod.name = "SittingBeh"
# Clickable
clickable = nodes.new("PlasmaClickableNode")
clickable.link_output(sittingmod, "satisfies", "condition")
clickable.clickable_object = self.clickable_object
clickable.bounds = find_modifier(self.clickable_object, "collision").bounds
# Avatar Region (optional)
region_phys = find_modifier(self.region_object, "collision")
if region_phys is not None:
region = nodes.new("PlasmaClickableRegionNode")
region.link_output(clickable, "satisfies", "region")
region.name = "ClickableAvRegion"
region.region_object = self.region_object
region.bounds = region_phys.bounds
# Facing Target (optional)
if self.facing_enabled:
facing = nodes.new("PlasmaFacingTargetNode")
facing.link_output(clickable, "satisfies", "facing")
facing.name = "FacingClickable"
facing.directional = True
facing.tolerance = self.facing_degrees
else:
# this socket must be explicitly disabled, otherwise it automatically generates a default
# facing target conditional for us. isn't that nice?
clickable.find_input_socket("facing").allow_simple = False
@classmethod
def _idprop_mapping(cls):
return {"clickable_object": "clickable_obj",
"region_object": "region_obj"}
@property
def key_name(self):
return "{}_SitBeh".format(self.id_data.name)
@property
def requires_actor(self):
# This should be an empty, really...
return True
def sanity_check(self):
# The user absolutely MUST specify a clickable or this won't export worth crap.
if self.clickable_object is None:
raise ExportError("'{}': Sitting Behavior's clickable object is invalid".format(self.key_name))