441 lines
16 KiB
Python
441 lines
16 KiB
Python
import copy
|
|
|
|
import DistributedElevatorIntAI
|
|
from ElevatorConstants import *
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed import DistributedObjectAI
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.fsm import ClassicFSM, State
|
|
from direct.fsm import State
|
|
from direct.task import Timer
|
|
from otp.ai.AIBaseGlobal import *
|
|
from toontown.battle import BattleBase
|
|
from toontown.battle import DistributedBattleBldgAI
|
|
from toontown.toonbase.ToontownBattleGlobals import *
|
|
|
|
|
|
class DistributedSuitInteriorAI(DistributedObjectAI.DistributedObjectAI):
|
|
def __init__(self, air, elevator):
|
|
self.air = air
|
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
|
(self.extZoneId, self.zoneId) = elevator.bldg.getExteriorAndInteriorZoneId()
|
|
self.numFloors = elevator.bldg.planner.numFloors
|
|
self.avatarExitEvents = []
|
|
self.toons = []
|
|
self.toonSkillPtsGained = {}
|
|
self.toonExp = {}
|
|
self.toonOrigQuests = {}
|
|
self.toonItems = {}
|
|
self.toonOrigMerits = {}
|
|
self.toonMerits = {}
|
|
self.toonParts = {}
|
|
self.helpfulToons = []
|
|
self.currentFloor = 0
|
|
self.topFloor = self.numFloors - 1
|
|
self.bldg = elevator.bldg
|
|
self.elevator = elevator
|
|
self.suits = []
|
|
self.activeSuits = []
|
|
self.reserveSuits = []
|
|
self.joinedReserves = []
|
|
self.suitsKilled = []
|
|
self.suitsKilledPerFloor = []
|
|
self.battle = None
|
|
self.timer = Timer.Timer()
|
|
self.responses = {}
|
|
self.ignoreResponses = 0
|
|
self.ignoreElevatorDone = 0
|
|
self.ignoreReserveJoinDone = 0
|
|
self.toonIds = copy.copy(elevator.seats)
|
|
for toonId in self.toonIds:
|
|
if toonId is not None:
|
|
self.__addToon(toonId)
|
|
self.savedByMap = {}
|
|
self.fsm = ClassicFSM.ClassicFSM(
|
|
'DistributedSuitInteriorAI',
|
|
[
|
|
State.State('WaitForAllToonsInside',
|
|
self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside,
|
|
['Elevator']),
|
|
State.State('Elevator',
|
|
self.enterElevator, self.exitElevator,
|
|
['Battle']),
|
|
State.State('Battle',
|
|
self.enterBattle, self.exitBattle,
|
|
['ReservesJoining', 'BattleDone']),
|
|
State.State('ReservesJoining',
|
|
self.enterReservesJoining, self.exitReservesJoining,
|
|
['Battle']),
|
|
State.State('BattleDone',
|
|
self.enterBattleDone, self.exitBattleDone,
|
|
['Resting', 'Reward']),
|
|
State.State('Resting',
|
|
self.enterResting, self.exitResting,
|
|
['Elevator']),
|
|
State.State('Reward', self.enterReward, self.exitReward,
|
|
['Off']),
|
|
State.State('Off',
|
|
self.enterOff, self.exitOff,
|
|
['WaitForAllToonsInside'])
|
|
], 'Off', 'Off', onUndefTransition=ClassicFSM.ClassicFSM.ALLOW)
|
|
self.fsm.enterInitialState()
|
|
|
|
def delete(self):
|
|
self.ignoreAll()
|
|
self.toons = []
|
|
self.toonIds = []
|
|
self.fsm.requestFinalState()
|
|
del self.fsm
|
|
del self.bldg
|
|
del self.elevator
|
|
self.timer.stop()
|
|
del self.timer
|
|
self.__cleanupFloorBattle()
|
|
taskName = self.taskName('deleteInterior')
|
|
taskMgr.remove(taskName)
|
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|
|
|
|
def __handleUnexpectedExit(self, toonId):
|
|
self.notify.warning('toon: %d exited unexpectedly' % toonId)
|
|
self.__removeToon(toonId)
|
|
if len(self.toons) == 0:
|
|
self.timer.stop()
|
|
if self.fsm.getCurrentState().getName() == 'Resting':
|
|
return
|
|
elif self.battle is None:
|
|
self.bldg.deleteSuitInterior()
|
|
|
|
def __addToon(self, toonId):
|
|
if toonId not in self.air.doId2do:
|
|
self.notify.warning('addToon() - no toon for doId: %d' % toonId)
|
|
return
|
|
event = self.air.getAvatarExitEvent(toonId)
|
|
self.avatarExitEvents.append(event)
|
|
self.accept(event, self.__handleUnexpectedExit, extraArgs=[toonId])
|
|
self.toons.append(toonId)
|
|
self.responses[toonId] = 0
|
|
|
|
def __removeToon(self, toonId):
|
|
if toonId in self.toons:
|
|
self.toons.remove(toonId)
|
|
if toonId in self.toonIds:
|
|
self.toonIds[self.toonIds.index(toonId)] = None
|
|
if toonId in self.responses:
|
|
del self.responses[toonId]
|
|
event = self.air.getAvatarExitEvent(toonId)
|
|
if self.avatarExitEvents.count(event):
|
|
self.avatarExitEvents.remove(event)
|
|
self.ignore(event)
|
|
|
|
def __resetResponses(self):
|
|
self.responses = {}
|
|
for toon in self.toons:
|
|
self.responses[toon] = 0
|
|
self.ignoreResponses = 0
|
|
|
|
def __allToonsResponded(self):
|
|
for toon in self.toons:
|
|
if self.responses[toon] == 0:
|
|
return 0
|
|
self.ignoreResponses = 1
|
|
return 1
|
|
|
|
def getZoneId(self):
|
|
return self.zoneId
|
|
|
|
def getExtZoneId(self):
|
|
return self.extZoneId
|
|
|
|
def getDistBldgDoId(self):
|
|
return self.bldg.getDoId()
|
|
|
|
def getNumFloors(self):
|
|
return self.numFloors
|
|
|
|
def d_setToons(self):
|
|
self.sendUpdate('setToons', self.getToons())
|
|
|
|
def getToons(self):
|
|
sendIds = []
|
|
for toonId in self.toonIds:
|
|
if toonId is None:
|
|
sendIds.append(0)
|
|
else:
|
|
sendIds.append(toonId)
|
|
return [sendIds, 0]
|
|
|
|
def d_setSuits(self):
|
|
self.sendUpdate('setSuits', self.getSuits())
|
|
|
|
def getSuits(self):
|
|
suitIds = []
|
|
for suit in self.activeSuits:
|
|
suitIds.append(suit.doId)
|
|
reserveIds = []
|
|
values = []
|
|
for info in self.reserveSuits:
|
|
reserveIds.append(info[0].doId)
|
|
values.append(info[1])
|
|
return [suitIds, reserveIds, values]
|
|
|
|
def b_setState(self, state):
|
|
self.d_setState(state)
|
|
self.setState(state)
|
|
|
|
def d_setState(self, state):
|
|
stime = globalClock.getRealTime() + BattleBase.SERVER_BUFFER_TIME
|
|
self.sendUpdate('setState', [
|
|
state, globalClockDelta.localToNetworkTime(stime)])
|
|
|
|
def setState(self, state):
|
|
self.fsm.request(state)
|
|
|
|
def getState(self):
|
|
return [self.fsm.getCurrentState().getName(),
|
|
globalClockDelta.getRealNetworkTime()]
|
|
|
|
def setAvatarJoined(self):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
if self.toons.count(avId) == 0:
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedSuitInteriorAI.setAvatarJoined from toon not in %s.' % self.toons)
|
|
self.notify.warning('setAvatarJoined() - av: %d not in list' % avId)
|
|
return
|
|
avatar = self.air.doId2do.get(avId)
|
|
if avatar is not None:
|
|
self.savedByMap[avId] = (avatar.getName(), avatar.dna.asTuple())
|
|
self.responses[avId] += 1
|
|
if self.__allToonsResponded():
|
|
self.fsm.request('Elevator')
|
|
|
|
def elevatorDone(self):
|
|
toonId = self.air.getAvatarIdFromSender()
|
|
if self.ignoreResponses == 1:
|
|
return
|
|
elif self.fsm.getCurrentState().getName() != 'Elevator':
|
|
self.notify.warning('elevatorDone() - in state: %s' % self.fsm.getCurrentState().getName())
|
|
return
|
|
elif self.toons.count(toonId) == 0:
|
|
self.notify.warning('elevatorDone() - toon not in toon list: %d' % toonId)
|
|
return
|
|
self.responses[toonId] += 1
|
|
if self.__allToonsResponded() and self.ignoreElevatorDone == 0:
|
|
self.b_setState('Battle')
|
|
|
|
def reserveJoinDone(self):
|
|
toonId = self.air.getAvatarIdFromSender()
|
|
if self.ignoreResponses == 1:
|
|
return
|
|
elif self.fsm.getCurrentState().getName() != 'ReservesJoining':
|
|
self.notify.warning('reserveJoinDone() - in state: %s' % self.fsm.getCurrentState().getName())
|
|
return
|
|
elif self.toons.count(toonId) == 0:
|
|
self.notify.warning('reserveJoinDone() - toon not in list: %d' % toonId)
|
|
return
|
|
self.responses[toonId] += 1
|
|
if self.__allToonsResponded() and self.ignoreReserveJoinDone == 0:
|
|
self.b_setState('Battle')
|
|
|
|
def enterOff(self):
|
|
pass
|
|
|
|
def exitOff(self):
|
|
pass
|
|
|
|
def enterWaitForAllToonsInside(self):
|
|
self.__resetResponses()
|
|
|
|
def exitWaitForAllToonsInside(self):
|
|
self.__resetResponses()
|
|
|
|
def enterElevator(self):
|
|
suitHandles = self.bldg.planner.genFloorSuits(self.currentFloor)
|
|
self.suits = suitHandles['activeSuits']
|
|
self.activeSuits = []
|
|
for suit in self.suits:
|
|
self.activeSuits.append(suit)
|
|
self.reserveSuits = suitHandles['reserveSuits']
|
|
self.d_setToons()
|
|
self.d_setSuits()
|
|
self.__resetResponses()
|
|
self.d_setState('Elevator')
|
|
self.timer.startCallback(BattleBase.ELEVATOR_T + ElevatorData[ELEVATOR_NORMAL]['openTime'] + BattleBase.SERVER_BUFFER_TIME, self.__serverElevatorDone)
|
|
|
|
def __serverElevatorDone(self):
|
|
self.ignoreElevatorDone = 1
|
|
self.b_setState('Battle')
|
|
|
|
def exitElevator(self):
|
|
self.timer.stop()
|
|
self.__resetResponses()
|
|
|
|
def __createFloorBattle(self):
|
|
if self.currentFloor == self.topFloor:
|
|
bossBattle = 1
|
|
else:
|
|
bossBattle = 0
|
|
self.battle = DistributedBattleBldgAI.DistributedBattleBldgAI(self.air, self.zoneId, self.__handleRoundDone, self.__handleBattleDone, bossBattle = bossBattle)
|
|
self.battle.suitsKilled = self.suitsKilled
|
|
self.battle.suitsKilledPerFloor = self.suitsKilledPerFloor
|
|
self.battle.battleCalc.toonSkillPtsGained = self.toonSkillPtsGained
|
|
self.battle.toonExp = self.toonExp
|
|
self.battle.toonOrigQuests = self.toonOrigQuests
|
|
self.battle.toonItems = self.toonItems
|
|
self.battle.toonOrigMerits = self.toonOrigMerits
|
|
self.battle.toonMerits = self.toonMerits
|
|
self.battle.toonParts = self.toonParts
|
|
self.battle.helpfulToons = self.helpfulToons
|
|
self.battle.setInitialMembers(self.toons, self.suits)
|
|
self.battle.generateWithRequired(self.zoneId)
|
|
mult = getCreditMultiplier(self.currentFloor)
|
|
if self.air.suitInvasionManager.getInvading():
|
|
mult *= getInvasionMultiplier()
|
|
self.battle.battleCalc.setSkillCreditMultiplier(mult)
|
|
|
|
def __cleanupFloorBattle(self):
|
|
for suit in self.suits:
|
|
self.notify.debug('cleaning up floor suit: %d' % suit.doId)
|
|
if suit.isDeleted():
|
|
self.notify.debug('whoops, suit %d is deleted.' % suit.doId)
|
|
continue
|
|
suit.requestDelete()
|
|
self.suits = []
|
|
self.reserveSuits = []
|
|
self.activeSuits = []
|
|
if self.battle != None:
|
|
self.battle.requestDelete()
|
|
self.battle = None
|
|
|
|
def __handleRoundDone(self, toonIds, totalHp, deadSuits):
|
|
totalMaxHp = 0
|
|
for suit in self.suits:
|
|
totalMaxHp += suit.maxHP
|
|
|
|
for suit in deadSuits:
|
|
self.activeSuits.remove(suit)
|
|
|
|
if len(self.reserveSuits) > 0 and len(self.activeSuits) < 4:
|
|
self.joinedReserves = []
|
|
hpPercent = 100 - (totalHp / totalMaxHp) * 100.0
|
|
for info in self.reserveSuits:
|
|
if info[1] <= hpPercent and len(self.activeSuits) < 4:
|
|
self.suits.append(info[0])
|
|
self.activeSuits.append(info[0])
|
|
self.joinedReserves.append(info)
|
|
|
|
for info in self.joinedReserves:
|
|
self.reserveSuits.remove(info)
|
|
|
|
if len(self.joinedReserves) > 0:
|
|
self.fsm.request('ReservesJoining')
|
|
self.d_setSuits()
|
|
return
|
|
if len(self.activeSuits) == 0:
|
|
self.fsm.request('BattleDone', [toonIds])
|
|
else:
|
|
self.battle.resume()
|
|
|
|
def __handleBattleDone(self, zoneId, toonIds):
|
|
if len(toonIds) == 0:
|
|
taskName = self.taskName('deleteInterior')
|
|
taskMgr.doMethodLater(10, self.__doDeleteInterior, taskName)
|
|
elif self.currentFloor == self.topFloor:
|
|
self.setState('Reward')
|
|
else:
|
|
self.b_setState('Resting')
|
|
|
|
def __doDeleteInterior(self, task):
|
|
self.bldg.deleteSuitInterior()
|
|
|
|
def enterBattle(self):
|
|
if self.battle is None:
|
|
self.__createFloorBattle()
|
|
self.elevator.d_setFloor(self.currentFloor)
|
|
|
|
def exitBattle(self):
|
|
pass
|
|
|
|
def enterReservesJoining(self):
|
|
self.__resetResponses()
|
|
self.timer.startCallback(ElevatorData[ELEVATOR_NORMAL]['openTime'] + SUIT_HOLD_ELEVATOR_TIME + BattleBase.SERVER_BUFFER_TIME, self.__serverReserveJoinDone)
|
|
|
|
def __serverReserveJoinDone(self):
|
|
self.ignoreReserveJoinDone = 1
|
|
self.b_setState('Battle')
|
|
|
|
def exitReservesJoining(self):
|
|
self.timer.stop()
|
|
self.__resetResponses()
|
|
for info in self.joinedReserves:
|
|
self.battle.suitRequestJoin(info[0])
|
|
self.battle.resume()
|
|
self.joinedReserves = []
|
|
|
|
def enterBattleDone(self, toonIds):
|
|
if len(toonIds) != len(self.toons):
|
|
deadToons = []
|
|
for toon in self.toons:
|
|
if toonIds.count(toon) == 0:
|
|
deadToons.append(toon)
|
|
continue
|
|
for toon in deadToons:
|
|
self.__removeToon(toon)
|
|
self.d_setToons()
|
|
if len(self.toons) == 0:
|
|
self.bldg.deleteSuitInterior()
|
|
elif self.currentFloor == self.topFloor:
|
|
self.battle.resume(self.currentFloor, topFloor = 1)
|
|
else:
|
|
self.battle.resume(self.currentFloor, topFloor = 0)
|
|
|
|
def exitBattleDone(self):
|
|
self.__cleanupFloorBattle()
|
|
|
|
def __handleEnterElevator(self):
|
|
self.fsm.request('Elevator')
|
|
|
|
def enterResting(self):
|
|
self.intElevator = DistributedElevatorIntAI.DistributedElevatorIntAI(self.air, self, self.toons)
|
|
self.intElevator.generateWithRequired(self.zoneId)
|
|
|
|
def handleAllAboard(self, seats):
|
|
if not hasattr(self, 'fsm'):
|
|
return
|
|
numOfEmptySeats = seats.count(None)
|
|
if numOfEmptySeats == 4:
|
|
self.bldg.deleteSuitInterior()
|
|
return
|
|
elif numOfEmptySeats >= 0 and numOfEmptySeats <= 3:
|
|
pass
|
|
else:
|
|
self.error('Bad number of empty seats: %s' % numOfEmptySeats)
|
|
for toon in self.toons:
|
|
if seats.count(toon) == 0:
|
|
self.__removeToon(toon)
|
|
continue
|
|
self.toonIds = copy.copy(seats)
|
|
self.toons = []
|
|
for toonId in self.toonIds:
|
|
if toonId != None:
|
|
self.toons.append(toonId)
|
|
continue
|
|
self.d_setToons()
|
|
self.currentFloor += 1
|
|
self.fsm.request('Elevator')
|
|
|
|
def exitResting(self):
|
|
self.intElevator.requestDelete()
|
|
del self.intElevator
|
|
|
|
def enterReward(self):
|
|
victors = self.toonIds[:]
|
|
savedBy = []
|
|
for v in victors:
|
|
tuple = self.savedByMap.get(v)
|
|
if tuple:
|
|
savedBy.append([v, tuple[0], tuple[1]])
|
|
continue
|
|
self.bldg.fsm.request('waitForVictors', [victors, savedBy])
|
|
self.d_setState('Reward')
|
|
|
|
def exitReward(self):
|
|
pass
|