New laff restock NPC

This commit is contained in:
John 2015-07-25 09:08:54 +03:00
parent 6d902c4d5d
commit 9494a47466
6 changed files with 156 additions and 287 deletions

View file

@ -1811,9 +1811,8 @@ dclass DistributedNPCKartClerk : DistributedNPCToonBase {
};
dclass DistributedNPCLaffRestock : DistributedNPCToonBase {
setMovie(uint8, uint32, uint32, uint32[], int16) broadcast ram;
restock(uint32, uint16, uint16) airecv clsend;
transactionDone() airecv clsend;
restock(uint8) airecv clsend;
restockResult(uint8) broadcast;
};
dclass DistributedNPCGlove : DistributedNPCToonBase {

View file

@ -1,121 +1,71 @@
from panda3d.core import *
from direct.distributed import ClockDelta
from otp.nametag.NametagConstants import CFSpeech, CFTimeout
from toontown.toonbase import TTLocalizer, ToontownGlobals
from toontown.toontowngui import TTDialog
from toontown.toon import NPCToons
from DistributedNPCToonBase import DistributedNPCToonBase
import LaffRestockGlobals
from LaffShopGui import *
import LaffRestockGlobals, LaffShopGui, time
class DistributedNPCLaffRestock(DistributedNPCToonBase):
zone2id = {
10000: 0,
13000: 1,
12000: 2,
11000: 3,
}
def __init__(self, cr):
DistributedNPCToonBase.__init__(self, cr)
self.isLocalToon = 0
self.av = None
self.laffGui = None
self.lastCollision = 0
self.laffDialog = None
def disable(self):
self.ignoreAll()
if self.laffGui:
self.laffGui.destroy()
self.laffGui = None
self.av = None
self.destroyDialog()
DistributedNPCToonBase.disable(self)
def destroyDialog(self):
self.clearChat()
if self.laffDialog:
self.laffDialog.destroy()
self.laffDialog = None
def initToonState(self):
self.setAnimState('neutral', 0.9, None, None)
self.putOnSuit(ToontownGlobals.cogHQZoneId2deptIndex(self.zoneId), rental=True)
if self.name in NPCToons.LaffRestockPositions:
pos = NPCToons.LaffRestockPositions[self.name]
self.setPos(*pos[0])
self.setH(pos[1])
self.putOnSuit(self.zone2id.get(self.zoneId, -1), rental=True)
def getCollSphereRadius(self):
return 3.0
return 1.25
def handleCollisionSphereEnter(self, collEntry):
base.cr.playGame.getPlace().fsm.request('purchase')
self.sendUpdate('avatarEnter', [])
def __handleUnexpectedExit(self):
self.notify.warning('unexpected exit')
self.av = None
def resetLaffClerk(self):
self.ignoreAll()
if self.laffGui:
self.laffGui.destroy()
self.laffGui = None
self.show()
self.startLookAround()
self.detectAvatars()
if self.isLocalToon:
self.showNametag2d()
self.freeAvatar()
return Task.done
def setMovie(self, mode, npcId, avId, extraArgs, timestamp):
timeStamp = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
self.remain = NPCToons.CLERK_COUNTDOWN_TIME - timeStamp
self.npcId = npcId
self.isLocalToon = avId == base.localAvatar.doId
if mode == NPCToons.SELL_MOVIE_CLEAR:
if self.lastCollision > time.time():
return
if mode == NPCToons.SELL_MOVIE_TIMEOUT:
if self.isLocalToon:
if self.laffGui:
self.laffGui.destroy()
self.laffGui = None
self.setChatAbsolute(TTLocalizer.STOREOWNER_TOOKTOOLONG, CFSpeech | CFTimeout)
self.resetLaffClerk()
elif mode == NPCToons.SELL_MOVIE_START:
self.av = base.cr.doId2do.get(avId)
if self.av is None:
self.notify.warning('Avatar %d not found in doId' % avId)
return
else:
self.accept(self.av.uniqueName('disable'), self.__handleUnexpectedExit)
self.setupAvatars(self.av)
if self.isLocalToon:
self.hideNametag2d()
laff = self.av.getMaxHp() - self.av.getHp()
cost = laff * ToontownGlobals.CostPerLaffRestock
self.popupLaffGUI(laff, cost)
elif mode == NPCToons.SELL_MOVIE_COMPLETE:
self.setChatAbsolute(TTLocalizer.RestockLaffMessage, CFSpeech | CFTimeout)
self.resetLaffClerk()
elif mode == LaffRestockGlobals.FullLaff:
self.lastCollision = time.time() + ToontownGlobals.NPCCollisionDelay
self.lookAt(base.localAvatar)
if base.localAvatar.getHp() >= base.localAvatar.getMaxHp():
self.setChatAbsolute(TTLocalizer.RestockFullLaffMessage, CFSpeech | CFTimeout)
self.resetLaffClerk()
elif mode == LaffRestockGlobals.NoMoney:
self.setChatAbsolute(TTLocalizer.RestockNoMoneyMessage, CFSpeech | CFTimeout)
self.resetLaffClerk()
elif mode == NPCToons.SELL_MOVIE_CHEATER:
self.setChatAbsolute(TTLocalizer.RestockCheaterMessage, CFSpeech | CFTimeout)
self.resetLaffClerk()
return
base.cr.playGame.getPlace().fsm.request('stopped')
base.setCellsAvailable(base.bottomCells, 0)
self.destroyDialog()
self.acceptOnce('laffShopDone', self.__laffShopDone)
self.laffDialog = LaffShopGui.LaffShopGui()
def freeAvatar(self):
base.cr.playGame.getPlace().fsm.request('walk')
base.setCellsAvailable(base.bottomCells, 1)
def __laffShopDone(self, state, laff):
self.freeAvatar()
def __handleRestock(self, laff, cost):
self.sendUpdate('restock', [self.av.doId, laff, cost])
if state == LaffRestockGlobals.TIMER_END:
self.setChatAbsolute(TTLocalizer.STOREOWNER_TOOKTOOLONG, CFSpeech|CFTimeout)
elif state == LaffRestockGlobals.USER_CANCEL:
self.setChatAbsolute(TTLocalizer.STOREOWNER_GOODBYE, CFSpeech|CFTimeout)
elif state == LaffRestockGlobals.RESTOCK:
self.sendUpdate('restock', [laff])
def __handleGuiDone(self, bTimedOut=False):
self.ignoreAll()
if self.laffGui:
self.laffGui.destroy()
self.laffGui = None
if not bTimedOut:
self.sendUpdate('transactionDone')
def popupLaffGUI(self, laff, cost):
self.setChatAbsolute('', CFSpeech)
self.accept('restockLaff', self.__handleRestock)
self.acceptOnce('guiDone', self.__handleGuiDone)
self.laffGui = LaffShopGui(text=TTLocalizer.RestockAskMessage % (laff, cost))
def restockResult(self, state):
if state in LaffRestockGlobals.RestockMessages:
self.setChatAbsolute(LaffRestockGlobals.RestockMessages[state], CFSpeech | CFTimeout)

View file

@ -1,99 +1,29 @@
from direct.distributed import ClockDelta
from toontown.toonbase import ToontownGlobals
from DistributedNPCToonBaseAI import DistributedNPCToonBaseAI
from panda3d.core import *
from toontown.toonbase import TTLocalizer
from direct.task import Task
import LaffRestockGlobals
from toontown.toon import NPCToons
import LaffRestockGlobals, DistributedNPCToonBaseAI
class DistributedNPCLaffRestockAI(DistributedNPCToonBaseAI):
class DistributedNPCLaffRestockAI(DistributedNPCToonBaseAI.DistributedNPCToonBaseAI):
def __init__(self, air, npcId):
DistributedNPCToonBaseAI.__init__(self, air, npcId)
self.givesQuests = 0
self.busy = 0
def restock(self, laff):
av = simbase.air.doId2do.get(self.air.getAvatarIdFromSender())
def delete(self):
taskMgr.remove(self.uniqueName('clearMovie'))
self.ignoreAll()
DistributedNPCToonBaseAI.delete(self)
def d_setMovie(self, avId, flag, extraArgs=[]):
self.sendUpdate('setMovie', [flag,
self.npcId,
avId,
extraArgs,
ClockDelta.globalClockDelta.getRealNetworkTime()])
def avatarEnter(self):
avId = self.air.getAvatarIdFromSender()
if avId not in self.air.doId2do:
self.notify.warning('Avatar: %s not found' % avId)
if not av:
return
if self.isBusy():
self.freeAvatar(avId)
newLaff = av.getHp() + laff
if newLaff > av.getMaxHp():
self.sendUpdate('restockResult', [LaffRestockGlobals.FULL_LAFF])
return
av = self.air.doId2do[avId]
self.busy = avId
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId])
laff = av.getMaxHp() - av.getHp()
elif laff <= 0 or newLaff <= av.getHp():
self.sendUpdate('restockResult', [LaffRestockGlobals.LESS_LAFF])
return
cost = laff * ToontownGlobals.CostPerLaffRestock
if laff <= 0:
self.d_setMovie(avId, LaffRestockGlobals.FullLaff)
self.sendClearMovie(None)
elif cost > av.getTotalMoney():
self.d_setMovie(avId, LaffRestockGlobals.NoMoney)
self.sendClearMovie(None)
else:
self.d_setMovie(avId, NPCToons.SELL_MOVIE_START)
taskMgr.doMethodLater(LaffRestockGlobals.LAFFCLERK_TIMER, self.sendTimeoutMovie, self.uniqueName('clearMovie'))
DistributedNPCToonBaseAI.avatarEnter(self)
def transactionDone(self):
avId = self.air.getAvatarIdFromSender()
if self.busy != avId:
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCLaffRestockAI.transactionDone busy with %s' % self.busy)
self.notify.warning('somebody called transactionDone that I was not busy with! avId: %s' % avId)
if cost > av.getTotalMoney():
self.sendUpdate('restockResult', [LaffRestockGlobals.NOT_ENOUGH_MONEY])
return
av = simbase.air.doId2do.get(avId)
if av:
self.d_setMovie(avId, NPCToons.SELL_MOVIE_COMPLETE, [])
self.sendClearMovie(None)
return
def __handleUnexpectedExit(self, avId):
self.notify.warning('avatar:' + str(avId) + ' has exited unexpectedly')
self.notify.warning('not busy with avId: %s, busy: %s ' % (avId, self.busy))
taskMgr.remove(self.uniqueName('clearMovie'))
self.sendClearMovie(None)
return
def sendTimeoutMovie(self, task):
self.d_setMovie(self.busy, NPCToons.SELL_MOVIE_TIMEOUT)
self.sendClearMovie(None)
return Task.done
def sendClearMovie(self, task):
self.ignore(self.air.getAvatarExitEvent(self.busy))
taskMgr.remove(self.uniqueName('clearMovie'))
self.busy = 0
self.d_setMovie(0, NPCToons.SELL_MOVIE_CLEAR)
return Task.done
def restock(self, avId, laff, cost):
sendAvId = self.air.getAvatarIdFromSender()
if self.busy != avId:
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCLaffRestockAI.restock busy with %s' % self.busy)
self.notify.warning('somebody called restock that I was not busy with! avId: %s' % avId)
return
av = simbase.air.doId2do.get(avId)
if av:
if av.getMaxHp() < (av.getHp() + laff):
movieType = NPCToons.SELL_MOVIE_CHEATER
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCLaffRestockAI.restock invalid restock')
self.notify.warning('somebody tried to buy an invalid hp restock! avId: %s' % avId)
else:
movieType = NPCToons.SELL_MOVIE_COMPLETE
av.takeMoney(cost)
av.b_setHp(av.getHp() + laff)
av.takeMoney(cost)
av.toonUp(laff)
self.sendUpdate('restockResult', [LaffRestockGlobals.RESTOCK_SUCCESSFUL])

View file

@ -1,6 +1,21 @@
LAFFCLERK_TIMER = 30
FullLaff = 12
NoMoney = 14
Success = 1
GuiOk = 'Ok'
GuiCancel = 'Cancel'
from toontown.toonbase import TTLocalizer
TIMER_SECONDS = 30
# Laff Shop GUI
TIMER_END = 0
USER_CANCEL = 1
RESTOCK = 2
# Restock Results
FULL_LAFF = 0
LESS_LAFF = 1
NOT_ENOUGH_MONEY = 2
RESTOCK_SUCCESSFUL = 3
RestockMessages = {
FULL_LAFF: TTLocalizer.RestockFullLaffMessage,
LESS_LAFF: TTLocalizer.RestockLessLaffMessage,
NOT_ENOUGH_MONEY: TTLocalizer.RestockNoMoneyMessage,
RESTOCK_SUCCESSFUL: TTLocalizer.RestockSuccessfulMessage
}

View file

@ -1,144 +1,117 @@
from panda3d.core import *
from direct.directnotify import DirectNotifyGlobal
from direct.gui.DirectGui import *
from direct.showbase import DirectObject
from toontown.toonbase import ToontownGlobals
from toontown.toonbase import TTLocalizer
from direct.gui.DirectGui import DirectButton, DirectFrame, DGG
from direct.task.Task import Task
from toontown.toonbase import ToontownTimer
import LaffRestockGlobals
from LaffMeter import LaffMeter
from otp.otpbase import OTPLocalizer
from toontown.toonbase import ToontownGlobals, TTLocalizer, ToontownTimer
import LaffMeter, LaffRestockGlobals
class LaffShopGui(DirectFrame):
def __init__(self, text):
DirectFrame.__init__(self, parent=aspect2d, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=ToontownGlobals.GlobalDialogColor, geom_scale=(1.33, 1, 1.1), pos=(0, 0, 0), text=text, text_scale=0.07, text_pos=(0, 0.475))
def __init__(self):
DirectFrame.__init__(self, parent=aspect2d, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=ToontownGlobals.GlobalDialogColor, geom_scale=(1.33, 1, 1.3), pos=(0, 0, 0), text='', text_scale=0.07, text_pos=(0, 0.475))
self.initialiseoptions(LaffShopGui)
self.text = text
self.additionalLaff = 0
self.timer = ToontownTimer.ToontownTimer()
self.timer.reparentTo(aspect2d)
self.timer.posInTopRightCorner()
self.timer.accept('RESET_LAFFSHOP_TIMER', self.__resetTimer)
self.timer.countdown(LaffRestockGlobals.LAFFCLERK_TIMER, self.__timerExpired)
self.hp = base.localAvatar.getHp()
self.maxHp = base.localAvatar.getMaxHp()
self.floorLimit = self.hp
self.ceilLimit = 0
money = base.localAvatar.getTotalMoney()
while self.ceilLimit * ToontownGlobals.CostPerLaffRestock < money:
self.ceilLimit += 1
self.__additionalLaff = 0
self.__setupButtons()
self.__bindButtons()
self.laffMeter = LaffMeter(base.localAvatar.style, self.hp, self.maxHp)
self.timer.countdown(LaffRestockGlobals.TIMER_SECONDS, self.__cancel, [LaffRestockGlobals.TIMER_END])
self.setupButtons()
self.bindButtons()
self.laffMeter = LaffMeter.LaffMeter(base.localAvatar.style, base.localAvatar.getHp(), base.localAvatar.getMaxHp())
self.laffMeter.reparentTo(self)
self.laffMeter.setPos(0, 0, 0.165)
self.laffMeter.setPos(0, 0, 0.065)
self.laffMeter.setScale(0.13)
self.__updateLaffMeter(0)
self.__updateLaffMeter(1)
def __setupButtons(self):
def setupButtons(self):
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
arrowGui = loader.loadModel('phase_3/models/gui/create_a_toon_gui')
okImageList = (buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr'))
cancelImageList = (buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr'))
arrowImageList = (arrowGui.find('**/CrtATn_R_Arrow_UP'), arrowGui.find('**/CrtATn_R_Arrow_DN'), arrowGui.find('**/CrtATn_R_Arrow_RLVR'), arrowGui.find('**/CrtATn_R_Arrow_UP'))
self.cancelButton = DirectButton(parent=self, relief=None, image=cancelImageList, pos=(-0.2, 0, -0.4), text=LaffRestockGlobals.GuiCancel, text_scale=0.06, text_pos=(0, -0.1), command=self.__cancel)
self.okButton = DirectButton(parent=self, relief=None, image=okImageList, pos=(0.2, 0, -0.4), text=LaffRestockGlobals.GuiOk, text_scale=0.06, text_pos=(0, -0.1), command=self.__requestLaff)
self.upArrow = DirectButton(parent=self, relief=None, image=arrowImageList, image_scale=(1, 1, 1), image3_color=Vec4(0.6, 0.6, 0.6, 0.25), pos=(0.2, 0, -0.165))
self.downArrow = DirectButton(parent=self, relief=None, image=arrowImageList, image_scale=(-1, 1, 1), image3_color=Vec4(0.6, 0.6, 0.6, 0.25), pos=(-0.2, 0, -0.165))
self.cancelButton = DirectButton(parent=self, relief=None, image=(buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr')), pos=(-0.2, 0, -0.5), text=OTPLocalizer.lCancel, text_scale=0.06, text_pos=(0, -0.1), command=self.__cancel, extraArgs=[LaffRestockGlobals.USER_CANCEL])
self.okButton = DirectButton(parent=self, relief=None, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), pos=(0.2, 0, -0.5), text=OTPLocalizer.lOK, text_scale=0.06, text_pos=(0, -0.1), command=self.__restock)
self.upArrow = DirectButton(parent=self, relief=None, image=arrowImageList, image_scale=(1, 1, 1), image3_color=Vec4(0.6, 0.6, 0.6, 0.25), pos=(0.2, 0, -0.265))
self.downArrow = DirectButton(parent=self, relief=None, image=arrowImageList, image_scale=(-1, 1, 1), image3_color=Vec4(0.6, 0.6, 0.6, 0.25), pos=(-0.2, 0, -0.265))
buttons.removeNode()
arrowGui.removeNode()
def __bindButtons(self):
self.downArrow.bind(DGG.B1PRESS, self.__downButtonDown)
self.downArrow.bind(DGG.B1RELEASE, self.__downButtonUp)
self.upArrow.bind(DGG.B1PRESS, self.__upButtonDown)
self.upArrow.bind(DGG.B1RELEASE, self.__upButtonUp)
def bindButtons(self):
self.downArrow.bind(DGG.B1PRESS, self.__taskUpdate, extraArgs=[-1])
self.downArrow.bind(DGG.B1RELEASE, self.__taskDone)
self.upArrow.bind(DGG.B1PRESS, self.__taskUpdate, extraArgs=[1])
self.upArrow.bind(DGG.B1RELEASE, self.__taskDone)
def destroy(self):
self.ignoreAll()
if self.timer:
self.timer.destroy()
taskMgr.remove(self.taskName('runCounter'))
taskMgr.remove(self.taskName('runLaffCounter'))
DirectFrame.destroy(self)
def __resetTimer(self):
if self.timer:
self.timer.stop()
self.timer.countdown(LaffRestockGlobals.LAFFCLERK_TIMER, self.__timerExpired)
def __timerExpired(self):
def __cancel(self, state):
self.destroy()
messenger.send('guiDone', [True])
messenger.send('laffShopDone', [state, 0])
def __cancel(self):
def __restock(self):
self.destroy()
messenger.send('guiDone', [False])
messenger.send('laffShopDone', [LaffRestockGlobals.RESTOCK, self.additionalLaff])
def __requestLaff(self):
if self.timer:
self.ignoreAll()
self.destroy()
cost = self.__additionalLaff * ToontownGlobals.CostPerLaffRestock
messenger.send('restockLaff', [self.__additionalLaff, cost])
messenger.send('guiDone', [False])
def __updateLaffMeter(self, amt):
def __updateLaffMeter(self, amount):
self.additionalLaff += amount
hitLimit = 0
self.__additionalLaff += amt
newLaff = self.hp + self.__additionalLaff
cost = self.__additionalLaff * ToontownGlobals.CostPerLaffRestock
if newLaff <= self.floorLimit:
newLaff = base.localAvatar.getHp() + self.additionalLaff
if (newLaff - 1) <= base.localAvatar.getHp():
self.downArrow['state'] = DGG.DISABLED
hitLimit = 1
else:
self.downArrow['state'] = DGG.NORMAL
if newLaff >= self.maxHp or self.__additionalLaff >= self.ceilLimit:
if newLaff >= base.localAvatar.getMaxHp():
self.upArrow['state'] = DGG.DISABLED
hitLimit = 1
else:
self.upArrow['state'] = DGG.NORMAL
self['text'] = TTLocalizer.RestockAskMessage % (self.__additionalLaff, cost)
cost = self.additionalLaff * ToontownGlobals.CostPerLaffRestock
self['text'] = TTLocalizer.RestockAskMessage % (self.additionalLaff, cost)
if cost > base.localAvatar.getTotalMoney():
self.okButton['state'] = DGG.DISABLED
self['text'] += TTLocalizer.RestockNoMoneyGuiMessage
else:
self.okButton['state'] = DGG.NORMAL
self.laffMeter.hp = newLaff
self.laffMeter.start()
return (hitLimit, newLaff, self.__additionalLaff)
def __runCounter(self, task):
return hitLimit
def __runTask(self, task):
if task.time - task.prevTime < task.delayTime:
return Task.cont
else:
task.delayTime = max(0.05, task.delayTime * 0.75)
task.prevTime = task.time
hitLimit, laff, trans = self.__updateLaffMeter(task.delta)
if hitLimit:
return Task.done
else:
return Task.cont
hitLimit = self.__updateLaffMeter(task.delta)
def __downButtonUp(self, event):
messenger.send('wakeup')
taskMgr.remove(self.taskName('runCounter'))
return Task.done if hitLimit else Task.cont
def __downButtonDown(self, event):
def __taskDone(self, event):
messenger.send('wakeup')
task = Task(self.__runCounter)
taskMgr.remove(self.taskName('runLaffCounter'))
def __taskUpdate(self, delta, event):
messenger.send('wakeup')
task = Task(self.__runTask)
task.delayTime = 0.4
task.prevTime = 0.0
task.delta = -1
hitLimit, laff, trans = self.__updateLaffMeter(task.delta)
if not hitLimit:
taskMgr.add(task, self.taskName('runCounter'))
task.delta = delta
hitLimit = self.__updateLaffMeter(delta)
def __upButtonUp(self, event):
messenger.send('wakeup')
taskMgr.remove(self.taskName('runCounter'))
def __upButtonDown(self, event):
messenger.send('wakeup')
task = Task(self.__runCounter)
task.delayTime = 0.4
task.prevTime = 0.0
task.delta = 1
hitLimit, laff, trans = self.__updateLaffMeter(task.delta)
if not hitLimit:
taskMgr.add(task, self.taskName('runCounter'))
taskMgr.add(task, self.taskName('runLaffCounter'))

View file

@ -8470,11 +8470,13 @@ DonaldChatter = ["I'm glad you're here today!",
'I love to play tag. Do you?']
NPCFriendUnavailable = 'Unavailable'
FireTalkMessage = "You're fired!"
RestockFullLaffMessage = "You're already happy!"
RestockNoMoneyMessage = "You need more jellybeans to restock your laff!"
RestockLaffMessage = "Have fun!"
RestockAskMessage = "Would you like to\nrestock %s laff for %s jellybeans?"
RestockCheaterMessage = "No cheaters allowed! Your transaction has been declined."
RestockNoMoneyGuiMessage = "\n\x01WLRed\x01Not enough jellybeans\x02"
RestockFullLaffMessage = "You're already happy!"
RestockLessLaffMessage = "Why would you want to be less happy than you are right now?"
RestockNoMoneyMessage = "You don't have enough jellybeans for that!"
RestockSuccessfulMessage = "You're welcome! Have fun!"
InVP = ' in a V.P. Battle'
InFieldOffice = ' in a Sellbot Field Office'
CogPanelLevel = 'Level %s'