open-toontown/toontown/safezone/DistributedFishingSpotAI.py

218 lines
9.0 KiB
Python

from otp.ai.AIBase import *
from direct.distributed import DistributedObjectAI
import random
from toontown.toonbase import ToontownAccessAI
from toontown.toonbase import TTLocalizer
from direct.directnotify import DirectNotifyGlobal
from toontown.fishing import FishGlobals
class DistributedFishingSpotAI(DistributedObjectAI.DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedFishingSpotAI")
def __init__(self, air, pond, x, y, z, h, p, r):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
self.notify.debug("init")
self.posHpr = (x, y, z, h, p, r)
self.avId = 0
self.timeoutTask = None
self.pond = pond
self.wantTimeouts = simbase.config.GetBool("want-fishing-timeouts", 1)
def delete(self):
self.notify.debug("delete")
taskMgr.remove(self.taskName("clearEmpty"))
self.ignore(self.air.getAvatarExitEvent(self.avId))
self.__stopTimeout()
self.d_setMovie(FishGlobals.ExitMovie)
self.avId = 0
self.pond = None
DistributedObjectAI.DistributedObjectAI.delete(self)
def getPondDoId(self):
return self.pond.getDoId()
def requestEnter(self):
# A client is requesting sole use of the fishing spot. If
# it's available, he can have it.
avId = self.air.getAvatarIdFromSender()
self.notify.debug("requestEnter: avId: %s" % (avId))
if self.avId == avId:
# This seems to happen in the estates when we get a double request
# coming out of fishing directly onto the dock
self.notify.debug("requestEnter: avId %s is already fishing here" % (avId))
return
# Check that player has full access
if not ToontownAccessAI.canAccess(avId, self.zoneId):
self.sendUpdateToAvatarId(avId, "rejectEnter", [])
return
if self.avId == 0:
self.avId = avId
# Tell the pond we are here
self.pond.addAvSpot(avId, self)
self.acceptOnce(self.air.getAvatarExitEvent(self.avId),
self.unexpectedExit)
self.__stopTimeout()
self.d_setOccupied(self.avId)
self.d_setMovie(FishGlobals.EnterMovie)
self.__startTimeout(FishGlobals.CastTimeout)
self.air.writeServerEvent("fished_enter",self.avId, "%s" % (self.zoneId))
else:
self.sendUpdateToAvatarId(avId, "rejectEnter", [])
def requestExit(self):
# The client within the spot is ready to leave.
avId = self.air.getAvatarIdFromSender()
self.notify.debug("requestExit: avId: %s" % (avId))
if not self.validate(avId, (self.avId == avId), "requestExit: avId is not fishing in this spot"):
return
self.normalExit()
def d_setOccupied(self, avId):
self.notify.debug("setOccupied: %s" % (avId))
self.sendUpdate("setOccupied", [avId])
def doCast(self, power, heading):
# The client begins a cast.
avId = self.air.getAvatarIdFromSender()
self.notify.debug("doCast: avId: %s" % (avId))
if not self.validate(avId, (self.avId == avId),
"doCast: avId is not fishing in this spot"):
return
if not self.validate(avId, (0.0 <= power <= 1.0),
("doCast: power: %s is out of range" % power)):
return
if not self.validate(avId,
(-FishGlobals.FishingAngleMax <= heading <= FishGlobals.FishingAngleMax),
("doCast: heading: %s is out of range" % heading)):
return
av = self.air.doId2do.get(self.avId)
if not self.validate(avId, (av), "doCast: avId not currently logged in to this AI"):
return
self.__stopTimeout()
money = av.getMoney()
# cast cost is based on rod now
castCost = FishGlobals.getCastCost(av.getFishingRod())
if money < castCost:
# Not enough money to cast
self.normalExit()
return
self.air.writeServerEvent("fished_cast", avId, "%s|%s" %(av.getFishingRod(), castCost))
av.b_setMoney(money - castCost)
self.d_setMovie(FishGlobals.CastMovie, power=power, h=heading)
self.__startTimeout(FishGlobals.CastTimeout)
def d_setMovie(self, mode, code=0, itemDesc1=0, itemDesc2=0, itemDesc3=0, power=0, h=0):
self.notify.debug(
"setMovie: mode:%s code:%s itemDesc1:%s itemDesc2:%s itemDesc3:%s power:%s h:%s" %
(mode, code, itemDesc1, itemDesc2, itemDesc3, power, h))
self.sendUpdate("setMovie", [mode, code, itemDesc1, itemDesc2, itemDesc3, power, h])
def getPosHpr(self):
# This is needed because setPosHpr is a required field.
return self.posHpr
def __startTimeout(self, timeLimit):
self.notify.debug("__startTimeout")
# Sets the timeout counter running. If __stopTimeout() is not
# called before the time expires, we'll exit the avatar. This
# prevents avatars from hanging out in the fishing spot all
# day.
self.__stopTimeout()
if self.wantTimeouts:
self.timeoutTask = taskMgr.doMethodLater(timeLimit,
self.__handleTimeout,
self.taskName("timeout"))
def __stopTimeout(self):
self.notify.debug("__stopTimeout")
# Stops a previously-set timeout from expiring.
if self.timeoutTask:
taskMgr.remove(self.timeoutTask)
self.timeoutTask = None
def __handleTimeout(self, task):
self.notify.debug("__handleTimeout")
# Called when a timeout expires, this sends the avatar home.
self.normalExit()
def cleanupAvatar(self):
# Tell the pond we are leaving
self.air.writeServerEvent("fished_exit",self.avId, "%s" % (self.zoneId))
self.pond.removeAvSpot(self.avId, self)
self.ignore(self.air.getAvatarExitEvent(self.avId))
self.__stopTimeout()
self.avId = 0
def normalExit(self):
self.notify.debug("normalExit")
# Send the avatar out of the fishing spot, either because of
# his own request or due to some other cause (like a timeout).
self.cleanupAvatar()
self.d_setMovie(FishGlobals.ExitMovie)
# Give everyone enough time to play the goodbye movie,
# then dump the avatar.
taskMgr.doMethodLater(1.2, self.__clearEmpty,
self.taskName("clearEmpty"))
def __clearEmpty(self, task=None):
self.notify.debug("__clearEmpty")
self.d_setOccupied(0)
def unexpectedExit(self):
self.notify.debug("unexpectedExit")
# Called when the avatar in the fishing spot vanishes.
# Tell the pond we are leaving
self.cleanupAvatar()
self.d_setOccupied(0)
def hitTarget(self, code, item):
self.notify.debug("hitTarget: code: %s item: %s" % (code, item))
if code == FishGlobals.QuestItem:
self.d_setMovie(FishGlobals.PullInMovie, code, item)
elif code in (FishGlobals.FishItem,
FishGlobals.FishItemNewEntry,
FishGlobals.FishItemNewRecord):
genus, species, weight = item.getVitals()
self.d_setMovie(FishGlobals.PullInMovie, code, genus, species, weight)
elif code == FishGlobals.BootItem:
self.d_setMovie(FishGlobals.PullInMovie, code)
elif code == FishGlobals.JellybeanItem:
self.d_setMovie(FishGlobals.PullInMovie, code, item)
else:
self.d_setMovie(FishGlobals.PullInMovie, code)
self.__startTimeout(FishGlobals.CastTimeout)
def d_sellFishComplete(self, avId, trophyResult, numFishCaught):
self.sendUpdateToAvatarId(avId, "sellFishComplete", [trophyResult, numFishCaught])
def sellFish(self):
# The client asks to sell his fish
gotTrophy = -1
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(self.avId)
self.notify.debug("sellFish: avId: %s" % (avId))
if not self.validate(avId, (simbase.wantBingo), "sellFish: Currently, you can only do this if bingo is turned on"):
gotTrophy = False
elif not self.validate(avId, (self.pond.hasPondBingoManager()), "sellFish: Currently, you can only do this during bingo night"):
gotTrophy = False
elif not self.validate(avId, (self.avId == avId), "sellFish: avId is not fishing in this spot"):
gotTrophy = False
elif not self.validate(avId, (av), "sellFish: avId not currently logged in to this AI"):
gotTrophy = False
if gotTrophy is -1:
gotTrophy = self.air.fishManager.creditFishTank(av)
self.d_sellFishComplete(avId, gotTrophy, len(av.fishCollection))
else:
self.d_sellFishComplete(avId, False, 0)