Poodletooth-iLand/toontown/cogdominium/DistributedCogdoInteriorAI.py

560 lines
19 KiB
Python
Raw Normal View History

2015-03-03 16:10:12 -06:00
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedObjectAI import DistributedObjectAI
2015-03-06 20:46:05 -06:00
from direct.distributed.ClockDelta import *
from direct.fsm import FSM
from direct.task import Timer
from toontown.battle import BattleBase
from toontown.building.ElevatorConstants import *
from toontown.toonbase.ToontownGlobals import *
from toontown.toonbase.ToontownBattleGlobals import *
import DistCogdoMazeGameAI, CogdoMazeGameGlobals, DistributedCogdoElevatorIntAI
import DistCogdoFlyingGameAI, DistributedCogdoBarrelAI
from DistributedCogdoBattleBldgAI import DistributedCogdoBattleBldgAI
from SuitPlannerCogdoInteriorAI import SuitPlannerCogdoInteriorAI
from toontown.cogdominium import CogdoBarrelRoomConsts
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
from toontown.toon import NPCToons
import random, math
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
NUM_FLOORS_DICT = {
's': 1,
'l': 2,
'm':1,
'c': 1
}
BATTLE_INTRO_DURATION = 10
BARREL_INTRO_DURATION = 12
BARREL_ROOM_DURATION = 30
BARREL_ROOM_REWARD_DURATION = 7
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
class DistributedCogdoInteriorAI(DistributedObjectAI, FSM.FSM):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedCogdoInteriorAI")
def __init__(self, air, exterior):
DistributedObjectAI.__init__(self, air)
FSM.FSM.__init__(self, 'CogdoInteriorAIFSM')
self.toons = filter(None, exterior.elevator.seats[:])
self.responses = {}
self.bldgDoId = exterior.doId
self.numFloors = NUM_FLOORS_DICT[exterior.track]
self.sosNPC = self.__generateSOS(exterior.difficulty)
self.shopOwnerNpcId = 0
self.extZoneId, self.zoneId = exterior.getExteriorAndInteriorZoneId()
npcIdList = NPCToons.zone2NpcDict.get(self.zoneId, [])
if len(npcIdList) == 0:
self.notify.info('No NPC in taken cogdo at %s' % self.zoneId)
else:
if len(npcIdList) > 1:
self.notify.warning('Multiple NPCs in taken cogdo at %s' % self.zoneId)
self.shopOwnerNpcId = npcIdList[0]
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
self.gameDone = 0
self.bossBattleDone = 0
self.curFloor = 0
self.topFloor = 2
self.timer = Timer.Timer()
self.exterior = exterior
self.planner = self.exterior.planner
self.savedByMap = { }
self.battle = None
self.FOType = exterior.track
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
self.gameFloor = 1
self.battleFloor = 2
self.barrelFloor = -1
if self.FOType == 'l':
self.battleFloor = 3
self.barrelFloor = 2
self.topFloor += 1
self.toonSkillPtsGained = { }
self.toonExp = { }
self.toonOrigQuests = { }
self.toonItems = { }
self.toonOrigMerits = { }
self.toonMerits = { }
self.toonParts = { }
self.helpfulToons = []
self.barrels = []
self.suits = []
self.activeSuits = []
self.reserveSuits = []
self.joinedReserves = []
self.suitsKilled = []
self.suitsKilledPerFloor = []
self.ignoreResponses = 0
self.ignoreElevatorDone = 0
self.ignoreReserveJoinDone = 0
def __generateSOS(self, difficulty):
g = lambda: random.choice(NPCToons.FOnpcFriends.keys())
v = g()
getStars = lambda x: NPCToons.getNPCTrackLevelHpRarity(x)[-1]
maxStars = min(2, int(math.ceil(difficulty / 5.)))
minStars = max(0, maxStars - 1)
while not (minStars <= getStars(v) <= maxStars):
v = g()
self.notify.info('selected SOS %s (stars = %s)' % (v, getStars(v)))
return v
def setZoneId(self, zoneId):
self.zoneId = zoneId
def getZoneId(self):
return self.zoneId
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
def setExtZoneId(self, extZoneId):
self.extZoneId = extZoneId
def getExtZoneId(self):
return self.extZoneId
def setDistBldgDoId(self, bldgDoId):
self.bldgDoId = bldgDoId
def getDistBldgDoId(self):
return self.bldgDoId
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
def setNumFloors(self, numFloors):
self.numFloors = numFloors
def getNumFloors(self):
return self.numFloors
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
def setShopOwnerNpcId(self, id):
self.shopOwnerNpcId = id
def getShopOwnerNpcId(self):
return self.shopOwnerNpcId
def setState(self, state, timestamp):
self.request(state)
def getState(self):
timestamp = globalClockDelta.getRealNetworkTime()
return [self.state, timestamp]
def b_setState(self, state):
self.setState(state, 0)
self.d_setState(state)
def d_setState(self, state):
timestamp = globalClockDelta.getRealNetworkTime()
self.sendUpdate('setState', [state, timestamp])
2015-03-03 16:10:12 -06:00
def reserveJoinDone(self):
2015-03-06 20:46:05 -06:00
toonId = self.air.getAvatarIdFromSender()
if self.ignoreResponses == 1:
return None
elif self.toons.count(toonId) == 0:
self.notify.warning('reserveJoinDone() - toon not in list: %d' % toonId)
return None
self.b_setState('Battle')
def elevatorDone(self):
toonId = self.air.getAvatarIdFromSender()
if self.ignoreResponses == 1:
return None
elif self.toons.count(toonId) == 0:
self.notify.warning('elevatorDone() - toon not in toon list: %d' % toonId)
def enterWaitForAllToonsInside(self):
self.resetResponses()
if self.FOType == "s":
self.game = DistCogdoMazeGameAI.DistCogdoMazeGameAI(self.air)
self.game.setNumSuits(CogdoMazeGameGlobals.NumSuits)
elif self.FOType == "l":
self.game = DistCogdoFlyingGameAI.DistCogdoFlyingGameAI(self.air)
elif self.FOType == "m":
self.game = DistCogdoCraneGameAI.DistCogdoCraneGameAI(self.air)
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
self.sendUpdate("setSOSNpcId", [self.sosNPC])
self.sendUpdate("setFOType", [ord(self.FOType)])
def resetResponses(self):
for toon in self.toons:
self.responses[toon] = 0
def setAvatarJoined(self):
avId = self.air.getAvatarIdFromSender()
self.responses[avId] = 1
avatar = self.air.doId2do.get(avId)
if avatar != None:
self.savedByMap[avId] = (avatar.getName(), avatar.dna.asTuple())
self.addToon(avId)
if self.allToonsJoined():
self.request('Elevator')
def addToon(self, avId):
if not avId in self.toons:
self.toons.append(avId)
if self.air.doId2do.has_key(avId):
event = self.air.getAvatarExitEvent(avId)
self.accept(event, self.__handleUnexpectedExit, [avId])
def __handleUnexpectedExit(self, avId):
self.removeToon(avId)
if len(self.toons) == 0:
self.exterior.deleteSuitInterior()
if self.battle:
self.battle.requestDelete()
self.battle = None
def removeToon(self, avId):
if avId in self.toons: self.toons.pop(avId)
def enterElevator(self):
self.curFloor += 1
self.d_setToons()
self.resetResponses()
if self.curFloor == self.gameFloor:
self.enterGame()
self.d_setState('Elevator')
self.timer.stop()
self.timer.startCallback(BattleBase.ELEVATOR_T + ElevatorData[ELEVATOR_NORMAL]['openTime'] + BattleBase.SERVER_BUFFER_TIME, self.serverElevatorDone)
if self.curFloor == self.battleFloor:
self.planner.myPrint()
suitHandles = self.planner.genFloorSuits(0)
self.suits = suitHandles['activeSuits']
self.activeSuits = self.suits[:]
self.reserveSuits = suitHandles['reserveSuits']
self.d_setSuits()
def exitElevator(self):
self.timer.stop()
def serverElevatorDone(self):
if self.curFloor == self.gameFloor:
self.d_setState('Game')
elif self.curFloor == self.battleFloor:
self.b_setState('BattleIntro')
self.timer.startCallback(BATTLE_INTRO_DURATION, self.battleIntroDone)
else:
self.notify.warning('Unknown floor %s (track=%s)' % (self.curFloor, self.FOType))
def battleIntroDone(self):
if self.air:
self.createBattle()
self.b_setState('Battle')
def barrelIntroDone(self):
if not self.air:
return
self.b_setState('CollectBarrels')
for i in xrange(len(CogdoBarrelRoomConsts.BarrelProps)):
barrel = DistributedCogdoBarrelAI.DistributedCogdoBarrelAI(self.air, i)
barrel.generateWithRequired(self.zoneId)
self.barrels.append(barrel)
self.timer.startCallback(BARREL_ROOM_DURATION, self.barrelReward)
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
def barrelReward(self):
if not self.air:
return
self.b_setState('BarrelRoomReward')
for i in self.barrels:
i.requestDelete()
self.timer.startCallback(BARREL_ROOM_REWARD_DURATION, self.barrelRewardDone)
def barrelRewardDone(self):
if not self.air:
return
barrelPlanner = SuitPlannerCogdoInteriorAI(self.exterior._cogdoLayout, max(0, self.exterior.difficulty - 5),
self.FOType, self.exterior.getExteriorAndInteriorZoneId()[1])
barrelPlanner.myPrint()
suitHandles = barrelPlanner.genFloorSuits(0)
self.suits = suitHandles['activeSuits']
self.activeSuits = self.suits[:]
self.reserveSuits = suitHandles['reserveSuits']
self.d_setSuits()
self.battleIntroDone()
def handleAllAboard(self, seats):
if not hasattr(self, 'air') or not self.air:
return None
numOfEmptySeats = seats.count(None)
if numOfEmptySeats == 4:
self.exterior.deleteSuitInterior()
return
elif not 0 <= numOfEmptySeats <= 3:
self.notify.error('Bad number of empty seats: %s' % numOfEmptySeats)
for toon in self.toons:
if toon not in seats:
self.removeToon(toon)
self.toons = filter(None, seats)
self.d_setToons()
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
self.request('Elevator')
def enterGame(self):
self.game.setToons(self.toons)
self.game.setInteriorId(self.doId)
self.game.setExteriorZone(self.exterior.zoneId)
self.game.setDifficultyOverrides(2147483647, -1)
self.game.generateWithRequired(self.zoneId)
self.game.d_startIntro()
self.accept(self.game.finishEvent, self.__handleGameDone)
self.accept(self.game.gameOverEvent, self.__handleGameOver)
def __handleGameDone(self, toons):
self.game.requestDelete()
self.gameDone = 1
self.toons = toons
if self.curFloor == self.barrelFloor - 1:
self.curFloor += 1
self.d_setToons()
self.resetResponses()
self.b_setState('BarrelRoomIntro')
self.timer.startCallback(BARREL_INTRO_DURATION, self.barrelIntroDone)
else:
self.request('Elevator')
def __handleGameOver(self):
self.game.requestDelete()
self.exterior.deleteSuitInterior()
def createBattle(self):
isBoss = self.curFloor == self.topFloor
self.battle = DistributedCogdoBattleBldgAI(self.air, self.zoneId, self.__handleRoundDone, self.__handleBattleDone, bossBattle = isBoss)
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.curFloor)
self.battle.battleCalc.setSkillCreditMultiplier(self.battle.battleCalc.getSkillCreditMultiplier() * mult)
def enterBattleDone(self, toonIds):
toonIds = toonIds[0]
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.exterior.deleteSuitInterior()
elif self.curFloor == self.topFloor:
self.battle.resume(self.curFloor, topFloor = 1)
else:
self.battle.resume(self.curFloor, topFloor = 0)
def __doDeleteInterior(self, task):
self.exterior.deleteSuitInterior()
return task.done
def exitBattleDone(self):
self.cleanupFloorBattle()
def cleanupFloorBattle(self):
for suit in self.suits:
if suit.isDeleted():
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)
continue
for info in self.joinedReserves:
self.reserveSuits.remove(info)
if len(self.joinedReserves) > 0:
self.d_setSuits()
self.request('ReservesJoining')
return
if len(self.activeSuits) == 0:
self.request('BattleDone', [
toonIds])
else:
self.battle.resume()
def enterReservesJoining(self):
self.resetResponses()
self.timer.startCallback(ElevatorData[ELEVATOR_NORMAL]['openTime'] + SUIT_HOLD_ELEVATOR_TIME + BattleBase.SERVER_BUFFER_TIME, self.serverReserveJoinDone)
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
def exitReservesJoining(self):
self.timer.stop()
self.resetResponses()
for info in self.joinedReserves:
self.battle.suitRequestJoin(info[0])
self.battle.resume()
self.joinedReserves = []
def serverReserveJoinDone(self):
self.ignoreReserveJoinDone = 1
self.b_setState('Battle')
def __handleBattleDone(self, zoneId, toonIds):
if len(toonIds) == 0:
taskMgr.doMethodLater(10, self.__doDeleteInterior, self.taskName('deleteInterior'))
elif self.curFloor == self.topFloor:
self.request('Reward')
else:
self.b_setState('Resting')
def enterResting(self):
self.intElevator = DistributedCogdoElevatorIntAI.DistributedCogdoElevatorIntAI(self.air, self, self.toons)
self.intElevator.generateWithRequired(self.zoneId)
def exitResting(self):
self.intElevator.requestDelete()
def enterReward(self):
victors = self.toons[:]
savedBy = []
for v in victors:
tuple = self.savedByMap.get(v)
if tuple:
savedBy.append([
v,
tuple[0],
tuple[1]])
toon = self.air.doId2do.get(v)
if toon:
if self.FOType == 's':
2015-04-10 06:08:35 -05:00
if not toon.attemptAddNPCFriend(self.sosNPC):
2015-03-06 20:46:05 -06:00
self.notify.info('%s unable to add NPCFriend %s to %s.' % (self.doId, self.sosNPC, v))
elif self.FOType == 'l':
reward = self.getEmblemsReward()
toon.addEmblems(reward)
else:
self.notify.warning('%s unable to reward %s: unknown reward for track %s' % (self.doId, v, self.FOType))
self.exterior.fsm.request('waitForVictorsFromCogdo', [
victors,
savedBy])
self.d_setState('Reward')
def removeToon(self, toonId):
if self.toons.count(toonId):
self.toons.remove(toonId)
def d_setToons(self):
self.sendUpdate('setToons', self.getToons())
def getToons(self):
return [self.toons, 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 allToonsJoined(self):
for toon in self.toons:
if self.responses[toon] == 0:
return 0
return 1
2015-03-03 16:10:12 -06:00
2015-03-06 20:46:05 -06:00
def delete(self):
DistributedObjectAI.delete(self)
self.timer.stop()
def getEmblemsReward(self):
hoodIdMap = {2: .5, # ttc
1: 1., # dd
5: 1.5, # dg
4: 2., # mm
3: 2.7, # br
9: 3.5, # dl
7: 4 # ff
}
hoodValue = hoodIdMap[int(self.exterior.zoneId // 1000)]
diff = max(self.exterior.difficulty, 1)
memos = self.game.getTotalMemos()
E = (hoodValue * max(memos, 1) * diff) / 2.5
return divmod(E, 100)[::-1]