class DistributedPicnicBasket(DistributedObject.DistributedObject): seatState = Enum('Empty, Full, Eating') notify = DirectNotifyGlobal.directNotify.newCategory( 'DistributedPicnicBasket') def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.localToonOnBoard = 0 self.seed = 0 self.random = None self.picnicCountdownTime = base.config.GetFloat( 'picnic-countdown-time', ToontownGlobals.PICNIC_COUNTDOWN_TIME) self.picnicBasketTrack = None self.fsm = ClassicFSM.ClassicFSM('DistributedTrolley', [ State.State('off', self.enterOff, self.exitOff, ['waitEmpty', 'waitCountdown']), State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, ['waitCountdown']), State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, ['waitEmpty']) ], 'off', 'off') self.fsm.enterInitialState() self.__toonTracks = {} return def generate(self): DistributedObject.DistributedObject.generate(self) self.loader = self.cr.playGame.hood.loader self.foodLoader = [ 'phase_6/models/golf/picnic_sandwich.bam', 'phase_6/models/golf/picnic_apple.bam', 'phase_6/models/golf/picnic_cupcake.bam', 'phase_6/models/golf/picnic_chocolate_cake.bam' ] self.fullSeat = [] self.food = [] for i in range(4): self.food.append(None) self.fullSeat.append(self.seatState.Empty) self.picnicItem = 0 return def announceGenerate(self): self.picnicTable = self.loader.geom.find('**/*picnic_table_' + str(self.tableNumber)) self.picnicTableSphereNodes = [] self.numSeats = 4 self.seats = [] self.jumpOffsets = [] self.basket = None for i in range(self.numSeats): self.seats.append(self.picnicTable.find('**/*seat%d' % (i + 1))) self.jumpOffsets.append( self.picnicTable.find('**/*jumpOut%d' % (i + 1))) self.tablecloth = self.picnicTable.find('**/basket_locator') DistributedObject.DistributedObject.announceGenerate(self) for i in range(self.numSeats): self.picnicTableSphereNodes.append(self.seats[i].attachNewNode( CollisionNode('picnicTable_sphere_%d_%d' % (self.getDoId(), i)))) self.picnicTableSphereNodes[i].node().addSolid( CollisionSphere(0, 0, 0, 2)) self.tableclothSphereNode = self.tablecloth.attachNewNode( CollisionNode('tablecloth_sphere')) self.tableclothSphereNode.node().addSolid(CollisionSphere(0, 0, -1, 4)) angle = self.startingHpr[0] angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 30.0 self.endPos = self.startingPos + unitVec dist = Vec3(self.endPos - self.enteringPos).length() wheelAngle = dist / (0.5 * 1.4 * math.pi) * 360 self.seatNumber = 0 self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() return def disable(self): DistributedObject.DistributedObject.disable(self) self.fsm.request('off') self.clearToonTracks() for i in range(self.numSeats): del self.picnicTableSphereNodes[0] del self.picnicTableSphereNodes self.notify.debug('Deleted self loader ' + str(self.getDoId())) self.picnicTable.removeNode() self.picnicBasketTrack = None return def delete(self): self.notify.debug('Golf kart getting deleted: %s' % self.getDoId()) DistributedObject.DistributedObject.delete(self) del self.fsm def setState(self, state, seed, timestamp): self.seed = seed if not self.random: self.random = RandomNumGen.RandomNumGen(seed) self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def handleEnterPicnicTableSphere(self, i, collEntry): self.seatNumber = i self.notify.debug('Entering Picnic Table Sphere.... %s' % self.getDoId()) self.loader.place.detectedPicnicTableSphereCollision(self) def handleEnterPicnicTable(self, i): toon = base.localAvatar self.sendUpdate('requestBoard', [i]) def fillSlot0(self, avId): self.fillSlot(0, avId) def fillSlot1(self, avId): self.fillSlot(1, avId) def fillSlot2(self, avId): self.fillSlot(2, avId) def fillSlot3(self, avId): self.fillSlot(3, avId) def fillSlot(self, index, avId): self.notify.debug('fill Slot: %d for %d' % (index, avId)) if avId == 0: pass else: self.fullSeat[index] = self.seatState.Full if avId == base.localAvatar.getDoId(): self.clockNode.show() if index == 0 or index == 3: side = -1 else: side = 1 if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.fsm.request( 'boarding', [self.tablecloth, side]) else: self.notify.warning('fillSlot no trolley in place') self.localToonOnBoard = 1 if avId == base.localAvatar.getDoId(): if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.fsm.request('boarded') self.loader.place.trolley.exitButton.hide() if avId in self.cr.doId2do: toon = self.cr.doId2do[avId] toon.stopSmooth() toon.wrtReparentTo(self.tablecloth) sitStartDuration = toon.getDuration('sit-start') jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence(jumpTrack, Func(toon.setAnimState, 'Sit', 1.0)) self.notify.debug('### fillSlot: fullSeat = %s' % self.fullSeat) if self.fullSeat.count(0) == 3: self.notify.debug('### fillSlot: adding basketAppear') if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence( Wait(waitDuration), self.generateBasketAppearTrack()) self.picnicBasketTrack.start() track.append(self.generateFoodAppearTrack(index)) track.append( Sequence(Func(self.clearToonTrack, avId), name=toon.uniqueName('fillTrolley'), autoPause=1)) if avId == base.localAvatar.getDoId(): if hasattr(self.loader.place, 'trolley'): track.append( Func(self.loader.place.trolley.exitButton.show)) track.delayDelete = DelayDelete.DelayDelete( toon, 'PicnicBasket.fillSlot') self.storeToonTrack(avId, track) track.start() def emptySlot0(self, avId, timestamp): self.emptySlot(0, avId, timestamp) def emptySlot1(self, avId, timestamp): self.emptySlot(1, avId, timestamp) def emptySlot2(self, avId, timestamp): self.emptySlot(2, avId, timestamp) def emptySlot3(self, avId, timestamp): self.emptySlot(3, avId, timestamp) def notifyToonOffTrolley(self, toon): toon.setAnimState('neutral', 1.0) if hasattr(base, 'localAvatar') and toon == base.localAvatar: if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.handleOffTrolley() self.localToonOnBoard = 0 else: toon.startSmooth() def emptySlot(self, index, avId, timestamp): def emptySeat(index): self.notify.debug('### seat %s now empty' % index) self.fullSeat[index] = self.seatState.Empty if avId == 0: pass elif avId == 1: self.fullSeat[index] = self.seatState.Empty track = Sequence(self.generateFoodDisappearTrack(index)) self.notify.debug('### empty slot - unexpetected: fullSeat = %s' % self.fullSeat) if self.fullSeat.count(0) == 4: self.notify.debug('### empty slot - unexpected: losing basket') if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence( Wait(waitDuration), self.generateBasketDisappearTrack()) self.picnicBasketTrack.start() track.start() else: self.fullSeat[index] = self.seatState.Empty if avId in self.cr.doId2do: if avId == base.localAvatar.getDoId(): if self.clockNode: self.clockNode.hide() toon = self.cr.doId2do[avId] toon.stopSmooth() sitStartDuration = toon.getDuration('sit-start') jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) track = Sequence(jumpOutTrack) track.append(self.generateFoodDisappearTrack(index)) self.notify.debug('### empty slot: fullSeat = %s' % self.fullSeat) if self.fullSeat.count(0) == 4: self.notify.debug('### empty slot: losing basket') if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence( Wait(waitDuration), self.generateBasketDisappearTrack()) self.picnicBasketTrack.start() track.append( Sequence(Func(self.notifyToonOffTrolley, toon), Func(self.clearToonTrack, avId), Func(self.doneExit, avId), Func(emptySeat, index), name=toon.uniqueName('emptyTrolley'), autoPause=1)) track.delayDelete = DelayDelete.DelayDelete( toon, 'PicnicBasket.emptySlot') self.storeToonTrack(avId, track) track.start() def rejectBoard(self, avId): self.loader.place.trolley.handleRejectBoard() def __enableCollisions(self): for i in range(self.numSeats): self.accept('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTableSphere, [i]) self.accept('enterPicnicTableOK_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTable, [i]) self.picnicTableSphereNodes[i].setCollideMask( ToontownGlobals.WallBitmask) def __disableCollisions(self): for i in range(self.numSeats): self.ignore('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i)) self.ignore('enterPicnicTableOK_%d_%d' % (self.getDoId(), i)) for i in range(self.numSeats): self.picnicTableSphereNodes[i].setCollideMask(BitMask32(0)) def enterOff(self): return None def exitOff(self): return None def enterWaitEmpty(self, ts): self.__enableCollisions() def exitWaitEmpty(self): self.__disableCollisions() def enterWaitCountdown(self, ts): self.__enableCollisions() self.accept('trolleyExitButton', self.handleExitButton) self.clockNode.countdown(self.picnicCountdownTime, self.handleExitButton) def handleExitButton(self): self.sendUpdate('requestExit') self.clockNode.hide() def exitWaitCountdown(self): self.__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def getStareAtNodeAndOffset(self): return (self.tablecloth, Point3(0, 0, 4)) 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() DelayDelete.cleanupDelayDeletes(oldTrack) 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 doneExit(self, avId): if avId == base.localAvatar.getDoId(): self.sendUpdate('doneExit') def setPosHpr(self, x, y, z, h, p, r): self.startingPos = Vec3(x, y, z) self.enteringPos = Vec3(x, y, z - 10) self.startingHpr = Vec3(h, 0, 0) def setTableNumber(self, tn): self.tableNumber = tn def generateToonJumpTrack(self, av, seatIndex): av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack(av, seatIndex): def getJumpDest(av=av, node=self.tablecloth): dest = Vec3(self.tablecloth.getPos(av.getParent())) seatNode = self.picnicTable.find('**/seat' + str(seatIndex + 1)) dest += seatNode.getPos(self.tablecloth) dna = av.getStyle() dest -= hipOffset if seatIndex == 2 or seatIndex == 3: dest.setY(dest.getY() + 2 * hipOffset.getY()) dest.setZ(dest.getZ() + 0.2) return dest def getJumpHpr(av=av, node=self.tablecloth): hpr = self.seats[seatIndex].getHpr(av.getParent()) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.43), Parallel( LerpHprInterval(av, hpr=getJumpHpr, duration=0.9), ProjectileInterval(av, endPos=getJumpDest, duration=0.9)))) return toonJumpTrack def getToonSitTrack(av): toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit')) return toonSitTrack toonJumpTrack = getToonJumpTrack(av, seatIndex) toonSitTrack = getToonSitTrack(av) jumpTrack = Sequence( Parallel(toonJumpTrack, Sequence(Wait(1), toonSitTrack)), Func(av.wrtReparentTo, self.tablecloth)) return jumpTrack def generateToonReverseJumpTrack(self, av, seatIndex): self.notify.debug('av.getH() = %s' % av.getH()) def getToonJumpTrack(av, destNode): def getJumpDest(av=av, node=destNode): dest = node.getPos(self.tablecloth) dest += self.jumpOffsets[seatIndex].getPos(self.tablecloth) return dest def getJumpHpr(av=av, node=destNode): hpr = node.getHpr(av.getParent()) hpr.setX(hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.1), Parallel( ProjectileInterval(av, endPos=getJumpDest, duration=0.9)))) return toonJumpTrack toonJumpTrack = getToonJumpTrack(av, self.tablecloth) jumpTrack = Sequence(toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render)) return jumpTrack def generateBasketAppearTrack(self): if self.basket == None: self.basket = loader.loadModel( 'phase_6/models/golf/picnic_basket.bam') self.basket.setScale(0.1) basketTrack = Sequence( Func(self.basket.show), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.ogg'), node=self.basket), Func(self.basket.reparentTo, self.tablecloth), Func(self.basket.setPos, 0, 0, 0.2), Func(self.basket.setHpr, 45, 0, 0), Func(self.basket.wrtReparentTo, render), Func(self.basket.setShear, 0, 0, 0), Sequence( LerpScaleInterval(self.basket, scale=Point3(1.1, 1.1, 0.1), duration=0.2), LerpScaleInterval(self.basket, scale=Point3(1.6, 1.6, 0.2), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1.0, 1.0, 0.4), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1.5, 1.5, 2.5), duration=0.2), LerpScaleInterval(self.basket, scale=Point3(2.5, 2.5, 1.5), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(2.0, 2.0, 2.0), duration=0.1), Func(self.basket.wrtReparentTo, self.tablecloth), Func(self.basket.setPos, 0, 0, 0))) return basketTrack def generateBasketDisappearTrack(self): if not self.basket: return Sequence() pos = self.basket.getPos() pos.addZ(-1) basketTrack = Sequence( LerpScaleInterval(self.basket, scale=Point3(2.0, 2.0, 1.8), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1.0, 1.0, 2.5), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(2.0, 2.0, 0.5), duration=0.2), LerpScaleInterval(self.basket, scale=Point3(0.5, 0.5, 1.0), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1.1, 1.1, 0.1), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(0.1, 0.1, 0.1), duration=0.2), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.ogg'), node=self.basket), Wait(0.2), LerpPosInterval(self.basket, pos=pos, duration=0.2), Func(self.basket.hide)) return basketTrack def generateFoodAppearTrack(self, seat): if self.fullSeat[seat] == self.seatState.Full: self.notify.debug('### food appear: self.fullSeat = %s' % self.fullSeat) if not self.food[seat]: self.food[seat] = loader.loadModel( self.random.choice(self.foodLoader)) self.notify.debug('### food appear: self.food = %s' % self.food) self.food[seat].setScale(0.1) self.food[seat].reparentTo(self.tablecloth) self.food[seat].setPos( self.seats[seat].getPos(self.tablecloth)[0] / 2, self.seats[seat].getPos(self.tablecloth)[1] / 2, 0) foodTrack = Sequence( Func(self.food[seat].show), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.ogg'), node=self.food[seat]), Func(self.food[seat].reparentTo, self.tablecloth), Func(self.food[seat].setHpr, 45, 0, 0), Func(self.food[seat].wrtReparentTo, render), Func(self.food[seat].setShear, 0, 0, 0), Sequence( LerpScaleInterval(self.food[seat], scale=Point3(1.1, 1.1, 0.1), duration=0.2), LerpScaleInterval(self.food[seat], scale=Point3(1.6, 1.6, 0.2), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1.0, 1.0, 0.4), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1.5, 1.5, 2.5), duration=0.2), LerpScaleInterval(self.food[seat], scale=Point3(2.5, 2.5, 1.5), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(2.0, 2.0, 2.0), duration=0.1), Func(self.food[seat].wrtReparentTo, self.tablecloth))) return foodTrack else: return Sequence() def generateFoodDisappearTrack(self, seat): if not self.food[seat]: return Sequence() pos = self.food[seat].getPos() pos.addZ(-1.0) foodTrack = Sequence( LerpScaleInterval(self.food[seat], scale=Point3(2.0, 2.0, 1.8), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1.0, 1.0, 2.5), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(2.0, 2.0, 0.5), duration=0.2), LerpScaleInterval(self.food[seat], scale=Point3(0.5, 0.5, 1.0), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1.1, 1.1, 0.1), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(0.1, 0.1, 0.1), duration=0.2), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.ogg'), node=self.food[seat]), Wait(0.2), LerpPosInterval(self.food[seat], pos=pos, duration=0.2), Func(self.food[seat].hide)) return foodTrack def destroy(self, node): node.removeNode() node = None self.basket.removeNode() self.basket = None for food in self.food: food.removeNode() self.food = None self.clockNode.removeNode() del self.clockNode self.clockNode = None return def setPicnicDone(self): if self.localToonOnBoard: if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.fsm.request('final') self.loader.place.trolley.fsm.request('start') self.localToonOnBoard = 0 messenger.send('picnicDone')
class DistributedFindFour(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, 'DistributedFindFour') DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel( 'phase_6/models/golf/findfour_game.bam') self.boardNode.reparentTo(self) self.board = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]] self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.playersTurnBlinker = Sequence() self.yourTurnBlinker = Sequence() self.winningSequence = Sequence() self.moveSequence = Sequence() self.moveList = [] self.mySquares = [] self.playerSeats = None self.moveCol = None self.move = None self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(BitMask32(4096)) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel( 'phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find( '**/InventoryButtonRollover') self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.tintConstant = Vec4(0.25, 0.25, 0.25, 0) self.ghostConstant = Vec4(0, 0, 0, 0.5) self.knockSound = base.loadSfx('phase_5/audio/sfx/GUI_knock_1.mp3') self.clickSound = base.loadSfx( 'phase_3/audio/sfx/GUI_balloon_popup.mp3') self.moveSound = base.loadSfx('phase_6/audio/sfx/CC_move.mp3') self.accept('stoppedAsleep', self.handleSleep) from direct.fsm import ClassicFSM, State self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [ State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin']) ], 'waitingToBegin', 'waitingToBegin') startLoc = self.boardNode.find('**/locators') self.locatorList = startLoc.getChildren() self.startingPositions = self.locatorList.pop(0) self.startingPositions = self.startingPositions.getChildren() instancePiece = self.boardNode.find('**/pieces') tempList = [] for x in range(7): self.startingPositions[x].setTag('StartLocator', '%d' % x) collNode = CollisionNode('startpicker%d' % x) collNode.setIntoCollideMask(BitMask32(4096)) tempList.append(self.startingPositions[x].attachNewNode(collNode)) tempList[x].node().addSolid( CollisionTube(0, 0, 0.23, 0, 0, -.23, 0.2)) for z in self.startingPositions: y = instancePiece.copyTo(z) for val in y.getChildren(): val.hide() tempList = [] for x in range(42): self.locatorList[x].setTag('GamePeiceLocator', '%d' % x) collNode = CollisionNode('startpicker%d' % x) collNode.setIntoCollideMask(BitMask32(4096)) tempList.append(self.locatorList[x].attachNewNode(collNode)) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, 0.2)) for z in self.locatorList: y = instancePiece.copyTo(z) for val in y.getChildren(): val.hide() dummyHide = instancePiece.getParent().attachNewNode('DummyHider') instancePiece.reparentTo(dummyHide) dummyHide.hide() return def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: self.seatPos = self.table.tableState.index( base.localAvatar.doId) if self.seatPos <= 2: for x in self.startingPositions: x.setH(0) for x in self.locatorList: x.setH(0) else: for x in self.startingPositions: x.setH(180) for x in self.locatorList: x.setH(180) self.moveCameraForGame() else: self.seatPos = self.table.seatBumpForObserve if self.seatPos > 2: for x in self.startingPositions: x.setH(180) for x in self.locatorList: x.setH(180) self.moveCameraForGame() def handleSleep(self, task=None): if self.fsm.getCurrentState().getName() == 'waitingToBegin': self.exitButtonPushed() if task != None: task.done return def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None taskMgr.remove('playerTurnTask') return def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None self.winningSequence.finish() taskMgr.remove('playerTurnTask') return def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState( ).getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() return def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(0.64, 0, -0.27) self.clockNode.countdown(timeLeft, self.doRandomMove) self.clockNode.show() return def gameStart(self, playerNum): if playerNum != 255: self.playerNum = playerNum if self.playerNum == 1: self.playerColorString = 'Red' else: self.playerColorString = 'Yellow' self.moveCameraForGame() self.fsm.request('playing') def sendTurn(self, playersTurn): if self.fsm.getCurrentState().getName() == 'playing': if playersTurn == self.playerNum: self.isMyTurn = True taskMgr.add(self.turnTask, 'playerTurnTask') self.enableTurnScreenText(playersTurn) def illegalMove(self): self.exitButtonPushed() def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.pause() rotation = 0 if self.seatPos <= 2: position = self.table.seats[1].getPos() position = position + Vec3(0, -8, 12.8) int = LerpPosHprInterval(camera, 2, position, Vec3(0, -38, 0), camera.getPos(), camera.getHpr()) else: position = self.table.seats[4].getPos() position = position + Vec3(0, -8, 12.8) if camera.getH() < 0: int = LerpPosHprInterval(camera, 2, position, Vec3(-180, -20, 0), camera.getPos(), camera.getHpr()) else: int = LerpPosHprInterval(camera, 2, position, Vec3(180, -20, 0), camera.getPos(), camera.getHpr()) int.start() def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() return def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() return def enterGameOver(self): pass def exitGameOver(self): pass def exitWaitCountdown(self): self.__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.8), scale=0.15, command=lambda self=self: self.exitButtonPushed()) return def enableScreenText(self): defaultPos = (-.7, -0.29) if self.playerNum == 1: message = 'You are Red' color = Vec4(1, 0, 0, 1) elif self.playerNum == 2: message = 'You are Yellow' color = Vec4(1, 1, 0, 1) else: message = TTLocalizer.CheckersObserver color = Vec4(0, 0, 0, 1) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.57), scale=0.15, command=lambda self=self: self.startButtonPushed()) return def enableLeaveButton(self): self.leaveButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.8), scale=0.15, command=lambda self=self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.CheckersIts if self.turnText != None: self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) elif player == 1: message2 = "Red's Turn" color = (1, 0, 0, 1) elif player == 2: message2 = "Yellow's Turn" color = (1, 1, 0, 1) self.turnText = OnscreenText(text=message1 + message2, pos=(-0.7, -0.39), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) return def startButtonPushed(self): self.sendUpdate('requestBegin') self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate('requestExit') def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True and not self.moveSequence.isPlaying( ): if self.moveCol != None: self.d_requestMove(self.moveCol) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') return def handleClicked(self, index): pass def turnTask(self, task): if base.mouseWatcherNode.hasMouse() == False: return task.cont if self.isMyTurn == False: return task.cont if self.moveSequence.isPlaying(): return task.cont mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.getNetTag('StartLocator') if pickedObj: colVal = int(pickedObj) if colVal == self.moveCol: return task.cont if self.board[0][colVal] == 0: if self.moveCol != None: for x in self.startingPositions[self.moveCol].getChild( 1).getChildren(): x.hide() self.moveCol = colVal if self.playerNum == 1: self.startingPositions[self.moveCol].getChild( 1).getChild(2).show() elif self.playerNum == 2: self.startingPositions[self.moveCol].getChild( 1).getChild(3).show() return task.cont def d_requestMove(self, moveCol): self.sendUpdate('requestMove', [moveCol]) def setGameState(self, tableState, moveCol, movePos, turn): messenger.send('wakeup') if self.table.fsm.getCurrentState().getName() == 'observing': isBlank = True for x in range(7): if self.board[5][x] != 0: isBlank = False break gameBlank = True for x in range(7): if tableState[5][x] != 0: gameBlank = False break if isBlank == True and gameBlank == False: for x in range(6): for y in range(7): self.board[x][y] = tableState[x][y] self.updateGameState() return if moveCol == 0 and movePos == 0 and turn == 0: for x in range(6): for y in range(7): self.board[x][y] = tableState[x][y] self.updateGameState() else: self.animatePeice(tableState, moveCol, movePos, turn) didIWin = self.checkForWin() if didIWin != None: self.sendUpdate('requestWin', [didIWin]) return def updateGameState(self): for x in range(6): for y in range(7): for z in self.locatorList[x * 7 + y].getChild(1).getChildren(): z.hide() for x in range(6): for y in range(7): state = self.board[x][y] if state == 1: self.locatorList[x * 7 + y].getChild(1).getChild(0).show() elif state == 2: self.locatorList[x * 7 + y].getChild(1).getChild(1).show() def checkForWin(self): for x in range(6): for y in range(7): if self.board[x][y] == self.playerNum: if self.checkHorizontal(x, y, self.playerNum) == True: return [x, y] elif self.checkVertical(x, y, self.playerNum) == True: return [x, y] elif self.checkDiagonal(x, y, self.playerNum) == True: return [x, y] return None def announceWinnerPosition(self, x, y, winDirection, playerNum): self.isMyturn = False if self.turnText: self.turnText.hide() self.clockNode.stop() self.clockNode.hide() if winDirection == 0: blinkList = self.findHorizontal(x, y, playerNum) elif winDirection == 1: blinkList = self.findVertical(x, y, playerNum) elif winDirection == 2: blinkList = self.findDiagonal(x, y, playerNum) if blinkList != []: print blinkList val0 = x * 7 + y x = blinkList[0][0] y = blinkList[0][1] val1 = x * 7 + y x = blinkList[1][0] y = blinkList[1][1] val2 = x * 7 + y x = blinkList[2][0] y = blinkList[2][1] val3 = x * 7 + y self.winningSequence = Sequence() downBlinkerParallel = Parallel( LerpColorInterval(self.locatorList[val0], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val1], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val2], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val3], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1))) upBlinkerParallel = Parallel( LerpColorInterval(self.locatorList[val0], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)), LerpColorInterval(self.locatorList[val1], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)), LerpColorInterval(self.locatorList[val2], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)), LerpColorInterval(self.locatorList[val3], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5))) self.winningSequence.append(downBlinkerParallel) self.winningSequence.append(upBlinkerParallel) self.winningSequence.loop() def tie(self): self.tieSequence = Sequence(autoFinish=1) self.clockNode.stop() self.clockNode.hide() self.isMyTurn = False self.moveSequence.finish() if self.turnText: self.turnText.hide() for x in range(41): self.tieSequence.append( Parallel( LerpColorInterval(self.locatorList[x], 0.15, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[x], 0.15, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)))) whisper = WhisperPopup('This Find Four game has resulted in a Tie!', OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) whisper.manage(base.marginManager) self.tieSequence.start() def hideChildren(self, nodeList): pass def animatePeice(self, tableState, moveCol, movePos, turn): messenger.send('wakeup') for x in range(6): for y in range(7): self.board[x][y] = tableState[x][y] pos = self.startingPositions[moveCol].getPos() if turn == 0: peice = self.startingPositions[moveCol].getChild( 1).getChildren()[2] peice.show() elif turn == 1: peice = self.startingPositions[moveCol].getChild( 1).getChildren()[3] peice.show() self.moveSequence = Sequence() startPos = self.startingPositions[moveCol].getPos() arrayLoc = movePos * 7 + moveCol self.moveSequence.append( LerpPosInterval(self.startingPositions[moveCol], 1.5, self.locatorList[arrayLoc].getPos(self), startPos)) self.moveSequence.append(Func(peice.hide)) self.moveSequence.append( Func(self.startingPositions[moveCol].setPos, startPos)) self.moveSequence.append(Func(self.updateGameState)) self.moveSequence.start() def announceWin(self, avId): self.fsm.request('gameOver') def doRandomMove(self): if self.isMyTurn: if self.moveCol != None: self.d_requestMove(self.moveCol) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') else: hasfound = False while hasfound == False: from random import * x = randint(0, 6) if self.board[0][x] == 0: self.d_requestMove(x) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') hasfound = True return def doNothing(self): pass def checkHorizontal(self, rVal, cVal, playerNum): if cVal == 3: for x in range(1, 4): if self.board[rVal][cVal - x] != playerNum: break if self.board[rVal][cVal - x] == playerNum and x == 3: return True for x in range(1, 4): if self.board[rVal][cVal + x] != playerNum: break if self.board[rVal][cVal + x] == playerNum and x == 3: return True return False elif cVal == 2: for x in range(1, 4): if self.board[rVal][cVal + x] != playerNum: break if self.board[rVal][cVal + x] == playerNum and x == 3: return True return False elif cVal == 4: for x in range(1, 4): if self.board[rVal][cVal - x] != playerNum: break if self.board[rVal][cVal - x] == playerNum and x == 3: return True return False else: return False def checkVertical(self, rVal, cVal, playerNum): if rVal == 2: for x in range(1, 4): if self.board[rVal + x][cVal] != playerNum: break if self.board[rVal + x][cVal] == playerNum and x == 3: return True return False elif rVal == 3: for x in range(1, 4): if self.board[rVal - x][cVal] != playerNum: break if self.board[rVal - x][cVal] == playerNum and x == 3: return True return False else: return False def checkDiagonal(self, rVal, cVal, playerNum): if cVal <= 2: if rVal == 2: for x in range(1, 4): if self.board[rVal + x][cVal + x] != playerNum: break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return True return False elif rVal == 3: for x in range(1, 4): if self.board[rVal - x][cVal + x] != playerNum: break if self.board[rVal - x][cVal + x] == playerNum and x == 3: return True return False elif cVal >= 4: if rVal == 2: for x in range(1, 4): if self.board[rVal + x][cVal - x] != playerNum: break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 3: for x in range(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 3 or rVal == 4 or rVal == 5: for x in range(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True for x in range(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 0 or rVal == 1 or rVal == 2: for x in range(1, 4): if self.board[rVal + x][cVal - x] != playerNum: break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return True for x in range(1, 4): if self.board[rVal + x][cVal + x] != playerNum: break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return True return False return False def findHorizontal(self, rVal, cVal, playerNum): if cVal == 3: retList = [] for x in range(1, 4): retList.append([rVal, cVal - x]) if self.board[rVal][cVal - x] != playerNum: retList = [] break if self.board[rVal][cVal - x] == playerNum and x == 3: return retList for x in range(1, 4): retList.append([rVal, cVal + x]) if self.board[rVal][cVal + x] != playerNum: retList = [] break if self.board[rVal][cVal + x] == playerNum and x == 3: return retList return [] elif cVal == 2: retList = [] for x in range(1, 4): retList.append([rVal, cVal + x]) if self.board[rVal][cVal + x] != playerNum: retList = [] break if self.board[rVal][cVal + x] == playerNum and x == 3: return retList return [] elif cVal == 4: retList = [] for x in range(1, 4): retList.append([rVal, cVal - x]) if self.board[rVal][cVal - x] != playerNum: retList = [] break if self.board[rVal][cVal - x] == playerNum and x == 3: return retList return [] else: return [] def findVertical(self, rVal, cVal, playerNum): if rVal == 2: retList = [] for x in range(1, 4): retList.append([rVal + x, cVal]) if self.board[rVal + x][cVal] != playerNum: retList = [] break if self.board[rVal + x][cVal] == playerNum and x == 3: return retList return [] elif rVal == 3: retList = [] for x in range(1, 4): retList.append([rVal - x, cVal]) if self.board[rVal - x][cVal] != playerNum: retList = [] break if self.board[rVal - x][cVal] == playerNum and x == 3: return retList return [] else: return [] def findDiagonal(self, rVal, cVal, playerNum): retList = [] if cVal <= 2: if rVal == 2: for x in range(1, 4): retList.append([rVal + x, cVal + x]) if self.board[rVal + x][cVal + x] != playerNum: retList = [] break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return retList return [] elif rVal == 3: for x in range(1, 4): retList.append([rVal - x, cVal + x]) if self.board[rVal - x][cVal + x] != playerNum: retList = [] break if self.board[rVal - x][cVal + x] == playerNum and x == 3: return retList return [] elif cVal >= 4: if rVal == 2: for x in range(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 3: for x in range(1, 4): retList.append([rVal - x, cVal - x]) if self.board[rVal - x][cVal - x] != playerNum: retList = [] break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 3 or rVal == 4 or rVal == 5: for x in range(1, 4): retList.append([rVal - x, cVal - x]) if self.board[rVal - x][cVal - x] != playerNum: retList = [] break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return retList for x in range(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 0 or rVal == 1 or rVal == 2: for x in range(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList for x in range(1, 4): retList.append([rVal + x, cVal + x]) if self.board[rVal + x][cVal + x] != playerNum: retList = [] break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return retList return [] return []
class DistributedCheckers(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, "DistributedCheckers") DistributedNode.DistributedNode.__init__(self,cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel("phase_6/models/golf/regular_checker_game.bam") self.boardNode.reparentTo(self) self.board = CheckersBoard() #game variables self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.moveList = [] self.mySquares = [] self.myKings = [] self.isRotated = False #Mouse picking required stuff self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(ToontownGlobals.WallBitmask) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel("phase_3.5/models/gui/inventory_gui") self.upButton = self.buttonModels.find("**//InventoryButtonUp") self.downButton = self.buttonModels.find("**/InventoryButtonDown") self.rolloverButton = self.buttonModels.find("**/InventoryButtonRollover") self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() #[0] GREEN [1] YELLOW [2] PURPLE [3] BLUE [4] PINK [5] RED self.playerColors = [ Vec4(0,0,1,1), Vec4(0,1,0,1) ] self.tintConstant = Vec4(.25,.25,.25,.5) self.ghostConstant = Vec4(0,0,0,.8) #starting positions are used to check and see if a player has gone into #his opposing players starting position, thus to tell if he won. self.startingPositions = [[0,1,2,3,4,5,6,7,8,9,10,11], [20,21,22,23,24,25,26,27,28,29,30,31]] self.knockSound = base.loadSfx("phase_5/audio/sfx/GUI_knock_1.mp3") self.clickSound = base.loadSfx("phase_3/audio/sfx/GUI_balloon_popup.mp3") self.moveSound = base.loadSfx("phase_6/audio/sfx/CC_move.mp3") self.accept('stoppedAsleep', self.handleSleep) ####################### #Fsm and State Data # from direct.fsm import ClassicFSM,State self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing','gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin'])], # Initial State 'waitingToBegin', # Final State 'waitingToBegin', ) ######################### #Set up the Board Locators ## x = self.boardNode.find("**/locator*") #set up the locator list so we can mess with it self.locatorList = x.getChildren() #tag the locators for "picking" ingame #also add colision spheres for movement tempList = [] for x in range(0,32): self.locatorList[x].setTag("GamePeiceLocator", "%d" % x) tempList.append(self.locatorList[x].attachNewNode(CollisionNode("picker%d" % x))) tempList[x].node().addSolid(CollisionSphere(0,0,0,.39)) for z in self.locatorList: y = loader.loadModel("phase_6/models/golf/regular_checker_piecewhite.bam") y.find("**/checker_k*").hide() zz = loader.loadModel("phase_6/models/golf/regular_checker_pieceblack.bam") zz.find("**/checker_k*").hide() y.reparentTo(z) y.hide() zz.reparentTo(z) zz.hide() def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: # Fix for strange state #TEMP until i find the cause self.seatPos = self.table.tableState.index(base.localAvatar.doId) def handleSleep(self, task = None): if self.fsm.getCurrentState().getName() == "waitingToBegin": self.exitButtonPushed() if task != None: task.done #task.done ########## ##setTableDoId (required broadcast ram) # #Upon construction, sets local pointer to the table, as well as #sets the pointer on the table to itself. #This is necessary to handle events that occur on the table, not #particularly inside of any one game. ### def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) ######### ##Disable/Delete #Must be sure to remove/delete any buttons, screen text #that may be on the screen in the event of a chosen ( or asynchrinous ) #disable or deletion - Code redundance here is necessary #being that "disable" is called upon server crash, and delete is #called upon zone exit ### def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton : self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None ########## ##Timer Functions #setTimer (broadcast ram required) #setTurnTimer(broadcast ram required) # #setTimer() controlls the timer for game begin, which upon its timout #calls the startButton. # #turnTimer() does just that # #Important to note that both timers run on the same clockNode. ########## def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState().getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime() ) if(timeLeft > 0 and timerEnd != 0): if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime() ) if timeLeft > 0: self.clockNode.setPos(-.74, 0, -0.20) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doNothing) else: self.clockNode.countdown(timeLeft, self.doNothing) self.clockNode.show() ########### ##Game start(broadcast) and Send Turn (broadcast ram) # #IMPORTANT - 255 is the Uint8 sent to the player when a game starts #to dictate to him that a game is beginning and he is labeled as an observer #for that game - this affects the visual queues for his player color ect. ########## def gameStart(self, playerNum): if playerNum != 255: #observer value self.playerNum = playerNum if self.playerNum == 1: self.playerColorString = "white" else: self.playerColorString = "black" self.playerColor = self.playerColors[playerNum-1] self.moveCameraForGame() self.fsm.request('playing') def sendTurn(self,playersTurn): if self.fsm.getCurrentState().getName() == 'playing': if playersTurn == self.playerNum: self.isMyTurn = True self.enableTurnScreenText(playersTurn) def illegalMove(self): self.exitButtonPushed() ########## ##Move camera # #To make camera movement not seem weird (turning 270 degrees example) #Must check the clients orientation between the seatPos and his current H # so that he turns the least possible amount for the camera orientation # # ########## def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.finish() rotation = 0 if self.seatPos >2: if self.playerNum == 1: rotation = 180 elif self.playerNum == 2: rotation = 0 for x in self.locatorList: x.setH(180) self.isRotated = True else: if self.playerNum == 1: rotation = 0 elif self.playerNum == 2: rotation = 180 for x in self.locatorList: x.setH(180) self.isRotated = True int = LerpHprInterval(self.boardNode, 4.2, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) int.start() ##################### #FSM Stuff ### def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton : self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() def enterPlaying(self): self.inGame = True self.enableScreenText() #print "IM IN PLAYING?????!?!?!" if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() def enterGameOver(self): pass def exitGameOver(self): pass ################################################## # Button Functions and Text ### def exitWaitCountdown(self): self.__disableCollisions() self.ignore("trolleyExitButton") self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton( relief = None, text = TTLocalizer.ChineseCheckersGetUpButton, text_fg = (1, 1, 0.65, 1), text_pos = (0, -.23), text_scale = 0.8, image = (self.upButton, self.downButton, self.rolloverButton), image_color = (1, 0, 0, 1), image_scale = (20, 1, 11), pos = (.92, 0, 0.4), scale = 0.15, command = lambda self=self: self.exitButtonPushed(), ) return def enableScreenText(self): defaultPos = (-.80, -0.40) if self.playerNum == 1: message = TTLocalizer.CheckersColorWhite color = Vec4(1,1,1,1) elif self.playerNum == 2: message = TTLocalizer.CheckersColorBlack color = Vec4(0,0,0,1) else: message = TTLocalizer.CheckersObserver color = Vec4(0,0,0,1) defaultPos = (-.80, -0.40) self.screenText = OnscreenText(text = message, pos = defaultPos, scale = 0.10,fg=color,align=TextNode.ACenter,mayChange=1) def enableStartButton(self): self.startButton = DirectButton( relief = None, text = TTLocalizer.ChineseCheckersStartButton, text_fg = (1, 1, 0.65, 1), text_pos = (0, -.23), text_scale = 0.6, image = (self.upButton, self.downButton, self.rolloverButton), image_color = (1, 0, 0, 1), image_scale = (20, 1, 11), pos = (.92, 0, 0.1), scale = 0.15, command = lambda self=self: self.startButtonPushed(), ) return def enableLeaveButton(self): self.leaveButton = DirectButton( relief = None, text = TTLocalizer.ChineseCheckersQuitButton, text_fg = (1, 1, 0.65, 1), text_pos = (0, -.13), text_scale = 0.5, image = (self.upButton, self.downButton, self.rolloverButton), image_color = (1, 0, 0, 1), image_scale = (20, 1, 11), pos = (.92, 0, 0.4), scale = 0.15, command = lambda self=self: self.exitButtonPushed(), ) return def enableTurnScreenText(self,player): playerOrder = [1,4,2,5,3,6] message1 = TTLocalizer.CheckersIts if(self.turnText != None): self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0,0,0,1) else: if player == 1: message2 = TTLocalizer.CheckersWhiteTurn color = (1,1,1,1) elif player == 2: message2 = TTLocalizer.CheckersBlackTurn color = (0,0,0,1) self.turnText = OnscreenText(text = message1+message2, pos = (-0.80,-0.50), scale = 0.092,fg=color,align=TextNode.ACenter,mayChange=1) #This function is called either if the player clicks on it (to begin a game) #or if the game begin timer runs out. (timer is in sync with server so results should be # + or - ~ 1 second def startButtonPushed(self): self.sendUpdate("requestBegin") self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate("requestExit") ########## #Mouse Picking/clicking operations # # #These functions handle all of the mous clicking functions #Its best to look through the code for comments for it to make #the most sense. # #The self.blinker that is referenced in these functions, is a cosmetic #colorLerp that gives the player a visual feedback as to what checkers peice #he has (currently) selected. ########## def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True : #cant pick stuff if its not your turn mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode,mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries()#get the closest Object pickedObj = self.myHandler.getEntry(0).getIntoNodePath() #will return the INT for the locator node closest parent pickedObj = pickedObj.getNetTag("GamePeiceLocator") if pickedObj: #make sure something actually was "picked" self.handleClicked(int(pickedObj)) def handleClicked(self, index): self.sound = Sequence( SoundInterval(self.clickSound)) #You clicked something play the click sound #First Moved Square if self.moveList == []: #check if owned if not index in self.mySquares and not index in self.myKings: return #you clicked on nothing or an opposing peice self.moveList.append(index) #put this on the movelist type = self.board.squareList[index].getState() if type == 3 or type == 4: self.moverType = "king" else: self.moverType = "normal" #Start blinking the new "active" peice self.blinker = Sequence() col = self.locatorList[index].getColor() self.blinker.append(LerpColorInterval(self.locatorList[index], .7,self.tintConstant, col)) self.blinker.append(LerpColorInterval(self.locatorList[index], .7, col ,self.tintConstant)) self.blinker.loop() self.sound.start() else: if index in self.mySquares or index in self.myKings: #selected a new peice for x in self.moveList: #the nodes from self.locatorList[x].setColor(1,1,1,1) self.locatorList[x].hide() self.blinker.finish() self.blinker = Sequence() col = self.locatorList[index].getColor() self.blinker.append(LerpColorInterval(self.locatorList[index], .7,self.tintConstant, col)) self.blinker.append(LerpColorInterval(self.locatorList[index], .7, col ,self.tintConstant)) self.blinker.loop() self.sound.start() #Swap back to the original peice #set the original node back to playercolor #self.locatorList[self.moveList[0]].setColor(self.playerColor) self.locatorList[self.moveList[0]].show() self.moveList = [] self.moveList.append(index) type = self.board.squareList[index].getState() if type == 3 or type == 4: self.moverType = "king" else: self.moverType = "normal" else: #item is either BLANK or the opposing players (checkJump will validate if it is opposing players) self.currentMove = index lastItem = self.board.squareList[self.moveList[len(self.moveList)-1]] thisItem = self.board.squareList[index] if self.mustJump == True: if lastItem.getNum() == index: #selected the same item twice self.blinker.finish() self.d_requestMove(self.moveList) self.isMyTurn = False self.moveList= [] return #print "CHECK LEGAL JUMP", self.checkLegalJump(lastItem, thisItem, self.moverType), "TYPE == ", self.moverType if self.checkLegalJump(lastItem, thisItem, self.moverType) == True: #There is a Legal Jump #ghostConstant here is a small alpha offset to give it a transparent look #tintConstant makes the peice a bit darker (necessary when ghosting) col = self.locatorList[index].getColor() self.locatorList[index].show() self.sound.start() if self.existsLegalJumpsFrom(index, self.moverType) == False: #No more Series of jumps => Commit the move self.moveList.append(index) self.blinker.finish() self.d_requestMove(self.moveList) self.moveList= [] self.isMyTurn = False else: self.moveList.append(index) if self.playerColorString == "white": x = self.locatorList[index].getChildren()[1] x.show() else: x = self.locatorList[index].getChildren()[2] x.show() if self.moverType == "king": x.find("**/checker_k*").show() #self.locatorList[index].ls() self.locatorList[index].setColor(Vec4(.5,.5,.5,.5)) else: #must do an adjacent move! if self.checkLegalMove(lastItem, thisItem, self.moverType) == True: #there exists a legal move self.moveList.append(index) #ghostConstant here is a small alpha offset to give it a transparent look #tintConstant makes the peice a bit darker (necessary when ghosting) col = self.locatorList[index].getColor() #self.locatorList[index].setColor(col - self.tintConstant - self.ghostConstant) self.locatorList[index].show() self.sound.start() self.blinker.finish() self.d_requestMove(self.moveList) self.moveList= [] self.isMyTurn = False def existsLegalJumpsFrom(self,index, peice): if peice == "king": for x in range(4): if self.board.squareList[index].getAdjacent()[x] != None and self.board.squareList[index].getJumps()[x] != None: # Off the board adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]] jump = self.board.squareList[self.board.squareList[index].getJumps()[x]] if adj.getState() == 0: pass elif adj.getState() == self.playerNum or adj.getState() == self.playerNum+2: pass elif jump.getState() == 0: #peice is owned by other dude and its a legal jump if not index in self.moveList and not jump.getNum() in self.moveList: return True else: pass return False elif peice == "normal": if self.playerNum == 1: moveForward = [1,2] elif self.playerNum == 2: moveForward = [0,3] for x in moveForward: if self.board.squareList[index].getAdjacent()[x] != None and self.board.squareList[index].getJumps()[x] != None: adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]] jump = self.board.squareList[self.board.squareList[index].getJumps()[x]] if adj.getState() == 0: pass elif adj.getState() == self.playerNum or adj.getState() == self.playerNum+2: pass else: if jump.getState() == 0: if not index in self.moveList: return True return False def existsLegalMovesFrom(self,index, peice): if peice == "king": for x in self.board.squareList[index].getAdjacent(): if x != None: if self.board.squareList[x].getState() == 0: return True return False elif peice == "normal": if self.playerNum == 1: moveForward = [1,2] elif self.playerNum == 2: moveForward = [0,3] for x in moveForward: if self.board.squareList[index].getAdjacent()[x] != None: adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]] if adj.getState() == 0: return True return False def checkLegalMove(self, firstSquare, secondSquare, peice): if (not firstSquare.getNum() in self.mySquares) and (not firstSquare.getNum() in self.myKings): return False if self.playerNum == 1: moveForward = [1,2] else: #self.playerNum == 2: moveForward = [0,3] if peice == "king": for x in range(4): if firstSquare.getAdjacent()[x] != None: if self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0 and secondSquare.getNum() in firstSquare.getAdjacent(): return True return False elif peice == "normal": for x in moveForward: if firstSquare.getAdjacent()[x] != None and secondSquare.getNum() in firstSquare.getAdjacent(): if self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0 and firstSquare.getAdjacent().index(secondSquare.getNum()) == x: return True return False def checkLegalJump(self, firstSquare, secondSquare, peice): if (not firstSquare.getNum() in self.mySquares) and (not firstSquare.getNum() in self.myKings) and len(self.moveList) == 1: return False if self.playerNum == 1: moveForward = [1,2] opposingPeices = [2,4] else: #self.playerNum == 2: moveForward = [0,3] opposingPeices = [1,3] if peice == "king": if secondSquare.getNum() in firstSquare.getJumps(): index = firstSquare.getJumps().index(secondSquare.getNum()) if self.board.squareList[firstSquare.getAdjacent()[index]].getState() in opposingPeices: return True else: return False elif peice == "normal": if secondSquare.getNum() in firstSquare.getJumps(): index = firstSquare.getJumps().index(secondSquare.getNum()) if index in moveForward: if self.board.squareList[firstSquare.getAdjacent()[index]].getState() in opposingPeices: #is the peice jumping over yours or his return True else: return False else: return False else: return False def d_requestMove(self, moveList): self.sendUpdate('requestMove', [moveList]) ########## ##setGameState (required broadcast ram) # #This is the function that handles the moves made after a move is parsed by the AI #and deemed to be valid # #If moveList is the empty List, then the player is asynchronously joining the game, (OBSERVING) #and just wants the board state. # #otherwise there is a series of jumps (or jump) that needs to be parsed and animated, then #consequently setting the board state # #after every setGameState, the client checks to see the current #Status of his peices (checkForWin), if he belives he won, he requests it to the server ######### def setGameState(self, tableState, moveList): if moveList != []: if self.board.squareList[moveList[0]].getState() == 1 or self.board.squareList[moveList[0]].getState() == 3: playerColor = "white" else: playerColor = "black" if self.board.squareList[moveList[0]].getState() <= 2: self.animatePeice(tableState, moveList, "normal", playerColor) else: self.animatePeice(tableState, moveList, "king", playerColor) else: self.updateGameState(tableState) def updateGameState(self, squares): self.board.setStates(squares) #set the board state self.mySquares = [] self.myKings = [] messenger.send('wakeup') #Because i designed this poorly, Must do a temporary playerNum #for observers, and set it back to None when i am done. isObserve = False if self.playerNum == None: self.playerNum = 1 self.playerColorString = "white" isObserve = True #Need to traverse the list to do the showing of peices ect for xx in range(32): #self.hideChildren(self.locatorList[xx].getChildren()) # Hide all off the pieces for blah in self.locatorList[xx].getChildren(): blah.hide() if self.locatorList[xx].getChildren().index(blah) != 0: blah1 = blah.find("**/checker_k*") owner = self.board.squareList[xx].getState() #Get the State of that square #print owner # This means it is MY Peice if owner == self.playerNum: #need to see what color i am if self.playerColorString == "white": x = self.locatorList[xx].getChildren()[1] # white x.show() x.find("**/checker_k*").hide() else: x = self.locatorList[xx].getChildren()[2] # black x.show() x.find("**/checker_k*").hide() self.mySquares.append(xx) ####################### elif owner == 0: # blank Tile self.hideChildren(self.locatorList[xx].getChildren()) # Hide all off the pieces ####################### elif owner == self.playerNum + 2: #its MY peice but its a KING if self.playerColorString == "white": x = self.locatorList[xx].getChildren()[1] # white x.show() x.find("**/checker_k*").show() else: x = self.locatorList[xx].getChildren()[2] # black x.show() x.find("**/checker_k*").show() self.myKings.append(xx) ######################## else: # opposing player peice if owner <= 2: #Opposing player Non king if self.playerColorString == "white": #we are white so show the black piece x = self.locatorList[xx].getChildren()[2] x.show() x.find("**/checker_k*").hide() else: x = self.locatorList[xx].getChildren()[1] x.show() x.find("**/checker_k*").hide() else: #the peice is an opposing players KING if self.playerColorString == "white": x = self.locatorList[xx].getChildren()[2] x.show() x.find("**/checker_k*").show() else: x = self.locatorList[xx].getChildren()[1] x.show() x.find("**/checker_k*").show() ########################### if isObserve == True: self.playerNum = None self.playerColorString = None return ###### #A player MUST move if he has a legal jump #This will flag the bool making him do so ###### self.mustJump = False self.hasNormalMoves = False for x in self.myKings: if self.existsLegalJumpsFrom(x, "king") == True: self.mustJump = True break else: self.mustJump = False if self.mustJump == False: for x in self.mySquares: if self.existsLegalJumpsFrom(x, "normal") == True: self.mustJump = True break else: self.mustJump = False ############# #if i dont have any jumps, Must check to see if i have any legal moves #If i dont, then the game is over. ### if self. mustJump != True: #Check for legal moves and possibly LOSS for x in self.mySquares: if self.existsLegalMovesFrom(x, "normal") == True: self.hasNormalMoves = True break else: self.hasNormalMoves = False if self.hasNormalMoves == False: #make sure to not overRide a True for x in self.myKings: if self.existsLegalMovesFrom(x, "king") == True: self.hasNormalMoves = True break else: self.hasNormalMoves = False if self.mustJump == False and self.hasNormalMoves == False: pass #Server is calculating everything def hideChildren(self, nodeList): for x in range (1,2): nodeList[x].hide() def animatePeice(self, tableState, moveList,type, playerColor): messenger.send('wakeup') ###for x in self.locatorList: #x.show() if playerColor == "white": gamePeiceForAnimation = loader.loadModel("phase_6/models/golf/regular_checker_piecewhite.bam") else: gamePeiceForAnimation = loader.loadModel("phase_6/models/golf/regular_checker_pieceblack.bam") if type == "king": gamePeiceForAnimation.find("**/checker_k*").show() else: gamePeiceForAnimation.find("**/checker_k*").hide() gamePeiceForAnimation.reparentTo(self.boardNode) gamePeiceForAnimation.setPos(self.locatorList[moveList[0]].getPos()) if self.isRotated == True: gamePeiceForAnimation.setH(180) #self.hideChildren(self.locatorList[moveList[0]].getChildren()) #self.locatorList[moveList[0]].hide() for x in self.locatorList[moveList[0]].getChildren(): x.hide() checkersPeiceTrack = Sequence() length = len(moveList) for x in range(length - 1): checkersPeiceTrack.append(Parallel( SoundInterval(self.moveSound), ProjectileInterval(gamePeiceForAnimation, endPos = self.locatorList[moveList[x+1]].getPos(), duration = .5 ))) checkersPeiceTrack.append(Func(gamePeiceForAnimation.removeNode)) checkersPeiceTrack.append(Func(self.updateGameState, tableState)) checkersPeiceTrack.append(Func(self.unAlpha, moveList)) checkersPeiceTrack.start() def announceWin(self, avId): self.fsm.request('gameOver') def unAlpha(self, moveList): for x in moveList: self.locatorList[x].setColorOff() ########### ##doRandomMove # #If a clients move Timer runs out, it will calculate a random move for him #after 3 random moves, it kicks the client out of the game by pushing the #"get up" button for him. ########### def doRandomMove(self): import random move = [] foundLegal = False self.blinker.pause() self.numRandomMoves += 1 while not foundLegal: x = random.randint(0,9) for y in self.board.getAdjacent(self.mySquares[x]): if y != None and self.board.getState(y) == 0: move.append(self.mySquares[x]) move.append(y) foundLegal = True break if move == []: pass #current flaw in the logic, but shouldnt really ever happen #though on live it might #print "random move is empty" playSound = Sequence(SoundInterval(self.knockSound)) playSound.start() self.d_requestMove(move) self.moveList=[] self.isMyTurn = False if(self.numRandomMoves >= 5): self.exitButtonPushed() def doNothing(self): pass
class DistributedCheckers(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, 'DistributedCheckers') DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel('phase_6/models/golf/regular_checker_game.bam') self.boardNode.reparentTo(self) self.board = CheckersBoard() self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.moveList = [] self.mySquares = [] self.myKings = [] self.isRotated = False self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = base.camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(ToontownGlobals.WallBitmask) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.playerColors = [Vec4(0, 0, 1, 1), Vec4(0, 1, 0, 1)] self.tintConstant = Vec4(0.25, 0.25, 0.25, 0.5) self.ghostConstant = Vec4(0, 0, 0, 0.8) self.startingPositions = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]] self.knockSound = base.loadSfx('phase_5/audio/sfx/GUI_knock_1.ogg') self.clickSound = base.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.ogg') self.moveSound = base.loadSfx('phase_6/audio/sfx/CC_move.ogg') self.accept('stoppedAsleep', self.handleSleep) self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin'])], 'waitingToBegin', 'waitingToBegin') x = self.boardNode.find('**/locator*') self.locatorList = x.getChildren() tempList = [] for x in xrange(0, 32): self.locatorList[x].setTag('GamePeiceLocator', '%d' % x) tempList.append(self.locatorList[x].attachNewNode(CollisionNode('picker%d' % x))) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, 0.39)) for z in self.locatorList: y = loader.loadModel('phase_6/models/golf/regular_checker_piecewhite.bam') y.find('**/checker_k*').hide() zz = loader.loadModel('phase_6/models/golf/regular_checker_pieceblack.bam') zz.find('**/checker_k*').hide() y.reparentTo(z) y.hide() zz.reparentTo(z) zz.hide() return def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: self.seatPos = self.table.tableState.index(base.localAvatar.doId) def handleSleep(self, task = None): if self.fsm.getCurrentState().getName() == 'waitingToBegin': self.exitButtonPushed() if task != None: task.done return def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None return def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None return def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState().getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() return def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(-.74, 0, -0.2) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doNothing) else: self.clockNode.countdown(timeLeft, self.doNothing) self.clockNode.show() return def gameStart(self, playerNum): if playerNum != 255: self.playerNum = playerNum if self.playerNum == 1: self.playerColorString = 'white' else: self.playerColorString = 'black' self.playerColor = self.playerColors[playerNum - 1] self.moveCameraForGame() self.fsm.request('playing') def sendTurn(self, playersTurn): if self.fsm.getCurrentState().getName() == 'playing': if playersTurn == self.playerNum: self.isMyTurn = True self.enableTurnScreenText(playersTurn) def illegalMove(self): self.exitButtonPushed() def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.finish() rotation = 0 if self.seatPos > 2: if self.playerNum == 1: rotation = 180 elif self.playerNum == 2: rotation = 0 for x in self.locatorList: x.setH(180) self.isRotated = True elif self.playerNum == 1: rotation = 0 elif self.playerNum == 2: rotation = 180 for x in self.locatorList: x.setH(180) self.isRotated = True int = LerpHprInterval(self.boardNode, 4.2, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) int.start() def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() return def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() return def enterGameOver(self): pass def exitGameOver(self): pass def exitWaitCountdown(self): self.__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableScreenText(self): defaultPos = (-.8, -0.4) if self.playerNum == 1: message = TTLocalizer.CheckersColorWhite color = Vec4(1, 1, 1, 1) elif self.playerNum == 2: message = TTLocalizer.CheckersColorBlack color = Vec4(0, 0, 0, 1) else: message = TTLocalizer.CheckersObserver color = Vec4(0, 0, 0, 1) defaultPos = (-.8, -0.4) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.1), scale=0.15, command=lambda self = self: self.startButtonPushed()) return def enableLeaveButton(self): self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.CheckersIts if self.turnText != None: self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) elif player == 1: message2 = TTLocalizer.CheckersWhiteTurn color = (1, 1, 1, 1) elif player == 2: message2 = TTLocalizer.CheckersBlackTurn color = (0, 0, 0, 1) self.turnText = OnscreenText(text=message1 + message2, pos=(-0.8, -0.5), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) return def startButtonPushed(self): self.sendUpdate('requestBegin') self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate('requestExit') def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True: mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.getNetTag('GamePeiceLocator') if pickedObj: self.handleClicked(int(pickedObj)) def handleClicked(self, index): self.sound = Sequence(SoundInterval(self.clickSound)) if self.moveList == []: if index not in self.mySquares and index not in self.myKings: return self.moveList.append(index) type = self.board.squareList[index].getState() if type == 3 or type == 4: self.moverType = 'king' else: self.moverType = 'normal' self.blinker = Sequence() col = self.locatorList[index].getColor() self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, self.tintConstant, col)) self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, col, self.tintConstant)) self.blinker.loop() self.sound.start() elif index in self.mySquares or index in self.myKings: for x in self.moveList: self.locatorList[x].setColor(1, 1, 1, 1) self.locatorList[x].hide() self.blinker.finish() self.blinker = Sequence() col = self.locatorList[index].getColor() self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, self.tintConstant, col)) self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, col, self.tintConstant)) self.blinker.loop() self.sound.start() self.locatorList[self.moveList[0]].show() self.moveList = [] self.moveList.append(index) type = self.board.squareList[index].getState() if type == 3 or type == 4: self.moverType = 'king' else: self.moverType = 'normal' else: self.currentMove = index lastItem = self.board.squareList[self.moveList[len(self.moveList) - 1]] thisItem = self.board.squareList[index] if self.mustJump == True: if lastItem.getNum() == index: self.blinker.finish() self.d_requestMove(self.moveList) self.isMyTurn = False self.moveList = [] return if self.checkLegalJump(lastItem, thisItem, self.moverType) == True: col = self.locatorList[index].getColor() self.locatorList[index].show() self.sound.start() if self.existsLegalJumpsFrom(index, self.moverType) == False: self.moveList.append(index) self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False else: self.moveList.append(index) if self.playerColorString == 'white': x = self.locatorList[index].getChildren()[1] x.show() else: x = self.locatorList[index].getChildren()[2] x.show() if self.moverType == 'king': x.find('**/checker_k*').show() self.locatorList[index].setColor(Vec4(0.5, 0.5, 0.5, 0.5)) elif self.checkLegalMove(lastItem, thisItem, self.moverType) == True: self.moveList.append(index) col = self.locatorList[index].getColor() self.locatorList[index].show() self.sound.start() self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False def existsLegalJumpsFrom(self, index, peice): if peice == 'king': for x in xrange(4): if self.board.squareList[index].getAdjacent()[x] != None and \ self.board.squareList[index].getJumps()[x] != None: adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]] jump = self.board.squareList[self.board.squareList[index].getJumps()[x]] if adj.getState() == 0: pass elif adj.getState() == self.playerNum or adj.getState() == self.playerNum + 2: pass elif jump.getState() == 0: if index not in self.moveList and jump.getNum() not in self.moveList: return True return False elif peice == 'normal': if self.playerNum == 1: moveForward = [1, 2] elif self.playerNum == 2: moveForward = [0, 3] for x in moveForward: if self.board.squareList[index].getAdjacent()[x] != None and \ self.board.squareList[index].getJumps()[x] != None: adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]] jump = self.board.squareList[self.board.squareList[index].getJumps()[x]] if adj.getState() == 0: pass elif adj.getState() == self.playerNum or adj.getState() == self.playerNum + 2: pass elif jump.getState() == 0: if index not in self.moveList: return True return False def existsLegalMovesFrom(self, index, peice): if peice == 'king': for x in self.board.squareList[index].getAdjacent(): if x != None: if self.board.squareList[x].getState() == 0: return True return False elif peice == 'normal': if self.playerNum == 1: moveForward = [1, 2] elif self.playerNum == 2: moveForward = [0, 3] for x in moveForward: if self.board.squareList[index].getAdjacent()[x] != None: adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]] if adj.getState() == 0: return True return False return def checkLegalMove(self, firstSquare, secondSquare, peice): if firstSquare.getNum() not in self.mySquares and firstSquare.getNum() not in self.myKings: return False if self.playerNum == 1: moveForward = [1, 2] else: moveForward = [0, 3] if peice == 'king': for x in xrange(4): if firstSquare.getAdjacent()[x] != None: if self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0 and secondSquare.getNum() in firstSquare.getAdjacent(): return True return False elif peice == 'normal': for x in moveForward: if firstSquare.getAdjacent()[x] != None and secondSquare.getNum() in firstSquare.getAdjacent(): if self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0 and firstSquare.getAdjacent().index(secondSquare.getNum()) == x: return True return False return def checkLegalJump(self, firstSquare, secondSquare, peice): if firstSquare.getNum() not in self.mySquares and firstSquare.getNum() not in self.myKings and len(self.moveList) == 1: return False if self.playerNum == 1: moveForward = [1, 2] opposingPeices = [2, 4] else: moveForward = [0, 3] opposingPeices = [1, 3] if peice == 'king': if secondSquare.getNum() in firstSquare.getJumps(): index = firstSquare.getJumps().index(secondSquare.getNum()) if self.board.squareList[firstSquare.getAdjacent()[index]].getState() in opposingPeices: return True else: return False elif peice == 'normal': if secondSquare.getNum() in firstSquare.getJumps(): index = firstSquare.getJumps().index(secondSquare.getNum()) if index in moveForward: if self.board.squareList[firstSquare.getAdjacent()[index]].getState() in opposingPeices: return True else: return False else: return False else: return False def d_requestMove(self, moveList): self.sendUpdate('requestMove', [moveList]) def setGameState(self, tableState, moveList): if moveList != []: if self.board.squareList[moveList[0]].getState() == 1 or self.board.squareList[moveList[0]].getState() == 3: playerColor = 'white' else: playerColor = 'black' if self.board.squareList[moveList[0]].getState() <= 2: self.animatePeice(tableState, moveList, 'normal', playerColor) else: self.animatePeice(tableState, moveList, 'king', playerColor) else: self.updateGameState(tableState) def updateGameState(self, squares): self.board.setStates(squares) self.mySquares = [] self.myKings = [] messenger.send('wakeup') isObserve = False if self.playerNum == None: self.playerNum = 1 self.playerColorString = 'white' isObserve = True for xx in xrange(32): for blah in self.locatorList[xx].getChildren(): blah.hide() if self.locatorList[xx].getChildren().index(blah) != 0: blah1 = blah.find('**/checker_k*') owner = self.board.squareList[xx].getState() if owner == self.playerNum: if self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').hide() else: x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').hide() self.mySquares.append(xx) elif owner == 0: self.hideChildren(self.locatorList[xx].getChildren()) elif owner == self.playerNum + 2: if self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').show() else: x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').show() self.myKings.append(xx) elif owner <= 2: if self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').hide() else: x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').hide() elif self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').show() else: x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').show() if isObserve == True: self.playerNum = None self.playerColorString = None return self.mustJump = False self.hasNormalMoves = False for x in self.myKings: if self.existsLegalJumpsFrom(x, 'king') == True: self.mustJump = True break else: self.mustJump = False if self.mustJump == False: for x in self.mySquares: if self.existsLegalJumpsFrom(x, 'normal') == True: self.mustJump = True break else: self.mustJump = False if self.mustJump != True: for x in self.mySquares: if self.existsLegalMovesFrom(x, 'normal') == True: self.hasNormalMoves = True break else: self.hasNormalMoves = False if self.hasNormalMoves == False: for x in self.myKings: if self.existsLegalMovesFrom(x, 'king') == True: self.hasNormalMoves = True break else: self.hasNormalMoves = False if self.mustJump == False and self.hasNormalMoves == False: pass return def hideChildren(self, nodeList): for x in xrange(1, 2): nodeList[x].hide() def animatePeice(self, tableState, moveList, type, playerColor): messenger.send('wakeup') if playerColor == 'white': gamePeiceForAnimation = loader.loadModel('phase_6/models/golf/regular_checker_piecewhite.bam') else: gamePeiceForAnimation = loader.loadModel('phase_6/models/golf/regular_checker_pieceblack.bam') if type == 'king': gamePeiceForAnimation.find('**/checker_k*').show() else: gamePeiceForAnimation.find('**/checker_k*').hide() gamePeiceForAnimation.reparentTo(self.boardNode) gamePeiceForAnimation.setPos(self.locatorList[moveList[0]].getPos()) if self.isRotated == True: gamePeiceForAnimation.setH(180) for x in self.locatorList[moveList[0]].getChildren(): x.hide() checkersPeiceTrack = Sequence() length = len(moveList) for x in xrange(length - 1): checkersPeiceTrack.append(Parallel(SoundInterval(self.moveSound), ProjectileInterval(gamePeiceForAnimation, endPos=self.locatorList[moveList[x + 1]].getPos(), duration=0.5))) checkersPeiceTrack.append(Func(gamePeiceForAnimation.removeNode)) checkersPeiceTrack.append(Func(self.updateGameState, tableState)) checkersPeiceTrack.append(Func(self.unAlpha, moveList)) checkersPeiceTrack.start() def announceWin(self, avId): self.fsm.request('gameOver') def unAlpha(self, moveList): for x in moveList: self.locatorList[x].setColorOff() def doRandomMove(self): import random move = [] foundLegal = False self.blinker.pause() self.numRandomMoves += 1 while not foundLegal: x = random.randint(0, 9) for y in self.board.getAdjacent(self.mySquares[x]): if y != None and self.board.getState(y) == 0: move.append(self.mySquares[x]) move.append(y) foundLegal = True break if move == []: pass playSound = Sequence(SoundInterval(self.knockSound)) playSound.start() self.d_requestMove(move) self.moveList = [] self.isMyTurn = False if self.numRandomMoves >= 5: self.exitButtonPushed() return def doNothing(self): pass
class DistributedCheckers(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, 'DistributedCheckers') DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel( 'phase_6/models/golf/regular_checker_game') self.boardNode.reparentTo(self) self.board = CheckersBoard() self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.moveList = [] self.mySquares = [] self.myKings = [] self.isRotated = False self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(ToontownGlobals.WallBitmask) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel( 'phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find( '**/InventoryButtonRollover') self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.playerColors = [Vec4(0, 0, 1, 1), Vec4(0, 1, 0, 1)] self.tintConstant = Vec4(0.25, 0.25, 0.25, 0.5) self.ghostConstant = Vec4(0, 0, 0, 0.8) self.startingPositions = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ]] self.knockSound = base.loader.loadSfx( 'phase_5/audio/sfx/GUI_knock_1.ogg') self.clickSound = base.loader.loadSfx( 'phase_3/audio/sfx/GUI_balloon_popup.ogg') self.moveSound = base.loader.loadSfx('phase_6/audio/sfx/CC_move.ogg') self.accept('stoppedAsleep', self.handleSleep) self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [ State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin']) ], 'waitingToBegin', 'waitingToBegin') x = self.boardNode.find('**/locator*') self.locatorList = x.getChildren() tempList = [] for x in range(0, 32): self.locatorList[x].setTag('GamePeiceLocator', '%d' % x) tempList.append(self.locatorList[x].attachNewNode( CollisionNode('picker%d' % x))) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, 0.39)) for z in self.locatorList: y = loader.loadModel( 'phase_6/models/golf/regular_checker_piecewhite') y.find('**/checker_k*').hide() zz = loader.loadModel( 'phase_6/models/golf/regular_checker_pieceblack') zz.find('**/checker_k*').hide() y.reparentTo(z) y.hide() zz.reparentTo(z) zz.hide() return def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: self.seatPos = self.table.tableState.index( base.localAvatar.doId) def handleSleep(self, task=None): if self.fsm.getCurrentState().getName() == 'waitingToBegin': self.exitButtonPushed() if task != None: task.done return def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None return def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None return def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState( ).getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() return def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(-0.74, 0, -0.2) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doNothing) else: self.clockNode.countdown(timeLeft, self.doNothing) self.clockNode.show() return def gameStart(self, playerNum): if playerNum != 255: self.playerNum = playerNum if self.playerNum == 1: self.playerColorString = 'white' else: self.playerColorString = 'black' self.playerColor = self.playerColors[(playerNum - 1)] self.moveCameraForGame() self.fsm.request('playing') def sendTurn(self, playersTurn): if self.fsm.getCurrentState().getName() == 'playing': if playersTurn == self.playerNum: self.isMyTurn = True self.enableTurnScreenText(playersTurn) def illegalMove(self): self.exitButtonPushed() def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.finish() rotation = 0 if self.seatPos > 2: if self.playerNum == 1: rotation = 180 else: if self.playerNum == 2: rotation = 0 for x in self.locatorList: x.setH(180) self.isRotated = True else: if self.playerNum == 1: rotation = 0 else: if self.playerNum == 2: rotation = 180 for x in self.locatorList: x.setH(180) self.isRotated = True int = LerpHprInterval( self.boardNode, 4.2, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) int.start() def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() return def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() return def enterGameOver(self): pass def exitGameOver(self): pass def exitWaitCountdown(self): self.__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self=self: self.exitButtonPushed()) return def enableScreenText(self): defaultPos = (-0.8, -0.4) if self.playerNum == 1: message = TTLocalizer.CheckersColorWhite color = Vec4(1, 1, 1, 1) else: if self.playerNum == 2: message = TTLocalizer.CheckersColorBlack color = Vec4(0, 0, 0, 1) else: message = TTLocalizer.CheckersObserver color = Vec4(0, 0, 0, 1) defaultPos = (-0.8, -0.4) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.1), scale=0.15, command=lambda self=self: self.startButtonPushed()) return def enableLeaveButton(self): self.leaveButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self=self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.CheckersIts if self.turnText != None: self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) else: if player == 1: message2 = TTLocalizer.CheckersWhiteTurn color = (1, 1, 1, 1) else: if player == 2: message2 = TTLocalizer.CheckersBlackTurn color = (0, 0, 0, 1) self.turnText = OnscreenText(text=message1 + message2, pos=(-0.8, -0.5), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) return def startButtonPushed(self): self.sendUpdate('requestBegin') self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate('requestExit') def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True: mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.getNetTag('GamePeiceLocator') if pickedObj: self.handleClicked(int(pickedObj)) def handleClicked(self, index): self.sound = Sequence(SoundInterval(self.clickSound)) if self.moveList == []: if index not in self.mySquares and index not in self.myKings: return self.moveList.append(index) type = self.board.squareList[index].getState() if type == 3 or type == 4: self.moverType = 'king' else: self.moverType = 'normal' self.blinker = Sequence() col = self.locatorList[index].getColor() self.blinker.append( LerpColorInterval(self.locatorList[index], 0.7, self.tintConstant, col)) self.blinker.append( LerpColorInterval(self.locatorList[index], 0.7, col, self.tintConstant)) self.blinker.loop() self.sound.start() else: if index in self.mySquares or index in self.myKings: for x in self.moveList: self.locatorList[x].setColor(1, 1, 1, 1) self.locatorList[x].hide() self.blinker.finish() self.blinker = Sequence() col = self.locatorList[index].getColor() self.blinker.append( LerpColorInterval(self.locatorList[index], 0.7, self.tintConstant, col)) self.blinker.append( LerpColorInterval(self.locatorList[index], 0.7, col, self.tintConstant)) self.blinker.loop() self.sound.start() self.locatorList[self.moveList[0]].show() self.moveList = [] self.moveList.append(index) type = self.board.squareList[index].getState() if type == 3 or type == 4: self.moverType = 'king' else: self.moverType = 'normal' else: self.currentMove = index lastItem = self.board.squareList[self.moveList[( len(self.moveList) - 1)]] thisItem = self.board.squareList[index] if self.mustJump == True: if lastItem.getNum() == index: self.blinker.finish() self.d_requestMove(self.moveList) self.isMyTurn = False self.moveList = [] return if self.checkLegalJump(lastItem, thisItem, self.moverType) == True: col = self.locatorList[index].getColor() self.locatorList[index].show() self.sound.start() if self.existsLegalJumpsFrom(index, self.moverType) == False: self.moveList.append(index) self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False else: self.moveList.append(index) if self.playerColorString == 'white': x = self.locatorList[index].getChildren()[1] x.show() else: x = self.locatorList[index].getChildren()[2] x.show() if self.moverType == 'king': x.find('**/checker_k*').show() self.locatorList[index].setColor( Vec4(0.5, 0.5, 0.5, 0.5)) else: if self.checkLegalMove(lastItem, thisItem, self.moverType) == True: self.moveList.append(index) col = self.locatorList[index].getColor() self.locatorList[index].show() self.sound.start() self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False def existsLegalJumpsFrom(self, index, peice): if peice == 'king': for x in range(4): if self.board.squareList[index].getAdjacent( )[x] != None and self.board.squareList[index].getJumps( )[x] != None: adj = self.board.squareList[ self.board.squareList[index].getAdjacent()[x]] jump = self.board.squareList[ self.board.squareList[index].getJumps()[x]] if adj.getState() == 0: pass elif adj.getState() == self.playerNum or adj.getState( ) == self.playerNum + 2: pass elif jump.getState() == 0: if index not in self.moveList and jump.getNum( ) not in self.moveList: return True return False if peice == 'normal': if self.playerNum == 1: moveForward = [1, 2] else: if self.playerNum == 2: moveForward = [0, 3] for x in moveForward: if self.board.squareList[index].getAdjacent( )[x] != None and self.board.squareList[index].getJumps( )[x] != None: adj = self.board.squareList[ self.board.squareList[index].getAdjacent()[x]] jump = self.board.squareList[ self.board.squareList[index].getJumps()[x]] if adj.getState() == 0: pass elif adj.getState() == self.playerNum or adj.getState( ) == self.playerNum + 2: pass elif jump.getState() == 0: if index not in self.moveList: return True return False return def existsLegalMovesFrom(self, index, peice): if peice == 'king': for x in self.board.squareList[index].getAdjacent(): if x != None: if self.board.squareList[x].getState() == 0: return True return False if peice == 'normal': if self.playerNum == 1: moveForward = [1, 2] else: if self.playerNum == 2: moveForward = [0, 3] for x in moveForward: if self.board.squareList[index].getAdjacent()[x] != None: adj = self.board.squareList[ self.board.squareList[index].getAdjacent()[x]] if adj.getState() == 0: return True return False return def checkLegalMove(self, firstSquare, secondSquare, peice): if firstSquare.getNum() not in self.mySquares and firstSquare.getNum( ) not in self.myKings: return False if self.playerNum == 1: moveForward = [1, 2] else: moveForward = [0, 3] if peice == 'king': for x in range(4): if firstSquare.getAdjacent()[x] != None: if self.board.squareList[firstSquare.getAdjacent( )[x]].getState() == 0 and secondSquare.getNum( ) in firstSquare.getAdjacent(): return True return False if peice == 'normal': for x in moveForward: if firstSquare.getAdjacent( )[x] != None and secondSquare.getNum( ) in firstSquare.getAdjacent(): if self.board.squareList[firstSquare.getAdjacent( )[x]].getState() == 0 and firstSquare.getAdjacent().index( secondSquare.getNum()) == x: return True return False return def checkLegalJump(self, firstSquare, secondSquare, peice): if firstSquare.getNum() not in self.mySquares and firstSquare.getNum( ) not in self.myKings and len(self.moveList) == 1: return False if self.playerNum == 1: moveForward = [1, 2] opposingPeices = [2, 4] else: moveForward = [0, 3] opposingPeices = [1, 3] if peice == 'king': if secondSquare.getNum() in firstSquare.getJumps(): index = firstSquare.getJumps().index(secondSquare.getNum()) if self.board.squareList[firstSquare.getAdjacent() [index]].getState() in opposingPeices: return True return False else: if peice == 'normal': if secondSquare.getNum() in firstSquare.getJumps(): index = firstSquare.getJumps().index(secondSquare.getNum()) if index in moveForward: if self.board.squareList[firstSquare.getAdjacent( )[index]].getState() in opposingPeices: return True return False else: return False else: return False def d_requestMove(self, moveList): self.sendUpdate('requestMove', [moveList]) def setGameState(self, tableState, moveList): if moveList != []: if self.board.squareList[moveList[0]].getState( ) == 1 or self.board.squareList[moveList[0]].getState() == 3: playerColor = 'white' else: playerColor = 'black' if self.board.squareList[moveList[0]].getState() <= 2: self.animatePeice(tableState, moveList, 'normal', playerColor) else: self.animatePeice(tableState, moveList, 'king', playerColor) else: self.updateGameState(tableState) def updateGameState(self, squares): self.board.setStates(squares) self.mySquares = [] self.myKings = [] messenger.send('wakeup') isObserve = False if self.playerNum == None: self.playerNum = 1 self.playerColorString = 'white' isObserve = True for xx in range(32): for blah in self.locatorList[xx].getChildren(): blah.hide() if self.locatorList[xx].getChildren().index(blah) != 0: blah1 = blah.find('**/checker_k*') owner = self.board.squareList[xx].getState() if owner == self.playerNum: if self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').hide() else: x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').hide() self.mySquares.append(xx) elif owner == 0: self.hideChildren(self.locatorList[xx].getChildren()) elif owner == self.playerNum + 2: if self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').show() else: x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').show() self.myKings.append(xx) elif owner <= 2: if self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').hide() else: x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').hide() elif self.playerColorString == 'white': x = self.locatorList[xx].getChildren()[2] x.show() x.find('**/checker_k*').show() else: x = self.locatorList[xx].getChildren()[1] x.show() x.find('**/checker_k*').show() if isObserve == True: self.playerNum = None self.playerColorString = None return self.mustJump = False self.hasNormalMoves = False for x in self.myKings: if self.existsLegalJumpsFrom(x, 'king') == True: self.mustJump = True break else: self.mustJump = False if self.mustJump == False: for x in self.mySquares: if self.existsLegalJumpsFrom(x, 'normal') == True: self.mustJump = True break else: self.mustJump = False if self.mustJump != True: for x in self.mySquares: if self.existsLegalMovesFrom(x, 'normal') == True: self.hasNormalMoves = True break else: self.hasNormalMoves = False if self.hasNormalMoves == False: for x in self.myKings: if self.existsLegalMovesFrom(x, 'king') == True: self.hasNormalMoves = True break else: self.hasNormalMoves = False if self.mustJump == False and self.hasNormalMoves == False: pass return def hideChildren(self, nodeList): for x in range(1, 2): nodeList[x].hide() def animatePeice(self, tableState, moveList, type, playerColor): messenger.send('wakeup') if playerColor == 'white': gamePeiceForAnimation = loader.loadModel( 'phase_6/models/golf/regular_checker_piecewhite') else: gamePeiceForAnimation = loader.loadModel( 'phase_6/models/golf/regular_checker_pieceblack') if type == 'king': gamePeiceForAnimation.find('**/checker_k*').show() else: gamePeiceForAnimation.find('**/checker_k*').hide() gamePeiceForAnimation.reparentTo(self.boardNode) gamePeiceForAnimation.setPos(self.locatorList[moveList[0]].getPos()) if self.isRotated == True: gamePeiceForAnimation.setH(180) for x in self.locatorList[moveList[0]].getChildren(): x.hide() checkersPeiceTrack = Sequence() length = len(moveList) for x in range(length - 1): checkersPeiceTrack.append( Parallel( SoundInterval(self.moveSound), ProjectileInterval( gamePeiceForAnimation, endPos=self.locatorList[moveList[(x + 1)]].getPos(), duration=0.5))) checkersPeiceTrack.append(Func(gamePeiceForAnimation.removeNode)) checkersPeiceTrack.append(Func(self.updateGameState, tableState)) checkersPeiceTrack.append(Func(self.unAlpha, moveList)) checkersPeiceTrack.start() def announceWin(self, avId): self.fsm.request('gameOver') def unAlpha(self, moveList): for x in moveList: self.locatorList[x].setColorOff() def doRandomMove(self): import random move = [] foundLegal = False self.blinker.pause() self.numRandomMoves += 1 while not foundLegal: x = random.randint(0, 9) for y in self.board.getAdjacent(self.mySquares[x]): if y != None and self.board.getState(y) == 0: move.append(self.mySquares[x]) move.append(y) foundLegal = True break if move == []: pass playSound = Sequence(SoundInterval(self.knockSound)) playSound.start() self.d_requestMove(move) self.moveList = [] self.isMyTurn = False if self.numRandomMoves >= 5: self.exitButtonPushed() return def doNothing(self): pass
class DistributedViewingBlock(DistributedStartingBlock): notify = DirectNotifyGlobal.directNotify.newCategory( 'DistributedViewingBlock') sphereRadius = 6 def __init__(self, cr): DistributedStartingBlock.__init__(self, cr) self.timer = None return def delete(self): if self.timer is not None: self.timer.destroy() del self.timer DistributedStartingBlock.delete(self) return def generateInit(self): self.notify.debugStateCall(self) DistributedObject.DistributedObject.generateInit(self) self.nodePath = NodePath(self.uniqueName('StartingBlock')) self.collSphere = CollisionSphere(-1, 6.75, -1, self.sphereRadius) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.uniqueName('StartingBlockSphere')) self.collNode.setCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.nodePath.attachNewNode(self.collNode) def announceGenerate(self): self.notify.debugStateCall(self) DistributedObject.DistributedObject.announceGenerate(self) self.nodePath.reparentTo(render) self.accept(self.uniqueName('enterStartingBlockSphere'), self.__handleEnterSphere) if (__debug__): if self.testLOD: self.__generateKartAppearTrack() def setPadLocationId(self, padLocationId): self.notify.debugStateCall(self) self.movieNode = self.nodePath.attachNewNode( self.uniqueName('MovieNode')) self.exitMovieNode = self.nodePath.attachNewNode( self.uniqueName('ExitMovieNode')) if padLocationId % 2: self.movieNode.setPosHpr(0, 6.5, 0, 0, 0, 0) else: self.movieNode.setPosHpr(0, -6.5, 0, 0, 0, 0) self.exitMovieNode.setPosHpr(3, 6.5, 0, 270, 0, 0) self.collNodePath.reparentTo(self.movieNode) def __handleEnterSphere(self, collEntry): if base.localAvatar.doId == self.lastAvId and globalClock.getFrameCount( ) <= self.lastFrame + 1: self.notify.debug('Ignoring duplicate entry for avatar.') return if base.localAvatar.hp > 0: def handleEnterRequest(self=self): self.ignore('stoppedAsleep') if hasattr(self.dialog, 'doneStatus') and self.dialog.doneStatus == 'ok': self.d_requestEnter() else: self.cr.playGame.getPlace().setState('walk') self.dialog.ignoreAll() self.dialog.cleanup() del self.dialog self.cr.playGame.getPlace().fsm.request('stopped') self.accept('stoppedAsleep', handleEnterRequest) doneEvent = 'enterRequest|dialog' msg = TTLocalizer.StartingBlock_EnterShowPad self.dialog = TTGlobalDialog(msg, doneEvent, 4) self.dialog.accept(doneEvent, handleEnterRequest) def generateCameraMoveTrack(self): self.cPos = camera.getPos(self.av) self.cHpr = camera.getHpr(self.av) cameraPos = Point3(23, -10, 7) cameraHpr = Point3(65, -10, 0) camera.wrtReparentTo(self.nodePath) cameraTrack = LerpPosHprInterval(camera, 1.5, cameraPos, cameraHpr) return cameraTrack def makeGui(self): self.notify.debugStateCall(self) if self.timer is not None: return self.timer = ToontownTimer() self.timer.setScale(0.3) self.timer.setPos(-0.173333, 0, 0.27) self.timer.reparentTo(base.a2dBottomRight) self.timer.hide() DistributedStartingBlock.makeGui(self) return def showGui(self): self.notify.debugStateCall(self) self.timer.show() DistributedStartingBlock.showGui(self) def hideGui(self): self.notify.debugStateCall(self) if not hasattr(self, 'timer') or self.timer is None: return self.timer.reset() self.timer.hide() DistributedStartingBlock.hideGui(self) return def countdown(self): countdownTime = KartGlobals.COUNTDOWN_TIME - globalClockDelta.localElapsedTime( self.kartPad.getTimestamp(self.avId)) self.timer.countdown(countdownTime) def enterEnterMovie(self): self.notify.debug( '%d enterEnterMovie: Entering the Enter Movie State.' % self.doId) if base.config.GetBool('want-qa-regression', 0): raceName = "Display Block (No Race)" if hasattr(self.kartPad, "trackType"): raceName = TTLocalizer.KartRace_RaceNames[ self.kartPad.trackType] self.notify.info('QA-REGRESSION: KARTING: %s' % raceName) pos = self.nodePath.getPos(render) hpr = self.nodePath.getHpr(render) pos.addZ(1.7) hpr.addX(270) self.kartNode.setPosHpr(pos, hpr) toonTrack = self.generateToonMoveTrack() kartTrack = self.generateKartAppearTrack() jumpTrack = self.generateToonJumpTrack() name = self.av.uniqueName('EnterRaceTrack') if self.av is not None and self.localToonKarting: cameraTrack = self.generateCameraMoveTrack() self.finishMovie() self.movieTrack = Sequence(Parallel(cameraTrack, Sequence()), kartTrack, jumpTrack, Func(self.makeGui), Func(self.showGui), Func(self.countdown), Func(self.request, 'Waiting'), Func(self.d_movieFinished), name=name, autoFinish=1) else: self.finishMovie() self.movieTrack = Sequence(toonTrack, kartTrack, jumpTrack, name=name, autoFinish=1) self.movieTrack.start() self.exitRequested = True return
class DistributedChineseCheckers(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, 'DistributedChineseCheckers') DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel('phase_6/models/golf/checker_game.bam') self.boardNode.reparentTo(self) self.board = ChineseCheckersBoard() self.playerTags = render.attachNewNode('playerTags') self.playerTagList = [] self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.playersTurnBlinker = Sequence() self.yourTurnBlinker = Sequence() self.moveList = [] self.mySquares = [] self.playerSeats = None self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(ToontownGlobals.WallBitmask) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.playerColors = [Vec4(0, 0.9, 0, 1), Vec4(0.9, 0.9, 0, 1), Vec4(0.45, 0, 0.45, 1), Vec4(0.2, 0.4, 0.8, 1), Vec4(1, 0.45, 1, 1), Vec4(0.8, 0, 0, 1)] self.tintConstant = Vec4(0.25, 0.25, 0.25, 0) self.ghostConstant = Vec4(0, 0, 0, 0.5) self.startingPositions = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 23, 24, 25, 35, 36, 46], [65, 75, 76, 86, 87, 88, 98, 99, 100, 101], [111, 112, 113, 114, 115, 116, 117, 118, 119, 120], [74, 84, 85, 95, 96, 97, 107, 108, 109, 110], [19, 20, 21, 22, 32, 33, 34, 44, 45, 55]] self.nonOpposingPositions = [] self.knockSound = base.loadSfx('phase_5/audio/sfx/GUI_knock_1.ogg') self.clickSound = base.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.ogg') self.moveSound = base.loadSfx('phase_6/audio/sfx/CC_move.ogg') self.accept('stoppedAsleep', self.handleSleep) from direct.fsm import ClassicFSM, State self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin'])], 'waitingToBegin', 'waitingToBegin') x = self.boardNode.find('**/locators') self.locatorList = x.getChildren() tempList = [] for x in xrange(0, 121): self.locatorList[x].setTag('GamePeiceLocator', '%d' % x) tempList.append(self.locatorList[x].attachNewNode(CollisionNode('picker%d' % x))) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, 0.115)) for z in self.locatorList: y = loader.loadModel('phase_6/models/golf/checker_marble.bam') z.setColor(0, 0, 0, 0) y.reparentTo(z) return def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: self.seatPos = self.table.tableState.index(base.localAvatar.doId) self.playerTags.setPos(self.getPos()) def handleSleep(self, task = None): if self.fsm.getCurrentState().getName() == 'waitingToBegin': self.exitButtonPushed() if task != None: task.done return def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.cleanPlayerTags() return def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None self.cleanPlayerTags() del self.playerTags del self.playerTagList self.playerSeats = None self.yourTurnBlinker.finish() return def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState().getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() return def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(-.74, 0, -0.2) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doRandomMove) else: self.clockNode.countdown(timeLeft, self.doNothing) self.clockNode.show() return def gameStart(self, playerNum): if playerNum != 255: self.playerNum = playerNum self.playerColor = self.playerColors[playerNum - 1] self.moveCameraForGame() playerPos = playerNum - 1 import copy self.nonOpposingPositions = copy.deepcopy(self.startingPositions) if playerPos == 0: self.nonOpposingPositions.pop(0) self.opposingPositions = self.nonOpposingPositions.pop(2) elif playerPos == 1: self.nonOpposingPositions.pop(1) self.opposingPositions = self.nonOpposingPositions.pop(3) elif playerPos == 2: self.nonOpposingPositions.pop(2) self.opposingPositions = self.nonOpposingPositions.pop(4) elif playerPos == 3: self.nonOpposingPositions.pop(3) self.opposingPositions = self.nonOpposingPositions.pop(0) elif playerPos == 4: self.nonOpposingPositions.pop(4) self.opposingPositions = self.nonOpposingPositions.pop(1) elif playerPos == 5: self.nonOpposingPositions.pop(5) self.opposingPositions = self.nonOpposingPositions.pop(2) self.fsm.request('playing') def sendTurn(self, playersTurn): self.playersTurnBlinker.finish() if self.fsm.getCurrentState().getName() == 'playing': if self.playerSeats == None: self.sendUpdate('requestSeatPositions', []) else: if playersTurn == self.playerNum: self.isMyTurn = True self.enableTurnScreenText(playersTurn) self.playersTurnBlinker = Sequence() origColor = self.playerColors[playersTurn - 1] self.playersTurnBlinker.append(LerpColorInterval(self.playerTagList[self.playerSeats.index(playersTurn)], 0.4, origColor - self.tintConstant - self.ghostConstant, origColor)) self.playersTurnBlinker.append(LerpColorInterval(self.playerTagList[self.playerSeats.index(playersTurn)], 0.4, origColor, origColor - self.tintConstant - self.ghostConstant)) self.playersTurnBlinker.loop() return def announceSeatPositions(self, playerPos): self.playerSeats = playerPos for x in xrange(6): pos = self.table.seats[x].getPos(render) renderedPeice = loader.loadModel('phase_6/models/golf/checker_marble.bam') renderedPeice.reparentTo(self.playerTags) renderedPeice.setPos(pos) renderedPeice.setScale(1.5) if x == 1: renderedPeice.setZ(renderedPeice.getZ() + 3.3) renderedPeice.setScale(1.3) elif x == 4: renderedPeice.setZ(renderedPeice.getZ() + 3.3) renderedPeice.setScale(1.45) else: renderedPeice.setZ(renderedPeice.getZ() + 3.3) renderedPeice.hide() self.playerTagList = self.playerTags.getChildren() for x in playerPos: if x != 0: self.playerTagList[playerPos.index(x)].setColor(self.playerColors[x - 1]) self.playerTagList[playerPos.index(x)].show() def cleanPlayerTags(self): for x in self.playerTagList: x.removeNode() self.playerTagList = [] self.playerTags.removeNode() def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.finish() rotation = 0 if self.seatPos > 2: if self.playerNum == 1: rotation = 180 elif self.playerNum == 2: rotation = -120 elif self.playerNum == 3: rotation = -60 elif self.playerNum == 4: rotation = 0 elif self.playerNum == 5: rotation = 60 elif self.playerNum == 6: rotation = 120 elif self.playerNum == 1: rotation = 0 elif self.playerNum == 2: rotation = 60 elif self.playerNum == 3: rotation = 120 elif self.playerNum == 4: rotation = 180 elif self.playerNum == 5: rotation = -120 elif self.playerNum == 6: rotation = -60 if rotation == 60 or rotation == -60: int = LerpHprInterval(self.boardNode, 2.5, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) elif rotation == 120 or rotation == -120: int = LerpHprInterval(self.boardNode, 3.5, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) else: int = LerpHprInterval(self.boardNode, 4.2, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) int.start() def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() return def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.cleanPlayerTags() return def enterGameOver(self): pass def exitGameOver(self): pass def exitWaitCountdown(self): self.__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableScreenText(self): defaultPos = (-.8, -0.4) if self.playerNum == 1: message = TTLocalizer.ChineseCheckersColorG color = self.playerColors[0] elif self.playerNum == 2: message = TTLocalizer.ChineseCheckersColorY color = self.playerColors[1] elif self.playerNum == 3: message = TTLocalizer.ChineseCheckersColorP color = self.playerColors[2] elif self.playerNum == 4: message = TTLocalizer.ChineseCheckersColorB color = self.playerColors[3] elif self.playerNum == 5: message = TTLocalizer.ChineseCheckersColorPink color = self.playerColors[4] elif self.playerNum == 6: message = TTLocalizer.ChineseCheckersColorR color = self.playerColors[5] else: message = TTLocalizer.ChineseCheckersColorO color = Vec4(0.0, 0.0, 0.0, 1.0) defaultPos = (-.8, -0.4) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.1), scale=0.15, command=lambda self = self: self.startButtonPushed()) return def enableLeaveButton(self): self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): self.yourTurnBlinker.finish() playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.ChineseCheckersIts if self.turnText != None: self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) elif player == 1: message2 = TTLocalizer.ChineseCheckersGreenTurn color = self.playerColors[0] elif player == 2: message2 = TTLocalizer.ChineseCheckersYellowTurn color = self.playerColors[1] elif player == 3: message2 = TTLocalizer.ChineseCheckersPurpleTurn color = self.playerColors[2] elif player == 4: message2 = TTLocalizer.ChineseCheckersBlueTurn color = self.playerColors[3] elif player == 5: message2 = TTLocalizer.ChineseCheckersPinkTurn color = self.playerColors[4] elif player == 6: message2 = TTLocalizer.ChineseCheckersRedTurn color = self.playerColors[5] self.turnText = OnscreenText(text=message1 + message2, pos=(-0.8, -0.5), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) if player == self.playerNum: self.yourTurnBlinker = Sequence() self.yourTurnBlinker.append(LerpScaleInterval(self.turnText, 0.6, 1.045, 1)) self.yourTurnBlinker.append(LerpScaleInterval(self.turnText, 0.6, 1, 1.045)) self.yourTurnBlinker.loop() return def startButtonPushed(self): self.sendUpdate('requestBegin') self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate('requestExit') def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True: mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.getNetTag('GamePeiceLocator') if pickedObj: self.handleClicked(int(pickedObj)) def handleClicked(self, index): self.sound = Sequence(SoundInterval(self.clickSound)) if self.moveList == []: if index not in self.mySquares: return self.moveList.append(index) if index in self.opposingPositions: self.isOpposing = True else: self.isOpposing = False self.blinker = Sequence() self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, self.playerColor - self.tintConstant, self.playerColor)) self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, self.playerColor, self.playerColor - self.tintConstant)) self.blinker.loop() self.sound.start() elif self.board.squareList[index].getState() == self.playerNum: for x in self.moveList: self.locatorList[x].setColor(1, 1, 1, 1) self.locatorList[x].hide() self.blinker.finish() self.blinker = Sequence() self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, self.playerColor - self.tintConstant, self.playerColor)) self.blinker.append(LerpColorInterval(self.locatorList[index], 0.7, self.playerColor, self.playerColor - self.tintConstant)) self.blinker.loop() self.sound.start() self.locatorList[self.moveList[0]].setColor(self.playerColor) self.locatorList[self.moveList[0]].show() self.moveList = [] self.moveList.append(index) if index in self.opposingPositions: self.isOpposing = True else: self.isOpposing = False elif self.board.squareList[index].getState() != 0: return else: if len(self.moveList) == 1 and self.board.squareList[index].getState() == 0: if index in self.board.squareList[self.moveList[0]].getAdjacent(): for x in self.nonOpposingPositions: if index in x: return self.moveList.append(index) self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.sound.start() if len(self.moveList) >= 1: if index == self.moveList[len(self.moveList) - 1]: for x in self.nonOpposingPositions: if index in x: return if self.existsLegalJumpsFrom(index) == True: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.sound.start() elif self.checkLegalMove(self.board.getSquare(self.moveList[len(self.moveList) - 1]), self.board.getSquare(index)) == True: if index not in self.board.squareList[self.moveList[len(self.moveList) - 1]].getAdjacent(): for x in self.nonOpposingPositions: if self.existsLegalJumpsFrom(index) == False: if index in x: return self.moveList.append(index) self.locatorList[index].setColor(self.playerColor - self.tintConstant - self.ghostConstant) self.locatorList[index].show() self.sound.start() if self.existsLegalJumpsFrom(index) == False: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False def existsLegalJumpsFrom(self, index): for x in self.board.squareList[index].getAdjacent(): if x == None: pass elif x in self.moveList: pass elif self.board.getState(x) == 0: pass elif self.board.squareList[x].getAdjacent()[self.board.squareList[index].getAdjacent().index(x)] == None: pass elif self.board.getState(self.board.squareList[x].getAdjacent()[self.board.squareList[index].getAdjacent().index(x)]) == 0 and self.board.squareList[x].getAdjacent()[self.board.squareList[index].getAdjacent().index(x)] not in self.moveList: return True return False def checkLegalMove(self, firstSquare, secondSquare): if secondSquare.getNum() in firstSquare.getAdjacent(): return True else: for x in firstSquare.getAdjacent(): if x == None: pass elif self.board.squareList[x].getState() == 0: pass elif self.board.squareList[x].getAdjacent()[firstSquare.getAdjacent().index(x)] == secondSquare.getNum(): return True return False return def d_requestMove(self, moveList): self.sendUpdate('requestMove', [moveList]) def setGameState(self, tableState, moveList): if moveList != []: self.animatePeice(tableState, moveList) else: self.updateGameState(tableState) def updateGameState(self, squares): self.board.setStates(squares) self.mySquares = [] messenger.send('wakeup') for x in xrange(121): self.locatorList[x].clearColor() owner = self.board.squareList[x].getState() if owner == self.playerNum: self.mySquares.append(x) if owner == 0: self.locatorList[x].hide() else: self.locatorList[x].show() if owner == 1: self.locatorList[x].setColor(self.playerColors[0]) elif owner == 2: self.locatorList[x].setColor(self.playerColors[1]) elif owner == 3: self.locatorList[x].setColor(self.playerColors[2]) elif owner == 4: self.locatorList[x].setColor(self.playerColors[3]) elif owner == 5: self.locatorList[x].setColor(self.playerColors[4]) elif owner == 6: self.locatorList[x].setColor(self.playerColors[5]) self.mySquares.sort() self.checkForWin() def animatePeice(self, tableState, moveList): messenger.send('wakeup') gamePeiceForAnimation = loader.loadModel('phase_6/models/golf/checker_marble.bam') gamePeiceForAnimation.setColor(self.locatorList[moveList[0]].getColor()) gamePeiceForAnimation.reparentTo(self.boardNode) gamePeiceForAnimation.setPos(self.locatorList[moveList[0]].getPos()) self.locatorList[moveList[0]].hide() checkersPeiceTrack = Sequence() length = len(moveList) for x in xrange(length - 1): checkersPeiceTrack.append(Parallel(SoundInterval(self.moveSound), ProjectileInterval(gamePeiceForAnimation, endPos=self.locatorList[moveList[x + 1]].getPos(), duration=0.5))) checkersPeiceTrack.append(Func(gamePeiceForAnimation.removeNode)) checkersPeiceTrack.append(Func(self.updateGameState, tableState)) checkersPeiceTrack.start() def checkForWin(self): if self.playerNum == 1: if self.mySquares == self.startingPositions[3]: self.sendUpdate('requestWin', []) elif self.playerNum == 2: if self.mySquares == self.startingPositions[4]: self.sendUpdate('requestWin', []) elif self.playerNum == 3: if self.mySquares == self.startingPositions[5]: self.sendUpdate('requestWin', []) elif self.playerNum == 4: if self.mySquares == self.startingPositions[0]: self.sendUpdate('requestWin', []) elif self.playerNum == 5: if self.mySquares == self.startingPositions[1]: self.sendUpdate('requestWin', []) elif self.playerNum == 6: if self.mySquares == self.startingPositions[2]: self.sendUpdate('requestWin', []) def announceWin(self, avId): self.fsm.request('gameOver') def doRandomMove(self): if len(self.moveList) >= 2: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.playSound = Sequence(SoundInterval(self.knockSound)) self.playSound.start() else: import random move = [] foundLegal = False self.blinker.pause() self.numRandomMoves += 1 while not foundLegal: x = random.randint(0, 9) for y in self.board.getAdjacent(self.mySquares[x]): if y != None and self.board.getState(y) == 0: for zz in self.nonOpposingPositions: if y not in zz: move.append(self.mySquares[x]) move.append(y) foundLegal = True break break if move == []: pass playSound = Sequence(SoundInterval(self.knockSound)) playSound.start() self.d_requestMove(move) self.moveList = [] self.isMyTurn = False if self.numRandomMoves >= 5: self.exitButtonPushed() return def doNothing(self): pass
class DistributedChineseCheckers(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, 'DistributedChineseCheckers') DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel('phase_6/models/golf/checker_game.bam') self.boardNode.reparentTo(self) self.board = ChineseCheckersBoard() self.playerTags = render.attachNewNode('playerTags') self.playerTagList = [] self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.playersTurnBlinker = Sequence() self.yourTurnBlinker = Sequence() self.moveList = [] self.mySquares = [] self.playerSeats = None self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(ToontownGlobals.WallBitmask) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() self.clockNode.setPos(1.1599999999999999, 0, -0.82999999999999996) self.clockNode.setScale(0.29999999999999999) self.clockNode.hide() self.playerColors = [ Vec4(0, 0.90000000000000002, 0, 1), Vec4(0.90000000000000002, 0.90000000000000002, 0, 1), Vec4(0.45000000000000001, 0, 0.45000000000000001, 1), Vec4(0.20000000000000001, 0.40000000000000002, 0.80000000000000004, 1), Vec4(1, 0.45000000000000001, 1, 1), Vec4(0.80000000000000004, 0, 0, 1)] self.tintConstant = Vec4(0.25, 0.25, 0.25, 0) self.ghostConstant = Vec4(0, 0, 0, 0.5) self.startingPositions = [ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [ 10, 11, 12, 13, 23, 24, 25, 35, 36, 46], [ 65, 75, 76, 86, 87, 88, 98, 99, 100, 101], [ 111, 112, 113, 114, 115, 116, 117, 118, 119, 120], [ 74, 84, 85, 95, 96, 97, 107, 108, 109, 110], [ 19, 20, 21, 22, 32, 33, 34, 44, 45, 55]] self.nonOpposingPositions = [] self.knockSound = base.loadSfx('phase_5/audio/sfx/GUI_knock_1.mp3') self.clickSound = base.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.mp3') self.moveSound = base.loadSfx('phase_6/audio/sfx/CC_move.mp3') self.accept('stoppedAsleep', self.handleSleep) ClassicFSM = ClassicFSM State = State import direct.fsm self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [ State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, [ 'playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, [ 'gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, [ 'waitingToBegin'])], 'waitingToBegin', 'waitingToBegin') x = self.boardNode.find('**/locators') self.locatorList = x.getChildren() tempList = [] for x in range(0, 121): self.locatorList[x].setTag('GamePeiceLocator', '%d' % x) tempList.append(self.locatorList[x].attachNewNode(CollisionNode('picker%d' % x))) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, 0.115)) for z in self.locatorList: y = loader.loadModel('phase_6/models/golf/checker_marble.bam') z.setColor(0, 0, 0, 0) y.reparentTo(z) def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: self.seatPos = self.table.tableState.index(base.localAvatar.doId) self.playerTags.setPos(self.getPos()) def handleSleep(self, task = None): if self.fsm.getCurrentState().getName() == 'waitingToBegin': self.exitButtonPushed() if task != None: pass 1 def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.cleanPlayerTags() def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None self.cleanPlayerTags() del self.playerTags del self.playerTagList self.playerSeats = None self.yourTurnBlinker.finish() def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'waitingToBegin' and not (self.table.fsm.getCurrentState().getName() == 'observing'): self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.1599999999999999, 0, -0.82999999999999996) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(-0.73999999999999999, 0, -0.20000000000000001) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doRandomMove) else: self.clockNode.countdown(timeLeft, self.doNothing) self.clockNode.show() def gameStart(self, playerNum): if playerNum != 255: self.playerNum = playerNum self.playerColor = self.playerColors[playerNum - 1] self.moveCameraForGame() playerPos = playerNum - 1 import copy as copy self.nonOpposingPositions = copy.deepcopy(self.startingPositions) if playerPos == 0: self.nonOpposingPositions.pop(0) self.opposingPositions = self.nonOpposingPositions.pop(2) elif playerPos == 1: self.nonOpposingPositions.pop(1) self.opposingPositions = self.nonOpposingPositions.pop(3) elif playerPos == 2: self.nonOpposingPositions.pop(2) self.opposingPositions = self.nonOpposingPositions.pop(4) elif playerPos == 3: self.nonOpposingPositions.pop(3) self.opposingPositions = self.nonOpposingPositions.pop(0) elif playerPos == 4: self.nonOpposingPositions.pop(4) self.opposingPositions = self.nonOpposingPositions.pop(1) elif playerPos == 5: self.nonOpposingPositions.pop(5) self.opposingPositions = self.nonOpposingPositions.pop(2) self.fsm.request('playing') def sendTurn(self, playersTurn): self.playersTurnBlinker.finish() if self.fsm.getCurrentState().getName() == 'playing': if self.playerSeats == None: self.sendUpdate('requestSeatPositions', []) elif playersTurn == self.playerNum: self.isMyTurn = True self.enableTurnScreenText(playersTurn) self.playersTurnBlinker = Sequence() origColor = self.playerColors[playersTurn - 1] self.playersTurnBlinker.append(LerpColorInterval(self.playerTagList[self.playerSeats.index(playersTurn)], 0.40000000000000002, origColor - self.tintConstant - self.ghostConstant, origColor)) self.playersTurnBlinker.append(LerpColorInterval(self.playerTagList[self.playerSeats.index(playersTurn)], 0.40000000000000002, origColor, origColor - self.tintConstant - self.ghostConstant)) self.playersTurnBlinker.loop() def announceSeatPositions(self, playerPos): self.playerSeats = playerPos for x in range(6): pos = self.table.seats[x].getPos(render) renderedPeice = loader.loadModel('phase_6/models/golf/checker_marble.bam') renderedPeice.reparentTo(self.playerTags) renderedPeice.setPos(pos) renderedPeice.setScale(1.5) if x == 1: renderedPeice.setZ(renderedPeice.getZ() + 3.2999999999999998) renderedPeice.setScale(1.3) elif x == 4: renderedPeice.setZ(renderedPeice.getZ() + 3.2999999999999998) renderedPeice.setScale(1.45) else: renderedPeice.setZ(renderedPeice.getZ() + 3.2999999999999998) renderedPeice.hide() self.playerTagList = self.playerTags.getChildren() for x in playerPos: if x != 0: self.playerTagList[playerPos.index(x)].setColor(self.playerColors[x - 1]) self.playerTagList[playerPos.index(x)].show() continue def cleanPlayerTags(self): for x in self.playerTagList: x.removeNode() self.playerTagList = [] self.playerTags.removeNode() def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.finish() rotation = 0 if self.seatPos > 2: if self.playerNum == 1: rotation = 180 elif self.playerNum == 2: rotation = -120 elif self.playerNum == 3: rotation = -60 elif self.playerNum == 4: rotation = 0 elif self.playerNum == 5: rotation = 60 elif self.playerNum == 6: rotation = 120 elif self.playerNum == 1: rotation = 0 elif self.playerNum == 2: rotation = 60 elif self.playerNum == 3: rotation = 120 elif self.playerNum == 4: rotation = 180 elif self.playerNum == 5: rotation = -120 elif self.playerNum == 6: rotation = -60 if rotation == 60 or rotation == -60: int = LerpHprInterval(self.boardNode, 2.5, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) elif rotation == 120 or rotation == -120: int = LerpHprInterval(self.boardNode, 3.5, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) else: int = LerpHprInterval(self.boardNode, 4.2000000000000002, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) int.start() def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.cleanPlayerTags() def enterGameOver(self): pass def exitGameOver(self): pass def exitWaitCountdown(self): self._DistributedChineseCheckers__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton(relief = None, text = TTLocalizer.ChineseCheckersGetUpButton, text_fg = (1, 1, 0.65000000000000002, 1), text_pos = (0, -0.23000000000000001), text_scale = 0.80000000000000004, image = (self.upButton, self.downButton, self.rolloverButton), image_color = (1, 0, 0, 1), image_scale = (20, 1, 11), pos = (0.92000000000000004, 0, 0.40000000000000002), scale = 0.14999999999999999, command = lambda self = self: self.exitButtonPushed()) def enableScreenText(self): defaultPos = (-0.80000000000000004, -0.40000000000000002) if self.playerNum == 1: message = TTLocalizer.ChineseCheckersColorG color = self.playerColors[0] elif self.playerNum == 2: message = TTLocalizer.ChineseCheckersColorY color = self.playerColors[1] elif self.playerNum == 3: message = TTLocalizer.ChineseCheckersColorP color = self.playerColors[2] elif self.playerNum == 4: message = TTLocalizer.ChineseCheckersColorB color = self.playerColors[3] elif self.playerNum == 5: message = TTLocalizer.ChineseCheckersColorPink color = self.playerColors[4] elif self.playerNum == 6: message = TTLocalizer.ChineseCheckersColorR color = self.playerColors[5] else: message = TTLocalizer.ChineseCheckersColorO color = Vec4(0.0, 0.0, 0.0, 1.0) defaultPos = (-0.80000000000000004, -0.40000000000000002) self.screenText = OnscreenText(text = message, pos = defaultPos, scale = 0.10000000000000001, fg = color, align = TextNode.ACenter, mayChange = 1) def enableStartButton(self): self.startButton = DirectButton(relief = None, text = TTLocalizer.ChineseCheckersStartButton, text_fg = (1, 1, 0.65000000000000002, 1), text_pos = (0, -0.23000000000000001), text_scale = 0.59999999999999998, image = (self.upButton, self.downButton, self.rolloverButton), image_color = (1, 0, 0, 1), image_scale = (20, 1, 11), pos = (0.92000000000000004, 0, 0.10000000000000001), scale = 0.14999999999999999, command = lambda self = self: self.startButtonPushed()) def enableLeaveButton(self): self.leaveButton = DirectButton(relief = None, text = TTLocalizer.ChineseCheckersQuitButton, text_fg = (1, 1, 0.65000000000000002, 1), text_pos = (0, -0.13), text_scale = 0.5, image = (self.upButton, self.downButton, self.rolloverButton), image_color = (1, 0, 0, 1), image_scale = (20, 1, 11), pos = (0.92000000000000004, 0, 0.40000000000000002), scale = 0.14999999999999999, command = lambda self = self: self.exitButtonPushed()) def enableTurnScreenText(self, player): self.yourTurnBlinker.finish() playerOrder = [ 1, 4, 2, 5, 3, 6] message1 = TTLocalizer.ChineseCheckersIts if self.turnText != None: self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) elif player == 1: message2 = TTLocalizer.ChineseCheckersGreenTurn color = self.playerColors[0] elif player == 2: message2 = TTLocalizer.ChineseCheckersYellowTurn color = self.playerColors[1] elif player == 3: message2 = TTLocalizer.ChineseCheckersPurpleTurn color = self.playerColors[2] elif player == 4: message2 = TTLocalizer.ChineseCheckersBlueTurn color = self.playerColors[3] elif player == 5: message2 = TTLocalizer.ChineseCheckersPinkTurn color = self.playerColors[4] elif player == 6: message2 = TTLocalizer.ChineseCheckersRedTurn color = self.playerColors[5] self.turnText = OnscreenText(text = message1 + message2, pos = (-0.80000000000000004, -0.5), scale = 0.091999999999999998, fg = color, align = TextNode.ACenter, mayChange = 1) if player == self.playerNum: self.yourTurnBlinker = Sequence() self.yourTurnBlinker.append(LerpScaleInterval(self.turnText, 0.59999999999999998, 1.0449999999999999, 1)) self.yourTurnBlinker.append(LerpScaleInterval(self.turnText, 0.59999999999999998, 1, 1.0449999999999999)) self.yourTurnBlinker.loop() def startButtonPushed(self): self.sendUpdate('requestBegin') self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate('requestExit') def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True: mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.getNetTag('GamePeiceLocator') if pickedObj: self.handleClicked(int(pickedObj)) def handleClicked(self, index): self.sound = Sequence(SoundInterval(self.clickSound)) if self.moveList == []: if index not in self.mySquares: return None self.moveList.append(index) if index in self.opposingPositions: self.isOpposing = True else: self.isOpposing = False self.blinker = Sequence() self.blinker.append(LerpColorInterval(self.locatorList[index], 0.69999999999999996, self.playerColor - self.tintConstant, self.playerColor)) self.blinker.append(LerpColorInterval(self.locatorList[index], 0.69999999999999996, self.playerColor, self.playerColor - self.tintConstant)) self.blinker.loop() self.sound.start() elif self.board.squareList[index].getState() == self.playerNum: for x in self.moveList: self.locatorList[x].setColor(1, 1, 1, 1) self.locatorList[x].hide() self.blinker.finish() self.blinker = Sequence() self.blinker.append(LerpColorInterval(self.locatorList[index], 0.69999999999999996, self.playerColor - self.tintConstant, self.playerColor)) self.blinker.append(LerpColorInterval(self.locatorList[index], 0.69999999999999996, self.playerColor, self.playerColor - self.tintConstant)) self.blinker.loop() self.sound.start() self.locatorList[self.moveList[0]].setColor(self.playerColor) self.locatorList[self.moveList[0]].show() self.moveList = [] self.moveList.append(index) if index in self.opposingPositions: self.isOpposing = True else: self.isOpposing = False elif self.board.squareList[index].getState() != 0: return None elif len(self.moveList) == 1 and self.board.squareList[index].getState() == 0: if index in self.board.squareList[self.moveList[0]].getAdjacent(): for x in self.nonOpposingPositions: if index in x: return None continue self.moveList.append(index) self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.sound.start() if len(self.moveList) >= 1: if index == self.moveList[len(self.moveList) - 1]: for x in self.nonOpposingPositions: if index in x: return None continue if self.existsLegalJumpsFrom(index) == True: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.sound.start() elif self.checkLegalMove(self.board.getSquare(self.moveList[len(self.moveList) - 1]), self.board.getSquare(index)) == True: if index not in self.board.squareList[self.moveList[len(self.moveList) - 1]].getAdjacent(): for x in self.nonOpposingPositions: if self.existsLegalJumpsFrom(index) == False: if index in x: return None index in x self.moveList.append(index) self.locatorList[index].setColor(self.playerColor - self.tintConstant - self.ghostConstant) self.locatorList[index].show() self.sound.start() if self.existsLegalJumpsFrom(index) == False: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False def existsLegalJumpsFrom(self, index): for x in self.board.squareList[index].getAdjacent(): if x == None: continue if x in self.moveList: continue if self.board.getState(x) == 0: continue if self.board.squareList[x].getAdjacent()[self.board.squareList[index].getAdjacent().index(x)] == None: continue if self.board.getState(self.board.squareList[x].getAdjacent()[self.board.squareList[index].getAdjacent().index(x)]) == 0 and self.board.squareList[x].getAdjacent()[self.board.squareList[index].getAdjacent().index(x)] not in self.moveList: return True continue return False def checkLegalMove(self, firstSquare, secondSquare): if secondSquare.getNum() in firstSquare.getAdjacent(): return True else: for x in firstSquare.getAdjacent(): if x == None: continue if self.board.squareList[x].getState() == 0: continue if self.board.squareList[x].getAdjacent()[firstSquare.getAdjacent().index(x)] == secondSquare.getNum(): return True continue return False def d_requestMove(self, moveList): self.sendUpdate('requestMove', [ moveList]) def setGameState(self, tableState, moveList): if moveList != []: self.animatePeice(tableState, moveList) else: self.updateGameState(tableState) def updateGameState(self, squares): self.board.setStates(squares) self.mySquares = [] messenger.send('wakeup') for x in range(121): self.locatorList[x].clearColor() owner = self.board.squareList[x].getState() if owner == self.playerNum: self.mySquares.append(x) if owner == 0: self.locatorList[x].hide() else: self.locatorList[x].show() if owner == 1: self.locatorList[x].setColor(self.playerColors[0]) continue if owner == 2: self.locatorList[x].setColor(self.playerColors[1]) continue if owner == 3: self.locatorList[x].setColor(self.playerColors[2]) continue if owner == 4: self.locatorList[x].setColor(self.playerColors[3]) continue if owner == 5: self.locatorList[x].setColor(self.playerColors[4]) continue if owner == 6: self.locatorList[x].setColor(self.playerColors[5]) continue self.mySquares.sort() self.checkForWin() def animatePeice(self, tableState, moveList): messenger.send('wakeup') gamePeiceForAnimation = loader.loadModel('phase_6/models/golf/checker_marble.bam') gamePeiceForAnimation.setColor(self.locatorList[moveList[0]].getColor()) gamePeiceForAnimation.reparentTo(self.boardNode) gamePeiceForAnimation.setPos(self.locatorList[moveList[0]].getPos()) self.locatorList[moveList[0]].hide() checkersPeiceTrack = Sequence() length = len(moveList) for x in range(length - 1): checkersPeiceTrack.append(Parallel(SoundInterval(self.moveSound), ProjectileInterval(gamePeiceForAnimation, endPos = self.locatorList[moveList[x + 1]].getPos(), duration = 0.5))) checkersPeiceTrack.append(Func(gamePeiceForAnimation.removeNode)) checkersPeiceTrack.append(Func(self.updateGameState, tableState)) checkersPeiceTrack.start() def checkForWin(self): if self.playerNum == 1: if self.mySquares == self.startingPositions[3]: self.sendUpdate('requestWin', []) elif self.playerNum == 2: if self.mySquares == self.startingPositions[4]: self.sendUpdate('requestWin', []) elif self.playerNum == 3: if self.mySquares == self.startingPositions[5]: self.sendUpdate('requestWin', []) elif self.playerNum == 4: if self.mySquares == self.startingPositions[0]: self.sendUpdate('requestWin', []) elif self.playerNum == 5: if self.mySquares == self.startingPositions[1]: self.sendUpdate('requestWin', []) elif self.playerNum == 6: if self.mySquares == self.startingPositions[2]: self.sendUpdate('requestWin', []) def announceWin(self, avId): self.fsm.request('gameOver') def doRandomMove(self): if len(self.moveList) >= 2: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.playSound = Sequence(SoundInterval(self.knockSound)) self.playSound.start() else: import random as random move = [] foundLegal = False self.blinker.pause() self.numRandomMoves += 1 while not foundLegal: x = random.randint(0, 9) for y in self.board.getAdjacent(self.mySquares[x]): if y != None and self.board.getState(y) == 0: for zz in self.nonOpposingPositions: if y not in zz: move.append(self.mySquares[x]) move.append(y) foundLegal = True break continue break continue if move == []: pass 1 playSound = Sequence(SoundInterval(self.knockSound)) playSound.start() self.d_requestMove(move) self.moveList = [] self.isMyTurn = False if self.numRandomMoves >= 5: self.exitButtonPushed() def doNothing(self): pass
class DistributedPicnicBasket(DistributedObject.DistributedObject): seatState = Enum('Empty, Full, Eating') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPicnicBasket') def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.localToonOnBoard = 0 self.seed = 0 self.random = None self.picnicCountdownTime = base.config.GetFloat('picnic-countdown-time', ToontownGlobals.PICNIC_COUNTDOWN_TIME) self.picnicBasketTrack = None self.fsm = ClassicFSM.ClassicFSM('DistributedTrolley', [ State.State('off', self.enterOff, self.exitOff, [ 'waitEmpty', 'waitCountdown']), State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, [ 'waitCountdown']), State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, [ 'waitEmpty'])], 'off', 'off') self.fsm.enterInitialState() self._DistributedPicnicBasket__toonTracks = { } def generate(self): DistributedObject.DistributedObject.generate(self) self.loader = self.cr.playGame.hood.loader self.foodLoader = [ 'phase_6/models/golf/picnic_sandwich.bam', 'phase_6/models/golf/picnic_apple.bam', 'phase_6/models/golf/picnic_cupcake.bam', 'phase_6/models/golf/picnic_chocolate_cake.bam'] self.fullSeat = [] self.food = [] for i in range(4): self.food.append(None) self.fullSeat.append(self.seatState.Empty) self.picnicItem = 0 def announceGenerate(self): self.picnicTable = self.loader.geom.find('**/*picnic_table_' + str(self.tableNumber)) self.picnicTableSphereNodes = [] self.numSeats = 4 self.seats = [] self.jumpOffsets = [] self.basket = None for i in range(self.numSeats): self.seats.append(self.picnicTable.find('**/*seat%d' % (i + 1))) self.jumpOffsets.append(self.picnicTable.find('**/*jumpOut%d' % (i + 1))) self.tablecloth = self.picnicTable.find('**/basket_locator') DistributedObject.DistributedObject.announceGenerate(self) for i in range(self.numSeats): self.picnicTableSphereNodes.append(self.seats[i].attachNewNode(CollisionNode('picnicTable_sphere_%d_%d' % (self.getDoId(), i)))) self.picnicTableSphereNodes[i].node().addSolid(CollisionSphere(0, 0, 0, 2)) self.tableclothSphereNode = self.tablecloth.attachNewNode(CollisionNode('tablecloth_sphere')) self.tableclothSphereNode.node().addSolid(CollisionSphere(0, 0, -1, 4)) angle = self.startingHpr[0] angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 30.0 self.endPos = self.startingPos + unitVec dist = Vec3(self.endPos - self.enteringPos).length() wheelAngle = (dist / 0.5 * 1.3999999999999999 * math.pi) * 360 self.seatNumber = 0 self.clockNode = ToontownTimer() self.clockNode.setPos(1.1599999999999999, 0, -0.82999999999999996) self.clockNode.setScale(0.29999999999999999) self.clockNode.hide() def disable(self): DistributedObject.DistributedObject.disable(self) self.fsm.request('off') self.clearToonTracks() for i in range(self.numSeats): del self.picnicTableSphereNodes[0] del self.picnicTableSphereNodes self.notify.debug('Deleted self loader ' + str(self.getDoId())) self.picnicTable.removeNode() self.picnicBasketTrack = None def delete(self): self.notify.debug('Golf kart getting deleted: %s' % self.getDoId()) DistributedObject.DistributedObject.delete(self) del self.fsm def setState(self, state, seed, timestamp): self.seed = seed if not self.random: self.random = RandomNumGen.RandomNumGen(seed) self.fsm.request(state, [ globalClockDelta.localElapsedTime(timestamp)]) def handleEnterPicnicTableSphere(self, i, collEntry): self.seatNumber = i self.notify.debug('Entering Picnic Table Sphere.... %s' % self.getDoId()) self.loader.place.detectedPicnicTableSphereCollision(self) def handleEnterPicnicTable(self, i): toon = base.localAvatar self.sendUpdate('requestBoard', [ i]) def fillSlot0(self, avId): self.fillSlot(0, avId) def fillSlot1(self, avId): self.fillSlot(1, avId) def fillSlot2(self, avId): self.fillSlot(2, avId) def fillSlot3(self, avId): self.fillSlot(3, avId) def fillSlot(self, index, avId): self.notify.debug('fill Slot: %d for %d' % (index, avId)) if avId == 0: pass 1 self.fullSeat[index] = self.seatState.Full if avId == base.localAvatar.getDoId(): self.clockNode.show() if index == 0 or index == 3: side = -1 else: side = 1 if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.fsm.request('boarding', [ self.tablecloth, side]) else: self.notify.warning('fillSlot no trolley in place') self.localToonOnBoard = 1 if avId == base.localAvatar.getDoId(): if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.fsm.request('boarded') self.loader.place.trolley.exitButton.hide() if self.cr.doId2do.has_key(avId): toon = self.cr.doId2do[avId] toon.stopSmooth() toon.wrtReparentTo(self.tablecloth) sitStartDuration = toon.getDuration('sit-start') jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence(jumpTrack, Func(toon.setAnimState, 'Sit', 1.0)) self.notify.debug('### fillSlot: fullSeat = %s' % self.fullSeat) if self.fullSeat.count(0) == 3: self.notify.debug('### fillSlot: adding basketAppear') if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence(Wait(waitDuration), self.generateBasketAppearTrack()) self.picnicBasketTrack.start() track.append(self.generateFoodAppearTrack(index)) track.append(Sequence(Func(self.clearToonTrack, avId), name = toon.uniqueName('fillTrolley'), autoPause = 1)) if avId == base.localAvatar.getDoId(): if hasattr(self.loader.place, 'trolley'): track.append(Func(self.loader.place.trolley.exitButton.show)) track.delayDelete = DelayDelete.DelayDelete(toon, 'PicnicBasket.fillSlot') self.storeToonTrack(avId, track) track.start() def emptySlot0(self, avId, timestamp): self.emptySlot(0, avId, timestamp) def emptySlot1(self, avId, timestamp): self.emptySlot(1, avId, timestamp) def emptySlot2(self, avId, timestamp): self.emptySlot(2, avId, timestamp) def emptySlot3(self, avId, timestamp): self.emptySlot(3, avId, timestamp) def notifyToonOffTrolley(self, toon): toon.setAnimState('neutral', 1.0) if hasattr(base, 'localAvatar') and toon == base.localAvatar: if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.handleOffTrolley() self.localToonOnBoard = 0 else: toon.startSmooth() def emptySlot(self, index, avId, timestamp): def emptySeat(index): self.notify.debug('### seat %s now empty' % index) self.fullSeat[index] = self.seatState.Empty if avId == 0: pass 1 if avId == 1: self.fullSeat[index] = self.seatState.Empty track = Sequence(self.generateFoodDisappearTrack(index)) self.notify.debug('### empty slot - unexpetected: fullSeat = %s' % self.fullSeat) if self.fullSeat.count(0) == 4: self.notify.debug('### empty slot - unexpected: losing basket') if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence(Wait(waitDuration), self.generateBasketDisappearTrack()) self.picnicBasketTrack.start() track.start() else: self.fullSeat[index] = self.seatState.Empty if self.cr.doId2do.has_key(avId): if avId == base.localAvatar.getDoId(): if self.clockNode: self.clockNode.hide() toon = self.cr.doId2do[avId] toon.stopSmooth() sitStartDuration = toon.getDuration('sit-start') jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) track = Sequence(jumpOutTrack) track.append(self.generateFoodDisappearTrack(index)) self.notify.debug('### empty slot: fullSeat = %s' % self.fullSeat) if self.fullSeat.count(0) == 4: self.notify.debug('### empty slot: losing basket') if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence(Wait(waitDuration), self.generateBasketDisappearTrack()) self.picnicBasketTrack.start() track.append(Sequence(Func(self.notifyToonOffTrolley, toon), Func(self.clearToonTrack, avId), Func(self.doneExit, avId), Func(emptySeat, index), name = toon.uniqueName('emptyTrolley'), autoPause = 1)) track.delayDelete = DelayDelete.DelayDelete(toon, 'PicnicBasket.emptySlot') self.storeToonTrack(avId, track) track.start() def rejectBoard(self, avId): self.loader.place.trolley.handleRejectBoard() def _DistributedPicnicBasket__enableCollisions(self): for i in range(self.numSeats): self.accept('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTableSphere, [ i]) self.accept('enterPicnicTableOK_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTable, [ i]) self.picnicTableSphereNodes[i].setCollideMask(ToontownGlobals.WallBitmask) def _DistributedPicnicBasket__disableCollisions(self): for i in range(self.numSeats): self.ignore('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i)) self.ignore('enterPicnicTableOK_%d_%d' % (self.getDoId(), i)) for i in range(self.numSeats): self.picnicTableSphereNodes[i].setCollideMask(BitMask32(0)) def enterOff(self): pass def exitOff(self): pass def enterWaitEmpty(self, ts): self._DistributedPicnicBasket__enableCollisions() def exitWaitEmpty(self): self._DistributedPicnicBasket__disableCollisions() def enterWaitCountdown(self, ts): self._DistributedPicnicBasket__enableCollisions() self.accept('trolleyExitButton', self.handleExitButton) self.clockNode.countdown(self.picnicCountdownTime, self.handleExitButton) def handleExitButton(self): self.sendUpdate('requestExit') self.clockNode.hide() def exitWaitCountdown(self): self._DistributedPicnicBasket__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def getStareAtNodeAndOffset(self): return (self.tablecloth, Point3(0, 0, 4)) def storeToonTrack(self, avId, track): self.clearToonTrack(avId) self._DistributedPicnicBasket__toonTracks[avId] = track def clearToonTrack(self, avId): oldTrack = self._DistributedPicnicBasket__toonTracks.get(avId) if oldTrack: oldTrack.pause() DelayDelete.cleanupDelayDeletes(oldTrack) del self._DistributedPicnicBasket__toonTracks[avId] def clearToonTracks(self): keyList = [] for key in self._DistributedPicnicBasket__toonTracks: keyList.append(key) for key in keyList: if self._DistributedPicnicBasket__toonTracks.has_key(key): self.clearToonTrack(key) continue def doneExit(self, avId): if avId == base.localAvatar.getDoId(): self.sendUpdate('doneExit') def setPosHpr(self, x, y, z, h, p, r): self.startingPos = Vec3(x, y, z) self.enteringPos = Vec3(x, y, z - 10) self.startingHpr = Vec3(h, 0, 0) def setTableNumber(self, tn): self.tableNumber = tn def generateToonJumpTrack(self, av, seatIndex): av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack(av, seatIndex): def getJumpDest(av = av, node = self.tablecloth): dest = Vec3(self.tablecloth.getPos(av.getParent())) seatNode = self.picnicTable.find('**/seat' + str(seatIndex + 1)) dest += seatNode.getPos(self.tablecloth) dna = av.getStyle() dest -= hipOffset if seatIndex == 2 or seatIndex == 3: dest.setY(dest.getY() + 2 * hipOffset.getY()) dest.setZ(dest.getZ() + 0.20000000000000001) return dest def getJumpHpr(av = av, node = self.tablecloth): hpr = self.seats[seatIndex].getHpr(av.getParent()) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel(ActorInterval(av, 'jump'), Sequence(Wait(0.42999999999999999), Parallel(LerpHprInterval(av, hpr = getJumpHpr, duration = 0.90000000000000002), ProjectileInterval(av, endPos = getJumpDest, duration = 0.90000000000000002)))) return toonJumpTrack def getToonSitTrack(av): toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit')) return toonSitTrack toonJumpTrack = getToonJumpTrack(av, seatIndex) toonSitTrack = getToonSitTrack(av) jumpTrack = Sequence(Parallel(toonJumpTrack, Sequence(Wait(1), toonSitTrack)), Func(av.wrtReparentTo, self.tablecloth)) return jumpTrack def generateToonReverseJumpTrack(self, av, seatIndex): self.notify.debug('av.getH() = %s' % av.getH()) def getToonJumpTrack(av, destNode): def getJumpDest(av = av, node = destNode): dest = node.getPos(self.tablecloth) dest += self.jumpOffsets[seatIndex].getPos(self.tablecloth) return dest def getJumpHpr(av = av, node = destNode): hpr = node.getHpr(av.getParent()) hpr.setX(hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel(ActorInterval(av, 'jump'), Sequence(Wait(0.10000000000000001), Parallel(ProjectileInterval(av, endPos = getJumpDest, duration = 0.90000000000000002)))) return toonJumpTrack toonJumpTrack = getToonJumpTrack(av, self.tablecloth) jumpTrack = Sequence(toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render)) return jumpTrack def generateBasketAppearTrack(self): if self.basket == None: self.basket = loader.loadModel('phase_6/models/golf/picnic_basket.bam') self.basket.setScale(0.10000000000000001) basketTrack = Sequence(Func(self.basket.show), SoundInterval(globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node = self.basket), Func(self.basket.reparentTo, self.tablecloth), Func(self.basket.setPos, 0, 0, 0.20000000000000001), Func(self.basket.setHpr, 45, 0, 0), Func(self.basket.wrtReparentTo, render), Func(self.basket.setShear, 0, 0, 0), Sequence(LerpScaleInterval(self.basket, scale = Point3(1.1000000000000001, 1.1000000000000001, 0.10000000000000001), duration = 0.20000000000000001), LerpScaleInterval(self.basket, scale = Point3(1.6000000000000001, 1.6000000000000001, 0.20000000000000001), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(1.0, 1.0, 0.40000000000000002), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(1.5, 1.5, 2.5), duration = 0.20000000000000001), LerpScaleInterval(self.basket, scale = Point3(2.5, 2.5, 1.5), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(2.0, 2.0, 2.0), duration = 0.10000000000000001), Func(self.basket.wrtReparentTo, self.tablecloth), Func(self.basket.setPos, 0, 0, 0))) return basketTrack def generateBasketDisappearTrack(self): if not self.basket: return Sequence() pos = self.basket.getPos() pos.addZ(-1) basketTrack = Sequence(LerpScaleInterval(self.basket, scale = Point3(2.0, 2.0, 1.8), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(1.0, 1.0, 2.5), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(2.0, 2.0, 0.5), duration = 0.20000000000000001), LerpScaleInterval(self.basket, scale = Point3(0.5, 0.5, 1.0), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(1.1000000000000001, 1.1000000000000001, 0.10000000000000001), duration = 0.10000000000000001), LerpScaleInterval(self.basket, scale = Point3(0.10000000000000001, 0.10000000000000001, 0.10000000000000001), duration = 0.20000000000000001), SoundInterval(globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node = self.basket), Wait(0.20000000000000001), LerpPosInterval(self.basket, pos = pos, duration = 0.20000000000000001), Func(self.basket.hide)) return basketTrack def generateFoodAppearTrack(self, seat): if self.fullSeat[seat] == self.seatState.Full: self.notify.debug('### food appear: self.fullSeat = %s' % self.fullSeat) if not self.food[seat]: self.food[seat] = loader.loadModel(self.random.choice(self.foodLoader)) self.notify.debug('### food appear: self.food = %s' % self.food) self.food[seat].setScale(0.10000000000000001) self.food[seat].reparentTo(self.tablecloth) self.food[seat].setPos(self.seats[seat].getPos(self.tablecloth)[0] / 2, self.seats[seat].getPos(self.tablecloth)[1] / 2, 0) foodTrack = Sequence(Func(self.food[seat].show), SoundInterval(globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node = self.food[seat]), Func(self.food[seat].reparentTo, self.tablecloth), Func(self.food[seat].setHpr, 45, 0, 0), Func(self.food[seat].wrtReparentTo, render), Func(self.food[seat].setShear, 0, 0, 0), Sequence(LerpScaleInterval(self.food[seat], scale = Point3(1.1000000000000001, 1.1000000000000001, 0.10000000000000001), duration = 0.20000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(1.6000000000000001, 1.6000000000000001, 0.20000000000000001), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(1.0, 1.0, 0.40000000000000002), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(1.5, 1.5, 2.5), duration = 0.20000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(2.5, 2.5, 1.5), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(2.0, 2.0, 2.0), duration = 0.10000000000000001), Func(self.food[seat].wrtReparentTo, self.tablecloth))) return foodTrack else: return Sequence() def generateFoodDisappearTrack(self, seat): if not self.food[seat]: return Sequence() pos = self.food[seat].getPos() pos.addZ(-1.0) foodTrack = Sequence(LerpScaleInterval(self.food[seat], scale = Point3(2.0, 2.0, 1.8), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(1.0, 1.0, 2.5), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(2.0, 2.0, 0.5), duration = 0.20000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(0.5, 0.5, 1.0), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(1.1000000000000001, 1.1000000000000001, 0.10000000000000001), duration = 0.10000000000000001), LerpScaleInterval(self.food[seat], scale = Point3(0.10000000000000001, 0.10000000000000001, 0.10000000000000001), duration = 0.20000000000000001), SoundInterval(globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node = self.food[seat]), Wait(0.20000000000000001), LerpPosInterval(self.food[seat], pos = pos, duration = 0.20000000000000001), Func(self.food[seat].hide)) return foodTrack def destroy(self, node): node.removeNode() node = None self.basket.removeNode() self.basket = None for food in self.food: food.removeNode() self.food = None self.clockNode.removeNode() del self.clockNode self.clockNode = None def setPicnicDone(self): if self.localToonOnBoard: if hasattr(self.loader.place, 'trolley'): self.loader.place.trolley.fsm.request('final') self.loader.place.trolley.fsm.request('start') self.localToonOnBoard = 0 messenger.send('picnicDone')
class DistributedFindFour(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, 'DistributedFindFour') DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel('phase_6/models/golf/findfour_game.bam') self.boardNode.reparentTo(self) self.board = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]] self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.playersTurnBlinker = Sequence() self.yourTurnBlinker = Sequence() self.winningSequence = Sequence() self.moveSequence = Sequence() self.moveList = [] self.mySquares = [] self.playerSeats = None self.moveCol = None self.move = None self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(BitMask32(4096)) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.tintConstant = Vec4(0.25, 0.25, 0.25, 0) self.ghostConstant = Vec4(0, 0, 0, 0.5) self.knockSound = base.loadSfx('phase_5/audio/sfx/GUI_knock_1.ogg') self.clickSound = base.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.ogg') self.moveSound = base.loadSfx('phase_6/audio/sfx/CC_move.ogg') self.accept('stoppedAsleep', self.handleSleep) from direct.fsm import ClassicFSM, State self.fsm = ClassicFSM.ClassicFSM('ChineseCheckers', [State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin'])], 'waitingToBegin', 'waitingToBegin') startLoc = self.boardNode.find('**/locators') self.locatorList = startLoc.getChildren() self.startingPositions = self.locatorList.pop(0) self.startingPositions = self.startingPositions.getChildren() instancePiece = self.boardNode.find('**/pieces') tempList = [] for x in xrange(7): self.startingPositions[x].setTag('StartLocator', '%d' % x) collNode = CollisionNode('startpicker%d' % x) collNode.setIntoCollideMask(BitMask32(4096)) tempList.append(self.startingPositions[x].attachNewNode(collNode)) tempList[x].node().addSolid(CollisionTube(0, 0, 0.23, 0, 0, -.23, 0.2)) for z in self.startingPositions: y = instancePiece.copyTo(z) for val in y.getChildren(): val.hide() tempList = [] for x in xrange(42): self.locatorList[x].setTag('GamePeiceLocator', '%d' % x) collNode = CollisionNode('startpicker%d' % x) collNode.setIntoCollideMask(BitMask32(4096)) tempList.append(self.locatorList[x].attachNewNode(collNode)) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, 0.2)) for z in self.locatorList: y = instancePiece.copyTo(z) for val in y.getChildren(): val.hide() dummyHide = instancePiece.getParent().attachNewNode('DummyHider') instancePiece.reparentTo(dummyHide) dummyHide.hide() return def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: self.seatPos = self.table.tableState.index(base.localAvatar.doId) if self.seatPos <= 2: for x in self.startingPositions: x.setH(0) for x in self.locatorList: x.setH(0) else: for x in self.startingPositions: x.setH(180) for x in self.locatorList: x.setH(180) self.moveCameraForGame() else: self.seatPos = self.table.seatBumpForObserve if self.seatPos > 2: for x in self.startingPositions: x.setH(180) for x in self.locatorList: x.setH(180) self.moveCameraForGame() def handleSleep(self, task = None): if self.fsm.getCurrentState().getName() == 'waitingToBegin': self.exitButtonPushed() if task != None: task.done return def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None taskMgr.remove('playerTurnTask') return def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None self.winningSequence.finish() taskMgr.remove('playerTurnTask') return def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState().getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() return def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState().getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(0.64, 0, -0.27) self.clockNode.countdown(timeLeft, self.doRandomMove) self.clockNode.show() return def gameStart(self, playerNum): if playerNum != 255: self.playerNum = playerNum if self.playerNum == 1: self.playerColorString = 'Red' else: self.playerColorString = 'Yellow' self.moveCameraForGame() self.fsm.request('playing') def sendTurn(self, playersTurn): if self.fsm.getCurrentState().getName() == 'playing': if playersTurn == self.playerNum: self.isMyTurn = True taskMgr.add(self.turnTask, 'playerTurnTask') self.enableTurnScreenText(playersTurn) def illegalMove(self): self.exitButtonPushed() def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.pause() rotation = 0 if self.seatPos <= 2: position = self.table.seats[1].getPos() position = position + Vec3(0, -8, 12.8) int = LerpPosHprInterval(camera, 2, position, Vec3(0, -38, 0), camera.getPos(), camera.getHpr()) else: position = self.table.seats[4].getPos() position = position + Vec3(0, -8, 12.8) if camera.getH() < 0: int = LerpPosHprInterval(camera, 2, position, Vec3(-180, -20, 0), camera.getPos(), camera.getHpr()) else: int = LerpPosHprInterval(camera, 2, position, Vec3(180, -20, 0), camera.getPos(), camera.getHpr()) int.start() def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() return def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() return def enterGameOver(self): pass def exitGameOver(self): pass def exitWaitCountdown(self): self.__disableCollisions() self.ignore('trolleyExitButton') self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.8), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableScreenText(self): defaultPos = (-.7, -0.29) if self.playerNum == 1: message = 'You are Red' color = Vec4(1, 0, 0, 1) elif self.playerNum == 2: message = 'You are Yellow' color = Vec4(1, 1, 0, 1) else: message = TTLocalizer.CheckersObserver color = Vec4(0, 0, 0, 1) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.57), scale=0.15, command=lambda self = self: self.startButtonPushed()) return def enableLeaveButton(self): self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.8), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.CheckersIts if self.turnText != None: self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) elif player == 1: message2 = "Red's Turn" color = (1, 0, 0, 1) elif player == 2: message2 = "Yellow's Turn" color = (1, 1, 0, 1) self.turnText = OnscreenText(text=message1 + message2, pos=(-0.7, -0.39), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) return def startButtonPushed(self): self.sendUpdate('requestBegin') self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate('requestExit') def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True and not self.moveSequence.isPlaying(): if self.moveCol != None: self.d_requestMove(self.moveCol) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') return def handleClicked(self, index): pass def turnTask(self, task): if base.mouseWatcherNode.hasMouse() == False: return task.cont if self.isMyTurn == False: return task.cont if self.moveSequence.isPlaying(): return task.cont mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.getNetTag('StartLocator') if pickedObj: colVal = int(pickedObj) if colVal == self.moveCol: return task.cont if self.board[0][colVal] == 0: if self.moveCol != None: for x in self.startingPositions[self.moveCol].getChild(1).getChildren(): x.hide() self.moveCol = colVal if self.playerNum == 1: self.startingPositions[self.moveCol].getChild(1).getChild(2).show() elif self.playerNum == 2: self.startingPositions[self.moveCol].getChild(1).getChild(3).show() return task.cont def d_requestMove(self, moveCol): self.sendUpdate('requestMove', [moveCol]) def setGameState(self, tableState, moveCol, movePos, turn): messenger.send('wakeup') if self.table.fsm.getCurrentState().getName() == 'observing': isBlank = True for x in xrange(7): if self.board[5][x] != 0: isBlank = False break gameBlank = True for x in xrange(7): if tableState[5][x] != 0: gameBlank = False break if isBlank == True and gameBlank == False: for x in xrange(6): for y in xrange(7): self.board[x][y] = tableState[x][y] self.updateGameState() return if moveCol == 0 and movePos == 0 and turn == 0: for x in xrange(6): for y in xrange(7): self.board[x][y] = tableState[x][y] self.updateGameState() else: self.animatePeice(tableState, moveCol, movePos, turn) didIWin = self.checkForWin() if didIWin != None: self.sendUpdate('requestWin', [didIWin]) return def updateGameState(self): for x in xrange(6): for y in xrange(7): for z in self.locatorList[x * 7 + y].getChild(1).getChildren(): z.hide() for x in xrange(6): for y in xrange(7): state = self.board[x][y] if state == 1: self.locatorList[x * 7 + y].getChild(1).getChild(0).show() elif state == 2: self.locatorList[x * 7 + y].getChild(1).getChild(1).show() def checkForWin(self): for x in xrange(6): for y in xrange(7): if self.board[x][y] == self.playerNum: if self.checkHorizontal(x, y, self.playerNum) == True: return [x, y] elif self.checkVertical(x, y, self.playerNum) == True: return [x, y] elif self.checkDiagonal(x, y, self.playerNum) == True: return [x, y] return None def announceWinnerPosition(self, x, y, winDirection, playerNum): self.isMyturn = False if self.turnText: self.turnText.hide() self.clockNode.stop() self.clockNode.hide() if winDirection == 0: blinkList = self.findHorizontal(x, y, playerNum) elif winDirection == 1: blinkList = self.findVertical(x, y, playerNum) elif winDirection == 2: blinkList = self.findDiagonal(x, y, playerNum) if blinkList != []: print blinkList val0 = x * 7 + y x = blinkList[0][0] y = blinkList[0][1] val1 = x * 7 + y x = blinkList[1][0] y = blinkList[1][1] val2 = x * 7 + y x = blinkList[2][0] y = blinkList[2][1] val3 = x * 7 + y self.winningSequence = Sequence() downBlinkerParallel = Parallel(LerpColorInterval(self.locatorList[val0], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val1], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val2], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val3], 0.3, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1))) upBlinkerParallel = Parallel(LerpColorInterval(self.locatorList[val0], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)), LerpColorInterval(self.locatorList[val1], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)), LerpColorInterval(self.locatorList[val2], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)), LerpColorInterval(self.locatorList[val3], 0.3, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5))) self.winningSequence.append(downBlinkerParallel) self.winningSequence.append(upBlinkerParallel) self.winningSequence.loop() def tie(self): self.tieSequence = Sequence(autoFinish=1) self.clockNode.stop() self.clockNode.hide() self.isMyTurn = False self.moveSequence.finish() if self.turnText: self.turnText.hide() for x in xrange(41): self.tieSequence.append(Parallel(LerpColorInterval(self.locatorList[x], 0.15, Vec4(0.5, 0.5, 0.5, 0.5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[x], 0.15, Vec4(1, 1, 1, 1), Vec4(0.5, 0.5, 0.5, 0.5)))) whisper = WhisperPopup('This Find Four game has resulted in a Tie!', OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) whisper.manage(base.marginManager) self.tieSequence.start() def hideChildren(self, nodeList): pass def animatePeice(self, tableState, moveCol, movePos, turn): messenger.send('wakeup') for x in xrange(6): for y in xrange(7): self.board[x][y] = tableState[x][y] pos = self.startingPositions[moveCol].getPos() if turn == 0: peice = self.startingPositions[moveCol].getChild(1).getChildren()[2] peice.show() elif turn == 1: peice = self.startingPositions[moveCol].getChild(1).getChildren()[3] peice.show() self.moveSequence = Sequence() startPos = self.startingPositions[moveCol].getPos() arrayLoc = movePos * 7 + moveCol self.moveSequence.append(LerpPosInterval(self.startingPositions[moveCol], 1.5, self.locatorList[arrayLoc].getPos(self), startPos)) self.moveSequence.append(Func(peice.hide)) self.moveSequence.append(Func(self.startingPositions[moveCol].setPos, startPos)) self.moveSequence.append(Func(self.updateGameState)) self.moveSequence.start() def announceWin(self, avId): self.fsm.request('gameOver') def doRandomMove(self): if self.isMyTurn: if self.moveCol != None: self.d_requestMove(self.moveCol) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') else: hasfound = False while hasfound == False: from random import * x = randint(0, 6) if self.board[0][x] == 0: self.d_requestMove(x) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') hasfound = True return def doNothing(self): pass def checkHorizontal(self, rVal, cVal, playerNum): if cVal == 3: for x in xrange(1, 4): if self.board[rVal][cVal - x] != playerNum: break if self.board[rVal][cVal - x] == playerNum and x == 3: return True for x in xrange(1, 4): if self.board[rVal][cVal + x] != playerNum: break if self.board[rVal][cVal + x] == playerNum and x == 3: return True return False elif cVal == 2: for x in xrange(1, 4): if self.board[rVal][cVal + x] != playerNum: break if self.board[rVal][cVal + x] == playerNum and x == 3: return True return False elif cVal == 4: for x in xrange(1, 4): if self.board[rVal][cVal - x] != playerNum: break if self.board[rVal][cVal - x] == playerNum and x == 3: return True return False else: return False def checkVertical(self, rVal, cVal, playerNum): if rVal == 2: for x in xrange(1, 4): if self.board[rVal + x][cVal] != playerNum: break if self.board[rVal + x][cVal] == playerNum and x == 3: return True return False elif rVal == 3: for x in xrange(1, 4): if self.board[rVal - x][cVal] != playerNum: break if self.board[rVal - x][cVal] == playerNum and x == 3: return True return False else: return False def checkDiagonal(self, rVal, cVal, playerNum): if cVal <= 2: if rVal == 2: for x in xrange(1, 4): if self.board[rVal + x][cVal + x] != playerNum: break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return True return False elif rVal == 3: for x in xrange(1, 4): if self.board[rVal - x][cVal + x] != playerNum: break if self.board[rVal - x][cVal + x] == playerNum and x == 3: return True return False elif cVal >= 4: if rVal == 2: for x in xrange(1, 4): if self.board[rVal + x][cVal - x] != playerNum: break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 3: for x in xrange(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 3 or rVal == 4 or rVal == 5: for x in xrange(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True for x in xrange(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 0 or rVal == 1 or rVal == 2: for x in xrange(1, 4): if self.board[rVal + x][cVal - x] != playerNum: break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return True for x in xrange(1, 4): if self.board[rVal + x][cVal + x] != playerNum: break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return True return False return False def findHorizontal(self, rVal, cVal, playerNum): if cVal == 3: retList = [] for x in xrange(1, 4): retList.append([rVal, cVal - x]) if self.board[rVal][cVal - x] != playerNum: retList = [] break if self.board[rVal][cVal - x] == playerNum and x == 3: return retList for x in xrange(1, 4): retList.append([rVal, cVal + x]) if self.board[rVal][cVal + x] != playerNum: retList = [] break if self.board[rVal][cVal + x] == playerNum and x == 3: return retList return [] elif cVal == 2: retList = [] for x in xrange(1, 4): retList.append([rVal, cVal + x]) if self.board[rVal][cVal + x] != playerNum: retList = [] break if self.board[rVal][cVal + x] == playerNum and x == 3: return retList return [] elif cVal == 4: retList = [] for x in xrange(1, 4): retList.append([rVal, cVal - x]) if self.board[rVal][cVal - x] != playerNum: retList = [] break if self.board[rVal][cVal - x] == playerNum and x == 3: return retList return [] else: return [] def findVertical(self, rVal, cVal, playerNum): if rVal == 2: retList = [] for x in xrange(1, 4): retList.append([rVal + x, cVal]) if self.board[rVal + x][cVal] != playerNum: retList = [] break if self.board[rVal + x][cVal] == playerNum and x == 3: return retList return [] elif rVal == 3: retList = [] for x in xrange(1, 4): retList.append([rVal - x, cVal]) if self.board[rVal - x][cVal] != playerNum: retList = [] break if self.board[rVal - x][cVal] == playerNum and x == 3: return retList return [] else: return [] def findDiagonal(self, rVal, cVal, playerNum): retList = [] if cVal <= 2: if rVal == 2: for x in xrange(1, 4): retList.append([rVal + x, cVal + x]) if self.board[rVal + x][cVal + x] != playerNum: retList = [] break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return retList return [] elif rVal == 3: for x in xrange(1, 4): retList.append([rVal - x, cVal + x]) if self.board[rVal - x][cVal + x] != playerNum: retList = [] break if self.board[rVal - x][cVal + x] == playerNum and x == 3: return retList return [] elif cVal >= 4: if rVal == 2: for x in xrange(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 3: for x in xrange(1, 4): retList.append([rVal - x, cVal - x]) if self.board[rVal - x][cVal - x] != playerNum: retList = [] break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 3 or rVal == 4 or rVal == 5: for x in xrange(1, 4): retList.append([rVal - x, cVal - x]) if self.board[rVal - x][cVal - x] != playerNum: retList = [] break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return retList for x in xrange(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 0 or rVal == 1 or rVal == 2: for x in xrange(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList for x in xrange(1, 4): retList.append([rVal + x, cVal + x]) if self.board[rVal + x][cVal + x] != playerNum: retList = [] break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return retList return [] return []
class DistributedFindFour(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, "DistributedFindFour") DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel( "phase_6/models/golf/findfour_game.bam") self.boardNode.reparentTo(self) #self.boardNode.setScale(.05) self.board = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]] #game variables self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.playersTurnBlinker = Sequence() self.yourTurnBlinker = Sequence() self.winningSequence = Sequence() self.moveSequence = Sequence() self.moveList = [] self.mySquares = [] self.playerSeats = None self.moveCol = None self.move = None ###self.playerTags = [None, None, None, None, None, None #Mouse picking required stuff self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(BitMask32(0x1000)) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel( "phase_3.5/models/gui/inventory_gui") self.upButton = self.buttonModels.find("**//InventoryButtonUp") self.downButton = self.buttonModels.find("**/InventoryButtonDown") self.rolloverButton = self.buttonModels.find( "**/InventoryButtonRollover") self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.tintConstant = Vec4(.25, .25, .25, 0) self.ghostConstant = Vec4(0, 0, 0, .5) self.knockSound = base.loader.loadSfx( "phase_5/audio/sfx/GUI_knock_1.mp3") self.clickSound = base.loader.loadSfx( "phase_3/audio/sfx/GUI_balloon_popup.mp3") self.moveSound = base.loader.loadSfx("phase_6/audio/sfx/CC_move.mp3") self.accept('stoppedAsleep', self.handleSleep) ####################### #Fsm and State Data from direct.fsm import ClassicFSM, State self.fsm = ClassicFSM.ClassicFSM( 'ChineseCheckers', [ State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin']) ], # Initial State 'waitingToBegin', # Final State 'waitingToBegin', ) ######################### #Set up the Board Locators ## startLoc = self.boardNode.find("**/locators") self.locatorList = startLoc.getChildren() self.startingPositions = self.locatorList.pop(0) self.startingPositions = self.startingPositions.getChildren() instancePiece = self.boardNode.find("**/pieces") #tag the locators for "picking" ingame #also add colision spheres for movement tempList = [] #Start Position locators #Up above the board for x in range(7): self.startingPositions[x].setTag("StartLocator", "%d" % x) collNode = CollisionNode("startpicker%d" % x) collNode.setIntoCollideMask(BitMask32(0x1000)) tempList.append(self.startingPositions[x].attachNewNode(collNode)) tempList[x].node().addSolid( CollisionTube(0, 0, .23, 0, 0, -.23, .2)) for z in self.startingPositions: y = instancePiece.copyTo(z) for val in y.getChildren(): val.hide() tempList = [] #the peices themselves inside of the board. for x in range(42): self.locatorList[x].setTag("GamePeiceLocator", "%d" % x) collNode = CollisionNode("startpicker%d" % x) collNode.setIntoCollideMask(BitMask32(0x1000)) tempList.append(self.locatorList[x].attachNewNode(collNode)) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, .2)) for z in self.locatorList: y = instancePiece.copyTo(z) for val in y.getChildren(): val.hide() dummyHide = instancePiece.getParent().attachNewNode("DummyHider") instancePiece.reparentTo(dummyHide) dummyHide.hide() def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: # Fix for strange state #TEMP until i find the cause #got to rotate all the peices so that they are facing the side the player is sitting in, #this is a byproduct of backface culling && polygon optimization self.seatPos = self.table.tableState.index( base.localAvatar.doId) if self.seatPos <= 2: for x in self.startingPositions: x.setH(0) for x in self.locatorList: x.setH(0) else: for x in self.startingPositions: x.setH(180) for x in self.locatorList: x.setH(180) self.moveCameraForGame() else: self.seatPos = self.table.seatBumpForObserve if self.seatPos > 2: for x in self.startingPositions: x.setH(180) for x in self.locatorList: x.setH(180) self.moveCameraForGame() def handleSleep(self, task=None): if self.fsm.getCurrentState().getName() == "waitingToBegin": self.exitButtonPushed() if task != None: task.done ########## ##setTableDoId (required broadcast ram) # #Upon construction, sets local pointer to the table, as well as #sets the pointer on the table to itself. #This is necessary to handle events that occur on the table, not #particularly inside of any one game. ### def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) ######### ##Disable/Delete #Must be sure to remove/delete any buttons, screen text #that may be on the screen in the event of a chosen ( or asynchrinous ) #disable or deletion - Code redundance here is necessary #being that "disable" is called upon server crash, and delete is #called upon zone exit ### def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None taskMgr.remove('playerTurnTask') #self.table = None def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None self.winningSequence.finish() taskMgr.remove('playerTurnTask') ########## ##Timer Functions #setTimer (broadcast ram required) #setTurnTimer(broadcast ram required) # #setTimer() controlls the timer for game begin, which upon its timout #calls the startButton. # #turnTimer() does just that # #Important to note that both timers run on the same clockNode. ########## def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState( ).getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if (timeLeft > 0 and timerEnd != 0): if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(.64, 0, -0.27) self.clockNode.countdown(timeLeft, self.doRandomMove) self.clockNode.show() ########### ##Game start(broadcast) and Send Turn (broadcast ram) # #IMPORTANT - 255 is the Uint8 sent to the player when a game starts #to dictate to him that a game is beginning and he is labeled as an observer #for that game - this affects the visual queues for his player color ect. ########## def gameStart(self, playerNum): if playerNum != 255: #observer value self.playerNum = playerNum if self.playerNum == 1: self.playerColorString = "Red" else: self.playerColorString = "Yellow" self.moveCameraForGame() self.fsm.request('playing') def sendTurn(self, playersTurn): if self.fsm.getCurrentState().getName() == 'playing': if playersTurn == self.playerNum: self.isMyTurn = True taskMgr.add(self.turnTask, "playerTurnTask") self.enableTurnScreenText(playersTurn) def illegalMove(self): self.exitButtonPushed() ########## ##Move camera # #Got to move the camera to the specific location in the 3d environment so that the #nametags ect do not collide with the gameboard itself. #also half to do some if statements on the camera itself so that the camera will not (for instance) #rotate 350 degrees when rather it could rotate -10 degrees to get its finishing location ########## def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.pause() rotation = 0 if self.seatPos <= 2: position = self.table.seats[1].getPos() position = position + Vec3(0, -8, 12.8) int = LerpPosHprInterval(camera, 2, position, Vec3(0, -38, 0), camera.getPos(), camera.getHpr()) else: position = self.table.seats[4].getPos() position = position + Vec3(0, -8, 12.8) if camera.getH() < 0: int = LerpPosHprInterval(camera, 2, position, Vec3(-180, -20, 0), camera.getPos(), camera.getHpr()) else: int = LerpPosHprInterval(camera, 2, position, Vec3(180, -20, 0), camera.getPos(), camera.getHpr()) int.start() ##################### #FSM Stuff ### def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() def enterGameOver(self): pass def exitGameOver(self): pass ################################################## # Button Functions and Text ### def exitWaitCountdown(self): self.__disableCollisions() self.ignore("trolleyExitButton") self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton( relief=None, text=TTLocalizer.FindFourGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.80), scale=0.15, command=lambda self=self: self.exitButtonPushed(), ) return def enableScreenText(self): defaultPos = (-.7, -0.29) if self.playerNum == 1: message = "You are Red" color = Vec4(1, 0, 0, 1) elif self.playerNum == 2: message = "You are Yellow" color = Vec4(1, 1, 0, 1) else: message = TTLocalizer.FindFourObserver color = Vec4(0, 0, 0, 1) #defaultPos = (-.80, -0.25) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.10, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton( relief=None, text=TTLocalizer.FindFourStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.57), scale=0.15, command=lambda self=self: self.startButtonPushed(), ) return def enableLeaveButton(self): self.leaveButton = DirectButton( relief=None, text=TTLocalizer.FindFourQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.8), scale=0.15, command=lambda self=self: self.exitButtonPushed(), ) return def enableTurnScreenText(self, player): playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.FindFourIts if (self.turnText != None): self.turnText.destroy() if player == self.playerNum: message2 = TTLocalizer.FindFourYourTurn color = (0, 0, 0, 1) else: if player == 1: message2 = TTLocalizer.FindFourRedTurn color = (1, 0, 0, 1) elif player == 2: message2 = TTLocalizer.FindFourYellowTurn color = (1, 1, 0, 1) self.turnText = OnscreenText(text=message1 + message2, pos=(-0.7, -0.39), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) #This function is called either if the player clicks on it (to begin a game) #or if the game begin timer runs out. (timer is in sync with server so results should be # + or - ~ 1 second def startButtonPushed(self): self.sendUpdate("requestBegin") self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate("requestExit") ########## #Mouse Picking/clicking operations # # #These functions handle all of the mouse clicking functions #Its best to look through the code for comments for it to make #the most sense. # #The self.blinker that is referenced in these functions, is a cosmetic #colorLerp that gives the player a visual feedback as to what checkers peice #he has (currently) selected. # # #mouseClick is just an extention to the Task that is generated whenever it is your turn - #mouseClick simply commits the move that you have been deciding upon inside of the 'playerTurnTask" ########## def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True and not self.moveSequence.isPlaying( ): #cant pick stuff if its not your turn if self.moveCol != None: self.d_requestMove(self.moveCol) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') def handleClicked(self, index): pass #This is the wonderul task that handles the magic for the selecting of the game piece #it is important to note that this task gets spawned up whenever it is deemed your turn #by the sendTurn stuff #I had to make some optimizations to not make this task completely bogg down the computer #(1) set the bit masks for the collision traverser so that it will not even test anything that #is not a collision sphere for the findFour Game def turnTask(self, task): if base.mouseWatcherNode.hasMouse() == False: return task.cont if self.isMyTurn == False: return task.cont if self.moveSequence.isPlaying(): return task.cont mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() #get the closest Object pickedObj = self.myHandler.getEntry(0).getIntoNodePath() #will return the INT for the locator node closest parent pickedObj = pickedObj.getNetTag("StartLocator") if pickedObj: #make sure something actually was "picked" colVal = int(pickedObj) if colVal == self.moveCol: return task.cont if self.board[0][colVal] == 0: #it is a legal move if self.moveCol != None: for x in self.startingPositions[self.moveCol].getChild( 1).getChildren(): #hide the old peices x.hide() self.moveCol = colVal if self.playerNum == 1: self.startingPositions[self.moveCol].getChild( 1).getChild(2).show() elif self.playerNum == 2: self.startingPositions[self.moveCol].getChild( 1).getChild(3).show() return task.cont def d_requestMove(self, moveCol): self.sendUpdate('requestMove', [moveCol]) ########## ##setGameState (required broadcast ram) # #This is the function that handles the moves made after a move is parsed by the AI #and deemed to be valid # #If moveList is the empty List, then the player is asynchronously joining the game, (OBSERVING) #and just wants the board state. # #otherwise there is a series of jumps (or jump) that needs to be parsed and animated, then #consequently setting the board state # #after every setGameState, the client checks to see the current #Status of his peices (checkForWin), if he belives he won, he requests it to the server ######### def setGameState(self, tableState, moveCol, movePos, turn): messenger.send('wakeup') ##Funny if statement #1 #This slew of statements is to handle a specific case that looks funny #when a client joins the game (to observe) after the game has begun # #If you notice, you will see that the movePos and the MoveCol are parts #of the game state (required RAM), so when a client joins this game asynchrinously #they too will see the last moves animation as they are sitting down at the table. # # These slew of if statements are to handle that fact, by testing the state of the #current game board, as well as the state of the board that was handed to the client #through the DC message. if self.table.fsm.getCurrentState().getName() == 'observing': isBlank = True for x in range(7): if self.board[5][x] != 0: isBlank = False break gameBlank = True for x in range(7): if tableState[5][x] != 0: gameBlank = False break if isBlank == True and gameBlank == False: for x in range(6): for y in range(7): self.board[x][y] = tableState[x][y] self.updateGameState() return ### #This if statement really doesnt apply unless the board is completely blank! if moveCol == 0 and movePos == 0 and turn == 0: #Someones coming in after a Move for x in range(6): for y in range(7): self.board[x][y] = tableState[x][y] self.updateGameState() else: #need to animate because a movePos was given in the Ram Field self.animatePeice(tableState, moveCol, movePos, turn) #Clients all check if they won in this game, where the AI #verifies - to save cycles on the AI server didIWin = self.checkForWin() if didIWin != None: self.sendUpdate("requestWin", [didIWin]) ############################################ ##UpdateGameState # #For the games (visual) state, it is important to note that child 0 and child1 #are the pieces that have been copied and reparented to that node. #Really, i just have 2 peices that are in the model, and i hide/show them #instead of instantiating them on the fly. ## def updateGameState(self): for x in range(6): for y in range(7): for z in self.locatorList[(x * 7) + y].getChild(1).getChildren(): z.hide() for x in range(6): for y in range(7): state = self.board[x][y] if state == 1: self.locatorList[(x * 7) + y].getChild(1).getChild(0).show() elif state == 2: self.locatorList[(x * 7) + y].getChild(1).getChild(1).show() ########## ##CheckForWin # #This function is pretty self explanitory, it checks all of the directions for #all of the pieces on the players current boardState to check for a win. # #this is needed because programming wise it would be a disgusting case to test #for a win if a peice is in the middle of a (4) piece run - Rather it is easier #to simply test all the pieces whether or not they are on the Edge of a win, #thus making the code 1000% easier to read and understand. ### def checkForWin(self): for x in range(6): for y in range(7): if self.board[x][y] == self.playerNum: if self.checkHorizontal(x, y, self.playerNum) == True: return [x, y] elif self.checkVertical(x, y, self.playerNum) == True: return [x, y] elif self.checkDiagonal(x, y, self.playerNum) == True: return [x, y] return None ########### ##AnnounceWinnerPosition # #Fancy function that is called after the AI determines the players' request was #in deed a true win. # #This function does all of the animations for the blinking after a person wins # #Also - Note that there are two separate functions for finding/checking a win. # #check(direction) - returns true or false #find(direction) - returns the list of 4 ints if win and [] for no win ### def announceWinnerPosition(self, x, y, winDirection, playerNum): self.isMyturn = False if self.turnText: self.turnText.hide() self.clockNode.stop() self.clockNode.hide() if winDirection == 0: blinkList = self.findHorizontal(x, y, playerNum) elif winDirection == 1: blinkList = self.findVertical(x, y, playerNum) elif winDirection == 2: blinkList = self.findDiagonal(x, y, playerNum) if blinkList != []: print(blinkList) val0 = (x * 7) + y x = blinkList[0][0] y = blinkList[0][1] val1 = (x * 7) + y x = blinkList[1][0] y = blinkList[1][1] val2 = (x * 7) + y x = blinkList[2][0] y = blinkList[2][1] val3 = (x * 7) + y self.winningSequence = Sequence() downBlinkerParallel = Parallel( LerpColorInterval(self.locatorList[val0], .3, Vec4(.5, .5, .5, .5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val1], .3, Vec4(.5, .5, .5, .5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val2], .3, Vec4(.5, .5, .5, .5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[val3], .3, Vec4(.5, .5, .5, .5), Vec4(1, 1, 1, 1))) upBlinkerParallel = Parallel( LerpColorInterval(self.locatorList[val0], .3, Vec4(1, 1, 1, 1), Vec4(.5, .5, .5, .5)), LerpColorInterval(self.locatorList[val1], .3, Vec4(1, 1, 1, 1), Vec4(.5, .5, .5, .5)), LerpColorInterval(self.locatorList[val2], .3, Vec4(1, 1, 1, 1), Vec4(.5, .5, .5, .5)), LerpColorInterval(self.locatorList[val3], .3, Vec4(1, 1, 1, 1), Vec4(.5, .5, .5, .5))) self.winningSequence.append(downBlinkerParallel) self.winningSequence.append(upBlinkerParallel) self.winningSequence.loop() ########## ##Tie # #This is the function that sends the tie message, and animates the whole board in a fun way such that #dictates that a tie has occurred ### def tie(self): self.tieSequence = Sequence(autoFinish=1) self.clockNode.stop() self.clockNode.hide() self.isMyTurn = False self.moveSequence.finish() if self.turnText: self.turnText.hide() for x in range(41): self.tieSequence.append( Parallel( LerpColorInterval(self.locatorList[x], .15, Vec4(.5, .5, .5, .5), Vec4(1, 1, 1, 1)), LerpColorInterval(self.locatorList[x], .15, Vec4(1, 1, 1, 1), Vec4(.5, .5, .5, .5)))) whisper = WhisperPopup("This Find Four game has resulted in a Tie!", OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) whisper.manage(base.marginManager) self.tieSequence.start() def hideChildren(self, nodeList): pass ########## ##animatePiece # #Function that handles the animation of the next move, as well as sets the current #view of the board so that the player can see it def animatePeice(self, tableState, moveCol, movePos, turn): messenger.send('wakeup') #update the board state from DC parent function for x in range(6): for y in range(7): self.board[x][y] = tableState[x][y] #show the column piece that was selected for the move pos = self.startingPositions[moveCol].getPos() if turn == 0: peice = self.startingPositions[moveCol].getChild( 1).getChildren()[2] peice.show() elif turn == 1: peice = self.startingPositions[moveCol].getChild( 1).getChildren()[3] peice.show() #animate the thing self.moveSequence = Sequence() startPos = self.startingPositions[moveCol].getPos() arrayLoc = (movePos * 7) + moveCol self.moveSequence.append( LerpPosInterval(self.startingPositions[moveCol], 1.5, self.locatorList[arrayLoc].getPos(self), startPos)) self.moveSequence.append(Func(peice.hide)) self.moveSequence.append( Func(self.startingPositions[moveCol].setPos, startPos)) self.moveSequence.append(Func(self.updateGameState)) self.moveSequence.start() def announceWin(self, avId): self.fsm.request('gameOver') ########## ##doRandomMove # #For this game, doRandom move will as well fire when the turnTimer runs out - but will also, #(if the player has been debating pieces with his cursor), will commite the last selected piece #by the 'playerTurnTask' # #It is also smart enough to not randomly commit an illegal move :) ########### def doRandomMove(self): if self.isMyTurn: if self.moveCol != None: self.d_requestMove(self.moveCol) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') else: hasfound = False while hasfound == False: import random x = random.randint(0, 6) if self.board[0][x] == 0: self.d_requestMove(x) self.moveCol = None self.isMyTurn = False taskMgr.remove('playerTurnTask') hasfound = True def doNothing(self): pass ########## ##Large slew of check/find Functions # #I would suggest getting out paper to analyze how these things work, but hopefully #with a bit of ASCII art and some explaining it wont be too bad. # # Game board is represented as such in memory (as you see it in real life): # |0 0 0 0 0 0 0 | 0 1 2 3 4 5 6 # |0 0 0 0 0 0 0 | 0 . . . . . . . # |0 0 0 0 0 0 0 | 1 . . . . . . . # |0 0 0 0 0 0 0 | 2 . . . . . . . # |0 0 0 0 0 0 0 | 3 . . . . . . . # |0 0 0 0 0 0 0 | 4 . . . . . . . # 5 . . . . . . . # # # as you can see, (0,0) is in the top left corner, and just makes things easier to write about #because the locators, and lists seem to function well in this sense # board state looks like [ [0,0,0,0,0,0,0], # [0,0,0,0,0,0,0], # [0,0,0,0,0,0,0], # [0,0,0,0,0,0,0], # [0,0,0,0,0,0,0], # [0,0,0,0,0,0,0] ] # # #So when looking at this code just keep in mind this is how the board is working in memory # #Also, important to see that there are two types of functions here #(1) the check(direction) functions who return true or false whether or not they detect # a win in that direction #(2) the find(direction) functions who return the list of where they detected a win # or [ ] if they found nothing. ## def checkHorizontal(self, rVal, cVal, playerNum): if cVal == 3: for x in range(1, 4): if self.board[rVal][cVal - x] != playerNum: break if self.board[rVal][cVal - x] == playerNum and x == 3: return True for x in range(1, 4): if self.board[rVal][cVal + x] != playerNum: break if self.board[rVal][cVal + x] == playerNum and x == 3: return True return False elif cVal == 2: for x in range(1, 4): if self.board[rVal][cVal + x] != playerNum: break if self.board[rVal][cVal + x] == playerNum and x == 3: return True return False elif cVal == 4: for x in range(1, 4): if self.board[rVal][cVal - x] != playerNum: break if self.board[rVal][cVal - x] == playerNum and x == 3: return True return False else: return False def checkVertical(self, rVal, cVal, playerNum): if rVal == 2: for x in range(1, 4): if self.board[rVal + x][cVal] != playerNum: break if self.board[rVal + x][cVal] == playerNum and x == 3: return True return False elif rVal == 3: for x in range(1, 4): if self.board[rVal - x][cVal] != playerNum: break if self.board[rVal - x][cVal] == playerNum and x == 3: return True return False else: return False def checkDiagonal(self, rVal, cVal, playerNum): if cVal <= 2: #Cannot have Left Diagonals if rVal == 2: #cannot have upper Diagonal for x in range(1, 4): if self.board[rVal + x][cVal + x] != playerNum: break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return True return False elif rVal == 3: #cannot have downard diagonal for x in range(1, 4): if self.board[rVal - x][cVal + x] != playerNum: break if self.board[rVal - x][cVal + x] == playerNum and x == 3: return True return False elif cVal >= 4: if rVal == 2: #cannot have upper Diagonal for x in range(1, 4): if self.board[rVal + x][cVal - x] != playerNum: break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 3: #cannot have downard diagonal for x in range(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True return False else: #we are in column 3 if rVal == 3 or rVal == 4 or rVal == 5: #we have 2 upward Diagonals for x in range(1, 4): #Up left if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True for x in range(1, 4): if self.board[rVal - x][cVal - x] != playerNum: break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return True return False elif rVal == 0 or rVal == 1 or rVal == 2: for x in range(1, 4): #down left if self.board[rVal + x][cVal - x] != playerNum: break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return True for x in range(1, 4): if self.board[rVal + x][cVal + x] != playerNum: break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return True return False return False ####################################### def findHorizontal(self, rVal, cVal, playerNum): if cVal == 3: retList = [] for x in range(1, 4): retList.append([rVal, cVal - x]) if self.board[rVal][cVal - x] != playerNum: retList = [] break if self.board[rVal][cVal - x] == playerNum and x == 3: return retList for x in range(1, 4): retList.append([rVal, cVal + x]) if self.board[rVal][cVal + x] != playerNum: retList = [] break if self.board[rVal][cVal + x] == playerNum and x == 3: return retList return [] elif cVal == 2: retList = [] for x in range(1, 4): retList.append([rVal, cVal + x]) if self.board[rVal][cVal + x] != playerNum: retList = [] break if self.board[rVal][cVal + x] == playerNum and x == 3: return retList return [] elif cVal == 4: retList = [] for x in range(1, 4): retList.append([rVal, cVal - x]) if self.board[rVal][cVal - x] != playerNum: retList = [] break if self.board[rVal][cVal - x] == playerNum and x == 3: return retList return [] else: return [] def findVertical(self, rVal, cVal, playerNum): if rVal == 2: retList = [] for x in range(1, 4): retList.append([rVal + x, cVal]) if self.board[rVal + x][cVal] != playerNum: retList = [] break if self.board[rVal + x][cVal] == playerNum and x == 3: return retList return [] elif rVal == 3: retList = [] for x in range(1, 4): retList.append([rVal - x, cVal]) if self.board[rVal - x][cVal] != playerNum: retList = [] break if self.board[rVal - x][cVal] == playerNum and x == 3: return retList return [] else: return [] def findDiagonal(self, rVal, cVal, playerNum): retList = [] if cVal <= 2: #Cannot have Left Diagonals if rVal == 2: #cannot have upper Diagonal for x in range(1, 4): retList.append([rVal + x, cVal + x]) if self.board[rVal + x][cVal + x] != playerNum: retList = [] break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return retList return [] elif rVal == 3: #cannot have downard diagonal for x in range(1, 4): retList.append([rVal - x, cVal + x]) if self.board[rVal - x][cVal + x] != playerNum: retList = [] break if self.board[rVal - x][cVal + x] == playerNum and x == 3: return retList return [] elif cVal >= 4: if rVal == 2: #cannot have upper Diagonal for x in range(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 3: #cannot have downard diagonal for x in range(1, 4): retList.append([rVal - x, cVal - x]) if self.board[rVal - x][cVal - x] != playerNum: retList = [] break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return retList return [] else: #we are in column 3 if rVal == 3 or rVal == 4 or rVal == 5: #we have 2 upward Diagonals for x in range(1, 4): #Up left retList.append([rVal - x, cVal - x]) if self.board[rVal - x][cVal - x] != playerNum: retList = [] break if self.board[rVal - x][cVal - x] == playerNum and x == 3: return retList for x in range(1, 4): retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList return [] elif rVal == 0 or rVal == 1 or rVal == 2: for x in range(1, 4): #down left retList.append([rVal + x, cVal - x]) if self.board[rVal + x][cVal - x] != playerNum: retList = [] break if self.board[rVal + x][cVal - x] == playerNum and x == 3: return retList for x in range(1, 4): retList.append([rVal + x, cVal + x]) if self.board[rVal + x][cVal + x] != playerNum: retList = [] break if self.board[rVal + x][cVal + x] == playerNum and x == 3: return retList return [] return []
class DistributedViewingBlock(DistributedStartingBlock): """ Derived from the starting block to provide specific movies for the Viewing pads. """ ###################################################################### # Class Variables ###################################################################### notify = DirectNotifyGlobal.directNotify.newCategory( "DistributedViewingBlock") #notify.setInfo(True) sphereRadius = 6 #cameraPos = Point3(-23, 0, 10) #cameraHpr = Point3(90, -10, 0) def __init__(self, cr): """ Comment """ # Initialize the Super Class DistributedStartingBlock.__init__(self, cr) # Initialize Instance Variables self.timer = None def delete(self): """ """ if (self.timer is not None): self.timer.destroy() del self.timer # Perform the Super Class Delete Call DistributedStartingBlock.delete(self) def generateInit(self): """ comment """ self.notify.debugStateCall(self) # skip over DistributedStartingBlock, since this method is # a cut-and-paste of DistributedStartingBlock.generateInit DistributedObject.DistributedObject.generateInit(self) # Create a NodePath to represent the spot itself. It gets # repositioned according to setPosHpr. self.nodePath = NodePath(self.uniqueName('StartingBlock')) # Make a collision sphere to detect when an avatar enters the # kart block. self.collSphere = CollisionSphere(-1, 6.75, -1, self.sphereRadius) # Make sure the sphere is intangible initially. self.collSphere.setTangible(0) self.collNode = CollisionNode(self.uniqueName('StartingBlockSphere')) self.collNode.setCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.nodePath.attachNewNode(self.collNode) def announceGenerate(self): """ Comment """ self.notify.debugStateCall(self) # skip over DistributedStartingBlock, since this method is # a cut-and-paste of DistributedStartingBlock.announceGenerate DistributedObject.DistributedObject.announceGenerate(self) # The posHpr has been set at this point, thus reparent to render # and accept the collision sphere event. #if( __debug__ ): # self.smiley = loader.loadModel( "models/misc/smiley" ) # self.smiley.setScale( 0.25 ) # self.smiley.setColorScale( 1, 0, 0, 1 ) # self.smiley.reparentTo( self.nodePath ) self.nodePath.reparentTo(render) self.accept(self.uniqueName('enterStartingBlockSphere'), self.__handleEnterSphere) if (__debug__): if self.testLOD: self.__generateKartAppearTrack() def setPadLocationId(self, padLocationId): """ Comment: """ self.notify.debugStateCall(self) # Generate a new node on the nodepath. self.movieNode = self.nodePath.attachNewNode( self.uniqueName('MovieNode')) self.exitMovieNode = self.nodePath.attachNewNode( self.uniqueName('ExitMovieNode')) if (padLocationId % 2): # padLocation is on the right-side, thus the view node should # be placed on the right-side. self.movieNode.setPosHpr(0, 6.5, 0, 0, 0, 0) else: # otherwise its on the left-side. self.movieNode.setPosHpr(0, -6.5, 0, 0, 0, 0) self.exitMovieNode.setPosHpr(3, 6.5, 0, 270, 0, 0) #if( __debug__ ): # self.smiley3 = loader.loadModel( "models/misc/smiley" ) # self.smiley3.setScale( 0.2 ) # self.smiley3.setColorScale( 1, 1, 0, 1 ) # self.smiley3.reparentTo( self.exitMovieNode ) # self.smiley2 = loader.loadModel( "models/misc/smiley" ) # self.smiley2.setScale( 0.2 ) # self.smiley2.setColorScale( 0, 1, 0, 1 ) # self.smiley2.reparentTo( self.movieNode ) self.collNodePath.reparentTo(self.movieNode) #if ( __debug__): # self.collNodePath.show() def __handleEnterSphere(self, collEntry): """ comment """ assert self.notify.debug("__handleEnterSphere") # Protect against the same toon from re-entering the sphere # immediately after exiting. It is most likely a mistake on the # toon's part. if( base.localAvatar.doId == self.lastAvId and \ globalClock.getFrameCount() <= self.lastFrame + 1 ): self.notify.debug("Ignoring duplicate entry for avatar.") return # Only toons with hp > 0 and own a kart may enter the sphere. if ((base.localAvatar.hp > 0)): def handleEnterRequest(self=self): self.ignore("stoppedAsleep") if hasattr(self.dialog, 'doneStatus') and (self.dialog.doneStatus == 'ok'): self.d_requestEnter(base.cr.isPaid()) else: self.cr.playGame.getPlace().setState("walk") self.dialog.ignoreAll() self.dialog.cleanup() del self.dialog # take the localToon out of walk mode self.cr.playGame.getPlace().fsm.request('stopped') # make dialog go away if they fall asleep while stopped self.accept("stoppedAsleep", handleEnterRequest) # A dialog box should prompt the toon for action, to either # enter a race or ignore it. doneEvent = 'enterRequest|dialog' msg = TTLocalizer.StartingBlock_EnterShowPad self.dialog = TTGlobalDialog(msg, doneEvent, 4) self.dialog.accept(doneEvent, handleEnterRequest) #self.d_requestEnter() def generateCameraMoveTrack(self): """ """ self.cPos = camera.getPos(self.av) self.cHpr = camera.getHpr(self.av) cameraPos = Point3(23, -10, 7) cameraHpr = Point3(65, -10, 0) camera.wrtReparentTo(self.nodePath) cameraTrack = LerpPosHprInterval(camera, 1.5, cameraPos, cameraHpr) return cameraTrack def makeGui(self): self.notify.debugStateCall(self) if (self.timer is not None): return # TEMPORARY TOONTOWN TIMER FOR TIME UNTIL RACE LAUNCH self.timer = ToontownTimer() self.timer.setScale(0.3) self.timer.setPos(1.16, 0, -.73) self.timer.hide() # Make Super Class GUI DistributedStartingBlock.makeGui(self) def showGui(self): self.notify.debugStateCall(self) # Show Timer and Super class gui self.timer.show() DistributedStartingBlock.showGui(self) def hideGui(self): self.notify.debugStateCall(self) if (not hasattr(self, "timer") or self.timer is None): return self.timer.reset() self.timer.hide() DistributedStartingBlock.hideGui(self) def countdown(self): countdownTime = KartGlobals.COUNTDOWN_TIME - globalClockDelta.localElapsedTime( self.kartPad.getTimestamp(self.avId)) self.timer.countdown(countdownTime) def enterEnterMovie(self): """ """ #pdb.set_trace() self.notify.debug( "%d enterEnterMovie: Entering the Enter Movie State." % self.doId) if ConfigVariableBool('want-qa-regression', 0).getValue(): raceName = TTLocalizer.KartRace_RaceNames[self.kartPad.trackType] self.notify.info('QA-REGRESSION: KARTING: %s' % raceName) # Obtain the toon's kart. pos = self.nodePath.getPos(render) hpr = self.nodePath.getHpr(render) pos.addZ(1.7) #1.5 ) hpr.addX(270) self.kartNode.setPosHpr(pos, hpr) # Obtain the Enter Movie Tracks toonTrack = self.generateToonMoveTrack() kartTrack = self.generateKartAppearTrack() jumpTrack = self.generateToonJumpTrack() name = self.av.uniqueName("EnterRaceTrack") if ((self.av is not None) and (self.localToonKarting)): cameraTrack = self.generateCameraMoveTrack() self.finishMovie() self.movieTrack = Sequence(Parallel( cameraTrack, Sequence(), ), kartTrack, jumpTrack, Func(self.makeGui), Func(self.showGui), Func(self.countdown), Func(self.request, "Waiting"), Func(self.d_movieFinished), name=name, autoFinish=1) else: self.finishMovie() self.movieTrack = Sequence( toonTrack, kartTrack, jumpTrack, name=name, autoFinish=1, ) self.movieTrack.start() # never show the dialog on viewing pads self.exitRequested = True
class DistributedViewingBlock(DistributedStartingBlock): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedViewingBlock') sphereRadius = 6 def __init__(self, cr): DistributedStartingBlock.__init__(self, cr) self.timer = None return def delete(self): if self.timer is not None: self.timer.destroy() del self.timer DistributedStartingBlock.delete(self) return def generateInit(self): self.notify.debugStateCall(self) DistributedObject.DistributedObject.generateInit(self) self.nodePath = NodePath(self.uniqueName('StartingBlock')) self.collSphere = CollisionSphere(-1, 6.75, -1, self.sphereRadius) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.uniqueName('StartingBlockSphere')) self.collNode.setCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.nodePath.attachNewNode(self.collNode) def announceGenerate(self): self.notify.debugStateCall(self) DistributedObject.DistributedObject.announceGenerate(self) self.nodePath.reparentTo(render) self.accept(self.uniqueName('enterStartingBlockSphere'), self.__handleEnterSphere) if (__debug__): if self.testLOD: self.__generateKartAppearTrack() def setPadLocationId(self, padLocationId): self.notify.debugStateCall(self) self.movieNode = self.nodePath.attachNewNode(self.uniqueName('MovieNode')) self.exitMovieNode = self.nodePath.attachNewNode(self.uniqueName('ExitMovieNode')) if padLocationId % 2: self.movieNode.setPosHpr(0, 6.5, 0, 0, 0, 0) else: self.movieNode.setPosHpr(0, -6.5, 0, 0, 0, 0) self.exitMovieNode.setPosHpr(3, 6.5, 0, 270, 0, 0) self.collNodePath.reparentTo(self.movieNode) def __handleEnterSphere(self, collEntry): if base.localAvatar.doId == self.lastAvId and globalClock.getFrameCount() <= self.lastFrame + 1: self.notify.debug('Ignoring duplicate entry for avatar.') return if base.localAvatar.hp > 0: def handleEnterRequest(self = self): self.ignore('stoppedAsleep') if hasattr(self.dialog, 'doneStatus') and self.dialog.doneStatus == 'ok': self.d_requestEnter(base.cr.isPaid()) else: self.cr.playGame.getPlace().setState('walk') self.dialog.ignoreAll() self.dialog.cleanup() del self.dialog self.cr.playGame.getPlace().fsm.request('stopped') self.accept('stoppedAsleep', handleEnterRequest) doneEvent = 'enterRequest|dialog' msg = TTLocalizer.StartingBlock_EnterShowPad self.dialog = TTGlobalDialog(msg, doneEvent, 4) self.dialog.accept(doneEvent, handleEnterRequest) def generateCameraMoveTrack(self): self.cPos = camera.getPos(self.av) self.cHpr = camera.getHpr(self.av) cameraPos = Point3(23, -10, 7) cameraHpr = Point3(65, -10, 0) camera.wrtReparentTo(self.nodePath) cameraTrack = LerpPosHprInterval(camera, 1.5, cameraPos, cameraHpr) return cameraTrack def makeGui(self): self.notify.debugStateCall(self) if self.timer is not None: return self.timer = ToontownTimer() self.timer.setScale(0.3) self.timer.setPos(1.16, 0, -.73) self.timer.hide() DistributedStartingBlock.makeGui(self) return def showGui(self): self.notify.debugStateCall(self) self.timer.show() DistributedStartingBlock.showGui(self) def hideGui(self): self.notify.debugStateCall(self) if not hasattr(self, 'timer') or self.timer is None: return self.timer.reset() self.timer.hide() DistributedStartingBlock.hideGui(self) return def countdown(self): countdownTime = KartGlobals.COUNTDOWN_TIME - globalClockDelta.localElapsedTime(self.kartPad.getTimestamp(self.avId)) self.timer.countdown(countdownTime) def enterEnterMovie(self): self.notify.debug('%d enterEnterMovie: Entering the Enter Movie State.' % self.doId) if base.config.GetBool('want-qa-regression', 0): raceName = TTLocalizer.KartRace_RaceNames[self.kartPad.trackType] self.notify.info('QA-REGRESSION: KARTING: %s' % raceName) pos = self.nodePath.getPos(render) hpr = self.nodePath.getHpr(render) pos.addZ(1.7) hpr.addX(270) self.kartNode.setPosHpr(pos, hpr) toonTrack = self.generateToonMoveTrack() kartTrack = self.generateKartAppearTrack() jumpTrack = self.generateToonJumpTrack() name = self.av.uniqueName('EnterRaceTrack') if self.av is not None and self.localToonKarting: cameraTrack = self.generateCameraMoveTrack() self.finishMovie() self.movieTrack = Sequence(Parallel(cameraTrack, Sequence()), kartTrack, jumpTrack, Func(self.makeGui), Func(self.showGui), Func(self.countdown), Func(self.request, 'Waiting'), Func(self.d_movieFinished), name=name, autoFinish=1) else: self.finishMovie() self.movieTrack = Sequence(toonTrack, kartTrack, jumpTrack, name=name, autoFinish=1) self.movieTrack.start() self.exitRequested = True return
class DistributedChineseCheckers(DistributedNode.DistributedNode): def __init__(self, cr): NodePath.__init__(self, "DistributedChineseCheckers") DistributedNode.DistributedNode.__init__(self, cr) self.cr = cr self.reparentTo(render) self.boardNode = loader.loadModel( "phase_6/models/golf/checker_game.bam") self.boardNode.reparentTo(self) #self.boardNode.setZ(2.85) #self.boardNode.setZ(3.5) #self.boardNode.setZ(0.3) #self.boardNode.setZ(self.getZ()) self.board = ChineseCheckersBoard() self.playerTags = render.attachNewNode("playerTags") self.playerTagList = [] #game variables self.exitButton = None self.inGame = False self.waiting = True self.startButton = None self.playerNum = None self.turnText = None self.isMyTurn = False self.wantTimer = True self.leaveButton = None self.screenText = None self.turnText = None self.exitButton = None self.numRandomMoves = 0 self.blinker = Sequence() self.playersTurnBlinker = Sequence() self.yourTurnBlinker = Sequence() self.moveList = [] self.mySquares = [] self.playerSeats = None ###self.playerTags = [None, None, None, None, None, None #Mouse picking required stuff self.accept('mouse1', self.mouseClick) self.traverser = base.cTrav self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(ToontownGlobals.WallBitmask) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myHandler = CollisionHandlerQueue() self.traverser.addCollider(self.pickerNP, self.myHandler) self.buttonModels = loader.loadModel( "phase_3.5/models/gui/inventory_gui") self.upButton = self.buttonModels.find("**//InventoryButtonUp") self.downButton = self.buttonModels.find("**/InventoryButtonDown") self.rolloverButton = self.buttonModels.find( "**/InventoryButtonRollover") self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() #[0] GREEN [1] YELLOW [2] PURPLE [3] BLUE [4] PINK [5] RED self.playerColors = [ Vec4(0, .90, 0, 1), Vec4(.9, .9, 0, 1), Vec4(.45, 0, .45, 1), Vec4(.2, .4, .8, 1), Vec4(1, .45, 1, 1), Vec4(.8, 0, 0, 1) ] self.tintConstant = Vec4(.25, .25, .25, 0) self.ghostConstant = Vec4(0, 0, 0, .5) #starting positions are used to check and see if a player has gone into #his opposing players starting position, thus to tell if he won. self.startingPositions = [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 23, 24, 25, 35, 36, 46], [65, 75, 76, 86, 87, 88, 98, 99, 100, 101], [111, 112, 113, 114, 115, 116, 117, 118, 119, 120], [74, 84, 85, 95, 96, 97, 107, 108, 109, 110], [19, 20, 21, 22, 32, 33, 34, 44, 45, 55] ] self.nonOpposingPositions = [] self.knockSound = base.loadSfx("phase_5/audio/sfx/GUI_knock_1.mp3") self.clickSound = base.loadSfx( "phase_3/audio/sfx/GUI_balloon_popup.mp3") self.moveSound = base.loadSfx("phase_6/audio/sfx/CC_move.mp3") self.accept('stoppedAsleep', self.handleSleep) #base.setCellsAvailable(base.leftCells + #[base.bottomCells[0]], 0) #base.setCellsAvailable(base.bottomCells,0) ####################### #Fsm and State Data from direct.fsm import ClassicFSM, State self.fsm = ClassicFSM.ClassicFSM( 'ChineseCheckers', [ State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, ['playing', 'gameOver']), State.State('playing', self.enterPlaying, self.exitPlaying, ['gameOver']), State.State('gameOver', self.enterGameOver, self.exitGameOver, ['waitingToBegin']) ], # Initial State 'waitingToBegin', # Final State 'waitingToBegin', ) ######################### #Set up the Board Locators ## x = self.boardNode.find("**/locators") #set up the locator list so we can mess with it self.locatorList = x.getChildren() #tag the locators for "picking" ingame #also add colision spheres for movement tempList = [] for x in range(0, 121): self.locatorList[x].setTag("GamePeiceLocator", "%d" % x) tempList.append(self.locatorList[x].attachNewNode( CollisionNode("picker%d" % x))) tempList[x].node().addSolid(CollisionSphere(0, 0, 0, .115)) for z in self.locatorList: y = loader.loadModel("phase_6/models/golf/checker_marble.bam") z.setColor(0, 0, 0, 0) y.reparentTo(z) #y.show() #y.hide() def setName(self, name): self.name = name def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) if self.table.fsm.getCurrentState().getName() != 'observing': if base.localAvatar.doId in self.table.tableState: # Fix for strange state #TEMP until i find the cause self.seatPos = self.table.tableState.index( base.localAvatar.doId) self.playerTags.setPos(self.getPos()) def handleSleep(self, task=None): if self.fsm.getCurrentState().getName() == "waitingToBegin": self.exitButtonPushed() if task != None: task.done #task.done ########## ##setTableDoId (required broadcast ram) # #Upon construction, sets local pointer to the table, as well as #sets the pointer on the table to itself. #This is necessary to handle events that occur on the table, not #particularly inside of any one game. ### def setTableDoId(self, doId): self.tableDoId = doId self.table = self.cr.doId2do[doId] self.table.setTimerFunc(self.startButtonPushed) self.fsm.enterInitialState() self.table.setGameDoId(self.doId) #self.table.tempCheckers.hide() #self.boardNode.setP(self.table.getP()) ######### ##Disable/Delete #Must be sure to remove/delete any buttons, screen text #that may be on the screen in the event of a chosen ( or asynchrinous ) #disable or deletion - Code redundance here is necessary #being that "disable" is called upon server crash, and delete is #called upon zone exit ### def disable(self): DistributedNode.DistributedNode.disable(self) if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.cleanPlayerTags() ###self.table = None def delete(self): DistributedNode.DistributedNode.delete(self) self.table.gameDoId = None self.table.game = None if self.exitButton: self.exitButton.destroy() if self.startButton: self.startButton.destroy() self.clockNode.stop() self.clockNode.hide() self.table.startButtonPushed = None self.ignore('mouse1') self.ignore('stoppedAsleep') self.fsm = None self.table = None self.cleanPlayerTags() del self.playerTags del self.playerTagList self.playerSeats = None self.yourTurnBlinker.finish() ########## ##Timer Functions #setTimer (broadcast ram required) #setTurnTimer(broadcast ram required) # #setTimer() controlls the timer for game begin, which upon its timout #calls the startButton. # #turnTimer() does just that # #Important to note that both timers run on the same clockNode. ########## def getTimer(self): self.sendUpdate('requestTimer', []) def setTimer(self, timerEnd): #print "TIMEREND! ", timerEnd if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'waitingToBegin' and not self.table.fsm.getCurrentState( ).getName() == 'observing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) timeLeft = int(time - globalClock.getRealTime()) if (timeLeft > 0 and timerEnd != 0): if timeLeft > 60: timeLeft = 60 self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: self.clockNode.stop() self.clockNode.hide() def setTurnTimer(self, turnEnd): if self.fsm.getCurrentState() != None and self.fsm.getCurrentState( ).getName() == 'playing': self.clockNode.stop() time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: self.clockNode.setPos(-.74, 0, -0.20) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doRandomMove) else: self.clockNode.countdown(timeLeft, self.doNothing) self.clockNode.show() ########### ##Game start(broadcast) and Send Turn (broadcast ram) # #IMPORTANT - 255 is the Uint8 sent to the player when a game starts #to dictate to him that a game is beginning and he is labeled as an observer #for that game - this affects the visual queues for his player color ect. ########## def gameStart(self, playerNum): if playerNum != 255: #observer value self.playerNum = playerNum self.playerColor = self.playerColors[playerNum - 1] self.moveCameraForGame() playerPos = playerNum - 1 import copy self.nonOpposingPositions = copy.deepcopy(self.startingPositions) if playerPos == 0: self.nonOpposingPositions.pop(0) self.opposingPositions = self.nonOpposingPositions.pop(2) elif playerPos == 1: self.nonOpposingPositions.pop(1) self.opposingPositions = self.nonOpposingPositions.pop(3) elif playerPos == 2: self.nonOpposingPositions.pop(2) self.opposingPositions = self.nonOpposingPositions.pop(4) elif playerPos == 3: self.nonOpposingPositions.pop(3) self.opposingPositions = self.nonOpposingPositions.pop(0) elif playerPos == 4: self.nonOpposingPositions.pop(4) self.opposingPositions = self.nonOpposingPositions.pop(1) elif playerPos == 5: self.nonOpposingPositions.pop(5) self.opposingPositions = self.nonOpposingPositions.pop(2) self.fsm.request('playing') def sendTurn(self, playersTurn): self.playersTurnBlinker.finish() if self.fsm.getCurrentState().getName() == 'playing': #print "GETTING HERE!", playersTurn - 1, " LENGTH!!!" , self.playerTagList #self.playerTagList if self.playerSeats == None: self.sendUpdate("requestSeatPositions", []) else: if playersTurn == self.playerNum: self.isMyTurn = True self.enableTurnScreenText(playersTurn) self.playersTurnBlinker = Sequence() origColor = self.playerColors[playersTurn - 1] self.playersTurnBlinker.append( LerpColorInterval( self.playerTagList[self.playerSeats.index( playersTurn)], .4, origColor - self.tintConstant - self.ghostConstant, origColor)) self.playersTurnBlinker.append( LerpColorInterval( self.playerTagList[self.playerSeats.index( playersTurn)], .4, origColor, origColor - self.tintConstant - self.ghostConstant)) self.playersTurnBlinker.loop() def announceSeatPositions(self, playerPos): #print "ANNOUNCESEATPOSITIONS!", playerPos self.playerSeats = playerPos for x in range(6): pos = self.table.seats[x].getPos(render) renderedPeice = loader.loadModel( "phase_6/models/golf/checker_marble.bam") #renderedPeice.setColor(self.playerColors[x-1]) renderedPeice.reparentTo(self.playerTags) renderedPeice.setPos(pos) renderedPeice.setScale(1.5) if x == 1: renderedPeice.setZ(renderedPeice.getZ() + 3.3) renderedPeice.setScale(1.3) elif x == 4: renderedPeice.setZ(renderedPeice.getZ() + 3.3) renderedPeice.setScale(1.45) else: renderedPeice.setZ(renderedPeice.getZ() + 3.3) renderedPeice.hide() self.playerTagList = self.playerTags.getChildren() for x in playerPos: if x != 0: self.playerTagList[playerPos.index(x)].setColor( self.playerColors[x - 1]) self.playerTagList[playerPos.index(x)].show() #if game is already going #if self.fsm.getCurrentState().getName() == 'playing': # if not self.playersTurnBlinker.isPlaying(): # self.playersTurnBlinker = Sequence() # origColor = self.playerColors[playersTurn-1] # self.playersTurnBlinker.append(LerpColorInterval(self.playerTagList[self.playerSeats.index(playersTurn)], .4, origColor - self.tintConstant - self.ghostConstant, origColor)) # self.playersTurnBlinker.append(LerpColorInterval(self.playerTagList[self.playerSeats.index(playersTurn)], .4,origColor, origColor - self.tintConstant - self.ghostConstant)) # self.playersTurnBlinker.loop() def cleanPlayerTags(self): for x in self.playerTagList: x.removeNode() self.playerTagList = [] self.playerTags.removeNode() ########## ##Move camera # #To make camera movement not seem weird (turning 270 degrees example) #Must check the clients orientation between the seatPos and his current H # so that he turns the least possible amount for the camera orientation # # ########## def moveCameraForGame(self): if self.table.cameraBoardTrack.isPlaying(): self.table.cameraBoardTrack.finish() rotation = 0 if self.seatPos > 2: if self.playerNum == 1: rotation = 180 elif self.playerNum == 2: rotation = -120 elif self.playerNum == 3: rotation = -60 elif self.playerNum == 4: rotation = 0 elif self.playerNum == 5: rotation = 60 elif self.playerNum == 6: rotation = 120 else: if self.playerNum == 1: rotation = 0 elif self.playerNum == 2: rotation = 60 elif self.playerNum == 3: rotation = 120 elif self.playerNum == 4: rotation = 180 elif self.playerNum == 5: rotation = -120 elif self.playerNum == 6: rotation = -60 #print self.boardNode.getHpr() # int = LerpHprInterval(camera, 3,Vec3(camera.getH(),camera.getP(),rotation), camera.getHpr()) #self.table.tempCheckers.hide() if rotation == 60 or rotation == -60: int = LerpHprInterval( self.boardNode, 2.5, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) elif rotation == 120 or rotation == -120: int = LerpHprInterval( self.boardNode, 3.5, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) else: int = LerpHprInterval( self.boardNode, 4.2, Vec3(rotation, self.boardNode.getP(), self.boardNode.getR()), self.boardNode.getHpr()) #self.table.tempCheckers.setHpr( Vec3(rotation, self.table.tempCheckers.getP(), self.table.tempCheckers.getR())) int.start() ##################### #FSM Stuff ### def enterWaitingToBegin(self): if self.table.fsm.getCurrentState().getName() != 'observing': self.enableExitButton() self.enableStartButton() def exitWaitingToBegin(self): if self.exitButton: self.exitButton.destroy() self.exitButton = None if self.startButton: self.startButton.destroy() self.exitButton = None self.clockNode.stop() self.clockNode.hide() def enterPlaying(self): self.inGame = True self.enableScreenText() if self.table.fsm.getCurrentState().getName() != 'observing': self.enableLeaveButton() def exitPlaying(self): self.inGame = False if self.leaveButton: self.leaveButton.destroy() self.leavebutton = None self.playerNum = None if self.screenText: self.screenText.destroy() self.screenText = None if self.turnText: self.turnText.destroy() self.turnText = None self.clockNode.stop() self.clockNode.hide() self.cleanPlayerTags() def enterGameOver(self): pass def exitGameOver(self): pass ################################################## # Button Functions and Text ### def exitWaitCountdown(self): self.__disableCollisions() self.ignore("trolleyExitButton") self.clockNode.reset() def enableExitButton(self): self.exitButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.4), scale=0.15, command=lambda self=self: self.exitButtonPushed(), ) return def enableScreenText(self): defaultPos = (-.80, -0.40) if self.playerNum == 1: message = TTLocalizer.ChineseCheckersColorG color = self.playerColors[0] elif self.playerNum == 2: message = TTLocalizer.ChineseCheckersColorY color = self.playerColors[1] elif self.playerNum == 3: message = TTLocalizer.ChineseCheckersColorP color = self.playerColors[2] elif self.playerNum == 4: message = TTLocalizer.ChineseCheckersColorB color = self.playerColors[3] elif self.playerNum == 5: message = TTLocalizer.ChineseCheckersColorPink color = self.playerColors[4] elif self.playerNum == 6: message = TTLocalizer.ChineseCheckersColorR color = self.playerColors[5] else: message = TTLocalizer.ChineseCheckersColorO color = Vec4(0.0, 0.0, 0.0, 1.0) defaultPos = (-.80, -0.40) self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.10, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): self.startButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.1), scale=0.15, command=lambda self=self: self.startButtonPushed(), ) return def enableLeaveButton(self): self.leaveButton = DirectButton( relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.4), scale=0.15, command=lambda self=self: self.exitButtonPushed(), ) return def enableTurnScreenText(self, player): self.yourTurnBlinker.finish() playerOrder = [1, 4, 2, 5, 3, 6] message1 = TTLocalizer.ChineseCheckersIts if (self.turnText != None): self.turnText.destroy() #print "player ---",player #print "playerNum --" ,self.playerNum if player == self.playerNum: message2 = TTLocalizer.ChineseCheckersYourTurn color = (0, 0, 0, 1) else: if player == 1: message2 = TTLocalizer.ChineseCheckersGreenTurn color = self.playerColors[0] elif player == 2: message2 = TTLocalizer.ChineseCheckersYellowTurn color = self.playerColors[1] elif player == 3: message2 = TTLocalizer.ChineseCheckersPurpleTurn color = self.playerColors[2] elif player == 4: message2 = TTLocalizer.ChineseCheckersBlueTurn color = self.playerColors[3] elif player == 5: message2 = TTLocalizer.ChineseCheckersPinkTurn color = self.playerColors[4] elif player == 6: message2 = TTLocalizer.ChineseCheckersRedTurn color = self.playerColors[5] self.turnText = OnscreenText(text=message1 + message2, pos=(-0.80, -0.50), scale=0.092, fg=color, align=TextNode.ACenter, mayChange=1) if player == self.playerNum: self.yourTurnBlinker = Sequence() self.yourTurnBlinker.append( LerpScaleInterval(self.turnText, .6, 1.045, 1)) self.yourTurnBlinker.append( LerpScaleInterval(self.turnText, .6, 1, 1.045)) self.yourTurnBlinker.loop() #This function is called either if the player clicks on it (to begin a game) #or if the game begin timer runs out. (timer is in sync with server so results should be # + or - ~ 1 second def startButtonPushed(self): self.sendUpdate("requestBegin") self.startButton.hide() self.clockNode.stop() self.clockNode.hide() def exitButtonPushed(self): self.fsm.request('gameOver') self.table.fsm.request('off') self.clockNode.stop() self.clockNode.hide() self.table.sendUpdate("requestExit") ########## #Mouse Picking/clicking operations # # #These functions handle all of the mous clicking functions #Its best to look through the code for comments for it to make #the most sense. # #The self.blinker that is referenced in these functions, is a cosmetic #colorLerp that gives the player a visual feedback as to what checkers peice #he has (currently) selected. ########## def mouseClick(self): messenger.send('wakeup') if self.isMyTurn == True and self.inGame == True: #cant pick stuff if its not your turn mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) if self.myHandler.getNumEntries() > 0: self.myHandler.sortEntries() #get the closest Object pickedObj = self.myHandler.getEntry(0).getIntoNodePath() #will return the INT for the locator node closest parent pickedObj = pickedObj.getNetTag("GamePeiceLocator") if pickedObj: #make sure something actually was "picked" self.handleClicked(int(pickedObj)) def handleClicked(self, index): #self.inOpposing = False self.sound = Sequence(SoundInterval( self.clickSound)) #You clicked something play the click sound #First Moved Square if self.moveList == []: #check if owned if not index in self.mySquares: return self.moveList.append(index) #put this on the movelist if index in self.opposingPositions: self.isOpposing = True else: self.isOpposing = False #Start blinking the new "active" peice self.blinker = Sequence() self.blinker.append( LerpColorInterval(self.locatorList[index], .7, self.playerColor - self.tintConstant, self.playerColor)) self.blinker.append( LerpColorInterval(self.locatorList[index], .7, self.playerColor, self.playerColor - self.tintConstant)) self.blinker.loop() self.sound.start() else: #Check if the square clicked is not open, if so break out not legal #If the Player Clicks on one of his peices after an array of clicking new peices #will reset his "move" and start a new movelist if self.board.squareList[index].getState() == self.playerNum: for x in self.moveList: #clear the already selected Nodes back to white self.locatorList[x].setColor(1, 1, 1, 1) self.locatorList[x].hide() #Blinker is the color lerp for the peice "flashing" - need to stop the flashing of the old one self.blinker.finish() self.blinker = Sequence() self.blinker.append( LerpColorInterval(self.locatorList[index], .7, self.playerColor - self.tintConstant, self.playerColor)) self.blinker.append( LerpColorInterval(self.locatorList[index], .7, self.playerColor, self.playerColor - self.tintConstant)) self.blinker.loop() self.sound.start() #Swap back to the original peice #set the original node back to playercolor self.locatorList[self.moveList[0]].setColor(self.playerColor) self.locatorList[self.moveList[0]].show() self.moveList = [] self.moveList.append(index) if index in self.opposingPositions: self.isOpposing = True else: self.isOpposing = False elif self.board.squareList[index].getState() != 0: return #do nothing because he clicked someone elses peice else: #Check for Explicit adjacent move if len(self.moveList ) == 1 and self.board.squareList[index].getState() == 0: #print "I AM OUTSIDE" if index in self.board.squareList[ self.moveList[0]].getAdjacent(): #print "I AM INSIDE" for x in self.nonOpposingPositions: if index in x: return #You cannot end a move in a non opposing players square self.moveList.append(index) self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.sound.start() #Check for mid series jumps stoppage #print len(self.moveList), len(self.moveList)-1 if len(self.moveList) >= 1: if index == self.moveList[ len(self.moveList) - 1]: #you clicked the same thing TWICE for x in self.nonOpposingPositions: if index in x: return #Will force you to jump out ... if self.existsLegalJumpsFrom(index) == True: self.blinker.finish() #self.locatorList[index].setColor(self.playerColor - self.tintConstant) #self.locatorList[index].show() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.sound.start() #Check for Normal jump #Also check if its a 'finishing jump' #Therefore no jumps possible after it ###print "CHECK LEGAL JUMP!", self.checkLegalMove(self.board.getSquare(self.moveList[len(self.moveList)-1]), self.board.getSquare(index)) == True elif self.checkLegalMove( self.board.getSquare( self.moveList[len(self.moveList) - 1]), self.board.getSquare(index)) == True: #this is the part that adds moves to a series of jumps ## #This if statement is an Explicit check to make sure that #the clicked peice, after a series of jumps #is not in the middle jump adjacent, This results in a #bug due to the way ive detected "legal moves" #but this explicit check should fix that. if not index in self.board.squareList[self.moveList[ len(self.moveList) - 1]].getAdjacent(): for x in self.nonOpposingPositions: #print " LEGAL JUMPS FROM! ", self.existsLegalJumpsFrom(index) if self.existsLegalJumpsFrom(index) == False: if index in x: return #He tried to JUMP into non opposing players startPos => Illegal self.moveList.append(index) #ghostConstant here is a small alpha offset to give it a transparent look #tintConstant makes the peice a bit darker (necessary when ghosting) self.locatorList[index].setColor( self.playerColor - self.tintConstant - self.ghostConstant) self.locatorList[index].show() self.sound.start() if self.existsLegalJumpsFrom(index) == False: self.blinker.finish() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False ################################################################## # Legal Move Request/Checker # (COPY PASTED FROM AI) # (Logic here reflects the (NEXT) move not a series of moves, but still #Checks the validity of two different move peices # #This is probably the most complicated as well as most important part #of the chinese checkers code. To completely understand the CheckLegalMoves, #get out a peice of paper and try to DRAW out what the logic is doing, ill do #my best to explain it. # # #Players request moves as a list of Uint8s (already should be verified on the client side) #but since players are cheating bastards, we check on the server. Basically, how the logic works #is it takes pairs one at a time and checks for a legal move between the two, ect and traverses the #list. # #A move is Legal if (it is adjacent to its last move) - in a checkerboard adjacent is stored in a list #of 6 integers representing the other squares (see ChineseCheckerBoard.py) # #board.squareList[x].getAdjacent() visually looks like this # 1 2 # 0 x 3 where those values [ ] are integers to adjacent squares. # 5 4 # # If a adjacent square does not exist on the board, say the first square only has two adjacent, # the squares in the adjacent list are set to None # #A move is also legal if there exists a legal Jump from A to B. the logic here is difficult to #express without a picture, but for instance, say A is jumping to B # # 1 2 1 2 # 0 A 3 B 3 # 5 4 5 6 # # You check all of A's adjacents, and check the index of that \ # particular one (of A's adjacents) that it sits in A, #if that is equal to B, there is a legal jump, if no one is found the move is illegal. # # EX. board.squareList[A].adjacent[3] == (some number to the left of b) # board.squareList[that number].getAdjacent[self.board.squareList[A].index(some number) # # in this case it equals B (draw it out, Trust me it helps) #### def existsLegalJumpsFrom(self, index): for x in self.board.squareList[index].getAdjacent(): if x == None: pass elif x in self.moveList: pass elif self.board.getState(x) == 0: pass elif self.board.squareList[x].getAdjacent( )[self.board.squareList[index].getAdjacent().index(x)] == None: pass elif self.board.getState(self.board.squareList[x].getAdjacent( )[self.board.squareList[index].getAdjacent().index( x)]) == 0 and not (self.board.squareList[x].getAdjacent()[ self.board.squareList[index].getAdjacent().index(x)] ) in self.moveList: return True return False def checkLegalMove(self, firstSquare, secondSquare): if secondSquare.getNum() in firstSquare.getAdjacent(): return True else: for x in firstSquare.getAdjacent(): if x == None: pass elif self.board.squareList[x].getState() == 0: pass else: #print " FIRSTSQUARE ADJACENT AND X -- " , firstSquare.getAdjacent(), " X == " , x #print "Xs Adjacent and its Index", self.board.squareList[x].getAdjacent(), " INDEX == " , firstSquare.getAdjacent().index(x) if (self.board.squareList[x].getAdjacent()[ firstSquare.getAdjacent().index(x)] ) == secondSquare.getNum(): return True return False def d_requestMove(self, moveList): self.sendUpdate('requestMove', [moveList]) ########## ##setGameState (required broadcast ram) # #This is the function that handles the moves made after a move is parsed by the AI #and deemed to be valid # #If moveList is the empty List, then the player is asynchronously joining the game, (OBSERVING) #and just wants the board state. # #otherwise there is a series of jumps (or jump) that needs to be parsed and animated, then #consequently setting the board state # #after every setGameState, the client checks to see the current #Status of his peices (checkForWin), if he belives he won, he requests it to the server ######### def setGameState(self, tableState, moveList): if moveList != []: self.animatePeice(tableState, moveList) else: self.updateGameState(tableState) def updateGameState(self, squares): self.board.setStates(squares) self.mySquares = [] messenger.send('wakeup') for x in range(121): self.locatorList[x].clearColor() owner = self.board.squareList[x].getState() if owner == self.playerNum: self.mySquares.append(x) if owner == 0: self.locatorList[x].hide() else: self.locatorList[x].show() if owner == 1: self.locatorList[x].setColor(self.playerColors[0]) elif owner == 2: self.locatorList[x].setColor(self.playerColors[1]) elif owner == 3: self.locatorList[x].setColor(self.playerColors[2]) elif owner == 4: self.locatorList[x].setColor(self.playerColors[3]) elif owner == 5: self.locatorList[x].setColor(self.playerColors[4]) elif owner == 6: self.locatorList[x].setColor(self.playerColors[5]) self.mySquares.sort() self.checkForWin() def animatePeice(self, tableState, moveList): messenger.send('wakeup') gamePeiceForAnimation = loader.loadModel( "phase_6/models/golf/checker_marble.bam") gamePeiceForAnimation.setColor( self.locatorList[moveList[0]].getColor()) gamePeiceForAnimation.reparentTo(self.boardNode) gamePeiceForAnimation.setPos(self.locatorList[moveList[0]].getPos()) self.locatorList[moveList[0]].hide() checkersPeiceTrack = Sequence() length = len(moveList) for x in range(length - 1): checkersPeiceTrack.append( Parallel( SoundInterval(self.moveSound), ProjectileInterval( gamePeiceForAnimation, endPos=self.locatorList[moveList[x + 1]].getPos(), duration=.5))) checkersPeiceTrack.append(Func(gamePeiceForAnimation.removeNode)) checkersPeiceTrack.append(Func(self.updateGameState, tableState)) checkersPeiceTrack.start() def checkForWin(self): if self.playerNum == 1: if (self.mySquares == self.startingPositions[3]): self.sendUpdate('requestWin', []) elif self.playerNum == 2: if (self.mySquares == self.startingPositions[4]): self.sendUpdate('requestWin', []) elif self.playerNum == 3: if (self.mySquares == self.startingPositions[5]): self.sendUpdate('requestWin', []) elif self.playerNum == 4: if (self.mySquares == self.startingPositions[0]): self.sendUpdate('requestWin', []) elif self.playerNum == 5: if (self.mySquares == self.startingPositions[1]): self.sendUpdate('requestWin', []) elif self.playerNum == 6: if (self.mySquares == self.startingPositions[2]): self.sendUpdate('requestWin', []) def announceWin(self, avId): self.fsm.request('gameOver') ########### ##doRandomMove # #If a clients move Timer runs out, it will calculate a random move for him #after 3 random moves, it kicks the client out of the game by pushing the #"get up" button for him. ########### def doRandomMove(self): if len(self.moveList) >= 2: self.blinker.finish() #self.locatorList[index].setColor(self.playerColor - self.tintConstant) #self.locatorList[index].show() self.d_requestMove(self.moveList) self.moveList = [] self.isMyTurn = False self.playSound = Sequence(SoundInterval(self.knockSound)) self.playSound.start() else: import random move = [] foundLegal = False self.blinker.pause() self.numRandomMoves += 1 ###self.blinker.finish() while not foundLegal: x = random.randint(0, 9) for y in self.board.getAdjacent(self.mySquares[x]): if y != None and self.board.getState(y) == 0: for zz in self.nonOpposingPositions: if not y in zz: move.append(self.mySquares[x]) move.append(y) foundLegal = True break break if move == []: pass #current flaw in the logic, but shouldnt really ever happen #though on live it might #print "random move is empty" playSound = Sequence(SoundInterval(self.knockSound)) playSound.start() self.d_requestMove(move) self.moveList = [] self.isMyTurn = False if (self.numRandomMoves >= 5): self.exitButtonPushed() def doNothing(self): pass
class DistributedPicnicBasket(DistributedObject.DistributedObject): seatState = Enum("Empty, Full, Eating") notify = DirectNotifyGlobal.directNotify.newCategory( "DistributedPicnicBasket") def __init__(self, cr): """__init__(cr) """ DistributedObject.DistributedObject.__init__(self, cr) self.localToonOnBoard = 0 self.seed = 0 self.random = None self.picnicCountdownTime = \ ConfigVariableDouble("picnic-countdown-time", ToontownGlobals.PICNIC_COUNTDOWN_TIME).getValue() self.picnicBasketTrack = None # only one track contains the picnic basket shrink/grow self.fsm = ClassicFSM.ClassicFSM( 'DistributedTrolley', [ State.State('off', self.enterOff, self.exitOff, ['waitEmpty', 'waitCountdown']), State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, ['waitCountdown']), State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, ['waitEmpty']) ], # Initial State 'off', # Final State 'off', ) self.fsm.enterInitialState() # Tracks on toons, for starting and stopping # stored by avId : track. There is only a need for one at a time, # in fact the point of the dict is to ensure only one is playing at a time self.__toonTracks = {} def generate(self): """generate(self) This method is called when the DistributedObject is reintroduced to the world, either for the first time or from the cache. """ DistributedObject.DistributedObject.generate(self) # Get the state machine stuff for playGame self.loader = self.cr.playGame.hood.loader self.foodLoader = [ 'phase_6/models/golf/picnic_sandwich.bam', 'phase_6/models/golf/picnic_apple.bam', 'phase_6/models/golf/picnic_cupcake.bam', 'phase_6/models/golf/picnic_chocolate_cake.bam' ] self.fullSeat = [] self.food = [] for i in range(4): self.food.append(None) self.fullSeat.append(self.seatState.Empty) self.picnicItem = 0 def announceGenerate(self): """Setup other fields dependent on the required fields.""" self.picnicTable = self.loader.geom.find("**/*picnic_table_" + str(self.tableNumber)) self.picnicTableSphereNodes = [] self.numSeats = 4 self.seats = [] self.jumpOffsets = [] self.basket = None for i in range(self.numSeats): self.seats.append(self.picnicTable.find("**/*seat%d" % (i + 1))) self.jumpOffsets.append( self.picnicTable.find("**/*jumpOut%d" % (i + 1))) #debugAxis = loader.loadModel('models/misc/xyzAxis') #debugAxis.setColorScale(1.0, 1.0, 1.0, 0.25) #debugAxis.setTransparency(True) #debugAxis.reparentTo(self.seats[i]) self.tablecloth = self.picnicTable.find("**/basket_locator") DistributedObject.DistributedObject.announceGenerate(self) for i in range(self.numSeats): self.picnicTableSphereNodes.append(self.seats[i].attachNewNode( CollisionNode('picnicTable_sphere_%d_%d' % (self.getDoId(), i)))) self.picnicTableSphereNodes[i].node().addSolid( CollisionSphere(0, 0, 0, 2)) self.tableclothSphereNode = self.tablecloth.attachNewNode( CollisionNode('tablecloth_sphere')) self.tableclothSphereNode.node().addSolid(CollisionSphere(0, 0, -1, 4)) angle = self.startingHpr[0] angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 30.0 self.endPos = self.startingPos + unitVec dist = Vec3(self.endPos - self.enteringPos).length() wheelAngle = dist / (0.5 * 1.4 * math.pi) * 360 self.seatNumber = 0 self.clockNode = ToontownTimer() self.clockNode.reparentTo(base.a2dBottomRight) self.clockNode.setPos(-0.173, 0, 0.17) self.clockNode.setScale(0.3) self.clockNode.hide() def disable(self): DistributedObject.DistributedObject.disable(self) # Go to the off state when the object is put in the cache self.fsm.request("off") # No more toon animating self.clearToonTracks() for i in range(self.numSeats): del self.picnicTableSphereNodes[0] del self.picnicTableSphereNodes self.notify.debug("Deleted self loader " + str(self.getDoId())) self.picnicTable.removeNode() self.picnicBasketTrack = None #self.kart.removeNode() #del self.kart #import pdb; #pdb.set_trace() def delete(self): self.notify.debug("Golf kart getting deleted: %s" % self.getDoId()) DistributedObject.DistributedObject.delete(self) del self.fsm def setState(self, state, seed, timestamp): self.seed = seed if not self.random: self.random = RandomNumGen.RandomNumGen(seed) self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def handleEnterPicnicTableSphere(self, i, collEntry): # collEntry): assert self.notify.debugStateCall(self) self.seatNumber = i self.notify.debug("Entering Picnic Table Sphere.... %s" % self.getDoId()) # Put localToon into requestBoard mode. #import pdb; pdb.set_trace() self.loader.place.detectedPicnicTableSphereCollision(self) def handleEnterPicnicTable(self, i): # Tell the server that this avatar wants to board. assert self.notify.debugStateCall(self) toon = base.localAvatar self.sendUpdate("requestBoard", [i]) def fillSlot0(self, avId): self.fillSlot(0, avId) def fillSlot1(self, avId): self.fillSlot(1, avId) def fillSlot2(self, avId): self.fillSlot(2, avId) def fillSlot3(self, avId): self.fillSlot(3, avId) def fillSlot(self, index, avId): assert self.notify.debugStateCall(self) self.notify.debug("fill Slot: %d for %d" % (index, avId)) if avId == 0: # This means that the slot is now empty, and no action should # be taken. pass else: self.fullSeat[index] = self.seatState.Full # If localToon is boarding, he needs to change state if avId == base.localAvatar.getDoId(): # Start the countdown clock... self.clockNode.show() if index == 0 or index == 3: side = -1 else: side = 1 if hasattr(self.loader.place, "trolley"): self.loader.place.trolley.fsm.request( "boarding", [self.tablecloth, side]) else: self.notify.warning('fillSlot no trolley in place') self.localToonOnBoard = 1 # Put that toon on the table # If it's localToon, tell him he's on the trolley now if avId == base.localAvatar.getDoId(): if hasattr(self.loader.place, "trolley"): self.loader.place.trolley.fsm.request("boarded") # hide the exit button until basket interval is over self.loader.place.trolley.exitButton.hide() if avId in self.cr.doId2do: # If the toon exists, look it up toon = self.cr.doId2do[avId] # Parent it to the trolley toon.stopSmooth() toon.wrtReparentTo(self.tablecloth) sitStartDuration = toon.getDuration("sit-start") jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence(jumpTrack, Func(toon.setAnimState, "Sit", 1.0)) # only add basket appear if there is no toons are already sitting self.notify.debug("### fillSlot: fullSeat = %s" % self.fullSeat) if self.fullSeat.count(0) == 3: self.notify.debug("### fillSlot: adding basketAppear") #track.append(self.generateBasketAppearTrack()) if self.picnicBasketTrack: self.picnicBasketTrack.finish() waitDuration = track.getDuration() self.picnicBasketTrack = Sequence( Wait(waitDuration), self.generateBasketAppearTrack()) self.picnicBasketTrack.start() # make a random food appear track.append(self.generateFoodAppearTrack(index)) # finish the rest of the staging track.append( Sequence(Func(self.clearToonTrack, avId), name=toon.uniqueName("fillTrolley"), autoPause=1)) if avId == base.localAvatar.getDoId(): if hasattr(self.loader.place, "trolley"): track.append( Func(self.loader.place.trolley.exitButton.show)) track.delayDelete = DelayDelete.DelayDelete( toon, 'PicnicBasket.fillSlot') self.storeToonTrack(avId, track) track.start() def emptySlot0(self, avId, timestamp): self.emptySlot(0, avId, timestamp) def emptySlot1(self, avId, timestamp): self.emptySlot(1, avId, timestamp) def emptySlot2(self, avId, timestamp): self.emptySlot(2, avId, timestamp) def emptySlot3(self, avId, timestamp): self.emptySlot(3, avId, timestamp) def notifyToonOffTrolley(self, toon): toon.setAnimState("neutral", 1.0) if hasattr(base, 'localAvatar') and toon == base.localAvatar: if hasattr(self.loader.place, "trolley"): self.loader.place.trolley.handleOffTrolley() self.localToonOnBoard = 0 else: toon.startSmooth() return def emptySlot(self, index, avId, timestamp): def emptySeat(index): # If localToon is exiting, he needs to change state self.notify.debug("### seat %s now empty" % index) self.fullSeat[index] = self.seatState.Empty if avId == 0: # This means that the slot is now empty, and no action should # be taken. pass elif avId == 1: # Special cardinal value for unexpected exit. # The toon is gone, but we may still need to clean up his food self.fullSeat[index] = self.seatState.Empty track = Sequence(self.generateFoodDisappearTrack(index)) # if no toons left, make the basket go away self.notify.debug("### empty slot - unexpetected: fullSeat = %s" % self.fullSeat) if self.fullSeat.count(0) == 4: self.notify.debug("### empty slot - unexpected: losing basket") if self.picnicBasketTrack: self.picnicBasketTrack.finish() #track.append(self.generateBasketDisappearTrack()) waitDuration = track.getDuration() self.picnicBasketTrack = Sequence( Wait(waitDuration), self.generateBasketDisappearTrack()) self.picnicBasketTrack.start() track.start() else: self.fullSeat[index] = self.seatState.Empty if avId in self.cr.doId2do: if avId == base.localAvatar.getDoId(): # Stop the countdown clock.. if (self.clockNode): self.clockNode.hide() # If the toon exists, look it up toon = self.cr.doId2do[avId] toon.stopSmooth() sitStartDuration = toon.getDuration("sit-start") jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) track = Sequence(jumpOutTrack) # make the food go away track.append(self.generateFoodDisappearTrack(index)) # if no toons left, make the basket go away self.notify.debug("### empty slot: fullSeat = %s" % self.fullSeat) if self.fullSeat.count(0) == 4: self.notify.debug("### empty slot: losing basket") if self.picnicBasketTrack: self.picnicBasketTrack.finish() #track.append(self.generateBasketDisappearTrack()) waitDuration = track.getDuration() self.picnicBasketTrack = Sequence( Wait(waitDuration), self.generateBasketDisappearTrack()) self.picnicBasketTrack.start() # let the toon loose track.append( Sequence( # Tell the toon he is free to roam now Func(self.notifyToonOffTrolley, toon), Func(self.clearToonTrack, avId), Func(self.doneExit, avId), Func(emptySeat, index), name=toon.uniqueName("emptyTrolley"), autoPause=1)) track.delayDelete = DelayDelete.DelayDelete( toon, 'PicnicBasket.emptySlot') self.storeToonTrack(avId, track) track.start() def rejectBoard(self, avId): # This should only be sent to us if our localToon requested # permission to board the trolley. assert (base.localAvatar.getDoId() == avId) self.loader.place.trolley.handleRejectBoard() def __enableCollisions(self): # start listening for toons to enter. assert self.notify.debugStateCall(self) for i in range(self.numSeats): self.accept('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTableSphere, [i]) self.accept('enterPicnicTableOK_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTable, [i]) self.picnicTableSphereNodes[i].setCollideMask( ToontownGlobals.WallBitmask) def __disableCollisions(self): assert self.notify.debugStateCall(self) for i in range(self.numSeats): self.ignore('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i)) self.ignore('enterPicnicTableOK_%d_%d' % (self.getDoId(), i)) for i in range(self.numSeats): self.picnicTableSphereNodes[i].setCollideMask(BitMask32(0)) ##### Off state ##### def enterOff(self): return None def exitOff(self): return None ##### WaitEmpty state ##### def enterWaitEmpty(self, ts): # Toons may now try to board the trolley self.__enableCollisions() def exitWaitEmpty(self): # Toons may not attempt to board the trolley if it isn't waiting self.__disableCollisions() ##### WaitCountdown state ##### def enterWaitCountdown(self, ts): # Toons may now try to board the trolley self.__enableCollisions() self.accept("trolleyExitButton", self.handleExitButton) #self.clockNode.countdown(self.picnicCountdownTime - ts, self.handleExitButton) self.clockNode.countdown(self.picnicCountdownTime, self.handleExitButton) def handleExitButton(self): # This gets called when the exit button gets pushed. self.sendUpdate("requestExit") self.clockNode.hide() #import pdb; pdb.set_trace() def exitWaitCountdown(self): # Toons may not attempt to board the trolley if it isn't waiting self.__disableCollisions() self.ignore("trolleyExitButton") self.clockNode.reset() def getStareAtNodeAndOffset(self): return self.tablecloth, Point3(0, 0, 4) def storeToonTrack(self, avId, track): # Clear out any currently playing tracks on this toon self.clearToonTrack(avId) # Store this new one self.__toonTracks[avId] = track def clearToonTrack(self, avId): # Clear out any currently playing tracks on this toon oldTrack = self.__toonTracks.get(avId) if oldTrack: oldTrack.pause() DelayDelete.cleanupDelayDeletes(oldTrack) del self.__toonTracks[avId] def clearToonTracks(self): #We can't use an iter because we are deleting keys keyList = [] for key in self.__toonTracks: keyList.append(key) for key in keyList: if key in self.__toonTracks: self.clearToonTrack(key) def doneExit(self, avId): if (avId == base.localAvatar.getDoId()): self.sendUpdate("doneExit") def setPosHpr(self, x, y, z, h, p, r): """Set the pos hpr as dictated by the AI.""" self.startingPos = Vec3(x, y, z) self.enteringPos = Vec3(x, y, z - 10) self.startingHpr = Vec3(h, 0, 0) #self.golfKart.setPosHpr( x, y, z, h, 0, 0 ) def setTableNumber(self, tn): self.tableNumber = tn def generateToonJumpTrack(self, av, seatIndex): """Return an interval of the toon jumping into the golf kart.""" # Maintain a reference to Parent and Scale of avatar in case they # exit from the kart. #base.sb = self av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack(av, seatIndex): # using a local func allows the ProjectileInterval to # calculate this pos at run-time def getJumpDest(av=av, node=self.tablecloth): dest = Vec3(self.tablecloth.getPos(av.getParent())) seatNode = self.picnicTable.find("**/seat" + str(seatIndex + 1)) dest += seatNode.getPos(self.tablecloth) dna = av.getStyle() dest -= hipOffset if (seatIndex == 2 or seatIndex == 3): dest.setY(dest.getY() + 2 * hipOffset.getY()) dest.setZ(dest.getZ() + 0.2) return dest def getJumpHpr(av=av, node=self.tablecloth): hpr = self.seats[seatIndex].getHpr(av.getParent()) #if(seatIndex < 2): #hpr.setX( hpr.getX() + 180) #else: # hpr.setX( hpr.getX() ) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.43), Parallel( LerpHprInterval(av, hpr=getJumpHpr, duration=.9), ProjectileInterval(av, endPos=getJumpDest, duration=.9)), )) return toonJumpTrack def getToonSitTrack(av): toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit')) return toonSitTrack toonJumpTrack = getToonJumpTrack(av, seatIndex) toonSitTrack = getToonSitTrack(av) jumpTrack = Sequence( Parallel( toonJumpTrack, Sequence( Wait(1), toonSitTrack, ), ), Func(av.wrtReparentTo, self.tablecloth), ) return jumpTrack def generateToonReverseJumpTrack(self, av, seatIndex): """Return an interval of the toon jumping out of the golf kart.""" self.notify.debug("av.getH() = %s" % av.getH()) def getToonJumpTrack(av, destNode): # using a local func allows the ProjectileInterval to # calculate this pos at run-time def getJumpDest(av=av, node=destNode): dest = node.getPos(self.tablecloth) dest += self.jumpOffsets[seatIndex].getPos(self.tablecloth) return dest def getJumpHpr(av=av, node=destNode): hpr = node.getHpr(av.getParent()) hpr.setX(hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.1), #43 ), Parallel( #LerpHprInterval( av, # hpr = getJumpHpr, # duration = .9 ), ProjectileInterval(av, endPos=getJumpDest, duration=.9)))) return toonJumpTrack toonJumpTrack = getToonJumpTrack(av, self.tablecloth) #self.seats[seatIndex]) jumpTrack = Sequence( toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render), #Func( self.av.setPosHpr, self.exitMovieNode, 0,0,0,0,0,0 ), ) return jumpTrack def generateBasketAppearTrack(self): """ """ if (self.basket == None): self.basket = loader.loadModel( 'phase_6/models/golf/picnic_basket.bam') self.basket.setScale(0.1) basketTrack = Sequence( Func(self.basket.show), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node=self.basket), Func(self.basket.reparentTo, self.tablecloth), Func(self.basket.setPos, 0, 0, .2), Func(self.basket.setHpr, 45, 0, 0), Func(self.basket.wrtReparentTo, render), Func(self.basket.setShear, 0, 0, 0), #Func( self.basket.setActiveShadow, True ), # Must be a cleaner way to do this. Sequence( LerpScaleInterval(self.basket, scale=Point3(1.1, 1.1, .1), duration=0.2), LerpScaleInterval(self.basket, scale=Point3(1.6, 1.6, 0.2), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1., 1., 0.4), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1.5, 1.5, 2.5), duration=0.2), LerpScaleInterval(self.basket, scale=Point3(2.5, 2.5, 1.5), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(2., 2., 2.), duration=0.1), Func(self.basket.wrtReparentTo, self.tablecloth), Func(self.basket.setPos, 0, 0, 0)), ) return basketTrack def generateBasketDisappearTrack(self): if not self.basket: return Sequence() pos = self.basket.getPos() pos.addZ(-1) basketTrack = Sequence( LerpScaleInterval(self.basket, scale=Point3(2., 2., 1.8), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1., 1., 2.5), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(2., 2., 0.5), duration=0.2), LerpScaleInterval(self.basket, scale=Point3(0.5, 0.5, 1.0), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(1.1, 1.1, .1), duration=0.1), LerpScaleInterval(self.basket, scale=Point3(.1, .1, .1), duration=0.2), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node=self.basket), Wait(0.2), LerpPosInterval(self.basket, pos=pos, duration=0.2), Func(self.basket.hide), ) return basketTrack def generateFoodAppearTrack(self, seat): """ """ if (self.fullSeat[seat] == self.seatState.Full): self.notify.debug("### food appear: self.fullSeat = %s" % self.fullSeat) if not self.food[seat]: self.food[seat] = loader.loadModel( self.random.choice(self.foodLoader)) self.notify.debug("### food appear: self.food = %s" % self.food) self.food[seat].setScale(0.1) self.food[seat].reparentTo(self.tablecloth) self.food[seat].setPos( self.seats[seat].getPos(self.tablecloth)[0] / 2, self.seats[seat].getPos(self.tablecloth)[1] / 2, 0) # Func( self.food[seat].setActiveShadow, False ), foodTrack = Sequence( Func(self.food[seat].show), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node=self.food[seat]), Func(self.food[seat].reparentTo, self.tablecloth), Func(self.food[seat].setHpr, 45, 0, 0), Func(self.food[seat].wrtReparentTo, render), Func(self.food[seat].setShear, 0, 0, 0), #Func( self.food[seat].setActiveShadow, True ), # Must be a cleaner way to do this. Sequence( LerpScaleInterval(self.food[seat], scale=Point3(1.1, 1.1, .1), duration=0.2), LerpScaleInterval(self.food[seat], scale=Point3(1.6, 1.6, 0.2), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1., 1., 0.4), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1.5, 1.5, 2.5), duration=0.2), LerpScaleInterval(self.food[seat], scale=Point3(2.5, 2.5, 1.5), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(2., 2., 2.), duration=0.1), Func(self.food[seat].wrtReparentTo, self.tablecloth)), ) return foodTrack else: return Sequence() def generateFoodDisappearTrack(self, seat): if not self.food[seat]: return Sequence() pos = self.food[seat].getPos() pos.addZ(-1.) foodTrack = Sequence( LerpScaleInterval(self.food[seat], scale=Point3(2., 2., 1.8), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1., 1., 2.5), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(2., 2., 0.5), duration=0.2), LerpScaleInterval(self.food[seat], scale=Point3(0.5, 0.5, 1.0), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(1.1, 1.1, .1), duration=0.1), LerpScaleInterval(self.food[seat], scale=Point3(.1, .1, .1), duration=0.2), SoundInterval( globalBattleSoundCache.getSound('GUI_balloon_popup.mp3'), node=self.food[seat]), Wait(0.2), LerpPosInterval(self.food[seat], pos=pos, duration=0.2), Func(self.food[seat].hide), ) return foodTrack def destroy(self, node): node.removeNode() node = None self.basket.removeNode() self.basket = None for food in self.food: food.removeNode() self.food = None self.clockNode.removeNode() del self.clockNode self.clockNode = None def setPicnicDone(self): if self.localToonOnBoard: if hasattr(self.loader.place, "trolley"): self.loader.place.trolley.fsm.request("final") self.loader.place.trolley.fsm.request("start") self.localToonOnBoard = 0 messenger.send("picnicDone")