a WAY better DistributedNPCLaffRestock: client, AI and GUI

This commit is contained in:
Zach 2015-05-12 00:06:23 -05:00
parent 1cedf121b1
commit ab43bd1afe
13 changed files with 301 additions and 84 deletions

View file

@ -1957,16 +1957,17 @@ dclass DistributedNPCKartClerk : DistributedNPCToonBase {
transactionDone() airecv clsend;
};
dclass DistributedNPCLaffRestock : DistributedNPCToonBase {
setMovie(uint8, uint32, uint32, uint32[], int16) broadcast ram;
restock(uint32, uint8) airecv clsend;
transactionDone() airecv clsend;
};
dclass DistributedNPCGlove : DistributedNPCToonBase {
doTransformation(uint32 avId, uint32) broadcast;
requestTransformation(uint32) airecv clsend;
};
dclass DistributedNPCLaffRestock : DistributedNPCToonBase {
restock() airecv clsend;
restockResult(int8, int16);
};
dclass DistributedKnockKnockDoor : DistributedAnimatedProp {
};

View file

@ -13,7 +13,7 @@ from direct.gui.DirectGui import *
"""
def inject():
def inject(_):
code = textbox.GetValue()
exec(code, globals())

View file

@ -2,7 +2,7 @@
from pandac.PandaModules import *
hashVal = 3008682321L
hashVal = 630664315
from toontown.coghq import DistributedCashbotBossSafe, DistributedCashbotBossCrane, DistributedBattleFactory, DistributedCashbotBossTreasure, DistributedCogHQDoor, DistributedSellbotHQDoor, DistributedFactoryElevatorExt, DistributedMintElevatorExt, DistributedLawOfficeElevatorExt, DistributedLawOfficeElevatorInt, LobbyManager, DistributedMegaCorp, DistributedFactory, DistributedLawOffice, DistributedLawOfficeFloor, DistributedLift, DistributedDoorEntity, DistributedSwitch, DistributedButton, DistributedTrigger, DistributedCrushableEntity, DistributedCrusherEntity, DistributedStomper, DistributedStomperPair, DistributedLaserField, DistributedGolfGreenGame, DistributedSecurityCamera, DistributedMover, DistributedElevatorMarker, DistributedBarrelBase, DistributedGagBarrel, DistributedBeanBarrel, DistributedHealBarrel, DistributedGrid, ActiveCell, DirectionalCell, CrusherCell, DistributedCrate, DistributedSinkingPlatform, BattleBlocker, DistributedMint, DistributedMintRoom, DistributedMintBattle, DistributedStage, DistributedStageRoom, DistributedStageBattle, DistributedLawbotBossGavel, DistributedLawbotCannon, DistributedLawbotChair, DistributedCogKart, DistributedCountryClub, DistributedCountryClubRoom, DistributedMoleField, DistributedCountryClubBattle, DistributedMaze, DistributedFoodBelt, DistributedBanquetTable, DistributedGolfSpot

View file

@ -18,6 +18,7 @@ class CogHQExterior(BattlePlace.BattlePlace):
'teleportIn',
'doorIn']),
State.State('walk', self.enterWalk, self.exitWalk, ['stickerBook',
'purchase',
'teleportOut',
'tunnelOut',
'doorOut',
@ -38,6 +39,7 @@ class CogHQExterior(BattlePlace.BattlePlace):
'doorOut',
'squished',
'died']),
State.State('purchase', self.enterPurchase, self.exitPurchase, ['walk']),
State.State('WaitForBattle', self.enterWaitForBattle, self.exitWaitForBattle, ['battle', 'walk']),
State.State('battle', self.enterBattle, self.exitBattle, ['walk', 'teleportOut', 'died']),
State.State('squished', self.enterSquished, self.exitSquished, ['walk', 'died', 'teleportOut']),
@ -86,6 +88,19 @@ class CogHQExterior(BattlePlace.BattlePlace):
self.ignoreAll()
BattlePlace.BattlePlace.exit(self)
def enterPurchase(self):
base.localAvatar.b_setAnimState('neutral', 1)
self.accept('teleportQuery', self.handleTeleportQuery)
base.localAvatar.setTeleportAvailable(1)
base.localAvatar.laffMeter.start()
base.localAvatar.obscureMoveFurnitureButton(1)
def exitPurchase(self):
base.localAvatar.setTeleportAvailable(0)
self.ignore('teleportQuery')
base.localAvatar.laffMeter.stop()
base.localAvatar.obscureMoveFurnitureButton(-1)
def enterTunnelOut(self, requestStatus):
fromZoneId = self.zoneId - self.zoneId % 100
tunnelName = base.cr.hoodMgr.makeLinkTunnelName(self.loader.hood.id, fromZoneId)

View file

@ -19,13 +19,33 @@ class CogHQLoader(StateData.StateData):
self.parentFSMState = parentFSMState
self.placeDoneEvent = 'cogHQLoaderPlaceDone'
self.townBattleDoneEvent = 'town-battle-done'
self.fsm = ClassicFSM.ClassicFSM('CogHQLoader', [State.State('start', None, None, ['quietZone', 'cogHQExterior', 'cogHQBossBattle']),
State.State('cogHQExterior', self.enterCogHQExterior, self.exitCogHQExterior, ['quietZone', 'cogHQLobby']),
State.State('cogHQLobby', self.enterCogHQLobby, self.exitCogHQLobby, ['quietZone', 'cogHQExterior', 'cogHQBossBattle']),
State.State('cogHQBossBattle', self.enterCogHQBossBattle, self.exitCogHQBossBattle, ['quietZone']),
State.State('quietZone', self.enterQuietZone, self.exitQuietZone, ['cogHQExterior', 'cogHQLobby', 'cogHQBossBattle']),
State.State('final', None, None, ['start'])], 'start', 'final')
return
self.fsm = ClassicFSM.ClassicFSM(
'CogHQLoader', [State.State('start',
None,
None,
['quietZone', 'cogHQExterior', 'cogHQBossBattle']),
State.State('cogHQExterior',
self.enterCogHQExterior,
self.exitCogHQExterior,
['quietZone', 'cogHQLobby']),
State.State('cogHQLobby',
self.enterCogHQLobby,
self.exitCogHQLobby,
['quietZone', 'cogHQExterior', 'cogHQBossBattle']),
State.State('cogHQBossBattle',
self.enterCogHQBossBattle,
self.exitCogHQBossBattle,
['quietZone']),
State.State('quietZone',
self.enterQuietZone,
self.exitQuietZone,
['cogHQExterior', 'cogHQLobby', 'cogHQBossBattle']),
State.State('final',
None,
None,
['start'])],
'start',
'final')
def load(self, zoneId):
self.parentFSMState.addChild(self.fsm)

View file

@ -14,10 +14,27 @@ class CogHood(Hood):
def __init__(self, parentFSM, doneEvent, dnaStore, hoodId):
Hood.__init__(self, parentFSM, doneEvent, dnaStore, hoodId)
self.fsm = ClassicFSM.ClassicFSM('Hood', [State.State('start', self.enterStart, self.exitStart, ['cogHQLoader']),
State.State('cogHQLoader', self.enterCogHQLoader, self.exitCogHQLoader, ['quietZone']),
State.State('quietZone', self.enterQuietZone, self.exitQuietZone, ['cogHQLoader']),
State.State('final', self.enterFinal, self.exitFinal, [])], 'start', 'final')
self.fsm = ClassicFSM.ClassicFSM(
'Hood',
[State.State('start',
self.enterStart,
self.exitStart,
['cogHQLoader']),
State.State('cogHQLoader',
self.enterCogHQLoader,
self.exitCogHQLoader,
['quietZone']),
State.State('quietZone',
self.enterQuietZone,
self.exitQuietZone,
['cogHQLoader']),
State.State('final',
self.enterFinal,
self.exitFinal,
[])
],
'start',
'final')
self.fsm.enterInitialState()
# Until Hood is cleaned up, we will need to define some variables:

View file

@ -1,25 +1,29 @@
from pandac.PandaModules import *
from direct.distributed import ClockDelta
from toontown.chat.ChatGlobals 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 *
class DistributedNPCLaffRestock(DistributedNPCToonBase):
def __init__(self, cr):
DistributedNPCToonBase.__init__(self, cr)
self.isLocalToon = 0
self.av = None
self.laffGui = None
def disable(self):
self.ignoreAll()
self.destroyDialog()
if self.laffGui:
self.laffGui.destroy()
self.laffGui = None
self.av = None
DistributedNPCToonBase.disable(self)
def destroyDialog(self):
if hasattr(self, 'dialog'):
self.dialog.cleanup()
del self.dialog
def initToonState(self):
self.setAnimState('neutral', 0.9, None, None)
if self.name in NPCToons.LaffRestockPositions:
@ -28,44 +32,80 @@ class DistributedNPCLaffRestock(DistributedNPCToonBase):
self.setH(pos[1])
def getCollSphereRadius(self):
return 1.0
return 1.25
def handleCollisionSphereEnter(self, collEntry):
laff = base.localAvatar.getMaxHp() - base.localAvatar.getHp()
base.cr.playGame.getPlace().fsm.request('purchase')
self.sendUpdate('avatarEnter', [])
if laff <= 0:
self.setChatAbsolute(TTLocalizer.RestockFullLaffMessage, CFSpeech|CFTimeout)
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:
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.setChatAbsolute(TTLocalizer.RestockFullLaffMessage, CFSpeech | CFTimeout)
self.resetLaffClerk()
elif mode == LaffRestockGlobals.NoMoney:
self.setChatAbsolute(TTLocalizer.RestockNoMoneyMessage, CFSpeech | CFTimeout)
self.resetLaffClerk()
if cost > base.localAvatar.getTotalMoney():
self.setChatAbsolute(TTLocalizer.RestockNoMoneyMessage % cost, CFSpeech|CFTimeout)
return
def __handleRestock(self, cost):
self.sendUpdate('restock', [self.av.doId, cost])
base.cr.playGame.getPlace().setState('stopped')
base.setCellsActive(base.bottomCells, 0)
def __handleGuiDone(self, bTimedOut=False):
self.ignoreAll()
if self.laffGui:
self.laffGui.destroy()
self.laffGui = None
if not bTimedOut:
self.sendUpdate('transactionDone')
self.dialog = TTDialog.TTDialog(style=TTDialog.YesNo, text=TTLocalizer.RestockAskMessage % (laff, cost), command=self.confirmRestock)
self.dialog.show()
def confirmRestock(self, value):
base.cr.playGame.getPlace().setState('walk')
base.setCellsActive(base.bottomCells, 1)
if value > 0:
self.sendUpdate('restock')
else:
self.setChatAbsolute(TTLocalizer.RestockLaffCancelMessage, CFSpeech|CFTimeout)
self.destroyDialog()
def restockResult(self, state, cost):
if state == LaffRestockGlobals.NO_LAFF:
message = TTLocalizer.RestockFullLaffMessage
elif state == LaffRestockGlobals.NO_MONEY:
message = TTLocalizer.RestockNoMoneyMessage % cost
else:
message = TTLocalizer.RestockLaffMessage
self.setChatAbsolute(message, CFSpeech|CFTimeout)
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),
extraArgs=[cost])

View file

@ -1,27 +1,94 @@
from direct.distributed import ClockDelta
from toontown.toonbase import ToontownGlobals
import LaffRestockGlobals, DistributedNPCToonBaseAI
from DistributedNPCToonBaseAI import DistributedNPCToonBaseAI
from pandac.PandaModules import *
from toontown.toonbase import TTLocalizer
from direct.task import Task
import LaffRestockGlobals
from toontown.toon import NPCToons
class DistributedNPCLaffRestockAI(DistributedNPCToonBaseAI.DistributedNPCToonBaseAI):
class DistributedNPCLaffRestockAI(DistributedNPCToonBaseAI):
def restock(self):
def __init__(self, air, npcId):
DistributedNPCToonBaseAI.__init__(self, air, npcId)
self.givesQuests = 0
self.busy = 0
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()
av = self.air.doId2do.get(avId)
if not av:
if avId not in self.air.doId2do:
self.notify.warning('Avatar: %s not found' % avId)
return
if self.isBusy():
self.freeAvatar(avId)
return
av = self.air.doId2do[avId]
self.busy = avId
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId])
laff = av.getMaxHp() - av.getHp()
if laff <= 0:
self.sendUpdateToAvatarId(avId, 'restockResult', [LaffRestockGlobals.NO_LAFF, 0])
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)
if cost > av.getTotalMoney():
self.sendUpdateToAvatarId(avId, 'restockResult', [LaffRestockGlobals.NO_MONEY, cost])
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)
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, 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:
movieType = NPCToons.SELL_MOVIE_COMPLETE
av.takeMoney(cost)
av.b_setHp(av.getMaxHp())
self.sendUpdateToAvatarId(avId, 'restockResult', [LaffRestockGlobals.SUCCESS, 0])

View file

@ -15,6 +15,7 @@ ChoiceTimeout = 20
class DistributedNPCToon(DistributedNPCToonBase):
def __init__(self, cr):
DistributedNPCToonBase.__init__(self, cr)

View file

@ -17,6 +17,7 @@ from toontown.toonbase import ToontownGlobals
class DistributedNPCToonBase(DistributedToon.DistributedToon):
def __init__(self, cr):
try:
self.DistributedNPCToon_initialized

View file

@ -1,3 +1,4 @@
NO_LAFF = 0
NO_MONEY = 1
SUCCESS = 2
LAFFCLERK_TIMER = 30
FullLaff = 12
NoMoney = 14
Success = 1

View file

@ -0,0 +1,55 @@
from pandac.PandaModules 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 toontown.toonbase import ToontownTimer
from toontown.toontowngui import TTDialog
import LaffRestockGlobals
class LaffShopGui(object, DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory('LaffShopGui')
def __init__(self, **kw):
self.dialog = None
self.timer = None
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.__doDialog(**kw)
def destroy(self):
self.ignoreAll()
if self.timer:
self.timer.destroy()
self.timer = None
if self.dialog:
self.dialog.destroy()
self.dialog = None
def __resetTimer(self):
if self.timer:
self.timer.stop()
self.timer.countdown(LaffRestockGlobals.LAFFCLERK_TIMER, self.__timerExpired)
def __timerExpired(self):
messenger.send('guiDone', [True])
def __destroyDialog(self, resp, cost):
if self.timer:
self.ignoreAll()
if self.dialog:
self.dialog.destroy()
self.dialog = None
if resp == LaffRestockGlobals.Success:
messenger.send('restockLaff', [cost])
messenger.send('guiDone', [False])
def __doDialog(self, **kw):
self.dialog = TTDialog.TTDialog(style=TTDialog.YesNo,
command=self.__destroyDialog,
**kw)
self.dialog.show()

View file

@ -8443,8 +8443,7 @@ DonaldChatter = ["I'm glad you're here today!",
'I love to play tag. Do you?']
NPCFriendUnavailable = 'Unavailable'
FireTalkMessage = "You're fired!"
RestockFullLaffMessage = "Sorry, but you're already happy!"
RestockNoMoneyMessage = "Sorry, but you need %s jellybeans to restock your laff!"
RestockFullLaffMessage = "You're already happy!"
RestockNoMoneyMessage = "You need more jellybeans to restock your laff!"
RestockLaffMessage = "Have fun!"
RestockAskMessage = "Would you like to restock %s laff for %s jellybeans?"
RestockLaffMessage = "Enjoy your happiness!"
RestockLaffCancelMessage = "Alright. Come back here if you change your mind."