from panda3d.core import Point3, Vec3 from direct.directnotify.DirectNotifyGlobal import directNotify from direct.interval.IntervalGlobal import LerpHprInterval from direct.showbase.MessengerGlobal import messenger from direct.showbase.PythonUtil import fitSrcAngle2Dest from direct.task.TaskManagerGlobal import taskMgr from otp.otpbase import OTPGlobals from toontown.minigame.ArrowKeys import ArrowKeys from toontown.toonbase.ToonBaseGlobal import base class TwoDDrive: notify = directNotify.newCategory('TwoDDrive') TASK_NAME = 'TwoDDriveTask' SET_ATREST_HEADING_TASK = 'setAtRestHeadingTask' def __init__(self, game, speed, maxFrameMove = None, customCollisionCallback = None, priority = 0, setHeading = 1, upHeading = 0): self.game = game self.speed = speed self.maxFrameMove = maxFrameMove self.customCollisionCallback = customCollisionCallback self.priority = priority self.setHeading = setHeading self.upHeading = upHeading self.arrowKeys = ArrowKeys() self.wasUpReleased = True self.lt = base.localAvatar base.localAvatar.useTwoDControls() base.localAvatar.controlManager.currentControls.avatarControlJumpForce = 30.0 self.ONE_JUMP_PER_UP_PRESSED = True self.lastAction = None self.isMovingX = False def destroy(self): self.game = None base.localAvatar.controlManager.currentControls.avatarControlJumpForce = 24.0 base.localAvatar.useWalkControls() self.arrowKeys.destroy() del self.arrowKeys del self.customCollisionCallback self.lastAction = None def start(self): self.notify.debug('start') self.__placeToonHOG(self.lt.getPos()) base.localAvatar.enableAvatarControls() taskMgr.remove(TwoDDrive.TASK_NAME) taskMgr.add(self.__update, TwoDDrive.TASK_NAME, priority=self.priority) def __placeToonHOG(self, pos, h = None): if h == None: h = self.lt.getH() self.lt.setPos(pos) self.lt.setH(h) self.lastPos = pos self.atRestHeading = h self.oldAtRestHeading = h self.lastXVel = 0 self.lastYVel = 0 def stop(self): self.notify.debug('stop') base.localAvatar.disableAvatarControls() taskMgr.remove(TwoDDrive.TASK_NAME) taskMgr.remove(TwoDDrive.SET_ATREST_HEADING_TASK) if hasattr(self, 'turnLocalToonIval'): if self.turnLocalToonIval.isPlaying(): self.turnLocalToonIval.pause() del self.turnLocalToonIval base.localAvatar.setSpeed(0, 0) base.localAvatar.stopSound() def __update(self, task): vel = Vec3(0, 0, 0) xVel = 0 yVel = 0 if self.ONE_JUMP_PER_UP_PRESSED: if not self.arrowKeys.upPressed(): self.wasUpReleased = True elif self.arrowKeys.upPressed() and self.wasUpReleased: self.wasUpReleased = False if not self.game.isHeadInFloor: if base.localAvatar.controlManager.currentControls == base.localAvatar.controlManager.get('twoD'): base.localAvatar.controlManager.currentControls.jumpPressed() elif self.arrowKeys.upPressed(): if not self.game.isHeadInFloor: if base.localAvatar.controlManager.currentControls == base.localAvatar.controlManager.get('twoD'): base.localAvatar.controlManager.currentControls.jumpPressed() if self.arrowKeys.leftPressed(): xVel -= 1 if self.arrowKeys.rightPressed(): xVel += 1 vel.setX(xVel) vel.setY(yVel) vel.normalize() vel *= self.speed if abs(xVel) > 0: if not self.isMovingX: self.isMovingX = True messenger.send('avatarMovingX') elif self.isMovingX: self.isMovingX = False messenger.send('avatarStoppedX') speed = vel.length() action = self.lt.setSpeed(speed, 0) if action != self.lastAction: self.lastAction = action if action == OTPGlobals.RUN_INDEX: base.localAvatar.runSound() else: base.localAvatar.stopSound() if self.setHeading: self.__handleHeading(xVel, yVel) toonPos = self.lt.getPos() dt = base.clock.getDt() posOffset = vel * dt if self.customCollisionCallback: toonPos = self.customCollisionCallback(toonPos, toonPos + posOffset) else: toonPos += posOffset self.lt.setPos(toonPos) self.lastPos = toonPos return task.cont def __handleHeading(self, xVel, yVel): def getHeading(xVel, yVel): angTab = [[None, 0, 180], [-90, -45, -135], [90, 45, 135]] return angTab[xVel][yVel] + self.upHeading def orientToon(angle, self = self): startAngle = self.lt.getH() startAngle = fitSrcAngle2Dest(startAngle, angle) dur = 0.1 * abs(startAngle - angle) / 90 self.turnLocalToonIval = LerpHprInterval(self.lt, dur, Point3(angle, 0, 0), startHpr=Point3(startAngle, 0, 0), name='TwoDDriveLerpHpr') self.turnLocalToonIval.start() if self.atRestHeading != self.oldAtRestHeading: self.oldAtRestHeading = self.atRestHeading messenger.send('avatarOrientationChanged', [self.atRestHeading]) if xVel != self.lastXVel or yVel != self.lastYVel: taskMgr.remove(TwoDDrive.SET_ATREST_HEADING_TASK) if not (xVel or yVel): orientToon(self.atRestHeading) else: curHeading = getHeading(xVel, yVel) if ((self.lastXVel and self.lastYVel) and not (xVel and yVel)): def setAtRestHeading(task, self = self, angle = curHeading): self.atRestHeading = angle return task.done taskMgr.doMethodLater(0.05, setAtRestHeading, TwoDDrive.SET_ATREST_HEADING_TASK) else: self.atRestHeading = curHeading orientToon(curHeading) self.lastXVel = xVel self.lastYVel = yVel