520 lines
21 KiB
Python
520 lines
21 KiB
Python
from panda3d.core import *
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.interval.IntervalGlobal import *
|
|
from ElevatorConstants import *
|
|
from ElevatorUtils import *
|
|
from direct.showbase import PythonUtil
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.fsm import ClassicFSM, State
|
|
from direct.distributed import DistributedObject
|
|
from direct.fsm import State
|
|
from toontown.toonbase import TTLocalizer, ToontownGlobals
|
|
from direct.task.Task import Task
|
|
from toontown.distributed import DelayDelete
|
|
from toontown.hood import ZoneUtil
|
|
from toontown.building import BoardingGroupShow
|
|
|
|
class DistributedElevator(DistributedObject.DistributedObject):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedElevator')
|
|
JumpOutOffsets = JumpOutOffsets
|
|
|
|
def __init__(self, cr):
|
|
DistributedObject.DistributedObject.__init__(self, cr)
|
|
self.bldgRequest = None
|
|
self.toonRequests = {}
|
|
self.deferredSlots = []
|
|
self.localToonOnBoard = 0
|
|
self.boardedAvIds = {}
|
|
self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg')
|
|
self.finalOpenSfx = None
|
|
self.closeSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_close.ogg')
|
|
self.elevatorFSM = None
|
|
self.finalCloseSfx = None
|
|
self.elevatorPoints = ElevatorPoints
|
|
self.fillSlotTrack = None
|
|
self.type = ELEVATOR_NORMAL
|
|
self.countdownTime = ElevatorData[self.type]['countdown']
|
|
self.__toonTracks = {}
|
|
self.fsm = ClassicFSM.ClassicFSM('DistributedElevator', [State.State('off', self.enterOff, self.exitOff, ['opening',
|
|
'waitEmpty',
|
|
'waitCountdown',
|
|
'closing',
|
|
'closed']),
|
|
State.State('opening', self.enterOpening, self.exitOpening, ['waitEmpty', 'waitCountdown']),
|
|
State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, ['waitCountdown']),
|
|
State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, ['waitEmpty', 'closing']),
|
|
State.State('closing', self.enterClosing, self.exitClosing, ['closed', 'waitEmpty']),
|
|
State.State('closed', self.enterClosed, self.exitClosed, ['opening'])], 'off', 'off')
|
|
self.fsm.enterInitialState()
|
|
self.isSetup = 0
|
|
self.__preSetupState = None
|
|
self.bigElevator = 0
|
|
self.offsetNp = None
|
|
return
|
|
|
|
def generate(self):
|
|
DistributedObject.DistributedObject.generate(self)
|
|
|
|
def setupElevator(self):
|
|
collisionRadius = ElevatorData[self.type]['collRadius']
|
|
self.elevatorSphere = CollisionSphere(0, 5, 0, collisionRadius)
|
|
self.elevatorSphere.setTangible(0)
|
|
self.elevatorSphereNode = CollisionNode(self.uniqueName('elevatorSphere'))
|
|
self.elevatorSphereNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
|
|
self.elevatorSphereNode.addSolid(self.elevatorSphere)
|
|
self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode(self.elevatorSphereNode)
|
|
self.elevatorSphereNodePath.reparentTo(self.getElevatorModel())
|
|
self.elevatorSphereNodePath.stash()
|
|
self.boardedAvIds = {}
|
|
self.openDoors = getOpenInterval(self, self.leftDoor, self.rightDoor, self.openSfx, self.finalOpenSfx, self.type)
|
|
self.closeDoors = getCloseInterval(self, self.leftDoor, self.rightDoor, self.closeSfx, self.finalCloseSfx, self.type)
|
|
self.closeDoors = Sequence(self.closeDoors, Func(self.onDoorCloseFinish))
|
|
self.finishSetup()
|
|
|
|
def finishSetup(self):
|
|
self.isSetup = 1
|
|
self.offsetNP = self.getElevatorModel().attachNewNode('dummyNP')
|
|
if self.__preSetupState:
|
|
self.fsm.request(self.__preSetupState, [0])
|
|
self.__preSetupState = None
|
|
for slot in self.deferredSlots:
|
|
self.fillSlot(*slot)
|
|
|
|
self.deferredSlots = []
|
|
return
|
|
|
|
def disable(self):
|
|
if self.bldgRequest:
|
|
self.cr.relatedObjectMgr.abortRequest(self.bldgRequest)
|
|
self.bldgRequest = None
|
|
for request in self.toonRequests.values():
|
|
self.cr.relatedObjectMgr.abortRequest(request)
|
|
|
|
self.toonRequests = {}
|
|
if hasattr(self, 'openDoors'):
|
|
self.openDoors.pause()
|
|
if hasattr(self, 'closeDoors'):
|
|
self.closeDoors.pause()
|
|
self.clearToonTracks()
|
|
self.fsm.request('off')
|
|
DistributedObject.DistributedObject.disable(self)
|
|
return
|
|
|
|
def delete(self):
|
|
if self.isSetup:
|
|
self.elevatorSphereNodePath.removeNode()
|
|
del self.elevatorSphereNodePath
|
|
del self.elevatorSphereNode
|
|
del self.elevatorSphere
|
|
del self.bldg
|
|
if self.leftDoor:
|
|
del self.leftDoor
|
|
if self.rightDoor:
|
|
del self.rightDoor
|
|
if hasattr(self, 'openDoors'):
|
|
del self.openDoors
|
|
if hasattr(self, 'closeDoors'):
|
|
del self.closeDoors
|
|
del self.fsm
|
|
del self.openSfx
|
|
del self.closeSfx
|
|
self.isSetup = 0
|
|
self.fillSlotTrack = None
|
|
if not self.offsetNp:
|
|
return
|
|
self.offsetNP.removeNode()
|
|
if hasattr(base.localAvatar, 'elevatorNotifier'):
|
|
base.localAvatar.elevatorNotifier.cleanup()
|
|
DistributedObject.DistributedObject.delete(self)
|
|
return
|
|
|
|
def setBldgDoId(self, bldgDoId):
|
|
self.bldgDoId = bldgDoId
|
|
self.bldgRequest = self.cr.relatedObjectMgr.requestObjects([bldgDoId], allCallback=self.gotBldg, timeout=2)
|
|
|
|
def gotBldg(self, buildingList):
|
|
self.bldgRequest = None
|
|
self.bldg = buildingList[0]
|
|
if not self.bldg:
|
|
self.notify.error('setBldgDoId: elevator %d cannot find bldg %d!' % (self.doId, self.bldgDoId))
|
|
return
|
|
self.setupElevator()
|
|
return
|
|
|
|
def gotToon(self, index, avId, toonList):
|
|
request = self.toonRequests.get(index)
|
|
if request:
|
|
del self.toonRequests[index]
|
|
self.fillSlot(index, avId)
|
|
else:
|
|
self.notify.error('gotToon: already had got toon in slot %s.' % index)
|
|
|
|
def setState(self, state, timestamp):
|
|
if self.isSetup:
|
|
self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])
|
|
else:
|
|
self.__preSetupState = state
|
|
|
|
def fillSlot0(self, avId, wantBoardingShow):
|
|
self.fillSlot(0, avId, wantBoardingShow)
|
|
|
|
def fillSlot1(self, avId, wantBoardingShow):
|
|
self.fillSlot(1, avId, wantBoardingShow)
|
|
|
|
def fillSlot2(self, avId, wantBoardingShow):
|
|
self.fillSlot(2, avId, wantBoardingShow)
|
|
|
|
def fillSlot3(self, avId, wantBoardingShow):
|
|
self.fillSlot(3, avId, wantBoardingShow)
|
|
|
|
def fillSlot4(self, avId, wantBoardingShow):
|
|
self.fillSlot(4, avId, wantBoardingShow)
|
|
|
|
def fillSlot5(self, avId, wantBoardingShow):
|
|
self.fillSlot(5, avId, wantBoardingShow)
|
|
|
|
def fillSlot6(self, avId, wantBoardingShow):
|
|
self.fillSlot(6, avId, wantBoardingShow)
|
|
|
|
def fillSlot7(self, avId, wantBoardingShow):
|
|
self.fillSlot(7, avId, wantBoardingShow)
|
|
|
|
def fillSlot(self, index, avId, wantBoardingShow = 0):
|
|
self.notify.debug('%s.fillSlot(%s, %s, ...)' % (self.doId, index, avId))
|
|
request = self.toonRequests.get(index)
|
|
if request:
|
|
self.cr.relatedObjectMgr.abortRequest(request)
|
|
del self.toonRequests[index]
|
|
if avId == 0:
|
|
pass
|
|
elif avId not in self.cr.doId2do:
|
|
func = PythonUtil.Functor(self.gotToon, index, avId)
|
|
self.toonRequests[index] = self.cr.relatedObjectMgr.requestObjects([avId], allCallback=func)
|
|
elif not self.isSetup:
|
|
self.deferredSlots.append((index, avId, wantBoardingShow))
|
|
else:
|
|
if avId == base.localAvatar.getDoId():
|
|
place = base.cr.playGame.getPlace()
|
|
if not place:
|
|
return
|
|
place.detectedElevatorCollision(self)
|
|
elevator = self.getPlaceElevator()
|
|
if elevator == None:
|
|
if place.fsm.hasStateNamed('elevator'):
|
|
place.fsm.request('elevator')
|
|
elif place.fsm.hasStateNamed('Elevator'):
|
|
place.fsm.request('Elevator')
|
|
elevator = self.getPlaceElevator()
|
|
if not elevator:
|
|
return
|
|
self.localToonOnBoard = 1
|
|
if hasattr(localAvatar, 'boardingParty') and localAvatar.boardingParty:
|
|
localAvatar.boardingParty.forceCleanupInviteePanel()
|
|
localAvatar.boardingParty.forceCleanupInviterPanels()
|
|
if hasattr(base.localAvatar, 'elevatorNotifier'):
|
|
base.localAvatar.elevatorNotifier.cleanup()
|
|
cameraTrack = Sequence()
|
|
cameraTrack.append(Func(elevator.fsm.request, 'boarding', [self.getElevatorModel()]))
|
|
cameraTrack.append(Func(elevator.fsm.request, 'boarded'))
|
|
toon = self.cr.doId2do[avId]
|
|
toon.stopSmooth()
|
|
if not wantBoardingShow:
|
|
toon.setZ(self.getElevatorModel(), self.elevatorPoints[index][2])
|
|
toon.setShadowHeight(0)
|
|
if toon.isDisguised:
|
|
animInFunc = Sequence(Func(toon.suit.loop, 'walk'))
|
|
animFunc = Sequence(Func(toon.setAnimState, 'neutral', 1.0), Func(toon.suit.loop, 'neutral'))
|
|
else:
|
|
animInFunc = Sequence(Func(toon.setAnimState, 'run', 1.0))
|
|
animFunc = Func(toon.setAnimState, 'neutral', 1.0)
|
|
toon.headsUp(self.getElevatorModel(), apply(Point3, self.elevatorPoints[index]))
|
|
track = Sequence(animInFunc, LerpPosInterval(toon, TOON_BOARD_ELEVATOR_TIME * 0.75, apply(Point3, self.elevatorPoints[index]), other=self.getElevatorModel()), LerpHprInterval(toon, TOON_BOARD_ELEVATOR_TIME * 0.25, Point3(180, 0, 0), other=self.getElevatorModel()), Func(self.clearToonTrack, avId), animFunc, name=toon.uniqueName('fillElevator'), autoPause=1)
|
|
if wantBoardingShow:
|
|
boardingTrack, boardingTrackType = self.getBoardingTrack(toon, index, False)
|
|
track = Sequence(boardingTrack, track)
|
|
if avId == base.localAvatar.getDoId():
|
|
cameraWaitTime = 2.5
|
|
if boardingTrackType == BoardingGroupShow.TRACK_TYPE_RUN:
|
|
cameraWaitTime = 0.5
|
|
elif boardingTrackType == BoardingGroupShow.TRACK_TYPE_POOF:
|
|
cameraWaitTime = 1
|
|
cameraTrack = Sequence(Wait(cameraWaitTime), cameraTrack)
|
|
if self.canHideBoardingQuitBtn(avId):
|
|
track = Sequence(Func(localAvatar.boardingParty.groupPanel.disableQuitButton), track)
|
|
if avId == base.localAvatar.getDoId():
|
|
track = Parallel(cameraTrack, track)
|
|
track.delayDelete = DelayDelete.DelayDelete(toon, 'Elevator.fillSlot')
|
|
self.storeToonTrack(avId, track)
|
|
track.start()
|
|
self.fillSlotTrack = track
|
|
self.boardedAvIds[avId] = None
|
|
return
|
|
|
|
def emptySlot0(self, avId, timestamp, time):
|
|
self.emptySlot(0, avId, timestamp, time)
|
|
|
|
def emptySlot1(self, avId, timestamp, time):
|
|
self.emptySlot(1, avId, timestamp, time)
|
|
|
|
def emptySlot2(self, avId, timestamp, time):
|
|
self.emptySlot(2, avId, timestamp, time)
|
|
|
|
def emptySlot3(self, avId, timestamp, time):
|
|
self.emptySlot(3, avId, timestamp, time)
|
|
|
|
def emptySlot4(self, avId, timestamp, time):
|
|
self.emptySlot(4, avId, timestamp, time)
|
|
|
|
def emptySlot5(self, avId, timestamp, time):
|
|
self.emptySlot(5, avId, timestamp)
|
|
|
|
def emptySlot6(self, avId, timestamp, time):
|
|
self.emptySlot(6, avId, timestamp, time)
|
|
|
|
def emptySlot7(self, avId, timestamp, time):
|
|
self.emptySlot(7, avId, timestamp, time)
|
|
|
|
def notifyToonOffElevator(self, toon):
|
|
toon.setAnimState('neutral', 1.0)
|
|
if toon == base.localAvatar:
|
|
doneStatus = {'where': 'exit'}
|
|
elevator = self.getPlaceElevator()
|
|
if elevator:
|
|
elevator.signalDone(doneStatus)
|
|
self.localToonOnBoard = 0
|
|
else:
|
|
toon.startSmooth()
|
|
|
|
def emptySlot(self, index, avId, timestamp, timeSent = 0):
|
|
if self.fillSlotTrack:
|
|
self.fillSlotTrack.finish()
|
|
self.fillSlotTrack = None
|
|
if avId == 0:
|
|
pass
|
|
elif not self.isSetup:
|
|
newSlots = []
|
|
for slot in self.deferredSlots:
|
|
if slot[0] != index:
|
|
newSlots.append(slot)
|
|
|
|
self.deferredSlots = newSlots
|
|
else:
|
|
timeToSet = self.countdownTime
|
|
if timeSent > 0:
|
|
timeToSet = timeSent
|
|
if avId in self.cr.doId2do:
|
|
if hasattr(self, 'clockNode'):
|
|
if timestamp < timeToSet and timestamp >= 0:
|
|
self.countdown(timeToSet - timestamp)
|
|
else:
|
|
self.countdown(timeToSet)
|
|
toon = self.cr.doId2do[avId]
|
|
toon.stopSmooth()
|
|
if toon.isDisguised:
|
|
toon.suit.loop('walk')
|
|
animFunc = Func(toon.suit.loop, 'neutral')
|
|
else:
|
|
toon.setAnimState('run', 1.0)
|
|
animFunc = Func(toon.setAnimState, 'neutral', 1.0)
|
|
track = Sequence(LerpPosInterval(toon, TOON_EXIT_ELEVATOR_TIME, Point3(*self.JumpOutOffsets[index]), other=self.getElevatorModel()), animFunc, Func(self.notifyToonOffElevator, toon), Func(self.clearToonTrack, avId), name=toon.uniqueName('emptyElevator'), autoPause=1)
|
|
if self.canHideBoardingQuitBtn(avId):
|
|
track.append(Func(localAvatar.boardingParty.groupPanel.enableQuitButton))
|
|
track.append(Func(localAvatar.boardingParty.enableGoButton))
|
|
track.delayDelete = DelayDelete.DelayDelete(toon, 'Elevator.emptySlot')
|
|
self.storeToonTrack(avId, track)
|
|
track.start()
|
|
if avId == base.localAvatar.getDoId():
|
|
messenger.send('exitElevator')
|
|
if avId in self.boardedAvIds:
|
|
del self.boardedAvIds[avId]
|
|
else:
|
|
self.notify.warning('toon: ' + str(avId) + " doesn't exist, and" + ' cannot exit the elevator!')
|
|
return
|
|
|
|
def handleEnterSphere(self, collEntry):
|
|
self.notify.debug('Entering Elevator Sphere....')
|
|
if base.localAvatar.hp > 0:
|
|
self.cr.playGame.getPlace().detectedElevatorCollision(self)
|
|
toon = base.localAvatar
|
|
self.sendUpdate('requestBoard', [])
|
|
|
|
def rejectBoard(self, avId, reason = 0):
|
|
if hasattr(base.localAvatar, 'elevatorNotifier'):
|
|
if reason == REJECT_PROMOTION:
|
|
base.localAvatar.elevatorNotifier.showMe(TTLocalizer.BossElevatorRejectMessage)
|
|
doneStatus = {'where': 'reject'}
|
|
elevator = self.getPlaceElevator()
|
|
if elevator:
|
|
elevator.signalDone(doneStatus)
|
|
|
|
def timerTask(self, task):
|
|
countdownTime = int(task.duration - task.time)
|
|
timeStr = str(countdownTime)
|
|
if self.clockNode.getText() != timeStr:
|
|
self.clockNode.setText(timeStr)
|
|
if task.time >= task.duration:
|
|
return Task.done
|
|
else:
|
|
return Task.cont
|
|
|
|
def countdown(self, duration):
|
|
countdownTask = Task(self.timerTask)
|
|
countdownTask.duration = duration
|
|
taskMgr.remove(self.uniqueName('elevatorTimerTask'))
|
|
return taskMgr.add(countdownTask, self.uniqueName('elevatorTimerTask'))
|
|
|
|
def handleExitButton(self):
|
|
self.sendUpdate('requestExit')
|
|
|
|
def enterWaitCountdown(self, ts):
|
|
self.elevatorSphereNodePath.unstash()
|
|
self.accept(self.uniqueName('enterelevatorSphere'), self.handleEnterSphere)
|
|
self.accept('elevatorExitButton', self.handleExitButton)
|
|
|
|
def exitWaitCountdown(self):
|
|
self.elevatorSphereNodePath.stash()
|
|
self.ignore(self.uniqueName('enterelevatorSphere'))
|
|
self.ignore('elevatorExitButton')
|
|
self.ignore('localToonLeft')
|
|
taskMgr.remove(self.uniqueName('elevatorTimerTask'))
|
|
self.clock.removeNode()
|
|
del self.clock
|
|
del self.clockNode
|
|
|
|
def enterClosing(self, ts):
|
|
if self.localToonOnBoard:
|
|
elevator = self.getPlaceElevator()
|
|
if elevator:
|
|
elevator.fsm.request('elevatorClosing')
|
|
self.closeDoors.start(ts)
|
|
|
|
def exitClosing(self):
|
|
pass
|
|
|
|
def onDoorCloseFinish(self):
|
|
for avId in self.boardedAvIds.keys():
|
|
av = self.cr.doId2do.get(avId)
|
|
if av is not None:
|
|
if av.getParent().compareTo(self.getElevatorModel()) == 0:
|
|
av.detachNode()
|
|
|
|
self.boardedAvIds = {}
|
|
return
|
|
|
|
def enterClosed(self, ts):
|
|
self.forceDoorsClosed()
|
|
self.__doorsClosed(self.getZoneId())
|
|
|
|
def exitClosed(self):
|
|
pass
|
|
|
|
def forceDoorsOpen(self):
|
|
openDoors(self.leftDoor, self.rightDoor)
|
|
|
|
def forceDoorsClosed(self):
|
|
self.closeDoors.finish()
|
|
closeDoors(self.leftDoor, self.rightDoor)
|
|
|
|
def enterOff(self):
|
|
pass
|
|
|
|
def exitOff(self):
|
|
pass
|
|
|
|
def enterWaitEmpty(self, ts):
|
|
pass
|
|
|
|
def exitWaitEmpty(self):
|
|
pass
|
|
|
|
def enterOpening(self, ts):
|
|
self.openDoors.start(ts)
|
|
|
|
def exitOpening(self):
|
|
pass
|
|
|
|
def startCountdownClock(self, countdownTime, ts):
|
|
self.clockNode = TextNode('elevatorClock')
|
|
self.clockNode.setFont(ToontownGlobals.getSignFont())
|
|
self.clockNode.setAlign(TextNode.ACenter)
|
|
self.clockNode.setTextColor(0.5, 0.5, 0.5, 1)
|
|
self.clockNode.setText(str(int(countdownTime)))
|
|
self.clock = self.getElevatorModel().attachNewNode(self.clockNode)
|
|
self.clock.setPosHprScale(0, 2.0, 7.5, 0, 0, 0, 2.0, 2.0, 2.0)
|
|
if ts < countdownTime:
|
|
self.countdown(countdownTime - ts)
|
|
|
|
def _getDoorsClosedInfo(self):
|
|
return ('suitInterior', 'suitInterior')
|
|
|
|
def __doorsClosed(self, zoneId):
|
|
if self.localToonOnBoard:
|
|
hoodId = ZoneUtil.getHoodId(zoneId)
|
|
loader, where = self._getDoorsClosedInfo()
|
|
doneStatus = {'loader': loader,
|
|
'where': where,
|
|
'hoodId': hoodId,
|
|
'zoneId': zoneId,
|
|
'shardId': None}
|
|
elevator = self.elevatorFSM
|
|
del self.elevatorFSM
|
|
elevator.signalDone(doneStatus)
|
|
base.camLens.setMinFov(ToontownGlobals.CBElevatorFov/(4./3.))
|
|
|
|
def getElevatorModel(self):
|
|
self.notify.error('getElevatorModel: pure virtual -- inheritors must override')
|
|
|
|
def getPlaceElevator(self):
|
|
place = self.cr.playGame.getPlace()
|
|
if place:
|
|
if hasattr(place, 'elevator'):
|
|
return place.elevator
|
|
else:
|
|
self.notify.warning("Place was in state '%s' instead of Elevator." % place.fsm.getCurrentState().getName())
|
|
place.detectedElevatorCollision(self)
|
|
else:
|
|
self.notify.warning("Place didn't exist")
|
|
return None
|
|
|
|
def storeToonTrack(self, avId, track):
|
|
self.clearToonTrack(avId)
|
|
self.__toonTracks[avId] = track
|
|
|
|
def clearToonTrack(self, avId):
|
|
oldTrack = self.__toonTracks.get(avId)
|
|
if oldTrack:
|
|
oldTrack.pause()
|
|
if self.__toonTracks.get(avId):
|
|
DelayDelete.cleanupDelayDeletes(self.__toonTracks[avId])
|
|
del self.__toonTracks[avId]
|
|
|
|
def clearToonTracks(self):
|
|
keyList = []
|
|
for key in self.__toonTracks:
|
|
keyList.append(key)
|
|
|
|
for key in keyList:
|
|
if key in self.__toonTracks:
|
|
self.clearToonTrack(key)
|
|
|
|
def getDestName(self):
|
|
return None
|
|
|
|
def getOffsetPos(self, seatIndex = 0):
|
|
return self.JumpOutOffsets[seatIndex]
|
|
|
|
def getOffsetPosWrtToonParent(self, toon, seatIndex = 0):
|
|
self.offsetNP.setPos(apply(Point3, self.getOffsetPos(seatIndex)))
|
|
return self.offsetNP.getPos(toon.getParent())
|
|
|
|
def getOffsetPosWrtRender(self, seatIndex = 0):
|
|
self.offsetNP.setPos(apply(Point3, self.getOffsetPos(seatIndex)))
|
|
return self.offsetNP.getPos(render)
|
|
|
|
def canHideBoardingQuitBtn(self, avId):
|
|
return avId == localAvatar.doId and hasattr(localAvatar, 'boardingParty') and localAvatar.boardingParty and localAvatar.boardingParty.groupPanel
|
|
|
|
def getBoardingTrack(self, toon, seatIndex, wantToonRotation):
|
|
self.boardingGroupShow = BoardingGroupShow.BoardingGroupShow(toon)
|
|
track, trackType = self.boardingGroupShow.getBoardingTrack(self.getElevatorModel(), self.getOffsetPosWrtToonParent(toon, seatIndex), self.getOffsetPosWrtRender(seatIndex), wantToonRotation)
|
|
return (track, trackType)
|