Browse Source

Merge pull request #414 from Hoikas/phony_pfm_reorg

Reorganize PFM Stub Storage and Add the SDL Show/Hide Modifier.
pull/333/merge
Adam Johnson 3 months ago committed by GitHub
parent
commit
73639302cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      korman/exporter/convert.py
  2. 6
      korman/operators/op_ui.py
  3. 134
      korman/plasma_api.py
  4. 12
      korman/properties/modifiers/avatar.py
  5. 19
      korman/properties/modifiers/base.py
  6. 87
      korman/properties/modifiers/gui.py
  7. 108
      korman/properties/modifiers/logic.py
  8. 26
      korman/properties/modifiers/render.py
  9. 37
      korman/ui/modifiers/logic.py

8
korman/exporter/convert.py

@ -510,8 +510,12 @@ class Exporter:
@handle_temporary.register(bpy.types.NodeTree) @handle_temporary.register(bpy.types.NodeTree)
def _(temporary, parent): def _(temporary, parent):
# NodeTrees are reuseable, so make sure we haven't already encountered it.
if not temporary.name in self.want_node_trees:
self.exit_stack.enter_context(TemporaryObject(temporary, bpy.data.node_groups.remove)) self.exit_stack.enter_context(TemporaryObject(temporary, bpy.data.node_groups.remove))
log_msg(f"'{parent.name}' generated NodeTree '{temporary.name}'") log_msg(f"'{parent.name}' generated NodeTree '{temporary.name}'")
else:
log_msg(f"'{parent.name}' reused NodeTree '{temporary.name}'")
if temporary.bl_idname == "PlasmaNodeTree": if temporary.bl_idname == "PlasmaNodeTree":
parent_so = self.mgr.find_create_object(plSceneObject, bl=parent) parent_so = self.mgr.find_create_object(plSceneObject, bl=parent)
self.want_node_trees[temporary.name].add((parent, parent_so)) self.want_node_trees[temporary.name].add((parent, parent_so))
@ -594,6 +598,10 @@ class Exporter:
else: else:
return bpy.context.scene.world.plasma_age.age_name return bpy.context.scene.world.plasma_age.age_name
@property
def age_sdl(self) -> bool:
return bpy.context.scene.world.plasma_age.age_sdl
@property @property
def dat_only(self): def dat_only(self):
return self._op.dat_only return self._op.dat_only

6
korman/operators/op_ui.py

@ -77,11 +77,17 @@ class CollectionRemoveOperator(UIOperator, bpy.types.Operator):
index_prop = StringProperty(name="Index Property", index_prop = StringProperty(name="Index Property",
description="Name of the active element index property", description="Name of the active element index property",
options=set()) options=set())
manual_index = IntProperty(name="Manual Index",
description="Manual integer index to remove",
options=set())
def execute(self, context): def execute(self, context):
props = getattr(context, self.context).path_resolve(self.group_path) props = getattr(context, self.context).path_resolve(self.group_path)
collection = getattr(props, self.collection_prop) collection = getattr(props, self.collection_prop)
if self.index_prop:
index = getattr(props, self.index_prop) index = getattr(props, self.index_prop)
else:
index = self.manual_index
if len(collection) > index: if len(collection) > index:
collection.remove(index) collection.remove(index)
setattr(props, self.index_prop, index - 1) setattr(props, self.index_prop, index - 1)

134
korman/plasma_api.py

@ -0,0 +1,134 @@
# 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/>.
python_files = {
"xAgeSDLBoolShowHide.py": (
{ "id": 1, "type": "ptAttribString", "name": "sdlName" },
{ "id": 2, "type": "ptAttribBoolean", "name": "showOnTrue" },
# --- CWE Only Below ---
{ "id": 3, "type": "ptAttribBoolean", "name": "defaultValue" },
{ "id": 4, "type": "ptAttribBoolean", "name": "evalOnFirstUpdate "},
),
"xAgeSDLIntShowHide.py": (
{ "id": 1, "type": "ptAttribString", "name": "stringVarName" },
{ "id": 2, "type": "ptAttribString", "name": "stringShowStates" },
# --- CWE Only Below ---
{ "id": 3, "type": "ptAttribInt", "name": "intDefault" },
{ "id": 4, "type": "ptAttribBoolean", "name": "boolFirstUpdate "},
),
# Provided by all variants of Uru and Myst V
"xDialogToggle.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "Activate" },
{ "id": 4, "type": "ptAttribString", "name": "Vignette" },
),
# Provided by CWE or OfflineKI
"xDynTextLoc.py": (
{ "id": 1, "type": "ptAttribDynamicMap", "name": "dynTextMap", },
{ "id": 2, "type": "ptAttribString", "name": "locPath" },
{ "id": 3, "type": "ptAttribString", "name": "fontFace" },
{ "id": 4, "type": "ptAttribInt", "name": "fontSize" },
{ "id": 5, "type": "ptAttribFloat", "name": "fontColorR" },
{ "id": 6, "type": "ptAttribFloat", "name": "fontColorG" },
{ "id": 7, "type": "ptAttribFloat", "name": "fontColorB" },
{ "id": 8, "type": "ptAttribFloat", "name": "fontColorA" },
{ "id": 9, "type": "ptAttribInt", "name": "marginTop" },
{ "id": 10, "type": "ptAttribInt", "name": "marginLeft" },
{ "id": 11, "type": "ptAttribInt", "name": "marginBottom" },
{ "id": 12, "type": "ptAttribInt", "name": "marginRight" },
{ "id": 13, "type": "ptAttribInt", "name": "lineSpacing" },
# Yes, it"s really a ptAttribDropDownList, but those are only for use in
# artist generated node trees.
{ "id": 14, "type": "ptAttribString", "name": "justify" },
{ "id": 15, "type": "ptAttribFloat", "name": "clearColorR" },
{ "id": 16, "type": "ptAttribFloat", "name": "clearColorG" },
{ "id": 17, "type": "ptAttribFloat", "name": "clearColorB" },
{ "id": 18, "type": "ptAttribFloat", "name": "clearColorA" },
{ "id": 19, "type": "ptAttribBoolean", "name": "blockRGB" },
),
# Provided by CWE and OfflineKI
"xEntryCam.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "actRegionSensor" },
{ "id": 2, "type": "ptAttribSceneobject", "name": "camera" },
{ "id": 3, "type": "ptAttribBoolean", "name": "undoFirstPerson" },
),
# Provided by CWE
"xJournalBookGUIPopup.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "actClickableBook" },
{ "id": 10, "type": "ptAttribBoolean", "name": "StartOpen" },
{ "id": 11, "type": "ptAttribFloat", "name": "BookWidth" },
{ "id": 12, "type": "ptAttribFloat", "name": "BookHeight" },
{ "id": 13, "type": "ptAttribString", "name": "LocPath" },
{ "id": 14, "type": "ptAttribString", "name": "GUIType" },
),
# Provided by all variants of Uru and Myst V
"xLinkingBookGUIPopup.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "actClickableBook" },
{ "id": 2, "type": "ptAttribBehavior", "name": "SeekBehavior" },
{ "id": 3, "type": "ptAttribResponder", "name": "respLinkResponder" },
{ "id": 4, "type": "ptAttribString", "name": "TargetAge" },
{ "id": 5, "type": "ptAttribActivator", "name": "actBookshelf" },
{ "id": 6, "type": "ptAttribActivator", "name": "shareRegion" },
{ "id": 7, "type": "ptAttribBehavior", "name": "shareBookSeek" },
{ "id": 10, "type": "ptAttribBoolean", "name": "IsDRCStamped" },
{ "id": 11, "type": "ptAttribBoolean", "name": "ForceThirdPerson" },
),
# Supplied by the OfflineKI script:
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleJournal.py
"xSimpleJournal.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "bookClickable" },
{ "id": 2, "type": "ptAttribString", "name": "journalFileName" },
{ "id": 3, "type": "ptAttribBoolean", "name": "isNotebook" },
{ "id": 4, "type": "ptAttribFloat", "name": "BookWidth" },
{ "id": 5, "type": "ptAttribFloat", "name": "BookHeight" },
),
# Supplied by the OfflineKI script:
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleLinkingBook.py
"xSimpleLinkingBook.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "bookClickable" },
{ "id": 2, "type": "ptAttribString", "name": "destinationAge" },
{ "id": 3, "type": "ptAttribString", "name": "spawnPoint" },
{ "id": 4, "type": "ptAttribString", "name": "linkPanel" },
{ "id": 5, "type": "ptAttribString", "name": "bookCover" },
{ "id": 6, "type": "ptAttribString", "name": "stampTexture" },
{ "id": 7, "type": "ptAttribFloat", "name": "stampX" },
{ "id": 8, "type": "ptAttribFloat", "name": "stampY" },
{ "id": 9, "type": "ptAttribFloat", "name": "bookWidth" },
{ "id": 10, "type": "ptAttribFloat", "name": "BookHeight" },
{ "id": 11, "type": "ptAttribBehavior", "name": "msbSeekBeforeUI" },
{ "id": 12, "type": "ptAttribResponder", "name": "respOneShot" },
),
# Provided by CWE or OfflineKI
"xSitCam.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "sitAct" },
{ "id": 2, "type": "ptAttribSceneobject", "name": "sitCam" },
),
# Provided by all variants of Uru and Myst V
"xTelescope.py": (
{ "id": 1, "type": "ptAttribActivator", "name": "Activate" },
{ "id": 2, "type": "ptAttribSceneobject", "name": "Camera" },
{ "id": 3, "type": "ptAttribBehavior", "name": "Behavior" },
{ "id": 4, "type": "ptAttribString", "name": "Vignette" },
)
}

12
korman/properties/modifiers/avatar.py

@ -78,16 +78,6 @@ class PlasmaLadderModifier(PlasmaModifierProperties):
return True return True
# Use xSitCam.py for when we want a camera to pop up
sitting_pfm = {
"filename": "xSitCam.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", 'name': "sitAct" },
{ 'id': 2, 'type': "ptAttribSceneobject", 'name': "sitCam" },
)
}
sitting_approach_flags = [("kApproachFront", "Front", "Approach from the font"), sitting_approach_flags = [("kApproachFront", "Front", "Approach from the font"),
("kApproachLeft", "Left", "Approach from the left"), ("kApproachLeft", "Left", "Approach from the left"),
("kApproachRight", "Right", "Approach from the right"), ("kApproachRight", "Right", "Approach from the right"),
@ -140,7 +130,7 @@ class PlasmaSittingBehavior(idprops.IDPropObjectMixin, PlasmaModifierProperties,
sittingmod.name = "SittingBeh" sittingmod.name = "SittingBeh"
# xSitCam.py PythonFileMod # xSitCam.py PythonFileMod
if self.sitting_camera is not None: if self.sitting_camera is not None:
sittingpynode = self._create_python_file_node(tree, sitting_pfm["filename"], sitting_pfm["attribs"]) sittingpynode = self._create_python_standard_file_node(tree, "xSitCam.py")
sittingmod.link_output(sittingpynode, "satisfies", "sitAct") sittingmod.link_output(sittingpynode, "satisfies", "sitAct")
# Camera Object # Camera Object

19
korman/properties/modifiers/base.py

@ -26,6 +26,7 @@ if TYPE_CHECKING:
from ...nodes.node_python import * from ...nodes.node_python import *
from ... import helpers from ... import helpers
from ... import plasma_api
class PlasmaModifierProperties(bpy.types.PropertyGroup): class PlasmaModifierProperties(bpy.types.PropertyGroup):
@property @property
@ -180,19 +181,23 @@ class PlasmaModifierProperties(bpy.types.PropertyGroup):
class PlasmaModifierLogicWiz: class PlasmaModifierLogicWiz:
def convert_logic(self, bo, **kwargs): def convert_logic(self, bo, **kwargs):
"""Creates, converts, and returns an unmanaged NodeTree for this logic wizard. If the wizard """Attempts to look up an already existing logic tree matching the name provided and returns
fails during conversion, the temporary tree is deleted for you. However, on success, you it, if found. If not, creates, converts, and returns an unmanaged NodeTree for this wizard.
are responsible for removing the tree from Blender, if applicable.""" If the wizard fails during conversion, the temporary tree is deleted for you. However, on
success, you are responsible for removing the tree from Blender, if applicable."""
name = kwargs.pop("name", self.key_name) name = kwargs.pop("name", self.key_name)
assert not "tree" in kwargs assert not "tree" in kwargs
tree = bpy.data.node_groups.new(name, "PlasmaNodeTree")
node_groups = bpy.data.node_groups
tree = node_groups.get(name)
if tree is None:
tree = node_groups.new(name, "PlasmaNodeTree")
kwargs["tree"] = tree kwargs["tree"] = tree
try: try:
self.logicwiz(bo, **kwargs) self.logicwiz(bo, **kwargs)
except: except:
bpy.data.node_groups.remove(tree) bpy.data.node_groups.remove(tree)
raise raise
else:
return tree return tree
def _create_python_file_node(self, tree, filename: str, attributes: Dict[str, Any]) -> bpy.types.Node: def _create_python_file_node(self, tree, filename: str, attributes: Dict[str, Any]) -> bpy.types.Node:
@ -207,6 +212,10 @@ class PlasmaModifierLogicWiz:
pfm_node.update() pfm_node.update()
return pfm_node return pfm_node
def _create_standard_python_file_node(self, tree, filename: str) -> bpy.types.Node:
"""Create a Python File Node for a standard Plasma Python API file (e.g. xAgeSDLBoolShowHide.py)"""
return self._create_python_file_node(tree, filename, plasma_api.python_files[filename])
def _create_python_attribute(self, pfm_node: PlasmaPythonFileNode, attribute_name: str, **kwargs): def _create_python_attribute(self, pfm_node: PlasmaPythonFileNode, attribute_name: str, **kwargs):
"""Creates and links a Python Attribute Node to the Python File Node given by `pfm_node`. """Creates and links a Python Attribute Node to the Python File Node given by `pfm_node`.
For attribute nodes that require multiple values, the `value` may be set to None and For attribute nodes that require multiple values, the `value` may be set to None and

87
korman/properties/modifiers/gui.py

@ -35,33 +35,6 @@ if TYPE_CHECKING:
from ...exporter import Exporter from ...exporter import Exporter
from .game_gui import PlasmaGameGuiDialogModifier from .game_gui import PlasmaGameGuiDialogModifier
journal_pfms = {
pvPots : {
# Supplied by the OfflineKI script:
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleJournal.py
"filename": "xSimpleJournal.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", "name": "bookClickable" },
{ 'id': 2, 'type': "ptAttribString", "name": "journalFileName" },
{ 'id': 3, 'type': "ptAttribBoolean", "name": "isNotebook" },
{ 'id': 4, 'type': "ptAttribFloat", "name": "BookWidth" },
{ 'id': 5, 'type': "ptAttribFloat", "name": "BookHeight" },
)
},
pvMoul : {
"filename": "xJournalBookGUIPopup.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", 'name': "actClickableBook" },
{ 'id': 10, 'type': "ptAttribBoolean", 'name': "StartOpen" },
{ 'id': 11, 'type': "ptAttribFloat", 'name': "BookWidth" },
{ 'id': 12, 'type': "ptAttribFloat", 'name': "BookHeight" },
{ 'id': 13, 'type': "ptAttribString", 'name': "LocPath" },
{ 'id': 14, 'type': "ptAttribString", 'name': "GUIType" },
)
},
}
# Do not change the numeric IDs. They allow the list to be rearranged. # Do not change the numeric IDs. They allow the list to be rearranged.
_languages = [("Dutch", "Nederlands", "Dutch", 0), _languages = [("Dutch", "Nederlands", "Dutch", 0),
("English", "English", "", 1), ("English", "English", "", 1),
@ -246,11 +219,11 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
def logicwiz(self, bo, tree, age_name, version): def logicwiz(self, bo, tree, age_name, version):
# Assign journal script based on target version # Assign journal script based on target version
journal_pfm = journal_pfms[version]
journalnode = self._create_python_file_node(tree, journal_pfm["filename"], journal_pfm["attribs"])
if version <= pvPots: if version <= pvPots:
journalnode = self._create_standard_python_file_node(tree, "xSimpleJournal.py")
self._create_pots_nodes(bo, tree.nodes, journalnode, age_name) self._create_pots_nodes(bo, tree.nodes, journalnode, age_name)
else: else:
journalnode = self._create_standard_python_file_node(tree, "xJournalBookGUIPopup.py")
self._create_moul_nodes(bo, tree.nodes, journalnode, age_name) self._create_moul_nodes(bo, tree.nodes, journalnode, age_name)
def _create_pots_nodes(self, clickable_object, nodes, journalnode, age_name): def _create_pots_nodes(self, clickable_object, nodes, journalnode, age_name):
@ -324,43 +297,6 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
return self.journal_translations return self.journal_translations
linking_pfms = {
pvPots : {
# Supplied by the OfflineKI script:
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleLinkingBook.py
"filename": "xSimpleLinkingBook.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", "name": "bookClickable" },
{ 'id': 2, 'type': "ptAttribString", "name": "destinationAge" },
{ 'id': 3, 'type': "ptAttribString", "name": "spawnPoint" },
{ 'id': 4, 'type': "ptAttribString", "name": "linkPanel" },
{ 'id': 5, 'type': "ptAttribString", "name": "bookCover" },
{ 'id': 6, 'type': "ptAttribString", "name": "stampTexture" },
{ 'id': 7, 'type': "ptAttribFloat", "name": "stampX" },
{ 'id': 8, 'type': "ptAttribFloat", "name": "stampY" },
{ 'id': 9, 'type': "ptAttribFloat", "name": "bookWidth" },
{ 'id': 10, 'type': "ptAttribFloat", "name": "BookHeight" },
{ 'id': 11, 'type': "ptAttribBehavior", "name": "msbSeekBeforeUI" },
{ 'id': 12, 'type': "ptAttribResponder", "name": "respOneShot" },
)
},
pvMoul : {
"filename": "xLinkingBookGUIPopup.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", 'name': "actClickableBook" },
{ 'id': 2, 'type': "ptAttribBehavior", 'name': "SeekBehavior" },
{ 'id': 3, 'type': "ptAttribResponder", 'name': "respLinkResponder" },
{ 'id': 4, 'type': "ptAttribString", 'name': "TargetAge" },
{ 'id': 5, 'type': "ptAttribActivator", 'name': "actBookshelf" },
{ 'id': 6, 'type': "ptAttribActivator", 'name': "shareRegion" },
{ 'id': 7, 'type': "ptAttribBehavior", 'name': "shareBookSeek" },
{ 'id': 10, 'type': "ptAttribBoolean", 'name': "IsDRCStamped" },
{ 'id': 11, 'type': "ptAttribBoolean", 'name': "ForceThirdPerson" },
)
},
}
class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz): class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz):
pl_id = "linkingbookmod" pl_id = "linkingbookmod"
@ -495,12 +431,11 @@ class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
yield self.seek_point.name yield self.seek_point.name
def logicwiz(self, bo, tree, age_name, version): def logicwiz(self, bo, tree, age_name, version):
# Assign linking book script based on target version
linking_pfm = linking_pfms[version]
linkingnode = self._create_python_file_node(tree, linking_pfm["filename"], linking_pfm["attribs"])
if version <= pvPots: if version <= pvPots:
linkingnode = self._create_standard_python_file_node(tree, "xSimpleLinkingBook.py")
self._create_pots_nodes(bo, tree.nodes, linkingnode, age_name) self._create_pots_nodes(bo, tree.nodes, linkingnode, age_name)
else: else:
linkingnode = self._create_standard_python_file_node(tree, "xLinkingBookGUIPopup.py")
self._create_moul_nodes(bo, tree.nodes, linkingnode, age_name) self._create_moul_nodes(bo, tree.nodes, linkingnode, age_name)
def _create_pots_nodes(self, clickable_object, nodes, linkingnode, age_name): def _create_pots_nodes(self, clickable_object, nodes, linkingnode, age_name):
@ -667,14 +602,6 @@ class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
raise ExportError("{}: Linking Book modifier requires a seek point!", self.id_data.name) raise ExportError("{}: Linking Book modifier requires a seek point!", self.id_data.name)
dialog_toggle = {
"filename": "xDialogToggle.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", 'name': "Activate" },
{ 'id': 4, 'type': "ptAttribString", 'name': "Vignette" },
)
}
class PlasmaNotePopupModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz): class PlasmaNotePopupModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz):
pl_id = "note_popup" pl_id = "note_popup"
@ -755,11 +682,7 @@ class PlasmaNotePopupModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz):
nodes = tree.nodes nodes = tree.nodes
# xDialogToggle.py PythonFile Node # xDialogToggle.py PythonFile Node
dialog_node = self._create_python_file_node( dialog_node = self._create_standard_python_file_node(tree, "xDialogToggle.py")
tree,
dialog_toggle["filename"],
dialog_toggle["attribs"]
)
self._create_python_attribute(dialog_node, "Vignette", value=self.gui_page) self._create_python_attribute(dialog_node, "Vignette", value=self.gui_page)
# Clickable # Clickable

108
korman/properties/modifiers/logic.py

@ -15,10 +15,8 @@
from __future__ import annotations from __future__ import annotations
import bmesh
import bpy import bpy
from bpy.props import * from bpy.props import *
import mathutils
from PyHSPlasma import * from PyHSPlasma import *
from typing import * from typing import *
@ -28,21 +26,17 @@ if TYPE_CHECKING:
from ...nodes.node_messages import * from ...nodes.node_messages import *
from ...nodes.node_responder import * from ...nodes.node_responder import *
from typing import *
if TYPE_CHECKING:
from ...exporter import Exporter
from ...addon_prefs import game_versions from ...addon_prefs import game_versions
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
from ... import enum_props from ... import enum_props
from ...exporter import ExportError, utils from ...exporter import ExportError, utils
from ... import idprops from ... import idprops
entry_cam_pfm = {
"filename": "xEntryCam.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", 'name': "actRegionSensor" },
{ 'id': 2, 'type': "ptAttribSceneobject", 'name': "camera" },
{ 'id': 3, 'type': "ptAttribBoolean", 'name': "undoFirstPerson" },
)
}
class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup): class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup):
version = EnumProperty(name="Version", version = EnumProperty(name="Version",
description="Plasma versions this node tree exports under", description="Plasma versions this node tree exports under",
@ -137,11 +131,7 @@ class PlasmaSpawnPoint(PlasmaModifierProperties, PlasmaModifierLogicWiz):
yield self.convert_logic(bo) yield self.convert_logic(bo)
def logicwiz(self, bo, tree): def logicwiz(self, bo, tree):
pfm_node = self._create_python_file_node( pfm_node = self._create_standard_python_file_node(tree, "xEntryCam.py")
tree,
entry_cam_pfm["filename"],
entry_cam_pfm["attribs"]
)
volume_sensor: PlasmaVolumeSensorNode = tree.nodes.new("PlasmaVolumeSensorNode") volume_sensor: PlasmaVolumeSensorNode = tree.nodes.new("PlasmaVolumeSensorNode")
volume_sensor.find_input_socket("enter").allow = True volume_sensor.find_input_socket("enter").allow = True
@ -193,15 +183,83 @@ class PlasmaMaintainersMarker(PlasmaModifierProperties):
return True return True
telescope_pfm = { class PlasmaSDLIntState(bpy.types.PropertyGroup):
"filename": "xTelescope.py", value: int = IntProperty(
"attribs": ( name="State Value",
{ 'id': 1, 'type': "ptAttribActivator", 'name': "Activate" }, description="The object is shown when the SDL variable is set to this value",
{ 'id': 2, 'type': "ptAttribSceneobject", 'name': "Camera" }, min=0,
{ 'id': 3, 'type': "ptAttribBehavior", 'name': "Behavior" }, soft_max=255,
{ 'id': 4, 'type': "ptAttribString", 'name': "Vignette" }, options=set()
)
class PlasmaSDLShowHide(PlasmaModifierProperties, PlasmaModifierLogicWiz):
pl_id = "sdl_showhide"
bl_category = "Logic"
bl_label = "SDL Show/Hide"
bl_description = "Show/Hide an object based on an SDL Variable"
bl_object_types = {"MESH", "FONT"}
bl_icon = "VISIBLE_IPO_OFF"
sdl_variable: str = StringProperty(
name="SDL Variable",
description="Name of the SDL variable that controls visibility",
options=set()
) )
} variable_type: str = EnumProperty(
name="Type",
description="Data type of the SDL variable",
items=[
("bool", "Boolean", "A boolean, used to represent simple on/off for a single state"),
("int", "Integer", "An integer, used to represent multiple state combinations"),
],
options=set()
)
int_states = CollectionProperty(type=PlasmaSDLIntState)
bool_state: bool = BoolProperty(
name="Show When True",
description="If checked, show this object when the SDL Variable is TRUE. If not, hide it when TRUE.",
default=True,
options=set()
)
def created(self):
# Ensure at least one SDL int state is precreated for ease of use.
# REMEMBER: Blender's "sequences" don't do truthiness correctly...
if len(self.int_states) == 0:
self.int_states.add()
def sanity_check(self, exporter: Exporter):
if not exporter.age_sdl:
raise ExportError(f"'{self.id_data.name}': Age Global SDL is required for the SDL Show/Hide modifier!")
if not self.sdl_variable.strip():
raise ExportError(f"'{self.id_data.name}': A valid SDL variable is required for the SDL Show/Hide modifier!")
def logicwiz(self, bo, tree):
if self.variable_type == "bool":
pfm_node = self._create_standard_python_file_node(tree, "xAgeSDLBoolShowHide.py")
self._create_python_attribute(pfm_node, "sdlName", value=self.sdl_variable)
self._create_python_attribute(pfm_node, "showOnTrue", value=self.bool_state)
elif self.variable_type == "int":
pfm_node = self._create_standard_python_file_node(tree, "xAgeSDLIntShowHide.py")
self._create_python_attribute(pfm_node, "stringVarName", value=self.sdl_variable)
self._create_python_attribute(pfm_node, "stringShowStates", value=",".join(self._states))
else:
raise RuntimeError()
@property
def key_name(self):
if self.variable_type == "bool":
return f"cPythBoolShowHide_{self.sdl_variable}_{self.bool_state:d}"
elif self.variable_type == "int":
return f"cPythIntShowHide_{self.sdl_variable}_{'-'.join(self._states)}"
@property
def _states(self) -> Iterable[str]:
"""Returns a sorted, deduplicated iterable of the integer (converted to strings) states we should be visible in."""
return (str(i) for i in sorted(frozenset((i.value for i in self.int_states))))
class PlasmaTelescope(PlasmaModifierProperties, PlasmaModifierLogicWiz): class PlasmaTelescope(PlasmaModifierProperties, PlasmaModifierLogicWiz):
@ -244,7 +302,7 @@ class PlasmaTelescope(PlasmaModifierProperties, PlasmaModifierLogicWiz):
nodes = tree.nodes nodes = tree.nodes
# Create Python Node # Create Python Node
telescopepynode = self._create_python_file_node(tree, telescope_pfm["filename"], telescope_pfm["attribs"]) telescopepynode = self._create_standard_python_file_node(tree, "xTelescope.py")
# Clickable # Clickable
telescopeclick = nodes.new("PlasmaClickableNode") telescopeclick = nodes.new("PlasmaClickableNode")

26
korman/properties/modifiers/render.py

@ -624,30 +624,6 @@ class PlasmaLightingMod(PlasmaModifierProperties):
return False return False
_LOCALIZED_TEXT_PFM = (
{ 'id': 1, 'type': "ptAttribDynamicMap", 'name': "dynTextMap", },
{ 'id': 2, 'type': "ptAttribString", 'name': "locPath" },
{ 'id': 3, 'type': "ptAttribString", 'name': "fontFace" },
{ 'id': 4, 'type': "ptAttribInt", 'name': "fontSize" },
{ 'id': 5, 'type': "ptAttribFloat", 'name': "fontColorR" },
{ 'id': 6, 'type': "ptAttribFloat", 'name': "fontColorG" },
{ 'id': 7, 'type': "ptAttribFloat", 'name': "fontColorB" },
{ 'id': 8, 'type': "ptAttribFloat", 'name': "fontColorA" },
{ 'id': 9, 'type': "ptAttribInt", 'name': "marginTop" },
{ 'id': 10, 'type': "ptAttribInt", 'name': "marginLeft" },
{ 'id': 11, 'type': "ptAttribInt", 'name': "marginBottom" },
{ 'id': 12, 'type': "ptAttribInt", 'name': "marginRight" },
{ 'id': 13, 'type': "ptAttribInt", 'name': "lineSpacing" },
# Yes, it's really a ptAttribDropDownList, but those are only for use in
# artist generated node trees.
{ 'id': 14, 'type': "ptAttribString", 'name': "justify" },
{ 'id': 15, 'type': "ptAttribFloat", 'name': "clearColorR" },
{ 'id': 16, 'type': "ptAttribFloat", 'name': "clearColorG" },
{ 'id': 17, 'type': "ptAttribFloat", 'name': "clearColorB" },
{ 'id': 18, 'type': "ptAttribFloat", 'name': "clearColorA" },
{ 'id': 19, 'type': "ptAttribBoolean", 'name': "blockRGB" },
)
class PlasmaLocalizedTextModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz, TranslationMixin): class PlasmaLocalizedTextModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz, TranslationMixin):
pl_id = "dynatext" pl_id = "dynatext"
pl_page_types = {"gui", "room"} pl_page_types = {"gui", "room"}
@ -738,7 +714,7 @@ class PlasmaLocalizedTextModifier(PlasmaModifierProperties, PlasmaModifierLogicW
self._create_nodes(bo, tree, age_name=age_name, version=version) self._create_nodes(bo, tree, age_name=age_name, version=version)
def _create_nodes(self, bo, tree, *, age_name, version, material=None, clear_color=None): def _create_nodes(self, bo, tree, *, age_name, version, material=None, clear_color=None):
pfm_node = self._create_python_file_node(tree, "xDynTextLoc.py", _LOCALIZED_TEXT_PFM) pfm_node = self._create_standard_python_file_node(tree, "xDynTextLoc.py")
loc_path = self.key_name if version <= pvPots else "{}.{}.{}".format(age_name, self.localization_set, self.key_name) loc_path = self.key_name if version <= pvPots else "{}.{}.{}".format(age_name, self.localization_set, self.key_name)
self._create_python_attribute(pfm_node, "dynTextMap", "ptAttribDynamicMap", self._create_python_attribute(pfm_node, "dynTextMap", "ptAttribDynamicMap",

37
korman/ui/modifiers/logic.py

@ -60,6 +60,43 @@ def maintainersmarker(modifier, layout, context):
layout.label(text="Positive Y is North, positive Z is up.") layout.label(text="Positive Y is North, positive Z is up.")
layout.prop(modifier, "calibration") layout.prop(modifier, "calibration")
def sdl_showhide(modifier: PlasmaSDLShowHide, layout, context):
if not context.scene.world.plasma_age.age_sdl:
layout.label("This modifier requires Age Global SDL!", icon="ERROR")
return
valid_variable = modifier.sdl_variable.strip()
layout.alert = not valid_variable
layout.prop(modifier, "sdl_variable")
if not valid_variable:
layout.label("A valid SDL variable is required!", icon="ERROR")
layout.alert = False
layout.prop(modifier, "variable_type")
layout.separator()
def setup_collection_operator(op):
op.context = "object"
op.group_path = modifier.path_from_id()
op.collection_prop = "int_states"
op.index_prop = ""
if modifier.variable_type == "bool":
layout.prop(modifier, "bool_state")
elif modifier.variable_type == "int":
layout.label("Show when SDL variable is:")
sub = layout.column_flow()
for i, state in enumerate(modifier.int_states):
row = sub.row(align=True)
row.prop(state, "value", text="Value")
op = row.operator("ui.plasma_collection_remove", icon="ZOOMOUT", text="")
setup_collection_operator(op)
op.manual_index = i
op = layout.operator("ui.plasma_collection_add", icon="ZOOMIN", text="Add State Value")
setup_collection_operator(op)
else:
raise RuntimeError()
def telescope(modifier, layout, context): def telescope(modifier, layout, context):
layout.prop(modifier, "clickable_region") layout.prop(modifier, "clickable_region")
layout.prop(modifier, "seek_target_object", icon="EMPTY_DATA") layout.prop(modifier, "seek_target_object", icon="EMPTY_DATA")

Loading…
Cancel
Save