318 lines
14 KiB
Python
318 lines
14 KiB
Python
|
from otp.ai.AIBaseGlobal import *
|
||
|
from panda3d.core import *
|
||
|
from direct.distributed.ClockDelta import *
|
||
|
from PurchaseManagerConstants import *
|
||
|
import copy
|
||
|
from direct.task.Task import Task
|
||
|
from direct.distributed import DistributedObjectAI
|
||
|
from direct.directnotify import DirectNotifyGlobal
|
||
|
from toontown.toonbase import ToontownGlobals
|
||
|
from toontown.minigame import MinigameGlobals
|
||
|
|
||
|
class PurchaseManagerAI(DistributedObjectAI.DistributedObjectAI):
|
||
|
notify = DirectNotifyGlobal.directNotify.newCategory('PurchaseManagerAI')
|
||
|
|
||
|
def __init__(self, air, avArray, mpArray, previousMinigameId, trolleyZone, newbieIdList = []):
|
||
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||
|
self.avIds = copy.deepcopy(avArray)
|
||
|
self.minigamePoints = copy.deepcopy(mpArray)
|
||
|
self.previousMinigameId = previousMinigameId
|
||
|
self.trolleyZone = trolleyZone
|
||
|
self.newbieIds = copy.deepcopy(newbieIdList)
|
||
|
self.isShutdown = 0
|
||
|
for i in xrange(len(self.avIds), 4):
|
||
|
self.avIds.append(0)
|
||
|
|
||
|
for i in xrange(len(self.minigamePoints), 4):
|
||
|
self.minigamePoints.append(0)
|
||
|
|
||
|
self.playerStates = [None,
|
||
|
None,
|
||
|
None,
|
||
|
None]
|
||
|
self.playersReported = [None,
|
||
|
None,
|
||
|
None,
|
||
|
None]
|
||
|
self.playerMoney = [0,
|
||
|
0,
|
||
|
0,
|
||
|
0]
|
||
|
for i in xrange(len(self.avIds)):
|
||
|
avId = self.avIds[i]
|
||
|
if avId <= 3:
|
||
|
self.playerStates[i] = PURCHASE_NO_CLIENT_STATE
|
||
|
self.playersReported[i] = PURCHASE_CANTREPORT_STATE
|
||
|
elif avId in self.air.doId2do:
|
||
|
if avId not in self.getInvolvedAvIds():
|
||
|
self.playerStates[i] = PURCHASE_EXIT_STATE
|
||
|
self.playersReported[i] = PURCHASE_REPORTED_STATE
|
||
|
else:
|
||
|
self.playerStates[i] = PURCHASE_WAITING_STATE
|
||
|
self.playersReported[i] = PURCHASE_UNREPORTED_STATE
|
||
|
else:
|
||
|
self.playerStates[i] = PURCHASE_DISCONNECTED_STATE
|
||
|
self.playersReported[i] = PURCHASE_CANTREPORT_STATE
|
||
|
|
||
|
for avId in self.getInvolvedAvIds():
|
||
|
if avId > 3 and avId in self.air.doId2do:
|
||
|
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId])
|
||
|
av = self.air.doId2do[avId]
|
||
|
avIndex = self.findAvIndex(avId)
|
||
|
money = av.getMoney()
|
||
|
if avIndex == None:
|
||
|
self.notify.warning('__init__ avIndex is none but avId=%s' % avId)
|
||
|
continue
|
||
|
self.playerMoney[avIndex] = money
|
||
|
if self.playerMoney[avIndex] < 0:
|
||
|
simbase.air.writeServerEvent('suspicious', avId, 'toon has invalid money %s, forcing to zero' % money)
|
||
|
self.playerMoney[avIndex] = 0
|
||
|
av.addMoney(self.minigamePoints[avIndex])
|
||
|
self.air.writeServerEvent('minigame', avId, '%s|%s|%s|%s' % (self.previousMinigameId,
|
||
|
self.trolleyZone,
|
||
|
self.avIds,
|
||
|
self.minigamePoints[avIndex]))
|
||
|
|
||
|
self.receivingInventory = 1
|
||
|
self.receivingButtons = 1
|
||
|
return
|
||
|
|
||
|
def delete(self):
|
||
|
taskMgr.remove(self.uniqueName('countdown-timer'))
|
||
|
self.ignoreAll()
|
||
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||
|
|
||
|
def getInvolvedAvIds(self):
|
||
|
avIds = []
|
||
|
for avId in self.avIds:
|
||
|
if avId not in self.newbieIds:
|
||
|
avIds.append(avId)
|
||
|
|
||
|
return avIds
|
||
|
|
||
|
def getMinigamePoints(self):
|
||
|
return self.minigamePoints
|
||
|
|
||
|
def getAvIds(self):
|
||
|
return self.avIds
|
||
|
|
||
|
def getNewbieIds(self):
|
||
|
return self.newbieIds
|
||
|
|
||
|
def getPlayerMoney(self):
|
||
|
return self.playerMoney
|
||
|
|
||
|
def d_setPlayerStates(self, stateArray):
|
||
|
self.sendUpdate('setPlayerStates', stateArray)
|
||
|
return None
|
||
|
|
||
|
def getPlayerStates(self):
|
||
|
return self.playerStates
|
||
|
|
||
|
def getCountdown(self):
|
||
|
self.startCountdown()
|
||
|
return globalClockDelta.getRealNetworkTime()
|
||
|
|
||
|
def startCountdown(self):
|
||
|
if not config.GetBool('disable-purchase-timer', 0):
|
||
|
taskMgr.doMethodLater(PURCHASE_COUNTDOWN_TIME, self.timeIsUpTask, self.uniqueName('countdown-timer'))
|
||
|
|
||
|
def requestExit(self):
|
||
|
avId = self.air.getAvatarIdFromSender()
|
||
|
avIndex = self.findAvIndex(avId)
|
||
|
if avIndex is None:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestExit: unknown avatar: %s' % (avId,))
|
||
|
return
|
||
|
if self.receivingButtons:
|
||
|
if avId in self.air.doId2do:
|
||
|
av = self.air.doId2do[avId]
|
||
|
if avIndex == None:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestExit not on list')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested Exit, but is not on the list!')
|
||
|
else:
|
||
|
avState = self.playerStates[avIndex]
|
||
|
if avState == PURCHASE_PLAYAGAIN_STATE or avState == PURCHASE_WAITING_STATE:
|
||
|
self.playerStates[avIndex] = PURCHASE_EXIT_STATE
|
||
|
self.handlePlayerLeaving(avId)
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestExit invalid transition to exit')
|
||
|
self.notify.warning('Invalid transition to exit state.')
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestExit unknown avatar')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested Exit, but is not in doId2do.' + ' Assuming disconnected.')
|
||
|
self.playerStates[avIndex] = PURCHASE_DISCONNECTED_STATE
|
||
|
self.playersReported[avIndex] = PURCHASE_CANTREPORT_STATE
|
||
|
self.ignore(self.air.getAvatarExitEvent(avId))
|
||
|
self.d_setPlayerStates(self.playerStates)
|
||
|
if self.getNumUndecided() == 0:
|
||
|
self.timeIsUp()
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestExit not receiving requests now')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested Exit, but I am not receiving button requests now.')
|
||
|
return
|
||
|
|
||
|
def requestPlayAgain(self):
|
||
|
avId = self.air.getAvatarIdFromSender()
|
||
|
if self.findAvIndex(avId) == None:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestPlayAgain: unknown avatar')
|
||
|
return
|
||
|
if self.receivingButtons:
|
||
|
if avId in self.air.doId2do:
|
||
|
av = self.air.doId2do[avId]
|
||
|
avIndex = self.findAvIndex(avId)
|
||
|
if avIndex == None:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestPlayAgain not on list')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested PlayAgain, but is not on the list!')
|
||
|
else:
|
||
|
avState = self.playerStates[avIndex]
|
||
|
if avState == PURCHASE_WAITING_STATE:
|
||
|
self.notify.debug(str(avId) + ' wants to play again')
|
||
|
self.playerStates[avIndex] = PURCHASE_PLAYAGAIN_STATE
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestPlayAgain invalid transition to PlayAgain')
|
||
|
self.notify.warning('Invalid transition to PlayAgain state.')
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestPlayAgain unknown avatar')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested PlayAgain, but is not in doId2do.' + ' Assuming disconnected.')
|
||
|
avIndex = self.findAvIndex(avId)
|
||
|
self.playerStates[avIndex] = PURCHASE_DISCONNECTED_STATE
|
||
|
self.playersReported[avIndex] = PURCHASE_CANTREPORT_STATE
|
||
|
self.ignore(self.air.getAvatarExitEvent(avId))
|
||
|
self.d_setPlayerStates(self.playerStates)
|
||
|
if self.getNumUndecided() == 0:
|
||
|
self.timeIsUp()
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.requestPlayAgain not receiving requests now')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested PlayAgain, but I am not receiving button ' + 'requests now.')
|
||
|
return
|
||
|
|
||
|
def setInventory(self, blob, newMoney, done):
|
||
|
avId = self.air.getAvatarIdFromSender()
|
||
|
if self.receivingInventory:
|
||
|
if avId in self.air.doId2do:
|
||
|
av = self.air.doId2do[avId]
|
||
|
avIndex = self.findAvIndex(avId)
|
||
|
if avIndex == None:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.setInventory not on list')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' requested purchase, but is not on the list!')
|
||
|
else:
|
||
|
newInventory = av.inventory.makeFromNetString(blob)
|
||
|
currentMoney = av.getMoney()
|
||
|
if av.inventory.validatePurchase(newInventory, currentMoney, newMoney):
|
||
|
av.setMoney(newMoney)
|
||
|
if not done:
|
||
|
return
|
||
|
if self.playersReported[avIndex] != PURCHASE_UNREPORTED_STATE:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.setInventory bad report state')
|
||
|
self.notify.warning('Bad report state: ' + str(self.playersReported[avIndex]))
|
||
|
else:
|
||
|
av.d_setInventory(av.inventory.makeNetString())
|
||
|
av.d_setMoney(newMoney)
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.setInventory invalid purchase')
|
||
|
self.notify.warning('Avatar ' + str(avId) + ' attempted an invalid purchase.')
|
||
|
av.d_setInventory(av.inventory.makeNetString())
|
||
|
av.d_setMoney(av.getMoney())
|
||
|
self.playersReported[avIndex] = PURCHASE_REPORTED_STATE
|
||
|
if self.getNumUnreported() == 0:
|
||
|
self.shutDown()
|
||
|
else:
|
||
|
self.air.writeServerEvent('suspicious', avId, 'PurchaseManager.setInventory not receiving inventory')
|
||
|
self.notify.warning('Not receiving inventory. Ignored ' + str(avId) + "'s request")
|
||
|
return
|
||
|
|
||
|
def d_setPurchaseExit(self):
|
||
|
self.sendUpdate('setPurchaseExit', [])
|
||
|
return None
|
||
|
|
||
|
def timeIsUpTask(self, task):
|
||
|
self.timeIsUp()
|
||
|
return Task.done
|
||
|
|
||
|
def timeIsUp(self):
|
||
|
self.d_setPurchaseExit()
|
||
|
taskMgr.remove(self.uniqueName('countdown-timer'))
|
||
|
self.receivingButtons = 0
|
||
|
self.receivingInventory = 1
|
||
|
return None
|
||
|
|
||
|
def shutDown(self):
|
||
|
if self.isShutdown:
|
||
|
self.notify.warning('Got shutDown twice')
|
||
|
return
|
||
|
self.isShutdown = 1
|
||
|
from toontown.minigame import MinigameCreatorAI
|
||
|
playAgainNum = self.getNumPlayAgain()
|
||
|
if playAgainNum > 0:
|
||
|
MinigameCreatorAI.createMinigame(self.air, self.getPlayAgainList(), self.trolleyZone, minigameZone=self.zoneId, previousGameId=self.previousMinigameId, newbieIds=self.newbieIds)
|
||
|
else:
|
||
|
MinigameCreatorAI.releaseMinigameZone(self.zoneId)
|
||
|
self.requestDelete()
|
||
|
self.ignoreAll()
|
||
|
return None
|
||
|
|
||
|
def findAvIndex(self, avId):
|
||
|
for i in xrange(len(self.avIds)):
|
||
|
if avId == self.avIds[i]:
|
||
|
return i
|
||
|
|
||
|
return None
|
||
|
|
||
|
def getNumUndecided(self):
|
||
|
undecidedCounter = 0
|
||
|
for playerState in self.playerStates:
|
||
|
if playerState == PURCHASE_WAITING_STATE:
|
||
|
undecidedCounter += 1
|
||
|
|
||
|
return undecidedCounter
|
||
|
|
||
|
def getPlayAgainList(self):
|
||
|
playAgainList = []
|
||
|
for i in xrange(len(self.playerStates)):
|
||
|
if self.playerStates[i] == PURCHASE_PLAYAGAIN_STATE:
|
||
|
playAgainList.append(self.avIds[i])
|
||
|
|
||
|
return playAgainList
|
||
|
|
||
|
def getNumPlayAgain(self):
|
||
|
playAgainCounter = 0
|
||
|
for playerState in self.playerStates:
|
||
|
if playerState == PURCHASE_PLAYAGAIN_STATE:
|
||
|
playAgainCounter += 1
|
||
|
|
||
|
return playAgainCounter
|
||
|
|
||
|
def getNumUnreported(self):
|
||
|
unreportedCounter = 0
|
||
|
for playerState in self.playersReported:
|
||
|
if playerState == PURCHASE_UNREPORTED_STATE:
|
||
|
unreportedCounter += 1
|
||
|
elif playerState == PURCHASE_REPORTED_STATE:
|
||
|
pass
|
||
|
elif playerState == PURCHASE_CANTREPORT_STATE:
|
||
|
pass
|
||
|
else:
|
||
|
self.notify.warning('Weird report state: ' + str(playerState))
|
||
|
|
||
|
return unreportedCounter
|
||
|
|
||
|
def __handleUnexpectedExit(self, avId):
|
||
|
self.notify.warning('Avatar: ' + str(avId) + ' has exited unexpectedly')
|
||
|
index = self.findAvIndex(avId)
|
||
|
if index == None:
|
||
|
self.notify.warning('Something is seriously screwed up...' + 'An avatar exited unexpectedly, and they' + ' are not on my list!')
|
||
|
else:
|
||
|
self.playerStates[index] = PURCHASE_DISCONNECTED_STATE
|
||
|
self.playersReported[index] = PURCHASE_CANTREPORT_STATE
|
||
|
self.d_setPlayerStates(self.playerStates)
|
||
|
if self.receivingButtons:
|
||
|
if self.getNumUndecided() == 0:
|
||
|
self.timeIsUp()
|
||
|
if self.receivingInventory:
|
||
|
if self.getNumUnreported() == 0:
|
||
|
self.shutDown()
|
||
|
return
|
||
|
|
||
|
def handlePlayerLeaving(self, avId):
|
||
|
pass
|