from panda3d.core import * from direct.interval.IntervalGlobal import * from direct.directnotify import DirectNotifyGlobal from direct.distributed import DistributedSmoothNode from toontown.toonbase import ToontownGlobals from otp.otpbase import OTPGlobals from direct.fsm import FSM from direct.task import Task smileyDoId = 1 class DistCogdoCraneObject(DistributedSmoothNode.DistributedSmoothNode, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistCogdoCraneObject') wantsWatchDrift = 1 def __init__(self, cr): DistributedSmoothNode.DistributedSmoothNode.__init__(self, cr) FSM.FSM.__init__(self, 'DistCogdoCraneObject') self.craneGame = None self.avId = 0 self.craneId = 0 self.cleanedUp = 0 self.collisionNode = CollisionNode('object') self.collisionNode.setIntoCollideMask(ToontownGlobals.PieBitmask | OTPGlobals.WallBitmask | ToontownGlobals.CashbotBossObjectBitmask | OTPGlobals.CameraBitmask) self.collisionNode.setFromCollideMask(ToontownGlobals.PieBitmask | OTPGlobals.FloorBitmask) self.collisionNodePath = NodePath(self.collisionNode) self.physicsActivated = 0 self.toMagnetSoundInterval = Sequence() self.hitFloorSoundInterval = Sequence() self.hitBossSfx = loader.loadSfx('phase_5/audio/sfx/AA_drop_safe_miss.ogg') self.hitBossSoundInterval = SoundInterval(self.hitBossSfx) self.touchedBossSfx = loader.loadSfx('phase_5/audio/sfx/AA_drop_sandbag.ogg') self.touchedBossSoundInterval = SoundInterval(self.touchedBossSfx, duration=0.8) self.lerpInterval = None return def disable(self): self.cleanup() self.stopSmooth() DistributedSmoothNode.DistributedSmoothNode.disable(self) def cleanup(self): if self.cleanedUp: return else: self.cleanedUp = 1 self.demand('Off') self.detachNode() self.toMagnetSoundInterval.finish() self.hitFloorSoundInterval.finish() self.hitBossSoundInterval.finish() self.touchedBossSoundInterval.finish() del self.toMagnetSoundInterval del self.hitFloorSoundInterval del self.hitBossSoundInterval del self.touchedBossSoundInterval self.craneGame = None return def setupPhysics(self, name): an = ActorNode('%s-%s' % (name, self.doId)) anp = NodePath(an) if not self.isEmpty(): self.reparentTo(anp) NodePath.assign(self, anp) self.physicsObject = an.getPhysicsObject() self.setTag('object', str(self.doId)) self.collisionNodePath.reparentTo(self) self.handler = PhysicsCollisionHandler() self.handler.addCollider(self.collisionNodePath, self) self.collideName = self.uniqueName('collide') self.handler.addInPattern(self.collideName + '-%in') self.handler.addAgainPattern(self.collideName + '-%in') self.watchDriftName = self.uniqueName('watchDrift') def activatePhysics(self): if not self.physicsActivated: self.craneGame.physicsMgr.attachPhysicalNode(self.node()) base.cTrav.addCollider(self.collisionNodePath, self.handler) self.physicsActivated = 1 self.accept(self.collideName + '-floor', self.__hitFloor) self.accept(self.collideName + '-goon', self.__hitGoon) self.acceptOnce(self.collideName + '-headTarget', self.__hitBoss) self.accept(self.collideName + '-dropPlane', self.__hitDropPlane) def deactivatePhysics(self): if self.physicsActivated: self.craneGame.physicsMgr.removePhysicalNode(self.node()) base.cTrav.removeCollider(self.collisionNodePath) self.physicsActivated = 0 self.ignore(self.collideName + '-floor') self.ignore(self.collideName + '-goon') self.ignore(self.collideName + '-headTarget') self.ignore(self.collideName + '-dropPlane') def hideShadows(self): pass def showShadows(self): pass def stashCollisions(self): self.collisionNodePath.stash() def unstashCollisions(self): self.collisionNodePath.unstash() def __hitFloor(self, entry): if self.state == 'Dropped' or self.state == 'LocalDropped': self.d_hitFloor() self.demand('SlidingFloor', localAvatar.doId) def __hitGoon(self, entry): if self.state == 'Dropped' or self.state == 'LocalDropped': goonId = int(entry.getIntoNodePath().getNetTag('doId')) goon = self.cr.doId2do.get(goonId) if goon: self.doHitGoon(goon) def doHitGoon(self, goon): pass def __hitBoss(self, entry): if (self.state == 'Dropped' or self.state == 'LocalDropped') and self.craneId != self.craneGame.doId: vel = self.physicsObject.getVelocity() vel = self.crane.root.getRelativeVector(render, vel) vel.normalize() impact = vel[1] if impact >= self.getMinImpact(): print 'hit! %s' % impact self.hitBossSoundInterval.start() self.doHitBoss(impact) else: self.touchedBossSoundInterval.start() print '--not hard enough: %s' % impact def doHitBoss(self, impact): self.d_hitBoss(impact) def __hitDropPlane(self, entry): self.notify.info('%s fell out of the world.' % self.doId) self.fellOut() def fellOut(self): raise StandardError, 'fellOut unimplented' def getMinImpact(self): return 0 def __watchDrift(self, task): v = self.physicsObject.getVelocity() if abs(v[0]) < 0.0001 and abs(v[1]) < 0.0001: self.d_requestFree() self.demand('Free') return Task.cont def prepareGrab(self): pass def prepareRelease(self): pass def setCraneGameId(self, craneGameId): self.craneGameId = craneGameId self.craneGame = base.cr.doId2do[craneGameId] def setObjectState(self, state, avId, craneId): if state == 'G': self.demand('Grabbed', avId, craneId) elif state == 'D': if self.state != 'Dropped': self.demand('Dropped', avId, craneId) elif state == 's': if self.state != 'SlidingFloor': self.demand('SlidingFloor', avId) elif state == 'F': self.demand('Free') else: self.notify.error('Invalid state from AI: %s' % state) def d_requestGrab(self): self.sendUpdate('requestGrab') def rejectGrab(self): if self.state == 'LocalGrabbed': self.demand('LocalDropped', self.avId, self.craneId) def d_requestDrop(self): self.sendUpdate('requestDrop') def d_hitFloor(self): self.sendUpdate('hitFloor') def d_requestFree(self): self.sendUpdate('requestFree', [self.getX(), self.getY(), self.getZ(), self.getH()]) def d_hitBoss(self, impact): self.sendUpdate('hitBoss', [impact]) def defaultFilter(self, request, args): if self.craneGame == None: raise FSM.RequestDenied, request return FSM.FSM.defaultFilter(self, request, args) def enterOff(self): self.detachNode() if self.lerpInterval: self.lerpInterval.finish() self.lerpInterval = None return def exitOff(self): self.reparentTo(render) def enterLocalGrabbed(self, avId, craneId): self.avId = avId self.craneId = craneId self.crane = self.cr.doId2do.get(craneId) self.hideShadows() self.prepareGrab() self.crane.grabObject(self) def exitLocalGrabbed(self): if self.newState != 'Grabbed': self.crane.dropObject(self) self.prepareRelease() del self.crane self.showShadows() def enterGrabbed(self, avId, craneId): if self.oldState == 'LocalGrabbed': if craneId == self.craneId: return else: self.crane.dropObject(self) self.prepareRelease() self.avId = avId self.craneId = craneId self.crane = self.cr.doId2do.get(craneId) self.hideShadows() self.prepareGrab() self.crane.grabObject(self) def exitGrabbed(self): self.crane.dropObject(self) self.prepareRelease() self.showShadows() del self.crane def enterLocalDropped(self, avId, craneId): self.avId = avId self.craneId = craneId self.crane = self.cr.doId2do.get(craneId) self.activatePhysics() self.startPosHprBroadcast() self.hideShadows() self.handler.setStaticFrictionCoef(0) self.handler.setDynamicFrictionCoef(0) def exitLocalDropped(self): if self.newState != 'SlidingFloor' and self.newState != 'Dropped': self.deactivatePhysics() self.stopPosHprBroadcast() del self.crane self.showShadows() def enterDropped(self, avId, craneId): self.avId = avId self.craneId = craneId self.crane = self.cr.doId2do.get(craneId) if self.avId == base.localAvatar.doId: self.activatePhysics() self.startPosHprBroadcast() self.handler.setStaticFrictionCoef(0) self.handler.setDynamicFrictionCoef(0) else: self.startSmooth() self.hideShadows() def exitDropped(self): if self.avId == base.localAvatar.doId: if self.newState != 'SlidingFloor': self.deactivatePhysics() self.stopPosHprBroadcast() else: self.stopSmooth() del self.crane self.showShadows() def enterSlidingFloor(self, avId): self.avId = avId if self.lerpInterval: self.lerpInterval.finish() self.lerpInterval = None if self.avId == base.localAvatar.doId: self.activatePhysics() self.startPosHprBroadcast() self.handler.setStaticFrictionCoef(0.9) self.handler.setDynamicFrictionCoef(0.5) if self.wantsWatchDrift: taskMgr.add(self.__watchDrift, self.watchDriftName) else: self.startSmooth() self.hitFloorSoundInterval.start() return def exitSlidingFloor(self): if self.avId == base.localAvatar.doId: taskMgr.remove(self.watchDriftName) self.deactivatePhysics() self.stopPosHprBroadcast() else: self.stopSmooth() def enterFree(self): self.avId = 0 self.craneId = 0 def exitFree(self): pass