text: from otp.otpbase import OTPGlobals
  from otp.ai.AIBase import *
  from toontown.toonbase import ToontownGlobals
  from direct.distributed.ClockDelta import *
  from ElevatorConstants import *
  from direct.distributed import DistributedObjectAI
  from direct.fsm import ClassicFSM, State
  from direct.fsm import State
  from direct.task import Task
  from direct.directnotify import DirectNotifyGlobal
  from toontown.building import BoardingPartyBase
  GROUPMEMBER = 0
  GROUPINVITE = 1
  
  class DistributedBoardingPartyAI(DistributedObjectAI.DistributedObjectAI, BoardingPartyBase.BoardingPartyBase):
      notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBoardingPartyAI')
  
      def __init__(self, air, elevatorList, maxSize = 4):
          DistributedObjectAI.DistributedObjectAI.__init__(self, air)
          BoardingPartyBase.BoardingPartyBase.__init__(self)
          self.setGroupSize(maxSize)
          self.elevatorIdList = elevatorList
          self.visibleZones = []
  
      def delete(self):
          self.cleanup()
          DistributedObjectAI.DistributedObjectAI.delete(self)
  
      def generate(self):
          DistributedObjectAI.DistributedObjectAI.generate(self)
          for elevatorId in self.elevatorIdList:
              elevator = simbase.air.doId2do.get(elevatorId)
              elevator.setBoardingParty(self)
  
          '''
          store = simbase.air.dnaStoreMap.get(self.zoneId)
          if store:
              numVisGroups = store.getNumDNAVisGroupsAI()
              myVisGroup = None
              for index in xrange(numVisGroups):
                  if store.getDNAVisGroupAI(index).getName() == str(self.zoneId):
                      myVisGroup = store.getDNAVisGroupAI(index)
  
              if myVisGroup:
                  numVisibles = myVisGroup.getNumVisibles()
                  for index in xrange(numVisibles):
                      newVisible = myVisGroup.getVisibleName(index)
                      self.visibleZones.append(int(newVisible))
  
              else:
                  self.visibleZones = [self.zoneId]
          else:
              self.visibleZones = [self.zoneId]
          '''
          return
  
      def cleanup(self):
          BoardingPartyBase.BoardingPartyBase.cleanup(self)
          del self.elevatorIdList
          del self.visibleZones
  
      def getElevatorIdList(self):
          return self.elevatorIdList
  
      def setElevatorIdList(self, elevatorIdList):
          self.elevatorIdList = elevatorIdList
  
      def addWacthAvStatus(self, avId):
          self.acceptOnce(self.air.getAvatarExitEvent(avId), self.handleAvatarDisco, extraArgs=[avId])
          self.accept(self.staticGetLogicalZoneChangeEvent(avId), self.handleAvatarZoneChange, extraArgs=[avId])
          messageToonAdded = 'Battle adding toon %s' % avId
          self.accept(messageToonAdded, self.handleToonJoinedBattle)
          messageToonReleased = 'Battle releasing toon %s' % avId
          self.accept(messageToonReleased, self.handleToonLeftBattle)
  
      def handleToonJoinedBattle(self, avId):
          self.notify.debug('handleToonJoinedBattle %s' % avId)
  
      def handleToonLeftBattle(self, avId):
          self.notify.debug('handleToonLeftBattle %s' % avId)
  
      def removeWacthAvStatus(self, avId):
          self.ignore(self.air.getAvatarExitEvent(avId))
          self.ignore(self.staticGetLogicalZoneChangeEvent(avId))
  
      # BoardingParty data model
      #
      # groupList[0] - people in the group
      # groupList[1] - people invited to the group
      # groupList[2] - people kicked from the group
      #
      # avIdDict - lookup from player to the leader of the group they are in
      #     if you are in a group or have been invited to a group, you
      #     are in this dictionary with a pointer to the leader of the
      #     group.   The only exception to this is if you were invited
      #     to merge groups.
      # mergeDict - This is a link that points back to the original
      #     invitee before we mapped it to the leader of the other group.
             
      def requestInvite(self, inviteeId):
          self.notify.debug('requestInvite %s' % inviteeId)
          inviterId = self.air.getAvatarIdFromSender()
          invitee = simbase.air.doId2do.get(inviteeId)
          originalInviteeId = inviteeId
          merger = False
          if invitee and invitee.battleId != 0:
              reason = BoardingPartyBase.BOARDCODE_BATTLE
              self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
              self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
              return
          if self.hasPendingInvite(inviteeId):
              reason = BoardingPartyBase.BOARDCODE_PENDING_INVITE
              self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
              self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
              return
          if self.__isInElevator(inviteeId):
              reason = BoardingPartyBase.BOARDCODE_IN_ELEVATOR
              self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
              self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
              return
          if self.hasActiveGroup(inviteeId):
              # We could make the assumption both are in the avIdDict but I'd prefer not to blow up the district
              if self.hasActiveGroup(inviterId):
                  inviteeLeaderId = self.avIdDict[inviteeId]
                  leaderId = self.avIdDict[inviterId]
  
                  # group merge already requested?
                  if self.hasPendingInvite(inviteeLeaderId):
                      reason = BoardingPartyBase.BOARDCODE_PENDING_INVITE
                      self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
                      self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
                      return
  
                  if ((len(self.getGroupMemberList(leaderId)) + len(self.getGroupMemberList(inviteeLeaderId))) <= self.maxSize):
                      # Lets send the invitation to the person in authority...
                      invitee = simbase.air.doId2do.get(inviteeLeaderId)
                      inviteeId = inviteeLeaderId
                      merger = True
                  else:
                      reason = BoardingPartyBase.BOARDCODE_GROUPS_TO_LARGE
                      self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
                      self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
                      return
              else:
                  reason = BoardingPartyBase.BOARDCODE_DIFF_GROUP
                  self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
                  self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
                  return
          # Lets see what the invitee is currently doing
          inviteeOkay = self.checkBoard(inviteeId, self.elevatorIdList[0])
          reason = 0
          # Oh, for the days when we are charging for this game.. :)
          if inviteeOkay == REJECT_NOTPAID:
              reason = BoardingPartyBase.BOARDCODE_NOT_PAID
              self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
              return
          # I know there is an unexpected issue here when we are merging groups... lets think about this really hard..
          if len(self.elevatorIdList) == 1:
              if inviteeOkay:
                  if inviteeOkay == REJECT_MINLAFF:
                      reason = BoardingPartyBase.BOARDCODE_MINLAFF
                  elif inviteeOkay == REJECT_PROMOTION:
                      reason = BoardingPartyBase.BOARDCODE_PROMOTION
                  self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, self.elevatorIdList[0]])
                  return
              else:
                  inviterOkay = self.checkBoard(inviterId, self.elevatorIdList[0])
                  if inviterOkay:
                      if inviterOkay == REJECT_MINLAFF:
                          reason = BoardingPartyBase.BOARDCODE_MINLAFF
                      elif inviterOkay == REJECT_PROMOTION:
                          reason = BoardingPartyBase.BOARDCODE_PROMOTION
                      self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviterId, reason, self.elevatorIdList[0]])
                      return
          # Is the inviter already in the avIdDict?  It follows they either must be in a group or have a pending invite... 
          if inviterId in self.avIdDict:
              self.notify.debug('old group')
              # Everything is indexed by the leaders
              leaderId = self.avIdDict[inviterId]
              groupList = self.groupListDict.get(leaderId)
              if groupList:  # One would hope we have a group...
                  self.notify.debug('got group list')
                  # Only the leader of a group can invite somebody who was kicked out back in
                  if inviterId == leaderId:
                      # The invitee was kicked out so lets let them back in again
                      if inviteeId in groupList[2]:
                          groupList[2].remove(inviteeId)
                  # Is the group already oversized?
                  if len(self.getGroupMemberList(leaderId)) >= self.maxSize:
                      self.sendUpdate('postSizeReject', [leaderId, inviterId, inviteeId])
                  elif merger:
                      # We cannot muck with the avIdDict because they are pointing to their original groups. 
                      # We shall stash away the info into a different
                      # dictionary.. This way, if something goes wrong,
                      # the original groups  with their original data
                      # structures are untouched.   The mergeDict gives
                      # us a pointer back to where the original invite
                      # went to so that we can issue a notice to close
                      # the appropriate invite dialog
                      self.mergeDict[inviteeId] = originalInviteeId
                      self.sendUpdateToAvatarId(inviteeId, 'postInvite', [leaderId, inviterId, True])
                      # notify everybody in the inviters group of the
                      # invitation.. 
                      for memberId in groupList[0]:
                          if not memberId == inviterId:
                              self.sendUpdateToAvatarId(memberId, 'postMessageInvited', [inviteeId, inviterId])
                  elif inviterId not in groupList[1] and inviterId not in groupList[2]:
                      # If the invitee isn't already in the group, add them.. 
                      if inviteeId not in groupList[1]:
                          groupList[1].append(inviteeId)
                      self.groupListDict[leaderId] = groupList
                      if inviteeId in self.avIdDict:
                          self.notify.warning('inviter %s tried to invite %s who already exists in the avIdDict.' % (inviterId, inviteeId))
                          self.air.writeServerEvent('suspicious: inviter', inviterId, ' tried to invite %s who already exists in the avIdDict.' % inviteeId)
                      self.avIdDict[inviteeId] = leaderId
                      self.sendUpdateToAvatarId(inviteeId, 'postInvite', [leaderId, inviterId, False])
                      # notify everybody of the invitation..
                      for memberId in groupList[0]:
                          if not memberId == inviterId:
                              self.sendUpdateToAvatarId(memberId, 'postMessageInvited', [inviteeId, inviterId])
                  # The inviter was kicked.. so, we cannot let them back in since they are not the leader...           
                  elif inviterId in groupList[2]:
                      self.sendUpdate('postKickReject', [leaderId, inviterId, inviteeId])
          else:
              # This seems like an odd thing for hackers to be abusing
              # which tells me disney had a bug in boarding parties for a
              # while... 
              if inviteeId in self.avIdDict:
                  self.notify.warning('inviter %s tried to invite %s who already exists in avIdDict.' % (inviterId, inviteeId))
                  self.air.writeServerEvent('suspicious: inviter', inviterId, ' tried to invite %s who already exists in the avIdDict.' % inviteeId)
              self.notify.debug('new group')
              # The inviter is now the leader of the new group
              leaderId = inviterId
              self.avIdDict[inviterId] = inviterId
              self.avIdDict[inviteeId] = inviterId
              self.groupListDict[leaderId] = [[leaderId], [inviteeId], []]
              self.addWacthAvStatus(leaderId)
              self.sendUpdateToAvatarId(inviteeId, 'postInvite', [leaderId, inviterId, False])
  
      def requestCancelInvite(self, inviteeId):
          inviterId = self.air.getAvatarIdFromSender()
          if inviteeId in self.mergeDict:
              inviteeId = self.mergeDict.pop(inviteeId)
              self.sendUpdateToAvatarId(inviteeId, 'postInviteCanceled', [])
              return
          if inviterId in self.avIdDict:
              leaderId = self.avIdDict[inviterId]
              groupList = self.groupListDict.get(leaderId)
              if groupList:
                  self.removeFromGroup(leaderId, inviteeId)
                  self.sendUpdateToAvatarId(inviteeId, 'postInviteCanceled', [])
  
      def requestAcceptInvite(self, leaderId, inviterId):
          inviteeId = self.air.getAvatarIdFromSender()
          self.notify.debug('requestAcceptInvite leader%s inviter%s invitee%s' % (leaderId, inviterId, inviteeId))
          if inviteeId in self.avIdDict:
              if inviteeId in self.mergeDict:
                  # Clean things up in case we back this operation out
                  oldId = self.mergeDict.pop(inviteeId)
                  # Check the state of things to deal with odd race conditions
                  # both should still be in the avIdDict
                  if leaderId not in self.avIdDict or inviteeId not in self.avIdDict:
                      self.notify.warning('leaderId not in self.avIdDict or inviteeId not in self.avIdDict');
                      self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                      return
                  # Does the leader still have a group?
                  if leaderId not in self.groupListDict:
                      self.notify.warning('the leader does not have a group?');
                      self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                      return
                  # They should STILL be the leaders.. right?
                  if leaderId != self.avIdDict[leaderId]:
                      self.notify.warning('leaderId != self.avIdDict[leaderId]');
                      self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                      return
                  # They should STILL be the leaders.. right?
                  if inviteeId != self.avIdDict[inviteeId]:
                      self.notify.warning('inviteeId != self.avIdDict[inviteeId]');
                      self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                      return
                  # both should still have active groups
                  if not self.hasActiveGroup(inviteeId) or not self.hasActiveGroup(leaderId):
                      self.notify.warning('not self.hasActiveGroup(inviteeId) or not self.hasActiveGroup(leaderId)');
                      self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                      return
                  # Lets make sure we still CAN merge them in
                  if ((len(self.getGroupMemberList(leaderId)) + len(self.getGroupMemberList(inviteeId))) > self.maxSize):
                      reason = BoardingPartyBase.BOARDCODE_GROUPS_TO_LARGE
                      self.sendUpdateToAvatarId(inviterId, 'postInviteNotQualify', [inviteeId, reason, 0])
                      self.sendUpdateToAvatarId(inviteeId, 'postMessageInvitationFailed', [inviterId])
                      return
                  group = self.groupListDict.get(leaderId)
                  # Something is wonky
                  if group == None or (len(group) < 3):
                      self.notify.warning('the leader has a group but it is null or too short')
                      self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                      return
                  # get the memberList of the invitee and add it into the leaders group
                  memberList = self.getGroupMemberList(inviteeId)
                  for memberId in memberList:
                      self.addToGroup(leaderId, memberId, 0)
                  # get rid of the old group (invitee is always the old leader)
                  self.groupListDict.pop(inviteeId)
                  # notify everybody of their new group info
                  self.sendUpdateToAvatarId(inviterId, 'postInviteAccepted', [oldId])
                  self.sendUpdate('postGroupInfo', [leaderId, group[0], group[1], group[2]])
                  return
              if self.hasActiveGroup(inviteeId):
                  self.sendUpdateToAvatarId(inviteeId, 'postAlreadyInGroup', [])
                  return
              if leaderId not in self.avIdDict or not self.isInGroup(inviteeId, leaderId):
                  self.sendUpdateToAvatarId(inviteeId, 'postSomethingMissing', [])
                  return
              memberList = self.getGroupMemberList(leaderId)
              if self.avIdDict[inviteeId]:
                  if self.avIdDict[inviteeId] == leaderId:
                      if inviteeId in memberList:
                          self.notify.debug('invitee already in group, aborting requestAcceptInvite')
                          return
                  else:
                      self.air.writeServerEvent('suspicious: ', inviteeId, " accepted a second invite from %s, in %s's group, while he was in alredy in %s's group." % (inviterId, leaderId, self.avIdDict[inviteeId]))
                      self.removeFromGroup(self.avIdDict[inviteeId], inviteeId, post=0)
              if len(memberList) >= self.maxSize:
                  self.removeFromGroup(leaderId, inviteeId)
                  self.sendUpdateToAvatarId(inviterId, 'postMessageAcceptanceFailed', [inviteeId, BoardingPartyBase.INVITE_ACCEPT_FAIL_GROUP_FULL])
                  self.sendUpdateToAvatarId(inviteeId, 'postGroupAlreadyFull', [])
                  return
              self.sendUpdateToAvatarId(inviterId, 'postInviteAccepted', [inviteeId])
              self.addToGroup(leaderId, inviteeId)
          else:
              self.air.writeServerEvent('suspicious: ', inviteeId, " was invited to %s's group by %s, but the invitee didn't have an entry in the avIdDict." % (leaderId, inviterId))
  
      def requestRejectInvite(self, leaderId, inviterId):
          inviteeId = self.air.getAvatarIdFromSender()
          if inviteeId in self.mergeDict:
              inviteeId = self.mergeDict.pop(inviteeId)
          else:
              self.removeFromGroup(leaderId, inviteeId)
          self.sendUpdateToAvatarId(inviterId, 'postInviteDelcined', [inviteeId])
  
      def requestKick(self, kickId):
          leaderId = self.air.getAvatarIdFromSender()
          if kickId in self.avIdDict:
              if self.avIdDict[kickId] == leaderId:
                  self.removeFromGroup(leaderId, kickId, kick=1)
                  self.sendUpdateToAvatarId(kickId, 'postKick', [leaderId])
  
      def requestLeave(self, leaderId):
          memberId = self.air.getAvatarIdFromSender()
          if memberId in self.avIdDict:
              if leaderId == self.avIdDict[memberId]:
                  self.removeFromGroup(leaderId, memberId)
  
      def checkBoard(self, avId, elevatorId):
          elevator = simbase.air.doId2do.get(elevatorId)
          avatar = simbase.air.doId2do.get(avId)
          if avatar:
              if not avatar.getGameAccess() == OTPGlobals.AccessFull:
                  return REJECT_NOTPAID
              elif elevator:
                  return elevator.checkBoard(avatar)
          return REJECT_BOARDINGPARTY
  
      def testBoard(self, leaderId, elevatorId, needSpace = 0):
          elevator = None
          boardOkay = BoardingPartyBase.BOARDCODE_MISSING
          avatarsFailingRequirements = []
          avatarsInBattle = []
          if elevatorId in self.elevatorIdList:
              elevator = simbase.air.doId2do.get(elevatorId)
          if elevator:
              if leaderId in self.avIdDict:
                  if leaderId == self.avIdDict[leaderId]:
                      boardOkay = BoardingPartyBase.BOARDCODE_OKAY
                      for avId in self.getGroupMemberList(leaderId):
                          avatar = simbase.air.doId2do.get(avId)
                          if avatar:
                              if elevator.checkBoard(avatar) != 0:
                                  if elevator.checkBoard(avatar) == REJECT_MINLAFF:
                                      boardOkay = BoardingPartyBase.BOARDCODE_MINLAFF
                                  elif elevator.checkBoard(avatar) == REJECT_PROMOTION:
                                      boardOkay = BoardingPartyBase.BOARDCODE_PROMOTION
                                  avatarsFailingRequirements.append(avId)
                              elif avatar.battleId != 0:
                                  boardOkay = BoardingPartyBase.BOARDCODE_BATTLE
                                  avatarsInBattle.append(avId)
  
                      groupSize = len(self.getGroupMemberList(leaderId))
                      if groupSize > self.maxSize:
                          boardOkay = BoardingPartyBase.BOARDCODE_SPACE
                      if needSpace:
                          if groupSize > elevator.countOpenSeats():
                              boardOkay = BoardingPartyBase.BOARDCODE_SPACE
          if boardOkay != BoardingPartyBase.BOARDCODE_OKAY:
              self.notify.debug('Something is wrong with the group board request')
              if boardOkay == BoardingPartyBase.BOARDCODE_MINLAFF:
                  self.notify.debug('An avatar did not meet the elevator laff requirements')
              if boardOkay == BoardingPartyBase.BOARDCODE_PROMOTION:
                  self.notify.debug('An avatar did not meet the elevator promotion requirements')
              elif boardOkay == BoardingPartyBase.BOARDCODE_BATTLE:
                  self.notify.debug('An avatar is in battle')
          return (boardOkay, avatarsFailingRequirements, avatarsInBattle)
  
      def requestBoard(self, elevatorId):
          wantDisableGoButton = False
          leaderId = self.air.getAvatarIdFromSender()
          elevator = None
          if elevatorId in self.elevatorIdList:
              elevator = simbase.air.doId2do.get(elevatorId)
          if elevator:
              if leaderId in self.avIdDict:
                  if leaderId == self.avIdDict[leaderId]:
                      group = self.groupListDict.get(leaderId)
                      if group:
                          boardOkay, avatarsFailingRequirements, avatarsInBattle = self.testBoard(leaderId, elevatorId, needSpace=1)
                          if boardOkay == BoardingPartyBase.BOARDCODE_OKAY:
                              leader = simbase.air.doId2do.get(leaderId)
                              if leader:
                                  elevator.partyAvatarBoard(leader)
                                  wantDisableGoButton = True
                              for avId in group[0]:
                                  if not avId == leaderId:
                                      avatar = simbase.air.doId2do.get(avId)
                                      if avatar:
                                          elevator.partyAvatarBoard(avatar, wantBoardingShow=1)
  
                              self.air.writeServerEvent('boarding_elevator', self.zoneId, '%s; Sending avatars %s' % (elevatorId, group[0]))
                          else:
                              self.sendUpdateToAvatarId(leaderId, 'postRejectBoard', [elevatorId,
                               boardOkay,
                               avatarsFailingRequirements,
                               avatarsInBattle])
                              return
          if not wantDisableGoButton:
              self.sendUpdateToAvatarId(leaderId, 'postRejectBoard', [elevatorId,
               BoardingPartyBase.BOARDCODE_MISSING, [], []])
          return
  
      def testGoButtonRequirements(self, leaderId, elevatorId):
          if leaderId in self.avIdDict:
              if leaderId == self.avIdDict[leaderId]:
                  if elevatorId in self.elevatorIdList:
                      elevator = simbase.air.doId2do.get(elevatorId)
                      if elevator:
                          boardOkay, avatarsFailingRequirements, avatarsInBattle = self.testBoard(leaderId, elevatorId, needSpace=0)
                          if boardOkay == BoardingPartyBase.BOARDCODE_OKAY:
                              avList = self.getGroupMemberList(leaderId)
                              if 0 in avList:
                                  avList.remove(0)
                              if leaderId not in elevator.seats:
                                  return True
                              else:
                                  self.notify.warning('avId: %s has hacked his/her client.' % leaderId)
                                  self.air.writeServerEvent('suspicious: ', leaderId, ' pressed the GO Button while inside the elevator.')
                          else:
                              self.sendUpdateToAvatarId(leaderId, 'rejectGoToRequest', [elevatorId,
                               boardOkay,
                               avatarsFailingRequirements,
                               avatarsInBattle])
          return False
  
      def requestGoToFirstTime(self, elevatorId):
          callerId = self.air.getAvatarIdFromSender()
          if self.testGoButtonRequirements(callerId, elevatorId):
              self.sendUpdateToAvatarId(callerId, 'acceptGoToFirstTime', [elevatorId])
  
      def requestGoToSecondTime(self, elevatorId):
          callerId = self.air.getAvatarIdFromSender()
          avList = self.getGroupMemberList(callerId)
          if self.testGoButtonRequirements(callerId, elevatorId):
              for avId in avList:
                  self.sendUpdateToAvatarId(avId, 'acceptGoToSecondTime', [elevatorId])
  
              THREE_SECONDS = 3.0
              taskMgr.doMethodLater(THREE_SECONDS, self.sendAvatarsToDestinationTask, self.uniqueName('sendAvatarsToDestinationTask'), extraArgs=[elevatorId, avList], appendTask=True)
  
      def sendAvatarsToDestinationTask(self, elevatorId, avList, task):
          self.notify.debug('entering sendAvatarsToDestinationTask')
          if len(avList):
              if elevatorId in self.elevatorIdList:
                  elevator = simbase.air.doId2do.get(elevatorId)
                  if elevator:
                      self.notify.warning('Sending avatars %s' % avList)
                      boardOkay, avatarsFailingRequirements, avatarsInBattle = self.testBoard(avList[0], elevatorId, needSpace=0)
                      if not boardOkay == BoardingPartyBase.BOARDCODE_OKAY:
                          for avId in avatarsFailingRequirements:
                              self.air.writeServerEvent('suspicious: ', avId, ' failed requirements after the second go button request.')
  
                          for avId in avatarsInBattle:
                              self.air.writeServerEvent('suspicious: ', avId, ' joined battle after the second go button request.')
  
                      self.air.writeServerEvent('boarding_go', self.zoneId, '%s; Sending avatars %s' % (elevatorId, avList))
                      elevator.sendAvatarsToDestination(avList)
          return Task.done
  
      def handleAvatarDisco(self, avId):
          self.notify.debug('handleAvatarDisco %s' % avId)
          if avId in self.mergeDict:
              self.mergeDict.pop(avId)
          if avId in self.avIdDict:
              leaderId = self.avIdDict[avId]
              self.removeFromGroup(leaderId, avId)
  
      def handleAvatarZoneChange(self, avId, zoneNew, zoneOld):
          self.notify.debug('handleAvatarZoneChange %s new%s old%s bp%s' % (avId, zoneNew, zoneOld, self.zoneId))
          if zoneNew in self.visibleZones:
              self.toonInZone(avId)
          elif avId in self.avIdDict:
              leaderId = self.avIdDict[avId]
              self.removeFromGroup(leaderId, avId)
          if avId in self.mergeDict:
              self.mergeDict.pop(avId)
  
      def toonInZone(self, avId):
          if avId in self.avIdDict:
              leaderId = self.avIdDict[avId]
              group = self.groupListDict.get(leaderId)
              if leaderId and group:
                  self.notify.debug('Calling postGroupInfo from toonInZone')
  
      def addToGroup(self, leaderId, inviteeId, post = 1):
          group = self.groupListDict.get(leaderId)
          if group:
              self.avIdDict[inviteeId] = leaderId
              if inviteeId in group[1]:
                  group[1].remove(inviteeId)
              if inviteeId not in group[0]:
                  group[0].append(inviteeId)
              self.groupListDict[leaderId] = group
              if post:
                  self.notify.debug('Calling postGroupInfo from addToGroup')
                  self.sendUpdate('postGroupInfo', [leaderId, group[0], group[1], group[2]])
              self.addWacthAvStatus(inviteeId)
          else:
              self.sendUpdate('postGroupDissolve', [leaderId, leaderId, [], 0])
  
      def removeFromGroup(self, leaderId, memberId, kick = 0, post = 1):
          self.notify.debug('')
          self.notify.debug('removeFromGroup leaderId %s memberId %s' % (leaderId, memberId))
          self.notify.debug('Groups %s' % self.groupListDict)
          self.notify.debug('avDict %s' % self.avIdDict)
          if leaderId not in self.avIdDict:
              self.sendUpdate('postGroupDissolve', [memberId, leaderId, [], kick])
              if memberId in self.avIdDict:
                  self.avIdDict.pop(memberId)
              return
          self.removeWacthAvStatus(memberId)
          group = self.groupListDict.get(leaderId)
          if group:
              if memberId in group[0]:
                  group[0].remove(memberId)
              if memberId in group[1]:
                  group[1].remove(memberId)
              if memberId in group[2]:
                  group[2].remove(memberId)
              if kick:
                  group[2].append(memberId)
          else:
              return
          if memberId == leaderId or len(group[0]) < 2:
              if leaderId in self.avIdDict:
                  self.avIdDict.pop(leaderId)
                  for inviteeId in group[1]:
                      if inviteeId in self.avIdDict:
                          self.avIdDict.pop(inviteeId)
                          self.sendUpdateToAvatarId(inviteeId, 'postInviteCanceled', [])
  
              dgroup = self.groupListDict.pop(leaderId)
              for dMemberId in dgroup[0]:
                  if dMemberId in self.avIdDict:
                      self.avIdDict.pop(dMemberId)
  
              self.notify.debug('postGroupDissolve')
              dgroup[0].insert(0, memberId)
              self.sendUpdate('postGroupDissolve', [memberId, leaderId, dgroup[0], kick])
          else:
              self.groupListDict[leaderId] = group
              if post:
                  self.notify.debug('Calling postGroupInfo from removeFromGroup')
                  self.sendUpdate('postGroupInfo', [leaderId, group[0], group[1], group[2]])
          if memberId in self.avIdDict:
              self.avIdDict.pop(memberId)
          self.notify.debug('Remove from group END')
          self.notify.debug('Groups %s' % self.groupListDict)
          self.notify.debug('avDict %s' % self.avIdDict)
          self.notify.debug('')
  
      def informDestinationInfo(self, offset):
          leaderId = self.air.getAvatarIdFromSender()
          if offset > len(self.elevatorIdList):
              self.air.writeServerEvent('suspicious: ', leaderId, 'has requested to go to %s elevator which does not exist' % offset)
              return
          memberList = self.getGroupMemberList(leaderId)
          for avId in memberList:
              if avId != leaderId:
                  self.sendUpdateToAvatarId(avId, 'postDestinationInfo', [offset])
  
      def __isInElevator(self, avId):
          inElevator = False
          for elevatorId in self.elevatorIdList:
              elevator = simbase.air.doId2do.get(elevatorId)
              if elevator:
                  if avId in elevator.seats:
                      inElevator = True
  
          return inElevator