Feature: Implemented MML Piano Marry-Go-Round

This commit is contained in:
Loudrob 2015-03-16 09:41:50 -04:00
parent d252a5cd03
commit 8e070a2231
6 changed files with 140 additions and 58 deletions

View file

@ -953,6 +953,7 @@ dclass DistributedButterfly : DistributedObject {
dclass DistributedMMPiano : DistributedObject { dclass DistributedMMPiano : DistributedObject {
requestSpeedUp() airecv clsend; requestSpeedUp() airecv clsend;
requestSlowDown() airecv clsend;
requestChangeDirection() airecv clsend; requestChangeDirection() airecv clsend;
setSpeed(int16/1000, uint16/100, int16) broadcast ram; setSpeed(int16/1000, uint16/100, int16) broadcast ram;
playSpeedUp(uint32) broadcast; playSpeedUp(uint32) broadcast;

View file

@ -2,7 +2,7 @@
from pandac.PandaModules import * from pandac.PandaModules import *
hashVal = 1610389195 hashVal = 177192120
from toontown.coghq import DistributedCashbotBossSafe, DistributedCashbotBossCrane, DistributedBattleFactory, DistributedCashbotBossTreasure, DistributedCogHQDoor, DistributedSellbotHQDoor, DistributedFactoryElevatorExt, DistributedMintElevatorExt, DistributedLawOfficeElevatorExt, DistributedLawOfficeElevatorInt, LobbyManager, DistributedMegaCorp, DistributedFactory, DistributedLawOffice, DistributedLawOfficeFloor, DistributedLift, DistributedDoorEntity, DistributedSwitch, DistributedButton, DistributedTrigger, DistributedCrushableEntity, DistributedCrusherEntity, DistributedStomper, DistributedStomperPair, DistributedLaserField, DistributedGolfGreenGame, DistributedSecurityCamera, DistributedMover, DistributedElevatorMarker, DistributedBarrelBase, DistributedGagBarrel, DistributedBeanBarrel, DistributedHealBarrel, DistributedGrid, ActiveCell, DirectionalCell, CrusherCell, DistributedCrate, DistributedSinkingPlatform, BattleBlocker, DistributedMint, DistributedMintRoom, DistributedMintBattle, DistributedStage, DistributedStageRoom, DistributedStageBattle, DistributedLawbotBossGavel, DistributedLawbotCannon, DistributedLawbotChair, DistributedCogKart, DistributedCountryClub, DistributedCountryClubRoom, DistributedMoleField, DistributedCountryClubBattle, DistributedMaze, DistributedFoodBelt, DistributedBanquetTable, DistributedGolfSpot from toontown.coghq import DistributedCashbotBossSafe, DistributedCashbotBossCrane, DistributedBattleFactory, DistributedCashbotBossTreasure, DistributedCogHQDoor, DistributedSellbotHQDoor, DistributedFactoryElevatorExt, DistributedMintElevatorExt, DistributedLawOfficeElevatorExt, DistributedLawOfficeElevatorInt, LobbyManager, DistributedMegaCorp, DistributedFactory, DistributedLawOffice, DistributedLawOfficeFloor, DistributedLift, DistributedDoorEntity, DistributedSwitch, DistributedButton, DistributedTrigger, DistributedCrushableEntity, DistributedCrusherEntity, DistributedStomper, DistributedStomperPair, DistributedLaserField, DistributedGolfGreenGame, DistributedSecurityCamera, DistributedMover, DistributedElevatorMarker, DistributedBarrelBase, DistributedGagBarrel, DistributedBeanBarrel, DistributedHealBarrel, DistributedGrid, ActiveCell, DirectionalCell, CrusherCell, DistributedCrate, DistributedSinkingPlatform, BattleBlocker, DistributedMint, DistributedMintRoom, DistributedMintBattle, DistributedStage, DistributedStageRoom, DistributedStageBattle, DistributedLawbotBossGavel, DistributedLawbotCannon, DistributedLawbotChair, DistributedCogKart, DistributedCountryClub, DistributedCountryClubRoom, DistributedMoleField, DistributedCountryClubBattle, DistributedMaze, DistributedFoodBelt, DistributedBanquetTable, DistributedGolfSpot

View file

@ -1,10 +1,12 @@
from toontown.classicchars import DistributedMinnieAI from toontown.classicchars import DistributedMinnieAI
from toontown.hood import HoodAI from toontown.hood import HoodAI
from toontown.safezone import DistributedTrolleyAI from toontown.safezone import DistributedTrolleyAI
from toontown.safezone import DistributedMMPianoAI
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals
from toontown.ai import DistributedTrickOrTreatTargetAI from toontown.ai import DistributedTrickOrTreatTargetAI
class MMHoodAI(HoodAI.HoodAI): class MMHoodAI(HoodAI.HoodAI):
def __init__(self, air): def __init__(self, air):
HoodAI.HoodAI.__init__(self, air, HoodAI.HoodAI.__init__(self, air,
@ -12,6 +14,7 @@ class MMHoodAI(HoodAI.HoodAI):
ToontownGlobals.MinniesMelodyland) ToontownGlobals.MinniesMelodyland)
self.trolley = None self.trolley = None
self.piano = None
self.classicChar = None self.classicChar = None
self.startup() self.startup()
@ -25,6 +28,9 @@ class MMHoodAI(HoodAI.HoodAI):
if simbase.config.GetBool('want-minnie', True): if simbase.config.GetBool('want-minnie', True):
self.createClassicChar() self.createClassicChar()
self.piano = DistributedMMPianoAI.DistributedMMPianoAI(self.air)
self.piano.generateWithRequired(self.zoneId)
if simbase.air.wantHalloween: if simbase.air.wantHalloween:
self.TrickOrTreatTargetManager = DistributedTrickOrTreatTargetAI.DistributedTrickOrTreatTargetAI(self.air) self.TrickOrTreatTargetManager = DistributedTrickOrTreatTargetAI.DistributedTrickOrTreatTargetAI(self.air)
self.TrickOrTreatTargetManager.generateWithRequired(4835) self.TrickOrTreatTargetManager.generateWithRequired(4835)

View file

@ -1,3 +1,4 @@
import random
from pandac.PandaModules import * from pandac.PandaModules import *
from direct.task.Task import Task from direct.task.Task import Task
from direct.distributed.ClockDelta import * from direct.distributed.ClockDelta import *
@ -9,31 +10,44 @@ ChangeDirectionDebounce = 1.0
ChangeDirectionTime = 1.0 ChangeDirectionTime = 1.0
class DistributedMMPiano(DistributedObject.DistributedObject): class DistributedMMPiano(DistributedObject.DistributedObject):
whitePartNodeName = 'midkey_floor_1'
def __init__(self, cr): def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr) DistributedObject.DistributedObject.__init__(self, cr)
self.spinStartTime = 0.0 self.spinStartTime = 0.0
self.rpm = 0.0 self.rpm = 0.0
self.degreesPerSecond = self.rpm / 60.0 * 360.0 self.degreesPerSecond = self.rpm / 60.0 * 360.0
self.offset = 0.0 self.offset = 0.0
self.oldOffset = 0.0
self.lerpStart = 0.0
self.lerpFinish = 1.0
self.speedUpSound = None self.speedUpSound = None
self.changeDirectionSound = None self.changeDirectionSound = None
self.lastChangeDirection = 0.0 self.lastChangeDirection = 0.0
return
def generate(self): def generate(self):
self.piano = base.cr.playGame.hood.loader.piano DistributedObject.DistributedObject.generate(self)
taskMgr.doMethodLater(4, self.setupGeom, self.uniqueName('setup-geom'))
def setupGeom(self, task):
geom = self.cr.playGame.getPlace().loader.geom
self.piano = geom.find('**/center_icon')
if self.piano.isEmpty():
loader.notify.error('Piano not found')
return
geom.find('**/center_icon').setPos(0,-20.1,0)
geom.find('**/midkey_floor').setPos(0,20.1,0)
geom.find('**/pond_floor').setPos(0,20.1,0)
geom.find('**/pond_floor').setScale(1.01,1.01,1)
geom.find('**/MMsz_water').setPos(0,20.0,0)
geom.find('**/midkey_floor').setScale(1.01,1.01,1)
geom.find('**/midkey_floor_1').setScale(1.01,1.01,1)
base.cr.parentMgr.registerParent(ToontownGlobals.SPMinniesPiano, self.piano) base.cr.parentMgr.registerParent(ToontownGlobals.SPMinniesPiano, self.piano)
self.accept('enterlarge_round_keyboard_collisions', self.__handleOnFloor) self.accept('enter' + self.whitePartNodeName, self.__handleOnFloor)
self.accept('exitlarge_round_keyboard_collisions', self.__handleOffFloor) self.accept('exit' + self.whitePartNodeName, self.__handleOffFloor)
self.accept('entero7', self.__handleChangeDirectionButton) self.accept('entermid_fishpond', self.__handleChangeDirectionButton)
self.speedUpSound = base.loadSfx('phase_6/audio/sfx/SZ_MM_gliss.ogg') self.speedUpSound = base.loadSfx('phase_6/audio/sfx/SZ_MM_gliss.ogg')
self.changeDirectionSound = base.loadSfx('phase_6/audio/sfx/SZ_MM_cymbal.ogg') self.changeDirectionSound = base.loadSfx('phase_6/audio/sfx/SZ_MM_cymbal.ogg')
self.__setupSpin() self.__setupSpin()
DistributedObject.DistributedObject.generate(self) return task.done
def __setupSpin(self): def __setupSpin(self):
taskMgr.add(self.__updateSpin, self.taskName('pianoSpinTask')) taskMgr.add(self.__updateSpin, self.taskName('pianoSpinTask'))
@ -42,51 +56,32 @@ class DistributedMMPiano(DistributedObject.DistributedObject):
taskMgr.remove(self.taskName('pianoSpinTask')) taskMgr.remove(self.taskName('pianoSpinTask'))
def __updateSpin(self, task): def __updateSpin(self, task):
now = globalClock.getFrameTime() if self.degreesPerSecond == 0:
if now > self.lerpFinish: return Task.cont
offset = self.offset
elif now > self.lerpStart: elapsed = globalClock.getRealTime() - self.spinStartTime
t = (now - self.lerpStart) / (self.lerpFinish - self.lerpStart) offset = self.offset
offset = self.oldOffset + t * (self.offset - self.oldOffset) heading = ((self.degreesPerSecond * elapsed) + offset) % 360
else: self.piano.setH(heading)
offset = self.oldOffset
heading = self.degreesPerSecond * (now - self.spinStartTime) + offset
self.piano.setHprScale(heading % 360.0, 0.0, 0.0, 1.0, 1.0, 1.0)
return Task.cont return Task.cont
def disable(self): def disable(self):
del self.piano if hasattr(self, 'piano'):
base.cr.parentMgr.unregisterParent(ToontownGlobals.SPMinniesPiano) del self.piano
self.ignore('enterlarge_round_keyboard_collisions') base.cr.parentMgr.unregisterParent(ToontownGlobals.SPMinniesPiano)
self.ignore('exitlarge_round_keyboard_collisions') self.ignoreAll()
self.ignore('entero7')
self.ignore('entericon_center_collisions')
self.speedUpSound = None self.speedUpSound = None
self.changeDirectionSound = None self.changeDirectionSound = None
self.__stopSpin() self.__stopSpin()
DistributedObject.DistributedObject.disable(self) DistributedObject.DistributedObject.disable(self)
return
def setSpeed(self, rpm, offset, timestamp): def setSpeed(self, rpm, offset, timestamp):
timestamp = globalClockDelta.networkToLocalTime(timestamp) timestamp = globalClockDelta.networkToLocalTime(timestamp)
degreesPerSecond = rpm / 60.0 * 360.0 degreesPerSecond = rpm / 60.0 * 360.0
now = globalClock.getFrameTime()
oldHeading = self.degreesPerSecond * (now - self.spinStartTime) + self.offset
oldHeading = oldHeading % 360.0
oldOffset = oldHeading - degreesPerSecond * (now - timestamp)
self.rpm = rpm self.rpm = rpm
self.degreesPerSecond = degreesPerSecond self.degreesPerSecond = degreesPerSecond
self.offset = offset self.offset = offset
self.spinStartTime = timestamp self.spinStartTime = timestamp
while oldOffset - offset < -180.0:
oldOffset += 360.0
while oldOffset - offset > 180.0:
oldOffset -= 360.0
self.oldOffset = oldOffset
self.lerpStart = now
self.lerpFinish = timestamp + ChangeDirectionTime
def playSpeedUp(self, avId): def playSpeedUp(self, avId):
if avId != base.localAvatar.doId: if avId != base.localAvatar.doId:
@ -103,6 +98,7 @@ class DistributedMMPiano(DistributedObject.DistributedObject):
def __handleOffFloor(self, collEntry): def __handleOffFloor(self, collEntry):
self.cr.playGame.getPlace().activityFsm.request('off') self.cr.playGame.getPlace().activityFsm.request('off')
self.sendUpdate('requestSlowDown', [])
def __handleSpeedUpButton(self, collEntry): def __handleSpeedUpButton(self, collEntry):
self.sendUpdate('requestSpeedUp', []) self.sendUpdate('requestSpeedUp', [])
@ -111,7 +107,12 @@ class DistributedMMPiano(DistributedObject.DistributedObject):
def __handleChangeDirectionButton(self, collEntry): def __handleChangeDirectionButton(self, collEntry):
now = globalClock.getFrameTime() now = globalClock.getFrameTime()
if now - self.lastChangeDirection < ChangeDirectionDebounce: if now - self.lastChangeDirection < ChangeDirectionDebounce:
loader.notify.debug('Rejecting change direction.')
return return
self.lastChangeDirection = now shouldChange = random.randint(1,10)
self.sendUpdate('requestChangeDirection', []) if int(shouldChange) == 10:
base.playSfx(self.changeDirectionSound) self.lastChangeDirection = now
self.sendUpdate('requestChangeDirection', [])
base.playSfx(self.changeDirectionSound)
else:
loader.notify.debug('Rejecting change direction.')

View file

@ -1,21 +1,73 @@
from direct.directnotify import DirectNotifyGlobal from otp.ai.AIBase import *
from direct.distributed.DistributedObjectAI import DistributedObjectAI from toontown.toonbase.ToontownGlobals import *
from direct.distributed.ClockDelta import *
from direct.distributed import DistributedObjectAI
from direct.task import Task
PianoSpeeds = [2, 4, 6, 8, 10, 12, 15, 20]
PianoMaxSpeed = PianoSpeeds[-1]
PianoSlowDownFactor = 0.7
PianoSlowDownInterval = 6.0
PianoSlowDownMinimum = 0.1
class DistributedMMPianoAI(DistributedObjectAI): class DistributedMMPianoAI(DistributedObjectAI.DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedMMPianoAI")
def __init__(self, air):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
self.spinStartTime = 0.0
self.rpm = 0.0
self.degreesPerSecond = (self.rpm / 60.0) * 360.0
self.offset = 0.0
self.direction = 1
def requestSpeedUp(self): def requestSpeedUp(self):
pass if self.rpm < PianoMaxSpeed:
for speed in PianoSpeeds:
if speed > self.rpm:
break
self.updateSpeed(speed, self.direction)
self.d_playSpeedUp(self.air.getAvatarIdFromSender())
self.__slowDownLater()
def requestChangeDirection(self): def requestChangeDirection(self):
pass rpm = self.rpm
if rpm == 0.0:
rpm = PianoSpeeds[0]
self.updateSpeed(rpm, -(self.direction))
self.__slowDownLater()
self.d_playChangeDirection(self.air.getAvatarIdFromSender())
def d_setSpeed(self, rpm, offset, startTime):
self.sendUpdate('setSpeed', [rpm, offset, globalClockDelta.localToNetworkTime(startTime)])
def setSpeed(self, todo0, todo1, todo2): def d_playSpeedUp(self, avId):
pass self.sendUpdate('playSpeedUp', [avId])
def playSpeedUp(self, todo0): def d_playChangeDirection(self, avId):
pass self.sendUpdate('playChangeDirection', [avId])
def playChangeDirection(self, todo0): def updateSpeed(self, rpm, direction):
pass now = globalClock.getFrameTime()
heading = self.degreesPerSecond * (now - self.spinStartTime) + self.offset
self.rpm = rpm
self.direction = direction
self.degreesPerSecond = (rpm / 60.0) * 360.0 * direction
self.offset = heading % 360.0
self.spinStartTime = now
self.d_setSpeed(self.rpm * self.direction, self.offset, self.spinStartTime)
def __slowDownLater(self):
taskName = self.uniqueName('slowDown')
taskMgr.remove(taskName)
taskMgr.doMethodLater(PianoSlowDownInterval, self.__slowDown, taskName)
def __slowDown(self, task):
rpm = self.rpm * PianoSlowDownFactor
if rpm < PianoSlowDownMinimum:
self.updateSpeed(0.0, self.direction)
else:
self.updateSpeed(rpm, self.direction)
self.__slowDownLater()
return Task.done

View file

@ -1,8 +1,30 @@
from toontown.classicchars import CCharPaths from toontown.classicchars import CCharPaths
from direct.fsm import ClassicFSM, State
import random
from toontown.safezone import Playground from toontown.safezone import Playground
from toontown.toonbase import TTLocalizer from toontown.toonbase import TTLocalizer
from toontown.toonbase import ToontownGlobals
class MMPlayground(Playground.Playground): class MMPlayground(Playground.Playground):
def __init__(self, loader, parentFSM, doneEvent):
Playground.Playground.__init__(self, loader, parentFSM, doneEvent)
self.activityFsm = ClassicFSM.ClassicFSM('Activity', [State.State('off', self.enterOff, self.exitOff, ['OnPiano']), State.State('OnPiano', self.enterOnPiano, self.exitOnPiano, ['off'])], 'off', 'off')
self.activityFsm.enterInitialState()
def showPaths(self): def showPaths(self):
self.showPathPoints(CCharPaths.getPaths(TTLocalizer.Minnie)) self.showPathPoints(CCharPaths.getPaths(TTLocalizer.Minnie))
def enterOff(self):
return None
def exitOff(self):
return None
def enterOnPiano(self):
base.localAvatar.b_setParent(ToontownGlobals.SPMinniesPiano)
def exitOnPiano(self):
base.localAvatar.b_setParent(ToontownGlobals.SPRender)