# 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 . import bmesh import bpy from bpy.props import * import mathutils from PyHSPlasma import * from ...addon_prefs import game_versions from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz from ...exporter import ExportError, utils from ... import idprops class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup): version = EnumProperty(name="Version", description="Plasma versions this node tree exports under", items=game_versions, options={"ENUM_FLAG"}, default=set(list(zip(*game_versions))[0])) node_tree = PointerProperty(name="Node Tree", description="Node Tree to export", type=bpy.types.NodeTree) @classmethod def _idprop_mapping(cls): return {"node_tree": "node_tree_name"} def _idprop_sources(self): return {"node_tree_name": bpy.data.node_groups} class PlasmaAdvancedLogic(PlasmaModifierProperties): pl_id = "advanced_logic" bl_category = "Logic" bl_label = "Advanced" bl_description = "Plasma Logic Nodes" bl_icon = "NODETREE" logic_groups = CollectionProperty(type=PlasmaVersionedNodeTree) active_group_index = IntProperty(options={"HIDDEN"}) def export(self, exporter, bo, so): version = exporter.mgr.getVer() for i in self.logic_groups: our_versions = [globals()[j] for j in i.version] if version in our_versions: if i.node_tree is None: raise ExportError("'{}': Advanced Logic is missing a node tree for '{}'".format(bo.name, i.name)) # Defer node tree export until all trees are harvested. exporter.want_node_trees[i.node_tree.name].add((bo, so)) def harvest_actors(self): actors = set() for i in self.logic_groups: if i.node_tree is not None: actors.update(i.node_tree.harvest_actors()) return actors @property def requires_actor(self): return any((i.node_tree.requires_actor for i in self.logic_groups if i.node_tree)) class PlasmaSpawnPoint(PlasmaModifierProperties): pl_id = "spawnpoint" bl_category = "Logic" bl_label = "Spawn Point" bl_description = "Point at which avatars link into the Age" bl_object_types = {"EMPTY"} def export(self, exporter, bo, so): # Not much to this modifier... It's basically a flag that tells the engine, "hey, this is a # place the avatar can show up." Nice to have a simple one to get started with. spawn = exporter.mgr.add_object(pl=plSpawnModifier, so=so, name=self.key_name) @property def requires_actor(self): return True class PlasmaMaintainersMarker(PlasmaModifierProperties): pl_id = "maintainersmarker" bl_category = "Logic" bl_label = "Maintainer's Marker" bl_description = "Designates an object as the D'ni coordinate origin point of the Age." bl_icon = "OUTLINER_DATA_EMPTY" calibration = EnumProperty(name="Calibration", description="State of repair for the Marker", items=[ ("kBroken", "Broken", "A marker which reports scrambled coordinates to the KI."), ("kRepaired", "Repaired", "A marker which reports blank coordinates to the KI."), ("kCalibrated", "Calibrated", "A marker which reports accurate coordinates to the KI.") ]) def export(self, exporter, bo, so): maintmark = exporter.mgr.add_object(pl=plMaintainersMarkerModifier, so=so, name=self.key_name) maintmark.calibration = getattr(plMaintainersMarkerModifier, self.calibration) @property def requires_actor(self): return True telescope_pfm = { "filename": "xTelescope.py", "attribs": ( { 'id': 1, 'type': "ptAttribActivator", 'name': "Activate" }, { 'id': 2, 'type': "ptAttribSceneobject", 'name': "Camera" }, { 'id': 3, 'type': "ptAttribBehavior", 'name': "Behavior" }, { 'id': 4, 'type': "ptAttribString", 'name': "Vignette" }, ) } class PlasmaTelescope(PlasmaModifierProperties, PlasmaModifierLogicWiz): pl_id="telescope" bl_category = "Logic" bl_label = "Telescope" bl_description = "Set up clickable mesh as a telescope." bl_icon = "VISIBLE_IPO_ON" clickable_region = PointerProperty(name="Region", description="Region inside which the avatar must stand to be able to use the telescope (optional).", type=bpy.types.Object, poll=idprops.poll_mesh_objects) seek_target_object = PointerProperty(name="Seek Point", description="Empty object representing the position/orientation of the player when using the telescope.", type=bpy.types.Object, poll=idprops.poll_empty_objects) camera_object = PointerProperty(name="Camera", description="Camera used when viewing through telescope.", type=bpy.types.Object, poll=idprops.poll_camera_objects) def sanity_check(self, exporter): if self.camera_object is None: raise ExportError(f"'{self.id_data.name}': Telescopes must specify a camera!") def pre_export(self, exporter, bo): # Generate a six-foot cube region if none was provided. if self.clickable_region is None: self.clickable_region = yield utils.create_cube_region( f"{self.key_name}_Telescope_ClkRgn", 6.0, bo ) # Generate the logic nodes yield self.convert_logic(bo) def logicwiz(self, bo, tree): nodes = tree.nodes # Create Python Node telescopepynode = self._create_python_file_node(tree, telescope_pfm["filename"], telescope_pfm["attribs"]) # Clickable telescopeclick = nodes.new("PlasmaClickableNode") telescopeclick.value = bo for i in telescopeclick.inputs: i.allow_simple = False telescopeclick.link_output(telescopepynode, "satisfies", "Activate") # Region telescoperegion = nodes.new("PlasmaClickableRegionNode") telescoperegion.region_object = self.clickable_region telescoperegion.link_output(telescopeclick, "satisfies", "region") # Telescope Camera telescopecam = nodes.new("PlasmaAttribObjectNode") telescopecam.target_object = self.camera_object telescopecam.link_output(telescopepynode, "pfm", "Camera") # Now for the tricky MSB! telescopemsb = nodes.new("PlasmaMultiStageBehaviorNode") telescopemsb.link_output(telescopepynode, "hosts", "Behavior") # OneShot telescopeoneshot = nodes.new("PlasmaSeekTargetNode") telescopeoneshot.target = self.seek_target_object if self.seek_target_object else bo telescopeoneshot.link_output(telescopemsb, "seekers", "seek_target") # Anim Stage 1 (Grab) telescopestageone = nodes.new("PlasmaAnimStageNode") telescopestageone.anim_name = "GlobalScopeGrab" telescopestageone.loop_option = "kLoop" telescopestageone.num_loops = 0 telescopestageone.link_output(telescopemsb, "stage", "stage_refs") # Settings telescopestageoneops = nodes.new("PlasmaAnimStageSettingsNode") telescopestageoneops.forward = "kPlayAuto" telescopestageoneops.stage_advance = "kAdvanceAuto" telescopestageoneops.notify_on = {"kNotifyAdvance"} telescopestageoneops.link_output(telescopestageone, "stage", "stage_settings") # Anim Stage 2 (Hold) telescopestagetwo = nodes.new("PlasmaAnimStageNode") telescopestagetwo.anim_name = "GlobalScopeHold" telescopestagetwo.loop_option = "kLoop" telescopestagetwo.num_loops = -1 telescopestagetwo.link_output(telescopemsb, "stage", "stage_refs") # Settings telescopestagetwoops = nodes.new("PlasmaAnimStageSettingsNode") telescopestagetwoops.forward = "kPlayAuto" telescopestagetwoops.notify_on = set() telescopestagetwoops.link_output(telescopestagetwo, "stage", "stage_settings") # Anim Stage 3 (Release) telescopestagethree = nodes.new("PlasmaAnimStageNode") telescopestagethree.anim_name = "GlobalScopeRelease" telescopestagethree.loop_option = "kLoop" telescopestagethree.num_loops = 0 telescopestagethree.link_output(telescopemsb, "stage", "stage_refs") # Settings telescopestagethreeops = nodes.new("PlasmaAnimStageSettingsNode") telescopestagethreeops.forward = "kPlayAuto" telescopestagethreeops.stage_advance = "kAdvanceAuto" telescopestagethreeops.notify_on = set() telescopestagethreeops.link_output(telescopestagethree, "stage", "stage_settings") telescopename = nodes.new("PlasmaAttribStringNode") telescopename.value = "telescope" telescopename.link_output(telescopepynode, "pfm", "Vignette")