tutorial: Cleanup and fix floating Flunky in battle
The following has been cleaned up: - Import statements - Whitespace - Small unnecessary comments Futhermore, I have added Anesidora documentation to the Tutorial files that did not have them.
This commit is contained in:
parent
4d566e1da9
commit
e22fee8fa8
|
|
@ -1,26 +1,19 @@
|
|||
from toontown.toonbase.ToonBaseGlobal import *
|
||||
from pandac.PandaModules import *
|
||||
import random
|
||||
from panda3d.core import Point3, Vec3
|
||||
from panda3d.toontown import DNADoor
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from direct.distributed.ClockDelta import *
|
||||
from toontown.toonbase import ToontownGlobals
|
||||
from . import ToonInterior
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed import DistributedObject
|
||||
import random
|
||||
from . import ToonInteriorColors
|
||||
from toontown.hood import ZoneUtil
|
||||
from toontown.char import Char
|
||||
from toontown.suit import SuitDNA
|
||||
from toontown.suit import Suit
|
||||
from toontown.quest import QuestParser
|
||||
|
||||
|
||||
class DistributedTutorialInterior(DistributedObject.DistributedObject):
|
||||
|
||||
def __init__(self, cr):
|
||||
DistributedObject.DistributedObject.__init__(self, cr)
|
||||
|
||||
def generate(self):
|
||||
DistributedObject.DistributedObject.generate(self)
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedTutorialInterior')
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedObject.DistributedObject.announceGenerate(self)
|
||||
|
|
@ -39,104 +32,181 @@ class DistributedTutorialInterior(DistributedObject.DistributedObject):
|
|||
del self.suitWalkTrack
|
||||
self.suit.delete()
|
||||
del self.suit
|
||||
self.ignore('enterTutotialInterior')
|
||||
self.ignore("enterTutotialInterior")
|
||||
DistributedObject.DistributedObject.disable(self)
|
||||
|
||||
def delete(self):
|
||||
DistributedObject.DistributedObject.delete(self)
|
||||
|
||||
def randomDNAItem(self, category, findFunc):
|
||||
codeCount = self.dnaStore.getNumCatalogCodes(category)
|
||||
index = self.randomGenerator.randint(0, codeCount - 1)
|
||||
code = self.dnaStore.getCatalogCode(category, index)
|
||||
# findFunc will probably be findNode or findTexture
|
||||
return findFunc(code)
|
||||
|
||||
def replaceRandomInModel(self, model):
|
||||
baseTag = 'random_'
|
||||
npc = model.findAllMatches('**/' + baseTag + '???_*')
|
||||
"""Replace named nodes with random items.
|
||||
Here are the name Here is
|
||||
prefixes that are what they
|
||||
affected: do:
|
||||
|
||||
random_mox_ change the Model Only.
|
||||
random_mcx_ change the Model and the Color.
|
||||
random_mrx_ change the Model and Recurse.
|
||||
random_tox_ change the Texture Only.
|
||||
random_tcx_ change the Texture and the Color.
|
||||
|
||||
x is simply a uniquifying integer because Multigen will not
|
||||
let you have multiple nodes with the same name
|
||||
|
||||
"""
|
||||
baseTag = "random_"
|
||||
npc = model.findAllMatches("**/" + baseTag + "???_*")
|
||||
for i in range(npc.getNumPaths()):
|
||||
np = npc.getPath(i)
|
||||
name = np.getName()
|
||||
|
||||
b = len(baseTag)
|
||||
category = name[b + 4:]
|
||||
key1 = name[b]
|
||||
key2 = name[b + 1]
|
||||
if key1 == 'm':
|
||||
|
||||
assert (key1 in ["m", "t"])
|
||||
assert (key2 in ["c", "o", "r"])
|
||||
if key1 == "m":
|
||||
# ...model.
|
||||
model = self.randomDNAItem(category, self.dnaStore.findNode)
|
||||
assert (not model.isEmpty())
|
||||
newNP = model.copyTo(np)
|
||||
# room has collisions already: remove collisions from models
|
||||
c = render.findAllMatches('**/collision')
|
||||
c.stash()
|
||||
if key2 == 'r':
|
||||
if key2 == "r":
|
||||
self.replaceRandomInModel(newNP)
|
||||
elif key1 == 't':
|
||||
elif key1 == "t":
|
||||
# ...texture.
|
||||
texture = self.randomDNAItem(category, self.dnaStore.findTexture)
|
||||
assert (texture)
|
||||
np.setTexture(texture, 100)
|
||||
newNP = np
|
||||
if key2 == 'c':
|
||||
if category == 'TI_wallpaper' or category == 'TI_wallpaper_border':
|
||||
if key2 == "c":
|
||||
if (category == "TI_wallpaper") or (category == "TI_wallpaper_border"):
|
||||
self.randomGenerator.seed(self.zoneId)
|
||||
newNP.setColorScale(self.randomGenerator.choice(self.colors[category]))
|
||||
newNP.setColorScale(
|
||||
self.randomGenerator.choice(self.colors[category]))
|
||||
else:
|
||||
newNP.setColorScale(self.randomGenerator.choice(self.colors[category]))
|
||||
newNP.setColorScale(
|
||||
self.randomGenerator.choice(self.colors[category]))
|
||||
|
||||
def setup(self):
|
||||
self.dnaStore = base.cr.playGame.dnaStore
|
||||
self.randomGenerator = random.Random()
|
||||
|
||||
# The math here is a little arbitrary. I'm trying to get a
|
||||
# substantially different seed for each zondId, even on the
|
||||
# same street. But we don't want to weigh to much on the
|
||||
# block number, because we want the same block number on
|
||||
# different streets to be different.
|
||||
# Here we use the block number and a little of the branchId:
|
||||
# seedX=self.zoneId&0x00ff
|
||||
# Here we're using only the branchId:
|
||||
# seedY=self.zoneId/100
|
||||
# Here we're using only the block number:
|
||||
# seedZ=256-int(self.block)
|
||||
|
||||
self.randomGenerator.seed(self.zoneId)
|
||||
self.interior = loader.loadModel('phase_3.5/models/modules/toon_interior_tutorial')
|
||||
self.interior.reparentTo(render)
|
||||
dnaStore = DNAStorage()
|
||||
node = loader.loadDNAFile(self.cr.playGame.hood.dnaStore, 'phase_3.5/dna/tutorial_street.dna')
|
||||
self.street = render.attachNewNode(node)
|
||||
|
||||
self.interior = loader.loadModel("phase_3.5/models/modules/toon_interior_tutorial")
|
||||
self.interior.reparentTo(base.render)
|
||||
node = loader.loadDNAFile(self.cr.playGame.hood.dnaStore, "phase_3.5/dna/tutorial_street.dna")
|
||||
self.street = base.render.attachNewNode(node)
|
||||
self.street.flattenMedium()
|
||||
self.street.setPosHpr(-17, 42, -0.5, 180, 0, 0)
|
||||
self.street.find('**/tb2:toon_landmark_TT_A1_DNARoot').stash()
|
||||
self.street.find('**/tb1:toon_landmark_hqTT_DNARoot/**/door_flat_0').stash()
|
||||
self.street.findAllMatches('**/+CollisionNode').stash()
|
||||
self.skyFile = 'phase_3.5/models/props/TT_sky'
|
||||
# Get rid of the building we are in
|
||||
self.street.find("**/tb2:toon_landmark_TT_A1_DNARoot").stash()
|
||||
# Get rid of the flashing doors on the HQ building
|
||||
self.street.find("**/tb1:toon_landmark_hqTT_DNARoot/**/door_flat_0").stash()
|
||||
# Get rid of collisions because we do not need them and they get in the way
|
||||
self.street.findAllMatches("**/+CollisionNode").stash()
|
||||
self.skyFile = "phase_3.5/models/props/TT_sky"
|
||||
self.sky = loader.loadModel(self.skyFile)
|
||||
self.sky.setScale(0.8)
|
||||
self.sky.reparentTo(render)
|
||||
# Parent the sky to our camera, the task will counter rotate it
|
||||
self.sky.reparentTo(base.render)
|
||||
# Turn off depth tests on the sky because as the cloud layers interpenetrate
|
||||
# we do not want to see the polys cutoff. Since there is nothing behing them
|
||||
# we can get away with this.
|
||||
self.sky.setDepthTest(0)
|
||||
self.sky.setDepthWrite(0)
|
||||
self.sky.setBin('background', 100)
|
||||
self.sky.find('**/Sky').reparentTo(self.sky, -1)
|
||||
self.sky.setBin("background", 100)
|
||||
# Make sure they are drawn in the correct order in the hierarchy
|
||||
# The sky should be first, then the clouds
|
||||
self.sky.find("**/Sky").reparentTo(self.sky, -1)
|
||||
|
||||
# Load a color dictionary for this hood:
|
||||
hoodId = ZoneUtil.getCanonicalHoodId(self.zoneId)
|
||||
self.colors = ToonInteriorColors.colors[hoodId]
|
||||
# Replace all the "random_xxx_" nodes:
|
||||
self.replaceRandomInModel(self.interior)
|
||||
doorModelName = 'door_double_round_ul'
|
||||
if doorModelName[-1:] == 'r':
|
||||
doorModelName = doorModelName[:-1] + 'l'
|
||||
|
||||
# Door:
|
||||
doorModelName = "door_double_round_ul" # hack zzzzzzz
|
||||
# Switch leaning of the door:
|
||||
if doorModelName[-1:] == "r":
|
||||
doorModelName = doorModelName[:-1] + "l"
|
||||
else:
|
||||
doorModelName = doorModelName[:-1] + 'r'
|
||||
doorModelName = doorModelName[:-1] + "r"
|
||||
door = self.dnaStore.findNode(doorModelName)
|
||||
door_origin = render.find('**/door_origin;+s')
|
||||
# Determine where should we put the door:
|
||||
door_origin = base.render.find("**/door_origin;+s")
|
||||
doorNP = door.copyTo(door_origin)
|
||||
assert (not doorNP.isEmpty())
|
||||
assert (not door_origin.isEmpty())
|
||||
# The rooms are too small for doors:
|
||||
door_origin.setScale(0.8, 0.8, 0.8)
|
||||
# Move the origin away from the wall so it does not shimmer
|
||||
# We do this instead of decals
|
||||
door_origin.setPos(door_origin, 0, -0.025, 0)
|
||||
color = self.randomGenerator.choice(self.colors['TI_door'])
|
||||
DNADoor.setupDoor(doorNP, self.interior, door_origin, self.dnaStore, str(self.block), color)
|
||||
doorFrame = doorNP.find('door_*_flat')
|
||||
color = self.randomGenerator.choice(self.colors["TI_door"])
|
||||
DNADoor.setupDoor(doorNP,
|
||||
self.interior, door_origin,
|
||||
self.dnaStore,
|
||||
str(self.block), color)
|
||||
# Setting the wallpaper texture with a priority overrides
|
||||
# the door texture, if it's decalled. So, we're going to
|
||||
# move it out from the decal, and float it in front of
|
||||
# the wall:
|
||||
doorFrame = doorNP.find("door_*_flat")
|
||||
doorFrame.wrtReparentTo(self.interior)
|
||||
doorFrame.setColor(color)
|
||||
|
||||
del self.colors
|
||||
del self.dnaStore
|
||||
del self.randomGenerator
|
||||
|
||||
# Get rid of any transitions and extra nodes
|
||||
self.interior.flattenMedium()
|
||||
npcOrigin = self.interior.find('**/npc_origin_' + repr((self.npc.posIndex)))
|
||||
|
||||
# Ok, this is a hack, but I'm tired of this freakin tutorial.
|
||||
# The problem is the interior must be created first so the npc can find the origin
|
||||
# of where to stand, but in this case the npc must be created first so the tutorial
|
||||
# can get a handle on him. Instead, I'll let the npc be created first which means
|
||||
# he will not find his origin. We'll just do that work here again.
|
||||
npcOrigin = self.interior.find(f"**/npc_origin_{self.npc.posIndex}")
|
||||
# Now he's no longer parented to render, but no one minds.
|
||||
if not npcOrigin.isEmpty():
|
||||
self.npc.reparentTo(npcOrigin)
|
||||
self.npc.clearMat()
|
||||
|
||||
self.createSuit()
|
||||
self.mickeyMovie = QuestParser.NPCMoviePlayer('tutorial_mickey', base.localAvatar, self.npc)
|
||||
|
||||
self.mickeyMovie = QuestParser.NPCMoviePlayer("tutorial_mickey", base.localAvatar, self.npc)
|
||||
place = base.cr.playGame.getPlace()
|
||||
if place and hasattr(place, 'fsm') and place.fsm.getCurrentState().getName():
|
||||
self.notify.info('Tutorial movie: Place ready.')
|
||||
self.playMovie()
|
||||
else:
|
||||
self.notify.info('Tutorial movie: Waiting for place=%s, has fsm=%s' % (place, hasattr(place, 'fsm')))
|
||||
self.notify.info(f'Tutorial movie: Waiting for place={place}, has fsm={hasattr(place, "fsm")}')
|
||||
if hasattr(place, 'fsm'):
|
||||
self.notify.info('Tutorial movie: place state=%s' % place.fsm.getCurrentState().getName())
|
||||
self.notify.info(f'Tutorial movie: place state={place.fsm.getCurrentState().getName()}')
|
||||
self.acceptOnce('enterTutorialInterior', self.playMovie)
|
||||
|
||||
def playMovie(self):
|
||||
|
|
@ -144,6 +214,7 @@ class DistributedTutorialInterior(DistributedObject.DistributedObject):
|
|||
self.mickeyMovie.play()
|
||||
|
||||
def createSuit(self):
|
||||
# Create a suit
|
||||
self.suit = Suit.Suit()
|
||||
suitDNA = SuitDNA.SuitDNA()
|
||||
suitDNA.newSuit('f')
|
||||
|
|
@ -151,7 +222,19 @@ class DistributedTutorialInterior(DistributedObject.DistributedObject):
|
|||
self.suit.loop('neutral')
|
||||
self.suit.setPosHpr(-20, 8, 0, 0, 0, 0)
|
||||
self.suit.reparentTo(self.interior)
|
||||
self.suitWalkTrack = Sequence(self.suit.hprInterval(0.1, Vec3(0, 0, 0)), Func(self.suit.loop, 'walk'), self.suit.posInterval(2, Point3(-20, 20, 0)), Func(self.suit.loop, 'neutral'), Wait(1.0), self.suit.hprInterval(0.1, Vec3(180, 0, 0)), Func(self.suit.loop, 'walk'), self.suit.posInterval(2, Point3(-20, 10, 0)), Func(self.suit.loop, 'neutral'), Wait(1.0))
|
||||
|
||||
self.suitWalkTrack = Sequence(
|
||||
self.suit.hprInterval(0.1, Vec3(0, 0, 0)),
|
||||
Func(self.suit.loop, 'walk'),
|
||||
self.suit.posInterval(2, Point3(-20, 20, 0)),
|
||||
Func(self.suit.loop, 'neutral'),
|
||||
Wait(1.0),
|
||||
self.suit.hprInterval(0.1, Vec3(180, 0, 0)),
|
||||
Func(self.suit.loop, 'walk'),
|
||||
self.suit.posInterval(2, Point3(-20, 10, 0)),
|
||||
Func(self.suit.loop, 'neutral'),
|
||||
Wait(1.0),
|
||||
)
|
||||
self.suitWalkTrack.loop()
|
||||
|
||||
def setZoneIdAndBlock(self, zoneId, block):
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
from toontown.toonbase.ToontownGlobals import *
|
||||
from otp.ai.AIBaseGlobal import *
|
||||
from direct.distributed.ClockDelta import *
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed import DistributedObjectAI
|
||||
from toontown.toon import NPCToons
|
||||
|
||||
|
||||
class DistributedTutorialInteriorAI(DistributedObjectAI.DistributedObjectAI):
|
||||
|
||||
if __debug__:
|
||||
|
|
@ -13,14 +10,12 @@ class DistributedTutorialInteriorAI(DistributedObjectAI.DistributedObjectAI):
|
|||
|
||||
def __init__(self, block, air, zoneId, building, npcId):
|
||||
"""blockNumber: the landmark building number (from the name)"""
|
||||
#self.air=air
|
||||
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||||
self.block=block
|
||||
self.zoneId=zoneId
|
||||
self.building=building
|
||||
self.block = block
|
||||
self.zoneId = zoneId
|
||||
self.building = building
|
||||
self.tutorialNpcId = npcId
|
||||
|
||||
|
||||
# Make any npcs that may be in this interior zone
|
||||
# If there are none specified, this will just be an empty list
|
||||
self.npcs = NPCToons.createNpcsInZone(air, zoneId)
|
||||
|
|
@ -32,9 +27,9 @@ class DistributedTutorialInteriorAI(DistributedObjectAI.DistributedObjectAI):
|
|||
del self.npcs
|
||||
del self.building
|
||||
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||
|
||||
|
||||
def getZoneIdAndBlock(self):
|
||||
return [self.zoneId, self.block]
|
||||
|
||||
|
||||
def getTutorialNpcId(self):
|
||||
return self.tutorialNpcId
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.building import DistributedDoorAI
|
||||
from toontown.building import DistributedHQInteriorAI
|
||||
from toontown.building import FADoorCodes
|
||||
|
|
@ -8,17 +6,19 @@ from toontown.toon import NPCToons
|
|||
from toontown.quest import Quests
|
||||
from toontown.toonbase import TTLocalizer
|
||||
|
||||
|
||||
# This is not a distributed class... It just owns and manages some distributed
|
||||
# classes.
|
||||
|
||||
class TutorialHQBuildingAI:
|
||||
|
||||
def __init__(self, air, exteriorZone, interiorZone, blockNumber):
|
||||
# While this is not a distributed object, it needs to know about
|
||||
# the repository.
|
||||
self.air = air
|
||||
self.exteriorZone = exteriorZone
|
||||
self.interiorZone = interiorZone
|
||||
|
||||
|
||||
self.setup(blockNumber)
|
||||
|
||||
def cleanup(self):
|
||||
|
|
@ -34,17 +34,17 @@ class TutorialHQBuildingAI:
|
|||
del self.insideDoor0
|
||||
self.insideDoor1.requestDelete()
|
||||
del self.insideDoor1
|
||||
return
|
||||
|
||||
def setup(self, blockNumber):
|
||||
# The interior
|
||||
self.interior=DistributedHQInteriorAI.DistributedHQInteriorAI(
|
||||
self.interior = DistributedHQInteriorAI.DistributedHQInteriorAI(
|
||||
blockNumber, self.air, self.interiorZone)
|
||||
|
||||
# We do not use a standard npc toon here becuase these npcs are created on
|
||||
# the fly for as many tutorials as we need. The interior zone is not known
|
||||
# until the ai allocates a zone, so we fabricate the description here.
|
||||
desc = (self.interiorZone, TTLocalizer.TutorialHQOfficerName, ('dls', 'ms', 'm', 'm', 6,0,6,6,0,10,0,10,2,9), "m", 1, 0)
|
||||
desc = (self.interiorZone, TTLocalizer.TutorialHQOfficerName,
|
||||
('dls', 'ms', 'm', 'm', 6, 0, 6, 6, 0, 10, 0, 10, 2, 9), "m", 1, 0)
|
||||
self.npc = NPCToons.createNPC(self.air, Quests.ToonHQ, desc,
|
||||
self.interiorZone,
|
||||
questCallback=self.unlockInsideDoor1)
|
||||
|
|
@ -53,24 +53,24 @@ class TutorialHQBuildingAI:
|
|||
|
||||
self.interior.generateWithRequired(self.interiorZone)
|
||||
# Outside door 0. Locked til you defeat the Flunky:
|
||||
door0=DistributedDoorAI.DistributedDoorAI(
|
||||
door0 = DistributedDoorAI.DistributedDoorAI(
|
||||
self.air, blockNumber, DoorTypes.EXT_HQ,
|
||||
doorIndex=0,
|
||||
lockValue=FADoorCodes.DEFEAT_FLUNKY_HQ)
|
||||
# Outside door 1. Always locked.
|
||||
door1=DistributedDoorAI.DistributedDoorAI(
|
||||
door1 = DistributedDoorAI.DistributedDoorAI(
|
||||
self.air, blockNumber, DoorTypes.EXT_HQ,
|
||||
doorIndex=1,
|
||||
lockValue=FADoorCodes.GO_TO_PLAYGROUND)
|
||||
# Inside door 0. Always locked, but the message will change.
|
||||
insideDoor0=DistributedDoorAI.DistributedDoorAI(
|
||||
insideDoor0 = DistributedDoorAI.DistributedDoorAI(
|
||||
self.air,
|
||||
blockNumber,
|
||||
DoorTypes.INT_HQ,
|
||||
doorIndex=0,
|
||||
lockValue=FADoorCodes.TALK_TO_HQ)
|
||||
# Inside door 1. Locked til you get your HQ reward.
|
||||
insideDoor1=DistributedDoorAI.DistributedDoorAI(
|
||||
insideDoor1 = DistributedDoorAI.DistributedDoorAI(
|
||||
self.air,
|
||||
blockNumber,
|
||||
DoorTypes.INT_HQ,
|
||||
|
|
@ -82,10 +82,10 @@ class TutorialHQBuildingAI:
|
|||
door1.setOtherDoor(insideDoor1)
|
||||
insideDoor1.setOtherDoor(door1)
|
||||
# Put them in the right zones
|
||||
door0.zoneId=self.exteriorZone
|
||||
door1.zoneId=self.exteriorZone
|
||||
insideDoor0.zoneId=self.interiorZone
|
||||
insideDoor1.zoneId=self.interiorZone
|
||||
door0.zoneId = self.exteriorZone
|
||||
door1.zoneId = self.exteriorZone
|
||||
insideDoor0.zoneId = self.interiorZone
|
||||
insideDoor1.zoneId = self.interiorZone
|
||||
# Now that they both now about each other, generate them:
|
||||
door0.generateWithRequired(self.exteriorZone)
|
||||
door1.generateWithRequired(self.exteriorZone)
|
||||
|
|
@ -96,14 +96,13 @@ class TutorialHQBuildingAI:
|
|||
insideDoor0.sendUpdate("setDoorIndex", [insideDoor0.getDoorIndex()])
|
||||
insideDoor1.sendUpdate("setDoorIndex", [insideDoor1.getDoorIndex()])
|
||||
# keep track of them:
|
||||
self.door0=door0
|
||||
self.door1=door1
|
||||
self.insideDoor0=insideDoor0
|
||||
self.insideDoor1=insideDoor1
|
||||
self.door0 = door0
|
||||
self.door1 = door1
|
||||
self.insideDoor0 = insideDoor0
|
||||
self.insideDoor1 = insideDoor1
|
||||
# hide the periscope
|
||||
self.interior.setTutorial(1)
|
||||
return
|
||||
|
||||
|
||||
def unlockDoor(self, door):
|
||||
door.setDoorLock(FADoorCodes.UNLOCKED)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
from toontown.battle import DistributedBattle
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.battle import DistributedBattle
|
||||
|
||||
|
||||
class DistributedBattleTutorial(DistributedBattle.DistributedBattle):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBattleTutorial')
|
||||
|
||||
def startTimer(self, ts = 0):
|
||||
def startTimer(self, ts=0):
|
||||
# Instead of starting the countdown,
|
||||
# hide the clock!
|
||||
self.townBattle.timer.hide()
|
||||
|
||||
def playReward(self, ts):
|
||||
self.movie.playTutorialReward(ts, self.uniqueName('reward'), self.handleRewardDone)
|
||||
self.movie.playTutorialReward(ts, self.uniqueName('reward'),
|
||||
self.handleRewardDone)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
from toontown.battle import DistributedBattleAI
|
||||
from toontown.battle import DistributedBattleBaseAI
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.battle import DistributedBattleAI
|
||||
|
||||
|
||||
class DistributedBattleTutorialAI(DistributedBattleAI.DistributedBattleAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBattleTutorialAI')
|
||||
|
||||
|
||||
def __init__(self, air, battleMgr, pos, suit, toonId, zoneId,
|
||||
finishCallback=None, maxSuits=4, interactivePropTrackBonus = -1):
|
||||
"""__init__(air, battleMgr, pos, suit, toonId, zoneId,
|
||||
finishCallback, maxSuits)
|
||||
"""
|
||||
finishCallback=None, maxSuits=4, interactivePropTrackBonus=-1):
|
||||
DistributedBattleAI.DistributedBattleAI.__init__(
|
||||
self, air, battleMgr, pos, suit, toonId, zoneId,
|
||||
finishCallback, maxSuits, tutorialFlag=1)
|
||||
|
|
@ -17,7 +14,3 @@ class DistributedBattleTutorialAI(DistributedBattleAI.DistributedBattleAI):
|
|||
# There is no timer in the tutorial... The reward movie is random length.
|
||||
def startRewardTimer(self):
|
||||
pass
|
||||
|
||||
#def handleRewardDone(self):
|
||||
# DistributedBattleAI.DistributedBattleAI.handleRewardDone(self)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
which handles management of the suit you will fight during the
|
||||
tutorial."""
|
||||
|
||||
from otp.ai.AIBaseGlobal import *
|
||||
|
||||
from panda3d.core import Vec3
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.suit import DistributedTutorialSuitAI
|
||||
from toontown.tutorial import TutorialBattleManagerAI
|
||||
|
||||
|
||||
class SuitPlannerTutorialAI:
|
||||
"""
|
||||
SuitPlannerTutorialAI: manages the single suit that you fight during
|
||||
|
|
@ -44,13 +44,13 @@ class SuitPlannerTutorialAI:
|
|||
self.suit.requestDelete()
|
||||
self.suit = None
|
||||
if self.battle:
|
||||
#self.battle.requestDelete()
|
||||
#RAU made to kill the mem leak when you close the window in the middle of the battle tutorial
|
||||
# self.battle.requestDelete()
|
||||
# RAU made to kill the mem leak when you close the window in the middle of the battle tutorial
|
||||
cellId = self.battle.battleCellId
|
||||
battleMgr = self.battle.battleMgr
|
||||
if cellId in battleMgr.cellId2battle:
|
||||
battleMgr.destroy(self.battle)
|
||||
|
||||
|
||||
self.battle = None
|
||||
|
||||
def getDoId(self):
|
||||
|
|
@ -61,16 +61,14 @@ class SuitPlannerTutorialAI:
|
|||
return 0
|
||||
|
||||
def requestBattle(self, zoneId, suit, toonId):
|
||||
# 70, 20, 0 is a battle cell position that I just made up.
|
||||
# 35, 20, -0.5 is a battle cell position that I just made up.
|
||||
self.battle = self.battleMgr.newBattle(
|
||||
zoneId, zoneId, Vec3(35, 20, 0),
|
||||
zoneId, zoneId, Vec3(35, 20, -0.5),
|
||||
suit, toonId,
|
||||
finishCallback=self.battleOverCallback)
|
||||
return 1
|
||||
return True
|
||||
|
||||
def removeSuit(self, suit):
|
||||
# Get rid of the suit.
|
||||
suit.requestDelete()
|
||||
self.suit = None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
from toontown.battle import BattleManagerAI
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.battle import BattleManagerAI
|
||||
from toontown.tutorial import DistributedBattleTutorialAI
|
||||
|
||||
class TutorialBattleManagerAI(BattleManagerAI.BattleManagerAI):
|
||||
|
||||
class TutorialBattleManagerAI(BattleManagerAI.BattleManagerAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('TutorialBattleManagerAI')
|
||||
|
||||
def __init__(self, air):
|
||||
BattleManagerAI.BattleManagerAI.__init__(self, air)
|
||||
self.battleConstructor = DistributedBattleTutorialAI.DistributedBattleTutorialAI
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
from pandac.PandaModules import *
|
||||
from toontown.toontowngui import TTDialog
|
||||
from toontown.toonbase import TTLocalizer
|
||||
from toontown.toontowngui import TTDialog
|
||||
|
||||
|
||||
class TutorialForceAcknowledge:
|
||||
|
||||
def __init__(self, doneEvent):
|
||||
self.doneEvent = doneEvent
|
||||
self.dialog = None
|
||||
return
|
||||
|
||||
def enter(self):
|
||||
base.localAvatar.loop('neutral')
|
||||
# Make the toon stop running.
|
||||
base.localAvatar.loop("neutral")
|
||||
self.doneStatus = {'mode': 'incomplete'}
|
||||
msg = TTLocalizer.TutorialForceAcknowledgeMessage
|
||||
self.dialog = TTDialog.TTDialog(text=msg, command=self.handleOk, style=TTDialog.Acknowledge)
|
||||
self.dialog = TTDialog.TTDialog(text=msg,
|
||||
command=self.handleOk,
|
||||
style=TTDialog.Acknowledge)
|
||||
|
||||
def exit(self):
|
||||
if self.dialog:
|
||||
self.dialog.cleanup()
|
||||
self.dialog = None
|
||||
return
|
||||
|
||||
def handleOk(self, value):
|
||||
messenger.send(self.doneEvent, [self.doneStatus])
|
||||
|
|
|
|||
|
|
@ -1,45 +1,57 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.distributed import DistributedObject
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.hood import ZoneUtil
|
||||
|
||||
class TutorialManager(DistributedObject.DistributedObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('TutorialManager')
|
||||
neverDisable = 1
|
||||
|
||||
def __init__(self, cr):
|
||||
DistributedObject.DistributedObject.__init__(self, cr)
|
||||
class TutorialManager(DistributedObject.DistributedObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("TutorialManager")
|
||||
neverDisable = 1
|
||||
|
||||
def generate(self):
|
||||
DistributedObject.DistributedObject.generate(self)
|
||||
messenger.send('tmGenerate')
|
||||
self.accept('requestTutorial', self.d_requestTutorial)
|
||||
self.accept('requestSkipTutorial', self.d_requestSkipTutorial)
|
||||
self.accept('rejectTutorial', self.d_rejectTutorial)
|
||||
# Let the cr know we have arrived.
|
||||
messenger.send("tmGenerate")
|
||||
# Wait for a tutorial request or rejection.
|
||||
self.accept("requestTutorial", self.d_requestTutorial)
|
||||
self.accept("requestSkipTutorial", self.d_requestSkipTutorial)
|
||||
self.accept("rejectTutorial", self.d_rejectTutorial)
|
||||
|
||||
def disable(self):
|
||||
self.ignoreAll()
|
||||
# In case we fell asleep in the tutorial
|
||||
ZoneUtil.overrideOff()
|
||||
DistributedObject.DistributedObject.disable(self)
|
||||
|
||||
def d_requestTutorial(self):
|
||||
self.sendUpdate('requestTutorial', [])
|
||||
self.sendUpdate("requestTutorial", [])
|
||||
|
||||
def d_rejectTutorial(self):
|
||||
self.sendUpdate('rejectTutorial', [])
|
||||
self.sendUpdate("rejectTutorial", [])
|
||||
|
||||
def d_requestSkipTutorial(self):
|
||||
self.sendUpdate('requestSkipTutorial', [])
|
||||
self.sendUpdate("requestSkipTutorial", [])
|
||||
|
||||
def skipTutorialResponse(self, allOk):
|
||||
messenger.send('skipTutorialAnswered', [allOk])
|
||||
"""Handle AI responding to our skip tutorial request."""
|
||||
messenger.send("skipTutorialAnswered", [allOk])
|
||||
|
||||
def enterTutorial(self, branchZone, streetZone, shopZone, hqZone):
|
||||
base.localAvatar.cantLeaveGame = 1
|
||||
ZoneUtil.overrideOn(branch=branchZone, exteriorList=[streetZone], interiorList=[shopZone, hqZone])
|
||||
messenger.send('startTutorial', [shopZone])
|
||||
self.acceptOnce('stopTutorial', self.__handleStopTutorial)
|
||||
self.acceptOnce('toonArrivedTutorial', self.d_toonArrived)
|
||||
# Override the ZoneUtil
|
||||
ZoneUtil.overrideOn(branch=branchZone,
|
||||
exteriorList=[streetZone],
|
||||
interiorList=[shopZone, hqZone])
|
||||
# We start the tutorial in the gag shop.
|
||||
messenger.send("startTutorial", [shopZone])
|
||||
# Add a hook on the tutorialDone event, which will get
|
||||
# thrown when we are leaving the tutorial (by the handleEnterTunnel
|
||||
# function in TutorialStreet.py
|
||||
self.acceptOnce("stopTutorial", self.__handleStopTutorial)
|
||||
# Add a hook that the Tutorial hood will send when the toon
|
||||
# is fully in a zone. This lets the AI know it is clear to
|
||||
# reset the toon properties in preparation for the tutorial
|
||||
# (in case they bailed halfway through before)
|
||||
self.acceptOnce("toonArrivedTutorial", self.d_toonArrived)
|
||||
|
||||
def __handleStopTutorial(self):
|
||||
base.localAvatar.cantLeaveGame = 0
|
||||
|
|
@ -47,7 +59,7 @@ class TutorialManager(DistributedObject.DistributedObject):
|
|||
ZoneUtil.overrideOff()
|
||||
|
||||
def d_allDone(self):
|
||||
self.sendUpdate('allDone', [])
|
||||
self.sendUpdate("allDone", [])
|
||||
|
||||
def d_toonArrived(self):
|
||||
self.sendUpdate('toonArrived', [])
|
||||
self.sendUpdate("toonArrived", [])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from otp.ai.AIBaseGlobal import *
|
||||
from pandac.PandaModules import *
|
||||
from panda3d.toontown import DNAStorage
|
||||
from direct.distributed import DistributedObjectAI
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.building import TutorialBuildingAI
|
||||
|
|
@ -7,10 +6,10 @@ from toontown.building import TutorialHQBuildingAI
|
|||
from toontown.tutorial import SuitPlannerTutorialAI
|
||||
from toontown.toonbase import ToontownBattleGlobals
|
||||
from toontown.toon import NPCToons
|
||||
from toontown.toonbase import TTLocalizer
|
||||
from toontown.ai import BlackCatHolidayMgrAI
|
||||
from toontown.ai import DistributedBlackCatMgrAI
|
||||
|
||||
|
||||
class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("TutorialManagerAI")
|
||||
|
||||
|
|
@ -37,21 +36,19 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
# Assumption: the only block that isn't an HQ is the gag shop block.
|
||||
self.hqBlock = None
|
||||
self.gagBlock = None
|
||||
for blockIndex in range (0, numBlocks):
|
||||
for blockIndex in range(0, numBlocks):
|
||||
blockNumber = self.dnaStore.getBlockNumberAt(blockIndex)
|
||||
buildingType = self.dnaStore.getBlockBuildingType(blockNumber)
|
||||
if (buildingType == 'hq'):
|
||||
self.hqBlock = blockNumber
|
||||
else:
|
||||
self.gagBlock = blockNumber
|
||||
|
||||
|
||||
assert self.hqBlock and self.gagBlock
|
||||
|
||||
# key is avId, value is real time when the request was made
|
||||
self.avIdsRequestingSkip = {}
|
||||
self.accept("avatarEntered", self.waitingToonEntered )
|
||||
|
||||
return None
|
||||
self.accept("avatarEntered", self.waitingToonEntered)
|
||||
|
||||
def requestTutorial(self):
|
||||
# TODO: possible security breach: what if client is repeatedly
|
||||
|
|
@ -100,7 +97,6 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
# No cogs defeated
|
||||
av.b_setCogStatus([1] * 32)
|
||||
av.b_setCogCount([0] * 32)
|
||||
return
|
||||
|
||||
def allDone(self):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
|
|
@ -118,13 +114,12 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
str(avId) +
|
||||
" isn't here, but just finished a tutorial. " +
|
||||
"I will ignore this."
|
||||
)
|
||||
return
|
||||
)
|
||||
|
||||
def __createTutorial(self, avId):
|
||||
if self.playerDict.get(avId):
|
||||
self.notify.warning(str(avId) + " is already in the playerDict!")
|
||||
|
||||
|
||||
branchZone = self.air.allocateZone()
|
||||
streetZone = self.air.allocateZone()
|
||||
shopZone = self.air.allocateZone()
|
||||
|
|
@ -143,7 +138,7 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
def battleOverCallback(zoneId):
|
||||
hqBuilding.battleOverCallback()
|
||||
building.battleOverCallback()
|
||||
|
||||
|
||||
# Create a suit planner
|
||||
suitPlanner = SuitPlannerTutorialAI.SuitPlannerTutorialAI(
|
||||
self.air,
|
||||
|
|
@ -151,8 +146,7 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
battleOverCallback)
|
||||
|
||||
# Create the NPC blocking the tunnel to the playground
|
||||
blockerNPC = NPCToons.createNPC(self.air, 20001, NPCToons.NPCToonDict[20001], streetZone,
|
||||
questCallback=self.__handleBlockDone)
|
||||
blockerNPC = NPCToons.createNPC(self.air, 20001, NPCToons.NPCToonDict[20001], streetZone)
|
||||
blockerNPC.setTutorial(1)
|
||||
|
||||
# is the black cat holiday enabled?
|
||||
|
|
@ -161,23 +155,20 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
blackCatMgr = DistributedBlackCatMgrAI.DistributedBlackCatMgrAI(
|
||||
self.air, avId)
|
||||
blackCatMgr.generateWithRequired(streetZone)
|
||||
|
||||
zoneDict={"branchZone" : branchZone,
|
||||
"streetZone" : streetZone,
|
||||
"shopZone" : shopZone,
|
||||
"hqZone" : hqZone,
|
||||
"building" : building,
|
||||
"hqBuilding" : hqBuilding,
|
||||
"suitPlanner" : suitPlanner,
|
||||
"blockerNPC" : blockerNPC,
|
||||
"blackCatMgr" : blackCatMgr,
|
||||
}
|
||||
|
||||
zoneDict = {"branchZone": branchZone,
|
||||
"streetZone": streetZone,
|
||||
"shopZone": shopZone,
|
||||
"hqZone": hqZone,
|
||||
"building": building,
|
||||
"hqBuilding": hqBuilding,
|
||||
"suitPlanner": suitPlanner,
|
||||
"blockerNPC": blockerNPC,
|
||||
"blackCatMgr": blackCatMgr,
|
||||
}
|
||||
self.playerDict[avId] = zoneDict
|
||||
return zoneDict
|
||||
|
||||
def __handleBlockDone(self):
|
||||
return None
|
||||
|
||||
def __destroyTutorial(self, avId):
|
||||
zoneDict = self.playerDict.get(avId)
|
||||
if zoneDict:
|
||||
|
|
@ -213,8 +204,7 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
str(avId) +
|
||||
" isn't here, but just rejected a tutorial. " +
|
||||
"I will ignore this."
|
||||
)
|
||||
return
|
||||
)
|
||||
|
||||
def respondToSkipTutorial(self, avId, av):
|
||||
"""Reply to the client if we let him skip the tutorial."""
|
||||
|
|
@ -239,7 +229,7 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
1000,
|
||||
1
|
||||
)
|
||||
|
||||
|
||||
self.air.questManager.completeAllQuestsMagically(av)
|
||||
av.removeQuest(101)
|
||||
self.air.questManager.assignQuest(avId,
|
||||
|
|
@ -253,7 +243,7 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
|
||||
# do whatever needs to be done to make his quest state good
|
||||
elif av:
|
||||
self.notify.debug("%s requestedSkipTutorial, but tutorialAck is 1")
|
||||
self.notify.debug(f"{avId} requestedSkipTutorial, but tutorialAck is 1")
|
||||
else:
|
||||
response = 0
|
||||
self.notify.warning(
|
||||
|
|
@ -261,31 +251,29 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
str(avId) +
|
||||
" isn't here, but requested to skip tutorial. " +
|
||||
"I will ignore this."
|
||||
)
|
||||
)
|
||||
self.sendUpdateToAvatarId(avId, "skipTutorialResponse", [response])
|
||||
return
|
||||
|
||||
def waitingToonEntered(self, av):
|
||||
"""Check if the avatar is someone who's requested to skip, then proceed accordingly."""
|
||||
avId = av.doId
|
||||
if avId in self.avIdsRequestingSkip:
|
||||
requestTime = self.avIdsRequestingSkip[avId]
|
||||
|
||||
|
||||
curTime = globalClock.getFrameTime()
|
||||
if (curTime - requestTime) <= self.WaitTimeForSkipTutorial:
|
||||
self.respondToSkipTutorial(avId, av)
|
||||
else:
|
||||
self.notify.warning("waited too long for toon %d responding no to skip tutorial request" % avId)
|
||||
self.notify.warning(f"waited too long for toon {avId} responding no to skip tutorial request")
|
||||
self.sendUpdateToAvatarId(avId, "skipTutorialResponse", [0])
|
||||
del self.avIdsRequestingSkip[avId]
|
||||
self.removeTask("skipTutorialToon-%d" % avId)
|
||||
|
||||
self.removeTask(f"skipTutorialToon-{avId}")
|
||||
|
||||
def waitForToonToEnter(self,avId):
|
||||
def waitForToonToEnter(self, avId):
|
||||
"""Mark our toon as requesting to skip, and start a task to timeout for it."""
|
||||
self.notify.debugStateCall(self)
|
||||
self.avIdsRequestingSkip[avId] = globalClock.getFrameTime()
|
||||
self.doMethodLater(self.WaitTimeForSkipTutorial, self.didNotGetToon, "skipTutorialToon-%d" % avId, [avId])
|
||||
self.doMethodLater(self.WaitTimeForSkipTutorial, self.didNotGetToon, f"skipTutorialToon-{avId}", [avId])
|
||||
|
||||
def didNotGetToon(self, avId):
|
||||
"""Just say no since the AI didn't get it."""
|
||||
|
|
@ -300,23 +288,19 @@ class TutorialManagerAI(DistributedObjectAI.DistributedObjectAI):
|
|||
self.notify.debugStateCall(self)
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
# Make sure the avatar exists
|
||||
av = self.air.doId2do.get(avId)
|
||||
av = self.air.doId2do.get(avId)
|
||||
if av:
|
||||
self.respondToSkipTutorial(avId,av)
|
||||
self.respondToSkipTutorial(avId, av)
|
||||
else:
|
||||
self.waitForToonToEnter(avId)
|
||||
|
||||
|
||||
def d_enterTutorial(self, avId, branchZone, streetZone, shopZone, hqZone):
|
||||
self.sendUpdateToAvatarId(avId, "enterTutorial", [branchZone,
|
||||
streetZone,
|
||||
shopZone,
|
||||
hqZone])
|
||||
return
|
||||
|
||||
def __handleUnexpectedExit(self, avId):
|
||||
self.notify.warning("Avatar: " + str(avId) +
|
||||
" has exited unexpectedly")
|
||||
self.__destroyTutorial(avId)
|
||||
return
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue