class ToonBase:

	def __init__(self, cr, head, headtype, headcolor, torsocolor, legcolor,
				gender, torsotype, legtype, name, shirtcolor, shortscolor, shirt, short, sleeve):
		self.cr = cr
		self.head = head
		self.headtype = headtype
		self.hr, self.hg, self.hb, self.ha = headcolor
		self.tr, self.tg, self.tb, self.ta = torsocolor
		self.lr, self.lg, self.lb, self.la = legcolor
		self.shir, self.shig, self.shib, self.shia = shirtcolor
		self.shor, self.shog, self.shob, self.shoa = shortscolor
		self.shirt = shirt
		self.short = short
		self.sleeve = sleeve
		self.gender = gender
		self.torsotype = torsotype
		self.legtype = legtype
		self.name = name
		
		base.avatar = None
		self.sb = ShtickerBook(self)
		
		self.laffMeter = LaffOMeter()
		
		self.run_sfx = loader.loadSfx("phase_3.5/audio/sfx/AV_footstep_runloop.ogg")
		self.run_sfx.setLoop(True)
		self.walk_sfx = loader.loadSfx("phase_3.5/audio/sfx/AV_footstep_walkloop.ogg")
		self.walk_sfx.setLoop(True)
		
		self.hoodUtil = HoodUtil(self.cr)
		
		self.smart_cam = SmartCamera.SmartCamera()
		
		self.isThrowing = False
		
		self.controlManager = ControlManager.ControlManager(True, False)
		
		self.offset = 3.2375
		
		self.keyMap = {"forward":0,"backward":0, "left":0, "right":0, "jump":0}
		
		base.cTrav = CollisionTraverser('general_traverser')
		self.dFov = CIGlobals.DefaultCameraFov
		self.oFov = CIGlobals.OriginalCameraFov
		
		self.createReady()
			
	def createReady(self):
		base.avatar = self.cr.createDistributedObject(className="DistributedToon", zoneId=5)
		base.avatar.b_setToon(self.gender, self.headtype, self.head, self.legtype, self.torsotype, self.hr, self.hg, self.hb, self.tr, self.tg,
						self.tb, self.lr, self.lg, self.lb, self.shir, self.shig, self.shib, self.shor,	self.shog, self.shob, self.shirt,
						self.short, self.sleeve)
		#base.avatar.initializeLocalSensor(2, 3, "localAvatar")
		base.avatar.initCollisions()
		#base.avatar.startBlink()
		base.avatar.startLookAround()
		base.avatar.startPosHprBroadcast()
		base.avatar.setMoney(20)
		base.accept("loadedHood", self.enterTeleportIn)
		base.accept("gotLookSpot", self.handleLookSpot)
		#base.accept("alt-1", self.enterFirstPerson)
		#base.accept("alt-2", self.exitFirstPerson)
		self.sendSuitInfoRequest()
		self.sendBossInfoRequest()
		self.setAvatarName(self.name)
		taskMgr.add(self.checkHealth, "checkHealth")
		self.smart_cam.set_default_pos(0.0, math.sqrt(base.avatar.getPart('head').getZ(base.avatar)) / Y_FACTOR, 
									base.avatar.getPart('head').getZ(base.avatar) + 0.3)
		self.smart_cam.set_parent(base.avatar)
		self.smart_cam.initialize_smartcamera()
		self.smart_cam.initialize_smartcamera_collisions()
		self.initMovement()
		self.pieGui = PieGui.PieGui(base.avatar.pies)
		self.pieGui.createGui()
		self.pieGui.enableWeaponSwitch()
		self.moneyGui = MoneyGui.MoneyGui()
		self.moneyGui.createGui()
		self.moneyGui.update()
		self.gagShop = GagShop.GagShop()
		self.changeHood(10, base.avatar.zoneId)
		base.camLens.setMinFov(self.dFov/(4./3.))
		base.accept("SuitsActive", self.handleSuitsActive)
		base.accept("SuitsInactive", self.handleSuitsInactive)
		base.accept("fullTrolley", self.handleFullTrolley)
		base.accept("openTrolley", self.handleOpenTrolley)
		base.accept("tookDamage", self.handleTookDamage)
		base.accept("enterGagShop", self.enterGagShop)
		base.accept("exitGagShop", self.exitGagShop)
		base.accept("moneyChanged", self.moneyGui.update)
		base.accept("ammoChanged", self.pieGui.update)
		base.accept("collectedMoney", self.handleMoneyCollected)
		base.accept("restartGame", self.exitGame)
		base.accept("bossSpawned", self.handleBossSpawned)
		base.accept("lostConnection", self.delete)
		base.accept("MinigameStationSlotOpen", self.handleMinigameStationSlotOpen)
		base.accept("MinigameStationHeadOff", self.handleMinigameStationHeadOff)
		self.createGui()
		
	def enterFirstPerson(self):
		base.avatar.toon_head.hide()
		base.camLens.setMinFov(70.0 / (4./3.))
		base.avatar.deleteShadow()
		self.smart_cam.enterFirstPerson()
		
	def exitFirstPerson(self):
		base.avatar.toon_head.show()
		base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4./3.))
		base.avatar.initShadow(base.avatar.avatarType)
		self.smart_cam.exitFirstPerson()
		
	def delete(self):
		self.cr.getCurrentHood().unloadHood()
		self.pieGui.deleteGui()
		self.moneyGui.deleteGui()
		self.smart_cam.stop_smartcamera()
		self.chatInput.delete()
		self.disableMovement()
		base.avatar.stopLookAround()
		base.avatar.stopBlink()
		base.avatar.sendDeleteMsg()
		self.deleteLaffMeter()
		self.book_btn.destroy()
		self.book_gui.removeNode()
		base.ignore("exitGagShop")
		base.ignore("moneyChanged")
		base.ignore("ammoChanged")
		base.ignore("collectedMoney")
		base.ignore("restartGame")
		base.ignore("SuitsActive")
		base.ignore("SuitsInactive")
		base.ignore("fullTrolley")
		base.ignore("openTrolley")
		base.ignore("tookDamage")
		base.ignore("enterGagShop")
		base.ignore("loadedHood")
		base.ignore("gotLookSpot")
		base.ignore("bossSpawned")
		base.ignore("lostConnection")
		#base.ignore("alt-1")
		#base.ignore("alt-2")
		base.ignore("MinigameStationSlotOpen")
		base.ignore("MinigameStationHeadOff")
		taskMgr.remove("checkHealth")
		base.camLens.setMinFov(self.oFov/(4./3.))
		camera.reparentTo(render)
		camera.setPos(0,0,0)
		camera.setHpr(0,0,0)
		del base.avatar
		del self.laffMeter
		del self.pieGui
		del self.sb
		del self.smart_cam
		del self.controlManager
		del self.walkControls
		del self.hoodUtil
		del self.cr
		del self.head
		del self.headtype
		del self.hr, self.hg, self.hb, self.ha
		del self.tr, self.tg, self.tb, self.ta
		del self.lr, self.lg, self.lb, self.la
		del self.gender
		del self.torsotype
		del self.legtype
		del self.shir, self.shig, self.shib
		del self.shor, self.shog, self.shob
		del self.sleeve, self.shirt, self.short
		del self.name
		del self.keyMap
		del self.offset
		if hasattr(self, 'dmg2BeDone'):
			del self.dmg2BeDone
		del self.run_sfx
		del self.walk_sfx
		del self.isThrowing
		del self.book_btn
		del self.book_gui
		del self.chatInput
		return
	
	def handleBossSpawned(self):
		if base.avatar.zoneId == 20:
			self.hoodUtil.centralHood.bossSpawned()
			
	def handleMinigameStationSlotOpen(self, slot, sdoid, adoid):
		if adoid == base.avatar.doId:
			for key in self.cr.doId2do.keys():
				station = self.cr.doId2do[key]
				if station.__class__.__name__ == "DistributedMinigameStation":
					if station.doId == sdoid:
						if slot == 1:
							self.enterMinigameStationSlot(station.circle1, station)
						elif slot == 2:
							self.enterMinigameStationSlot(station.circle2, station)
						elif slot == 3:
							self.enterMinigameStationSlot(station.circle3, station)
					
	def enterMinigameStationSlot(self, circle, station):
		self.disableMovement()
		self.smart_cam.stop_smartcamera()
		camera.reparentTo(station)
		camera.setPos(0, 30.0, 22.5)
		camera.setPos(camera.getPos(render))
		camera.reparentTo(render)
		camera.lookAt(station.sign)
		self.book_btn.hide()
		base.avatar.headsUp(circle)
		base.avatar.b_setAnimState("run")
		runTrack = LerpPosInterval(base.avatar,
								1.0,
								circle.getPos(render),
								startPos=base.avatar.getPos(render))
		runTrack.start()
		Sequence(Wait(1), Func(self.createStationAbortGui), Func(base.avatar.b_setAnimState, "neutral"), Func(base.avatar.headsUp, station.sign)).start()
		
	def createStationAbortGui(self):
		qt_btn = loader.loadModel("phase_3/models/gui/quit_button.bam")
		self.abortBtn = DirectButton(text="Abort", geom=(qt_btn.find('**/QuitBtn_UP'),
											qt_btn.find('**/QuitBtn_DN'),
											qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.055,
											pos=(0, 0, 0.85), command=self.sendStationAbort)
											
	def sendStationAbort(self):
		self.abortBtn.destroy()
		del self.abortBtn
		pkg = PyDatagram()
		pkg.addUint16(STATION_ABORT)
		pkg.addUint32(base.avatar.doId)
		self.cr.send(pkg)
		self.abortStation()
		
	def abortStation(self):
		self.enableMovement()
		self.book_btn.show()
		self.startSmartCam()
		
	def handleMinigameStationHeadOff(self, game, doid, zone):
		if doid == base.avatar.doId:
			self.abortBtn.destroy()
			del self.abortBtn
			self.startSmartCam()
			self.enterTeleportOut(None)
			Sequence(Wait(6.0), Func(self.changeHood, zone, base.avatar.zoneId, place="minigame")).start()
		
	def startSmartCam(self):
		self.smart_cam.initialize_smartcamera()
		self.smart_cam.initialize_smartcamera_collisions()
		self.smart_cam.start_smartcamera()
		
	def resetSmartCam(self):
		self.smart_cam.stop_smartcamera()
		self.startSmartCam()
		
	def enterGagShop(self):
		self.disableMovement()
		self.gagShop.enter()
		
	def exitGagShop(self):
		self.enableMovement()
		pkg = PyDatagram()
		pkg.addUint16(GAG_SHOP_EXIT)
		self.cr.send(pkg)
		
	def handleMoneyCollected(self, money):
		base.avatar.setMoney(base.avatar.getMoney() + money)
		
	def createGui(self):
		if base.config.GetBool('want-chat', True):
			self.chatInput = ChatInput.ChatInput()
			self.chatInput.createGui()
			self.chatInput.enableKeyboardShortcuts()
		self.book_gui = loader.loadModel("phase_3.5/models/gui/sticker_open_close_gui.bam")
		self.book_btn = DirectButton(geom=(self.book_gui.find('**/BookIcon_CLSD'),
											self.book_gui.find('**/BookIcon_OPEN'),
											self.book_gui.find('**/BookIcon_RLVR')), relief=None, pos=(-0.175, 0, 0.163), command=self.startBook, scale=(0.7, 0.8, 0.8), parent=base.a2dBottomRight)
		self.book_btn.hide()
		
	def createLaffMeter(self):
		self.laffMeter.generate(base.avatar.hr, base.avatar.hg, base.avatar.hb, base.avatar.head)
		self.laffMeter.start()
		
	def deleteLaffMeter(self):
		self.laffMeter.destroy()

	def setAvatarName(self, name):
		base.avatar.b_setName(name)
		base.avatar.tag['text_fg'] = CIGlobals.LocalNameTagColor

	def initMovement(self):
		self.walkControls = GravityWalker(legacyLifter=True)
		self.walkControls.setWallBitMask(CIGlobals.WallBitmask)
		self.walkControls.setFloorBitMask(CIGlobals.FloorBitmask)
		self.walkControls.setWalkSpeed(30, 30, 15, 75)
		self.walkControls.initializeCollisions(base.cTrav, base.avatar, floorOffset=0.025, reach=4.0)
		self.walkControls.setAirborneHeightFunc(self.getAirborneHeight)
		camera.reparent_to(base.avatar)
		self.smart_cam.start_smartcamera()

	def getAirborneHeight(self):
		return self.offset + 0.025000000000000001

	def enableMovement(self):
		self.movementEnabled = True
		self.walkControls.enableAvatarControls()
		base.accept("arrow_up", self.setKey, ["forward",1])
		base.accept("arrow_up-up", self.setKey, ["forward",0])
		base.accept("arrow_down", self.setKey, ["backward",1])
		base.accept("arrow_down-up", self.setKey, ["backward",0])
		base.accept("arrow_left", self.setKey, ["left", 1])
		base.accept("arrow_left-up", self.setKey, ["left", 0])
		base.accept("arrow_right", self.setKey, ["right",1])
		base.accept("arrow_right-up", self.setKey, ["right",0])
		base.accept("control", self.setKey, ["jump",1])
		base.accept("control-up", self.setKey, ["jump", 0])
		if base.config.GetBool('want-weapons', True):
			if base.config.GetBool('want-pies', True):
				base.accept("delete", self.startPie)
				base.accept("delete-up", self.throwPie)
		
		base.avatar.b_setAnimState("neutral")
		
		self.isMoving_forward = True
		self.isMoving_side = True
		
		taskMgr.add(self.move, "movetask")
		
	def startPie(self):
		if not base.avatar.pies.getAmmo() <= 0:
			# We need to store the damage amount to be done
			# so the avatar can't switch weapons while
			# the pie is airborne to do more damage without
			# losing the ammo.
			self.dmg2BeDone = base.avatar.pies.getDamage()
			self.isThrowing = True
			self.resetHeadHpr()
			base.avatar.stopLookAround()
			base.avatar.b_pieStart()
			base.avatar.pies.pieCollisions()

	def throwPie(self):
		base.avatar.b_pieThrow()
		self.disableThrow()
		taskMgr.doMethodLater(0.75, self.releasePie, "releasePie")
		taskMgr.doMethodLater(1.05, self.enableThrow, "enablepie")
		
	def disableThrow(self):
		base.ignore("delete")
		base.ignore("delete-up")

	def releasePie(self, task):
		base.avatar.b_pieRelease()
		self.isThrowing = False
		base.acceptOnce("pieSensor-into", self.checkPieCollisions)
		return task.done

	def enableThrow(self, task):
		if base.avatar.isDead():
			return
		base.avatar.startLookAround()
		base.accept("delete", self.startPie)
		base.accept("delete-up", self.throwPie)
		return

	def checkPieCollisions(self, entry):
		"""This method will figure out which CollisionNode the pie hit.
		If the hit CollisionNode is a Suit, then we'll send a datagram of
		the Suit's DoId to all clients. The client will then decide if
		the DoId sent matches its local DoId. If true, the Suit will take
		damage."""
		
		if base.avatar.pies.pie_state == 'start':
			return
		intoNP = entry.getIntoNodePath()
		suitNP = intoNP.getParent()
		for key in self.cr.doId2do.keys():
			val = self.cr.doId2do[key]
			# Let's see if the DoId ties into a Suit class.
			if "Suit" in val.__class__.__name__:
				if val.getKey() == suitNP.getKey():
					# It's true! Let's send a datagram of the DoId over the network.
					if val.getHealth() > 0:
						val.b_setDamage(self.dmg2BeDone)
						taskMgr.doMethodLater(0.1, self.checkSuitHealth, "checkSuitHealth", extraArgs=[val], appendTask=True)
			elif val.__class__.__name__ == "DistributedToon":
				if val.getKey() == suitNP.getKey():
					if not val.isDead():
						if val.getHealth() < 50:
							val.b_addHealth(1)
		base.avatar.b_handlePieSplat()
		
	def checkSuitHealth(self, suit, task):
		money = int(suit.maxHP / CIGlobals.SuitAttackDamageFactors['clipontie'])
		if suit.getHealth() <= 0:
			base.avatar.setMoney(base.avatar.getMoney() + money)
		return task.done
		
	def nul(self):
		pass
		
	def handleLookSpot(self, hpr):
		h, p, r = hpr
		base.avatar.d_lookAtObject(h, p, r)
		
	def startBook(self):
		self.resetHeadHpr()
		base.avatar.stopLookAround()
		self.book_btn.remove()
		self.disableMovement()
		base.avatar.b_openBook()
		taskMgr.doMethodLater(0.5, self.idleBook, "idlebook")

	def idleBook(self, task):
		self.sb.createBG()
		self.sb.zonePage()
		base.avatar.b_readBook()
		self.book_btn = DirectButton(geom=(self.book_gui.find('**/BookIcon_OPEN'),
											self.book_gui.find('**/BookIcon_CLSD'),
											self.book_gui.find('**/BookIcon_RLVR2')), relief=None, pos=(-0.175, 0, 0.163), command=self.endBook, extraArgs=["closebook"], scale=(0.7, 0.8, 0.8), parent=base.a2dBottomRight)
		self.book_btn.setBin('gui-popup', 60)
		return task.done

	def endBook(self, direction):
		self.sb.closeBook()
		self.book_btn.hide()
		base.avatar.b_closeBook()
		taskMgr.doMethodLater(2, self.finishBook, "finishBook", extraArgs=[None, direction])
		
	def finishBook(self, task, direction):
		base.avatar.startLookAround()
		self.book_btn['geom'] = (self.book_gui.find('**/BookIcon_CLSD'), self.book_gui.find('**/BookIcon_OPEN'), self.book_gui.find('**/BookIcon_RLVR'))
		self.book_btn['command'] = self.startBook
		self.book_btn['extraArgs'] = []
		if direction == "closebook":
			self.enableMovement()
			self.book_btn.show()

	def enterTeleportOut(self, task, place="hood"):
		base.avatar.stopLookAround()
		self.resetHeadHpr()
		base.avatar.b_teleportOut()
		self.moneyGui.deleteGui()
		self.pieGui.deleteGui()
		self.laffMeter.disable()

	def enterTeleportIn(self, place="hood"):
		base.avatar.setPos(0,0,0)
		base.avatar.setHpr(0,0,0)
		if place == "hood":
			base.avatar.b_teleportIn()
			taskMgr.doMethodLater(1, self.enableMovementAfterTele, "emat")
			self.pieGui.createGui()
			self.moneyGui.createGui()
			self.createLaffMeter()
			self.resetSmartCam()
		elif place == "minigame":
			self.smart_cam.stop_smartcamera()
			camera.setPos(0,0,0)
			camera.setHpr(0,0,0)
			base.avatar.d_clearSmoothing()
			base.avatar.b_setAnimState("neutral")
			self.pieGui.deleteGui()
			self.moneyGui.deleteGui()
			self.book_btn.hide()

	def enableMovementAfterTele(self, task):
		base.avatar.startLookAround()
		base.avatar.b_setAnimState("neutral")
		self.enableMovement()
		self.book_btn.show()
		return task.done
		
	def changeHoodTask(self, task, newzoneid, currentzoneid):
		self.changeHood(newzoneid, currentzoneid)
		
	def changeHood(self, newzoneid, currentzoneid, place="hood"):
		if currentzoneid == 10:
			self.hoodUtil.unload("home")
		elif currentzoneid == 20:
			self.hoodUtil.unload("TT")
		elif currentzoneid == 30:
			self.hoodUtil.unload("minigamearea")
		if newzoneid == 10:
			self.cr.setObjectZone(base.avatar, 10)
			self.hoodUtil.load("home")
			base.avatar.b_setPlace(CIGlobals.Estate)
		elif newzoneid == 20:
			self.cr.setObjectZone(base.avatar, 20)
			self.hoodUtil.load("TT")
			base.avatar.b_setPlace(CIGlobals.ToontownCentral)
			if self.cr.SuitsActive == 1:
				self.hoodUtil.enableSuitEffect(self.cr.invasionSize)
				if self.cr.BossActive == 1:
					self.handleBossSpawned()
		elif newzoneid == 30:
			self.cr.setObjectZone(base.avatar, 30)
			self.hoodUtil.load("minigamearea")
			base.avatar.b_setPlace(CIGlobals.MinigameArea)
		elif newzoneid == "exit":
			self.exitGame()
		else:
			self.cr.setObjectZone(base.avatar, newzoneid)
			messenger.send("loadedHood", [place])
		if newzoneid != "exit":
			self.spawn()
		
	def spawn(self):
		h = random.randint(0, 360)
		if base.avatar.zoneId == 20:
			point = random.randint(0, len(CIGlobals.SuitPaths) - 1)
			pos = CIGlobals.SuitPaths[point]
			base.avatar.setPos(pos)
		base.avatar.setH(h)
			
	def checkHealth(self, task):
		if base.avatar.getHealth() <= 0:
			base.avatar.b_toonLose()
			self.toonLose()
			return task.done
		return task.cont
		
	def exitGame(self):
		self.delete()
		messenger.send("enterPickAToon", [1])
		
	def toonLose(self):
		self.smart_cam.stop_smartcamera()
		self.disableMovement()
		aspect2d.hide()
		render2d.hide()
		camera.setPos(camera.getPos(render))
		camera.setHpr(camera.getHpr(render))
		camera.reparentTo(render)
		taskMgr.doMethodLater(8, self.leaveGame, "leaveGame")
		
	def leaveGame(self, task):
		self.delete()
		messenger.send("died")
		return task.done
		
	def handleSuitsActive(self, size):
		if base.avatar.zoneId == 20:
			self.hoodUtil.enableSuitEffect(size)
			
	def handleSuitsInactive(self):
		if base.avatar.zoneId == 20:
			self.hoodUtil.disableSuitEffect()
			
	def handleFullTrolley(self):
		notify.warning("Cannot enter full trolley!")

	def handleOpenTrolley(self):
		notify.info("Trolley is open!")
			
	def sendSuitInfoRequest(self):
		""" We have just arrived in-game, let's
		see if there are any active Suits. """
		
		pkg = PyDatagram()
		pkg.addUint16(WANTS_SUIT_INFO)
		self.cr.send(pkg)
		
	def sendBossInfoRequest(self):
		pkg = PyDatagram()
		pkg.addUint16(WANTS_BOSS_INFO)
		self.cr.send(pkg)
		
	def handleTrolleyEnter(self, entry):
		# Let's find out if we can join the trolley.
		pkg = PyDatagram()
		pkg.addUint16(TROLLEY_REQ_ENTER)
		self.cr.send(pkg)

	def handleTrolleyResponse(self):
		notify.info("Got response from trolley.")
		
	def resetHeadHpr(self):
		base.avatar.b_lookAtObject(0, 0, 0, blink=0)
		
	def handleTookDamage(self):
		if base.avatar.isDead():
			return
		base.avatar.stopLookAround()
		self.resetHeadHpr()
		self.disableMovement()
		if not base.avatar.isDead():
			taskMgr.doMethodLater(3, self.enableMovementTask, "enableMovementTask")
			
	def interruptPie(self):
		self.isThrowing = False
		self.cleanupPieModel()
		taskMgr.remove("releasePie")
		
	def cleanupPieModel(self):
		base.avatar.b_deletePie()
			
	def enableMovementTask(self, task):
		if base.avatar.isDead():
			return task.done
		base.avatar.startLookAround()
		self.enableMovement()
		return task.done
		
	def disableMovement(self):
		self.movementEnabled = False
		self.walkControls.disableAvatarControls()
		self.run_sfx.stop()
		self.walk_sfx.stop()
		base.ignore("arrow_up")
		base.ignore("arrow_up-up")
		base.ignore("arrow_down")
		base.ignore("arrow_down-up")
		base.ignore("arrow_left")
		base.ignore("arrow_left-up")
		base.ignore("arrow_right")
		base.ignore("arrow_right-up")
		base.ignore("control")
		base.ignore("control-up")
		base.ignore("delete")
		base.ignore("delete-up")
		
		self.isMoving_forward = True
		self.isMoving_side = True
		
	def setKey(self, key, value):
		self.keyMap[key] = value
		
	def move(self, task):
		if not self.movementEnabled:
			return task.done

		def checkIsAirborne(task):
			if not self.walkControls.isAirborne:
				if self.keyMap["forward"]!=0:
					if self.isMoving_forward is True:
						self.run_sfx.play()
						self.walk_sfx.stop()
						base.avatar.b_setAnimState("run")
						self.isMoving_forward = False
				elif (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0):
					if self.isMoving_side is True:
						self.walk_sfx.play()
						self.run_sfx.stop()
						base.avatar.b_setAnimState("walk")
						self.isMoving_side = False
				else:
					base.avatar.b_setAnimState("neutral")
					self.isMoving_side = False
					self.isMoving_forward = False
				return task.done
			return task.cont

		if (self.keyMap["jump"]!=0):
			if self.isMoving_forward is False and self.isMoving_side is False:
				if not self.walkControls.isAirborne:
					if self.isThrowing:
						self.interruptPie()
					self.walk_sfx.stop()
					self.run_sfx.stop()
					base.avatar.b_setAnimState("jump")
					taskMgr.doMethodLater(0.01, checkIsAirborne, "checkisairborne")
			elif self.isMoving_forward is True or self.isMoving_side is True:
				if not self.walkControls.isAirborne:
					if self.isThrowing:
						self.interruptPie()
					self.walk_sfx.stop()
					self.run_sfx.stop()
					base.avatar.b_setAnimState("leap")
					taskMgr.doMethodLater(0.01, checkIsAirborne, "checkisairborne")

		elif (self.keyMap["forward"]!=0):
			if self.isMoving_forward is False:
				if not self.walkControls.isAirborne:
					if self.isThrowing:
						self.interruptPie()
					self.run_sfx.play()
					self.walk_sfx.stop()
					self.isMoving_side = False
					base.avatar.b_setAnimState("run")
					base.avatar.stopLookAround()
					self.resetHeadHpr()
					self.isMoving_forward = True

		elif (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0):
			if self.isMoving_side is False:
				if not self.walkControls.isAirborne:
					if self.isThrowing:
						self.interruptPie()
					self.run_sfx.stop()
					self.walk_sfx.play()
					self.isMoving_forward = False
					base.avatar.stopLookAround()
					self.resetHeadHpr()
					base.avatar.setPlayRate(1.0, "walk")
					if self.keyMap["backward"] != 0 and self.keyMap["right"] == 0 and self.keyMap["left"] == 0:
						base.avatar.setPlayRate(-1.0, "walk")
					base.avatar.b_setAnimState("walk")
					self.isMoving_side = True

		else:
			if self.isMoving_forward or self.isMoving_side:
				if not self.walkControls.isAirborne:
					self.run_sfx.stop()
					self.walk_sfx.stop()
					base.avatar.b_setAnimState("neutral")
					base.avatar.startLookAround()
					self.resetHeadHpr()
					self.isMoving_side = False
					self.isMoving_forward = False
		
		return task.cont
Exemplo n.º 2
0
class LocalToon(DistributedToon):
    neverDisable = 1

    def __init__(self, cr):
        try:
            self.LocalToon_initialized
            return
        except:
            self.LocalToon_initialized = 1
        DistributedToon.__init__(self, cr)
        self.gagStartKey = config.GetString('gag-start-key')
        self.gagThrowKey = config.GetString('gag-throw-key')
        self.avatarChoice = cr.localAvChoice
        self.smartCamera = SmartCamera()
        self.chatInput = ChatInput()
        self.moneyGui = MoneyGui()
        self.laffMeter = LaffOMeter()
        self.positionExaminer = PositionExaminer()
        self.friendRequestManager = FriendRequestManager()
        self.friendsList = FriendsList()
        self.panel = ToonPanel()
        friendsgui = loader.loadModel(
            'phase_3.5/models/gui/friendslist_gui.bam')
        self.friendButton = DirectButton(
            geom=(friendsgui.find('**/FriendsBox_Closed'),
                  friendsgui.find('**/FriendsBox_Rollover'),
                  friendsgui.find('**/FriendsBox_Rollover')),
            text=("", "Friends", "Friends", ""),
            text_fg=(1, 1, 1, 1),
            text_shadow=(0, 0, 0, 1),
            text_scale=0.065,
            text_pos=(0, -0.2),
            relief=None,
            parent=base.a2dTopRight,
            pos=(-0.18, 0.0, -0.17),
            command=self.friendsButtonClicked,
            scale=0.75)
        friendsgui.removeNode()
        del friendsgui
        self.hideFriendButton()
        self.runSfx = base.loadSfx(
            "phase_3.5/audio/sfx/AV_footstep_runloop.ogg")
        self.runSfx.setLoop(True)
        self.walkSfx = base.loadSfx(
            "phase_3.5/audio/sfx/AV_footstep_walkloop.ogg")
        self.walkSfx.setLoop(True)
        self.controlManager = ControlManager.ControlManager(True, False)
        self.offset = 3.2375
        self.firstPersonCamPos = None
        self.movementKeymap = {
            "forward": 0,
            "backward": 0,
            "left": 0,
            "right": 0,
            "jump": 0
        }
        self.avatarMovementEnabled = False
        self.isMoving_forward = False
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_jump = False
        self.gagThrowBtn = None
        self.myBattle = None
        self.gagsTimedOut = False
        self.needsToSwitchToGag = None
        self.gagsEnabled = False

        self.pickerTrav = None
        self.pickerRay = None
        self.pickerRayNode = None
        self.pickerHandler = None
        self.rolledOverTag = None

        self.inTutorial = False
        self.hasDoneJump = False
        self.lastState = None
        self.lastAction = None

        self.jumpHardLandIval = None

        #base.cTrav.showCollisions(render)

    def _handleWentInTunnel(self, requestStatus):
        self.cr.playGame.getPlace().doneStatus = requestStatus
        messenger.send(self.cr.playGame.getPlace().doneEvent)

    def _handleCameOutTunnel(self):
        self.walkControls.setCollisionsActive(1)
        self.cr.playGame.getPlace().fsm.request(
            self.cr.playGame.getPlace().nextState)

    def handleClickedWhisper(self,
                             senderName,
                             fromId,
                             isPlayer,
                             openPanel=False):
        if self.cr.playGame.getPlace() == None or not hasattr(
                self.cr.playGame.getPlace(),
                'fsm') or self.cr.playGame.getPlace().fsm == None:
            return
        if openPanel and self.cr.playGame.getPlace().fsm.getCurrentState(
        ).getName() in ['walk', 'shtickerBook']:
            self.panel.makePanel(fromId)
        self.chatInput.disableKeyboardShortcuts()
        self.chatInput.fsm.request('input', ["", self.sendWhisper, [fromId]])

    def handleClickedSentWhisper(self, senderName, fromId, isPlayer):
        self.handleClickedWhisper(senderName, fromId, isPlayer, True)

    def sendWhisper(self, message, target):
        message = self.chatInput.chatInput.get()
        self.cr.friendsManager.d_sendWhisper(target, message)
        self.chatInput.fsm.request('idle')
        self.chatInput.enableKeyboardShortcuts()

    def hasDiscoveredHood(self, zoneId):
        return zoneId in self.hoodsDiscovered

    def hasTeleportAccess(self, zoneId):
        return zoneId in self.teleportAccess

    def tutorialCreated(self, zoneId):
        self.cr.tutorialCreated(zoneId)

    def friendsButtonClicked(self):
        self.hideFriendButton()
        self.friendsList.fsm.request('onlineFriendsList')

    def hideFriendButton(self):
        self.friendButton.hide()

    def showFriendButton(self):
        self.friendButton.show()

    def gotoNode(self, node, eyeHeight=3):
        possiblePoints = (Point3(3, 6, 0), Point3(-3, 6, 0), Point3(6, 6, 0),
                          Point3(-6, 6, 0), Point3(3, 9, 0), Point3(-3, 9, 0),
                          Point3(6, 9, 0), Point3(-6, 9, 0), Point3(9, 9, 0),
                          Point3(-9, 9, 0), Point3(6, 0, 0), Point3(-6, 0, 0),
                          Point3(6, 3, 0), Point3(-6, 3, 0), Point3(9, 9, 0),
                          Point3(-9, 9, 0), Point3(0, 12, 0), Point3(3, 12, 0),
                          Point3(-3, 12, 0), Point3(6, 12,
                                                    0), Point3(-6, 12, 0),
                          Point3(9, 12, 0), Point3(-9, 12,
                                                   0), Point3(0, -6, 0),
                          Point3(-3, -6, 0), Point3(0, -9,
                                                    0), Point3(-6, -9, 0))
        for point in possiblePoints:
            pos = self.positionExaminer.consider(node, point, eyeHeight)
            if pos:
                self.setPos(node, pos)
                self.lookAt(node)
                self.setHpr(self.getH() + random.choice((-10, 10)), 0, 0)
                return

        self.setPos(node, 0, 0, 0)

    def setFriendsList(self, friends):
        DistributedToon.setFriendsList(self, friends)
        self.cr.friendsManager.d_requestFriendsList()
        self.panel.maybeUpdateFriendButton()

    def d_requestAddFriend(self, avId):
        self.sendUpdate('requestAddFriend', [avId])

    def enablePicking(self):
        self.accept('toonClicked', self.toonClicked)

    def disablePicking(self):
        self.ignore('toonClicked')

    def toonClicked(self, avId):
        self.panel.makePanel(avId)

    def prepareToSwitchControlType(self):
        # Hack fix for getting stuck moving in one direction without pressing the movement keys.
        inputs = [
            "run", "forward", "reverse", "turnLeft", "turnRight", "slideLeft",
            "slideRight", "jump"
        ]
        for inputName in inputs:
            try:
                inputState.releaseInputs(inputName)
            except:
                pass

    def getBackpack(self):
        return DistributedToon.getBackpack(self)

    def setMyBattle(self, battle):
        self.myBattle = battle

    def getMyBattle(self):
        return self.myBattle

    def ghostOn(self):
        self.getGeomNode().setTransparency(1)
        self.getGeomNode().setColorScale(1, 1, 1, 0.25)

    def ghostOff(self):
        self.getGeomNode().setColorScale(1, 1, 1, 1)
        self.getGeomNode().setTransparency(0)

    def enterReadBook(self, ts=0, callback=None, extraArgs=[]):
        self.stopLookAround()
        self.b_lookAtObject(0, -45, 0)
        DistributedToon.enterReadBook(self, ts, callback, extraArgs)

    def exitReadBook(self):
        DistributedToon.exitReadBook(self)
        self.startLookAround()

    def getAirborneHeight(self):
        return self.offset + 0.025000000000000001

    def setupControls(self):
        self.walkControls = GravityWalker(legacyLifter=False)
        self.walkControls.setWallBitMask(CIGlobals.WallBitmask)
        self.walkControls.setFloorBitMask(CIGlobals.FloorBitmask)
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed,
                                       CIGlobals.ToonJumpForce,
                                       CIGlobals.ToonReverseSpeed,
                                       CIGlobals.ToonRotateSpeed)
        self.walkControls.initializeCollisions(base.cTrav,
                                               self,
                                               floorOffset=0.025,
                                               reach=4.0)
        self.walkControls.cEventSphereNodePath.node().setFromCollideMask(
            CIGlobals.WallBitmask | CIGlobals.WeaponBitmask
            | GunGameGlobals.HILL_BITMASK)
        self.walkControls.setAirborneHeightFunc(self.getAirborneHeight)

    def setWalkSpeedNormal(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed,
                                       CIGlobals.ToonJumpForce,
                                       CIGlobals.ToonReverseSpeed,
                                       CIGlobals.ToonRotateSpeed)

    def setWalkSpeedSlow(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSlowSpeed,
                                       CIGlobals.ToonJumpSlowForce,
                                       CIGlobals.ToonReverseSlowSpeed,
                                       CIGlobals.ToonRotateSlowSpeed)

    def setupCamera(self):
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4. / 3.))
        base.camLens.setNearFar(CIGlobals.DefaultCameraNear,
                                CIGlobals.DefaultCameraFar)
        self.smartCamera.initializeSmartCamera()
        self.smartCamera.initCameraPositions()
        self.smartCamera.setCameraPositionByIndex(0)

    def setDNAStrand(self, dnaStrand):
        DistributedToon.setDNAStrand(self, dnaStrand)
        self.initCollisions()
        self.setupCamera()

    def setMoney(self, money):
        DistributedToon.setMoney(self, money)
        self.moneyGui.update(money)

    def setupNameTag(self, tempName=None):
        DistributedToon.setupNameTag(self, tempName)
        self.nametag.setNametagColor(
            NametagGlobals.NametagColors[NametagGlobals.CCLocal])
        self.nametag.unmanage(base.marginManager)
        self.nametag.setActive(0)
        self.nametag.updateAll()

    def d_broadcastPositionNow(self):
        self.d_clearSmoothing()
        self.d_broadcastPosHpr()

    def b_setAnimState(self, anim, callback=None, extraArgs=[]):
        if self.anim != anim:
            self.d_setAnimState(anim)
            DistributedToon.setAnimState(self,
                                         anim,
                                         callback=callback,
                                         extraArgs=extraArgs)

    def attachCamera(self):
        #self.notify.info("Attaching camera...")
        camera.reparentTo(self)
        camera.setPos(self.smartCamera.getIdealCameraPos())

    def startSmartCamera(self):
        #self.notify.info("Starting camera...")
        self.smartCamera.startUpdateSmartCamera()

    def resetSmartCamera(self):
        #self.notify.info("Resetting camera...")
        self.stopSmartCamera()
        self.startSmartCamera()

    def stopSmartCamera(self):
        #self.notify.info("Stopping camera...")
        self.smartCamera.stopUpdateSmartCamera()

    def detachCamera(self):
        #self.notify.info("Detaching camera...")
        camera.reparentTo(render)
        camera.setPos(0, 0, 0)
        camera.setHpr(0, 0, 0)

    def handleSuitAttack(self, attack_id, suit_id):
        DistributedToon.handleSuitAttack(self, attack_id, suit_id)

        if not self.isDead() and base.config.GetBool('want-sa-reactions'):
            base.taskMgr.remove('LT.attackReactionDone')
            attack = SuitAttacks.SuitAttackLengths.keys()[attack_id]
            suit = self.cr.doId2do.get(suit_id)
            animToPlay = None
            timeToWait = 3.0
            if not attack in ["pickpocket", "fountainpen"]:
                suitH = suit.getH(render) % 360
                myH = self.getH(render) % 360
                if -90.0 <= (suitH - myH) <= 90.0:
                    animToPlay = "fallFWD"
                else:
                    animToPlay = "fallBCK"
            elif attack in ["pickpocket"]:
                animToPlay = "cringe"
            elif attack in ["fountainpen"]:
                animToPlay = "conked"
                timeToWait = 5.0
            self.cr.playGame.getPlace().fsm.request('stop')
            self.b_setAnimState(animToPlay)
            base.taskMgr.doMethodLater(timeToWait, self.__attackReactionDone,
                                       'LT.attackReactionDone')

    def __attackReactionDone(self, task):
        self.cr.playGame.hood.loader.place.fsm.request('walk')
        self.b_setAnimState('neutral')
        return Task.done

    def printPos(self):
        x, y, z = self.getPos(render)
        h, p, r = self.getHpr(render)
        print "Pos: (%s, %s, %s), Hpr: (%s, %s, %s)" % (x, y, z, h, p, r)

    def enableAvatarControls(self):
        self.walkControls.enableAvatarControls()
        self.accept("control", self.updateMovementKeymap, ["jump", 1])
        self.accept("control-up", self.updateMovementKeymap, ["jump", 0])
        self.accept('tab', self.smartCamera.nextCameraPos, [1])
        self.accept('shift-tab', self.smartCamera.nextCameraPos, [0])
        self.accept('page_up', self.smartCamera.pageUp)
        self.accept('page_down', self.smartCamera.pageDown)
        self.accept('p', self.printPos)
        self.accept('jumpStart', self.__jump)
        self.accept('jumpLand', self.__handleJumpLand)
        self.accept('jumpHardLand', self.__handleJumpHardLand)
        self.avatarMovementEnabled = True
        self.playMovementSfx(None)

    def __handleJumpLand(self):
        if self.jumpHardLandIval:
            self.jumpHardLandIval.finish()
            self.jumpHardLandIval = None
        if self.getHealth() > 0:
            self.b_setAnimState('Happy')

    def __handleJumpHardLand(self):
        if self.jumpHardLandIval:
            self.jumpHardLandIval.finish()
            self.jumpHardLandIval = None
        self.jumpHardLandIval = ActorInterval(self, 'zend')
        self.jumpHardLandIval.setDoneEvent('LT::zend-done')
        self.acceptOnce('LT::zend-done', self.__handleJumpLand)
        self.jumpHardLandIval.start()

    def disableAvatarControls(self):
        self.walkControls.disableAvatarControls()
        self.ignore('tab')
        self.ignore('shift-tab')
        self.ignore('page_up')
        self.ignore('page_down')
        self.ignore("arrow_up")
        self.ignore("arrow_up-up")
        self.ignore("arrow_down")
        self.ignore("arrow_down-up")
        self.ignore("arrow_left")
        self.ignore("arrow_left-up")
        self.ignore("arrow_right")
        self.ignore("arrow_right-up")
        self.ignore("control")
        self.ignore("control-up")
        self.ignore('jumpStart')
        self.ignore('jumpLand')
        self.ignore('jumpHardLand')
        taskMgr.remove("avatarMovementTask")
        self.isMoving_forward = False
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_jump = False
        self.avatarMovementEnabled = False
        self.playMovementSfx(None)
        for k, _ in self.movementKeymap.items():
            self.updateMovementKeymap(k, 0)

    def updateMovementKeymap(self, key, value):
        self.movementKeymap[key] = value

    def getMovementKeyValue(self, key):
        return self.movementKeymap[key]

    def playMovementSfx(self, movement):
        if movement == "run":
            self.walkSfx.stop()
            self.runSfx.play()
        elif movement == "walk":
            self.runSfx.stop()
            self.walkSfx.play()
        else:
            self.runSfx.stop()
            self.walkSfx.stop()

    def __forward(self):
        self.resetHeadHpr()
        self.stopLookAround()
        if self.getHealth() < 1:
            self.playMovementSfx("walk")
            self.setPlayRate(1.2, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.playMovementSfx("run")
            self.setAnimState('run')
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_forward = True
        self.isMoving_jump = False

    def __turn(self):
        self.resetHeadHpr()
        self.stopLookAround()
        self.playMovementSfx("walk")
        if self.getHealth() < 1:
            self.setPlayRate(1.2, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setPlayRate(1.0, "walk")
            self.setAnimState("walk")
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_side = True
        self.isMoving_jump = False

    def __reverse(self):
        self.resetHeadHpr()
        self.stopLookAround()
        self.playMovementSfx("walk")
        if self.getHealth() < 1:
            self.setPlayRate(-1.0, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setAnimState("walkBack")
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = True
        self.isMoving_jump = False

    def __jump(self):
        self.playMovementSfx(None)
        if base.localAvatar.getHealth() > 0:
            if self.playingAnim in ['run', 'walk']:
                self.b_setAnimState("leap")
            else:
                self.b_setAnimState("jump")
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_jump = True

    def __neutral(self):
        self.resetHeadHpr()
        self.startLookAround()
        self.playMovementSfx(None)
        if base.localAvatar.getHealth() > 0:
            self.setAnimState("neutral")
        else:
            self.setPlayRate(1.0, 'dneutral')
            self.setAnimState("deadNeutral")
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_jump = False

    def movementTask(self, task):
        if self.getMovementKeyValue("jump") == 1:
            if not self.walkControls.isAirborne:
                if self.walkControls.mayJump:
                    self.__jump()
                    self.hasDoneJump = True
                else:
                    if self.hasDoneJump:
                        if self.getHealth() > 0:
                            self.b_setAnimState('Happy')
                        self.hasDoneJump = False
        else:
            if not self.walkControls.isAirborne:
                if self.hasDoneJump:
                    if self.getHealth() > 0:
                        self.b_setAnimState('Happy')
                    self.hasDoneJump = False
        return task.cont

    def startTrackAnimToSpeed(self):
        if not base.taskMgr.hasTaskNamed(self.uniqueName('trackAnimToSpeed')):
            base.taskMgr.add(self.trackAnimToSpeed,
                             self.uniqueName('trackAnimToSpeed'))

    def stopTrackAnimToSpeed(self):
        base.taskMgr.remove(self.uniqueName('trackAnimToSpeed'))

    def trackAnimToSpeed(self, task):
        speed, rotSpeed, slideSpeed = self.walkControls.getSpeeds()
        state = None
        if self.getHealth() > 0:
            state = 'Happy'
        else:
            state = 'Sad'
        if state != self.lastState:
            self.lastState = state
            self.b_setAnimState(state)
            if base.minigame is None:
                if state == 'Sad':
                    self.setWalkSpeedSlow()
                else:
                    self.setWalkSpeedNormal()
        action = self.setSpeed(speed, rotSpeed)
        if action != self.lastAction:
            self.lastAction = action
            if action == CIGlobals.WALK_INDEX or action == CIGlobals.REVERSE_INDEX:
                self.resetHeadHpr()
                self.stopLookAround()
                self.playMovementSfx("walk")
            elif action == CIGlobals.RUN_INDEX:
                self.resetHeadHpr()
                self.stopLookAround()
                self.playMovementSfx("run")
            else:
                self.resetHeadHpr()
                self.startLookAround()
                self.playMovementSfx(None)
        return task.cont

    def createLaffMeter(self):
        r, g, b, _ = self.getHeadColor()
        animal = self.getAnimal()
        maxHp = self.getMaxHealth()
        hp = self.getHealth()
        self.laffMeter.generate(r, g, b, animal, maxHP=maxHp, initialHP=hp)
        self.laffMeter.start()

    def disableLaffMeter(self):
        self.laffMeter.stop()
        self.laffMeter.disable()

    def deleteLaffMeter(self):
        self.laffMeter.delete()

    def setLoadout(self, gagIds):
        DistributedToon.setLoadout(self, gagIds)
        if base.cr.playGame.getPlace() and base.cr.playGame.getPlace(
        ).fsm.getCurrentState().getName() == 'shtickerBook':
            if hasattr(base.cr.playGame.getPlace(), 'shtickerBookStateData'):
                if base.cr.playGame.getPlace(
                ).shtickerBookStateData.fsm.getCurrentState().getName(
                ) == 'inventoryPage':
                    base.cr.playGame.getPlace(
                    ).shtickerBookStateData.gui.fsm.request('idle')

    def enableGags(self, andKeys=0):
        if self.avatarMovementEnabled and andKeys:
            self.enableGagKeys()
        self.invGui.createGui()
        self.invGui.updateLoadout()
        self.backpack.loadoutGUI = self.invGui
        if self.backpack.getCurrentGag():
            self.invGui.setWeapon(self.backpack.getCurrentGag().getName(),
                                  playSound=False)

    def enableGagKeys(self):
        if self.gagThrowBtn:
            self.gagThrowBtn.bind(DGG.B1PRESS, self.startGag)
            self.gagThrowBtn.bind(DGG.B1RELEASE, self.throwGag)
        self.accept(self.gagStartKey, self.startGag)
        self.accept(self.gagThrowKey, self.throwGag)
        self.gagsEnabled = True

    def disableGagKeys(self):
        self.gagsEnabled = False
        if self.gagThrowBtn:
            self.gagThrowBtn.unbind(DGG.B1PRESS)
            self.gagThrowBtn.unbind(DGG.B1RELEASE)
        self.ignore(self.gagStartKey)
        self.ignore(self.gagThrowKey)

    def disableGags(self):
        self.disableGagKeys()
        if self.invGui:
            self.invGui.deleteGui()
        if hasattr(self, 'backpack'):
            if self.backpack:
                self.backpack.setCurrentGag()

    def setWeaponType(self, weaponType):
        enableKeysAgain = 0
        if weaponType != self.weaponType:
            enableKeysAgain = 1
        self.weaponType = weaponType
        if enableKeysAgain:
            self.disableGagKeys()
            self.enableGagKeys()

    def createMoney(self):
        self.moneyGui.createGui()
        # Automatically update incase we missed the db field.
        self.moneyGui.update(self.money)

    def handleMoneyChanged(self):
        self.moneyGui.update()

    def disableMoney(self):
        self.moneyGui.deleteGui()

    def resetHeadHpr(self):
        self.b_lookAtObject(0, 0, 0, blink=0)

    def canUseGag(self, preActive):
        if preActive:

            # We're checking if we can call `startGag` (before the gag gets activated)
            return (self.backpack is not None
                    and self.backpack.getCurrentGag() is not None
                    and self.backpack.getSupply() > 0 and self.gagsEnabled)

        else:

            # We're checking if we can call `throwGag` or `releaseGag` (after the gag gets activated)
            return (self.backpack is not None
                    and self.backpack.getCurrentGag() is not None
                    and self.backpack.getActiveGag() is not None
                    and self.backpack.getSupply() > 0 and self.gagsEnabled)

    def startGag(self, start=True):
        if not self.canUseGag(True) or self.backpack.getCurrentGag(
        ).__class__.__name__ == 'BananaPeel':
            return

        if self.gagThrowBtn:
            self.gagThrowBtn.unbind(DGG.B1PRESS)

        self.ignore(self.gagStartKey)
        self.resetHeadHpr()
        self.b_gagStart(self.backpack.getCurrentGag().getID())

    def throwGag(self, start=True):
        if not self.canUseGag(False):
            return

        if self.gagThrowBtn:
            self.gagThrowBtn.unbind(DGG.B1RELEASE)

        self.ignore(self.gagThrowKey)

        if self.backpack.getActiveGag().getType(
        ) == GagType.SQUIRT and self.backpack.getActiveGag().getName() in [
                CIGlobals.SeltzerBottle
        ]:
            self.b_gagRelease(self.backpack.getActiveGag().getID())
        else:
            self.b_gagThrow(self.backpack.getActiveGag().getID())

        activeGag = self.backpack.getActiveGag()
        if not activeGag:
            activeGag = self.backpack.getCurrentGag()

        if not activeGag.doesAutoRelease():
            Sequence(Wait(0.75), Func(self.releaseGag)).start()

    def releaseGag(self):
        if not self.canUseGag(False) or self.backpack.getCurrentGag(
        ).__class__.__name__ == 'BananaPeel':
            return
        gag = self.backpack.getActiveGag()
        if not gag:
            gag = self.backpack.getCurrentGag()
        if gag.getState() != GagState.RELEASED:
            gagName = gag.getName()
            self.b_gagRelease(GagGlobals.getIDByName(gagName))

    def checkSuitHealth(self, suit):
        pass

    def handleLookSpot(self, hpr):
        h, p, r = hpr
        self.d_lookAtObject(h, p, r, blink=1)

    def showGagButton(self):
        geom = CIGlobals.getDefaultBtnGeom()
        self.gagThrowBtn = DirectButton(geom=geom,
                                        geom_scale=(0.75, 1, 1),
                                        text="Throw Gag",
                                        text_scale=0.05,
                                        text_pos=(0, -0.01),
                                        relief=None,
                                        parent=base.a2dTopCenter,
                                        pos=(0, 0, -0.1))
        self.gagThrowBtn.setBin('gui-popup', 60)
        self.gagThrowBtn.hide()

    def hideGagButton(self):
        self.gagThrowBtn.removeNode()
        self.gagThrowBtn = None

    def showBookButton(self, inBook=0):
        self.book_gui = loader.loadModel(
            "phase_3.5/models/gui/sticker_open_close_gui.bam")
        self.book_btn = DirectButton(
            geom=(self.book_gui.find('**/BookIcon_CLSD'),
                  self.book_gui.find('**/BookIcon_OPEN'),
                  self.book_gui.find('**/BookIcon_RLVR')),
            relief=None,
            pos=(-0.175, 0, 0.163),
            command=self.bookButtonClicked,
            scale=(0.7, 0.8, 0.8),
            parent=base.a2dBottomRight)
        self.book_btn.setBin('gui-popup', 60)
        if inBook:
            self.book_btn["geom"] = (self.book_gui.find('**/BookIcon_OPEN'),
                                     self.book_gui.find('**/BookIcon_CLSD'),
                                     self.book_gui.find('**/BookIcon_RLVR2'))
            self.book_btn["command"] = self.bookButtonClicked
            self.book_btn["extraArgs"] = [0]

    def hideBookButton(self):
        if hasattr(self, 'book_gui'):
            self.book_gui.removeNode()
            del self.book_gui
        if hasattr(self, 'book_btn'):
            self.book_btn.destroy()
            del self.book_btn

    def bookButtonClicked(self, openIt=1):
        if openIt:
            base.cr.playGame.getPlace().fsm.request('shtickerBook')
        else:
            base.cr.playGame.getPlace().shtickerBookStateData.finished(
                "resume")

    def startMonitoringHP(self):
        taskMgr.add(self.monitorHealth, "localToon-monitorHealth")

    def monitorHealth(self, task):
        if self.isDead():
            base.taskMgr.remove("LT.attackReactionDone")
            if (self.cr.playGame.hood.id != ZoneUtil.getHoodId(self.zoneId)):
                self.cr.playGame.getPlace().fsm.request(
                    'died', [{}, self.diedStateDone])
                messenger.send(PCTMM.getLocalAvDiedEvent())
            return task.done
        return task.cont

    def stopMonitoringHP(self):
        taskMgr.remove("localToon-monitorHealth")

    def setHealth(self, hp):
        if hp > 0 and self.getHealth() < 1:
            if self.cr.playGame and self.cr.playGame.getPlace():
                if self.cr.playGame.getPlace().fsm.getCurrentState().getName(
                ) == 'walk':
                    if self.cr.playGame.getPlace(
                    ).walkStateData.fsm.getCurrentState().getName(
                    ) == 'deadWalking':
                        self.cr.playGame.getPlace().walkStateData.fsm.request(
                            'walking')
            if self.animFSM.getCurrentState().getName() == 'deadNeutral':
                self.playMovementSfx(None)
                self.b_setAnimState("neutral")
            elif self.animFSM.getCurrentState().getName() == 'deadWalk':
                self.playMovementSfx("run")
                self.b_setAnimState("run")
        DistributedToon.setHealth(self, hp)

    def diedStateDone(self, requestStatus):
        hood = self.cr.playGame.hood.id
        if hood == CIGlobals.BattleTTC:
            hood = CIGlobals.ToontownCentral
        toZone = ZoneUtil.getZoneId(hood)
        if self.zoneId != toZone:
            requestStatus = {
                'zoneId': toZone,
                'hoodId': hood,
                'where': ZoneUtil.getWhereName(toZone),
                'avId': self.doId,
                'loader': ZoneUtil.getLoaderName(toZone),
                'shardId': None,
                'wantLaffMeter': 1,
                'how': 'teleportIn'
            }
            self.cr.playGame.getPlace().doneStatus = requestStatus
            messenger.send(self.cr.playGame.getPlace().doneEvent)

        else:
            return

        ## Tell the ai we're dead so they can refill our hp.
        #self.sendUpdate("died", [])
        ## Then, log out and notify the client that they're dead.
        # self.cr.gameFSM.request("closeShard", ['died'])

    def teleportToCT(self):
        toZone = CIGlobals.CogTropolisId
        hood = CIGlobals.CogTropolis
        requestStatus = {
            'zoneId': toZone,
            'hoodId': hood,
            'where': ZoneUtil.getWhereName(toZone),
            'avId': self.doId,
            'loader': ZoneUtil.getLoaderName(toZone),
            'shardId': None,
            'wantLaffMeter': 1,
            'how': 'teleportIn',
            'world': CIGlobals.OToontown
        }
        self.cr.playGame.getPlace().fsm.request('teleportOut', [requestStatus])

    def createChatInput(self):
        self.chatInput.load()
        self.chatInput.enter()

    def disableChatInput(self):
        self.chatInput.exit()
        self.chatInput.unload()

    def collisionsOn(self):
        self.controlManager.collisionsOn()

    def collisionsOff(self):
        self.controlManager.collisionsOff()

    def toggleAspect2d(self):
        if base.aspect2d.isHidden():
            base.aspect2d.show()
        else:
            base.aspect2d.hide()

    def generate(self):
        DistributedToon.generate(self)

    def delete(self):
        DistributedToon.delete(self)
        self.deleteLaffMeter()
        return

    def disable(self):
        base.camLens.setMinFov(CIGlobals.OriginalCameraFov / (4. / 3.))
        if self.jumpHardLandIval:
            self.ignore('LT::zend-done')
            self.jumpHardLandIval.finish()
            self.jumpHardLandIval = None
        self.friendsList.destroy()
        self.friendsList = None
        self.panel.cleanup()
        self.panel = None
        self.positionExaminer.delete()
        self.positionExaminer = None
        self.disablePicking()
        self.stopMonitoringHP()
        taskMgr.remove("resetHeadColorAfterFountainPen")
        taskMgr.remove("LT.attackReactionDone")
        self.stopLookAround()
        DistributedToon.disable(self)
        self.disableAvatarControls()
        self.disableLaffMeter()
        self.disableGags()
        self.disableChatInput()
        self.weaponType = None
        self.myBattle = None
        self.ignore("gotLookSpot")
        self.ignore("clickedWhisper")
        self.ignore('f2')
        return

    def announceGenerate(self):
        DistributedToon.announceGenerate(self)
        self.setupControls()
        self.startLookAround()
        self.friendRequestManager.watch()
        self.accept("gotLookSpot", self.handleLookSpot)
        self.accept("clickedWhisper", self.handleClickedSentWhisper)
        self.accept('f2', self.toggleAspect2d)

        #self.accept('c', self.walkControls.setCollisionsActive, [0])

        self.invGui = InventoryGui()

        # Unused developer methods.
        #self.accept('enter', self.printAvPos)
        #self.accept('p', self.enterPictureMode)
        #self.accept('c', self.teleportToCT)
        #posBtn = DirectButton(text = "Get Pos", scale = 0.08, pos = (0.3, 0, 0), parent = base.a2dLeftCenter, command = self.printAvPos)

    def enterHiddenToonMode(self):
        self.laffMeter.stop()
        self.laffMeter.disable()
        self.laffMeter.destroy()
        self.getGeomNode().hide()
        self.deleteNameTag()
        self.moneyGui.deleteGui()
        self.invGui.deleteGui()
        self.hideGagButton()
        self.hideFriendButton()
        self.hideBookButton()
        self.removeAdminToken()

    def printAvPos(self):
        print "Pos: %s, Hpr: %s" % (self.getPos(), self.getHpr())