open_toontown_panda3d/direct/src/leveleditor/LevelEditor.py

5533 lines
224 KiB
Python

from pandac.PandaModules import *
from direct.directbase.DirectStart import *
from direct.showbase.DirectObject import DirectObject
from PieMenu import *
import direct.gui.DirectGuiGlobals as DGG
from direct.showbase.TkGlobal import *
from direct.directtools.DirectUtil import *
from direct.directtools.DirectGeometry import *
from direct.tkwidgets.SceneGraphExplorer import *
from direct.directnotify import DirectNotifyGlobal
from tkMessageBox import showinfo
from tkFileDialog import *
from Tkinter import *
#from whrandom import *
from random import *
from direct.tkwidgets import Floater
from direct.tkwidgets import VectorWidgets
import string
import os
import getopt
import sys
#import whrandom
import random
import types
from direct.task import Task
import Pmw
import __builtin__
# [gjeon] to control avatar movement in drive mode
from direct.controls import ControlManager
from direct.controls import GravityWalker
from direct.controls import NonPhysicsWalker
from direct.interval.LerpInterval import LerpFunctionInterval
from otp.avatar import LocalAvatar
from toontown.toon import RobotToon
from otp.otpbase import OTPGlobals
from LevelStyleManager import *
# Force direct and tk to be on
base.startDirect(fWantDirect = 1, fWantTk = 1)
visualizeZones = base.config.GetBool("visualize-zones", 0)
dnaDirectory = Filename.expandFrom(base.config.GetString("dna-directory", "$TTMODELS/src/dna"))
fUseCVS = base.config.GetBool("level-editor-use-cvs", 1)
useSnowTree = base.config.GetBool("use-snow-tree", 0)
# Colors used by all color menus
DEFAULT_COLORS = [
Vec4(1, 1, 1, 1),
Vec4(0.75, 0.75, 0.75, 1.0),
Vec4(0.5, 0.5, 0.5, 1.0),
Vec4(0.25, 0.25, 0.25, 1.0)
]
# The list of items with color attributes
COLOR_TYPES = ['wall_color', 'window_color',
'window_awning_color', 'sign_color', 'door_color',
'door_awning_color', 'cornice_color',
'prop_color']
# The list of dna components maintained in the style attribute dictionary
DNA_TYPES = ['wall', 'window', 'sign', 'door_double', 'door_single', 'cornice', 'toon_landmark',
'prop', 'street']
BUILDING_TYPES = ['10_10', '20', '10_20', '20_10', '10_10_10',
'4_21', '3_22', '4_13_8', '3_13_9', '10',
'12_8', '13_9_8', '4_10_10', '4_10', '4_20',
]
BUILDING_HEIGHTS = [10, 14, 20, 24, 25, 30]
NUM_WALLS = [1, 2, 3]
LANDMARK_SPECIAL_TYPES = ['', 'hq', 'gagshop', 'clotheshop', 'petshop', 'kartshop']
OBJECT_SNAP_POINTS = {
'street_5x20': [(Vec3(5.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_10x20': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x20': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_30x20': [(Vec3(30.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x20': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_80x20': [(Vec3(80.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_5x40': [(Vec3(5.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_10x40': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x40': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x40_15': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_30x40': [(Vec3(30.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x60': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x60': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x40_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_80x40': [(Vec3(80.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_angle_30': [(Vec3(0), Vec3(-30, 0, 0)),
(Vec3(0), Vec3(0))],
'street_angle_45': [(Vec3(0), Vec3(-45, 0, 0)),
(Vec3(0), Vec3(0))],
'street_angle_60': [(Vec3(0), Vec3(-60, 0, 0)),
(Vec3(0), Vec3(0))],
'street_inner_corner': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_outer_corner': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_full_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_tight_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_tight_corner_mirror': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_double_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_curved_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_curved_corner_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_t_intersection': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_y_intersection': [(Vec3(30.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_street_20x20': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_street_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_sidewalk_20x20': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_sidewalk_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_transition': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_40x70': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_transition_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_40x70_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_stairs_40x10x5': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_4way_intersection': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_incline_40x40x5': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_square_courtyard': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70_15': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70_15_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90_15': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90_15_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_50_transition': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x50': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x50': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_keyboard_10x40': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_keyboard_20x40': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_keyboard_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_sunken_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
}
# NEIGHBORHOOD DATA
# If you run this from the command line you can pass in the hood codes
# you want to load. For example:
# ppython LevelEditor.py DD TT BR
#
if sys.argv[1:]:
try:
opts, pargs = getopt.getopt(sys.argv[1:], '')
hoods = pargs
except Exception, e:
print e
# If you do not run from the command line, we just load all of them
# or you can hack this up for your own purposes.
else:
hoodString = base.config.GetString('level-editor-hoods',
'TT DD BR DG DL MM CC CL CM CS GS GZ OZ PA')
hoods = string.split(hoodString)
# The list of neighborhoods to edit
hoodIds = {'TT': 'toontown_central',
'DD': 'donalds_dock',
'MM': 'minnies_melody_land',
'BR': 'the_burrrgh',
'DG': 'daisys_garden',
'DL': 'donalds_dreamland',
'CC': 'cog_hq_bossbot',
'CL': 'cog_hq_lawbot',
'CM': 'cog_hq_cashbot',
'CS': 'cog_hq_sellbot',
'GS': 'goofy_speedway',
'OZ': 'outdoor_zone',
'GZ': 'golf_zone',
'PA': 'party_zone',
}
# Init neighborhood arrays
NEIGHBORHOODS = []
NEIGHBORHOOD_CODES = {}
for hoodId in hoods:
if hoodIds.has_key(hoodId):
hoodName = hoodIds[hoodId]
NEIGHBORHOOD_CODES[hoodName] = hoodId
NEIGHBORHOODS.append(hoodName)
else:
print 'Error: no hood defined for: ', hoodId
# Load DNA
try:
if dnaLoaded:
pass
except NameError:
print "Loading LevelEditor for hoods: ", hoods
# DNAStorage instance for storing level DNA info
# We need to use the __builtin__.foo syntax, not the
# __builtins__["foo"] syntax, since this file runs at the top
# level.
__builtin__.DNASTORE = DNASTORE = DNAStorage()
# Load the generic storage files
loadDNAFile(DNASTORE, 'dna/storage.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_4/dna/storage.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_5/dna/storage_town.dna', CSDefault, 1)
# loadDNAFile(DNASTORE, 'phase_5.5/dna/storage_estate.dna', CSDefault, 1)
# loadDNAFile(DNASTORE, 'phase_5.5/dna/storage_house_interior.dna', CSDefault, 1)
# Load all the neighborhood specific storage files
if 'TT' in hoods:
loadDNAFile(DNASTORE, 'phase_4/dna/storage_TT.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_4/dna/storage_TT_sz.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_5/dna/storage_TT_town.dna', CSDefault, 1)
if 'DD' in hoods:
loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD_sz.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD_town.dna', CSDefault, 1)
if 'MM' in hoods:
loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM_sz.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM_town.dna', CSDefault, 1)
if 'BR' in hoods:
loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR_sz.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR_town.dna', CSDefault, 1)
if 'DG' in hoods:
loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG_sz.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG_town.dna', CSDefault, 1)
if 'DL' in hoods:
loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL_sz.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL_town.dna', CSDefault, 1)
if 'CS' in hoods:
loadDNAFile(DNASTORE, 'phase_9/dna/storage_CS.dna', CSDefault, 1)
if 'GS' in hoods:
loadDNAFile(DNASTORE, 'phase_4/dna/storage_GS.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_4/dna/storage_GS_sz.dna', CSDefault, 1)
if 'OZ' in hoods:
loadDNAFile(DNASTORE, 'phase_6/dna/storage_OZ.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_6/dna/storage_OZ_sz.dna', CSDefault, 1)
if 'GZ' in hoods:
loadDNAFile(DNASTORE, 'phase_6/dna/storage_GZ.dna', CSDefault, 1)
loadDNAFile(DNASTORE, 'phase_6/dna/storage_GZ_sz.dna', CSDefault, 1)
if 'CC' in hoods:
loadDNAFile(DNASTORE, 'phase_12/dna/storage_CC_sz.dna', CSDefault, 1)
if 'PA' in hoods:
loadDNAFile(DNASTORE, 'phase_13/dna/storage_party_sz.dna', CSDefault, 1)
__builtin__.dnaLoaded = 1
class LevelEditor(NodePath, DirectObject):
"""Class used to create a Toontown LevelEditor object"""
notify = DirectNotifyGlobal.directNotify.newCategory('LevelEditor')
# Init the list of callbacks:
selectedNodePathHookHooks=[]
deselectedNodePathHookHooks=[]
# Primary variables:
# DNAData: DNA object holding DNA info about level
# DNAToplevel: Top level DNA Node, all DNA objects descend from this node
# NPToplevel: Corresponding Node Path
# DNAParent: Current DNA Node that new objects get added to
# NPParent: Corresponding Node Path
# DNAVisGroup: Current DNAVisGroup that new objects get added to
# NPVisGroup: Corresponding Node Path
# selectedDNARoot: DNA Node of currently selected object
# selectedNPRoot: Corresponding Node Path
# DNATarget: Subcomponent being modified by Pie Menu
def __init__(self, hoods = hoods):
# Make the level editor a node path so that you can show/hide
# The level editor separately from loading/saving the top level node
# Initialize superclass
NodePath.__init__(self)
# Become the new node path
self.assign(hidden.attachNewNode('LevelEditor'))
# Enable replaceSelected by default:
self.replaceSelectedEnabled=1
self.removeHookList=[self.landmarkBlockRemove]
# Start block ID at 0 (it will be incremented before use (to 1)):
self.landmarkBlock=0
# Create ancillary objects
# Style manager for keeping track of styles/colors
self.styleManager = LevelStyleManager(NEIGHBORHOODS, NEIGHBORHOOD_CODES)
# Load neighborhood maps
self.createLevelMaps()
# Marker for showing next insertion point
self.createInsertionMarker()
# Create level Editor Panel
self.panel = LevelEditorPanel(self)
# Used to store whatever edges and points are loaded in the level
self.edgeDict = {}
self.np2EdgeDict = {}
self.pointDict = {}
self.point2edgeDict = {}
self.cellDict = {}
self.visitedPoints = []
self.visitedEdges = []
self.zoneLabels = []
# Initialize LevelEditor variables DNAData, DNAToplevel, NPToplevel
# DNAParent, NPParent, groupNum, lastAngle
# Pass in the new toplevel group and don't clear out the old
# toplevel group (since it doesn't exist yet)
self.reset(fDeleteToplevel = 0, fCreateToplevel = 1)
# The list of events the level editor responds to
self.actionEvents = [
# Node path events
('preRemoveNodePath', self.removeNodePathHook),
# Actions in response to DIRECT operations
('DIRECT_selectedNodePath', self.selectedNodePathHook),
('DIRECT_deselectedNodePath', self.deselectedNodePathHook),
('DIRECT_manipulateObjectCleanup', self.updateSelectedPose),
('DIRECT_nodePathSetName', self.setName),
('DIRECT_activeParent', self.setActiveParent),
('DIRECT_reparent', self.reparent),
('RGBPanel_setColor', self.setColor),
# Actions in response to Level Editor Panel operations
('SGE_Add Group', self.addGroup),
('SGE_Add Vis Group', self.addVisGroup),
# Actions in response to Pie Menu interaction
('select_building_style_all', self.setBuildingStyle),
('select_building_type', self.setBuildingType),
('select_building_width', self.setBuildingWidth),
('select_cornice_color', self.setDNATargetColor),
('select_cornice_orientation', self.setDNATargetOrientation),
('select_cornice_texture', self.setDNATargetCode, ['cornice']),
('select_sign_color', self.setDNATargetColor),
('select_sign_orientation', self.setDNATargetOrientation),
('select_sign_texture', self.setDNATargetCode, ['sign']),
('select_baseline_style', self.panel.setSignBaselineStyle),
('select_door_color', self.setDNATargetColor),
('select_door_orientation', self.setDNATargetOrientation),
('select_door_single_texture', self.setDNATargetCode, ['door']),
('select_door_double_texture', self.setDNATargetCode, ['door']),
('select_door_awning_texture', self.setDNATargetCode,
['door_awning']),
('select_door_awning_color', self.setDNATargetColor),
('select_window_color', self.setDNATargetColor),
('select_window_count', self.setWindowCount),
('select_window_orientation', self.setDNATargetOrientation),
('select_window_texture', self.setDNATargetCode, ['windows']),
('select_window_awning_texture', self.setDNATargetCode,
['window_awning']),
('select_window_awning_color', self.setDNATargetColor),
('select_wall_style', self.setWallStyle),
('select_wall_color', self.setDNATargetColor),
('select_wall_orientation', self.setDNATargetOrientation),
('select_wall_texture', self.setDNATargetCode, ['wall']),
('select_toon_landmark_texture', self.setDNATargetCode,
['landmark']),
('select_toon_landmark_door_color', self.setDNATargetColor),
('select_toon_landmark_door_orientation',
self.setDNATargetOrientation),
('select_landmark_door_texture', self.setDNATargetCode,
['landmark_door']),
('select_street_texture', self.setDNATargetCode, ['street']),
('select_prop_texture', self.setDNATargetCode, ['prop']),
('select_prop_color', self.setDNATargetColor),
# Hot key actions
('a', self.autoPositionGrid),
('j', self.jumpToInsertionPoint),
('arrow_left', self.keyboardXformSelected, ['left', 'xlate']),
('arrow_right', self.keyboardXformSelected, ['right', 'xlate']),
('arrow_up', self.keyboardXformSelected, ['up','xlate']),
('arrow_down', self.keyboardXformSelected, ['down','xlate']),
('control-arrow_left', self.keyboardXformSelected, ['left', 'rotate']),
('control-arrow_right', self.keyboardXformSelected, ['right', 'rotate']),
('control-arrow_up', self.keyboardXformSelected, ['up', 'rotate']),
('control-arrow_down', self.keyboardXformSelected, ['down', 'rotate']),
('shift-s', self.placeSuitPoint),
('shift-c', self.placeBattleCell),
('k', self.addToLandmarkBlock),
('shift-k', self.toggleShowLandmarkBlock),
('%', self.pdbBreak),
('page_up', self.pageUp),
('page_down', self.pageDown),
]
self.overrideEvents = [
('page_up', base.direct),
('page_down', base.direct)
]
# Initialize state
# Make sure direct is running
base.direct.enable()
# And only the appropriate handles are showing
base.direct.widget.disableHandles(['x-ring', 'x-disc',
'y-ring', 'y-disc',
'z-post'])
# Initialize camera
base.camLens.setNear(1.0)
base.camLens.setFar(3000)
base.direct.camera.setPos(0, -10, 10)
# Initialize drive mode
self.configureDriveModeCollisionData()
# Init visibility variables
self.__zoneId = None
# Hide (disable) grid initially
self.showGrid(0)
# Create variable for vis groups panel
self.vgpanel = None
# Start off enabled
self.enable()
# SUIT POINTS
# Create a sphere model to show suit points
self.suitPointMarker = loader.loadModel('models/misc/sphere')
self.suitPointMarker.setScale(0.25)
# Initialize the suit points
self.startSuitPoint = None
self.endSuitPoint = None
self.currentSuitPointType = DNASuitPoint.STREETPOINT
# BATTLE CELLS
self.battleCellMarker = loader.loadModel('models/misc/sphere')
self.battleCellMarker.setName('battleCellMarker')
self.battleCellMarker.setScale(1)
self.currentBattleCellType = "20w 20l"
# Update panel
# Editing the first hood id on the list
self.outputFile = None
self.setEditMode(NEIGHBORHOODS[0])
# Start of with first item in lists
self.panel.streetSelector.selectitem(0)
self.panel.streetSelector.invoke()
self.panel.toonBuildingSelector.selectitem(0)
self.panel.toonBuildingSelector.invoke()
self.panel.landmarkBuildingSelector.selectitem(0)
self.panel.landmarkBuildingSelector.invoke()
self.panel.propSelector.selectitem(0)
self.panel.propSelector.invoke()
# Start off with 20 foot buildings
self.panel.twentyFootButton.invoke()
# Update scene graph explorer
self.panel.sceneGraphExplorer.update()
# Karting
# the key is the barricade number, the data is a two element list,
# first number is the first bldg group that uses this
# the second is the last bldg group that uses this
self.outerBarricadeDict = {}
self.innerBarricadeDict = {}
# [gjeon] to find out currently moving camera in maya mode
self.mouseMayaCamera = True
# [gjeon] to find out drive mode stat
self.fDrive = False
# [gjeon] to control drive mode
self.controlManager = None
self.avatar = None
self.fov = 60
self.isPageUp=0
self.isPageDown=0
# ENABLE/DISABLE
def enable(self):
""" Enable level editing and show level """
# Make sure level is visible
self.reparentTo(base.direct.group)
self.show()
# [gjeon] Ignore overridden events
for event in self.overrideEvents:
event[1].ignore(event[0])
# Add all the action events
for event in self.actionEvents:
if len(event) == 3:
self.accept(event[0], event[1], event[2])
else:
self.accept(event[0], event[1])
# Enable mouse interaction (pie menus)
self.enableMouse()
# Spawn task to keep insertion marker aligned with grid
self.spawnInsertionMarkerTask()
def disable(self):
""" Disable level editing and hide level """
# Deselect everything as a precaution
base.direct.deselectAll()
# Hide the level
self.reparentTo(hidden)
# Ignore the hooks
for eventPair in self.actionEvents:
self.ignore(eventPair[0])
# These are added outside of actionEvents list
self.ignore('insert')
self.ignore('space')
# Disable Pie Menu mouse interaction
self.disableMouse()
# Remove insertion marker task
taskMgr.remove('insertionMarkerTask')
def reset(self, fDeleteToplevel = 1, fCreateToplevel = 1,
fUpdateExplorer = 1):
"""
Reset level and re-initialize main class variables
Pass in the new top level group
"""
# Reset path markers
self.resetPathMarkers()
# Reset battle cell markers
self.resetBattleCellMarkers()
if fDeleteToplevel:
# First destroy existing scene-graph/DNA hierarchy
self.deleteToplevel()
# Clear DNASTORE
DNASTORE.resetDNAGroups()
# Reset DNA VIS Groups
DNASTORE.resetDNAVisGroups()
DNASTORE.resetSuitPoints()
DNASTORE.resetBattleCells()
# Create fresh DNA DATA
self.DNAData = DNAData('level_data')
# Create new toplevel node path and DNA
if fCreateToplevel:
self.createToplevel(DNANode('level'))
# Initialize variables
# Reset grid
base.direct.grid.setPosHprScale(0, 0, 0, 0, 0, 0, 1, 1, 1)
# The selected DNA Object/NodePath
self.selectedDNARoot = None
self.selectedNPRoot = None
self.selectedSuitPoint = None
self.lastLandmarkBuildingDNA = None
self.showLandmarkBlockToggleGroup = None
# Set active target (the subcomponent being modified)
self.DNATarget = None
self.DNATargetParent = None
# Set count of groups added to level
self.setGroupNum(0)
# Heading angle of last object added to level
self.setLastAngle(0.0)
# Last wall and building modified using pie menus
self.lastSign = None
self.lastWall = None
self.lastBuilding = None
# Code of last selected object (for autopositionGrid)
self.snapList = []
# Last menu used
self.activeMenu = None
# For highlighting suit paths
self.visitedPoints = []
self.visitedEdges = []
# Update scene graph explorer
if fUpdateExplorer:
self.panel.sceneGraphExplorer.update()
self.outputFile = None
self.panel["title"] = 'Level Editor: No file loaded'
def deleteToplevel(self):
# Destory old toplevel node path and DNA
# First the toplevel DNA
self.DNAData.remove(self.DNAToplevel)
# Then the toplevel Node Path
self.NPToplevel.removeNode()
def createToplevel(self, dnaNode, nodePath = None):
# When you create a new level, data is added to this node
# When you load a DNA file, you replace this node with the new data
self.DNAToplevel = dnaNode
self.DNAData.add(self.DNAToplevel)
if nodePath:
# Node path given, use it
self.NPToplevel = nodePath
self.NPToplevel.reparentTo(self)
else:
# No node path given, traverse
self.NPToplevel = self.DNAToplevel.traverse(self, DNASTORE, 1)
# Update parent pointers
self.DNAParent = self.DNAToplevel
self.NPParent = self.NPToplevel
self.VGParent = None
# Add toplevel node path for suit points
self.suitPointToplevel = self.NPToplevel.attachNewNode('suitPoints')
def destroy(self):
""" Disable level editor and destroy node path """
self.disable()
self.removeNode()
self.panel.destroy()
if self.vgpanel:
self.vgpanel.destroy()
def useDirectFly(self):
""" Disable player camera controls/enable direct camera control """
# Turn off collision traversal
self.traversalOff()
# Turn on collisions
self.collisionsOff()
# Turn on visiblity
self.visibilityOff()
base.camera.wrtReparentTo(render)
# Reset cam
base.camera.iPos(base.cam)
base.cam.iPosHpr()
# Renable mouse
self.enableMouse()
base.direct.enable()
# [gjeon] disable avatar and controlManager
if (self.avatar):
self.avatar.reparentTo(hidden)
self.avatar.stopUpdateSmartCamera()
if (self.controlManager):
self.controlManager.disable()
self.fDrive = False
def lerpCameraP(self, p, time):
"""
lerp the camera P over time (used by the battle)
"""
taskMgr.remove('cam-p-lerp')
if self.avatar:
self.avatar.stopUpdateSmartCamera()
def setCamP(p):
base.camera.setP(p)
if self.isPageUp:
fromP = 36.8699
elif self.isPageDown:
fromP = -27.5607
else:
fromP = 0
self.camLerpInterval = LerpFunctionInterval(setCamP,
fromData=fromP, toData=p, duration=time,
name='cam-p-lerp')
self.camLerpInterval.start()
def clearPageUpDown(self):
if self.isPageDown or self.isPageUp:
self.lerpCameraP(0, 0.6)
self.isPageDown = 0
self.isPageUp = 0
#self.setCameraPositionByIndex(self.cameraIndex)
if self.avatar:
self.avatar.startUpdateSmartCamera()
def pageUp(self):
if not self.isPageUp:
self.lerpCameraP(36.8699, 0.6)
self.isPageDown = 0
self.isPageUp = 1
#self.setCameraPositionByIndex(self.cameraIndex)
else:
self.clearPageUpDown()
def pageDown(self):
if not self.isPageDown:
self.lerpCameraP(-27.5607, 0.6)
self.isPageUp = 0
self.isPageDown = 1
#self.setCameraPositionByIndex(self.cameraIndex)
else:
self.clearPageUpDown()
def useDriveMode(self):
""" Lerp down to eye level then switch to Drive mode """
# create avatar and set it's location to the camera
if (self.avatar == None):
#self.avatar = RobotToon.RobotToon()
self.avatar = LEAvatar(None, None, None)
base.localAvatar = self.avatar
self.avatar.doId = 0
self.avatar.robot = RobotToon.RobotToon()
self.avatar.robot.reparentTo(self.avatar)
self.avatar.setHeight(self.avatar.robot.getHeight())
self.avatar.setName("The Inspector")
self.avatar.robot.loop('neutral')
self.avatar.setPos(base.camera.getPos())
self.avatar.reparentTo(render)
## pos = base.direct.camera.getPos()
## pos.setZ(4.0)
## hpr = base.direct.camera.getHpr()
## hpr.set(hpr[0], 0.0, 0.0)
## t = base.direct.camera.lerpPosHpr(pos, hpr, 1.0, blendType = 'easeInOut',
## task = 'manipulateCamera')
# Note, if this dies an unatural death, this could screw things up
# t.uponDeath = self.switchToDriveMode
self.switchToDriveMode(None)
self.fDrive = True
#[gjeon] deselect
base.direct.selected.deselect(base.direct.selected.last)
def switchToDriveMode(self, state):
""" Disable direct camera manipulation and enable player drive mode """
#base.direct.minimumConfiguration()
#base.direct.manipulationControl.disableManipulation()
# Update vis data
self.initVisibilityData()
## # Switch to drive mode
## base.useDrive()
## # Move cam up and back
## base.cam.setPos(0, -5, 4)
## # And move down and forward to compensate
## base.camera.setPos(base.camera, 0, 5, -4)
## # Make sure we're where we want to be
## pos = base.direct.camera.getPos()
## pos.setZ(0.0)
## hpr = base.direct.camera.getHpr()
## hpr.set(hpr[0], 0.0, 0.0)
## # Fine tune the drive mode
## base.mouseInterface.node().setPos(pos)
## base.mouseInterface.node().setHpr(hpr)
## base.mouseInterface.node().setForwardSpeed(0)
## base.mouseInterface.node().setReverseSpeed(0)
base.camera.wrtReparentTo(self.avatar)
base.camera.setHpr(0, 0, 0)
#base.camera.setPos(0, 0, 0)
base.camera.setPos(0, -11.8125, 3.9375)
base.camLens.setFov(VBase2(60, 46.8265))
#self.initializeSmartCameraCollisions()
#self._smartCamEnabled = False
# Turn on collisions
if self.panel.fColl.get():
self.collisionsOn()
# Turn on visiblity
if self.panel.fVis.get():
self.visibilityOn()
# Turn on collision traversal
if self.panel.fColl.get() or self.panel.fVis.get():
self.traversalOn()
if (self.controlManager == None):
# create player movement controls,camera controls, and avatar
self.controlManager = ControlManager.ControlManager()
avatarRadius = 1.4
floorOffset = OTPGlobals.FloorOffset
reach = 4.0
#walkControls=GravityWalker.GravityWalker(gravity = -32.1740 * 2.0)
walkControls=NonPhysicsWalker.NonPhysicsWalker()
walkControls.setWallBitMask(OTPGlobals.WallBitmask)
walkControls.setFloorBitMask(OTPGlobals.FloorBitmask)
walkControls.initializeCollisions(self.cTrav, self.avatar,
avatarRadius, floorOffset, reach)
self.controlManager.add(walkControls, "walk")
self.controlManager.use("walk", self)
# set speeds after adding controls to the control manager
self.controlManager.setSpeeds(
OTPGlobals.ToonForwardSpeed,
OTPGlobals.ToonJumpForce,
OTPGlobals.ToonReverseSpeed,
OTPGlobals.ToonRotateSpeed
)
else:
self.controlManager.enable()
self.avatarAnimTask = taskMgr.add(self.avatarAnimate, 'avatarAnimTask', 24)
self.avatar.startUpdateSmartCamera()
self.avatarMoving = 0
#--------------------------------------------------------------------------
# Function: animate avatar model based on if it is moving
# Parameters: none
# Changes:
# Returns:
#--------------------------------------------------------------------------
def avatarAnimate(self,task=None):
if (self.controlManager):
moving = self.controlManager.currentControls.speed or self.controlManager.currentControls.slideSpeed or self.controlManager.currentControls.rotationSpeed
if (moving and
self.avatarMoving == 0):
self.clearPageUpDown()
# moving, play walk anim
if (self.controlManager.currentControls.speed < 0 or
self.controlManager.currentControls.rotationSpeed):
self.avatar.robot.loop('walk')
else:
self.avatar.robot.loop('run')
self.avatarMoving = 1
elif (moving == 0 and
self.avatarMoving == 1):
# no longer moving, play neutral anim
self.avatar.robot.loop('neutral')
self.avatarMoving = 0
return Task.cont
def configureDriveModeCollisionData(self):
"""
Set up the local avatar for collisions
"""
# Set up the collision sphere
# This is a sphere on the ground to detect barrier collisions
self.cSphere = CollisionSphere(0.0, 0.0, 0.0, 1.5)
self.cSphereNode = CollisionNode('cSphereNode')
self.cSphereNode.addSolid(self.cSphere)
self.cSphereNodePath = camera.attachNewNode(self.cSphereNode)
self.cSphereNodePath.hide()
self.cSphereBitMask = BitMask32.bit(0)
self.cSphereNode.setFromCollideMask(self.cSphereBitMask)
self.cSphereNode.setIntoCollideMask(BitMask32.allOff())
# Set up the collison ray
# This is a ray cast from your head down to detect floor polygons
self.cRay = CollisionRay(0.0, 0.0, 6.0, 0.0, 0.0, -1.0)
self.cRayNode = CollisionNode('cRayNode')
self.cRayNode.addSolid(self.cRay)
self.cRayNodePath = camera.attachNewNode(self.cRayNode)
self.cRayNodePath.hide()
self.cRayBitMask = BitMask32.bit(1)
self.cRayNode.setFromCollideMask(self.cRayBitMask)
self.cRayNode.setIntoCollideMask(BitMask32.allOff())
# set up wall collision mechanism
self.pusher = CollisionHandlerPusher()
self.pusher.setInPattern("enter%in")
self.pusher.setOutPattern("exit%in")
# set up floor collision mechanism
self.lifter = CollisionHandlerFloor()
self.lifter.setInPattern("on-floor")
self.lifter.setOutPattern("off-floor")
self.floorOffset = 0.1
self.lifter.setOffset(self.floorOffset)
# Limit our rate-of-fall with the lifter.
# If this is too low, we actually "fall" off steep stairs
# and float above them as we go down. I increased this
# from 8.0 to 16.0 to prevent this
self.lifter.setMaxVelocity(16.0)
# set up the collision traverser
self.cTrav = CollisionTraverser("LevelEditor")
self.cTrav.setRespectPrevTransform(1)
# activate the collider with the traverser and pusher
#self.pusher.addCollider(self.cSphereNodePath, base.camera, base.drive.node())
#self.lifter.addCollider(self.cRayNodePath, base.camera, base.drive.node())
# A map of zone ID's to a list of nodes that are visible from
# that zone.
self.nodeDict = {}
# A map of zone ID's to the particular node that corresponds
# to that zone.
self.zoneDict = {}
# A list of all visible nodes
self.nodeList = []
# Flag for bootstrapping visibility
self.fVisInit = 0
def traversalOn(self):
base.cTrav = self.cTrav
def traversalOff(self):
base.cTrav = 0
def collisionsOff(self):
self.cTrav.removeCollider(self.cSphereNodePath)
def collisionsOn(self):
self.collisionsOff()
self.cTrav.addCollider(self.cSphereNodePath, self.pusher)
def toggleCollisions(self):
if self.panel.fColl.get():
self.collisionsOn()
self.traversalOn()
else:
self.collisionsOff()
if (not (self.panel.fColl.get() or self.panel.fVis.get())):
self.traversalOff()
def initVisibilityData(self):
# First make sure everything is shown
self.showAllVisibles()
# A map of zone ID's to a list of nodes that are visible from
# that zone.
self.nodeDict = {}
# A map of zone ID's to the particular node that corresponds
# to that zone.
self.zoneDict = {}
# A list of all visible nodes
self.nodeList = []
# NOTE: this should change to find the groupnodes in
# the dna storage instead of searching through the tree
for i in range(DNASTORE.getNumDNAVisGroups()):
groupFullName = DNASTORE.getDNAVisGroupName(i)
groupName = self.extractGroupName(groupFullName)
zoneId = int(groupName)
self.nodeDict[zoneId] = []
self.zoneDict[zoneId] = self.NPToplevel.find("**/" + groupName)
# TODO: we only need to look from the top of the hood
# down one level to find the vis groups as an optimization
groupNode = self.NPToplevel.find("**/" + groupFullName)
if groupNode.isEmpty():
print "Could not find visgroup"
self.nodeList.append(groupNode)
for j in range(DNASTORE.getNumVisiblesInDNAVisGroup(i)):
visName = DNASTORE.getVisibleName(i, j)
visNode = self.NPToplevel.find("**/" + visName)
self.nodeDict[zoneId].append(visNode)
# Rename the floor polys to have the same name as the
# visgroup they are in... This makes visibility possible.
self.renameFloorPolys(self.nodeList)
# Init vis flag
self.fVisInit = 1
def extractGroupName(self, groupFullName):
# The Idea here is that group names may have extra flags associated
# with them that tell more information about what is special about
# the particular vis zone. A normal vis zone might just be "13001",
# but a special one might be "14356:safe_zone" or
# "345:safe_zone:exit_zone"... These are hypotheticals. The main
# idea is that there are colon separated flags after the initial
# zone name.
return(string.split(groupFullName, ":", 1)[0])
def renameFloorPolys(self, nodeList):
for i in nodeList:
# Get all the collision nodes in the vis group
collNodePaths = i.findAllMatches("**/+CollisionNode")
numCollNodePaths = collNodePaths.getNumPaths()
visGroupName = i.node().getName()
for j in range(numCollNodePaths):
collNodePath = collNodePaths.getPath(j)
bitMask = collNodePath.node().getIntoCollideMask()
if bitMask.getBit(1):
# Bit 1 is the floor collision bit. This renames
# all floor collision polys to the same name as their
# visgroup.
collNodePath.node().setName(visGroupName)
def hideAllVisibles(self):
for i in self.nodeList:
i.hide()
def showAllVisibles(self):
for i in self.nodeList:
i.show()
i.clearColor()
def visibilityOn(self):
self.visibilityOff()
# Accept event
self.accept("on-floor", self.enterZone)
# Add collider
self.cTrav.addCollider(self.cRayNodePath, self.lifter)
# Reset lifter
self.lifter.clear()
# Reset flag
self.fVisInit = 1
def visibilityOff(self):
self.ignore("on-floor")
self.cTrav.removeCollider(self.cRayNodePath)
self.showAllVisibles()
def toggleVisibility(self):
if self.panel.fVis.get():
self.visibilityOn()
self.traversalOn()
else:
self.visibilityOff()
if (not (self.panel.fColl.get() or self.panel.fVis.get())):
self.traversalOff()
def enterZone(self, newZone):
return
"""
Puts the toon in the indicated zone. newZone may either be a
CollisionEntry object as determined by a floor polygon, or an
integer zone id. It may also be None, to indicate no zone.
"""
# First entry into a zone, hide everything
if self.fVisInit:
self.hideAllVisibles()
self.fVisInit = 0
# Get zone id
if isinstance(newZone, CollisionEntry):
# Get the name of the collide node
try:
newZoneId = int(newZone.getIntoNode().getName())
except:
newZoneId = 0
else:
newZoneId = newZone
# Ensure we have vis data
assert self.nodeDict
# Hide the old zone (if there is one)
if self.__zoneId != None:
for i in self.nodeDict[self.__zoneId]:
i.hide()
# Show the new zone
if newZoneId != None:
for i in self.nodeDict[newZoneId]:
i.show()
# Make sure we changed zones
if newZoneId != self.__zoneId:
if self.panel.fVisZones.get():
# Set a color override on our zone to make it obvious what
# zone we're in.
if self.__zoneId != None:
self.zoneDict[self.__zoneId].clearColor()
if newZoneId != None:
self.zoneDict[newZoneId].setColor(0, 0, 1, 1, 100)
# The new zone is now old
self.__zoneId = newZoneId
def enableMouse(self):
""" Enable Pie Menu interaction (and disable player camera control) """
# Turn off player camera control
base.disableMouse()
# Handle mouse events for pie menus
self.accept('DIRECT-mouse3', self.levelHandleMouse3)
self.accept('DIRECT-mouse3Up', self.levelHandleMouse3Up)
def disableMouse(self):
""" Disable Pie Menu interaction """
# Disable handling of mouse events
self.ignore('DIRECT-mouse3')
self.ignore('DIRECT-mouse3Up')
# LEVEL OBJECT MANAGEMENT FUNCTIONS
def findDNANode(self, nodePath):
""" Find node path's DNA Object in DNAStorage (if any) """
if nodePath:
return DNASTORE.findDNAGroup(nodePath.node())
else:
return None
def replaceSelected(self):
if self.replaceSelectedEnabled:
# Update visible geometry using new DNA
newRoot = self.replace(self.selectedNPRoot, self.selectedDNARoot)
# Reselect node path and respawn followSelectedNodePathTask
base.direct.select(newRoot)
def replace(self, nodePath, dnaNode):
""" Replace a node path with the results of a DNANode traversal """
# Find node path's parent
if not nodePath:
return None
parent = nodePath.getParent()
dnaParent = dnaNode.getParent()
# Get rid of the old node path and remove its DNA and
# node relations from the DNA Store
self.remove(dnaNode, nodePath)
# Traverse the old (modified) dna to create the new node path
try:
newNodePath = dnaNode.traverse(parent, DNASTORE, 1)
except Exception:
self.notify.debug("Couldn't traverse existing DNA! Do not trust replace")
return None
# Add it back to the dna parent
dnaParent.add(dnaNode)
# Update scene graph explorer
# self.panel.sceneGraphExplorer.update()
# Return new node path
return newNodePath
def remove(self, dnaNode, nodePath):
"""
Delete DNA and Node relation from DNA Store and remove the node
path from the scene graph.
"""
# First delete DNA and node relation from the DNA Store
if dnaNode:
# Get DNANode's parent
parentDNANode = dnaNode.getParent()
if parentDNANode:
# Remove DNANode from its parent
parentDNANode.remove(dnaNode)
# Delete DNA and associated Node Relations from DNA Store
DNASTORE.removeDNAGroup(dnaNode)
if nodePath:
# Next deselect nodePath to avoid having bad node paths in the dict
base.direct.deselect(nodePath)
# Now you can get rid of the node path
nodePath.removeNode()
def removeNodePathHook(self, nodePath):
dnaNode = self.findDNANode(nodePath)
# Does the node path correspond to a DNA Object
if dnaNode:
for hook in self.removeHookList:
hook(dnaNode, nodePath)
# Get DNANode's parent
parentDNANode = dnaNode.getParent()
if parentDNANode:
# Remove DNANode from its parent
parentDNANode.remove(dnaNode)
# Delete DNA and associated Node Relations from DNA Store
DNASTORE.removeDNAGroup(dnaNode)
else:
pointOrCell, type = self.findPointOrCell(nodePath)
if pointOrCell and type:
if (type == 'suitPointMarker'):
print 'Suit Point:', pointOrCell
if DNASTORE.removeSuitPoint(pointOrCell):
print "Removed from DNASTORE"
else:
print "Not found in DNASTORE"
# Remove point from pointDict
del(self.pointDict[pointOrCell])
# Remove point from visitedPoints list
if pointOrCell in self.visitedPoints:
self.visitedPoints.remove(pointOrCell)
# Update edge related dictionaries
for edge in self.point2edgeDict[pointOrCell]:
# Is it still in edge dict?
oldEdgeLine = self.edgeDict.get(edge, None)
if oldEdgeLine:
del self.edgeDict[edge]
oldEdgeLine.reset()
del oldEdgeLine
# Find other endpoints of edge and clear out
# corresponding point2edgeDict entry
startPoint = edge.getStartPoint()
endPoint = edge.getEndPoint()
if pointOrCell == startPoint:
self.point2edgeDict[endPoint].remove(edge)
elif pointOrCell == endPoint:
self.point2edgeDict[startPoint].remove(edge)
# Is it in the visited edges list?
if edge in self.visitedEdges:
self.visitedEdges.remove(edge)
# Now delete point2edgeDict entry for this point
del(self.point2edgeDict[pointOrCell])
elif (type == 'battleCellMarker'):
# Get parent vis group
visGroupNP, visGroupDNA = self.findParentVisGroup(
nodePath)
print 'Battle Cell:', pointOrCell
# Remove cell from vis group
if visGroupNP and visGroupDNA:
if visGroupDNA.removeBattleCell(pointOrCell):
print "Removed from Vis Group"
else:
print "Not found in Vis Group"
else:
print "Parent Vis Group not found"
# Remove cell from DNASTORE
if DNASTORE.removeBattleCell(pointOrCell):
print "Removed from DNASTORE"
else:
print "Not found in DNASTORE"
# Remove cell from cellDict
del(self.cellDict[pointOrCell])
def reparent(self, nodePath, oldParent, newParent):
""" Move node path (and its DNA) to active parent """
# Does the node path correspond to a DNA Object
dnaNode = self.findDNANode(nodePath)
if dnaNode:
# Find old parent DNA
oldParentDNANode = self.findDNANode(oldParent)
# Remove DNA from old parent
if oldParentDNANode:
oldParentDNANode.remove(dnaNode)
if newParent:
# Update active parent just to be safe
self.setActiveParent(newParent)
# Move DNA to new parent (if active parent set)
if self.DNAParent != None:
self.DNAParent.add(dnaNode)
# It is, is it a DNA_NODE (i.e. it has pos/hpr/scale)?
# Update pose to reflect new relationship
if DNAIsDerivedFrom(dnaNode, DNA_NODE):
# Update DNA
self.updatePose(dnaNode, nodePath)
elif newParent:
# See if this node path is a suit edge
suitEdge, oldVisGroup = self.np2EdgeDict.get(nodePath.id(), (None, None))
# And see if the new parent is a vis group
newVisGroupNP, newVisGroupDNA = self.findParentVisGroup(newParent)
if suitEdge and DNAClassEqual(newVisGroupDNA, DNA_VIS_GROUP):
# If so, remove suit edge from old vis group and add it to the new group
oldVisGroup.removeSuitEdge(suitEdge)
# Update suit edge to reflect new zone ID
suitEdge.setZoneId(newVisGroupDNA.getName())
newVisGroupDNA.addSuitEdge(suitEdge)
# Update np2EdgeDict to reflect changes
self.np2EdgeDict[nodePath.id()] = [suitEdge, newVisGroupDNA]
def setActiveParent(self, nodePath = None):
""" Set NPParent and DNAParent to node path and its DNA """
# If we've got a valid node path
if nodePath:
# See if this is in the DNA database
newDNAParent = self.findDNANode(nodePath)
if newDNAParent:
self.DNAParent = newDNAParent
self.NPParent = nodePath
else:
print 'LevelEditor.setActiveParent: nodePath not found'
else:
print 'LevelEditor.setActiveParent: nodePath == None'
def setName(self, nodePath, newName):
""" Set name of nodePath's DNA (if it exists) """
# Find the DNA that corresponds to this node path
dnaNode = self.findDNANode(nodePath)
if dnaNode:
# If it exists, set the name of the DNA Node
dnaNode.setName(newName)
def updateSelectedPose(self, nodePathList):
"""
Update the DNA database to reflect selected objects current positions
"""
for selectedNode in nodePathList:
# Is this a DNA Object in the DNASTORE database?
dnaObject = self.findDNANode(selectedNode)
if dnaObject:
# It is, is it a DNA_NODE (i.e. does it have pos/hpr/scale)?
if DNAIsDerivedFrom(dnaObject, DNA_NODE):
# First snap selected node path to grid
pos = selectedNode.getPos(base.direct.grid)
snapPos = base.direct.grid.computeSnapPoint(pos)
if self.panel.fPlaneSnap.get():
zheight = 0
else:
zheight = snapPos[2]
selectedNode.setPos(base.direct.grid,
snapPos[0], snapPos[1], zheight)
# Angle snap
h = base.direct.grid.computeSnapAngle(selectedNode.getH())
if base.direct.grid.getHprSnap():
selectedNode.setH(h)
if selectedNode == base.direct.selected.last:
self.setLastAngle(h)
# Update DNA
self.updatePose(dnaObject, selectedNode)
else:
pointOrCell, type = self.findPointOrCell(selectedNode)
if pointOrCell and type:
# First snap selected node path to grid
pos = selectedNode.getPos(base.direct.grid)
snapPos = base.direct.grid.computeSnapPoint(pos)
if self.panel.fPlaneSnap.get():
zheight = 0
else:
zheight = snapPos[2]
selectedNode.setPos(
base.direct.grid,
snapPos[0], snapPos[1], zheight)
newPos = selectedNode.getPos(self.NPToplevel)
# Update DNA
pointOrCell.setPos(newPos)
if (type == 'suitPointMarker'):
print "Found suit point!", pointOrCell
# Ok, now update all the lines into that node
for edge in self.point2edgeDict[pointOrCell]:
# Is it still in edge dict?
oldEdgeLine = self.edgeDict.get(edge, None)
if oldEdgeLine:
del self.edgeDict[edge]
oldEdgeLine.reset()
oldEdgeLine.removeNode()
del oldEdgeLine
newEdgeLine = self.drawSuitEdge(
edge, self.NPParent)
self.edgeDict[edge] = newEdgeLine
elif (type == 'battleCellMarker'):
print "Found battle cell!", pointOrCell
def updatePose(self, dnaObject, nodePath):
"""
Update a DNA Object's pos, hpr, and scale based upon
node path's current pose
"""
# Set DNA's pos, hpr, and scale
dnaObject.setPos(nodePath.getPos())
dnaObject.setHpr(nodePath.getHpr())
dnaObject.setScale(nodePath.getScale())
# LEVEL OBJECT CREATION FUNCTIONS
def initDNANode(self, dnaNode):
"""
This method adds a new DNA object to the scene and adds hooks that
allow duplicate copies of this DNA node to be added using the
space bar. For DNAFlatBuildings, a new copy with random style is
generated by hitting the insert key.
"""
# First create the visible geometry for this DNA Node
self.initNodePath(dnaNode)
# And add hooks to insert copies of dnaNode
self.addReplicationHooks(dnaNode)
def addReplicationHooks(self, dnaNode):
# Now add hook to allow placement of a new dna Node of this type
# by simply hitting the space bar or insert key. Note, extra paramter
# indicates new dnaNode should be a copy
self.accept('space', self.initNodePath, [dnaNode, 'space'])
self.accept('insert', self.initNodePath, [dnaNode, 'insert'])
def setRandomBuildingStyle(self, dnaNode, name = 'building'):
""" Initialize a new DNA Flat building to a random building style """
# What is the current building type?
buildingType = self.getCurrent('building_type')
# If random
if buildingType == 'random':
# Generate height list based on current building height
buildingHeight = self.getCurrent('building_height')
heightList = self.getRandomHeightList(buildingHeight)
# Convert height list to building type
buildingType = createHeightCode(heightList)
else:
# Use specified height list
heightList = map(string.atof, string.split(buildingType, '_'))
height = calcHeight(heightList)
# Is this a never before seen height list? If so, record it.
try:
attr = self.getAttribute(`height` + '_ft_wall_heights')
if heightList not in attr.getList():
print 'Adding new height list entry'
attr.add(heightList)
except KeyError:
print 'Non standard height building'
# See if this building type corresponds to existing style dict
try:
dict = self.getDict(buildingType + '_styles')
except KeyError:
# Nope
dict = {}
# No specific dict or empty dict, try to pick a dict
# based on number of walls
if not dict:
# How many walls?
numWalls = len(heightList)
# Get the building_style attribute dictionary for
# this number of walls
dict = self.getDict(`numWalls` + '_wall_styles')
if not dict:
# Still no dict, create new random style using height list
styleList = []
# Build up wall styles
for height in heightList:
wallStyle = self.getRandomDictionaryEntry(
self.getDict('wall_style'))
styleList.append((wallStyle, height))
# Create new random flat building style
style = DNAFlatBuildingStyle(styleList = styleList)
else:
# Pick a style
style = self.getRandomDictionaryEntry(dict)
# Set style....finally
self.styleManager.setDNAFlatBuildingStyle(
dnaNode, style, width = self.getRandomWallWidth(),
heightList = heightList, name = name)
def getRandomHeightList(self, buildingHeight):
# Select a list of wall heights
heightLists = self.getList(`buildingHeight` + '_ft_wall_heights')
l = len(heightLists)
if l > 0:
# If a list exists for this building height, pick randomly
return heightLists[randint(0, l - 1)]
else:
# No height lists exists for this building height, generate
chance = randint(0, 100)
if buildingHeight <= 10:
return [buildingHeight]
elif buildingHeight <= 14:
return [4, 10]
elif buildingHeight <= 20:
if chance <= 30:
return [20]
elif chance <= 80:
return [10, 10]
else:
return [12, 8]
elif buildingHeight <= 24:
if chance <= 50:
return [4, 10, 10]
else:
return [4, 20]
elif buildingHeight <= 25:
if chance <= 25:
return [3, 22]
elif chance <= 50:
return [4, 21]
elif chance <= 75:
return [3, 13, 9]
else:
return [4, 13, 8]
else:
if chance <= 20:
return [10, 20]
elif chance <= 35:
return [20, 10]
elif chance <= 75:
return [10, 10, 10]
else:
return [13, 9, 8]
def getRandomWallWidth(self):
chance = randint(0, 100)
if chance <= 15:
return 5.0
elif chance <= 30:
return 10.0
elif chance <= 65:
return 15.0
elif chance <= 85:
return 20.0
else:
return 25.0
def initNodePath(self, dnaNode, hotKey = None):
"""
Update DNA to reflect latest style choices and then generate
new node path and add it to the scene graph
"""
# Determine dnaNode Class Type
nodeClass = DNAGetClassType(dnaNode)
# Did the user hit insert or space?
if hotKey:
# Yes, make a new copy of the dnaNode
dnaNode = dnaNode.__class__(dnaNode)
# And determine dnaNode type and perform any type specific updates
if nodeClass.eq(DNA_PROP):
dnaNode.setCode(self.getCurrent('prop_texture'))
elif nodeClass.eq(DNA_STREET):
dnaNode.setCode(self.getCurrent('street_texture'))
elif nodeClass.eq(DNA_FLAT_BUILDING):
# If insert, pick a new random style
if hotKey == 'insert':
self.setRandomBuildingStyle(dnaNode, dnaNode.getName())
# Get a new building width
self.setCurrent('building_width',
self.getRandomWallWidth())
dnaNode.setWidth(self.getCurrent('building_width'))
# Position it
# First kill autoposition task so grid can jump to its final
# destination (part of cleanup
taskMgr.remove('autoPositionGrid')
# Now find where to put node path
if (hotKey is not None) and nodeClass.eq(DNA_PROP):
# If its a prop and a copy, place it based upon current
# mouse position
hitPt = self.getGridIntersectionPoint()
# Attach a node, so we can set pos with respect to:
tempNode = hidden.attachNewNode('tempNode')
# Place it:
tempNode.setPos(base.direct.grid, hitPt)
# Copy the pos to where we really want it:
dnaNode.setPos(tempNode.getPos())
# Clean up:
tempNode.removeNode()
else:
# Place the new node path at the current grid origin
dnaNode.setPos(base.direct.grid.getPos())
# Initialize angle to match last object
dnaNode.setHpr(Vec3(self.getLastAngle(), 0, 0))
# Add the DNA to the active parent
self.DNAParent.add(dnaNode)
# And create the geometry
newNodePath = dnaNode.traverse(self.NPParent, DNASTORE, 1)
# Update scene graph explorer
# self.panel.sceneGraphExplorer.update()
# Reset last Code (for autoPositionGrid)
if DNAClassEqual(dnaNode, DNA_STREET):
self.snapList = self.getSnapPoint(dnaNode.getCode())
# Select the instance
base.direct.select(newNodePath)
self.lastNodePath = newNodePath
# Update grid to get ready for the next object
self.autoPositionGrid()
def getSnapPoint(self, code):
return OBJECT_SNAP_POINTS.get(code, [(Vec3(0.0, 0, 0), Vec3(0)), (Vec3(0), Vec3(0))])
def addGroup(self, nodePath):
""" Add a new DNA Node Group to the specified Node Path """
# Set the node path as the current parent
base.direct.setActiveParent(nodePath)
# Add a new group to the selected parent
self.createNewGroup()
def addVisGroup(self, nodePath):
""" Add a new DNA Group to the specified Node Path """
# Set the node path as the current parent
base.direct.setActiveParent(nodePath)
# Add a new group to the selected parent
self.createNewGroup(type = 'vis')
def createNewGroup(self, type = 'dna'):
print "createNewGroup"
""" Create a new DNA Node group under the active parent """
# Create a new DNA Node group
if type == 'dna':
newDNANode = DNANode('group_' + `self.getGroupNum()`)
else:
newDNANode = DNAVisGroup('VisGroup_' + `self.getGroupNum()`)
# Increment group counter
self.setGroupNum(self.getGroupNum() + 1)
# Add new DNA Node group to the current parent DNA Object
self.DNAParent.add(newDNANode)
# The new Node group becomes the active parent
self.DNAParent = newDNANode
# Traverse it to generate the new node path as a child of NPParent
newNodePath = self.DNAParent.traverse(self.NPParent, DNASTORE, 1)
# Update NPParent to point to the new node path
self.NPParent = newNodePath
# Update scene graph explorer
# self.panel.sceneGraphExplorer.update()
def addFlatBuilding(self, buildingType):
# Create new building
newDNAFlatBuilding = DNAFlatBuilding()
self.setRandomBuildingStyle(newDNAFlatBuilding,
name = 'tb0:'+ buildingType + '_DNARoot')
# Now place new building in the world
self.initDNANode(newDNAFlatBuilding)
def getNextLandmarkBlock(self):
self.landmarkBlock=self.landmarkBlock+1
return str(self.landmarkBlock)
def addLandmark(self, landmarkType, specialType):
# Record new landmark type
self.setCurrent('toon_landmark_texture', landmarkType)
# And create new landmark building
block=self.getNextLandmarkBlock()
newDNALandmarkBuilding = DNALandmarkBuilding(
'tb'+block+':'+landmarkType + '_DNARoot')
newDNALandmarkBuilding.setCode(landmarkType)
newDNALandmarkBuilding.setBuildingType(specialType)
newDNALandmarkBuilding.setPos(VBase3(0))
newDNALandmarkBuilding.setHpr(VBase3(0))
# Headquarters do not have doors
if specialType not in ['hq', 'kartshop']:
newDNADoor = self.createDoor('landmark_door')
newDNALandmarkBuilding.add(newDNADoor)
# Now place new landmark building in the world
self.initDNANode(newDNALandmarkBuilding)
def addProp(self, propType):
print "addProp %s " % propType
# Record new prop type
self.setCurrent('prop_texture', propType)
# And create new prop
newDNAProp = DNAProp(propType + '_DNARoot')
newDNAProp.setCode(propType)
newDNAProp.setPos(VBase3(0))
newDNAProp.setHpr(VBase3(0))
# Now place new prop in the world
self.initDNANode(newDNAProp)
def addStreet(self, streetType):
# Record new street type
self.setCurrent('street_texture', streetType)
# And create new street
newDNAStreet = DNAStreet(streetType + '_DNARoot')
newDNAStreet.setCode(streetType)
newDNAStreet.setPos(VBase3(0))
newDNAStreet.setHpr(VBase3(0))
# Set street texture to neighborhood dependant texture
newDNAStreet.setStreetTexture(
'street_street_' + self.neighborhoodCode + '_tex')
newDNAStreet.setSidewalkTexture(
'street_sidewalk_' + self.neighborhoodCode + '_tex')
newDNAStreet.setCurbTexture(
'street_curb_' + self.neighborhoodCode + '_tex')
# Now place new street in the world
self.initDNANode(newDNAStreet)
def createCornice(self):
newDNACornice = DNACornice('cornice')
newDNACornice.setCode(self.getCurrent('cornice_texture'))
newDNACornice.setColor(self.getCurrent('cornice_color'))
return newDNACornice
def createDoor(self, type):
if (type == 'landmark_door'):
newDNADoor = DNADoor('door')
print "createDoor %s" % type
if not (self.getCurrent('door_double_texture')):
doorStyles = self.styleManager.attributeDictionary['door_double_texture'].getList()[1:]
defaultDoorStyle = random.choice(doorStyles)
self.setCurrent('door_double_texture', defaultDoorStyle)
newDNADoor.setCode(self.getCurrent('door_double_texture'))
print "doorcolor = %s" % self.getCurrent('door_color')
newDNADoor.setColor(self.getCurrent('door_color'))
elif (type == 'door'):
newDNADoor = DNAFlatDoor('door')
if not (self.getCurrent('door_single_texture')):
doorStyles = self.styleManager.attributeDictionary['door_single_texture'].getList()[1:]
defaultDoorStyle = random.choice(doorStyles)
self.setCurrent('door_single_texture', defaultDoorStyle)
newDNADoor.setCode(self.getCurrent('door_single_texture'))
newDNADoor.setColor(self.getCurrent('door_color'))
return newDNADoor
def createSign(self):
if not (self.getCurrent('sign_texture')):
defaultSignStyle = self.styleManager.attributeDictionary['sign_texture'].getList()[0]
self.setCurrent('sign_texture', defaultSignStyle)
newDNASign = DNASign('sign')
newDNASign.setCode(self.getCurrent('sign_texture'))
newDNASign.setColor(self.getCurrent('sign_color'))
#newDNASign.setColor(VBase4(0.0, 1.0, 0.0, 1.0))
#newDNASign.setScale(VBase3(2.0, 1.0, 2.0))
baseline = DNASignBaseline('baseline')
baseline.setCode("humanist")
baseline.setColor(VBase4(0.0, 0.0, 0.0, 1.0))
#baseline.setKern(1.0)
#baseline.setWiggle(30.0)
#baseline.setStumble(1.0)
#baseline.setStomp(10.0)
#baseline.setWidth(16.0)
#baseline.setHeight(16.0)
baseline.setScale(VBase3(0.7, 1.0, 0.7))
newDNASign.add(baseline)
#graphic = DNASignGraphic('graphic')
#graphic.setCode("sign_general1")
#graphic.setColor(VBase4(1.0, 1.0, 0.0, 0.5))
#graphic.setScale(VBase3(.2, 1.0, .2))
#graphic.setHpr(VBase3(0.0, 0.0, 90.0))
#baseline.add(graphic)
DNASetBaselineString(baseline, "Toon Shop")
return newDNASign
def createWindows(self):
newDNAWindows = DNAWindows()
newDNAWindows.setCode(self.getCurrent('window_texture'))
newDNAWindows.setWindowCount(self.getCurrent('window_count'))
newDNAWindows.setColor(self.getCurrent('window_color'))
return newDNAWindows
def removeCornice(self, cornice, parent):
self.setCurrent('cornice_color', cornice.getColor())
DNARemoveChildOfClass(parent, DNA_CORNICE)
def removeLandmarkDoor(self, door, parent):
self.setCurrent('door_color', door.getColor())
DNARemoveChildOfClass(parent, DNA_DOOR)
def removeSign(self, sign, parent):
self.setCurrent('sign_color', sign.getColor())
DNARemoveChildOfClass(parent, DNA_SIGN)
def removeDoor(self, door, parent):
self.setCurrent('door_color', door.getColor())
DNARemoveChildOfClass(parent, DNA_FLAT_DOOR)
def removeWindows(self, windows, parent):
# And record number of windows
self.setCurrent('window_color', windows.getColor())
self.setCurrent('window_count', windows.getWindowCount())
DNARemoveChildOfClass(parent, DNA_WINDOWS)
# LEVEL-OBJECT MODIFICATION FUNCTIONS
def levelHandleMouse3(self, modifiers):
# import pdb; pdb.set_trace()
if base.direct.cameraControl.useMayaCamControls and modifiers == 4: # alt is down, use maya controls
self.mouseMayaCamera = True
return
else:
self.mouseMayaCamera = False
# Initialize dna target
self.DNATarget = None
# If nothing selected, just return
if not self.selectedNPRoot:
return
# Next check to see if the selected object is a DNA object
dnaObject = self.findDNANode(self.selectedNPRoot)
# Nope, not a DNA object, just return
if not dnaObject:
return
# Pick a menu based upon object type
if DNAClassEqual(dnaObject, DNA_FLAT_BUILDING):
# FLAT BUILDING OPERATIONS
menuMode, wallNum = self.getFlatBuildingMode(dnaObject, modifiers)
# Check menuMode
if menuMode == None:
return
# Find appropriate target
wall = self.getWall(dnaObject, wallNum)
# Record bldg/wall
self.lastBuilding = dnaObject
self.lastWall = wall
if string.find(menuMode,'wall') >= 0:
self.DNATarget = wall
self.DNATargetParent = dnaObject
elif string.find(menuMode,'door') >= 0:
self.DNATarget = DNAGetChildOfClass(wall, DNA_FLAT_DOOR)
self.DNATargetParent = wall
elif string.find(menuMode, 'window') >= 0:
self.DNATarget = DNAGetChildOfClass(wall, DNA_WINDOWS)
self.DNATargetParent = wall
elif string.find(menuMode,'cornice') >= 0:
self.DNATarget = DNAGetChildOfClass(wall, DNA_CORNICE)
self.DNATargetParent = wall
else:
self.DNATarget = dnaObject
elif DNAClassEqual(dnaObject, DNA_PROP):
# PROP OPERATIONS
self.DNATarget = dnaObject
if base.direct.gotControl(modifiers):
menuMode = 'prop_color'
elif base.direct.gotAlt(modifiers) and self.panel.currentBaselineDNA:
menuMode = 'baseline_style'
elif base.direct.gotShift(modifiers):
menuMode = 'sign_texture'
self.DNATarget = DNAGetChildOfClass(dnaObject, DNA_SIGN)
self.DNATargetParent = dnaObject
else:
menuMode = 'prop_texture'
elif DNAClassEqual(dnaObject, DNA_LANDMARK_BUILDING):
# INSERT HERE
# LANDMARK BUILDING OPERATIONS
menuMode = self.getLandmarkBuildingMode(dnaObject, modifiers)
if string.find(menuMode, 'door') >= 0:
self.DNATarget = DNAGetChildOfClass(dnaObject, DNA_DOOR)
self.DNATargetParent = dnaObject
elif string.find(menuMode, 'sign') >= 0:
self.DNATarget = DNAGetChildOfClass(dnaObject, DNA_SIGN)
self.DNATargetParent = dnaObject
else:
self.DNATarget = dnaObject
elif DNAClassEqual(dnaObject, DNA_STREET):
# STREET OPERATIONS
self.DNATarget = dnaObject
menuMode = 'street_texture'
# No valid menu mode, get the hell out of here!
if menuMode == None:
return
# Now spawn apropriate menu task if menu selected
self.activeMenu = self.getMenu(menuMode)
# Set initial state
state = None
if self.DNATarget:
if string.find(menuMode,'texture') >= 0:
state = self.DNATarget.getCode()
elif string.find(menuMode, 'color') >= 0:
state = self.DNATarget.getColor()
self.panel.setCurrentColor(state)
self.panel.setResetColor(state)
elif string.find(menuMode, 'orientation') >= 0:
state = self.DNATarget.getCode()[-2:]
elif menuMode == 'building_width':
state = self.DNATarget.getWidth()
elif menuMode == 'window_count':
state = self.DNATarget.getWindowCount()
elif menuMode == 'building_style_all':
# Extract the building style from the current building
state = DNAFlatBuildingStyle(building = self.DNATarget)
elif menuMode == 'baseline_style':
# Extract the baseline style
state = DNABaselineStyle(
baseline = self.panel.currentBaselineDNA)
elif menuMode == 'wall_style':
# Extract the wall style from the current wall
state = DNAWallStyle(wall = self.DNATarget)
self.activeMenu.setInitialState(state)
# Spawn active menu's task
self.activeMenu.spawnPieMenuTask()
def getLandmarkBuildingMode(self, dnaObject, modifiers):
# Where are we hitting the building?
hitPt = self.getWallIntersectionPoint(self.selectedNPRoot)
if hitPt[2] < 10.0:
# Do door operations
if base.direct.gotControl(modifiers):
menuMode = 'door_color'
elif base.direct.gotAlt(modifiers):
menuMode = 'door_orientation'
else:
menuMode = 'door_double_texture'
else:
# Do sign operations
if base.direct.gotControl(modifiers):
menuMode = 'sign_color'
elif base.direct.gotAlt(modifiers) and self.panel.currentBaselineDNA:
menuMode = 'baseline_style'
elif base.direct.gotAlt(modifiers):
menuMode = 'sign_orientation'
else:
menuMode = 'sign_texture'
return menuMode
def getFlatBuildingMode(self, dnaObject, modifiers):
# Where are we hitting the building?
hitPt = self.getWallIntersectionPoint(self.selectedNPRoot)
wallNum = self.computeWallNum(dnaObject, hitPt)
if wallNum < 0:
# Do building related operations
if base.direct.gotAlt(modifiers):
menuMode = 'building_width'
else:
menuMode = 'building_style_all'
else:
# Otherwise, do wall specific operations
# Figure out where you are hitting on the wall
wallHeights, offsetList = DNAGetWallHeights(dnaObject)
# Find a normalized X and Z coordinate
xPt = hitPt[0]/dnaObject.getWidth()
# Adjust zPt depending on what wall you are pointing at
wallHeight = wallHeights[wallNum]
zPt = (hitPt[2] - offsetList[wallNum])/wallHeight
# Record current wall height
self.setCurrent('wall_height', wallHeight)
# Determine which zone you are pointing at
if (zPt > 0.8):
# Do cornice operations
if base.direct.gotControl(modifiers):
menuMode = 'cornice_color'
elif base.direct.gotAlt(modifiers):
menuMode = 'cornice_orientation'
else:
menuMode = 'cornice_texture'
elif ((xPt < 0.3) or (xPt > 0.7)):
# Do wall operations
if base.direct.gotControl(modifiers):
menuMode = 'wall_color'
elif base.direct.gotAlt(modifiers):
menuMode = 'wall_orientation'
elif base.direct.gotShift(modifiers):
menuMode = 'wall_texture'
else:
menuMode = 'wall_style'
elif (zPt < 0.4):
# Do door operations
if base.direct.gotControl(modifiers):
menuMode = 'door_color'
elif base.direct.gotAlt(modifiers):
menuMode = 'door_orientation'
else:
menuMode = 'door_single_texture'
else:
# Do window operations
if base.direct.gotControl(modifiers):
menuMode = 'window_color'
elif base.direct.gotAlt(modifiers):
menuMode = 'window_orientation'
elif base.direct.gotShift(modifiers):
menuMode = 'window_count'
else:
menuMode = 'window_texture'
return menuMode, wallNum
def levelHandleMouse3Up(self):
if self.mouseMayaCamera:
return
if self.activeMenu:
self.activeMenu.removePieMenuTask()
# Update panel color if appropriate
if self.DNATarget:
objClass = DNAGetClassType(self.DNATarget)
if ((objClass.eq(DNA_WALL)) or
(objClass.eq(DNA_WINDOWS)) or
(objClass.eq(DNA_DOOR)) or
(objClass.eq(DNA_FLAT_DOOR)) or
(objClass.eq(DNA_CORNICE)) or
(objClass.eq(DNA_PROP))
):
self.panel.setCurrentColor(self.DNATarget.getColor())
## b1 = DirectButton(text = ("Button1", "click!", "roll", "disabled"),
## text_scale=0.1, borderWidth = (0.01, 0.01),
## relief=2)
##
## b2 = DirectButton(text = ("Button2", "click!", "roll", "disabled"),
## text_scale=0.1, borderWidth = (0.01, 0.01),
## relief=2)
##
## l1 = DirectLabel(text = "Test1", text_scale=0.1)
## l2 = DirectLabel(text = "Test2", text_scale=0.1)
## l3 = DirectLabel(text = "Test3", text_scale=0.1)
##
## numItemsVisible = 4
## itemHeight = 0.11
##
## myScrolledList = DirectScrolledList(
## decButton_pos= (0.35, 0, 0.53),
## decButton_text = "Dec",
## decButton_text_scale = 0.04,
## decButton_borderWidth = (0.005, 0.005),
##
## incButton_pos= (0.35, 0, -0.02),
## incButton_text = "Inc",
## incButton_text_scale = 0.04,
## incButton_borderWidth = (0.005, 0.005),
##
## frameSize = (0.0, 0.7, -0.05, 0.59),
## frameColor = (1,0,0,0.5),
## pos = (-1, 0, 0),
## items = [b1, b2],
## numItemsVisible = numItemsVisible,
## forceHeight = itemHeight,
## itemFrame_frameSize = (-0.2, 0.2, -0.37, 0.11),
## itemFrame_pos = (0.35, 0, 0.4),
## )
##
## myScrolledList.addItem(l1)
## myScrolledList.addItem(l2)
## myScrolledList.addItem(l3)
##
## for fruit in ['apple', 'pear', 'banana', 'orange']:
## l = DirectLabel(text = fruit, text_scale=0.1)
## myScrolledList.addItem(l)
##
## myScrolledList.reparentTo(aspect2d)
def setDNATargetColor(self, color):
if self.DNATarget:
self.DNATarget.setColor(color)
self.replaceSelected()
def setDNATargetCode(self, type, code):
if (self.DNATarget != None) and (code != None):
# Update code
self.DNATarget.setCode(code)
elif (self.DNATarget != None) and (code == None):
# Delete object, record pertinant properties before
# you delete the object so you can restore them later
# Remove object
if (type == 'cornice'):
self.removeCornice(self.DNATarget, self.DNATargetParent)
elif (type == 'sign'):
self.removeSign(self.DNATarget, self.DNATargetParent)
elif (type == 'landmark_door'):
self.removeLandmarkDoor(self.DNATarget, self.DNATargetParent)
elif (type == 'door'):
self.removeDoor(self.DNATarget, self.DNATargetParent)
elif (type == 'windows'):
self.removeWindows(self.DNATarget, self.DNATargetParent)
# Clear out DNATarget
self.DNATarget = None
elif (self.DNATarget == None) and (code != None):
# Add new object
if (type == 'cornice'):
self.DNATarget = self.createCornice()
elif (type == 'sign'):
self.DNATarget = self.createSign()
elif (type == 'landmark_door'):
self.DNATarget = self.createDoor('landmark_door')
elif (type == 'door'):
self.DNATarget = self.createDoor('door')
elif (type == 'windows'):
# Make sure window_count n.e. 0
if self.getCurrent('window_count') == 0:
self.setCurrent(
'window_count',
self.getRandomWindowCount())
# Now create the windows
self.DNATarget = self.createWindows()
if self.DNATarget:
self.DNATargetParent.add(self.DNATarget)
# Update visible representation
self.replaceSelected()
def setDNATargetOrientation(self, orientation):
if (self.DNATarget != None) and (orientation != None):
oldCode = self.DNATarget.getCode()[:-2]
# Suit walls only have two orientations!
if oldCode.find('wall_suit') >= 0:
orientation = 'u' + orientation[1]
self.DNATarget.setCode(oldCode+orientation)
self.replaceSelected()
def setBuildingStyle(self, style):
if (self.DNATarget != None) and (style != None):
self.styleManager.setDNAFlatBuildingStyle(
self.DNATarget, style,
width = self.DNATarget.getWidth(),
name = self.DNATarget.getName())
# MRM: Need to disable dna store warning
self.replaceSelected()
# Re-add replication hooks so we get right kind of copy
self.addReplicationHooks(self.DNATarget)
def setBuildingType(self, type):
print 'setBuildingType: ', `type`
def setBuildingWidth(self, width):
if self.DNATarget:
self.DNATarget.setWidth(width)
self.replaceSelected()
def setWindowCount(self, count):
if (self.DNATarget != None) and (count != 0):
self.DNATarget.setWindowCount(count)
elif (self.DNATarget != None) and (count == 0):
# Remove windows and clear out DNATarget
self.removeWindows(self.DNATarget, self.DNATargetParent)
self.DNATarget = None
elif (self.DNATarget == None) and (count != 0):
self.DNATarget = self.createWindows()
self.DNATargetParent.add(self.DNATarget)
self.replaceSelected()
def setWallStyle(self, style):
if (self.DNATarget != None) and (style != None):
self.styleManager.setDNAWallStyle(
self.DNATarget, style,
self.DNATarget.getHeight())
self.replaceSelected()
def setColor(self, nodePath, r, g, b, a):
""" This is used to set color of dnaNode subparts """
dnaNode = self.findDNANode(nodePath)
if dnaNode:
objClass = DNAGetClassType(dnaNode)
if ((objClass.eq(DNA_WALL)) or
(objClass.eq(DNA_WINDOWS)) or
(objClass.eq(DNA_DOOR)) or
(objClass.eq(DNA_FLAT_DOOR)) or
(objClass.eq(DNA_CORNICE)) or
(objClass.eq(DNA_PROP)) or
(objClass.eq(DNA_SIGN)) or
(objClass.eq(DNA_SIGN_BASELINE)) or
(objClass.eq(DNA_SIGN_TEXT)) or
(objClass.eq(DNA_SIGN_GRAPHIC))
):
# Update dna information
dnaNode.setColor(VBase4(r/255.0, g/255.0, b/255.0, a/255.0))
# SELECTION FUNCTIONS
def selectedNodePathHook(self, nodePath):
"""
Hook called upon selection of a node path used to restrict
selection to DNA Objects. Press control to select any type of
DNA Object, with no control key pressed, hook selects only
DNA Root objects
"""
# Clear out old root variables
self.selectedDNARoot = None
self.selectedNPRoot = None
self.selectedSuitPoint = None
# Now process newly selected node path
dnaParent = None
dnaNode = self.findDNANode(nodePath)
if base.direct.fControl:
# Is the current node a DNA Object?
if not dnaNode:
# No it isn't, look for a parent DNA object
dnaParent = self.findDNAParent(nodePath.getParent())
else:
# Is the current node a DNA Root object?
if nodePath.getName()[-8:] != '_DNARoot':
# No it isn't, look for a parent DNA Root object
dnaParent = self.findDNARoot(nodePath.getParent())
# Do we need to switch selection to a parent object?
if dnaParent:
# Yes, deselect currently selected node path
base.direct.deselect(nodePath)
# And select parent
base.direct.select(dnaParent, base.direct.fShift)
elif dnaNode:
# We got a valid node path/DNA object, continue
self.selectedNPRoot = nodePath
self.selectedDNARoot = dnaNode
# Reset last landmark
if DNAClassEqual(dnaNode, DNA_LANDMARK_BUILDING):
self.lastLandmarkBuildingDNA=dnaNode
if self.showLandmarkBlockToggleGroup:
# Toggle old highlighting off:
self.toggleShowLandmarkBlock()
# Toggle on the the new highlighting:
self.toggleShowLandmarkBlock()
# Reset last Code (for autoPositionGrid)
if DNAClassEqual(dnaNode, DNA_STREET):
self.snapList = self.getSnapPoint(dnaNode.getCode())
else:
pointOrCell, type = self.findPointOrCell(nodePath)
if pointOrCell and (type == 'suitPointMarker'):
print "Found suit point!", pointOrCell
self.selectedSuitPoint = pointOrCell
elif pointOrCell and (type == 'battleCellMarker'):
print "Found battle cell!", pointOrCell
else:
if nodePath.getName() != 'suitEdge':
suitEdge = self.findSuitEdge(nodePath.getParent())
if suitEdge:
# Yes, deselect currently selected node path
base.direct.deselect(nodePath)
# And select parent
base.direct.select(suitEdge, base.direct.fShift)
# Let others know that something new may be selected:
for i in self.selectedNodePathHookHooks:
i()
if self.fDrive:
base.direct.deselect(nodePath)
def deselectedNodePathHook(self, nodePath):
# Clear out old root variables
self.selectedDNARoot = None
self.selectedNPRoot = None
self.selectedSuitPoint = None
# Let others know:
for i in self.deselectedNodePathHookHooks:
i()
def findDNAParent(self, nodePath):
""" Walk up a node path's ancestry looking for its DNA Root """
# Check to see if current node is a dna object
if self.findDNANode(nodePath):
# Its a root!
return nodePath
else:
# If reached the top: fail
if not nodePath.hasParent():
return 0
else:
# Try parent
return self.findDNAParent(nodePath.getParent())
def findDNARoot(self, nodePath):
""" Walk up a node path's ancestry looking for its DNA Root """
# Check current node's name for root marker
if (nodePath.getName()[-8:] == '_DNARoot'):
# Its a root!
return nodePath
else:
# If reached the top: fail
if not nodePath.hasParent():
return None
else:
# Try parent
return self.findDNARoot(nodePath.getParent())
def findSuitEdge(self, nodePath):
""" Walk up a node path's ancestry looking for a suit edge """
# Check current node's name for suitEdge marker
if (nodePath.getName() == 'suitEdge'):
# Its a suitEdge
return nodePath
else:
# If reached the top: fail
if not nodePath.hasParent():
return None
else:
# Try parent
return self.findSuitEdge(nodePath.getParent())
def findPointOrCell(self, nodePath):
"""
Walk up a node path's ancestry to see if its a suit point marker
or a battle cell marker
"""
# Check current node's name for root marker
if (nodePath.getName() == 'suitPointMarker'):
# Its a suit point marker!
# See if point is in pointDict
point = self.getSuitPointFromNodePath(nodePath)
return point, 'suitPointMarker'
elif (nodePath.getName() == 'battleCellMarker'):
# Its a battle cell marker
# See if cell is in cell Dict
cell = self.getBattleCellFromNodePath(nodePath)
return cell, 'battleCellMarker'
else:
# If reached the top: fail
if not nodePath.hasParent():
return None, None
else:
# Try parent
return self.findPointOrCell(nodePath.getParent())
# MANIPULATION FUNCTIONS
def keyboardRotateSelected(self, arrowDirection):
""" Rotate selected objects using arrow keys """
# Get snap angle
if base.direct.fShift:
oldSnapAngle = base.direct.grid.snapAngle
base.direct.grid.setSnapAngle(1.0)
snapAngle = base.direct.grid.snapAngle
# Compute new angle
if ((arrowDirection == 'left') or (arrowDirection == 'up')):
self.setLastAngle(self.getLastAngle() + snapAngle)
else:
self.setLastAngle(self.getLastAngle() - snapAngle)
if (self.getLastAngle() < -180.0):
self.setLastAngle(self.getLastAngle() + 360.0)
elif (self.getLastAngle() > 180.0):
self.setLastAngle(self.getLastAngle() - 360.0)
# Move selected objects
for selectedNode in base.direct.selected:
selectedNode.setHpr(self.getLastAngle(), 0, 0)
# Snap objects to grid and update DNA if necessary
self.updateSelectedPose(base.direct.selected.getSelectedAsList())
if base.direct.fShift:
base.direct.grid.setSnapAngle(oldSnapAngle)
def keyboardTranslateSelected(self, arrowDirection):
gridToCamera = base.direct.grid.getMat(base.direct.camera)
camXAxis = gridToCamera.xformVec(X_AXIS)
xxDot = camXAxis.dot(X_AXIS)
xzDot = camXAxis.dot(Z_AXIS)
# what is the current grid spacing?
if base.direct.fShift:
# If shift, divide grid spacing by 10.0
oldGridSpacing = base.direct.grid.gridSpacing
# Use back door to set grid spacing to avoid grid update
base.direct.grid.gridSpacing = base.direct.grid.gridSpacing/10.0
deltaMove = base.direct.grid.gridSpacing
# Compute the specified delta
deltaPos = Vec3(0)
if (abs(xxDot) > abs(xzDot)):
if (xxDot < 0.0):
deltaMove = -deltaMove
# Compute delta
if (arrowDirection == 'right'):
deltaPos.setX(deltaPos[0] + deltaMove)
elif (arrowDirection == 'left'):
deltaPos.setX(deltaPos[0] - deltaMove)
elif (arrowDirection == 'up'):
deltaPos.setY(deltaPos[1] + deltaMove)
elif (arrowDirection == 'down'):
deltaPos.setY(deltaPos[1] - deltaMove)
else:
if (xzDot < 0.0):
deltaMove = -deltaMove
# Compute delta
if (arrowDirection == 'right'):
deltaPos.setY(deltaPos[1] - deltaMove)
elif (arrowDirection == 'left'):
deltaPos.setY(deltaPos[1] + deltaMove)
elif (arrowDirection == 'up'):
deltaPos.setX(deltaPos[0] + deltaMove)
elif (arrowDirection == 'down'):
deltaPos.setX(deltaPos[0] - deltaMove)
# Move selected objects
for selectedNode in base.direct.selected:
# Move it
selectedNode.setPos(base.direct.grid,
selectedNode.getPos(base.direct.grid) + deltaPos)
# Snap objects to grid and update DNA if necessary
self.updateSelectedPose(base.direct.selected.getSelectedAsList())
# Restore grid spacing
if base.direct.fShift:
# Use back door to set grid spacing to avoid grid update
base.direct.grid.gridSpacing = oldGridSpacing
def keyboardXformSelected(self, arrowDirection, mode):
if mode == 'rotate':
self.keyboardRotateSelected(arrowDirection)
else:
self.keyboardTranslateSelected(arrowDirection)
# VISIBILITY FUNCTIONS
def editDNAVisGroups(self):
visGroups = self.getDNAVisGroups(self.NPToplevel)
if visGroups:
self.vgpanel = VisGroupsEditor(self, visGroups)
else:
showinfo('Vis Groups Editor','No DNA Vis Groups Found!')
def getDNAVisGroups(self, nodePath):
""" Find the highest level vis groups in the scene graph """
dnaNode = self.findDNANode(nodePath)
if dnaNode:
if DNAClassEqual(dnaNode, DNA_VIS_GROUP):
return [[nodePath, dnaNode]]
childVisGroups = []
children = nodePath.getChildren()
for child in children:
childVisGroups = (childVisGroups + self.getDNAVisGroups(child))
return childVisGroups
def findParentVisGroup(self, nodePath):
""" Find the containing vis group """
dnaNode = self.findDNANode(nodePath)
if dnaNode:
if DNAClassEqual(dnaNode, DNA_VIS_GROUP):
return nodePath, dnaNode
elif nodePath.hasParent():
return self.findParentVisGroup(nodePath.getParent())
# Fall through
return None, None
def showGrid(self, flag):
""" toggle direct grid """
if flag:
base.direct.grid.enable()
else:
base.direct.grid.disable()
# LEVEL MAP/MARKER FUNCTIONS
def createLevelMaps(self):
"""
Load up the various neighborhood maps
"""
# For neighborhood maps
self.levelMap = hidden.attachNewNode('level-map')
self.activeMap = None
self.mapDictionary = {}
"""
for neighborhood in NEIGHBORHOODS:
self.createMap(neighborhood)
"""
def createMap(self, neighborhood):
map = loader.loadModel('models/level_editor/' + neighborhood +
'_layout')
if map:
map.setTransparency(1)
map.setColor(Vec4(1, 1, 1, .4))
self.mapDictionary[neighborhood] = map
# Make sure this item isn't pickable
base.direct.addUnpickable(neighborhood + '_layout')
def selectMap(self, neighborhood):
if self.activeMap:
self.activeMap.reparentTo(hidden)
if self.mapDictionary.has_key(neighborhood):
self.activeMap = self.mapDictionary[neighborhood]
self.activeMap.reparentTo(self.levelMap)
def toggleMapVis(self, flag):
if flag:
self.levelMap.reparentTo(base.direct.group)
else:
self.levelMap.reparentTo(hidden)
def createInsertionMarker(self):
self.insertionMarker = LineNodePath(self)
self.insertionMarker.lineNode.setName('insertionMarker')
self.insertionMarker.setColor(VBase4(0.785, 0.785, 0.5, 1))
self.insertionMarker.setThickness(1)
self.insertionMarker.reset()
self.insertionMarker.moveTo(-75, 0, 0)
self.insertionMarker.drawTo(75, 0, 0)
self.insertionMarker.moveTo(0, -75, 0)
self.insertionMarker.drawTo(0, 75, 0)
self.insertionMarker.moveTo(0, 0, -75)
self.insertionMarker.drawTo(0, 0, 75)
self.insertionMarker.create()
def spawnInsertionMarkerTask(self):
taskMgr.add(self.insertionMarkerTask, 'insertionMarkerTask')
def insertionMarkerTask(self, state):
self.insertionMarker.setPosHpr(base.direct.grid, 0, 0, 0, 0, 0, 0)
# MRM: Why is this necessary?
self.insertionMarker.setScale(1, 1, 1)
return Task.cont
# UTILITY FUNCTIONS
def getRandomDictionaryEntry(self, dict):
numKeys = len(dict)
if numKeys > 0:
keys = dict.keys()
key = keys[randint(0, numKeys - 1)]
return dict[key]
else:
return None
def getRandomWindowCount(self):
if ((self.lastWall != None) and (self.lastBuilding != None)):
h = ROUND_INT(self.lastWall.getHeight())
w = ROUND_INT(self.lastBuilding.getWidth())
# Otherwise....
if w == 5:
# 5 ft walls can have 1 window
return 1
elif h == 10:
# All other 10 ft high bldgs can have 1 or 2
return randint(1, 2)
else:
# All others can have 1 - 4
return randint(1, 4)
else:
return 1
def autoPositionGrid(self, fLerp = 1):
taskMgr.remove('autoPositionGrid')
# Move grid to prepare for placement of next object
selectedNode = base.direct.selected.last
if selectedNode:
dnaNode = self.findDNANode(selectedNode)
if dnaNode == None:
return
nodeClass = DNAGetClassType(dnaNode)
deltaPos = Point3(20, 0, 0)
deltaHpr = VBase3(0)
if nodeClass.eq(DNA_FLAT_BUILDING):
deltaPos.setX(dnaNode.getWidth())
elif nodeClass.eq(DNA_STREET):
objectCode = dnaNode.getCode()
deltas = self.getNextSnapPoint()
deltaPos.assign(deltas[0])
deltaHpr.assign(deltas[1])
elif nodeClass.eq(DNA_LANDMARK_BUILDING):
objectCode = dnaNode.getCode()
if objectCode[-2:-1] == 'A':
deltaPos.setX(25.0)
elif objectCode[-2:-1] == 'B':
deltaPos.setX(15.0)
elif objectCode[-2:-1] == 'C':
deltaPos.setX(20.0)
if fLerp:
# Position grid for placing next object
# Eventually we need to setHpr too
t = base.direct.grid.lerpPosHpr(
deltaPos, deltaHpr, 0.25,
other = selectedNode,
blendType = 'easeInOut',
task = 'autoPositionGrid')
t.deltaPos = deltaPos
t.deltaHpr = deltaHpr
t.selectedNode = selectedNode
t.setUponDeath(self.autoPositionCleanup)
else:
base.direct.grid.setPosHpr(selectedNode, deltaPos, deltaHpr)
if self.mouseMayaCamera:
return
# Also move the camera
taskMgr.remove('autoMoveDelay')
handlesToCam = base.direct.widget.getPos(base.direct.camera)
handlesToCam = handlesToCam * (base.direct.dr.near/handlesToCam[1])
if ((abs(handlesToCam[0]) > (base.direct.dr.nearWidth * 0.4)) or
(abs(handlesToCam[2]) > (base.direct.dr.nearHeight * 0.4))):
taskMgr.remove('manipulateCamera')
base.direct.cameraControl.centerCamIn(0.5)
def autoPositionCleanup(self, state):
base.direct.grid.setPosHpr(state.selectedNode, state.deltaPos,
state.deltaHpr)
if base.direct.grid.getHprSnap():
# Clean up grid angle
base.direct.grid.setH(ROUND_TO(base.direct.grid.getH(),
base.direct.grid.snapAngle))
def getNextSnapPoint(self):
""" Pull next pos hpr deltas off of snap list then rotate list """
if self.snapList:
deltas = self.snapList[0]
# Rotate list by one
self.snapList = self.snapList[1:] + self.snapList[:1]
return deltas
else:
return (ZERO_VEC, ZERO_VEC)
def getWallIntersectionPoint(self, selectedNode):
"""
Return point of intersection between building's wall and line from cam
through mouse.
"""
# Find mouse point on near plane
mouseX = base.direct.dr.mouseX
mouseY = base.direct.dr.mouseY
nearX = (math.tan(deg2Rad(base.direct.dr.fovH)/2.0) *
mouseX * base.direct.dr.near)
nearZ = (math.tan(deg2Rad(base.direct.dr.fovV)/2.0) *
mouseY * base.direct.dr.near)
# Initialize points
mCam2Wall = base.direct.camera.getMat(selectedNode)
mouseOrigin = Point3(0)
mouseOrigin.assign(mCam2Wall.getRow3(3))
mouseDir = Vec3(0)
mouseDir.set(nearX, base.direct.dr.near, nearZ)
mouseDir.assign(mCam2Wall.xformVec(mouseDir))
# Calc intersection point
return planeIntersect(mouseOrigin, mouseDir, ZERO_POINT, NEG_Y_AXIS)
def getGridSnapIntersectionPoint(self):
"""
Return point of intersection between ground plane and line from cam
through mouse. Return false, if nothing selected. Snap to grid.
"""
return base.direct.grid.computeSnapPoint(self.getGridIntersectionPoint())
def getGridIntersectionPoint(self):
"""
Return point of intersection between ground plane and line from cam
through mouse. Return false, if nothing selected
"""
# Find mouse point on near plane
mouseX = base.direct.dr.mouseX
mouseY = base.direct.dr.mouseY
nearX = (math.tan(deg2Rad(base.direct.dr.fovH)/2.0) *
mouseX * base.direct.dr.near)
nearZ = (math.tan(deg2Rad(base.direct.dr.fovV)/2.0) *
mouseY * base.direct.dr.near)
# Initialize points
mCam2Grid = base.direct.camera.getMat(base.direct.grid)
mouseOrigin = Point3(0)
mouseOrigin.assign(mCam2Grid.getRow3(3))
mouseDir = Vec3(0)
mouseDir.set(nearX, base.direct.dr.near, nearZ)
mouseDir.assign(mCam2Grid.xformVec(mouseDir))
# Calc intersection point
return planeIntersect(mouseOrigin, mouseDir, ZERO_POINT, Z_AXIS)
def jumpToInsertionPoint(self):
""" Move selected object to insertion point """
selectedNode = base.direct.selected.last
if selectedNode:
# Check if its a dna node
dnaNode = self.findDNANode(selectedNode)
if dnaNode:
# Place the new node path at the current grid origin
selectedNode.setPos(base.direct.grid, 0, 0, 0)
# Initialize angle to match last object
selectedNode.setHpr(self.getLastAngle(), 0, 0)
# Now update DNA pos and hpr to reflect final pose
dnaNode.setPos(selectedNode.getPos())
dnaNode.setHpr(selectedNode.getHpr())
# Update grid to get ready for the next object
self.autoPositionGrid()
# CVS OPERATIONS
def cvsUpdate(self, filename):
dirname = os.path.dirname(filename)
if not os.path.isdir(dirname):
print 'Cannot CVS update %s: invalid directory' % (filename)
return
basename = os.path.basename(filename)
cwd = os.getcwd()
os.chdir(dirname)
cvsCommand = 'cvs update ' + basename
print cvsCommand
os.system(cvsCommand)
os.chdir(cwd)
def cvsAdd(self, filename):
dirname = os.path.dirname(filename)
if not os.path.isdir(dirname):
print 'Cannot CVS add %s: invalid directory' % (filename)
return
basename = os.path.basename(filename)
cwd = os.getcwd()
os.chdir(dirname)
cvsCommand = 'cvs add ' + basename
print cvsCommand
os.system(cvsCommand)
os.chdir(cwd)
def cvsUpdateAll(self):
# Update the entire dna source directory.
dirname = dnaDirectory.toOsSpecific()
if not os.path.isdir(dirname):
print 'Cannot CVS commit: invalid directory'
return
cwd = os.getcwd()
os.chdir(dirname)
cvsCommand = 'cvs update -dP'
print cvsCommand
os.system(cvsCommand)
os.chdir(cwd)
def cvsCommitAll(self):
# cvs commit always commits the entire dna source directory.
dirname = dnaDirectory.toOsSpecific()
if not os.path.isdir(dirname):
print 'Cannot CVS commit: invalid directory'
return
cwd = os.getcwd()
os.chdir(dirname)
cvsCommand = 'cvs commit -m "level editor"'
print cvsCommand
os.system(cvsCommand)
os.chdir(cwd)
# STYLE/DNA FILE FUNCTIONS
def loadSpecifiedDNAFile(self):
path = dnaDirectory.toOsSpecific()
if not os.path.isdir(path):
print 'LevelEditor Warning: Invalid default DNA directory!'
print 'Using current directory'
path = '.'
dnaFilename = askopenfilename(
defaultextension = '.dna',
filetypes = (('DNA Files', '*.dna'), ('All files', '*')),
initialdir = path,
title = 'Load DNA File',
parent = self.panel.component('hull'))
if dnaFilename:
self.loadDNAFromFile(dnaFilename)
self.outputFile = dnaFilename
print "Finished Load: ", dnaFilename
def saveToSpecifiedDNAFile(self):
path = dnaDirectory.toOsSpecific()
if not os.path.isdir(path):
print 'LevelEditor Warning: Invalid DNA save directory!'
print 'Using current directory'
path = '.'
dnaFilename = asksaveasfilename(
defaultextension = '.dna',
filetypes = (('DNA Files', '*.dna'), ('All files', '*')),
initialdir = path,
title = 'Save DNA File as',
parent = self.panel.component('hull'))
if dnaFilename:
self.outputDNA(dnaFilename)
self.outputFile = dnaFilename
def loadDNAFromFile(self, filename):
print filename
# Reset level, destroying existing scene/DNA hierarcy
self.reset(fDeleteToplevel = 1, fCreateToplevel = 0,
fUpdateExplorer = 0)
# Now load in new file
if fUseCVS:
self.cvsUpdate(filename)
try:
node = loadDNAFile(DNASTORE, Filename.fromOsSpecific(filename).cStr(), CSDefault, 1)
except Exception:
self.notify.debug("Couldn't load specified DNA file. Please make sure storage code has been specified in Config.prc file")
if node.getNumParents() == 1:
# If the node already has a parent arc when it's loaded, we must
# be using the level editor and we want to preserve that arc.
newNPToplevel = NodePath(node)
newNPToplevel.reparentTo(hidden)
else:
# Otherwise, we should create a new arc for the node.
newNPToplevel = hidden.attachNewNode(node)
# Make sure the topmost file DNA object gets put under DNARoot
newDNAToplevel = self.findDNANode(newNPToplevel)
# reset the landmark block number:
(self.landmarkBlock, needTraverse)=self.findHighestLandmarkBlock(
newDNAToplevel, newNPToplevel)
# Update toplevel variables
if needTraverse:
self.createToplevel(newDNAToplevel)
else:
self.createToplevel(newDNAToplevel, newNPToplevel)
# Create visible representations of all the paths and battle cells
self.createSuitPaths()
self.hideSuitPaths()
self.createBattleCells()
self.hideBattleCells()
# Set the title bar to have the filename to make it easier
# to remember what file you are working on
self.panel["title"] = 'Level Editor: ' + os.path.basename(filename)
self.panel.sceneGraphExplorer.update()
def outputDNADefaultFile(self):
outputFile = self.outputFile
if outputFile == None:
outputFile = self.neighborhood + '_working.dna'
file = os.path.join(dnaDirectory.toOsSpecific(), outputFile)
self.outputDNA(file)
def outputDNA(self, filename):
print 'Saving DNA to: ', filename
binaryFilename = Filename(filename)
binaryFilename.setBinary()
self.DNAData.writeDna(binaryFilename, Notify.out(), DNASTORE)
def saveColor(self):
self.appendColorToColorPaletteFile(self.panel.colorEntry.get())
def appendColorToColorPaletteFile(self, color):
obj = self.DNATarget
if obj:
classType = DNAGetClassType(obj)
if classType.eq(DNA_WALL):
tag = 'wall_color:'
elif classType.eq(DNA_WINDOWS):
tag = 'window_color:'
elif classType.eq(DNA_DOOR):
tag = 'door_color:'
elif classType.eq(DNA_FLAT_DOOR):
tag = 'door_color:'
elif classType.eq(DNA_CORNICE):
tag = 'cornice_color:'
elif classType.eq(DNA_PROP):
tag = 'prop_color:'
else:
return
# Valid type, add color to file
filename = self.neighborhood + '_colors.txt'
fname = Filename(dnaDirectory.getFullpath() +
'/stylefiles/' + filename)
f = open(fname.toOsSpecific(), 'ab')
f.write('%s Vec4(%.2f, %.2f, %.2f, 1.0)\n' %
(tag,
color[0]/255.0,
color[1]/255.0,
color[2]/255.0))
f.close()
def saveStyle(self, filename, style):
# A generic routine to append a new style definition to one of
# the style files.
fname = Filename(dnaDirectory.getFullpath() +
'/stylefiles/' + filename)
# We use binary mode to avoid Windows' end-of-line convention
f = open(fname.toOsSpecific(), 'ab')
# Add a blank line
f.write('\n')
# Now output style details to file
style.output(f)
# Close the file
f.close()
def saveBaselineStyle(self):
if self.panel.currentBaselineDNA:
# Valid baseline, add style to file
filename = self.neighborhood + '_baseline_styles.txt'
style = DNABaselineStyle(self.panel.currentBaselineDNA)
self.saveStyle(filename, style)
def saveWallStyle(self):
if self.lastWall:
# Valid wall, add style to file
filename = self.neighborhood + '_wall_styles.txt'
style = DNAWallStyle(self.lastWall)
self.saveStyle(filename, style)
def saveBuildingStyle(self):
dnaObject = self.selectedDNARoot
if dnaObject:
if DNAClassEqual(dnaObject, DNA_FLAT_BUILDING):
# Valid wall, add style to file
filename = self.neighborhood + '_building_styles.txt'
style = DNAFlatBuildingStyle(dnaObject)
self.saveStyle(filename, style)
return
print 'Must select building before saving building style'
# GET/SET
# DNA Object elements
def getWall(self, dnaFlatBuilding, wallNum):
wallCount = 0
for i in range(dnaFlatBuilding.getNumChildren()):
child = dnaFlatBuilding.at(i)
if DNAClassEqual(child, DNA_WALL):
if wallCount == wallNum:
return child
wallCount = wallCount + 1
# Not found
return None
def computeWallNum(self, aDNAFlatBuilding, hitPt):
"""
Given a hitPt, return wall number if cursor is over building
Return -1 if cursor is outside of building
"""
xPt = hitPt[0]
zPt = hitPt[2]
# Left or right of building
if ((xPt < 0) or (xPt > aDNAFlatBuilding.getWidth())):
return -1
# Below the building
if zPt < 0:
return -1
# Above z = 0 and within wall width, check height of walls
heightList, offsetList = DNAGetWallHeights(aDNAFlatBuilding)
wallNum = 0
for i in range(len(heightList)):
# Compute top of wall segment
top = offsetList[i] + heightList[i]
if zPt < top:
return wallNum
wallNum = wallNum + 1
return -1
def getWindowCount(self, dnaWall):
windowCount = 0
for i in range(dnaWall.getNumChildren()):
child = dnaWall.at(i)
if DNAClassEqual(child, DNA_WINDOWS):
windowCount = windowCount + 1
# Not found
return windowCount
# Style manager edit mode
def setEditMode(self, neighborhood):
self.neighborhood = neighborhood
self.neighborhoodCode = NEIGHBORHOOD_CODES[self.neighborhood]
if neighborhood == 'toontown_central':
self.outputDir = 'ToontownCentral'
elif neighborhood == 'donalds_dock':
self.outputDir = 'DonaldsDock'
elif neighborhood == 'minnies_melody_land':
self.outputDir = 'MinniesMelodyLand'
elif neighborhood == 'the_burrrgh':
self.outputDir = 'TheBurrrgh'
elif neighborhood == 'daisys_garden':
self.outputDir = 'DaisysGarden'
elif neighborhood == 'donalds_dreamland':
self.outputDir = 'DonaldsDreamland'
self.panel.editMenu.selectitem(neighborhood)
self.styleManager.setEditMode(neighborhood)
self.panel.updateHeightList(self.getCurrent('building_height'))
self.selectMap(neighborhood)
def getEditMode(self):
return self.styleManager.getEditMode()
# Level Style Attributes
def __getitem__(self, attribute):
""" Return top level entry in attribute dictionary """
return self.styleManager.attributeDictionary[attribute]
def getAttribute(self, attribute):
""" Return specified attribute for current neighborhood """
return self.styleManager.getAttribute(attribute)
def hasAttribute(self, attribute):
""" Return specified attribute for current neighborhood """
return self.styleManager.hasAttribute(attribute)
def getCurrent(self, attribute):
""" Return neighborhood's current selection for specified attribute """
return self.getAttribute(attribute).getCurrent()
def setCurrent(self, attribute, newCurrent):
""" Set neighborhood's current selection for specified attribute """
self.getAttribute(attribute).setCurrent(newCurrent, fEvent = 0)
def getMenu(self, attribute):
""" Return neighborhood's Pie Menu object for specified attribute """
return self.getAttribute(attribute).getMenu()
def getDict(self, attribute):
""" Return neighborhood's Dictionary for specified attribute """
return self.getAttribute(attribute).getDict()
def getList(self, attribute):
""" Return neighborhood's List for specified attribute """
return self.getAttribute(attribute).getList()
# DNA variables
def getDNAData(self):
return self.DNAData
def getDNAToplevel(self):
return self.DNAToplevel
def getDNAParent(self):
return self.DNAParent
def getDNATarget(self):
return self.DNATarget
# Node Path variables
def getNPToplevel(self):
return self.NPToplevel
def getNPParent(self):
return self.NPParent
# Count of groups added to level
def setGroupNum(self, num):
self.groupNum = num
def getGroupNum(self):
return self.groupNum
# Angle of last object added to level
def setLastAngle(self, angle):
self.lastAngle = angle
def getLastAngle(self):
return self.lastAngle
def drawSuitEdge(self, edge, parent):
# Draw a line from start to end
edgeLine = LineNodePath(parent)
edgeLine.lineNode.setName('suitEdge')
edgeLine.setColor(VBase4(0.0, 0.0, 0.5, 1))
edgeLine.setThickness(1)
edgeLine.reset()
# We need to draw the arrow relative to the parent, but the
# point positions are relative to the NPToplevel. So get the
# start and end positions relative to the parent, then draw
# the arrow using those points
tempNode = self.NPToplevel.attachNewNode('tempNode')
mat = self.NPToplevel.getMat(parent)
relStartPos = Point3(mat.xformPoint(edge.getStartPoint().getPos()))
relEndPos = Point3(mat.xformPoint(edge.getEndPoint().getPos()))
# Compute offset: a vector rotated 90 degrees clockwise
offset = Vec3(relEndPos - relStartPos)
offset.normalize()
offset *= 0.1
a = offset[0]
offset.setX(offset[1])
offset.setY(-1 * a)
# Just to get it above the street
offset.setZ(0.05)
# Add offset to start and end to help differentiate lines
relStartPos += offset
relEndPos += offset
# Draw arrow
edgeLine.drawArrow(relStartPos,
relEndPos,
15, # arrow angle
1) # arrow length
edgeLine.create()
# Add a clickable sphere
marker = self.suitPointMarker.copyTo(edgeLine)
marker.setName('suitEdgeMarker')
midPos = (relStartPos + relEndPos)/2.0
marker.setPos(midPos)
# Adjust color of highlighted lines
if edge in self.visitedEdges:
NodePath.setColor(edgeLine, 1, 0, 0, 1)
# Clean up:
tempNode.removeNode()
return edgeLine
def drawSuitPoint(self, suitPoint, pos, type, parent):
marker = self.suitPointMarker.copyTo(parent)
marker.setName("suitPointMarker")
marker.setPos(pos)
if (type == DNASuitPoint.STREETPOINT):
marker.setColor(0, 0, 0.6)
marker.setScale(0.4)
elif (type == DNASuitPoint.FRONTDOORPOINT):
marker.setColor(0, 0, 1)
marker.setScale(0.5)
elif (type == DNASuitPoint.SIDEDOORPOINT):
marker.setColor(0, 0.6, 0.2)
marker.setScale(0.5)
# Highlight if necessary
if suitPoint in self.visitedPoints:
marker.setColor(1, 0, 0, 1)
return marker
def placeSuitPoint(self):
v = self.getGridSnapIntersectionPoint()
# get the absolute pos relative to the top level.
# That is what gets stored in the point
mat = base.direct.grid.getMat(self.NPToplevel)
absPos = Point3(mat.xformPoint(v))
print 'Suit point: ' + `absPos`
# Store the point in the DNA. If this point is already in there,
# it returns the existing point
suitPoint = DNASTORE.storeSuitPoint(self.currentSuitPointType, absPos)
print "placeSuitPoint: ", suitPoint
# In case the point returned is a different type, update our type
self.currentSuitPointType = suitPoint.getPointType()
if not self.pointDict.has_key(suitPoint):
marker = self.drawSuitPoint(suitPoint,
absPos, self.currentSuitPointType,
self.suitPointToplevel)
self.pointDict[suitPoint] = marker
self.currentSuitPointIndex = suitPoint.getIndex()
if self.startSuitPoint:
self.endSuitPoint = suitPoint
# Make a new dna edge
if DNAClassEqual(self.DNAParent, DNA_VIS_GROUP):
zoneId = self.DNAParent.getName()
suitEdge = DNASuitEdge(
self.startSuitPoint, self.endSuitPoint, zoneId)
DNASTORE.storeSuitEdge(suitEdge)
# Add edge to the current vis group so it can be written out
self.DNAParent.addSuitEdge(suitEdge)
# Draw a line to represent the edge
edgeLine = self.drawSuitEdge(suitEdge, self.NPParent)
# Store the line in a dict so we can hide/show them
self.edgeDict[suitEdge] = edgeLine
self.np2EdgeDict[edgeLine.id()] = [suitEdge, self.DNAParent]
# Store the edge on each point in case we move the point
# we can update the edge
for point in [self.startSuitPoint, self.endSuitPoint]:
if self.point2edgeDict.has_key(point):
self.point2edgeDict[point].append(suitEdge)
else:
self.point2edgeDict[point] = [suitEdge]
# If this is a building point, you need edges in both directions
# so just make the other edge automatically
if ((self.startSuitPoint.getPointType() == DNASuitPoint.FRONTDOORPOINT)
or (self.startSuitPoint.getPointType() == DNASuitPoint.SIDEDOORPOINT)):
suitEdge = DNASuitEdge(
self.endSuitPoint, self.startSuitPoint, zoneId)
DNASTORE.storeSuitEdge(suitEdge)
# Add edge to the current vis group so it can be written out
self.DNAParent.addSuitEdge(suitEdge)
# Draw a line to represent the edge
edgeLine = self.drawSuitEdge(suitEdge, self.NPParent)
# Store the line in a dict so we can hide/show them
self.edgeDict[suitEdge] = edgeLine
self.np2EdgeDict[edgeLine.id()] = [suitEdge, self.DNAParent]
for point in [self.startSuitPoint, self.endSuitPoint]:
if self.point2edgeDict.has_key(point):
self.point2edgeDict[point].append(suitEdge)
else:
self.point2edgeDict[point] = [suitEdge]
print 'Added dnaSuitEdge to zone: ' + zoneId
else:
print 'Error: DNAParent is not a dnaVisGroup. Did not add edge'
# Reset
self.startSuitPoint = None
self.endSuitPoint = None
else:
# First point, store it
self.startSuitPoint = suitPoint
def highlightConnected(self, nodePath = None, fReversePath = 0):
if nodePath == None:
nodePath = base.direct.selected.last
if nodePath:
suitPoint = self.findPointOrCell(nodePath)[0]
if suitPoint:
self.clearPathHighlights()
self.highlightConnectedRec(suitPoint, fReversePath)
def highlightConnectedRec(self, suitPoint, fReversePath):
nodePath = self.pointDict.get(suitPoint, None)
if nodePath:
# highlight marker
nodePath.setColor(1, 0, 0, 1)
# Add point to visited points
self.visitedPoints.append(suitPoint)
# highlight connected edges
for edge in self.point2edgeDict[suitPoint]:
if ((fReversePath or (suitPoint == edge.getStartPoint())) and
(edge not in self.visitedEdges)):
edgeLine = self.edgeDict[edge]
# Call node path not LineNodePath setColor
NodePath.setColor(edgeLine, 1, 0, 0, 1)
# Add edge to visited edges
self.visitedEdges.append(edge)
# Color components connected to the edge
if fReversePath:
startPoint = edge.getStartPoint()
if startPoint not in self.visitedPoints:
self.highlightConnectedRec(startPoint,
fReversePath)
endPoint = edge.getEndPoint()
type = endPoint.getPointType()
if ((endPoint not in self.visitedPoints) and
(fReversePath or (type == DNASuitPoint.STREETPOINT))):
self.highlightConnectedRec(endPoint,
fReversePath)
def clearPathHighlights(self):
for point in self.pointDict.keys():
type = point.getPointType()
marker = self.pointDict[point]
if (type == DNASuitPoint.STREETPOINT):
marker.setColor(0, 0, 0.6)
elif (type == DNASuitPoint.FRONTDOORPOINT):
marker.setColor(0, 0, 1)
elif (type == DNASuitPoint.SIDEDOORPOINT):
marker.setColor(0, 0.6, 0.2)
for edge in self.edgeDict.values():
edge.clearColor()
self.visitedPoints = []
self.visitedEdges = []
def drawBattleCell(self, cell, parent):
marker = self.battleCellMarker.copyTo(parent)
# Greenish
marker.setColor(0.25, 0.75, 0.25, 0.5)
marker.setTransparency(1)
marker.setPos(cell.getPos())
# scale to radius which is width/2
marker.setScale(cell.getWidth()/2.0,
cell.getHeight()/2.0,
1)
return marker
def placeBattleCell(self):
# Store the battle cell in the current vis group
if not DNAClassEqual(self.DNAParent, DNA_VIS_GROUP):
print 'Error: DNAParent is not a dnaVisGroup. Did not add battle cell'
return
v = self.getGridSnapIntersectionPoint()
mat = base.direct.grid.getMat(self.NPParent)
absPos = Point3(mat.xformPoint(v))
if (self.currentBattleCellType == '20w 20l'):
cell = DNABattleCell(20, 20, absPos)
elif (self.currentBattleCellType == '20w 30l'):
cell = DNABattleCell(20, 30, absPos)
elif (self.currentBattleCellType == '30w 20l'):
cell = DNABattleCell(30, 20, absPos)
elif (self.currentBattleCellType == '30w 30l'):
cell = DNABattleCell(30, 30, absPos)
# Store the battle cell in the storage
DNASTORE.storeBattleCell(cell)
# Draw the battle cell
marker = self.drawBattleCell(cell, self.NPParent)
# Keep a handy dict of the visible markers
self.cellDict[cell] = marker
# Store the battle cell in the current vis group
self.DNAParent.addBattleCell(cell)
def createSuitPaths(self):
# Points
numPoints = DNASTORE.getNumSuitPoints()
for i in range(numPoints):
point = DNASTORE.getSuitPointAtIndex(i)
marker = self.drawSuitPoint(point,
point.getPos(), point.getPointType(),
self.suitPointToplevel)
self.pointDict[point] = marker
# Edges
visGroups = self.getDNAVisGroups(self.NPToplevel)
for visGroup in visGroups:
np = visGroup[0]
dnaVisGroup = visGroup[1]
numSuitEdges = dnaVisGroup.getNumSuitEdges()
for i in range(numSuitEdges):
edge = dnaVisGroup.getSuitEdge(i)
edgeLine = self.drawSuitEdge(edge, np)
self.edgeDict[edge] = edgeLine
self.np2EdgeDict[edgeLine.id()] = [edge, dnaVisGroup]
# Store the edge on each point in case we move the point
# we can update the edge
for point in [edge.getStartPoint(), edge.getEndPoint()]:
if self.point2edgeDict.has_key(point):
self.point2edgeDict[point].append(edge)
else:
self.point2edgeDict[point] = [edge]
def getSuitPointFromNodePath(self, nodePath):
"""
Given a node path, attempt to find the point, nodePath pair
in the pointDict. If it is there, return the point. If we
cannot find it, return None.
TODO: a reverse lookup pointDict would speed this up quite a bit
"""
for point, marker in self.pointDict.items():
if marker.eq(nodePath):
return point
return None
def resetPathMarkers(self):
for edge, edgeLine in self.edgeDict.items():
if not edgeLine.isEmpty():
edgeLine.reset()
edgeLine.removeNode()
self.edgeDict = {}
self.np2EdgeDict = {}
for point, marker in self.pointDict.items():
if not marker.isEmpty():
marker.removeNode()
self.pointDict = {}
def hideSuitPaths(self):
for edge, edgeLine in self.edgeDict.items():
edgeLine.hide()
for point, marker in self.pointDict.items():
marker.hide()
def showSuitPaths(self):
for edge, edgeLine in self.edgeDict.items():
edgeLine.show()
for point, marker in self.pointDict.items():
marker.show()
def createBattleCells(self):
# Edges
visGroups = self.getDNAVisGroups(self.NPToplevel)
for visGroup in visGroups:
np = visGroup[0]
dnaVisGroup = visGroup[1]
numCells = dnaVisGroup.getNumBattleCells()
for i in range(numCells):
cell = dnaVisGroup.getBattleCell(i)
marker = self.drawBattleCell(cell, np)
self.cellDict[cell] = marker
def resetBattleCellMarkers(self):
for cell, marker in self.cellDict.items():
if not marker.isEmpty():
marker.remove()
self.cellDict = {}
def hideBattleCells(self):
for cell, marker in self.cellDict.items():
marker.hide()
def showBattleCells(self):
for cell, marker in self.cellDict.items():
marker.show()
def getBattleCellFromNodePath(self, nodePath):
"""
Given a node path, attempt to find the battle cell, nodePath pair
in the cellDict. If it is there, return the cell. If we
cannot find it, return None.
TODO: a reverse lookup cellDict would speed this up quite a bit
"""
for cell, marker in self.cellDict.items():
if marker.eq(nodePath):
return cell
return None
def toggleZoneColors(self):
if self.panel.zoneColor.get():
self.colorZones()
else:
self.clearZoneColors()
def colorZones(self):
# Give each zone a random color to see them better
visGroups = self.getDNAVisGroups(self.NPToplevel)
for visGroup in visGroups:
np = visGroup[0]
np.setColor(0.5 + random()/2.0,
0.5 + random()/2.0,
0.5 + random()/2.0)
def clearZoneColors(self):
# Clear random colors
visGroups = self.getDNAVisGroups(self.NPToplevel)
for visGroup in visGroups:
np = visGroup[0]
np.clearColor()
def labelZones(self):
# Label each zone
# First clear out old labels if any
self.clearZoneLabels()
visGroups = self.getDNAVisGroups(self.NPToplevel)
from direct.gui import DirectGui
for np, dna in visGroups:
name = dna.getName()
label = DirectGui.DirectLabel(text = name,
parent = np.getParent(),
relief = None, scale = 3)
label.setBillboardPointEye(0)
center = np.getBounds().getCenter()
label.setPos(center[0], center[1], .1)
self.zoneLabels.append(label)
def clearZoneLabels(self):
for label in self.zoneLabels:
label.removeNode()
self.zoneLabels = []
def getBlockFromName(self, name):
block=name[2:name.find(':')]
return block
def addToLandmarkBlock(self):
dnaRoot=self.selectedDNARoot
if dnaRoot and self.lastLandmarkBuildingDNA:
if DNAClassEqual(dnaRoot, DNA_FLAT_BUILDING):
n=dnaRoot.getName()
n=n[n.find(':'):]
block=self.lastLandmarkBuildingDNA.getName()
block=block[2:block.find(':')]
dnaRoot.setName('tb'+block+n)
self.replaceSelected()
# If we're highlighting the landmark blocks:
if self.showLandmarkBlockToggleGroup:
# then highlight this one:
np=self.selectedNPRoot
self.showLandmarkBlockToggleGroup.append(np)
np.setColor(1, 0, 0, 1)
elif self.selectedSuitPoint and self.lastLandmarkBuildingDNA:
block=self.lastLandmarkBuildingDNA.getName()
block=block[2:block.find(':')]
print ("associate point with building: " + str(block))
self.selectedSuitPoint.setLandmarkBuildingIndex(int(block))
marker = self.pointDict[self.selectedSuitPoint]
marker.setColor(1, 0, 0, 1)
marker.setScale(1.0)
def findHighestLandmarkBlock(self, dnaRoot, npRoot):
npc=npRoot.findAllMatches("**/*:toon_landmark_*")
highest=0
for i in range(npc.getNumPaths()):
path=npc.getPath(i)
block=path.getName()
block=int(block[2:block.find(':')])
if (block > highest):
highest=block
# Make a list of flat building names, outside of the
# recursive function:
self.flatNames=['random'] + BUILDING_TYPES
self.flatNames=map(lambda n: n+'_DNARoot', self.flatNames)
# Search/recurse the dna:
newHighest=self.convertToLandmarkBlocks(highest, dnaRoot)
# Get rid of the list of flat building names:
del self.flatNames
needToTraverse = (highest!=newHighest)
return (newHighest, needToTraverse)
def convertToLandmarkBlocks(self, block, dnaRoot):
"""
Find all the buildings without landmark blocks and
assign them one.
"""
for i in range(dnaRoot.getNumChildren()):
child = dnaRoot.at(i)
if DNAClassEqual(child, DNA_LANDMARK_BUILDING):
# Landmark buildings:
name=child.getName()
if name.find('toon_landmark_')==0:
block=block+1
child.setName('tb'+str(block)+':'+name)
elif DNAClassEqual(child, DNA_FLAT_BUILDING):
# Flat buildings:
name=child.getName()
if (name in self.flatNames):
child.setName('tb0:'+name)
else:
block = self.convertToLandmarkBlocks(block, child)
return block
def revertLandmarkBlock(self, block):
"""
un-block flat buildings (set them to block zero).
"""
npc=self.NPToplevel.findAllMatches("**/tb"+block+":*_DNARoot")
for i in range(npc.getNumPaths()):
nodePath=npc.getPath(i)
name=nodePath.getName()
if name[name.find(':'):][:15] != ':toon_landmark_':
name='tb0'+name[name.find(':'):]
dna=self.findDNANode(nodePath)
dna.setName(name)
nodePath=self.replace(nodePath, dna)
# If we're highlighting the landmark blocks:
if self.showLandmarkBlockToggleGroup:
# then highlight this one:
self.showLandmarkBlockToggleGroup.append(nodePath)
nodePath.setColor(0, 1, 0, 1)
def landmarkBlockRemove(self, dna, nodePath):
if dna:
name=dna.getName()
# Get the underscore index within the name:
usIndex=name.find(':')
if name[usIndex:][:15] == ':toon_landmark_':
block=name[2:usIndex]
self.lastLandmarkBuildingDNA=None
self.revertLandmarkBlock(block)
def toggleShowLandmarkBlock(self):
dna=self.lastLandmarkBuildingDNA
if dna:
if not self.showLandmarkBlockToggleGroup:
group=[]
block=dna.getName()
block=block[2:block.find(':')]
# Get current landmark buildings:
npc=self.NPToplevel.findAllMatches("**/tb"+block+":*_DNARoot")
for i in range(npc.getNumPaths()):
nodePath=npc.getPath(i)
group.append(nodePath)
nodePath.setColor(1, 0, 0, 1)
# Get block zero buildings (i.e. non-blocked):
npc=self.NPToplevel.findAllMatches("**/tb0:*_DNARoot")
for i in range(npc.getNumPaths()):
nodePath=npc.getPath(i)
group.append(nodePath)
nodePath.setColor(0, 1, 0, 1)
# Get the suit point for this lb
for point, marker in self.pointDict.items():
if ((point.getPointType() == DNASuitPoint.FRONTDOORPOINT)
or (point.getPointType() == DNASuitPoint.SIDEDOORPOINT)):
lbIndex = point.getLandmarkBuildingIndex()
if (lbIndex == int(block)):
marker.setColor(1, 0, 0, 1)
marker.setScale(1.0)
# There should only be one, so break now
elif (lbIndex == -1):
# This point belongs to no block
marker.setColor(0, 1, 0, 1)
self.showLandmarkBlockToggleGroup=group
else:
for i in self.showLandmarkBlockToggleGroup:
i.clearColor()
for point, marker in self.pointDict.items():
if (point.getPointType() == DNASuitPoint.FRONTDOORPOINT):
marker.setColor(0, 0, 1, 1)
marker.setScale(0.5)
elif (point.getPointType() == DNASuitPoint.SIDEDOORPOINT):
marker.setColor(0, 0.6, 0.2, 1)
marker.setScale(0.5)
self.showLandmarkBlockToggleGroup=None
def pdbBreak(self):
pdb.set_trace()
def reparentStreetBuildings(self, nodePath):
dnaNode = self.findDNANode(nodePath)
if dnaNode:
if (DNAClassEqual(dnaNode, DNA_FLAT_BUILDING) or
DNAClassEqual(dnaNode, DNA_LANDMARK_BUILDING)):
base.direct.reparent(nodePath, fWrt = 1)
children = nodePath.getChildren()
for child in children:
self.reparentStreetBuildings(child)
def consolidateStreetBuildings(self):
# First put everything under the ATR group so the leftover
# can be easily deleted
originalChildren = self.NPToplevel.getChildren()
self.addGroup(self.NPToplevel)
atrGroup = self.NPParent
atrGroup.setName('ATR')
self.setName(atrGroup, 'ATR')
base.direct.setActiveParent(atrGroup)
for child in originalChildren:
base.direct.reparent(child)
# Now create a new group with just the buildings
self.addGroup(self.NPToplevel)
newGroup = self.NPParent
newGroup.setName('LongStreet')
self.setName(newGroup, 'LongStreet')
base.direct.setActiveParent(newGroup)
self.reparentStreetBuildings(self.NPToplevel)
return newGroup
def makeNewBuildingGroup(self, sequenceNum, side, curveName):
print "-------------------------- new building group %s curveName=%s------------------------" % (sequenceNum, curveName)
# Now create a new group with just the buildings
self.addGroup(self.NPToplevel)
newGroup = self.NPParent
groupName = ''
#if curveName == "urban_curveside_inner_1_1":
# import pdb; pdb.set_trace()
if 'curveside' in curveName:
#we want to preserve which group the side street is closest to
print "special casing %s" % curveName
parts = curveName.split('_')
groupName = 'Buildings_' + side + "-" + parts[3] + "_" + parts[4]
print "groupname = %s" % groupName
else:
groupName = 'Buildings_' + side + "-" + str(sequenceNum)
newGroup.setName(groupName)
self.setName(newGroup, groupName)
base.direct.setActiveParent(newGroup)
if 'barricade_curve' in curveName:
parts = curveName.split('_')
origBarricadeNum = parts[3]
self.updateBarricadeDict(side, int(origBarricadeNum), sequenceNum)
def adjustPropChildren(self, nodePath, maxPropOffset = -4):
for np in nodePath.getChildren():
dnaNode = self.findDNANode(np)
if dnaNode:
if DNAClassEqual(dnaNode, DNA_PROP):
if np.getY() < maxPropOffset:
np.setY(maxPropOffset)
self.updateSelectedPose([np])
def getBuildingWidth(self, bldg):
dnaNode = self.findDNANode(bldg)
bldgWidth = 0
if DNAClassEqual(dnaNode, DNA_FLAT_BUILDING):
bldgWidth = dnaNode.getWidth()
elif DNAClassEqual(dnaNode, DNA_LANDMARK_BUILDING):
objectCode = dnaNode.getCode()
if objectCode[-2:-1] == 'A':
bldgWidth = 25.0
elif objectCode[-2:-1] == 'B':
bldgWidth = 15.0
elif objectCode[-2:-1] == 'C':
bldgWidth = 20.0
return bldgWidth
def calcLongStreetLength(self, bldgs):
streetLength = 0
for bldg in bldgs:
streetLength += self.getBuildingWidth(bldg)
return streetLength
def addStreetUnits(self, streetLength):
base.direct.grid.setPosHpr(0, -40, 0, 0, 0, 0)
currLength = 0
while (currLength < streetLength):
self.addStreet('street_80x40')
currLength += 80
def makeLongStreet(self):
bldgGroup = self.consolidateStreetBuildings()
bldgs = bldgGroup.getChildren()
numBldgs = len(bldgs)
streetLength = self.calcLongStreetLength(bldgs)/2.0
ref = None
base.direct.grid.fXyzSnap = 0
currLength = 0
for i in range(numBldgs):
bldg = bldgs[i]
if ref == None:
base.direct.grid.iPosHpr(bldgGroup)
else:
ref.select()
self.autoPositionGrid(fLerp = 0)
if base.direct.grid.getX() >= streetLength:
base.direct.grid.setPosHpr(base.direct.grid, 0, -40, 0, 180, 0, 0)
bldg.iPosHpr(base.direct.grid)
self.updateSelectedPose([bldg])
self.adjustPropChildren(bldg)
ref = bldg
self.addStreetUnits(streetLength)
def loadStreetCurve(self):
path = '.'
streetCurveFilename = askopenfilename(
defaultextension = '.egg',
filetypes = (('Egg files', '*.egg'),
('Bam files', '*.bam'),
('Maya files', '*.mb'),
('All files', '*')),
initialdir = path,
title = 'Load Curve File',
parent = self.panel.component('hull'))
if streetCurveFilename:
modelFile = loader.loadModel(Filename.fromOsSpecific(streetCurveFilename))
#curves = modelFile.findAllMatches('**/+ClassicNurbsCurve')
curves = {'inner':[], 'outer':[],'innersidest':[], 'outersidest':[]}
curvesInner = modelFile.findAllMatches('**/*curve_inner*')
print("-------------- curvesInner-----------------")
print curvesInner
curvesOuter = modelFile.findAllMatches('**/*curve_outer*')
print("---------------- curvesOuter---------------")
print curvesOuter
curveInnerSideSts = modelFile.findAllMatches('**/*curveside_inner*')
print("--------- curveInnerSideSts----------")
print curveInnerSideSts
curveOuterSideSts = modelFile.findAllMatches('**/*curveside_outer*')
print("----------- curveOuterSideSits ----------")
print curveOuterSideSts
# return an ordered list
for i in range(len(curvesInner) +1): #RAU don't forget, these curves are 1 based
curve = modelFile.find('**/*curve_inner_'+str(i))
if not curve.isEmpty():
# Mark whether it is a section of buildings or trees
curveType = curve.getName().split("_")[0]
curves['inner'].append([curve.node(), curveType])
for i in range(len(curvesOuter) +1):
curve = modelFile.find('**/*curve_outer_'+str(i))
if not curve.isEmpty():
# Mark whether it is a section of buildings or trees
curveType = curve.getName().split("_")[0]
curves['outer'].append([curve.node(), curveType])
maxNum = len(curvesInner)
if len(curvesOuter) > maxNum:
maxNum = len(curvesOuter)
maxNum += 2; #track ends in a barricade, and add 1 since 1 based
#RAU also do special processing for the side streets
# side streets are numbered differently and could be non consecutive
# curveside_inner_28_1, curveside_outer_28_1, curveside_inner_28_2,
# curveside_outer_28_2 (two side streets closest to main building track 28)
for i in range(maxNum):
for barricade in ['innerbarricade','outerbarricade']:
curve = modelFile.find('**/*curveside_inner_'+ barricade + '_' + str(i))
if not curve.isEmpty():
# Mark whether it is a section of buildings or trees
curveType = curve.getName().split("_")[0]
curves['innersidest'].append([curve.node(), curveType])
print "adding innersidest %s" % curve.getName()
for i in range(maxNum):
for barricade in ['innerbarricade','outerbarricade']:
curve = modelFile.find('**/*curveside_outer_'+ barricade + '_' + str(i))
if not curve.isEmpty():
# Mark whether it is a section of buildings or trees
curveType = curve.getName().split("_")[0]
curves['outersidest'].append([curve.node(), curveType])
print "adding outersidest %s" % curve.getName()
print "loaded curves: %s" % curves
return curves
else:
return None
def duplicateFlatBuilding(self, oldDNANode):
# Yes, make a new copy of the dnaNode
print "a"
dnaNode = oldDNANode.__class__(oldDNANode)
print "b"
dnaNode.setWidth(oldDNANode.getWidth())
# Add the DNA to the active parent
print "c"
self.DNAParent.add(dnaNode)
# And create the geometry
print "d %s" % (oldDNANode)
newNodePath = dnaNode.traverse(self.NPParent, DNASTORE, 1)
print "e"
return newNodePath
def getBldg(self, bldgIndex, bldgs, forceDuplicate = False):
numBldgs = len(bldgs)
if bldgIndex < numBldgs and not forceDuplicate:
# Use original
print "using original bldg"
bldg = bldgs[bldgIndex]
bldgIndex += 1
else:
# Make a copy
oldBldg = bldgs[bldgIndex % numBldgs]
bldgIndex += 1
oldBldg.select()
oldDNANode = self.findDNANode(oldBldg)
nodeClass = DNAGetClassType(oldDNANode)
if nodeClass.eq(DNA_LANDMARK_BUILDING):
print "making landmark copy"
# Remove white and dark grey doors from color list
colorList = self.getAttribute('door_color').getList()
colorList = colorList[1:3] + colorList[4:len(colorList)]
# Set a random door color
doorColor = random.choice(colorList)
self.setCurrent('door_color', doorColor)
self.addLandmark(oldDNANode.getCode(), oldDNANode.getBuildingType())
bldg = self.lastNodePath
else:
print "making flatbuilding copy"
bldg = self.duplicateFlatBuilding(oldDNANode)
return bldg, bldgIndex
def updateBarricadeDict(self, side, barricadeOrigNum, curBldgGroupIndex):
barricadeDict = None
if (side == 'outer'):
barricadeDict = self.outerBarricadeDict
elif (side == 'inner'):
barricadeDict = self.innerBarricadeDict
else:
print("unhandled side %s" % side)
return
if not barricadeDict.has_key(barricadeOrigNum):
barricadeDict[barricadeOrigNum] = [curBldgGroupIndex, curBldgGroupIndex]
if curBldgGroupIndex < barricadeDict[barricadeOrigNum][0]:
barricadeDict[barricadeOrigNum][0] = curBldgGroupIndex
if barricadeDict[barricadeOrigNum][1] < curBldgGroupIndex:
barricadeDict[barricadeOrigNum][1] = curBldgGroupIndex
print "---------- %s barricadeDict origNum=%d data=(%d, %d)" %(side, barricadeOrigNum, barricadeDict[barricadeOrigNum][0], barricadeDict[barricadeOrigNum][1])
def makeStreetAlongCurve(self):
curves = self.loadStreetCurve()
if curves == None:
return
self.outerBarricadeDict = {}
self.innerBarricadeDict = {}
base.direct.grid.fXyzSnap = 0
base.direct.grid.fHprSnap = 0
self.panel.fPlaneSnap.set(0)
bldgGroup = self.consolidateStreetBuildings()
bldgs = bldgGroup.getChildren()
# streetWidth puts buildings on the edge of the street, not the middle
currPoint = Point3(0)
bldgIndex = 0
#populate side streets
self.makeSideStreets(curves)
# Populate buildings on both sides of the street
#sides = ['inner', 'outer','innersidest','outersidest']
sides = ['inner', 'outer']
maxGroupWidth = 500
for side in sides:
print "Building street for %s side" % side
# Subdivide the curve into different groups.
bldgGroupIndex = 0
curGroupWidth = 0
curveName = '';
if len(curves[side]):
initialCurve, initialCurveType = curves[side][0]
if initialCurve:
curveName = initialCurve.getName()
self.makeNewBuildingGroup(bldgGroupIndex, side, curveName)
for curve, curveType in curves[side]:
print "----------------- curve(%s, %s): %s --------------- " % (side, curve.getName(), curve)
#import pdb; pdb.set_trace()
currT = 0
endT = curve.getMaxT()
while currT < endT:
if curveType == 'urban':
bldg, bldgIndex = self.getBldg(bldgIndex, bldgs)
curve.getPoint(currT, currPoint)
if side == "inner" or side == "innersidest":
heading = 90
else:
heading = -90
bldg.setPos(currPoint)
bldgWidth = self.getBuildingWidth(bldg)
curGroupWidth += bldgWidth
# Adjust grid orientation based upon next point along curve
currT, currPoint = self.findBldgEndPoint(bldgWidth, curve, currT, currPoint, rd = 0)
bldg.lookAt(Point3(currPoint))
bldg.setH(bldg, heading)
# Shift building forward if it is on the out track, since we just turned it away from
# the direction of the track
if side == "outer" or side == "outersidest":
bldg.setPos(currPoint)
self.updateSelectedPose([bldg])
self.adjustPropChildren(bldg)
base.direct.reparent(bldg, fWrt = 1)
print bldgIndex
elif curveType == 'trees':
curve.getPoint(currT, currPoint)
# trees are spaced anywhere from 40-80 ft apart
treeWidth = random.randint(40, 80)
curGroupWidth += treeWidth
# Adjust grid orientation based upon next point along curve
currT, currPoint = self.findBldgEndPoint(treeWidth, curve, currT, currPoint, rd = 0)
# Add some trees
tree = random.choice(["prop_tree_small_ul",
"prop_tree_small_ur",
"prop_tree_large_ur",
"prop_tree_large_ul"])
#use snow if necessaryy
if (useSnowTree):
tree = random.choice(["prop_snow_tree_small_ul",
"prop_snow_tree_small_ur",
"prop_snow_tree_large_ur",
"prop_snow_tree_large_ul"])
self.addProp(tree)
for selectedNode in base.direct.selected:
# Move it
selectedNode.setPos(currPoint)
# Snap objects to grid and update DNA if necessary
self.updateSelectedPose(base.direct.selected.getSelectedAsList())
elif curveType == 'bridge':
# Don't add any dna for the bridge sections, but add the length
# of the bridge so we can increment our building groups correctly
print "adding bridge (%s), curT = %s" % (side, currT)
bridgeWidth = 1050
curGroupWidth += bridgeWidth
#currT, currPoint = self.findBldgEndPoint(bridgeWidth, curve, currT, currPoint, rd = 0)
print "currT after adding bridge = %s" % currT
# force move to next curve
currT = endT + 1
elif curveType == 'tunnel':
# Don't add any dna for the tunnel sections, but add the length
# of the bridge so we can increment our building groups correctly
print "adding tunnel (%s), curT = %s" % (side, currT)
tunnelWidth = 775
curGroupWidth += tunnelWidth
#currT, currPoint = self.findBldgEndPoint(tunnelWidth, curve, currT, currPoint, rd = 0)
print "currT after adding tunnel = %s" % currT
# force move to next curve
currT = endT + 1
elif curveType == 'barricade':
print "adding barricade (%s) %s, curT = %d" % (side, curve.getName(), currT)
barricadeWidth = curve.calcLength()
print "barricade width = %f" % barricadeWidth
simple =1
if (simple):
curGroupWidth += barricadeWidth
# force move to next curve
currT = endT + 1
else:
#add a prop_tree to force it to be shown
curve.getPoint(currT, currPoint)
#trees are spaced anywhere from 40-80 ft apart
#treeWidth = random.randint(40, 80)
treeWidth = barricadeWidth
curGroupWidth += treeWidth
# Adjust grid orientation based upon next point along curve
currT, currPoint = self.findBldgEndPoint(treeWidth, curve, currT, currPoint, rd = 0)
# Add some trees
tree = random.choice(["prop_snow_tree_small_ul",
"prop_snow_tree_small_ur",
"prop_snow_tree_large_ur",
"prop_snow_tree_large_ul"])
self.addProp(tree)
for selectedNode in base.direct.selected:
# Move it
selectedNode.setPos(currPoint)
# Snap objects to grid and update DNA if necessary
self.updateSelectedPose(base.direct.selected.getSelectedAsList())
# Check if we need a new group yet
if curGroupWidth > maxGroupWidth:
print "curGroupWidth %s > %s" % (curGroupWidth, maxGroupWidth)
diffGroup = curGroupWidth - maxGroupWidth
while diffGroup > 0:
bldgGroupIndex += 1
self.makeNewBuildingGroup(bldgGroupIndex, side, curve.getName())
print "adding group %s (%s)" % (bldgGroupIndex, diffGroup)
diffGroup -= maxGroupWidth
curGroupWidth = 0
print currT, curGroupWidth
def makeSideStreets(self, curves):
""" Each side in a sidestreet MUST be in 1 building group, otherwise the 2nd half
of a building group could be very far away. This would cause the stashing and
unstashing code to go off kilter.
"""
base.direct.grid.fXyzSnap = 0
base.direct.grid.fHprSnap = 0
self.panel.fPlaneSnap.set(0)
bldgGroup = self.consolidateStreetBuildings()
bldgs = bldgGroup.getChildren()
# streetWidth puts buildings on the edge of the street, not the middle
currPoint = Point3(0)
bldgIndex = 0
# Populate buildings on both sides of the street
#sides = ['inner', 'outer','innersidest','outersidest']
sides = ['innersidest', 'outersidest']
maxGroupWidth = 50000
for side in sides:
print "Building street for %s side" % side
# Subdivide the curve into different groups.
bldgGroupIndex = 0
curGroupWidth = 0
for curve, curveType in curves[side]:
print "----------------- curve(%s, %s): %s --------------- " % (side, curve.getName(), curve)
#import pdb; pdb.set_trace()
currT = 0
endT = curve.getMaxT()
#RAU side streets still too long, lets try arbitrarily dividing it in half
#endT = endT / 2
print ("endT = %f" % endT)
#if (maxGroupWidth < endT):
# self.notify.debug("changing endT from %f to %f" % (endT, maxGroupWidth))
# endT = maxGroupWidth
currGroupWidth = 0
self.makeNewBuildingGroup(bldgGroupIndex, side, curve.getName())
while currT < endT:
if curveType == 'urban':
bldg, bldgIndex = self.getBldg(bldgIndex, bldgs, forceDuplicate = True)
curve.getPoint(currT, currPoint)
if side == "inner" or side == "innersidest":
heading = 90
else:
heading = -90
bldg.setPos(currPoint)
bldgWidth = self.getBuildingWidth(bldg)
curGroupWidth += bldgWidth
# Adjust grid orientation based upon next point along curve
currT, currPoint = self.findBldgEndPoint(bldgWidth, curve, currT, currPoint, rd = 0)
bldg.lookAt(Point3(currPoint))
bldg.setH(bldg, heading)
# Shift building forward if it is on the out track, since we just turned it away from
# the direction of the track
if side == "outer" or side == "outersidest":
bldg.setPos(currPoint)
self.updateSelectedPose([bldg])
self.adjustPropChildren(bldg)
base.direct.reparent(bldg, fWrt = 1)
print bldgIndex
elif curveType == 'trees':
curve.getPoint(currT, currPoint)
# trees are spaced anywhere from 40-80 ft apart
treeWidth = random.randint(40, 80)
curGroupWidth += treeWidth
# Adjust grid orientation based upon next point along curve
currT, currPoint = self.findBldgEndPoint(treeWidth, curve, currT, currPoint, rd = 0)
# Add some trees
tree = random.choice(["prop_tree_small_ul",
"prop_tree_small_ur",
"prop_tree_large_ur",
"prop_tree_large_ul"])
#use snow tree if necessary
if (useSnowTree):
tree = random.choice(["prop_snow_tree_small_ul",
"prop_snow_tree_small_ur",
"prop_snow_tree_large_ur",
"prop_snow_tree_large_ul"])
self.addProp(tree)
for selectedNode in base.direct.selected:
# Move it
selectedNode.setPos(currPoint)
# Snap objects to grid and update DNA if necessary
self.updateSelectedPose(base.direct.selected.getSelectedAsList())
elif curveType == 'bridge':
# Don't add any dna for the bridge sections, but add the length
# of the bridge so we can increment our building groups correctly
print "adding bridge (%s), curT = %s" % (side, currT)
bridgeWidth = 1050
curGroupWidth += bridgeWidth
#currT, currPoint = self.findBldgEndPoint(bridgeWidth, curve, currT, currPoint, rd = 0)
print "currT after adding bridge = %s" % currT
# force move to next curve
currT = endT + 1
elif curveType == 'tunnel':
# Don't add any dna for the tunnel sections, but add the length
# of the bridge so we can increment our building groups correctly
print "adding tunnel (%s), curT = %s" % (side, currT)
tunnelWidth = 775
curGroupWidth += tunnelWidth
#currT, currPoint = self.findBldgEndPoint(tunnelWidth, curve, currT, currPoint, rd = 0)
print "currT after adding tunnel = %s" % currT
# force move to next curve
currT = endT + 1
elif curveType == 'barricade':
print "adding barricade (%s) %s, curT = %d" % (side, curve.getName(), currT)
barricadeWidth = curve.calcLength()
print "barricade width = %f" % barricadeWidth
simple =1
if (simple):
curGroupWidth += barricadeWidth
# force move to next curve
currT = endT + 1
else:
#add a prop_tree to force it to be shown
curve.getPoint(currT, currPoint)
#trees are spaced anywhere from 40-80 ft apart
#treeWidth = random.randint(40, 80)
treeWidth = barricadeWidth
curGroupWidth += treeWidth
# Adjust grid orientation based upon next point along curve
currT, currPoint = self.findBldgEndPoint(treeWidth, curve, currT, currPoint, rd = 0)
# Add some trees
tree = random.choice(["prop_snow_tree_small_ul",
"prop_snow_tree_small_ur",
"prop_snow_tree_large_ur",
"prop_snow_tree_large_ul"])
self.addProp(tree)
for selectedNode in base.direct.selected:
# Move it
selectedNode.setPos(currPoint)
# Snap objects to grid and update DNA if necessary
self.updateSelectedPose(base.direct.selected.getSelectedAsList())
#done with for loop, increment bldgGroupIndex
bldgGroupIndex += 1
def findBldgEndPoint(self, bldgWidth, curve, currT, currPoint,
startT = None, endT = None, tolerance = 0.1, rd = 0):
if startT == None:
startT = currT
if endT == None:
endT = curve.getMaxT()
if rd > 100:
import pdb
pdb.set_trace()
midT = (startT + endT)/2.0
midPoint = Point3(0)
curve.getPoint(midT, midPoint)
separation = Vec3(midPoint - currPoint).length()
error = separation - bldgWidth
#print error, startT, midT
if abs(error) < tolerance:
return midT, midPoint
elif error > 0:
# Mid point was beyond building end point, focus on first half
return self.findBldgEndPoint(bldgWidth, curve, currT, currPoint, startT = startT, endT = midT,
rd = rd + 1)
else:
# End point beyond Mid point, focus on second half
# But make sure buildind end point is not beyond curve end point
endPoint = Point3(0)
curve.getPoint(endT, endPoint)
separation = Vec3(endPoint - currPoint).length()
if bldgWidth > separation:
# Must have reached end of the curve
return endT, endPoint
else:
return self.findBldgEndPoint(bldgWidth, curve, currT, currPoint, startT = midT, endT = endT,
rd = rd + 1)
class OldLevelEditor(NodePath, DirectObject):
pass
class LevelEditorPanel(Pmw.MegaToplevel):
def __init__(self, levelEditor, parent = None, **kw):
INITOPT = Pmw.INITOPT
optiondefs = (
('title', 'Toontown Level Editor', None),
)
self.defineoptions(kw, optiondefs)
Pmw.MegaToplevel.__init__(self, parent, title = self['title'])
self.levelEditor = levelEditor
self.styleManager = self.levelEditor.styleManager
self.fUpdateSelected = 1
# Handle to the toplevels hull
hull = self.component('hull')
hull.geometry('400x625')
balloon = self.balloon = Pmw.Balloon(hull)
# Start with balloon help disabled
self.balloon.configure(state = 'none')
menuFrame = Frame(hull, relief = GROOVE, bd = 2)
menuFrame.pack(fill = X)
menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
menuBar.pack(side = LEFT, expand = 1, fill = X)
menuBar.addmenu('Level Editor', 'Level Editor Operations')
menuBar.addmenuitem('Level Editor', 'command',
'Load DNA from specified file',
label = 'Load DNA...',
command = self.levelEditor.loadSpecifiedDNAFile)
menuBar.addmenuitem('Level Editor', 'command',
'Save DNA data to specified file',
label = 'Save DNA As...',
command = self.levelEditor.saveToSpecifiedDNAFile)
menuBar.addmenuitem('Level Editor', 'command',
'Save DNA File',
label = 'Save DNA',
command = self.levelEditor.outputDNADefaultFile)
menuBar.addmenuitem('Level Editor', 'command',
'CVS update directory',
label = 'CVS update',
command = self.levelEditor.cvsUpdateAll)
menuBar.addmenuitem('Level Editor', 'command',
'CVS commit directory',
label = 'CVS commit',
command = self.levelEditor.cvsCommitAll)
menuBar.addmenuitem('Level Editor', 'command',
'Edit Visibility Groups',
label = 'Edit Vis Groups',
command = self.levelEditor.editDNAVisGroups)
menuBar.addmenuitem('Level Editor', 'command',
'Reset level',
label = 'Reset level',
command = self.levelEditor.reset)
menuBar.addmenuitem('Level Editor', 'command',
'Make Long Street',
label = 'Make Long Street',
command = self.levelEditor.makeLongStreet)
menuBar.addmenuitem('Level Editor', 'command',
'Make Street Along Curve',
label = 'Make Street Along Curve',
command = self.levelEditor.makeStreetAlongCurve)
menuBar.addmenuitem('Level Editor', 'command',
'Exit Level Editor Panel',
label = 'Exit',
command = self.levelEditor.destroy)
menuBar.addmenu('Style', 'Style Operations')
menuBar.addmenuitem('Style', 'command',
"Save Selected Object's Color",
label = 'Save Color',
command = self.levelEditor.saveColor)
menuBar.addmenuitem('Style', 'command',
"Save Selected Baseline's Style",
label = 'Save Baseline Style',
command = self.levelEditor.saveBaselineStyle)
menuBar.addmenuitem('Style', 'command',
"Save Selected Wall's Style",
label = 'Save Wall Style',
command = self.levelEditor.saveWallStyle)
menuBar.addmenuitem('Style', 'command',
"Save Selected Buildings's Style",
label = 'Save Bldg Style',
command = self.levelEditor.saveBuildingStyle)
menuBar.addmenuitem('Style', 'command',
'Reload Color Palettes',
label = 'Reload Colors',
command = self.styleManager.createColorAttributes)
menuBar.addmenuitem('Style', 'command',
'Reload Baseline Style Palettes',
label = 'Reload Baseline Styles',
command = self.styleManager.createBaselineStyleAttributes)
menuBar.addmenuitem('Style', 'command',
'Reload Wall Style Palettes',
label = 'Reload Wall Styles',
command = self.styleManager.createWallStyleAttributes)
menuBar.addmenuitem('Style', 'command',
'Reload Building Style Palettes',
label = 'Reload Bldg Styles',
command = self.styleManager.createBuildingStyleAttributes)
menuBar.addmenu('Help', 'Level Editor Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menuBar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
self.editMenu = Pmw.ComboBox(
menuFrame, labelpos = W,
label_text = 'Edit Mode:', entry_width = 18,
selectioncommand = self.levelEditor.setEditMode, history = 0,
scrolledlist_items = NEIGHBORHOODS)
self.editMenu.selectitem(NEIGHBORHOODS[0])
self.editMenu.pack(side = LEFT, expand = 0)
# Create the notebook pages
self.notebook = Pmw.NoteBook(hull)
self.notebook.pack(fill = BOTH, expand = 1)
streetsPage = self.notebook.add('Streets')
toonBuildingsPage = self.notebook.add('Toon Bldgs')
landmarkBuildingsPage = self.notebook.add('Landmark Bldgs')
# suitBuildingsPage = self.notebook.add('Suit Buildings')
propsPage = self.notebook.add('Props')
signPage = self.notebook.add('Signs')
suitPathPage = self.notebook.add('Paths')
battleCellPage = self.notebook.add('Cells')
sceneGraphPage = self.notebook.add('SceneGraph')
self.notebook['raisecommand'] = self.updateInfo
# STREETS
Label(streetsPage, text = 'Streets',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
self.addStreetButton = Button(
streetsPage,
text = 'ADD STREET',
command = self.addStreet)
self.addStreetButton.pack(fill = X, padx = 20, pady = 10)
streets = map(lambda s: s[7:],
self.styleManager.getCatalogCodes(
'street'))
streets.sort()
self.streetSelector = Pmw.ComboBox(
streetsPage,
dropdown = 0,
listheight = 200,
labelpos = W,
label_text = 'Street type:',
label_width = 12,
label_anchor = W,
entry_width = 30,
selectioncommand = self.setStreetModuleType,
scrolledlist_items = streets
)
self.streetModuleType = self.styleManager.getCatalogCode('street', 0)
self.streetSelector.selectitem(self.streetModuleType[7:])
self.streetSelector.pack(expand = 1, fill = BOTH)
# TOON BUILDINGS
Label(toonBuildingsPage, text = 'Toon Buildings',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
self.addToonBuildingButton = Button(
toonBuildingsPage,
text = 'ADD TOON BUILDING',
command = self.addFlatBuilding)
self.addToonBuildingButton.pack(fill = X, padx = 20, pady = 10)
self.toonBuildingSelector = Pmw.ComboBox(
toonBuildingsPage,
dropdown = 0,
listheight = 200,
labelpos = W,
label_width = 12,
label_anchor = W,
label_text = 'Bldg type:',
entry_width = 30,
selectioncommand = self.setFlatBuildingType,
scrolledlist_items = (['random'] + BUILDING_TYPES)
)
bf = Frame(toonBuildingsPage)
Label(bf, text = 'Building Height:').pack(side = LEFT, expand = 0)
self.heightMode = IntVar()
self.heightMode.set(20)
self.tenFootButton = Radiobutton(
bf,
text = '10 ft',
value = 10,
variable = self.heightMode,
command = self.setFlatBuildingHeight)
self.tenFootButton.pack(side = LEFT, expand = 1, fill = X)
self.fourteenFootButton = Radiobutton(
bf,
text = '14 ft',
value = 14,
variable = self.heightMode,
command = self.setFlatBuildingHeight)
self.fourteenFootButton.pack(side = LEFT, expand = 1, fill = X)
self.twentyFootButton = Radiobutton(
bf,
text = '20 ft',
value = 20,
variable = self.heightMode,
command = self.setFlatBuildingHeight)
self.twentyFootButton.pack(side = LEFT, expand = 1, fill = X)
self.twentyFourFootButton = Radiobutton(
bf,
text = '24 ft',
value = 24,
variable = self.heightMode,
command = self.setFlatBuildingHeight)
self.twentyFourFootButton.pack(side = LEFT, expand = 1, fill = X)
self.twentyFiveFootButton = Radiobutton(
bf,
text = '25 ft',
value = 25,
variable = self.heightMode,
command = self.setFlatBuildingHeight)
self.twentyFiveFootButton.pack(side = LEFT, expand = 1, fill = X)
self.thirtyFootButton = Radiobutton(
bf,
text = '30 ft',
value = 30,
variable = self.heightMode,
command = self.setFlatBuildingHeight)
self.thirtyFootButton.pack(side = LEFT, expand = 1, fill = X)
bf.pack(fill = X)
self.toonBuildingType = 'random'
self.toonBuildingSelector.selectitem(self.toonBuildingType)
self.toonBuildingSelector.pack(expand = 1, fill = BOTH)
# LANDMARK BUILDINGS
Label(landmarkBuildingsPage, text = 'Landmark Buildings',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
"""
self.landmarkHQIntVar = IntVar()
self.landmarkHQIntVar.set(0)
self.landmarkHQButton = Checkbutton(
landmarkBuildingsPage,
text = 'HQ',
variable=self.landmarkHQIntVar,
command=self.setLandmarkHQ)
self.landmarkHQButton.pack(side = LEFT, expand = 1, fill = X)
"""
self.addLandmarkBuildingButton = Button(
landmarkBuildingsPage,
text = 'ADD LANDMARK BUILDING',
command = self.addLandmark)
self.addLandmarkBuildingButton.pack(fill = X, padx = 20, pady = 10)
bldgs = map(lambda s: s[14:],
self.styleManager.getCatalogCodes(
'toon_landmark'))
bldgs.sort()
self.landmarkBuildingSelector = Pmw.ComboBox(
landmarkBuildingsPage,
dropdown = 0,
listheight = 200,
labelpos = W,
label_width = 12,
label_anchor = W,
label_text = 'Bldg type:',
entry_width = 30,
selectioncommand = self.setLandmarkType,
scrolledlist_items = bldgs
)
self.landmarkType = self.styleManager.getCatalogCode(
'toon_landmark', 0)
self.landmarkBuildingSelector.selectitem(
self.styleManager.getCatalogCode('toon_landmark', 0)[14:])
self.landmarkBuildingSelector.pack(expand = 1, fill = BOTH)
self.landmarkBuildingSpecialSelector = Pmw.ComboBox(
landmarkBuildingsPage,
dropdown = 0,
listheight = 100,
labelpos = W,
label_width = 12,
label_anchor = W,
label_text = 'Special type:',
entry_width = 30,
selectioncommand = self.setLandmarkSpecialType,
scrolledlist_items = LANDMARK_SPECIAL_TYPES
)
self.landmarkSpecialType = LANDMARK_SPECIAL_TYPES[0]
self.landmarkBuildingSpecialSelector.selectitem(
LANDMARK_SPECIAL_TYPES[0])
self.landmarkBuildingSpecialSelector.pack(expand = 0)
# SIGNS
Label(signPage, text = 'Signs',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
self.currentSignDNA=None
self.currentBaselineDNA=None
self.levelEditor.selectedNodePathHookHooks.append(self.updateSignPage)
gridFrame = Frame(signPage)
signSelectedFrame = Frame(gridFrame)
self.currentBaselineIndex=0
self.baselineMenu = Pmw.ComboBox(
signSelectedFrame,
labelpos = W,
label_text = 'Selected:', entry_width = 24,
selectioncommand = self.selectSignBaseline,
history = 0, # unique = 0,
scrolledlist_items = ['<the sign>'])
self.baselineMenu.selectitem(self.currentBaselineIndex)
self.baselineMenu.pack(side = LEFT, expand = 1, fill = X)
self.baselineAddButton = Button(
signSelectedFrame,
text="Add Baseline", command=self.addBaseline)
self.baselineAddButton.pack(side = LEFT, expand = 1, fill = X)
self.baselineDeleteButton = Button(
signSelectedFrame,
text="Del", command=self.deleteSignItem)
self.baselineDeleteButton.pack(side = LEFT, expand = 1, fill = X)
signSelectedFrame.grid(row=0, column=0, columnspan=6)
self.baselineString=StringVar()
self.baselineString.trace("wu", self.signBaselineTrace)
self.baselineTextBox = Entry(
gridFrame, width = 24,
textvariable=self.baselineString)
self.baselineTextBox.grid(row=1, column=0, columnspan=3)
fontList = [""]+self.styleManager.getCatalogCodes('font')
self.fontMenu = Pmw.ComboBox(
gridFrame, labelpos = W,
label_text = 'Font:', entry_width = 12,
selectioncommand = self.setSignBaslineFont, history = 0,
scrolledlist_items = fontList)
self.fontMenu.selectitem(0)
self.fontMenu.grid(row=1, column=3, columnspan=3)
graphicList = self.styleManager.getCatalogCodes('graphic')
self.graphicMenu = Pmw.ComboBox(
gridFrame, labelpos = W,
label_text = 'Add Graphic:', entry_width = 24,
selectioncommand = self.addSignGraphic, history = 0,
scrolledlist_items = graphicList)
self.graphicMenu.selectitem(0)
self.graphicMenu.grid(row=2, column=0, columnspan=4)
signButtonFrame = Frame(gridFrame)
self.bigFirstLetterIntVar = IntVar()
self.bigFirstLetterCheckbutton = Checkbutton(
signButtonFrame,
text = 'Big First Letter',
variable=self.bigFirstLetterIntVar, command=self.setBigFirstLetter)
self.bigFirstLetterCheckbutton.pack(
side = LEFT, expand = 1, fill = X)
self.allCapsIntVar = IntVar()
self.allCapsCheckbutton = Checkbutton(
signButtonFrame,
text = 'All Caps',
variable=self.allCapsIntVar, command=self.setAllCaps)
self.allCapsCheckbutton.pack(side = LEFT, expand = 1, fill = X)
self.dropShadowIntVar = IntVar()
self.dropShadowCheckbutton = Checkbutton(
signButtonFrame,
text = 'Drop Shadow',
variable=self.dropShadowIntVar, command=self.setDropShadow)
self.dropShadowCheckbutton.pack(side = LEFT, expand = 1, fill = X)
signButtonFrame.grid(row=3, column=0, columnspan=6)
self.addKernFloater = Floater.Floater(
gridFrame,
text='Kern',
#maxVelocity=1.0,
command=self.setSignBaselineKern)
self.addKernFloater.grid(row=4, column=0, rowspan=2, columnspan=3,
sticky = EW)
self.addWiggleFloater = Floater.Floater(
gridFrame,
text='Wiggle',
#maxVelocity=10.0,
command=self.setSignBaselineWiggle)
self.addWiggleFloater.grid(row=6, column=0, rowspan=2, columnspan=3,
sticky = EW)
self.addStumbleFloater = Floater.Floater(
gridFrame,
text='Stumble',
#maxVelocity=1.0,
command=self.setSignBaselineStumble)
self.addStumbleFloater.grid(row=8, column=0, rowspan=2, columnspan=3,
sticky = EW)
self.addStompFloater = Floater.Floater(
gridFrame,
text='Stomp',
#maxVelocity=1.0,
command=self.setSignBaselineStomp)
self.addStompFloater.grid(row=10, column=0, rowspan=2, columnspan=3,
sticky = EW)
self.addCurveFloater = Floater.Floater(
gridFrame,
text='Curve',
#maxVelocity = 1.0,
command=self.setSignBaselineCurve)
self.addCurveFloater.grid(row=12, column=0, rowspan=2, columnspan=3,
sticky = EW)
self.addXFloater = Floater.Floater(
gridFrame,
text='X',
#maxVelocity=1.0,
command=self.setDNATargetX)
self.addXFloater.grid(row=4, column=3, rowspan=2, columnspan=3,
sticky = EW)
self.addZFloater = Floater.Floater(
gridFrame,
text='Z',
#maxVelocity=1.0,
command=self.setDNATargetZ)
self.addZFloater.grid(row=6, column=3, rowspan=2, columnspan=3,
sticky = EW)
self.addScaleXFloater = Floater.Floater(
gridFrame,
text='Scale X',
#maxVelocity=1.0,
command=self.setDNATargetScaleX)
self.addScaleXFloater.grid(row=8, column=3, rowspan=2, columnspan=3,
sticky = EW)
self.addScaleZFloater = Floater.Floater(
gridFrame,
text='Scale Z',
#maxVelocity=1.0,
command=self.setDNATargetScaleZ)
self.addScaleZFloater.grid(row=10, column=3, rowspan=2, columnspan=3,
sticky = EW)
self.addRollFloater = Floater.Floater(
gridFrame,
text='Roll',
#maxVelocity=10.0,
command=self.setDNATargetRoll)
self.addRollFloater.grid(row=12, column=3, rowspan=2, columnspan=3,
sticky = EW)
gridFrame.pack(fill=BOTH)
# PROPS
Label(propsPage, text = 'Props',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
self.addPropsButton = Button(
propsPage,
text = 'ADD PROP',
command = self.addProp)
self.addPropsButton.pack(fill = X, padx = 20, pady = 10)
codes = (self.styleManager.getCatalogCodes('prop') +
self.styleManager.getCatalogCodes('holiday_prop'))
codes.sort()
self.propSelector = Pmw.ComboBox(
propsPage,
dropdown = 0,
listheight = 200,
labelpos = W,
label_width = 12,
label_anchor = W,
label_text = 'Prop type:',
entry_width = 30,
selectioncommand = self.setPropType,
scrolledlist_items = codes
)
self.propType = self.styleManager.getCatalogCode('prop', 0)
self.propSelector.selectitem(
self.styleManager.getCatalogCode('prop', 0))
self.propSelector.pack(expand = 1, fill = BOTH)
# SUIT PATHS
Label(suitPathPage, text = 'Suit Paths',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
spButtons = Frame(suitPathPage)
self.fPaths = IntVar()
self.fPaths.set(0)
self.pathButton = Checkbutton(spButtons,
text = 'Show Paths',
width = 6,
variable = self.fPaths,
command = self.toggleSuitPaths)
self.pathButton.pack(side = LEFT, expand = 1, fill = X)
self.zoneColor = IntVar()
self.zoneColor.set(0)
self.colorZoneButton1 = Checkbutton(
spButtons,
text = 'Color Zones', width = 6,
variable = self.zoneColor,
command = self.levelEditor.toggleZoneColors)
self.colorZoneButton1.pack(side = LEFT, expand = 1, fill = X)
spButtons.pack(fill = X)
spButtons = Frame(suitPathPage)
Label(spButtons, text = 'Highlight:').pack(side = LEFT, fill = X)
self.highlightConnectedButton = Button(
spButtons,
text = 'Forward',
width = 6,
command = self.levelEditor.highlightConnected)
self.highlightConnectedButton.pack(side = LEFT, expand = 1, fill = X)
self.highlightConnectedButton2 = Button(
spButtons,
text = 'Connected',
width = 6,
command = lambda s = self: s.levelEditor.highlightConnected(fReversePath = 1))
self.highlightConnectedButton2.pack(side = LEFT, expand = 1, fill = X)
self.clearHighlightButton = Button(
spButtons,
text = 'Clear',
width = 6,
command = self.levelEditor.clearPathHighlights)
self.clearHighlightButton.pack(side = LEFT, expand = 1, fill = X)
spButtons.pack(fill = X, pady = 4)
self.suitPointSelector = Pmw.ComboBox(
suitPathPage,
dropdown = 0,
listheight = 200,
labelpos = W,
label_text = 'Point type:',
label_width = 12,
label_anchor = W,
entry_width = 30,
selectioncommand = self.setSuitPointType,
scrolledlist_items = ['street', 'front door', 'side door']
)
self.suitPointSelector.selectitem('street')
self.suitPointSelector.pack(expand = 1, fill = BOTH)
# BATTLE CELLS
Label(battleCellPage, text = 'Battle Cells',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
bcButtons = Frame(battleCellPage)
self.fCells = IntVar()
self.fCells.set(0)
self.cellButton = Checkbutton(bcButtons,
text = 'Show Cells',
width = 6,
variable = self.fCells,
command = self.toggleBattleCells)
self.cellButton.pack(side = LEFT, expand = 1, fill = X)
self.colorZoneButton2 = Checkbutton(
bcButtons,
text = 'Color Zones', width = 6,
variable = self.zoneColor,
command = self.levelEditor.toggleZoneColors)
self.colorZoneButton2.pack(side = LEFT, expand = 1, fill = X)
bcButtons.pack(fill = X)
self.battleCellSelector = Pmw.ComboBox(
battleCellPage,
dropdown = 0,
listheight = 200,
labelpos = W,
label_text = 'Cell type:',
label_width = 12,
label_anchor = W,
entry_width = 30,
selectioncommand = self.setBattleCellType,
scrolledlist_items = ['20w 20l', '20w 30l', '30w 20l', '30w 30l']
)
self.battleCellSelector.selectitem('20w 20l')
self.battleCellSelector.pack(expand = 1, fill = BOTH)
# SCENE GRAPH EXPLORER
Label(sceneGraphPage, text = 'Level Scene Graph',
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
self.sceneGraphExplorer = SceneGraphExplorer(
parent = sceneGraphPage,
nodePath = self.levelEditor,
menuItems = ['Add Group', 'Add Vis Group'])
self.sceneGraphExplorer.pack(expand = 1, fill = BOTH)
# Compact down notebook
self.notebook.setnaturalsize()
self.colorEntry = VectorWidgets.ColorEntry(
hull, text = 'Select Color',
command = self.updateSelectedObjColor)
self.colorEntry.menu.add_command(
label = 'Save Color', command = self.levelEditor.saveColor)
self.colorEntry.pack(fill = X)
buttonFrame = Frame(hull)
self.fMapVis = IntVar()
self.fMapVis.set(0)
self.mapSnapButton = Checkbutton(buttonFrame,
text = 'Map Vis',
width = 6,
variable = self.fMapVis,
command = self.toggleMapVis)
#self.mapSnapButton.pack(side = LEFT, expand = 1, fill = X)
self.fXyzSnap = IntVar()
self.fXyzSnap.set(1)
self.xyzSnapButton = Checkbutton(buttonFrame,
text = 'XyzSnap',
width = 6,
variable = self.fXyzSnap,
command = self.toggleXyzSnap)
self.xyzSnapButton.pack(side = LEFT, expand = 1, fill = X)
self.fHprSnap = IntVar()
self.fHprSnap.set(1)
self.hprSnapButton = Checkbutton(buttonFrame,
text = 'HprSnap',
width = 6,
variable = self.fHprSnap,
command = self.toggleHprSnap)
self.hprSnapButton.pack(side = LEFT, expand = 1, fill = X)
def toggleWidgetHandles(s = self):
if s.fPlaneSnap.get():
base.direct.widget.disableHandles(['x-ring', 'x-disc',
'y-ring', 'y-disc',
'z-post'])
else:
base.direct.widget.enableHandles('all')
self.fPlaneSnap = IntVar()
self.fPlaneSnap.set(1)
self.planeSnapButton = Checkbutton(buttonFrame,
text = 'PlaneSnap',
width = 6,
variable = self.fPlaneSnap,
command = toggleWidgetHandles)
self.planeSnapButton.pack(side = LEFT, expand = 1, fill = X)
self.fGrid = IntVar()
self.fGrid.set(0)
base.direct.gridButton = Checkbutton(buttonFrame,
text = 'Show Grid',
width = 6,
variable = self.fGrid,
command = self.toggleGrid)
base.direct.gridButton.pack(side = LEFT, expand = 1, fill = X)
self.fMaya = IntVar()
self.fMaya.set(1)
self.mayaButton = Checkbutton(buttonFrame,
text = 'Maya Cam',
width = 6,
variable = self.fMaya,
command = self.toggleMaya)
self.mayaButton.pack(side = LEFT, expand = 1, fill = X)
#Make maya mode on by default
self.toggleMaya()
buttonFrame.pack(fill = X)
buttonFrame4 = Frame(hull)
self.driveMode = IntVar()
self.driveMode.set(1)
self.directModeButton = Radiobutton(
buttonFrame4,
text = 'DIRECT Fly',
value = 1,
variable = self.driveMode,
command = self.levelEditor.useDirectFly)
self.directModeButton.pack(side = LEFT, fill = X, expand = 1)
self.driveModeButton = Radiobutton(
buttonFrame4,
text = 'Drive',
value = 0,
variable = self.driveMode,
command = self.levelEditor.useDriveMode)
self.driveModeButton.pack(side = LEFT, fill = X, expand = 1)
self.fColl = IntVar()
self.fColl.set(1)
base.direct.collButton = Checkbutton(
buttonFrame4,
text = 'Collide',
variable = self.fColl,
command = self.levelEditor.toggleCollisions)
base.direct.collButton.pack(side = LEFT, expand = 1, fill = X)
self.fVis = IntVar()
self.fVis.set(1)
base.direct.visButton = Checkbutton(
buttonFrame4,
text = 'Visibility',
variable = self.fVis,
command = self.levelEditor.toggleVisibility)
base.direct.visButton.pack(side = LEFT, expand = 1, fill = X)
self.fVisZones = IntVar()
self.fVisZones.set(visualizeZones)
base.direct.visZonesButton = Checkbutton(
buttonFrame4,
text = 'Show Zones',
variable = self.fVisZones)
base.direct.visZonesButton.pack(side = LEFT, expand = 1, fill = X)
buttonFrame4.pack(fill = X, padx = 5)
buttonFrame = Frame(hull)
self.fLabel = IntVar()
self.fLabel.set(0)
self.labelButton = Checkbutton(buttonFrame,
text = 'Show Zone Labels',
width = 6,
variable = self.fLabel,
command = self.toggleZoneLabels)
self.labelButton.pack(side = LEFT, expand = 1, fill = X)
self.selectButton = Button(buttonFrame,
text = 'Place Selected',
width = 6,
command = lambda: last.place()
)
self.selectButton.pack(side = LEFT, expand = 1, fill = X)
buttonFrame.pack(fill = X)
# Make sure input variables processed
self.initialiseoptions(LevelEditorPanel)
def updateInfo(self, page):
if page == 'Signs':
self.updateSignPage()
# [gjeon] to toggle maya cam mode
def toggleMaya(self):
base.direct.cameraControl.lockRoll = self.fMaya.get()
direct.cameraControl.useMayaCamControls = self.fMaya.get()
def toggleGrid(self):
if self.fGrid.get():
base.direct.grid.enable()
else:
base.direct.grid.disable()
def toggleSuitPaths(self):
if self.fPaths.get():
self.levelEditor.showSuitPaths()
else:
self.levelEditor.hideSuitPaths()
def toggleBattleCells(self):
if self.fCells.get():
self.levelEditor.showBattleCells()
else:
self.levelEditor.hideBattleCells()
def toggleZoneLabels(self):
if self.fLabel.get():
self.levelEditor.labelZones()
else:
self.levelEditor.clearZoneLabels()
def toggleXyzSnap(self):
base.direct.grid.setXyzSnap(self.fXyzSnap.get())
def toggleHprSnap(self):
base.direct.grid.setHprSnap(self.fXyzSnap.get())
def toggleMapVis(self):
self.levelEditor.toggleMapVis(self.fMapVis.get())
def setStreetModuleType(self, name):
self.streetModuleType = 'street_' + name
self.levelEditor.setCurrent('street_texture', self.streetModuleType)
def addStreet(self):
self.levelEditor.addStreet(self.streetModuleType)
def setFlatBuildingType(self, name):
self.toonBuildingType = name
self.levelEditor.setCurrent('building_type', self.toonBuildingType)
def setFlatBuildingHeight(self):
height = self.heightMode.get()
self.levelEditor.setCurrent('building_height', height)
self.updateHeightList(height)
def updateHeightList(self, height):
# Update combo box
heightList = self.levelEditor.getList(`height` + '_ft_wall_heights')
self.toonBuildingSelector.setlist(
['random'] + map(createHeightCode, heightList))
self.toonBuildingSelector.selectitem(0)
self.toonBuildingSelector.invoke()
def addFlatBuilding(self):
self.levelEditor.addFlatBuilding(self.toonBuildingType)
def setLandmarkType(self, name):
self.landmarkType = 'toon_landmark_' + name
self.levelEditor.setCurrent('toon_landmark_texture', self.landmarkType)
def signPanelSync(self):
self.baselineMenu.delete(1, END)
sign=self.findSignFromDNARoot()
if not sign:
return
baselineList = DNAGetChildren(sign, DNA_SIGN_BASELINE)
for baseline in baselineList:
s=DNAGetBaselineString(baseline)
self.baselineMenu.insert(END, s)
self.baselineMenu.selectitem(0)
self.selectSignBaseline(0)
def updateSignPage(self):
if (self.notebook.getcurselection() == 'Signs'):
sign=self.findSignFromDNARoot()
# Only update if it's not the current sign:
if (self.currentSignDNA != sign):
self.currentSignDNA = sign
self.signPanelSync()
def findSignFromDNARoot(self):
dnaRoot=self.levelEditor.selectedDNARoot
if not dnaRoot:
return
objClass=DNAGetClassType(dnaRoot)
if (objClass.eq(DNA_LANDMARK_BUILDING)
or objClass.eq(DNA_PROP)):
target=DNAGetChildRecursive(dnaRoot, DNA_SIGN)
return target
def selectSignBaseline(self, val):
if not self.currentSignDNA:
return
# Temporarily undefine DNATarget (this will speed
# up setting the values, because the callbacks won't
# call self.levelEditor.replaceSelected() with each
# setting):
self.levelEditor.DNATarget=None
self.currentBaselineDNA=None
target=None
index=self.currentBaselineIndex=int((self.baselineMenu.curselection())[0])
if (index==0):
target=self.currentSignDNA
# Unset some ui elements:
self.baselineString.set('')
self.fontMenu.selectitem(0)
self.addCurveFloater.set(0)
self.addKernFloater.set(0)
self.addWiggleFloater.set(0)
self.addStumbleFloater.set(0)
self.addStompFloater.set(0)
self.bigFirstLetterIntVar.set(0)
self.allCapsIntVar.set(0)
self.dropShadowIntVar.set(0)
else:
target=DNAGetChild(self.currentSignDNA, DNA_SIGN_BASELINE, index-1)
if target:
# Update panel info:
s = DNAGetBaselineString(target)
self.baselineString.set(s)
self.fontMenu.selectitem(target.getCode())
try:
val = 1.0/target.getWidth()
except ZeroDivisionError:
val = 0.0
self.addCurveFloater.set(val)
self.addKernFloater.set(target.getKern())
self.addWiggleFloater.set(target.getWiggle())
self.addStumbleFloater.set(target.getStumble())
self.addStompFloater.set(target.getStomp())
flags=target.getFlags()
self.bigFirstLetterIntVar.set('b' in flags)
self.allCapsIntVar.set('c' in flags)
self.dropShadowIntVar.set('d' in flags)
self.currentBaselineDNA=target
if target:
pos=target.getPos()
self.addXFloater.set(pos[0])
self.addZFloater.set(pos[2])
scale=target.getScale()
self.addScaleXFloater.set(scale[0])
self.addScaleZFloater.set(scale[2])
hpr=target.getHpr()
self.addRollFloater.set(hpr[2])
self.levelEditor.DNATarget=target
def deleteSignItem(self):
"""Delete the selected sign or sign baseline"""
if (self.currentBaselineDNA):
# Remove the baseline:
assert int((self.baselineMenu.curselection())[0]) == self.currentBaselineIndex
DNARemoveChildOfClass(self.currentSignDNA, DNA_SIGN_BASELINE,
self.currentBaselineIndex-1)
self.baselineMenu.delete(self.currentBaselineIndex)
self.baselineMenu.selectitem(0)
self.currentBaselineIndex=0
self.currentBaselineDNA=None
self.selectSignBaseline(0)
self.levelEditor.replaceSelected()
elif (self.currentSignDNA):
# Remove the sign:
assert int((self.baselineMenu.curselection())[0]) == 0
le = self.levelEditor
le.removeSign(le.DNATarget, le.DNATargetParent)
self.currentBaselineDNA=None
self.currentSignDNA=None
self.levelEditor.replaceSelected()
def signBaselineTrace(self, a, b, mode):
#print self, a, b, mode, self.baselineString.get()
baseline=self.currentBaselineDNA
if baseline:
s = self.baselineString.get()
self.setBaselineString(s)
def addSignGraphic(self, code):
"""
Create a new baseline with a graphic and
add it to the current sign
"""
sign=self.findSignFromDNARoot()
if sign:
graphic=DNASignGraphic()
graphic.setCode(code)
baseline=DNASignBaseline()
baseline.add(graphic)
sign.add(baseline)
# Show the UI to the new baseline:
self.levelEditor.DNATarget=baseline
self.baselineMenu.insert(END, '['+code+']')
current=self.baselineMenu.size()-1
self.baselineMenu.selectitem(current)
self.selectSignBaseline(current)
self.levelEditor.replaceSelected()
def addBaseline(self):
sign=self.findSignFromDNARoot()
if sign:
baseline=DNASignBaseline()
text="Zoo"
DNASetBaselineString(baseline, text)
sign.add(baseline)
# Show the UI to the new baseline:
self.levelEditor.DNATarget=baseline
self.baselineMenu.insert(END, text)
current=self.baselineMenu.size()-1
self.baselineMenu.selectitem(current)
self.selectSignBaseline(current)
self.levelEditor.replaceSelected()
def addBaselineItem(self):
pass
def selectSignBaselineItem(self, val):
baseline=self.currentBaselineDNA
if baseline:
baseline.setCode(val)
self.levelEditor.replaceSelected()
def setSignBaselineStyle(self, val):
baseline=self.currentBaselineDNA
if baseline == None:
print "\n\nbaseline == None"
return #skyler: This isn't working yet.
# As a workaround, select the baseline from the tk panel.
# Try to find the first baseline in the sign:
sign=self.findSignFromDNARoot()
if sign:
self.currentSignDNA = sign
baseline=DNAGetChild(sign, DNA_SIGN_BASELINE)
if baseline and val:
self.levelEditor.DNATarget=baseline
self.currentBaselineDNA=baseline
settings=val
self.levelEditor.replaceSelectedEnabled=0
# Don't set string: self.baselineString.set('')
if settings['curve'] != None:
self.addCurveFloater.set(settings['curve'])
if settings['kern'] != None:
self.addKernFloater.set(settings['kern'])
if settings['wiggle'] != None:
self.addWiggleFloater.set(settings['wiggle'])
if settings['stumble'] != None:
self.addStumbleFloater.set(settings['stumble'])
if settings['stomp'] != None:
self.addStompFloater.set(settings['stomp'])
flags=settings['flags']
if flags != None:
self.bigFirstLetterIntVar.set('b' in flags)
self.setBigFirstLetter()
self.allCapsIntVar.set('c' in flags)
self.setAllCaps()
self.dropShadowIntVar.set('d' in flags)
self.setDropShadow()
code = settings['code']
if code != None:
self.fontMenu.selectitem(code)
self.setSignBaslineFont(code)
if settings['x'] != None:
self.addXFloater.set(settings['x'])
if settings['z'] != None:
self.addZFloater.set(settings['z'])
if settings['scaleX'] != None:
self.addScaleXFloater.set(settings['scaleX'])
if settings['scaleZ'] != None:
self.addScaleZFloater.set(settings['scaleZ'])
if settings['roll'] != None:
self.addRollFloater.set(settings['roll'])
color = settings['color']
if color != None:
#self.updateSelectedObjColor(settings['color'])
self.setCurrentColor(color)
self.setResetColor(color)
baseline.setColor(color)
self.levelEditor.replaceSelectedEnabled=1
self.levelEditor.replaceSelected()
def setBaselineString(self, val):
baseline=self.currentBaselineDNA
if baseline:
DNASetBaselineString(baseline, val)
self.baselineMenu.delete(self.currentBaselineIndex)
self.baselineMenu.insert(self.currentBaselineIndex, val)
self.baselineMenu.selectitem(self.currentBaselineIndex)
self.levelEditor.replaceSelected()
def adjustBaselineFlag(self, newValue, flagChar):
baseline=self.currentBaselineDNA
if baseline:
flags=baseline.getFlags()
if newValue:
if not flagChar in flags:
# Add the flag:
baseline.setFlags(flags+flagChar)
elif flagChar in flags:
# Remove the flag:
flags=string.join(flags.split(flagChar), '')
baseline.setFlags(flags)
self.levelEditor.replaceSelected()
def setLandmarkSpecialType(self, type):
self.landmarkSpecialType = type
if self.levelEditor.lastLandmarkBuildingDNA:
self.levelEditor.lastLandmarkBuildingDNA.setBuildingType(self.landmarkSpecialType)
def setBigFirstLetter(self):
self.adjustBaselineFlag(self.bigFirstLetterIntVar.get(), 'b')
def setAllCaps(self):
self.adjustBaselineFlag(self.allCapsIntVar.get(), 'c')
def setDropShadow(self):
self.adjustBaselineFlag(self.dropShadowIntVar.get(), 'd')
def setSignBaslineFont(self, val):
target=self.levelEditor.DNATarget
if target and (DNAGetClassType(target).eq(DNA_SIGN_BASELINE)
or DNAGetClassType(target).eq(DNA_SIGN_TEXT)):
target.setCode(val)
self.levelEditor.replaceSelected()
def setSignBaselineCurve(self, val):
baseline=self.currentBaselineDNA
if baseline:
try:
val=1.0/val
except ZeroDivisionError:
val=0.0
baseline.setWidth(val)
baseline.setHeight(val)
self.levelEditor.replaceSelected()
def setSignBaselineKern(self, val):
baseline=self.currentBaselineDNA
if baseline:
baseline.setKern(val)
self.levelEditor.replaceSelected()
def setSignBaselineWiggle(self, val):
baseline=self.currentBaselineDNA
if baseline:
baseline.setWiggle(val)
self.levelEditor.replaceSelected()
def setSignBaselineStumble(self, val):
baseline=self.currentBaselineDNA
if baseline:
baseline.setStumble(val)
self.levelEditor.replaceSelected()
def setSignBaselineStomp(self, val):
baseline=self.currentBaselineDNA
if baseline:
baseline.setStomp(val)
self.levelEditor.replaceSelected()
def setDNATargetX(self, val):
target=self.levelEditor.DNATarget
if target:
pos=target.getPos()
pos=VBase3(val, pos[1], pos[2])
target.setPos(pos)
self.levelEditor.replaceSelected()
def setDNATargetZ(self, val):
target=self.levelEditor.DNATarget
if target:
pos=target.getPos()
pos=VBase3(pos[0], pos[1], val)
target.setPos(pos)
self.levelEditor.replaceSelected()
def setDNATargetScaleX(self, val):
target=self.levelEditor.DNATarget
if target:
scale=target.getScale()
scale=VBase3(val, scale[1], scale[2])
target.setScale(scale)
self.levelEditor.replaceSelected()
def setDNATargetScaleZ(self, val):
target=self.levelEditor.DNATarget
if target:
scale=target.getScale()
scale=VBase3(scale[0], scale[1], val)
target.setScale(scale)
self.levelEditor.replaceSelected()
def setDNATargetRoll(self, val):
target=self.levelEditor.DNATarget
if target:
hpr=target.getHpr()
hpr=VBase3(hpr[0], hpr[1], val)
target.setHpr(hpr)
self.levelEditor.replaceSelected()
def addLandmark(self):
self.levelEditor.addLandmark(self.landmarkType, self.landmarkSpecialType)
def setPropType(self, name):
self.propType = name
self.levelEditor.setCurrent('prop_texture', self.propType)
def addProp(self):
self.levelEditor.addProp(self.propType)
def updateSelectedWallWidth(self, strVal):
self.levelEditor.updateSelectedWallWidth(string.atof(strVal))
def setCurrentColor(self, colorVec, fUpdate = 0):
# Turn on/off update of selected before updating entry
self.fUpdateSelected = fUpdate
self.colorEntry.set([int(colorVec[0] * 255.0),
int(colorVec[1] * 255.0),
int(colorVec[2] * 255.0),
255])
def setResetColor(self, colorVec):
self.colorEntry['resetValue'] = (
[int(colorVec[0] * 255.0),
int(colorVec[1] * 255.0),
int(colorVec[2] * 255.0),
255])
def setSuitPointType(self, name):
if (name == "street"):
self.levelEditor.currentSuitPointType = DNASuitPoint.STREETPOINT
elif (name == "front door"):
self.levelEditor.currentSuitPointType = DNASuitPoint.FRONTDOORPOINT
elif (name == "side door"):
self.levelEditor.currentSuitPointType = DNASuitPoint.SIDEDOORPOINT
print self.levelEditor.currentSuitPointType
def setBattleCellType(self, name):
self.levelEditor.currentBattleCellType = name
def updateSelectedObjColor(self, color):
try:
obj = self.levelEditor.DNATarget
if self.fUpdateSelected and (obj != None):
objClass = DNAGetClassType(obj)
if ((objClass.eq(DNA_WALL)) or
(objClass.eq(DNA_WINDOWS)) or
(objClass.eq(DNA_DOOR)) or
(objClass.eq(DNA_FLAT_DOOR)) or
(objClass.eq(DNA_CORNICE)) or
(objClass.eq(DNA_PROP)) or
(objClass.eq(DNA_SIGN)) or
(objClass.eq(DNA_SIGN_BASELINE)) or
(objClass.eq(DNA_SIGN_TEXT)) or
(objClass.eq(DNA_SIGN_GRAPHIC))
):
self.levelEditor.setDNATargetColor(
VBase4((color[0]/255.0),
(color[1]/255.0),
(color[2]/255.0),
1.0))
except AttributeError:
pass
# Default is to update selected
self.fUpdateSelected = 1
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
class VisGroupsEditor(Pmw.MegaToplevel):
def __init__(self, levelEditor, visGroups = ['None'],
parent = None, **kw):
INITOPT = Pmw.INITOPT
optiondefs = (
('title', 'Visability Groups Editor', None),
)
self.defineoptions(kw, optiondefs)
Pmw.MegaToplevel.__init__(self, parent, title = self['title'])
self.levelEditor = levelEditor
self.visGroups = visGroups
self.visGroupNames = map(lambda pair: pair[1].getName(),
self.visGroups)
# Initialize dictionary of visibility relationships
self.visDict = {}
# Group we are currently setting visGroups for
self.target = None
# Flag to enable/disable toggleVisGroup command
self.fCommand = 1
# Handle to the toplevels hull
hull = self.component('hull')
balloon = self.balloon = Pmw.Balloon(hull)
# Start with balloon help disabled
self.balloon.configure(state = 'none')
menuFrame = Frame(hull, relief = GROOVE, bd = 2)
menuFrame.pack(fill = X, expand = 1)
menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
menuBar.pack(side = LEFT, expand = 1, fill = X)
menuBar.addmenu('Vis Groups Editor',
'Visability Groups Editor Operations')
menuBar.addmenuitem('Vis Groups Editor', 'command',
'Exit Visability Groups Editor',
label = 'Exit',
command = self.preDestroy)
menuBar.addmenu('Help', 'Visability Groups Editor Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menuBar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
# Create a combo box to choose target vis group
self.targetSelector = Pmw.ComboBox(
hull, labelpos = W, label_text = 'Target Vis Group:',
entry_width = 12, selectioncommand = self.selectVisGroup,
scrolledlist_items = self.visGroupNames)
self.targetSelector.selectitem(self.visGroupNames[0])
self.targetSelector.pack(expand = 1, fill = X)
# Scrolled frame to hold radio selector
sf = Pmw.ScrolledFrame(hull, horizflex = 'elastic',
usehullsize = 1, hull_width = 200,
hull_height = 400)
frame = sf.interior()
sf.pack(padx=5, pady=3, fill = BOTH, expand = 1)
# Add vis groups selector
self.selected = Pmw.RadioSelect(frame, selectmode=MULTIPLE,
orient = VERTICAL,
pady = 0,
command = self.toggleVisGroup)
for groupInfo in self.visGroups:
nodePath = groupInfo[0]
group = groupInfo[1]
name = group.getName()
self.selected.add(name, width = 12)
# Assemble list of groups visible from this group
visible = []
for i in range(group.getNumVisibles()):
visible.append(group.getVisibleName(i))
visible.sort()
self.visDict[name] = [nodePath, group, visible]
# Pack the widget
self.selected.pack(expand = 1, fill = X)
# And make sure scrolled frame is happy
sf.reposition()
buttonFrame = Frame(hull)
buttonFrame.pack(fill=X, expand = 1)
self.showMode = IntVar()
self.showMode.set(0)
self.showAllButton = Radiobutton(buttonFrame, text = 'Show All',
value = 0, indicatoron = 1,
variable = self.showMode,
command = self.refreshVisibility)
self.showAllButton.pack(side = LEFT, fill = X, expand = 1)
self.showActiveButton = Radiobutton(buttonFrame, text = 'Show Target',
value = 1, indicatoron = 1,
variable = self.showMode,
command = self.refreshVisibility)
self.showActiveButton.pack(side = LEFT, fill = X, expand = 1)
# Make sure input variables processed
self.initialiseoptions(VisGroupsEditor)
# Switch to current target's list
self.selectVisGroup(self.visGroupNames[0])
def selectVisGroup(self, target):
print 'Setting vis options for group:', target
# Record current target
oldTarget = self.target
# Record new target
self.target = target
# Deselect buttons from old target (first deactivating command)
self.fCommand = 0
if oldTarget:
visList = self.visDict[oldTarget][2]
for group in visList:
self.selected.invoke(self.selected.index(group))
# Now set buttons to reflect state of new target
visList = self.visDict[target][2]
for group in visList:
self.selected.invoke(self.selected.index(group))
# Reactivate command
self.fCommand = 1
# Update scene
self.refreshVisibility()
def toggleVisGroup(self, groupName, state):
if self.fCommand:
targetInfo = self.visDict[self.target]
target = targetInfo[1]
visList = targetInfo[2]
groupNP = self.visDict[groupName][0]
group = self.visDict[groupName][1]
# MRM: Add change in visibility here
# Show all vs. show active
if state == 1:
print 'Vis Group:', self.target, 'adding group:', groupName
if groupName not in visList:
visList.append(groupName)
target.addVisible(groupName)
# Update vis and color
groupNP.show()
groupNP.setColor(1, 0, 0, 1)
else:
print 'Vis Group:', self.target, 'removing group:', groupName
if groupName in visList:
visList.remove(groupName)
target.removeVisible(groupName)
# Update vis and color
if self.showMode.get() == 1:
groupNP.hide()
groupNP.clearColor()
def refreshVisibility(self):
# Get current visibility list for target
targetInfo = self.visDict[self.target]
visList = targetInfo[2]
for key in self.visDict.keys():
groupNP = self.visDict[key][0]
if key in visList:
groupNP.show()
if key == self.target:
groupNP.setColor(0, 1, 0, 1)
else:
groupNP.setColor(1, 0, 0, 1)
else:
if self.showMode.get() == 0:
groupNP.show()
else:
groupNP.hide()
groupNP.clearColor()
def preDestroy(self):
# First clear level editor variable
self.levelEditor.vgpanel = None
self.destroy()
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
# [gjeon] for LevelEditor specific Avatar
class LEAvatar(LocalAvatar.LocalAvatar):
def __init__(self, cr, chatMgr, chatAssistant, passMessagesThrough = False):
LocalAvatar.LocalAvatar.__init__(self, cr, chatMgr, chatAssistant, passMessagesThrough)
def getAutoRun(self):
return 0
base.l = LevelEditor()
run()