Merge remote-tracking branch 'origin/beta-wip' into estates
Conflicts: config/public_client.prc
This commit is contained in:
commit
e1f11bb0ac
69 changed files with 2405 additions and 943 deletions
|
@ -27,6 +27,7 @@ vfs-mount resources/phase_13 /phase_13
|
|||
model-path /
|
||||
default-model-extension .bam
|
||||
|
||||
|
||||
# Server settings
|
||||
want-rpc-server #f
|
||||
rpc-server-endpoint http://localhost:8080/
|
||||
|
|
|
@ -225,7 +225,7 @@ dclass DistributedAvatar : DistributedSmoothNode, TalkPath_whisper {
|
|||
setTalk(DoId fromAv, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) chat, TalkModification [], uint8 flags) broadcast;
|
||||
setTalkWhisper(DoId fromAv, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) chat, TalkModification [], uint8 flags) broadcast;
|
||||
string(0-400) chat, TalkModification [], uint8 flags) ownrecv;
|
||||
};
|
||||
|
||||
struct FriendEntry {
|
||||
|
@ -285,7 +285,7 @@ dclass OtpAvatarManager : DistributedObject {
|
|||
|
||||
dclass ChatAgent : DistributedObject {
|
||||
adminChat(uint32 aboutId, string message);
|
||||
chatMessage(string(0-256) message) clsend;
|
||||
chatMessage(string(0-256) message, uint8 chatMode) clsend;
|
||||
whisperMessage(uint32 receiverAvId, string(0-256) message) clsend;
|
||||
sfWhisperMessage(uint32 receiverAvId, string(0-256) message) clsend;
|
||||
};
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
# Client settings
|
||||
window-title Toontown Rewritten [BETA]
|
||||
server-version SERVER_VERSION_HERE
|
||||
language LANGUAGE_HERE
|
||||
audio-library-name p3openal_audio
|
||||
sync-video #f
|
||||
want-dev #f
|
||||
preload-avatars #t
|
||||
# This is a temporary 'fix' for DistributedSmoothNodes... probably not the permanent solution to our problem, but it works for now.
|
||||
smooth-lag 0.4
|
||||
language LANGUAGE_HERE
|
||||
|
||||
# Resources settings
|
||||
model-path /
|
||||
|
@ -32,6 +30,12 @@ vfs-mount phase_12.mf /
|
|||
vfs-mount phase_13.mf /
|
||||
default-model-extension .bam
|
||||
|
||||
# Now that we've loaded the phase files, tell panda to trust the TTRCA
|
||||
ssl-certificates phase_3/etc/TTRCA.crt
|
||||
|
||||
# This is the shared secret for CSMUD login
|
||||
# ##### NB! Update deployment/server.prc too! #####
|
||||
csmud-secret Yv1JrpTUdkX6M86h44Z9q4AUaQYdFnectDgl2I5HOQf8CBh7LUZWpzKB9FBD
|
||||
|
||||
# DC files are NOT configured.
|
||||
# They're wrapped up into the code automatically.
|
||||
|
@ -43,7 +47,8 @@ want-pets #f
|
|||
want-news-tab #f
|
||||
want-news-page #f
|
||||
want-old-fireworks #t
|
||||
want-accessories #f
|
||||
# This is a temporary 'fix' for DistributedSmoothNodes... probably not the permanent solution to our problem, but it works for now.
|
||||
smooth-lag 0.4
|
||||
|
||||
|
||||
# Holidays and Events
|
||||
|
|
|
@ -2853,7 +2853,7 @@ dclass DistributedGolfCourse : DistributedObject {
|
|||
setCurHoleIndex(int8 holeIndex) broadcast ram required;
|
||||
setCurHoleDoId(uint32 holeDoId) broadcast ram required;
|
||||
setDoneReward() airecv clsend;
|
||||
setReward(uint8 trophiesList[] [4], int8 rankingsList[], uint8 holeBestList[] [4], uint8 courseBestList[] [4], uint8 cupList[] [4], uint32 tieBreakWinner, uint32/100 aim0, uint32/100 aim1, uint32/100 aim2, uint32/100 aim3) broadcast;
|
||||
setReward(uint8[] [], int8[], uint8[] [], uint8[] [], uint8[] [], uint32, uint32/100, uint32/100, uint32/100, uint32/100) broadcast;
|
||||
setCourseReady(int8 numHoles, int16 holeIds[], int8 coursePar) broadcast;
|
||||
setHoleStart(int16 UNKNOWN) broadcast;
|
||||
setCourseExit() broadcast;
|
||||
|
@ -3272,11 +3272,9 @@ struct PotentialToon {
|
|||
};
|
||||
|
||||
dclass ClientServicesManager : DistributedObjectGlobal {
|
||||
login(string cookie) clsend;
|
||||
login(string cookie, blob sig) clsend;
|
||||
acceptLogin();
|
||||
|
||||
setClosed(bool closed);
|
||||
|
||||
requestAvatars() clsend;
|
||||
setAvatars(PotentialToon avatars[]);
|
||||
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
"astron": "a0608a9",
|
||||
"panda3d": "d048f43",
|
||||
"version-prefix": "ttr-beta-",
|
||||
"server-resources": ["dna", "xml", "txt", "dat"]
|
||||
}
|
||||
"server-resources": ["dna", "xml", "txt", "dat", "bam"]
|
||||
}
|
||||
|
|
|
@ -6,10 +6,17 @@
|
|||
want-dev #f
|
||||
want-cheesy-expirations #t
|
||||
|
||||
# Shared secret for CSMUD
|
||||
# ##### NB! Update config/public_client.prc too! #####
|
||||
csmud-secret Yv1JrpTUdkX6M86h44Z9q4AUaQYdFnectDgl2I5HOQf8CBh7LUZWpzKB9FBD
|
||||
|
||||
# ODE isn't ready yet :(
|
||||
want-golf #f
|
||||
|
||||
# Beta Modifications
|
||||
# Temporary modifications for unimplemented features go here.
|
||||
want-sbhq #t
|
||||
want-cbhq #f
|
||||
want-cbhq #t
|
||||
want-lbhq #f
|
||||
want-bbhq #f
|
||||
want-pets #f
|
||||
|
|
|
@ -104,7 +104,7 @@ class MagicWordCategory:
|
|||
self.words.append(word)
|
||||
|
||||
def getDefinedAccess(self):
|
||||
return config.GetInt('mw-' + self.name.replace(' ', '-').lower(), 0)
|
||||
return config.GetInt('mw-category-' + self.name.replace(' ', '-').lower(), 0)
|
||||
|
||||
CATEGORY_UNKNOWN = MagicWordCategory('Unknown')
|
||||
CATEGORY_GRAPHICAL = MagicWordCategory('Graphical debugging', defaultAccess=300,
|
||||
|
@ -215,6 +215,10 @@ class MagicWordDecorator:
|
|||
if name is None:
|
||||
name = mw.func_name
|
||||
|
||||
config_access = config.GetInt('mw-word-' + name.lower(), 0)
|
||||
if config_access:
|
||||
self.access = config_access
|
||||
|
||||
word = MagicWord(name, mw, self.types, self.access, mw.__doc__, self.category, self.targetClasses, self.aliases)
|
||||
spellbook.addWord(word)
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
|
||||
from pandac.PandaModules import *
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
|
||||
class ChatAgent(DistributedObjectGlobal):
|
||||
def __init__(self, cr):
|
||||
DistributedObjectGlobal.__init__(self, cr)
|
||||
self.chatMode = 0
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
self.cr.chatManager = None
|
||||
self.cr.chatAgent = None
|
||||
DistributedObjectGlobal.delete(self)
|
||||
return
|
||||
|
||||
|
@ -17,10 +20,35 @@ class ChatAgent(DistributedObjectGlobal):
|
|||
messenger.send('adminChat', [aboutId, message])
|
||||
|
||||
def sendChatMessage(self, message):
|
||||
self.sendUpdate('chatMessage', [message])
|
||||
self.sendUpdate('chatMessage', [message, self.chatMode])
|
||||
|
||||
def sendWhisperMessage(self, receiverAvId, message):
|
||||
self.sendUpdate('whisperMessage', [receiverAvId, message])
|
||||
|
||||
def sendSFWhisperMessage(self, receiverAvId, message):
|
||||
self.sendUpdate('sfWhisperMessage', [receiverAvId, message])
|
||||
|
||||
@magicWord(category=CATEGORY_MODERATION, types=[int])
|
||||
def chatmode(mode=-1):
|
||||
""" Set the chat mode of the current avatar. """
|
||||
mode2name = {
|
||||
0 : "user",
|
||||
1 : "moderator",
|
||||
2 : "administrator",
|
||||
3 : "system administrator",
|
||||
}
|
||||
if base.cr.chatAgent is None:
|
||||
return "No ChatAgent found."
|
||||
if mode == -1:
|
||||
return "You are currently talking in the %s chat mode." % mode2name.get(base.cr.chatAgent.chatMode, "N/A")
|
||||
if not 0 <= mode <= 3:
|
||||
return "Invalid chat mode specified."
|
||||
if mode == 3 and spellbook.getInvoker().getAdminAccess() < 500:
|
||||
return "Chat mode 3 is reserved for system administrators."
|
||||
if mode == 2 and spellbook.getInvoker().getAdminAccess() < 400:
|
||||
return "Chat mode 2 is reserved for administrators."
|
||||
if mode == 1 and spellbook.getInvoker().getAdminAccess() < 200:
|
||||
# Like this will ever happen, but whatever.
|
||||
return "Chat mode 1 is reserved for moderators."
|
||||
base.cr.chatAgent.chatMode = mode
|
||||
return "You are now talking in the %s chat mode." % mode2name.get(mode, "N/A")
|
||||
|
|
|
@ -2,6 +2,7 @@ from direct.directnotify import DirectNotifyGlobal
|
|||
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
||||
# TODO: OTP should not depend on Toontown... Hrrm.
|
||||
from toontown.chat.TTWhiteList import TTWhiteList
|
||||
from otp.distributed import OtpDoGlobals
|
||||
|
||||
class ChatAgentUD(DistributedObjectGlobalUD):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ChatAgentUD")
|
||||
|
@ -10,9 +11,18 @@ class ChatAgentUD(DistributedObjectGlobalUD):
|
|||
DistributedObjectGlobalUD.announceGenerate(self)
|
||||
|
||||
self.whiteList = TTWhiteList()
|
||||
|
||||
self.chatMode2channel = {
|
||||
1 : OtpDoGlobals.OTP_MOD_CHANNEL,
|
||||
2 : OtpDoGlobals.OTP_ADMIN_CHANNEL,
|
||||
3 : OtpDoGlobals.OTP_SYSADMIN_CHANNEL,
|
||||
}
|
||||
self.chatMode2prefix = {
|
||||
1 : "[MOD] ",
|
||||
2 : "[ADMIN] ",
|
||||
3 : "[SYSADMIN] ",
|
||||
}
|
||||
# Open chat
|
||||
def chatMessage(self, message):
|
||||
def chatMessage(self, message, chatMode):
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if sender == 0:
|
||||
self.air.writeServerEvent('suspicious', accId=self.air.getAccountIdFromSender(),
|
||||
|
@ -21,12 +31,20 @@ class ChatAgentUD(DistributedObjectGlobalUD):
|
|||
|
||||
cleanMessage, modifications = self.cleanWhitelist(message)
|
||||
|
||||
self.air.writeServerEvent('chat-said', avId=sender, msg=message, cleanMsg=cleanMessage)
|
||||
self.air.writeServerEvent('chat-said', avId=sender, chatMode=chatMode, msg=message, cleanMsg=cleanMessage)
|
||||
|
||||
# TODO: The above is probably a little too ugly for my taste... Maybe AIR
|
||||
# should be given an API for sending updates for unknown objects?
|
||||
if chatMode != 0:
|
||||
# Staff messages do not need to be cleaned. [TODO: Blacklist this?]
|
||||
if message.startswith('.'):
|
||||
# This is a thought bubble, move the point to the start.
|
||||
cleanMessage = '.' + self.chatMode2prefix.get(chatMode, "") + message[1:]
|
||||
else:
|
||||
cleanMessage = self.chatMode2prefix.get(chatMode, "") + message
|
||||
modifications = []
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalk', sender, sender,
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalk', sender, self.chatMode2channel.get(chatMode, sender),
|
||||
self.air.ourChannel,
|
||||
[0, 0, '', cleanMessage, modifications, 0])
|
||||
self.air.send(dg)
|
||||
|
@ -44,7 +62,7 @@ class ChatAgentUD(DistributedObjectGlobalUD):
|
|||
# Maybe a better "cleaner" way of doing this, but it works
|
||||
self.air.writeServerEvent('whisper-said', avId=sender, reciever=receiverAvId, msg=message, cleanMsg=cleanMessage)
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalkWhisper', receiverAvId, receiverAvId, self.air.ourChannel,
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalkWhisper', receiverAvId, receiverAvId, self.air.ourChannel,
|
||||
[sender, sender, '', cleanMessage, modifications, 0])
|
||||
self.air.send(dg)
|
||||
|
||||
|
@ -60,7 +78,7 @@ class ChatAgentUD(DistributedObjectGlobalUD):
|
|||
|
||||
self.air.writeServerEvent('sf-whisper-said', avId=sender, reciever=receiverAvId, msg=message, cleanMsg=cleanMessage)
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalkWhisper', receiverAvId, receiverAvId, self.air.ourChannel,
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalkWhisper', receiverAvId, receiverAvId, self.air.ourChannel,
|
||||
[sender, sender, '', cleanMessage, [], 0])
|
||||
self.air.send(dg)
|
||||
|
||||
|
|
|
@ -340,6 +340,8 @@ class ChatManager(DirectObject.DirectObject):
|
|||
|
||||
def changeFrameText(self, newText):
|
||||
self.whisperFrame['text'] = newText
|
||||
if len(newText) > 24:
|
||||
self.whisperFrame['text_pos'] = (0.18, 0.042)
|
||||
|
||||
def exitWhisper(self):
|
||||
self.whisperFrame.hide()
|
||||
|
|
|
@ -379,11 +379,11 @@ class TalkAssistant(DirectObject.DirectObject):
|
|||
|
||||
def receiveWhisperTalk(self, avatarId, avatarName, accountId, accountName, toId, toName, message, scrubbed = 0):
|
||||
error = None
|
||||
print 'receiveWhisperTalk %s %s %s %s %s' % (avatarId,
|
||||
self.notify.debug('receiveWhisperTalk %s %s %s %s %s' % (avatarId,
|
||||
avatarName,
|
||||
accountId,
|
||||
accountName,
|
||||
message)
|
||||
message))
|
||||
if not avatarName and avatarId:
|
||||
avatarName = self.findAvatarName(avatarId)
|
||||
if not accountName and accountId:
|
||||
|
@ -641,7 +641,7 @@ class TalkAssistant(DirectObject.DirectObject):
|
|||
if self.checkGuildTypedChat():
|
||||
base.cr.guildManager.sendTalk(message)
|
||||
else:
|
||||
print 'Guild chat error'
|
||||
self.notify.warning('Guild chat error')
|
||||
error = ERROR_NO_GUILD_CHAT
|
||||
return error
|
||||
|
||||
|
@ -709,7 +709,7 @@ class TalkAssistant(DirectObject.DirectObject):
|
|||
if self.checkGuildSpeedChat():
|
||||
base.cr.guildManager.sendSC(msgIndex)
|
||||
else:
|
||||
print 'Guild Speedchat error'
|
||||
self.notify.warning('Guild Speedchat error')
|
||||
error = ERROR_NO_GUILD_CHAT
|
||||
return error
|
||||
|
||||
|
|
|
@ -1496,7 +1496,11 @@ class OTPClientRepository(ClientRepositoryBase):
|
|||
elif msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER:
|
||||
self.handleGenerateWithRequired(di, other=True)
|
||||
elif msgType == CLIENT_OBJECT_SET_FIELD:
|
||||
self.handleUpdateField(di)
|
||||
# TODO: HACKFIX HERE, FIX PROPERLY!!!
|
||||
try:
|
||||
self.handleUpdateField(di)
|
||||
except AssertionError as e:
|
||||
self.notify.warning('AssertionError: %s' % e.message)
|
||||
elif msgType == CLIENT_OBJECT_LEAVING:
|
||||
self.handleDelete(di)
|
||||
else:
|
||||
|
|
|
@ -90,3 +90,6 @@ OTP_ZONE_ID_DISTRICTS = 3
|
|||
OTP_ZONE_ID_DISTRICTS_STATS = 4
|
||||
OTP_ZONE_ID_ELEMENTS = 5
|
||||
OTP_NET_MESSENGER_CHANNEL = (OTP_DO_ID_UBER_DOG << 32) + OTP_ZONE_ID_MANAGEMENT
|
||||
OTP_MOD_CHANNEL = 6200
|
||||
OTP_ADMIN_CHANNEL = 6400
|
||||
OTP_SYSADMIN_CHANNEL = 6500
|
||||
|
|
|
@ -24,6 +24,7 @@ class ClickablePopup(PandaNode, DirectObject):
|
|||
self.__hovered = False
|
||||
self.__onscreen = False
|
||||
self.__clickState = 0
|
||||
self.__clickArgs = []
|
||||
|
||||
self.__clickEvent = ''
|
||||
|
||||
|
@ -36,7 +37,7 @@ class ClickablePopup(PandaNode, DirectObject):
|
|||
self.__mwn.removeRegion(self.__region)
|
||||
self.ignoreAll()
|
||||
|
||||
def setClickRegionEvent(self, event):
|
||||
def setClickRegionEvent(self, event, clickArgs=[]):
|
||||
if event is None:
|
||||
# The caller is disabling us, so instead:
|
||||
self.__disabled = True
|
||||
|
@ -44,6 +45,7 @@ class ClickablePopup(PandaNode, DirectObject):
|
|||
self.__updateClickState()
|
||||
else:
|
||||
self.__clickEvent = event
|
||||
self.__clickArgs = clickArgs
|
||||
self.__disabled = False
|
||||
self.__region.setActive(True)
|
||||
self.__updateClickState()
|
||||
|
@ -97,7 +99,7 @@ class ClickablePopup(PandaNode, DirectObject):
|
|||
base.playSfx(NametagGlobals.clickSound)
|
||||
elif oldState == self.CS_CLICK and state == self.CS_HOVER:
|
||||
# Fire click event:
|
||||
messenger.send(self.__clickEvent)
|
||||
messenger.send(self.__clickEvent, self.__clickArgs)
|
||||
|
||||
self.clickStateChanged()
|
||||
|
||||
|
|
|
@ -9,23 +9,11 @@ class MarginManager(PandaNode):
|
|||
self.cells = set()
|
||||
self.visiblePopups = set()
|
||||
|
||||
def addGridCell(self, x, y, left, right, bottom, top):
|
||||
# FIXME: This is extremely ugly, but it looks fine on-screen.
|
||||
# TODO: For widescreen, the cells must be anchored to the a2d markers,
|
||||
# not to the MarginManager itself.
|
||||
padding = 0.125
|
||||
scale = 0.2
|
||||
xStart = left + scale/2. + padding
|
||||
yStart = bottom + scale/2. + padding
|
||||
xEnd = right - scale/2. - padding
|
||||
yEnd = top - scale/2. - padding
|
||||
xInc = (xEnd-xStart)/5.
|
||||
yInc = (yEnd-yStart)/3.5
|
||||
|
||||
def addGridCell(self, x, y, a2d):
|
||||
cell = MarginCell(self)
|
||||
cell.reparentTo(NodePath.anyPath(self))
|
||||
cell.setScale(scale)
|
||||
cell.setPos(xStart + xInc*x, 0, yStart + yInc*y)
|
||||
cell.reparentTo(a2d)
|
||||
cell.setScale(0.2)
|
||||
cell.setPos(x, 0, y)
|
||||
cell.setAvailable(True)
|
||||
cell.setPythonTag('MarginCell', cell)
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ class MarginPopup:
|
|||
pass # Fired externally when the result of isDisplayed changes. For subclasses.
|
||||
|
||||
def manage(self, manager):
|
||||
self.unmanage(self.__manager)
|
||||
if self.__manager:
|
||||
self.unmanage(self.__manager)
|
||||
self.__manager = manager
|
||||
|
||||
if self.__visible:
|
||||
|
|
|
@ -26,6 +26,14 @@ class WhisperPopup(MarginPopup, ClickablePopup):
|
|||
self.whisperType = whisperType
|
||||
self.timeout = timeout
|
||||
|
||||
self.active = False
|
||||
self.fromId = 0
|
||||
|
||||
self.left = 0.0
|
||||
self.right = 0.0
|
||||
self.top = 0.0
|
||||
self.bottom = 0.0
|
||||
|
||||
self.updateContents()
|
||||
|
||||
self.setPriority(2)
|
||||
|
@ -36,7 +44,9 @@ class WhisperPopup(MarginPopup, ClickablePopup):
|
|||
cc = self.whisperType
|
||||
else:
|
||||
cc = WTSystem
|
||||
fgColor, bgColor = WHISPER_COLORS[cc][0]
|
||||
|
||||
fgColor, bgColor = WHISPER_COLORS[cc][self.getClickState()]
|
||||
self.innerNP.node().removeAllChildren()
|
||||
|
||||
balloon, frame = NametagGlobals.speechBalloon2d.generate(
|
||||
self.text, self.font, textColor=fgColor, balloonColor=bgColor,
|
||||
|
@ -46,18 +56,42 @@ class WhisperPopup(MarginPopup, ClickablePopup):
|
|||
# Calculate the center of the TextNode.
|
||||
text = balloon.find('**/+TextNode')
|
||||
t = text.node()
|
||||
left, right, bottom, top = t.getFrameActual()
|
||||
center = self.innerNP.getRelativePoint(text,
|
||||
((left+right)/2., 0, (bottom+top)/2.))
|
||||
self.left, self.right, self.bottom, self.top = t.getFrameActual()
|
||||
center = self.innerNP.getRelativePoint(text, ((self.left + self.right) / 2., 0, (self.bottom + self.top) / 2.))
|
||||
|
||||
# Next translate the balloon along the inverse.
|
||||
balloon.setPos(balloon, -center)
|
||||
|
||||
if self.active and self.fromId:
|
||||
self.setClickRegionEvent('clickedWhisper', clickArgs=[self.fromId])
|
||||
|
||||
def setClickable(self, senderName, fromId, todo=0):
|
||||
pass
|
||||
self.active = True
|
||||
self.fromId = fromId
|
||||
|
||||
self.updateContents()
|
||||
self.__updateClickRegion()
|
||||
|
||||
def marginVisibilityChanged(self):
|
||||
self.__updateClickRegion()
|
||||
|
||||
def __updateClickRegion(self):
|
||||
if self.isDisplayed() and self.active:
|
||||
self.updateClickRegion(self.left, self.right, self.bottom, self.top)
|
||||
else:
|
||||
self.stashClickRegion()
|
||||
|
||||
def clickStateChanged(self):
|
||||
self.updateContents()
|
||||
|
||||
def manage(self, manager):
|
||||
MarginPopup.manage(self, manager)
|
||||
|
||||
taskMgr.doMethodLater(self.timeout, self.unmanage,
|
||||
'whisper-timeout-%d' % id(self), [manager])
|
||||
taskMgr.doMethodLater(self.timeout, self.unmanage, 'whisper-timeout-%d' % id(self), [manager])
|
||||
|
||||
# Manually Clean up
|
||||
def unmanage(self, manager):
|
||||
MarginPopup.unmanage(self, manager)
|
||||
|
||||
ClickablePopup.destroy(self)
|
||||
self.innerNP.removeNode()
|
||||
|
|
|
@ -175,7 +175,7 @@ WHISPER_COLORS = {
|
|||
# Normal FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.2, 0.6, 0.8, 0.6)),
|
||||
# Click FG BG
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 1.0)),
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 0.8)),
|
||||
# Hover FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.2, 0.7, 0.9, 0.6)),
|
||||
# Disable FG BG
|
||||
|
@ -185,7 +185,7 @@ WHISPER_COLORS = {
|
|||
# Normal FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.2, 0.6, 0.8, 0.6)),
|
||||
# Click FG BG
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 1.0)),
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 0.8)),
|
||||
# Hover FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.2, 0.7, 0.9, 0.6)),
|
||||
# Disable FG BG
|
||||
|
@ -195,9 +195,9 @@ WHISPER_COLORS = {
|
|||
# Normal FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.8, 0.3, 0.6, 0.6)),
|
||||
# Click FG BG
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 1.0)),
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 0.8)),
|
||||
# Hover FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.8, 0.4, 1.0, 1.0)),
|
||||
((0.0, 0.0, 0.0, 1.0), (0.8, 0.4, 1.0, 0.6)),
|
||||
# Disable FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.8, 0.3, 0.6, 0.6)),
|
||||
),
|
||||
|
@ -206,7 +206,7 @@ WHISPER_COLORS = {
|
|||
# Normal FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.9, 0.5, 0.1, 0.6)),
|
||||
# Click FG BG
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 1.0)),
|
||||
((1.0, 0.5, 0.5, 1.0), (1.0, 1.0, 1.0, 0.8)),
|
||||
# Hover FG BG
|
||||
((0.0, 0.0, 0.0, 1.0), (0.2, 0.7, 0.9, 0.6)),
|
||||
# Disable FG BG
|
||||
|
|
|
@ -184,8 +184,8 @@ CRBootedReasons = {1: 'Yikes - An unexpected problem occured. Your connection h
|
|||
100: 'You have been disconnected because someone else just logged in using your account on another computer.',
|
||||
120: 'You have been disconnected because of a problem with your authorization to use keyboard chat.',
|
||||
122: 'There was an issue getting you into Toontown. If the problem persists, please contact Toontown Rewritten Support.',
|
||||
124: 'Your installed files are out of date! Use the official launcher to download the newest version, or contact Toontown Rewritten Support of the problem persists.',
|
||||
125: 'Your installed files appear to be invalid. Use the official launcher to download the newest version, or contact Toontown Rewritten Support of the problem persists.',
|
||||
124: 'Your installed files are out of date! Use the official launcher to download the newest version, or contact Toontown Rewritten Support if the problem persists.',
|
||||
125: 'Your installed files appear to be invalid. Use the official launcher to download the newest version, or contact Toontown Rewritten Support if the problem persists.',
|
||||
126: 'You aren\'t authorized to use administrator privileges. The request has been noted.',
|
||||
127: 'There appears to be a problem with your Toon. Don\'t worry - we\'ll get it straightened out. Please contact Toontown Rewritten Support and referece Error Code 127.',
|
||||
151: 'You were kicked out by one of the developers working on the servers.',
|
||||
|
@ -193,9 +193,10 @@ CRBootedReasons = {1: 'Yikes - An unexpected problem occured. Your connection h
|
|||
153: 'The district you were playing on has been reset. Everyone who was playing on that district has also been disconnected, however, you should be able to connect again and go right back into Toontown.',
|
||||
154: 'Toontown Rewritten is going down for an update! Stay Tooned on our website for details, or try logging in again later.',
|
||||
155: 'You\'ve been warned for %(dc_reason)s. Try to behave next time!',
|
||||
156: 'Toontown Rewritten will be closing tomorrow to move into beta. From every hour from now to 2:00PM TTT tomorrow, you can enter Toontown and relive the excitement of the elections. Check our website for updates, and thank you for Alpha Testing with us!',
|
||||
200: 'Logins are currently disabled. Please try again later.',
|
||||
288: 'Sorry, you have used up all of your available minutes this month.',
|
||||
349: 'Sorry, you have used up all of your available minutes this month.'}
|
||||
349: 'Sorry, you have used up all of your available minutes this month.',
|
||||
350: 'Sorry, your play time is up for today! You\'re welcome to hop on the queue or schedule a new session at any time. Thanks for testing with us, and come back soon!',}
|
||||
CRBootedReasonUnknownCode = 'Yikes - An unexpected problem occured. (Error code %s) Your connection has been lost, but you should be able to connect again and go right back into Toontown.'
|
||||
CRSystemMessages = {
|
||||
# General, generic messages:
|
||||
|
@ -223,7 +224,7 @@ CRSystemMessages = {
|
|||
62: 'The district that you\'re on will be closed for maintenance in %s seconds.',
|
||||
|
||||
# Announcements.
|
||||
100: 'Toon Council: Congratulations, Your Toon name has been approved! You\'ll need to log out and back in to recieve your name certificate.',
|
||||
100: 'Toon Council: Congrats, Your Toon name has been approved! You\'ll need to log out to receive your name certificate.',
|
||||
101: 'Toon Council: Sorry, the name you submitted was rejected. You can log out and submit a new name on the main screen.',
|
||||
102: '%s just became the first Toon in Toon History to reach 137 Laff Points!'
|
||||
}
|
||||
|
@ -673,8 +674,8 @@ SuitFaceoffTaunts = {'b': ['Would you like to make a donation?',
|
|||
'I can bag this.',
|
||||
'Paper or plastic?',
|
||||
'Do you have your baggage claim?',
|
||||
"Remember, money won't make you happy.",
|
||||
'Careful, I have some serious baggage.',
|
||||
"I can guarantee money won't buy your happiness.",
|
||||
"I hope you're prepared -- there's no such thing as easy money.",
|
||||
"You're about to have money trouble.",
|
||||
'Money will make your world go around.',
|
||||
"I'm too rich for your blood.",
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 53c6223811c3f832e5a7307e91187a9306b63fbe
|
||||
Subproject commit 4469f9f491d02f3a60fedb8fdd0c907f4f591f6e
|
29
tools/chat_cleanup.py
Executable file
29
tools/chat_cleanup.py
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from collections import OrderedDict
|
||||
import sys, os
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print('Usage: %s chatlist_in.dat chatlist_out.dat' % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
inFile = sys.argv[1]
|
||||
outFile = sys.argv[2]
|
||||
|
||||
with open(inFile, 'r') as file:
|
||||
words = file.readlines()
|
||||
|
||||
words = [word.rstrip('\n') for word in words]
|
||||
|
||||
for index, word in enumerate(words):
|
||||
try: words[index] = int(word)
|
||||
except: pass
|
||||
|
||||
sorted_words = list(OrderedDict.fromkeys(sorted(words)))
|
||||
|
||||
with open(outFile, 'w+') as file:
|
||||
for word in sorted_words:
|
||||
file.write(str(word) + '\n')
|
||||
|
||||
print "A total of %d duplicates were removed." % (len(words)-len(sorted_words))
|
||||
print "A total of %d words were sorted." % len(sorted_words)
|
|
@ -335,7 +335,8 @@ def __doWaterGlass(squirt, delay, fShowStun):
|
|||
tContact = tSpray + dSprayScale
|
||||
tSuitDodges = max(tSpray - 0.5, 0.0)
|
||||
tracks = Parallel()
|
||||
tracks.append(ActorInterval(toon, 'spit'))
|
||||
toonTrack = Sequence(ActorInterval(toon, 'spit'), Func(toon.loop, 'neutral'))
|
||||
tracks.append(toonTrack)
|
||||
soundTrack = __getSoundTrack(level, hitSuit, 1.7, toon)
|
||||
tracks.append(soundTrack)
|
||||
glass = globalPropPool.getProp('glass')
|
||||
|
|
|
@ -84,6 +84,7 @@ class DistributedBuildingAI(DistributedObjectAI.DistributedObjectAI):
|
|||
self.requestDelete()
|
||||
|
||||
def delete(self):
|
||||
self.cleanup()
|
||||
taskMgr.remove(self.taskName('suitbldg-time-out'))
|
||||
taskMgr.remove(self.taskName(str(self.block) + '_becomingToon-timer'))
|
||||
taskMgr.remove(self.taskName(str(self.block) + '_becomingSuit-timer'))
|
||||
|
|
|
@ -48,6 +48,9 @@ class DistributedDoorAI(DistributedObjectAI.DistributedObjectAI):
|
|||
taskMgr.remove(self.uniqueName('exit_door_closing-timer'))
|
||||
taskMgr.remove(self.uniqueName('exit_door_opening-timer'))
|
||||
self.ignoreAll()
|
||||
del self.block
|
||||
del self.swing
|
||||
del self.doorType
|
||||
del self.fsm
|
||||
del self.exitDoorFSM
|
||||
del self.otherDoor
|
||||
|
|
|
@ -15,6 +15,9 @@ class DistributedKnockKnockDoorAI(DistributedAnimatedPropAI.DistributedAnimatedP
|
|||
self.doLaterTask = None
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
DistributedAnimatedPropAI.DistributedAnimatedPropAI.delete(self)
|
||||
|
||||
def enterOff(self):
|
||||
DistributedAnimatedPropAI.DistributedAnimatedPropAI.enterOff(self)
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ class DistributedToonInterior(DistributedObject.DistributedObject):
|
|||
del self.dnaStore
|
||||
del self.randomGenerator
|
||||
self.interior.flattenMedium()
|
||||
|
||||
|
||||
'''snowmanHeadInteriors = [
|
||||
2740, # TTC, Loopy Lane, Used Firecrackers
|
||||
4652, # MML, Alto Avenue, Full Stop Shop
|
||||
|
@ -162,6 +162,15 @@ class DistributedToonInterior(DistributedObject.DistributedObject):
|
|||
self.sendUpdate('nextSnowmanHeadPart', [])
|
||||
self.accept(SpeedChatGlobals.SCStaticTextMsgEvent, phraseSaid)'''
|
||||
|
||||
if config.GetBool('want-toonhall-cats', False):
|
||||
if self.zoneId == 2513:
|
||||
# Pfft... all this is needed for is the ActivateEvent...
|
||||
from toontown.ai.DistributedBlackCatMgr import DistributedBlackCatMgr
|
||||
def phraseSaid(phraseId):
|
||||
if phraseId == 5700: # Toontastic!
|
||||
messenger.send(DistributedBlackCatMgr.ActivateEvent)
|
||||
self.accept(SpeedChatGlobals.SCStaticTextMsgEvent, phraseSaid)
|
||||
|
||||
def setZoneIdAndBlock(self, zoneId, block):
|
||||
self.zoneId = zoneId
|
||||
self.block = block
|
||||
|
|
|
@ -19,6 +19,12 @@ class DistributedToonInteriorAI(DistributedObjectAI.DistributedObjectAI):
|
|||
self.fsm = ClassicFSM.ClassicFSM('DistributedToonInteriorAI', [State.State('toon', self.enterToon, self.exitToon, ['beingTakenOver']), State.State('beingTakenOver', self.enterBeingTakenOver, self.exitBeingTakenOver, []), State.State('off', self.enterOff, self.exitOff, [])], 'toon', 'off')
|
||||
self.fsm.enterInitialState()
|
||||
|
||||
if config.GetBool('want-toonhall-cats', False):
|
||||
if self.zoneId == 2513:
|
||||
from toontown.ai.DistributedBlackCatMgrAI import DistributedBlackCatMgrAI
|
||||
self.blackCatMgr = DistributedBlackCatMgrAI(air)
|
||||
self.blackCatMgr.generateWithRequired(self.zoneId)
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
for npc in self.npcs:
|
||||
|
@ -28,6 +34,7 @@ class DistributedToonInteriorAI(DistributedObjectAI.DistributedObjectAI):
|
|||
del self.npcs
|
||||
del self.fsm
|
||||
del self.building
|
||||
del self.block
|
||||
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||
|
||||
def getZoneIdAndBlock(self):
|
||||
|
|
|
@ -38,17 +38,17 @@ class ToontownChatManager(ChatManager.ChatManager):
|
|||
self.openScSfx.setVolume(0.6)
|
||||
self.scButton = DirectButton(image=(gui.find('**/ChtBx_ChtBtn_UP'), gui.find('**/ChtBx_ChtBtn_DN'), gui.find('**/ChtBx_ChtBtn_RLVR')), pos=TTLocalizer.TCMscButtonPos, parent=base.a2dTopLeft, scale=1.179, relief=None, image_color=Vec4(0.75, 1, 0.6, 1), text=('', OTPLocalizer.GlobalSpeedChatName, OTPLocalizer.GlobalSpeedChatName), text_scale=TTLocalizer.TCMscButton, text_fg=Vec4(1, 1, 1, 1), text_shadow=Vec4(0, 0, 0, 1), text_pos=(0, -0.09), textMayChange=0, sortOrder=DGG.FOREGROUND_SORT_INDEX, command=self.__scButtonPressed, clickSound=self.openScSfx)
|
||||
self.scButton.hide()
|
||||
self.whisperFrame = DirectFrame(parent=base.a2dTopLeft, relief=None, image=DGG.getDefaultDialogGeom(), image_scale=(0.70, 0.70, 0.20), image_color=OTPGlobals.GlobalDialogColor, pos=(0.37, 0, -0.105), text=OTPLocalizer.ChatManagerWhisperTo, text_wordwrap=7.0, text_scale=TTLocalizer.TCMwhisperFrame, text_fg=Vec4(0, 0, 0, 1), text_pos=(0.17, 0.01), textMayChange=1, sortOrder=DGG.FOREGROUND_SORT_INDEX)
|
||||
self.whisperFrame = DirectFrame(parent=base.a2dTopLeft, relief=None, image=DGG.getDefaultDialogGeom(), image_scale=(0.77, 0.70, 0.20), image_color=OTPGlobals.GlobalDialogColor, pos=(0.40, 0, -0.105), text=OTPLocalizer.ChatManagerWhisperTo, text_wordwrap=6.5, text_scale=TTLocalizer.TCMwhisperFrame, text_fg=Vec4(0, 0, 0, 1), text_pos=(0.18, 0.01), textMayChange=1, sortOrder=DGG.FOREGROUND_SORT_INDEX)
|
||||
self.whisperFrame.hide()
|
||||
self.whisperButton = DirectButton(parent=self.whisperFrame, image=(gui.find('**/ChtBx_ChtBtn_UP'), gui.find('**/ChtBx_ChtBtn_DN'), gui.find('**/ChtBx_ChtBtn_RLVR')), pos=(-0.29, 0, 0.033), scale=1.179, relief=None, image_color=Vec4(1, 1, 1, 1), text=('',
|
||||
self.whisperButton = DirectButton(parent=self.whisperFrame, image=(gui.find('**/ChtBx_ChtBtn_UP'), gui.find('**/ChtBx_ChtBtn_DN'), gui.find('**/ChtBx_ChtBtn_RLVR')), pos=(-0.33, 0, 0.033), scale=1.179, relief=None, image_color=Vec4(1, 1, 1, 1), text=('',
|
||||
OTPLocalizer.ChatManagerChat,
|
||||
OTPLocalizer.ChatManagerChat,
|
||||
''), image3_color=Vec4(0.6, 0.6, 0.6, 0.6), text_scale=TTLocalizer.TCMwhisperButton, text_fg=(0, 0, 0, 1), text_pos=(0, -0.09), textMayChange=0, command=self.__whisperButtonPressed)
|
||||
self.whisperScButton = DirectButton(parent=self.whisperFrame, image=(gui.find('**/ChtBx_ChtBtn_UP'), gui.find('**/ChtBx_ChtBtn_DN'), gui.find('**/ChtBx_ChtBtn_RLVR')), pos=(-0.165, 0, 0.033), scale=1.179, relief=None, image_color=Vec4(0.75, 1, 0.6, 1), text=('',
|
||||
self.whisperScButton = DirectButton(parent=self.whisperFrame, image=(gui.find('**/ChtBx_ChtBtn_UP'), gui.find('**/ChtBx_ChtBtn_DN'), gui.find('**/ChtBx_ChtBtn_RLVR')), pos=(-0.195, 0, 0.033), scale=1.179, relief=None, image_color=Vec4(0.75, 1, 0.6, 1), text=('',
|
||||
OTPLocalizer.GlobalSpeedChatName,
|
||||
OTPLocalizer.GlobalSpeedChatName,
|
||||
''), image3_color=Vec4(0.6, 0.6, 0.6, 0.6), text_scale=TTLocalizer.TCMwhisperScButton, text_fg=(0, 0, 0, 1), text_pos=(0, -0.09), textMayChange=0, command=self.__whisperScButtonPressed)
|
||||
self.whisperCancelButton = DirectButton(parent=self.whisperFrame, image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr')), pos=(-0.05, 0, 0.033), scale=1.179, relief=None, text=('', OTPLocalizer.ChatManagerCancel, OTPLocalizer.ChatManagerCancel), text_scale=0.05, text_fg=(0, 0, 0, 1), text_pos=(0, -0.09), textMayChange=0, command=self.__whisperCancelPressed)
|
||||
self.whisperCancelButton = DirectButton(parent=self.whisperFrame, image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr')), pos=(-0.06, 0, 0.033), scale=1.179, relief=None, text=('', OTPLocalizer.ChatManagerCancel, OTPLocalizer.ChatManagerCancel), text_scale=0.05, text_fg=(0, 0, 0, 1), text_pos=(0, -0.09), textMayChange=0, command=self.__whisperCancelPressed)
|
||||
gui.removeNode()
|
||||
ChatManager.ChatManager.__init__(self, cr, localAvatar)
|
||||
self.defaultToWhiteList = base.config.GetBool('white-list-is-default', 1)
|
||||
|
|
|
@ -37,6 +37,7 @@ class ToontownInternalRepository(AstronInternalRepository):
|
|||
self.netMessenger.register(1, 'accountDisconnected')
|
||||
self.netMessenger.register(2, 'avatarOnline')
|
||||
self.netMessenger.register(3, 'avatarOffline')
|
||||
self.netMessenger.register(4, 'enableLogins')
|
||||
|
||||
def getAvatarIdFromSender(self):
|
||||
return self.getMsgSender() & 0xFFFFFFFF
|
||||
|
|
|
@ -45,6 +45,11 @@ class DistributedFurnitureManagerAI(DistributedObjectAI):
|
|||
for item in self.items:
|
||||
item.generateWithRequired(self.zoneId)
|
||||
|
||||
def delete(self):
|
||||
for item in self.items:
|
||||
item.destroy()
|
||||
DistributedObjectAI.delete(self)
|
||||
|
||||
def loadFromHouse(self):
|
||||
self.b_setAtticItems(self.house.getAtticItems())
|
||||
self.b_setAtticWallpaper(self.house.getAtticWallpaper())
|
||||
|
|
|
@ -140,9 +140,9 @@ class DistributedPondBingoManagerAI(DistributedObjectAI):
|
|||
self.state = 'Reward'
|
||||
self.sendStateUpdate()
|
||||
for spot in self.pond.spots:
|
||||
if self.pond.spots[spot].avId == None or self.pond.spots[spot].avId == 0:
|
||||
av = self.pond.spots[spot].get(avId)
|
||||
if not av:
|
||||
continue
|
||||
av = self.air.doId2do[self.pond.spots[spot].avId]
|
||||
av.addMoney(self.jackpot)
|
||||
if self.shouldStop:
|
||||
self.stopGame()
|
||||
|
@ -230,4 +230,4 @@ def startBingo():
|
|||
@magicWord(category=CATEGORY_OVERRIDE, types=[str, int])
|
||||
def requestBingoCard(cardName, seed = None):
|
||||
RequestCard[spellbook.getTarget().doId] = ToontownGlobals.BingoCardNames[cardName], seed
|
||||
return "Sent request for the bingo card " + cardName
|
||||
return "Sent request for the bingo card " + cardName
|
||||
|
|
|
@ -24,7 +24,11 @@ class GetToonDataFSM(FSM):
|
|||
self.demand('QueryDB')
|
||||
|
||||
def enterQueryDB(self):
|
||||
self.mgr.air.dbInterface.queryObject(self.mgr.air.dbId, self.avId, self.__queryResponse)
|
||||
# TODO: Propper fix. This is just temporary
|
||||
try:
|
||||
self.mgr.air.dbInterface.queryObject(self.mgr.air.dbId, self.avId, self.__queryResponse)
|
||||
except:
|
||||
pass
|
||||
|
||||
def __queryResponse(self, dclass, fields):
|
||||
if dclass != self.mgr.air.dclassesByName['DistributedToonUD']:
|
||||
|
@ -230,7 +234,7 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
for friendId in friends:
|
||||
# Is our friend online?
|
||||
self.air.getActivated(friendId, functools.partial(self.__comingOnlineFriendOnline, otherId=avId))
|
||||
|
||||
|
||||
def __comingOnlineFriendOnline(self, avId, activated, otherId=None):
|
||||
if not (otherId and activated):
|
||||
#??!?!?
|
||||
|
@ -241,14 +245,14 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
dg.addUint32(otherId)
|
||||
dg.addUint16(self.air.dclassesByName['DistributedToonUD'].getNumber())
|
||||
self.air.send(dg)
|
||||
|
||||
|
||||
# Declare the friend to the avatar.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.GetPuppetConnectionChannel(otherId), self.air.ourChannel, CLIENTAGENT_DECLARE_OBJECT)
|
||||
dg.addUint32(avId)
|
||||
dg.addUint16(self.air.dclassesByName['DistributedToonUD'].getNumber())
|
||||
self.air.send(dg)
|
||||
|
||||
|
||||
# Tell the client their friend is online.
|
||||
self.sendUpdateToAvatarId(avId, 'friendOnline', [otherId, 0, 0])
|
||||
|
||||
|
@ -266,7 +270,7 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
return
|
||||
for friendId, tf in fields['setFriendsList'][0]:
|
||||
self.air.getActivated(friendId, functools.partial(self.__offlineToonOnline, otherId=requesterId, accId=fields['setDISLid'][0]))
|
||||
|
||||
|
||||
def __offlineToonOnline(self, avId, activated, otherId=None, accId=None):
|
||||
if not (otherId and activated and accId):
|
||||
return
|
||||
|
@ -275,13 +279,13 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
dg.addServerHeader(self.GetPuppetConnectionChannel(avId), self.air.ourChannel, CLIENTAGENT_UNDECLARE_OBJECT)
|
||||
dg.addUint32(otherId)
|
||||
self.air.send(dg)
|
||||
|
||||
|
||||
# Undeclare to our now-offline avId (they may still be around, about to log into a new toon!)
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.GetAccountConnectionChannel(accId), self.air.ourChannel, CLIENTAGENT_UNDECLARE_OBJECT)
|
||||
dg.addUint32(avId)
|
||||
self.air.send(dg)
|
||||
|
||||
|
||||
# Tell them they're offline!
|
||||
self.sendUpdateToAvatarId(avId, 'friendOffline', [otherId])
|
||||
|
||||
|
@ -300,11 +304,11 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
# Wtf, we got the wrong toon's data!
|
||||
return
|
||||
friendIds = fields['setFriendsList'][0][:]
|
||||
friendIds.append(requesterId)
|
||||
if friendIds[0] == requesterId:
|
||||
friendIds.append((requesterId, 1))
|
||||
if friendIds[0][0] == requesterId:
|
||||
# This toon has no friends, no point doing database operations.
|
||||
return
|
||||
fsm = GetToonDataFSM(self, requesterId, friendIds[0], functools.partial(self.__clearListGotFriendData, friendIds=friendIds[1:]))
|
||||
fsm = GetToonDataFSM(self, requesterId, friendIds[0][0], functools.partial(self.__clearListGotFriendData, friendIds=friendIds[1:]))
|
||||
fsm.start()
|
||||
self.fsms[requesterId] = fsm
|
||||
|
||||
|
@ -316,7 +320,7 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
if not success:
|
||||
if friendIds:
|
||||
# Move on to the next friend.
|
||||
fsm = GetToonDataFSM(self, requesterId, friendIds[0], functools.partial(self.__clearListGotFriendData, friendIds=friendIds[1:]))
|
||||
fsm = GetToonDataFSM(self, requesterId, friendIds[0][0], functools.partial(self.__clearListGotFriendData, friendIds=friendIds[1:]))
|
||||
fsm.start()
|
||||
self.fsms[requesterId] = fsm
|
||||
else:
|
||||
|
@ -327,12 +331,11 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
if requesterId == fields['ID']:
|
||||
# Delete our friends list entirely.
|
||||
friendsIds = []
|
||||
elif requesterId in friendsIds:
|
||||
# Remove ourself from our friend's list.
|
||||
friendsIds.remove(requesterId)
|
||||
else:
|
||||
# Wtf, we aren't friends with this toon?
|
||||
self.notify.warning('Tried to unfriend %s from %s\'s friendsList while not in friendsList!' % (requesterId, fields['ID']))
|
||||
for friend in friendsIds:
|
||||
if friend[0] == requesterId:
|
||||
# Remove ourself from our friend's list.
|
||||
friendsIds.remove(friend)
|
||||
fsm = UpdateToonFieldFSM(self, requesterId, fields['ID'], functools.partial(self.__clearListUpdatedToonField, avId=fields['ID'], friendIds=friendIds[1:]))
|
||||
fsm.start('setFriendsList', friendsIds)
|
||||
self.fsms[requesterId] = fsm
|
||||
|
@ -350,7 +353,7 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
if not friendIds:
|
||||
# We can now stop, since we have no friends left to clear.
|
||||
return
|
||||
fsm = GetToonData(self, requesterId, friendIds[0], functools.partial(self.__clearListGotFriendData, friendIds=friendIds[1:]))
|
||||
fsm = GetToonDataFSM(self, requesterId, friendIds[0], functools.partial(self.__clearListGotFriendData, friendIds=friendIds[1:]))
|
||||
fsm.start()
|
||||
self.fsms[requesterId] = fsm
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,215 +1,498 @@
|
|||
from direct.distributed import DistributedObjectAI
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.golf.DistributedPhysicsWorldAI import DistributedPhysicsWorldAI
|
||||
from toontown.toonbase import ToontownGlobals
|
||||
from pandac.PandaModules import *
|
||||
import DistributedPhysicsWorldAI
|
||||
from direct.fsm.FSM import FSM
|
||||
from toontown.ai.ToonBarrier import *
|
||||
from toontown.golf import GolfGlobals
|
||||
import random
|
||||
from toontown.golf import GolfHoleBase
|
||||
|
||||
class DistributedGolfHoleAI(DistributedPhysicsWorldAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGolfHoleAI")
|
||||
|
||||
def __init__(self, air):
|
||||
DistributedPhysicsWorldAI.__init__(self, air)
|
||||
self.air = air
|
||||
self.holeId = 1
|
||||
self.tcLength = 1.0
|
||||
self.gcDoId = 0
|
||||
self.avatars = []
|
||||
self.readyAvatars = []
|
||||
self.finishedAvatars = []
|
||||
self.avatarSwings = {}
|
||||
self.curGolfer = 0
|
||||
self.assignedAvatar = 0
|
||||
|
||||
def generate(self):
|
||||
DistributedPhysicsWorldAI.generate(self)
|
||||
for av in self.avatars:
|
||||
self.avatarSwings[av] = 0
|
||||
class DistributedGolfHoleAI(DistributedPhysicsWorldAI.DistributedPhysicsWorldAI, FSM, GolfHoleBase.GolfHoleBase):
|
||||
defaultTransitions = {'Off': ['Cleanup', 'WaitTee'],
|
||||
'WaitTee': ['WaitSwing',
|
||||
'Cleanup',
|
||||
'WaitTee',
|
||||
'WaitPlayback'],
|
||||
'WaitSwing': ['WaitPlayback',
|
||||
'Cleanup',
|
||||
'WaitSwing',
|
||||
'WaitTee'],
|
||||
'WaitPlayback': ['WaitSwing',
|
||||
'Cleanup',
|
||||
'WaitTee',
|
||||
'WaitPlayback'],
|
||||
'Cleanup': ['Off']}
|
||||
id = 0
|
||||
notify = directNotify.newCategory('DistributedGolfHoleAI')
|
||||
|
||||
def setHoleId(self, holeId):
|
||||
def __init__(self, zoneId, golfCourse, holeId):
|
||||
FSM.__init__(self, 'Golf_%s_FSM' % self.id)
|
||||
DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.__init__(self, simbase.air)
|
||||
GolfHoleBase.GolfHoleBase.__init__(self)
|
||||
self.zoneId = zoneId
|
||||
self.golfCourse = golfCourse
|
||||
self.holeId = holeId
|
||||
|
||||
def d_setHoleId(self, holeId):
|
||||
self.sendUpdate('setHoleId', [holeId])
|
||||
|
||||
def b_setHoleId(self, holeId):
|
||||
self.setHoleId(holeId)
|
||||
self.d_setHoleId(holeId)
|
||||
|
||||
self.avIdList = golfCourse.avIdList[:]
|
||||
self.watched = [0,
|
||||
0,
|
||||
0,
|
||||
0]
|
||||
self.barrierPlayback = None
|
||||
self.trustedPlayerId = None
|
||||
self.activeGolferIndex = None
|
||||
self.activeGolferId = None
|
||||
self.holeInfo = GolfGlobals.HoleInfo[self.holeId]
|
||||
self.teeChosen = {}
|
||||
for avId in self.avIdList:
|
||||
self.teeChosen[avId] = -1
|
||||
|
||||
self.ballPos = {}
|
||||
for avId in self.avIdList:
|
||||
self.ballPos[avId] = Vec3(0, 0, 0)
|
||||
|
||||
self.playStarted = False
|
||||
return
|
||||
|
||||
def curGolfBall(self):
|
||||
return self.ball
|
||||
|
||||
def generate(self):
|
||||
DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.generate(self)
|
||||
self.ball = self.createBall()
|
||||
self.createRays()
|
||||
if len(self.teePositions) > 1:
|
||||
startPos = self.teePositions[1]
|
||||
else:
|
||||
startPos = self.teePositions[0]
|
||||
startPos += Vec3(0, 0, GolfGlobals.GOLF_BALL_RADIUS)
|
||||
self.ball.setPosition(startPos)
|
||||
|
||||
def delete(self):
|
||||
self.notify.debug('__delete__')
|
||||
DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.delete(self)
|
||||
self.notify.debug('calling self.terrainModel.removeNode')
|
||||
self.terrainModel.removeNode()
|
||||
self.notify.debug('self.barrierPlayback is %s' % self.barrierPlayback)
|
||||
if self.barrierPlayback:
|
||||
self.notify.debug('calling self.barrierPlayback.cleanup')
|
||||
self.barrierPlayback.cleanup()
|
||||
self.notify.debug('calling self.barrierPlayback = None')
|
||||
self.barrierPlayback = None
|
||||
self.activeGolferId = None
|
||||
return
|
||||
|
||||
def setZoneId(self, zoneId):
|
||||
self.zoneId = zoneId
|
||||
|
||||
def setAvatarReadyHole(self):
|
||||
self.notify.debugStateCall(self)
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.golfCourse.avatarReadyHole(avId)
|
||||
|
||||
def startPlay(self):
|
||||
self.notify.debug('startPlay')
|
||||
self.playStarted = True
|
||||
self.numGolfers = len(self.golfCourse.getGolferIds())
|
||||
self.selectNextGolfer()
|
||||
|
||||
def selectNextGolfer(self):
|
||||
self.notify.debug('selectNextGolfer, old golferIndex=%s old golferId=%s' % (self.activeGolferIndex, self.activeGolferId))
|
||||
if self.golfCourse.isCurHoleDone():
|
||||
return
|
||||
if self.activeGolferIndex == None:
|
||||
self.activeGolferIndex = 0
|
||||
self.activeGolferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
|
||||
else:
|
||||
self.activeGolferIndex += 1
|
||||
if self.activeGolferIndex >= len(self.golfCourse.getGolferIds()):
|
||||
self.activeGolferIndex = 0
|
||||
self.activeGolferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
|
||||
safety = 0
|
||||
while safety < 50 and not self.golfCourse.checkGolferPlaying(self.golfCourse.getGolferIds()[self.activeGolferIndex]):
|
||||
self.activeGolferIndex += 1
|
||||
self.notify.debug('Index %s' % self.activeGolferIndex)
|
||||
if self.activeGolferIndex >= len(self.golfCourse.getGolferIds()):
|
||||
self.activeGolferIndex = 0
|
||||
self.activeGolferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
|
||||
safety += 1
|
||||
|
||||
if safety != 50:
|
||||
golferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
|
||||
if self.teeChosen[golferId] == -1:
|
||||
self.sendUpdate('golferChooseTee', [golferId])
|
||||
self.request('WaitTee')
|
||||
else:
|
||||
self.sendUpdate('golfersTurn', [golferId])
|
||||
self.request('WaitSwing')
|
||||
else:
|
||||
self.notify.debug('safety')
|
||||
self.notify.debug('selectNextGolfer, new golferIndex=%s new golferId=%s' % (self.activeGolferIndex, self.activeGolferId))
|
||||
return
|
||||
|
||||
def clearWatched(self):
|
||||
self.watched = [1,
|
||||
1,
|
||||
1,
|
||||
1]
|
||||
for index in range(len(self.golfCourse.getGolferIds())):
|
||||
self.watched[index] = 0
|
||||
|
||||
def setWatched(self, avId):
|
||||
for index in range(len(self.golfCourse.getGolferIds())):
|
||||
if self.golfCourse.getGolferIds()[index] == avId:
|
||||
self.watched[index] = 1
|
||||
|
||||
def checkWatched(self):
|
||||
if 0 not in self.watched:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def turnDone(self):
|
||||
self.notify.debug('Turn Done')
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if self.barrierPlayback:
|
||||
self.barrierPlayback.clear(avId)
|
||||
|
||||
def ballInHole(self, golferId = None):
|
||||
self.notify.debug('ballInHole')
|
||||
if golferId:
|
||||
avId = golferId
|
||||
else:
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.golfCourse.setBallIn(avId)
|
||||
if self.golfCourse.isCurHoleDone():
|
||||
self.notify.debug('ballInHole doing nothing')
|
||||
else:
|
||||
self.notify.debug('ballInHole calling self.selectNextGolfer')
|
||||
self.selectNextGolfer()
|
||||
|
||||
def getHoleId(self):
|
||||
return self.holeId
|
||||
|
||||
#this is required, but the client doesn't HAVE this. WTF
|
||||
def setTimingCycleLength(self, tcLength):
|
||||
self.tcLength = tcLength
|
||||
|
||||
def d_setTimingCycleLength(self, tcLength):
|
||||
self.sendUpdate('setTimingCycleLength', [tcLength])
|
||||
|
||||
def b_setTimingCycleLength(self, tcLength):
|
||||
self.setTimingCycleLength(tcLength)
|
||||
self.d_setTimingCycleLength(tcLength)
|
||||
|
||||
def getTimingCycleLength(self):
|
||||
return self.tcLength
|
||||
|
||||
def setAvatarReadyHole(self):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if not avId in self.avatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to join a hole for a game of golf they\'re not in!')
|
||||
return
|
||||
if avId in self.readyAvatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to join a golf hole twice!')
|
||||
return
|
||||
self.readyAvatars.append(avId)
|
||||
if set(self.readyAvatars) == set(self.avatars):
|
||||
self.__newGolfer(self.avatars[0])
|
||||
def finishHole(self):
|
||||
self.notify.debug('finishHole')
|
||||
self.golfCourse.holeOver()
|
||||
|
||||
def setGolfCourseDoId(self, gcDoId):
|
||||
self.gcDoId = gcDoId
|
||||
|
||||
def d_setGolfCourseDoId(self, gcDoId):
|
||||
self.sendUpdate('setGolfCourseDoId', [gcDoId])
|
||||
|
||||
def b_setGolfCourseDoId(self, gcDoId):
|
||||
self.setGolfCourseDoId(gcDoId)
|
||||
self.d_setGolfCourseDoId(gcDoId)
|
||||
|
||||
def getGolfCourseDoId(self):
|
||||
return self.gcDoId
|
||||
|
||||
def turnDone(self):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if not avId in self.avatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to end their turn in a golf game they\'re not playing in!')
|
||||
return
|
||||
if avId != self.curGolfer:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to end someone else\'s turn in a game of golf!')
|
||||
return
|
||||
avIndex = self.avatars.index(avId)
|
||||
if set(self.avatars) == set(self.finishedAvatars):
|
||||
self.air.doId2do[self.gcDoId].createNextHole()
|
||||
return
|
||||
if len(self.avatars) == 1:
|
||||
self.__newGolfer(avId)
|
||||
return
|
||||
#while avIndex != len(self.avatars) - 1:
|
||||
avIndex += 1
|
||||
if avIndex > len(self.avatars)-1:
|
||||
avIndex = 0
|
||||
while self.avatars[avIndex] in self.finishedAvatars:
|
||||
avIndex += 1
|
||||
if avIndex > len(self.avatars)-1:
|
||||
avIndex = 0
|
||||
self.__newGolfer(self.avatars[avIndex])
|
||||
#for i in range(len(self.avatars)):
|
||||
#if self.avatars[i] not in self.finishedAvatars:
|
||||
#self.__newGolfer(self.avatars[i])
|
||||
#return
|
||||
|
||||
def __newGolfer(self, avId):
|
||||
self.curGolfer = avId
|
||||
if self.avatarSwings[avId] == 0:
|
||||
self.sendUpdate('golferChooseTee', [avId])
|
||||
else:
|
||||
self.sendUpdate('golfersTurn', [avId])
|
||||
self.avatarSwings[avId] += 1
|
||||
|
||||
def ballInHole(self):
|
||||
#GOD DAMN IT
|
||||
#THIS FUNCTION IS NEVER CALLED BY THE DISNEY CLIENT
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if not avId in self.avatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to get a hole in a golf game they\'re not playing in!')
|
||||
return
|
||||
if avId in self.finishedAvatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to get a hole twice!')
|
||||
return
|
||||
if avId != self.curGolfer:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to get a hole while someone else is golfing!')
|
||||
return
|
||||
self.finishedAvatars.append(avId)
|
||||
|
||||
def setAvatarTempTee(self, todo0, todo1):
|
||||
pass
|
||||
|
||||
def setTempAimHeading(self, todo0, todo1):
|
||||
pass
|
||||
|
||||
def setAvatarFinalTee(self, avId, tee):
|
||||
pass
|
||||
|
||||
def setGolferIds(self, avatars):
|
||||
self.avatars = avatars
|
||||
|
||||
def d_setGolferIds(self, avatars):
|
||||
self.sendUpdate('setGolferIds', [avatars])
|
||||
|
||||
def b_setGolferIds(self, avatars):
|
||||
self.setGolferIds(avatars)
|
||||
self.d_setGolferIds(avatars)
|
||||
|
||||
def getGolferIds(self):
|
||||
return self.avatars
|
||||
return self.avIdList
|
||||
|
||||
def golfersTurn(self, todo0):
|
||||
pass
|
||||
|
||||
def golferChooseTee(self, todo0):
|
||||
pass
|
||||
|
||||
def setAvatarTee(self, tee):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if not avId in self.avatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to set their tee in a game they\'re not in!')
|
||||
return
|
||||
if avId != self.curGolfer:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to set their tee while not being the current golfer!')
|
||||
return
|
||||
self.sendUpdate('setAvatarFinalTee', [avId, tee])
|
||||
self.sendUpdate('golfersTurn', [avId])
|
||||
|
||||
def postSwing(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6):
|
||||
pass
|
||||
|
||||
def postSwingState(self, cycleTime, power, bX, bY, bZ, x, y, aimTime, cod):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if not avId in self.avatars:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to swing in a golf game they\'re not playing in!')
|
||||
return
|
||||
if avId != self.curGolfer:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to golf outside of their turn!')
|
||||
return
|
||||
if len(self.avatars) == 1:
|
||||
self.assignedAvatar = self.avatars[0]
|
||||
def loadLevel(self):
|
||||
GolfHoleBase.GolfHoleBase.loadLevel(self)
|
||||
optionalObjects = self.terrainModel.findAllMatches('**/optional*')
|
||||
requiredObjects = self.terrainModel.findAllMatches('**/required*')
|
||||
self.parseLocators(optionalObjects, 1)
|
||||
self.parseLocators(requiredObjects, 0)
|
||||
self.teeNodePath = self.terrainModel.find('**/tee0')
|
||||
if self.teeNodePath.isEmpty():
|
||||
teePos = Vec3(0, 0, 10)
|
||||
else:
|
||||
while self.assignedAvatar == self.curGolfer or self.assignedAvatar == 0:
|
||||
self.assignedAvatar = random.choice(self.avatars)
|
||||
course = self.air.doId2do[self.gcDoId]
|
||||
scoreList = course.scores
|
||||
scoreList[self.avatars.index(avId) * len(self.avatars) + course.chIndex] = self.avatarSwings[avId]
|
||||
course.b_setScores(scoreList)
|
||||
self.sendUpdateToAvatarId(self.assignedAvatar, 'assignRecordSwing', [avId, cycleTime, power, bX, bY, bZ, x, y, cod])
|
||||
teePos = self.teeNodePath.getPos()
|
||||
teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
|
||||
self.notify.debug('teeNodePath heading = %s' % self.teeNodePath.getH())
|
||||
self.teePositions = [teePos]
|
||||
teeIndex = 1
|
||||
teeNode = self.terrainModel.find('**/tee%d' % teeIndex)
|
||||
while not teeNode.isEmpty():
|
||||
teePos = teeNode.getPos()
|
||||
teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
|
||||
self.teePositions.append(teePos)
|
||||
self.notify.debug('teeNodeP heading = %s' % teeNode.getH())
|
||||
teeIndex += 1
|
||||
teeNode = self.terrainModel.find('**/tee%d' % teeIndex)
|
||||
|
||||
def swing(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6):
|
||||
pass
|
||||
def createLocatorDict(self):
|
||||
self.locDict = {}
|
||||
locatorNum = 1
|
||||
curNodePath = self.hardSurfaceNodePath.find('**/locator%d' % locatorNum)
|
||||
while not curNodePath.isEmpty():
|
||||
self.locDict[locatorNum] = curNodePath
|
||||
locatorNum += 1
|
||||
curNodePath = self.hardSurfaceNodePath.find('**/locator%d' % locatorNum)
|
||||
|
||||
def ballMovie2AI(self, cycleTime, avId, recording, aVRecording, ballInHoleFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame, COD):
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if sender != self.assignedAvatar:
|
||||
self.air.writeServerEvent('suspicious', avId=sender, issue='Toon tried to send ball movie with no assigned sender!')
|
||||
def loadBlockers(self):
|
||||
loadAll = simbase.config.GetBool('golf-all-blockers', 0)
|
||||
self.createLocatorDict()
|
||||
self.blockerNums = self.holeInfo['blockers']
|
||||
for locatorNum in self.locDict:
|
||||
if locatorNum in self.blockerNums or loadAll:
|
||||
locator = self.locDict[locatorNum]
|
||||
locatorParent = locator.getParent()
|
||||
locator.getChildren().wrtReparentTo(locatorParent)
|
||||
else:
|
||||
self.locDict[locatorNum].removeNode()
|
||||
|
||||
self.hardSurfaceNodePath.flattenStrong()
|
||||
|
||||
def createBall(self):
|
||||
golfBallGeom = self.createSphere(self.world, self.space, GolfGlobals.GOLF_BALL_DENSITY, GolfGlobals.GOLF_BALL_RADIUS, 1)[1]
|
||||
return golfBallGeom
|
||||
|
||||
def preStep(self):
|
||||
GolfHoleBase.GolfHoleBase.preStep(self)
|
||||
|
||||
def postStep(self):
|
||||
GolfHoleBase.GolfHoleBase.postStep(self)
|
||||
|
||||
def postSwing(self, cycleTime, power, x, y, z, dirX, dirY):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.storeAction = [avId,
|
||||
cycleTime,
|
||||
power,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
dirX,
|
||||
dirY]
|
||||
if self.commonHoldData:
|
||||
self.doAction()
|
||||
|
||||
def postSwingState(self, cycleTime, power, x, y, z, dirX, dirY, curAimTime, commonObjectData):
|
||||
self.notify.debug('postSwingState')
|
||||
if not self.golfCourse.getStillPlayingAvIds():
|
||||
return
|
||||
if ballInHoleFrame != 0:
|
||||
self.finishedAvatars.append(avId)
|
||||
self.assignedAvatar = 0
|
||||
self.sendUpdate('ballMovie2Client', [cycleTime, avId, recording, aVRecording, ballInHoleFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame, COD])
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.storeAction = [avId,
|
||||
cycleTime,
|
||||
power,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
dirX,
|
||||
dirY]
|
||||
self.commonHoldData = commonObjectData
|
||||
self.trustedPlayerId = self.choosePlayerToSimulate()
|
||||
self.sendUpdateToAvatarId(self.trustedPlayerId, 'assignRecordSwing', [avId,
|
||||
cycleTime,
|
||||
power,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
dirX,
|
||||
dirY,
|
||||
commonObjectData])
|
||||
self.golfCourse.addAimTime(avId, curAimTime)
|
||||
|
||||
def ballMovie2Client(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6, todo7):
|
||||
def choosePlayerToSimulate(self):
|
||||
stillPlaying = self.golfCourse.getStillPlayingAvIds()
|
||||
playerId = 0
|
||||
if simbase.air.config.GetBool('golf-trust-driver-first', 0):
|
||||
if stillPlaying:
|
||||
playerId = stillPlaying[0]
|
||||
else:
|
||||
playerId = random.choice(stillPlaying)
|
||||
return playerId
|
||||
|
||||
def ballMovie2AI(self, cycleTime, avId, movie, spinMovie, ballInFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame, commonObjectData):
|
||||
sentFromId = self.air.getAvatarIdFromSender()
|
||||
if sentFromId == self.trustedPlayerId:
|
||||
lastFrameNum = len(movie) - 2
|
||||
if lastFrameNum < 0:
|
||||
lastFrameNum = 0
|
||||
lastFrame = movie[lastFrameNum]
|
||||
lastPos = Vec3(lastFrame[1], lastFrame[2], lastFrame[3])
|
||||
self.ballPos[avId] = lastPos
|
||||
self.golfCourse.incrementScore(avId)
|
||||
for id in self.golfCourse.getStillPlayingAvIds():
|
||||
if not id == sentFromId:
|
||||
self.sendUpdateToAvatarId(id, 'ballMovie2Client', [cycleTime,
|
||||
avId,
|
||||
movie,
|
||||
spinMovie,
|
||||
ballInFrame,
|
||||
ballTouchedHoleFrame,
|
||||
ballFirstTouchedHoleFrame,
|
||||
commonObjectData])
|
||||
|
||||
if self.state == 'WaitPlayback' or self.state == 'WaitTee':
|
||||
self.notify.warning('ballMovie2AI requesting from %s to WaitPlayback' % self.state)
|
||||
self.request('WaitPlayback')
|
||||
elif self.trustedPlayerId == None:
|
||||
return
|
||||
else:
|
||||
self.doAction()
|
||||
self.trustedPlayerId = None
|
||||
return
|
||||
|
||||
def performReadyAction(self):
|
||||
avId = self.storeAction[0]
|
||||
if self.state == 'WaitPlayback':
|
||||
self.notify.debugStateCall(self)
|
||||
self.notify.debug('ignoring the postSwing for avId=%d since we are in WaitPlayback' % avId)
|
||||
return
|
||||
if avId == self.activeGolferId:
|
||||
self.golfCourse.incrementScore(self.activeGolferId)
|
||||
else:
|
||||
self.notify.warning('activGolferId %d not equal to sender avId %d' % (self.activeGolferId, avId))
|
||||
if avId not in self.golfCourse.drivingToons:
|
||||
position = self.ballPos[avId]
|
||||
else:
|
||||
position = Vec3(self.storeAction[3], self.storeAction[4], self.storeAction[5])
|
||||
self.useCommonObjectData(self.commonHoldData)
|
||||
newPos = self.trackRecordBodyFlight(self.ball, self.storeAction[1], self.storeAction[2], position, self.storeAction[6], self.storeAction[7])
|
||||
if self.state == 'WaitPlayback' or self.state == 'WaitTee':
|
||||
self.notify.warning('performReadyAction requesting from %s to WaitPlayback' % self.state)
|
||||
self.request('WaitPlayback')
|
||||
self.sendUpdate('ballMovie2Client', [self.storeAction[1],
|
||||
avId,
|
||||
self.recording,
|
||||
self.aVRecording,
|
||||
self.ballInHoleFrame,
|
||||
self.ballTouchedHoleFrame,
|
||||
self.ballFirstTouchedHoleFrame,
|
||||
self.commonHoldData])
|
||||
self.ballPos[avId] = newPos
|
||||
self.trustedPlayerId = None
|
||||
return
|
||||
|
||||
def postResult(self, cycleTime, avId, recording, aVRecording, ballInHoleFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame):
|
||||
pass
|
||||
|
||||
def assignRecordSwing(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6, todo7, todo8):
|
||||
def enterWaitSwing(self):
|
||||
pass
|
||||
|
||||
def setBox(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6, todo7, todo8, todo9, todo10, todo11, todo12):
|
||||
def exitWaitSwing(self):
|
||||
pass
|
||||
|
||||
def sendBox(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6, todo7, todo8, todo9, todo10, todo11, todo12):
|
||||
def enterWaitTee(self):
|
||||
pass
|
||||
|
||||
def exitWaitTee(self):
|
||||
pass
|
||||
|
||||
def enterWaitPlayback(self):
|
||||
self.notify.debug('enterWaitPlayback')
|
||||
stillPlayingList = self.golfCourse.getStillPlayingAvIds()
|
||||
self.barrierPlayback = ToonBarrier('waitClientsPlayback', self.uniqueName('waitClientsPlayback'), stillPlayingList, 120, self.handleWaitPlaybackDone, self.handlePlaybackTimeout)
|
||||
|
||||
def hasCurGolferReachedMaxSwing(self):
|
||||
strokes = self.golfCourse.getCurHoleScore(self.activeGolferId)
|
||||
maxSwing = self.holeInfo['maxSwing']
|
||||
retval = strokes >= maxSwing
|
||||
if retval:
|
||||
av = simbase.air.doId2do.get(self.activeGolferId)
|
||||
if av:
|
||||
if av.getUnlimitedSwing():
|
||||
retval = False
|
||||
return retval
|
||||
|
||||
def handleWaitPlaybackDone(self):
|
||||
if self.isCurBallInHole(self.activeGolferId) or self.hasCurGolferReachedMaxSwing():
|
||||
if self.activeGolferId:
|
||||
self.ballInHole(self.activeGolferId)
|
||||
else:
|
||||
self.selectNextGolfer()
|
||||
|
||||
def isCurBallInHole(self, golferId):
|
||||
retval = False
|
||||
for holePos in self.holePositions:
|
||||
displacement = self.ballPos[golferId] - holePos
|
||||
length = displacement.length()
|
||||
self.notify.debug('hole %s length=%s' % (holePos, length))
|
||||
if length <= GolfGlobals.DistanceToBeInHole:
|
||||
retval = True
|
||||
break
|
||||
|
||||
return retval
|
||||
|
||||
def exitWaitPlayback(self):
|
||||
self.notify.debug('exitWaitPlayback')
|
||||
if hasattr(self, 'barrierPlayback') and self.barrierPlayback:
|
||||
self.barrierPlayback.cleanup()
|
||||
self.barrierPlayback = None
|
||||
return
|
||||
|
||||
def enterCleanup(self):
|
||||
pass
|
||||
|
||||
def exitCleanup(self):
|
||||
pass
|
||||
|
||||
def handlePlaybackTimeout(self, task = None):
|
||||
self.notify.debug('handlePlaybackTimeout')
|
||||
self.handleWaitPlaybackDone()
|
||||
|
||||
def getGolfCourseDoId(self):
|
||||
return self.golfCourse.doId
|
||||
|
||||
def avatarDropped(self, avId):
|
||||
self.notify.warning('avId %d dropped, self.state=%s' % (avId, self.state))
|
||||
if self.barrierPlayback:
|
||||
self.barrierPlayback.clear(avId)
|
||||
else:
|
||||
if avId == self.trustedPlayerId:
|
||||
self.doAction()
|
||||
if avId == self.activeGolferId and not self.golfCourse.haveAllGolfersExited():
|
||||
self.selectNextGolfer()
|
||||
|
||||
def setAvatarTee(self, chosenTee):
|
||||
golferId = self.air.getAvatarIdFromSender()
|
||||
self.teeChosen[golferId] = chosenTee
|
||||
self.ballPos[golferId] = self.teePositions[chosenTee]
|
||||
self.sendUpdate('setAvatarFinalTee', [golferId, chosenTee])
|
||||
self.sendUpdate('golfersTurn', [golferId])
|
||||
self.request('WaitSwing')
|
||||
|
||||
def setBox(self, pos0, pos1, pos2, quat0, quat1, quat2, quat3, anV0, anV1, anV2, lnV0, lnV1, lnV2):
|
||||
self.sendUpdate('sendBox', [pos0,
|
||||
pos1,
|
||||
pos2,
|
||||
quat0,
|
||||
quat1,
|
||||
quat2,
|
||||
quat3,
|
||||
anV0,
|
||||
anV1,
|
||||
anV2,
|
||||
lnV0,
|
||||
lnV1,
|
||||
lnV2])
|
||||
|
||||
def parseLocators(self, objectCollection, optional = 0):
|
||||
if optional and objectCollection.getNumPaths():
|
||||
if self.holeInfo.has_key('optionalMovers'):
|
||||
for optionalMoverId in self.holeInfo['optionalMovers']:
|
||||
searchStr = 'optional_mover_' + str(optionalMoverId)
|
||||
for objIndex in xrange(objectCollection.getNumPaths()):
|
||||
object = objectCollection.getPath(objIndex)
|
||||
if searchStr in object.getName():
|
||||
self.fillLocator(objectCollection, objIndex)
|
||||
break
|
||||
|
||||
else:
|
||||
for index in range(objectCollection.getNumPaths()):
|
||||
self.fillLocator(objectCollection, index)
|
||||
|
||||
def fillLocator(self, objectCollection, index):
|
||||
path = objectCollection[index]
|
||||
pathName = path.getName()
|
||||
pathArray = pathName.split('_')
|
||||
sizeX = None
|
||||
sizeY = None
|
||||
move = None
|
||||
type = None
|
||||
for subString in pathArray:
|
||||
if subString[:1] == 'X':
|
||||
dataString = subString[1:]
|
||||
dataString = dataString.replace('p', '.')
|
||||
sizeX = float(dataString)
|
||||
elif subString[:1] == 'Y':
|
||||
dataString = subString[1:]
|
||||
dataString = dataString.replace('p', '.')
|
||||
sizeY = float(dataString)
|
||||
elif subString[:1] == 'd':
|
||||
dataString = subString[1:]
|
||||
dataString = dataString.replace('p', '.')
|
||||
move = float(dataString)
|
||||
elif subString == 'mover':
|
||||
type = 4
|
||||
elif subString == 'windmillLocator':
|
||||
type = 3
|
||||
|
||||
if type == 4 and move and sizeX and sizeY:
|
||||
self.createCommonObject(4, path.getPos(), path.getHpr(), sizeX, sizeY, move)
|
||||
elif type == 3:
|
||||
self.createCommonObject(3, path.getPos(), path.getHpr())
|
||||
return
|
||||
|
|
|
@ -11,5 +11,12 @@ class GZHoodAI(HoodAI):
|
|||
|
||||
self.golfKarts = []
|
||||
|
||||
self.createZone()
|
||||
|
||||
def createZone(self):
|
||||
self.spawnObjects()
|
||||
|
||||
def spawnObjects(self):
|
||||
HoodAI.spawnObjects(self)
|
||||
filename = self.air.genDNAFileName(self.HOOD)
|
||||
self.air.dnaSpawner.spawnObjects(filename, self.HOOD)
|
|
@ -528,7 +528,7 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
DistributedMinigame.setGameStart(self, timestamp)
|
||||
self.notify.debug('setGameStart')
|
||||
self.treasurePanel = TreasureScorePanel.TreasureScorePanel()
|
||||
self.treasurePanel.setPos(0.145, 0, -0.27)
|
||||
self.treasurePanel.setPos(0.145, 0, -0.5)
|
||||
self.treasurePanel.reparentTo(base.a2dTopLeft)
|
||||
self.treasurePanel.makeTransparent(0.7)
|
||||
self.introMovie.finish()
|
||||
|
@ -628,7 +628,7 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
self.treasures[i].treasureNode.wrtReparentTo(render)
|
||||
self.treasures[i].grabbedId = 0
|
||||
seq = Sequence()
|
||||
shrink = LerpScaleInterval(self.treasures[i].treasureNode, duration=1.0, startScale=self.treasures[i].treasureNode.getScale(), scale=Vec3(0.001, 0.001, 0.001), blendType='easeIn')
|
||||
shrink = LerpScaleInterval(self.treasures[i].treasureNode, duration=1.0, startScale=self.treasures[i].treasureNode.getScale(), scale=Vec3(0.0, 0.0, 0.0), blendType='easeIn')
|
||||
shrinkIcon = LerpScaleInterval(self.chestIcons[i], duration=1.0, startScale=self.chestIcons[i].getScale(), scale=Vec3(0.001, 0.001, 0.001), blendType='easeIn')
|
||||
jump = ProjectileInterval(self.treasures[i].treasureNode, duration=1.0, startPos=self.treasures[i].treasureNode.getPos(), endPos=Point3(0, 0, 40), gravityMult=0.7)
|
||||
shrinkJump = Parallel(shrink, shrinkIcon, jump)
|
||||
|
@ -690,7 +690,7 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
volume = (soundRange - distance) / soundRange
|
||||
if toonSD.status == 'normal' or toonSD.status == 'treasure':
|
||||
self.localLerp.finish()
|
||||
self.localLerp = Sequence(Func(toonSD.fsm.request, 'freeze'), Wait(3.0), Func(toonSD.fsm.request, 'normal'))
|
||||
self.localLerp = Sequence(Func(toonSD.fsm.request, 'freeze'), Wait(1.6), Func(toonSD.fsm.request, 'normal'))
|
||||
self.localLerp.start(ts)
|
||||
self.hitSound.play()
|
||||
self.hitSound.setVolume(volume)
|
||||
|
@ -708,7 +708,7 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
volume = (soundRange - distance) / soundRange
|
||||
if toonSD.status == 'normal' or toonSD.status == 'treasure':
|
||||
self.localLerp.finish()
|
||||
self.localLerp = Sequence(Func(toonSD.fsm.request, 'freeze'), Wait(3.0), Func(toonSD.fsm.request, 'normal'))
|
||||
self.localLerp = Sequence(Func(toonSD.fsm.request, 'freeze'), Wait(1.6), Func(toonSD.fsm.request, 'normal'))
|
||||
self.localLerp.start(ts)
|
||||
if self.spawners[spawnerId].fishArray.has_key(spawnId):
|
||||
fish = self.spawners[spawnerId].fishArray[spawnId]
|
||||
|
|
|
@ -1038,16 +1038,19 @@ class DistributedIceGame(DistributedMinigame.DistributedMinigame, DistributedIce
|
|||
|
||||
def postStep(self):
|
||||
DistributedIceWorld.DistributedIceWorld.postStep(self)
|
||||
for count in range(self.colCount):
|
||||
c0, c1 = self.getOrderedContacts(count)
|
||||
if c1 in self.tireCollideIds:
|
||||
tireIndex = self.tireCollideIds.index(c1)
|
||||
if c0 in self.tireCollideIds:
|
||||
self.tireSounds[tireIndex]['tireHit'].play()
|
||||
elif c0 == self.wallCollideId:
|
||||
self.tireSounds[tireIndex]['wallHit'].play()
|
||||
elif c0 == self.obstacleCollideId:
|
||||
self.tireSounds[tireIndex]['obstacleHit'].play()
|
||||
if self.colCount:
|
||||
for count in range(self.colCount):
|
||||
c0, c1 = self.getOrderedContacts(count)
|
||||
if c1 in self.tireCollideIds:
|
||||
tireIndex = self.tireCollideIds.index(c1)
|
||||
if c0 in self.tireCollideIds:
|
||||
self.tireSounds[tireIndex]['tireHit'].play()
|
||||
elif c0 == self.wallCollideId:
|
||||
self.tireSounds[tireIndex]['wallHit'].play()
|
||||
elif c0 == self.obstacleCollideId:
|
||||
self.tireSounds[tireIndex]['obstacleHit'].play()
|
||||
else:
|
||||
self.notify.error('Couldn\'t find any collisions!')
|
||||
|
||||
def forceLocalToonToTire(self):
|
||||
toon = localAvatar
|
||||
|
|
|
@ -130,7 +130,6 @@ class DistributedPhotoGame(DistributedMinigame, PhotoGameBase.PhotoGameBase):
|
|||
self.sceneData = sceneTree.generateData()
|
||||
self.scene = hidden.attachNewNode(node)
|
||||
self.construct()
|
||||
purchaseModels = loader.loadModel('phase_4/models/gui/purchase_gui')
|
||||
self.filmImage = loader.loadModel('phase_4/models/minigames/photogame_filmroll')
|
||||
self.filmImage.reparentTo(hidden)
|
||||
self.tripodModel = loader.loadModel('phase_4/models/minigames/toon_cannon')
|
||||
|
@ -149,6 +148,7 @@ class DistributedPhotoGame(DistributedMinigame, PhotoGameBase.PhotoGameBase):
|
|||
self.viewfinderNode.setDepthWrite(1)
|
||||
self.viewfinderNode.setDepthTest(1)
|
||||
self.viewfinderNode.setY(-1.0)
|
||||
self.viewfinderNode.hide()
|
||||
self.screenSizeMult = 0.5
|
||||
self.screenSizeX = (base.a2dRight - base.a2dLeft) * self.screenSizeMult
|
||||
self.screenSizeZ = (base.a2dTop - base.a2dBottom) * self.screenSizeMult
|
||||
|
@ -252,6 +252,7 @@ class DistributedPhotoGame(DistributedMinigame, PhotoGameBase.PhotoGameBase):
|
|||
self.notify.debug('Onstage')
|
||||
DistributedMinigame.onstage(self)
|
||||
self.__createTripod()
|
||||
self.viewfinderNode.show()
|
||||
self.tripod.reparentTo(render)
|
||||
self.tripod.hide()
|
||||
self.__loadToonInTripod(self.localAvId)
|
||||
|
|
|
@ -10,7 +10,7 @@ class QuestChoiceGui(DirectFrame):
|
|||
notify = DirectNotifyGlobal.directNotify.newCategory('QuestChoiceGui')
|
||||
|
||||
def __init__(self):
|
||||
DirectFrame.__init__(self, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=Vec4(0.8, 0.6, 0.4, 1), geom_scale=(1.85, 1, 0.9), geom_hpr=(0, 0, -90), pos=(-0.85, 0, 0))
|
||||
DirectFrame.__init__(self, relief=None, parent=base.a2dLeftCenter, geom=DGG.getDefaultDialogGeom(), geom_color=Vec4(0.8, 0.6, 0.4, 1), geom_scale=(1.85, 1, 0.9), geom_hpr=(0, 0, -90), pos=(0.5, 0, 0))
|
||||
self.initialiseoptions(QuestChoiceGui)
|
||||
self.questChoicePosters = []
|
||||
guiButton = loader.loadModel('phase_3/models/gui/quit_button')
|
||||
|
|
|
@ -44,9 +44,14 @@ class QuestManagerAI:
|
|||
if isinstance(quest, Quests.CogQuest):
|
||||
# It's a cog quest!
|
||||
for suit in suitsKilled:
|
||||
if quest.doesCogCount(toon.getDoId(), suit, zoneId, activeToons):
|
||||
# The cog we killed counts!
|
||||
self.__incrementQuestProgress(toon.quests[index])
|
||||
# N.B.: This will iterate once if True, none if False.
|
||||
# If it's a newbie quest, it will return an integer rather than a
|
||||
# boolean, and will iterate x times.
|
||||
for x in xrange(quest.doesCogCount(toon.getDoId(), suit, zoneId, activeToons)):
|
||||
# Give us credit for this cog. If this a newbie quest, it will
|
||||
# give us multiple credit(s), depending on how many newbies were
|
||||
# in the battle.
|
||||
self.__incrementQuestProgress(toon.quests[index])
|
||||
toon.updateQuests()
|
||||
|
||||
def recoverItems(self, toon, suitsKilled, zoneId):
|
||||
|
@ -100,12 +105,16 @@ class QuestManagerAI:
|
|||
if isinstance(quest, Quests.BuildingQuest):
|
||||
# This quest is a building quest, time to see if it counts towards
|
||||
# our progress!
|
||||
if quest.isLocationMatch(zoneId) and quest.doesBuildingCount(toon.getDoId(), activeToons):
|
||||
if quest.isLocationMatch(zoneId):
|
||||
# We defeated the building in the correct zone, and the building counts!
|
||||
if quest.getBuildingTrack() == Quests.Any or quest.getBuildingTrack() == track:
|
||||
if floors >= quest.getNumFloors():
|
||||
# This building has more (or equal to) the number of floors we need.
|
||||
self.__incrementQuestProgress(toon.quests[index])
|
||||
for x in xrange(quest.doesBuildingCount(toon.getDoId(), activeToons)):
|
||||
# Works the same as Cog Quests. Increment by one if it's a
|
||||
# normal quest, or by the amount of newbies if it's a
|
||||
# newbie quest.
|
||||
self.__incrementQuestProgress(toon.quests[index])
|
||||
toon.updateQuests()
|
||||
|
||||
def toonKilledCogdo(self, toon, difficulty, floors, zoneId, activeToons):
|
||||
|
@ -122,8 +131,9 @@ class QuestManagerAI:
|
|||
for index, quest in enumerate(self.__toonQuestsList2Quests(toon.quests)):
|
||||
if isinstance(quest, Quests.FactoryQuest):
|
||||
# Cool, it's a factory quest! Does it count?
|
||||
if quest.doesFactoryCount(toon.getDoId(), factoryId, activeToonVictors):
|
||||
for x in xrange(quest.doesFactoryCount(toon.getDoId(), factoryId, activeToonVictors)):
|
||||
# Woo, this counts towards our quest progress!
|
||||
# Increment by the amount of credit we deserve.
|
||||
self.__incrementQuestProgress(toon.quests[index])
|
||||
toon.updateQuests()
|
||||
|
||||
|
@ -135,7 +145,7 @@ class QuestManagerAI:
|
|||
for index, quest in enumerate(self.__toonQuestsList2Quests(toon.quests)):
|
||||
if isinstance(quest, Quests.MintQuest):
|
||||
# Oh lookie here, a mint quest! I love me some Polos.
|
||||
if quest.doesMintCount(toon.getDoId(), mintId, activeToonVictors):
|
||||
for x in xrange(quest.doesMintCount(toon.getDoId(), mintId, activeToonVictors)):
|
||||
# Nom nom nom nom, progress!
|
||||
self.__incrementQuestProgress(toon.quests[index])
|
||||
toon.updateQuests()
|
||||
|
|
|
@ -172,8 +172,9 @@ class QuestMap(DirectFrame):
|
|||
self.marker.setHpr(0, 0, -180 - self.av.getH())
|
||||
i = 0
|
||||
for buildingMarker in self.buildingMarkers:
|
||||
buildingMarker.setScale((math.sin(task.time * 16.0 + i * math.pi / 3.0) + 1) * 0.005 + 0.04)
|
||||
i = i + 1
|
||||
if not buildingMarker.isEmpty():
|
||||
buildingMarker.setScale((math.sin(task.time * 16.0 + i * math.pi / 3.0) + 1) * 0.005 + 0.04)
|
||||
i = i + 1
|
||||
|
||||
return Task.cont
|
||||
|
||||
|
|
|
@ -121,25 +121,25 @@ class QuestPoster(DirectFrame):
|
|||
sc.setZ(sc[2] + 0.07)
|
||||
self['image_scale'] = sc
|
||||
self.questFrame.setZ(0.03)
|
||||
self.headline.setZ(self.headline.getZ() + 0.03)
|
||||
self.lPictureFrame.setZ(self.lPictureFrame.getZ() + 0.03)
|
||||
self.rPictureFrame.setZ(self.rPictureFrame.getZ() + 0.03)
|
||||
self.questInfo.setZ(self.questInfo.getZ() + 0.03)
|
||||
self.questProgress.setZ(self.questProgress.getZ() + 0.03)
|
||||
self.auxText.setZ(self.auxText.getZ() + 0.03)
|
||||
self.funQuest.setZ(self.funQuest.getZ() + 0.03)
|
||||
self.headline.setZ(0.23 + 0.03)
|
||||
self.lPictureFrame.setZ(0.13 + 0.03)
|
||||
self.rPictureFrame.setZ(0.13 + 0.03)
|
||||
self.questInfo.setZ(-0.0625 + 0.03)
|
||||
self.questProgress.setZ(-0.195 + 0.03)
|
||||
self.auxText.setZ(0.12 + 0.03)
|
||||
self.funQuest.setZ(0.2 + 0.03)
|
||||
self.rewardText.show()
|
||||
|
||||
def mouseExitPoster(self, event):
|
||||
self['image_scale'] = self.initImageScale
|
||||
self.questFrame.setZ(0)
|
||||
self.headline.setZ(self.headline.getZ() - 0.03)
|
||||
self.lPictureFrame.setZ(self.lPictureFrame.getZ() - 0.03)
|
||||
self.rPictureFrame.setZ(self.rPictureFrame.getZ() - 0.03)
|
||||
self.questInfo.setZ(self.questInfo.getZ() - 0.03)
|
||||
self.questProgress.setZ(self.questProgress.getZ() - 0.03)
|
||||
self.auxText.setZ(self.auxText.getZ() - 0.03)
|
||||
self.funQuest.setZ(self.funQuest.getZ() - 0.03)
|
||||
self.headline.setZ(0.23)
|
||||
self.lPictureFrame.setZ(0.13)
|
||||
self.rPictureFrame.setZ(0.13)
|
||||
self.questInfo.setZ(-0.0625)
|
||||
self.questProgress.setZ(-0.195)
|
||||
self.auxText.setZ(0.12)
|
||||
self.funQuest.setZ(0.2)
|
||||
self.rewardText.hide()
|
||||
|
||||
def createNpcToonHead(self, toNpcId):
|
||||
|
|
|
@ -768,7 +768,7 @@ class SkeleReviveQBase:
|
|||
return TTLocalizer.v2CogP
|
||||
|
||||
def doesCogCount(self, avId, cogDict, zoneId, avList):
|
||||
return cogDict['hasRevives'] and avId in cogDict['activeToons'] and self.isLocationMatch(zoneId)
|
||||
return cogDict.get('hasRevives', False) and avId in cogDict.get('activeToons', []) and self.isLocationMatch(zoneId)
|
||||
|
||||
|
||||
class SkeleReviveQuest(CogQuest, SkeleReviveQBase):
|
||||
|
|
|
@ -34,7 +34,10 @@ class DistributedStartingBlockAI(DistributedObjectAI):
|
|||
|
||||
def requestEnter(self, isPaid):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
av = self.air.doId2do[avId]
|
||||
av = self.air.doId2do.get(avId)
|
||||
if not av:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to board a starting block, but is not on the district!')
|
||||
return
|
||||
if not av.hasKart():
|
||||
self.sendUpdateToAvatarId(avId, 'rejectEnter', [KartGlobals.ERROR_CODE.eNoKart])
|
||||
return
|
||||
|
|
|
@ -1,232 +1,334 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
||||
from otp.ai.AIBase import *
|
||||
from toontown.toonbase.ToontownGlobals import *
|
||||
from direct.distributed.ClockDelta import *
|
||||
from direct.fsm.FSM import FSM
|
||||
from toontown.golf.DistributedGolfCourseAI import DistributedGolfCourseAI
|
||||
from toontown.golf.DistributedGolfHoleAI import DistributedGolfHoleAI
|
||||
from TrolleyConstants 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.minigame import MinigameCreatorAI
|
||||
from toontown.quest import Quests
|
||||
from toontown.golf import GolfGlobals
|
||||
from toontown.golf.DistributedGolfCourseAI import DistributedGolfCourseAI
|
||||
import random
|
||||
|
||||
class DistributedGolfKartAI(DistributedObjectAI, FSM):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGolfKartAI")
|
||||
|
||||
def __init__(self, air):
|
||||
DistributedObjectAI.__init__(self, air)
|
||||
FSM.__init__(self, 'DistributedGolfKartAI')
|
||||
self.air = air
|
||||
self.lastTime = globalClockDelta.getRealNetworkTime()
|
||||
self.slots = [None, None, None, None]
|
||||
self.golfCountdownTime = simbase.config.GetFloat('golf-countdown-time', TROLLEY_COUNTDOWN_TIME)
|
||||
self.color = [255, 255 , 255]
|
||||
self.startingPos = None
|
||||
self.startingHpr = None
|
||||
self.boardable = True
|
||||
|
||||
def announceGenerate(self):
|
||||
self.b_setState('WaitEmpty', globalClockDelta.getRealNetworkTime())
|
||||
|
||||
def setState(self, state, timeStamp):
|
||||
self.lastTime = globalClockDelta.getRealNetworkTime()
|
||||
self.request(state)
|
||||
|
||||
def d_setState(self, state, timeStamp):
|
||||
state = state[:1].lower() + state[1:]
|
||||
self.sendUpdate('setState', [state, timeStamp])
|
||||
|
||||
def b_setState(self, state, timeStamp):
|
||||
self.setState(state, timeStamp)
|
||||
self.d_setState(state, timeStamp)
|
||||
|
||||
def getState(self):
|
||||
return [self.state, self.lastTime]
|
||||
from toontown.dna.DNASpawnerAI import *
|
||||
from toontown.dna.DNANode import DNANode
|
||||
|
||||
class DistributedGolfKartAI(DistributedObjectAI.DistributedObjectAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfKartAI')
|
||||
|
||||
def requestBoard(self): #stolen from trolley, clean it
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
|
||||
#TEMPORARY
|
||||
#for slot in self.slots:
|
||||
# if slot:
|
||||
# self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
||||
# return
|
||||
|
||||
if avId in self.slots:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon requested to board a trolley twice!')
|
||||
self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
||||
return
|
||||
|
||||
slot = self.getBoardingSlot()
|
||||
if slot == -1:
|
||||
self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
||||
return
|
||||
|
||||
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.removeFromKart, extraArgs=[avId])
|
||||
|
||||
self.sendUpdate('emptySlot%d' % slot, [0, globalClockDelta.getRealNetworkTime()])
|
||||
self.sendUpdate('fillSlot%d' % slot, [avId])
|
||||
self.slots[slot] = avId
|
||||
|
||||
if self.state == 'WaitEmpty':
|
||||
self.b_setState('WaitCountdown', globalClockDelta.getRealNetworkTime())
|
||||
|
||||
def requestExit(self): #stolen from trolley, clean it
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
|
||||
if avId not in self.slots:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon requested to exit a trolley they are not on!')
|
||||
return
|
||||
|
||||
if not self.boardable:
|
||||
# Trolley's leaving, can't hop off!
|
||||
return
|
||||
|
||||
self.removeFromKart(avId, True)
|
||||
|
||||
def removeFromKart(self, avId, hopOff=False): #just guess...
|
||||
if avId not in self.slots:
|
||||
return
|
||||
|
||||
self.ignore(self.air.getAvatarExitEvent(avId))
|
||||
|
||||
slot = self.slots.index(avId)
|
||||
self.sendUpdate('fillSlot%d' % slot, [0])
|
||||
if hopOff:
|
||||
# FIXME: Is this the correct way to make sure that the emptySlot
|
||||
# doesn't persist, yet still animate the avId hopping off? There
|
||||
# should probably be a timer that sets the slot to 0 after the
|
||||
# hopoff animation finishes playing. (And such a timer will have to
|
||||
# be canceled if another Toon occpuies the same slot in that time.)
|
||||
self.sendUpdate('emptySlot%d' % slot, [avId, globalClockDelta.getRealNetworkTime()])
|
||||
self.sendUpdate('emptySlot%d' % slot, [0, globalClockDelta.getRealNetworkTime()])
|
||||
self.slots[slot] = None
|
||||
|
||||
if self.state == 'WaitCountdown' and self.slots.count(None) == 4:
|
||||
self.b_setState('WaitEmpty', globalClockDelta.getRealNetworkTime())
|
||||
|
||||
def getBoardingSlot(self):
|
||||
if not self.boardable:
|
||||
print 'rejecting, not boardable'
|
||||
return -1
|
||||
|
||||
if None not in self.slots:
|
||||
print 'rejecting, no slot available'
|
||||
return -1
|
||||
|
||||
return self.slots.index(None)
|
||||
def setMinigameZone(self, todo0, todo1):
|
||||
pass
|
||||
|
||||
def setGolfZone(self, golfZone):
|
||||
self.golfZone = golfZone
|
||||
|
||||
def d_setGolfZone(self, golfZone):
|
||||
self.sendUpdate('setGolfZone', [golfZone])
|
||||
|
||||
def b_setGolfZone(self, golfZone):
|
||||
self.setGolfZone(golfZone)
|
||||
self.d_setGolfZone(golfZone)
|
||||
|
||||
def getGolfZone(self):
|
||||
return self.golfZone
|
||||
|
||||
def setGolfCourse(self, golfCourse):
|
||||
def __init__(self, air, golfCourse, x, y, z, h, p, r):
|
||||
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||||
self.seats = [None,
|
||||
None,
|
||||
None,
|
||||
None]
|
||||
self.golfCourse = golfCourse
|
||||
|
||||
def d_setGolfCourse(self, golfCourse):
|
||||
self.sendUpdate('setGolfCourse', [golfCourse])
|
||||
|
||||
def b_setGolfCourse(self, golfCourse):
|
||||
self.setGolfCourse(golfCourse)
|
||||
self.d_setGolfCourse(golfCourse)
|
||||
|
||||
self.posHpr = (x,
|
||||
y,
|
||||
z,
|
||||
h,
|
||||
p,
|
||||
r)
|
||||
self.color = (random.randint(GolfGlobals.KartColors[self.golfCourse][0][0], GolfGlobals.KartColors[self.golfCourse][0][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][1][0], GolfGlobals.KartColors[self.golfCourse][1][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][2][0], GolfGlobals.KartColors[self.golfCourse][2][1]))
|
||||
if self.golfCourse == 1:
|
||||
if self.color[0] + self.color[1] <= 255:
|
||||
self.color = (self.color[0], self.color[0] + self.color[1], self.color[2])
|
||||
else:
|
||||
self.color = (self.color[0], 255, self.color[2])
|
||||
self.accepting = 0
|
||||
self.trolleyCountdownTime = simbase.config.GetFloat('trolley-countdown-time', TROLLEY_COUNTDOWN_TIME)
|
||||
self.fsm = ClassicFSM.ClassicFSM('DistributedGolfKartAI', [State.State('off', self.enterOff, self.exitOff, ['entering']),
|
||||
State.State('entering', self.enterEntering, self.exitEntering, ['waitEmpty']),
|
||||
State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, ['waitCountdown']),
|
||||
State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, ['waitEmpty', 'allAboard']),
|
||||
State.State('allAboard', self.enterAllAboard, self.exitAllAboard, ['leaving', 'waitEmpty']),
|
||||
State.State('leaving', self.enterLeaving, self.exitLeaving, ['entering'])], 'off', 'off')
|
||||
self.fsm.enterInitialState()
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
self.fsm.requestFinalState()
|
||||
del self.fsm
|
||||
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||
|
||||
def findAvailableSeat(self):
|
||||
for i in range(len(self.seats)):
|
||||
if self.seats[i] == None:
|
||||
return i
|
||||
|
||||
return
|
||||
|
||||
def findAvatar(self, avId):
|
||||
for i in range(len(self.seats)):
|
||||
if self.seats[i] == avId:
|
||||
return i
|
||||
|
||||
return None
|
||||
|
||||
def countFullSeats(self):
|
||||
avCounter = 0
|
||||
for i in self.seats:
|
||||
if i:
|
||||
avCounter += 1
|
||||
|
||||
return avCounter
|
||||
|
||||
def rejectingBoardersHandler(self, avId):
|
||||
self.rejectBoarder(avId)
|
||||
|
||||
def rejectBoarder(self, avId):
|
||||
self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
||||
|
||||
def acceptingBoardersHandler(self, avId):
|
||||
self.notify.debug('acceptingBoardersHandler')
|
||||
seatIndex = self.findAvailableSeat()
|
||||
if seatIndex == None:
|
||||
self.rejectBoarder(avId)
|
||||
else:
|
||||
self.acceptBoarder(avId, seatIndex)
|
||||
return
|
||||
|
||||
def acceptBoarder(self, avId, seatIndex):
|
||||
self.notify.debug('acceptBoarder')
|
||||
if self.findAvatar(avId) != None:
|
||||
return
|
||||
self.seats[seatIndex] = avId
|
||||
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId])
|
||||
self.timeOfBoarding = globalClock.getRealTime()
|
||||
self.sendUpdate('fillSlot' + str(seatIndex), [avId])
|
||||
self.waitCountdown()
|
||||
return
|
||||
|
||||
def __handleUnexpectedExit(self, avId):
|
||||
self.notify.warning('Avatar: ' + str(avId) + ' has exited unexpectedly')
|
||||
seatIndex = self.findAvatar(avId)
|
||||
if seatIndex == None:
|
||||
pass
|
||||
else:
|
||||
self.clearFullNow(seatIndex)
|
||||
self.clearEmptyNow(seatIndex)
|
||||
if self.countFullSeats() == 0:
|
||||
self.waitEmpty()
|
||||
return
|
||||
|
||||
def rejectingExitersHandler(self, avId):
|
||||
self.rejectExiter(avId)
|
||||
|
||||
def rejectExiter(self, avId):
|
||||
pass
|
||||
|
||||
def acceptingExitersHandler(self, avId):
|
||||
self.acceptExiter(avId)
|
||||
|
||||
def acceptExiter(self, avId):
|
||||
seatIndex = self.findAvatar(avId)
|
||||
if seatIndex == None:
|
||||
pass
|
||||
else:
|
||||
self.clearFullNow(seatIndex)
|
||||
self.sendUpdate('emptySlot' + str(seatIndex), [avId, globalClockDelta.getRealNetworkTime()])
|
||||
if self.countFullSeats() == 0:
|
||||
self.waitEmpty()
|
||||
taskMgr.doMethodLater(TOON_EXIT_TIME, self.clearEmptyNow, self.uniqueName('clearEmpty-%s' % seatIndex), extraArgs=(seatIndex,))
|
||||
return
|
||||
|
||||
def clearEmptyNow(self, seatIndex):
|
||||
self.sendUpdate('emptySlot' + str(seatIndex), [0, globalClockDelta.getRealNetworkTime()])
|
||||
|
||||
def clearFullNow(self, seatIndex):
|
||||
avId = self.seats[seatIndex]
|
||||
if avId == 0 or avId == None:
|
||||
self.notify.warning('Clearing an empty seat index: ' + str(seatIndex) + ' ... Strange...')
|
||||
else:
|
||||
self.seats[seatIndex] = None
|
||||
self.sendUpdate('fillSlot' + str(seatIndex), [0])
|
||||
self.ignore(self.air.getAvatarExitEvent(avId))
|
||||
return
|
||||
|
||||
def d_setState(self, state):
|
||||
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime()])
|
||||
|
||||
def getState(self):
|
||||
return self.fsm.getCurrentState().getName()
|
||||
|
||||
def requestBoard(self, *args):
|
||||
self.notify.debug('requestBoard')
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if self.findAvatar(avId) != None:
|
||||
self.notify.warning('Ignoring multiple requests from %s to board.' % avId)
|
||||
return
|
||||
av = self.air.doId2do.get(avId)
|
||||
if av:
|
||||
newArgs = (avId,) + args
|
||||
if av.hp > 0 and self.accepting:
|
||||
self.acceptingBoardersHandler(*newArgs)
|
||||
else:
|
||||
self.rejectingBoardersHandler(*newArgs)
|
||||
else:
|
||||
self.notify.warning('avid: %s does not exist, but tried to board a trolley' % avId)
|
||||
return
|
||||
|
||||
def requestExit(self, *args):
|
||||
self.notify.debug('requestExit')
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
av = self.air.doId2do.get(avId)
|
||||
if av:
|
||||
newArgs = (avId,) + args
|
||||
if self.accepting:
|
||||
self.acceptingExitersHandler(*newArgs)
|
||||
else:
|
||||
self.rejectingExitersHandler(*newArgs)
|
||||
else:
|
||||
self.notify.warning('avId: %s does not exist, but tried to exit a trolley' % avId)
|
||||
|
||||
def start(self):
|
||||
self.enter()
|
||||
|
||||
def enterOff(self):
|
||||
self.accepting = 0
|
||||
if hasattr(self, 'doId'):
|
||||
for seatIndex in range(4):
|
||||
taskMgr.remove(self.uniqueName('clearEmpty-' + str(seatIndex)))
|
||||
|
||||
def exitOff(self):
|
||||
self.accepting = 0
|
||||
|
||||
def enter(self):
|
||||
self.fsm.request('entering')
|
||||
|
||||
def enterEntering(self):
|
||||
self.d_setState('entering')
|
||||
self.accepting = 0
|
||||
self.seats = [None,
|
||||
None,
|
||||
None,
|
||||
None]
|
||||
taskMgr.doMethodLater(TROLLEY_ENTER_TIME, self.waitEmptyTask, self.uniqueName('entering-timer'))
|
||||
return
|
||||
|
||||
def exitEntering(self):
|
||||
self.accepting = 0
|
||||
taskMgr.remove(self.uniqueName('entering-timer'))
|
||||
|
||||
def waitEmptyTask(self, task):
|
||||
self.waitEmpty()
|
||||
return Task.done
|
||||
|
||||
def waitEmpty(self):
|
||||
self.fsm.request('waitEmpty')
|
||||
|
||||
def enterWaitEmpty(self):
|
||||
self.d_setState('waitEmpty')
|
||||
self.accepting = 1
|
||||
|
||||
def exitWaitEmpty(self):
|
||||
self.accepting = 0
|
||||
|
||||
def waitCountdown(self):
|
||||
self.fsm.request('waitCountdown')
|
||||
|
||||
def enterWaitCountdown(self):
|
||||
self.d_setState('waitCountdown')
|
||||
self.accepting = 1
|
||||
taskMgr.doMethodLater(self.trolleyCountdownTime, self.timeToGoTask, self.uniqueName('countdown-timer'))
|
||||
|
||||
def timeToGoTask(self, task):
|
||||
if self.countFullSeats() > 0:
|
||||
self.allAboard()
|
||||
else:
|
||||
self.waitEmpty()
|
||||
return Task.done
|
||||
|
||||
def exitWaitCountdown(self):
|
||||
self.accepting = 0
|
||||
taskMgr.remove(self.uniqueName('countdown-timer'))
|
||||
|
||||
def allAboard(self):
|
||||
self.fsm.request('allAboard')
|
||||
|
||||
def enterAllAboard(self):
|
||||
self.accepting = 0
|
||||
currentTime = globalClock.getRealTime()
|
||||
elapsedTime = currentTime - self.timeOfBoarding
|
||||
self.notify.debug('elapsed time: ' + str(elapsedTime))
|
||||
waitTime = max(TOON_BOARD_TIME - elapsedTime, 0)
|
||||
taskMgr.doMethodLater(waitTime, self.leaveTask, self.uniqueName('waitForAllAboard'))
|
||||
|
||||
def exitAllAboard(self):
|
||||
self.accepting = 0
|
||||
taskMgr.remove(self.uniqueName('waitForAllAboard'))
|
||||
|
||||
def leaveTask(self, task):
|
||||
if self.countFullSeats() > 0:
|
||||
self.leave()
|
||||
else:
|
||||
self.waitEmpty()
|
||||
return Task.done
|
||||
|
||||
def leave(self):
|
||||
self.fsm.request('leaving')
|
||||
|
||||
def enterLeaving(self):
|
||||
self.d_setState('leaving')
|
||||
self.accepting = 0
|
||||
taskMgr.doMethodLater(TROLLEY_EXIT_TIME, self.trolleyLeftTask, self.uniqueName('leaving-timer'))
|
||||
|
||||
def trolleyLeftTask(self, task):
|
||||
self.trolleyLeft()
|
||||
return Task.done
|
||||
|
||||
def trolleyLeft(self):
|
||||
numPlayers = self.countFullSeats()
|
||||
avIdList = []
|
||||
if numPlayers > 0:
|
||||
for seatIndex in range(len(self.seats)):
|
||||
avId = self.seats[seatIndex]
|
||||
if avId != None and avId != 0:
|
||||
avIdList.append(avId)
|
||||
self.clearFullNow(seatIndex)
|
||||
|
||||
golfZone = self.air.allocateZone()
|
||||
course = DistributedGolfCourseAI(golfZone, avIdList, self.golfCourse)
|
||||
course.generateWithRequired(golfZone)
|
||||
for avId in avIdList:
|
||||
if avId:
|
||||
self.sendUpdateToAvatarId(avId, 'setGolfZone', [golfZone, 0])
|
||||
|
||||
else:
|
||||
self.notify.warning('The trolley left, but was empty.')
|
||||
self.enter()
|
||||
|
||||
def exitLeaving(self):
|
||||
self.accepting = 0
|
||||
self.color = (random.randint(GolfGlobals.KartColors[self.golfCourse][0][0], GolfGlobals.KartColors[self.golfCourse][0][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][1][0], GolfGlobals.KartColors[self.golfCourse][1][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][2][0], GolfGlobals.KartColors[self.golfCourse][2][1]))
|
||||
if self.golfCourse == 1:
|
||||
if self.color[0] + self.color[1] <= 255:
|
||||
self.color = (self.color[0], self.color[0] + self.color[1], self.color[2])
|
||||
else:
|
||||
self.color = (self.color[0], 255, self.color[2])
|
||||
self.sendUpdate('setColor', [self.color[0], self.color[1], self.color[2]])
|
||||
taskMgr.remove(self.uniqueName('leaving-timer'))
|
||||
|
||||
def getGolfCourse(self):
|
||||
return self.golfCourse
|
||||
|
||||
def setPosHpr(self, x, y, z, h, p, r):
|
||||
self.startingPos = Vec3(x, y, z)
|
||||
self.enteringPos = Vec3(x, y, z - 10)
|
||||
self.startingHpr = Vec3(h, 0, 0)
|
||||
|
||||
def d_setPosHpr(self, x, y, z, h, p, r):
|
||||
self.sendUpdate('setPosHpr', [[x, y, z, h, p, r]])
|
||||
|
||||
def b_setPosHpr(self, x, y, z, h, p, r):
|
||||
self.setPosHpr(x, y, z, h, p, r)
|
||||
self.d_setPosHpr(x, y, z, h, p, r)
|
||||
|
||||
def getPosHpr(self):
|
||||
return [self.startingPos[0], self.startingPos[1], self.startingPos[2], self.startingHpr[0], self.startingHpr[1], self.startingHpr[2]]
|
||||
return self.posHpr
|
||||
|
||||
def setColor(self, r, g, b):
|
||||
self.color = [r, g, b]
|
||||
|
||||
def enterOff(self):
|
||||
pass
|
||||
|
||||
def exitOff(self):
|
||||
pass
|
||||
|
||||
def getColor(self):
|
||||
return self.color #lol dividing by 0 on the client
|
||||
|
||||
def enterWaitEmpty(self):
|
||||
self.boardable = True
|
||||
|
||||
def exitWaitEmpty(self):
|
||||
self.boardable = False
|
||||
|
||||
def enterWaitCountdown(self):
|
||||
self.boardable = True
|
||||
self.departureTask = taskMgr.doMethodLater(self.golfCountdownTime, self.__depart, 'kartDepartureTask')
|
||||
|
||||
def __depart(self, task):
|
||||
self.b_setState('Leaving', globalClockDelta.getRealNetworkTime())
|
||||
return task.done
|
||||
|
||||
def exitWaitCountdown(self):
|
||||
taskMgr.remove(self.departureTask)
|
||||
self.boardable = False
|
||||
|
||||
def enterLeaving(self):
|
||||
self.leavingTask = taskMgr.doMethodLater(TROLLEY_EXIT_TIME, self.__activateGolf, 'kartLeaveTask')
|
||||
|
||||
def __activateGolf(self, task):
|
||||
players = [player for player in self.slots if player is not None]
|
||||
|
||||
if players:
|
||||
# If all players disconnected while the KART was departing, the
|
||||
# players array would be empty. Therefore, we should only attempt
|
||||
# to create a GOLF GAME if there are still players.
|
||||
|
||||
gg = self.createGolfGame(players)
|
||||
for player in players:
|
||||
self.sendUpdateToAvatarId(player, 'setGolfZone', gg)
|
||||
self.removeFromKart(player)
|
||||
|
||||
self.b_setState('Entering', globalClockDelta.getRealNetworkTime())
|
||||
return task.done
|
||||
|
||||
def createGolfGame(self, players):
|
||||
gameZone = self.air.allocateZone(owner=self)
|
||||
|
||||
course = DistributedGolfCourseAI(self.air)
|
||||
course.setGolferIds(players)
|
||||
course.setCourseId(self.index)
|
||||
course.zone = gameZone
|
||||
course.generateWithRequired(gameZone)
|
||||
|
||||
|
||||
return [gameZone, self.index]
|
||||
|
||||
def exitLeaving(self):
|
||||
taskMgr.remove(self.leavingTask)
|
||||
|
||||
def enterEntering(self):
|
||||
self.enteringTask = taskMgr.doMethodLater(TROLLEY_ENTER_TIME, self.__doneEntering, 'kartEnterTask')
|
||||
|
||||
def __doneEntering(self, task):
|
||||
self.b_setState('WaitEmpty', globalClockDelta.getRealNetworkTime())
|
||||
return task.done
|
||||
|
||||
def exitEntering(self):
|
||||
taskMgr.remove(self.enteringTask)
|
||||
return self.color
|
||||
|
||||
@dnaSpawn(DNANode, 'golf_kart_([0-9]+)_([0-9]+)')
|
||||
def spawn(air, zone, element, match):
|
||||
if config.GetBool('want-golf', True):
|
||||
index = int(match.group(1))
|
||||
dest = int(match.group(2))
|
||||
for child in element.children:
|
||||
x, y, z = child.getPos()
|
||||
h, p, r = child.getHpr()
|
||||
kart = DistributedGolfKartAI(air, index, x, y, z, h, p, r)
|
||||
kart.generateWithRequired(zone)
|
||||
kart.start()
|
||||
|
|
|
@ -99,7 +99,7 @@ SafeZoneTreasureSpawns = {
|
|||
(41.4197, 4.35384, -12.308),
|
||||
],
|
||||
10, # Rate
|
||||
2 # Maximum
|
||||
3 # Maximum
|
||||
),
|
||||
ToontownGlobals.DaisyGardens: (
|
||||
TreasureDG, 10, # DGTreasure heals 10 each...
|
||||
|
@ -126,7 +126,7 @@ SafeZoneTreasureSpawns = {
|
|||
(-102, 101, 0.0),
|
||||
],
|
||||
7, # Rate
|
||||
2 # Maximum
|
||||
4 # Maximum
|
||||
),
|
||||
ToontownGlobals.TheBrrrgh: (
|
||||
TreasureBR, 12, # +12 laff
|
||||
|
@ -151,7 +151,7 @@ SafeZoneTreasureSpawns = {
|
|||
(35, -98, 6.2),
|
||||
],
|
||||
10, # Rate
|
||||
2 # Maximum
|
||||
3 # Maximum
|
||||
),
|
||||
ToontownGlobals.MinniesMelodyland: (
|
||||
TreasureMM, 10, # +10 laff
|
||||
|
@ -177,7 +177,7 @@ SafeZoneTreasureSpawns = {
|
|||
(-24, -75, -14.5),
|
||||
],
|
||||
10, # Rate
|
||||
2 # Maximum
|
||||
4 # Maximum
|
||||
),
|
||||
ToontownGlobals.DonaldsDreamland: (
|
||||
TreasureDL, 12, # +12 laff
|
||||
|
@ -201,7 +201,7 @@ SafeZoneTreasureSpawns = {
|
|||
(-34, -88, 0.0),
|
||||
],
|
||||
10, # Rate
|
||||
2 #Maximum
|
||||
3 #Maximum
|
||||
),
|
||||
ToontownGlobals.OutdoorZone: (
|
||||
TreasureOZ, 3, # +3 laff
|
||||
|
|
|
@ -9,6 +9,7 @@ from toontown.hood import ZoneUtil
|
|||
from toontown.toonbase import ToontownGlobals
|
||||
from toontown.distributed import ToontownDistrictStats
|
||||
from toontown.toontowngui import TTDialog
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
POP_COLORS_NTT = (Vec4(0.0, 1.0, 0.0, 1.0), Vec4(1.0, 1.0, 0.0, 1.0), Vec4(1.0, 0.0, 0.0, 1.0))
|
||||
POP_COLORS = (Vec4(0.4, 0.4, 1.0, 1.0), Vec4(0.4, 1.0, 0.4, 1.0), Vec4(1.0, 0.4, 0.4, 1.0))
|
||||
|
||||
|
@ -27,6 +28,7 @@ class ShardPage(ShtikerPage.ShtikerPage):
|
|||
self.lowPop, self.midPop, self.highPop = base.getShardPopLimits()
|
||||
self.showPop = config.GetBool('show-total-population', 0)
|
||||
self.noTeleport = config.GetBool('shard-page-disable', 0)
|
||||
self.adminForceReload = 0
|
||||
return
|
||||
|
||||
def load(self):
|
||||
|
@ -200,7 +202,7 @@ class ShardPage(ShtikerPage.ShtikerPage):
|
|||
totalWVPop += WVPop
|
||||
currentMap[shardId] = 1
|
||||
buttonTuple = self.shardButtonMap.get(shardId)
|
||||
if buttonTuple == None:
|
||||
if buttonTuple == None or self.adminForceReload:
|
||||
buttonTuple = self.makeShardButton(shardId, name, pop)
|
||||
self.shardButtonMap[shardId] = buttonTuple
|
||||
anyChanges = 1
|
||||
|
@ -236,7 +238,8 @@ class ShardPage(ShtikerPage.ShtikerPage):
|
|||
buttonTuple[1]['text'] = self.getPopText(totalWVPop)
|
||||
buttonTuple[1]['command'] = self.getPopChoiceHandler(totalWVPop)
|
||||
buttonTuple[2]['command'] = self.getPopChoiceHandler(totalWVPop)
|
||||
if anyChanges:
|
||||
|
||||
if anyChanges or self.adminForceReload:
|
||||
self.regenerateScrollList()
|
||||
self.totalPopulationText['text'] = TTLocalizer.ShardPagePopulationTotal % totalPop
|
||||
helpText = TTLocalizer.ShardPageHelpIntro
|
||||
|
@ -248,6 +251,8 @@ class ShardPage(ShtikerPage.ShtikerPage):
|
|||
if not self.book.safeMode:
|
||||
helpText += TTLocalizer.ShardPageHelpMove
|
||||
self.helpText['text'] = helpText
|
||||
if self.adminForceReload:
|
||||
self.adminForceReload = 0
|
||||
return
|
||||
|
||||
def enter(self):
|
||||
|
@ -301,3 +306,17 @@ class ShardPage(ShtikerPage.ShtikerPage):
|
|||
place = base.cr.playGame.hood.place
|
||||
|
||||
place.requestTeleport(canonicalHoodId, canonicalHoodId, shardId, -1)
|
||||
|
||||
@magicWord(category=CATEGORY_MODERATION)
|
||||
def togpop():
|
||||
"""
|
||||
Moderation command to toggle shard population. If toggled off, moderators can teleport in
|
||||
to full districts, regardless of their population.
|
||||
|
||||
This command should NOT be abused for normal game play, as districts have a "full" status
|
||||
for a reason, and cramming more toons in to a district can cause stability issues.
|
||||
"""
|
||||
base.localAvatar.shardPage.showPop = not base.localAvatar.shardPage.showPop
|
||||
base.localAvatar.shardPage.adminForceReload = 1
|
||||
base.localAvatar.shardPage.updateScrollList()
|
||||
return "District population has been %s." % ("enabled" if base.localAvatar.shardPage.showPop else "disabled")
|
||||
|
|
|
@ -95,7 +95,7 @@ class DistributedGoon(DistributedCrushableEntity.DistributedCrushableEntity, Goo
|
|||
self.cSphereBitMask = ToontownGlobals.WallBitmask
|
||||
self.cSphereNode.setCollideMask(self.cSphereBitMask)
|
||||
self.cSphere.setTangible(1)
|
||||
self.sSphere = CollisionSphere(0.0, 0.0, self.headHeight + 0.8, 0.2)
|
||||
self.sSphere = CollisionSphere(0.0, 0.0, self.headHeight + 0.8, 1.2)
|
||||
self.sSphereNode = CollisionNode('toonSphere')
|
||||
self.sSphereNode.addSolid(self.sSphere)
|
||||
self.sSphereNodePath = self.head.attachNewNode(self.sSphereNode)
|
||||
|
|
|
@ -220,7 +220,8 @@ class DistributedSellbotBoss(DistributedBossCog.DistributedBossCog, FSM.FSM):
|
|||
self.cagedToon.reparentTo(self.cage)
|
||||
self.cagedToon.setPosHpr(0, -2, 0, 180, 0, 0)
|
||||
self.cagedToon.loop('neutral')
|
||||
touch = CollisionPolygon(Point3(-3.0382, 3.0382, -1), Point3(3.0382, 3.0382, -1), Point3(3.0382, -3.0382, -1), Point3(-3.0382, -3.0382, -1))
|
||||
|
||||
touch = cs = CollisionSphere(0, 0, 0, 4)
|
||||
touchNode = CollisionNode('Cage')
|
||||
touchNode.setCollideMask(ToontownGlobals.WallBitmask)
|
||||
touchNode.addSolid(touch)
|
||||
|
|
|
@ -24,7 +24,7 @@ class DistributedSellbotBossAI(DistributedBossCogAI.DistributedBossCogAI, FSM.FS
|
|||
DistributedBossCogAI.DistributedBossCogAI.__init__(self, air, 's')
|
||||
FSM.FSM.__init__(self, 'DistributedSellbotBossAI')
|
||||
self.doobers = []
|
||||
self.cagedToonNpcId = random.choice(NPCToons.npcFriends.keys())
|
||||
self.cagedToonNpcId = random.choice(NPCToons.HQnpcFriends.keys())
|
||||
self.bossMaxDamage = ToontownGlobals.SellbotBossMaxDamage
|
||||
self.recoverRate = 0
|
||||
self.recoverStartTime = 0
|
||||
|
|
|
@ -45,6 +45,13 @@ class DistributedSuitAI(DistributedSuitBaseAI.DistributedSuitBaseAI):
|
|||
self.buildingDestinationIsCogdo = False
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
del self.bldgTrack
|
||||
del self.branchId
|
||||
del self.buildingDestination
|
||||
del self.buildingDestinationIsCogdo
|
||||
DistributedSuitBaseAI.DistributedSuitBaseAI.delete(self)
|
||||
|
||||
def stopTasks(self):
|
||||
taskMgr.remove(self.taskName('flyAwayNow'))
|
||||
taskMgr.remove(self.taskName('danceNowFlyAwayLater'))
|
||||
|
|
|
@ -31,6 +31,7 @@ class DistributedSuitBaseAI(DistributedAvatarAI.DistributedAvatarAI, SuitBase.Su
|
|||
self.sp = None
|
||||
del self.dna
|
||||
DistributedAvatarAI.DistributedAvatarAI.delete(self)
|
||||
SuitBase.SuitBase.delete(self)
|
||||
return
|
||||
|
||||
def requestRemoval(self):
|
||||
|
|
|
@ -610,6 +610,7 @@ class DistributedSuitPlannerAI(DistributedObjectAI.DistributedObjectAI, SuitPlan
|
|||
def delete(self):
|
||||
self.cleanup()
|
||||
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||
SuitPlannerBase.SuitPlannerBase.delete(self)
|
||||
|
||||
def initBuildingsAndPoints(self):
|
||||
if not self.buildingMgr:
|
||||
|
|
|
@ -10,7 +10,8 @@ class FakeBattleManager:
|
|||
|
||||
def destroy(self, battle):
|
||||
if battle.suitsKilledThisBattle:
|
||||
simbase.air.tutorialManager.avId2fsm[self.avId].demand('HQ')
|
||||
if self.avId in simbase.air.tutorialManager.avId2fsm.keys():
|
||||
simbase.air.tutorialManager.avId2fsm[self.avId].demand('HQ')
|
||||
battle.requestDelete()
|
||||
|
||||
class DistributedTutorialSuitAI(DistributedSuitBaseAI):
|
||||
|
|
|
@ -22,10 +22,20 @@ class SuitBase:
|
|||
self.maxHP = 10
|
||||
self.currHP = 10
|
||||
self.isSkelecog = 0
|
||||
self.legList = None
|
||||
self.path = None
|
||||
self.suitGraph = None
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
pass
|
||||
if self.legList is not None:
|
||||
del self.legList
|
||||
# I have no idea if this will fix anything... but it looks like it isn't
|
||||
# deleted, so w/e.
|
||||
if self.path is not None:
|
||||
del self.path
|
||||
if self.suitGraph is not None:
|
||||
del self.suitGraph
|
||||
|
||||
def getStyleName(self):
|
||||
if hasattr(self, 'dna') and self.dna:
|
||||
|
|
|
@ -819,6 +819,8 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute
|
|||
self.stopSmooth()
|
||||
tunnelOrigin = render.attachNewNode('tunnelOrigin')
|
||||
tunnelOrigin.setPosHpr(x, y, z, h, 0, 0)
|
||||
if self.tunnelTrack:
|
||||
self.tunnelTrack.finish()
|
||||
self.tunnelTrack = Sequence(self.getTunnelInToonTrack(endX, tunnelOrigin), Func(tunnelOrigin.removeNode), Func(self.startSmooth))
|
||||
tOffset = globalClock.getFrameTime() - (startTime + self.smoother.getDelay())
|
||||
if tOffset < 0.0:
|
||||
|
@ -868,6 +870,8 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute
|
|||
def handleTunnelOut(self, startTime, startX, startY, x, y, z, h):
|
||||
tunnelOrigin = render.attachNewNode('tunnelOrigin')
|
||||
tunnelOrigin.setPosHpr(x, y, z, h, 0, 0)
|
||||
if self.tunnelTrack:
|
||||
self.tunnelTrack.finish()
|
||||
self.tunnelTrack = Sequence(Func(self.stopSmooth), self.getTunnelOutToonTrack(startX, startY, tunnelOrigin), Func(self.detachNode), Func(tunnelOrigin.removeNode))
|
||||
tOffset = globalClock.getFrameTime() - (startTime + self.smoother.getDelay())
|
||||
if tOffset < 0.0:
|
||||
|
|
|
@ -5044,18 +5044,100 @@ def exp(track, amt):
|
|||
av.b_setExperience(av.experience.makeNetString())
|
||||
return "Set %s exp to %d successfully." % (track, amt)
|
||||
|
||||
@magicWord(category=CATEGORY_CHARACTERSTATS)
|
||||
def disguise():
|
||||
""" Set disguise type and level. CURRENTLY MAX TOONS SUITS!!!"""
|
||||
@magicWord(category=CATEGORY_CHARACTERSTATS, types=[str, str, int])
|
||||
def disguise(corp, type, level=0):
|
||||
""" Set disguise type and level. """
|
||||
# Idk if this is defined anywhere, but laziness got the best of me.
|
||||
corps = ['bossbot', 'lawbot', 'cashbot', 'sellbot']
|
||||
if corp not in corps:
|
||||
return "Invalid cog corp. specified."
|
||||
corpIndex = corps.index(corp)
|
||||
toon = spellbook.getTarget()
|
||||
toon.b_setCogParts([
|
||||
0, # Bossbot
|
||||
0, # Lawbot
|
||||
0, # Cashbot
|
||||
CogDisguiseGlobals.PartsPerSuitBitmasks[3] # Sellbot
|
||||
])
|
||||
toon.b_setCogLevels([0, 0, 0, ToontownGlobals.MaxCogSuitLevel])
|
||||
toon.b_setCogTypes([0, 0, 0, SuitDNA.suitsPerDept-1])
|
||||
|
||||
if type == "nosuit":
|
||||
# They want to reset their suit entirely.
|
||||
parts = toon.getCogParts()
|
||||
parts[corpIndex] = 0
|
||||
toon.b_setCogParts(parts)
|
||||
types = toon.getCogTypes()
|
||||
types[corpIndex] = 0
|
||||
toon.b_setCogTypes(types)
|
||||
levels = toon.getCogLevels()
|
||||
levels[corpIndex] = 0
|
||||
toon.b_setCogLevels(levels)
|
||||
merits = toon.getCogMerits()
|
||||
merits[corpIndex] = 0
|
||||
toon.b_setCogMerits(merits)
|
||||
return "Reset %s disguise and removed all earned parts." % corp.capitalize()
|
||||
|
||||
if level == 0:
|
||||
return "You must specify a level!"
|
||||
|
||||
# Get the cog type from the specified short-hand value.
|
||||
types = SuitDNA.suitHeadTypes[8*corpIndex:(8*corpIndex)+8]
|
||||
if type not in types:
|
||||
return "Invalid cog type specified. Note that this uses the short-hand, such as 'rb' or 'tbc'."
|
||||
typeIndex = types.index(type)
|
||||
|
||||
# Make sure they gave a level that is in range.
|
||||
if typeIndex == 7:
|
||||
# The final suit can go up to Level 50.
|
||||
levelRange = range(8, 51) # Last digit is exclusive.
|
||||
else:
|
||||
levelRange = range((typeIndex+1), (typeIndex+6))
|
||||
if level not in levelRange:
|
||||
return "Invalid level specified for %s disguise %s." % (corp.capitalize(), SuitBattleGlobals.SuitAttributes[type]['name'])
|
||||
|
||||
# Reset their merits to 0.
|
||||
merits = toon.getCogMerits()
|
||||
merits[corpIndex] = 0
|
||||
toon.b_setCogMerits(merits)
|
||||
|
||||
# Ensure they have all the parts.
|
||||
# TODO: Allow them to set the parts they have. This will probably be another MW: ~parts leftleg 1
|
||||
parts = toon.getCogParts()
|
||||
parts[corpIndex] = CogDisguiseGlobals.PartsPerSuitBitmasks[corpIndex]
|
||||
toon.b_setCogParts(parts)
|
||||
|
||||
# Find out if they need laff boosts or laff points removed.
|
||||
for levelBoost in [14, 19, 29, 39, 49]:
|
||||
if level <= levelBoost and not levelBoost > toon.getCogLevels()[corpIndex]:
|
||||
if toon.getMaxHp() <= 15:
|
||||
continue
|
||||
toon.b_setMaxHp(toon.getMaxHp()-1)
|
||||
elif level > levelBoost and not levelBoost <= toon.getCogLevels()[corpIndex]:
|
||||
if toon.getMaxHp() >= 137:
|
||||
continue
|
||||
toon.b_setMaxHp(toon.getMaxHp()+1)
|
||||
# Lets be nice and give them a toonup or make them suffer.
|
||||
if toon.getHp() > toon.getMaxHp():
|
||||
toon.takeDamage(toon.getHp() - toon.getMaxHp())
|
||||
else:
|
||||
toon.toonUp(toon.getMaxHp() - toon.getHp())
|
||||
|
||||
# Set their type and level that they specified.
|
||||
types = toon.getCogTypes()
|
||||
types[corpIndex] = typeIndex
|
||||
toon.b_setCogTypes(types)
|
||||
levels = toon.getCogLevels()
|
||||
levels[corpIndex] = level-1 # -1 because it starts at 0
|
||||
toon.b_setCogLevels(levels)
|
||||
|
||||
return "Set %s disguise to %s Level %d." % (corp.capitalize(), SuitBattleGlobals.SuitAttributes[type]['name'], level)
|
||||
|
||||
@magicWord(category=CATEGORY_OVERRIDE, types=[str, int])
|
||||
def merits(corp, amount):
|
||||
""" Set the target's merits to the value specified. """
|
||||
corps = ['bossbot', 'lawbot', 'cashbot', 'sellbot']
|
||||
if corp not in corps:
|
||||
return "Invalid cog corp. specified."
|
||||
corpIndex = corps.index(corp)
|
||||
toon = spellbook.getTarget()
|
||||
|
||||
# Correct me if I'm wrong, but I don't think we need a sanity check for the amount.
|
||||
merits = toon.getCogMerits()
|
||||
merits[corpIndex] = amount
|
||||
toon.b_setCogMerits(merits)
|
||||
|
||||
@magicWord(category=CATEGORY_OVERRIDE)
|
||||
def fanfare():
|
||||
|
|
|
@ -69,7 +69,7 @@ class GroupPanel(DirectObject.DirectObject):
|
|||
frameZPos = 0.0278943
|
||||
quitButtonZPos = -0.30366
|
||||
guiButtons = loader.loadModel('phase_9/models/gui/tt_m_gui_brd_status')
|
||||
self.frame = DirectFrame(relief=None, image=bgImage, image_scale=(0.5, 1, 0.5), image_pos=(0, 0, bgImageZPos), textMayChange=1, pos=(-1.044, 0, frameZPos))
|
||||
self.frame = DirectFrame(relief=None, parent=base.a2dLeftCenter, image=bgImage, image_scale=(0.5, 1, 0.5), image_pos=(0, 0, bgImageZPos), textMayChange=1, pos=(0.32, 0, frameZPos))
|
||||
self.frameBounds = self.frame.getBounds()
|
||||
leaveButtonGui = loader.loadModel('phase_3.5/models/gui/tt_m_gui_brd_leaveBtn')
|
||||
leaveImageList = (leaveButtonGui.find('**/tt_t_gui_brd_leaveUp'),
|
||||
|
@ -91,8 +91,9 @@ class GroupPanel(DirectObject.DirectObject):
|
|||
arrowGui = loader.loadModel('phase_9/models/gui/tt_m_gui_brd_arrow')
|
||||
hideImageList = (arrowGui.find('**/tt_t_gui_brd_arrow_up'), arrowGui.find('**/tt_t_gui_brd_arrow_down'), arrowGui.find('**/tt_t_gui_brd_arrow_hover'))
|
||||
showImageList = (arrowGui.find('**/tt_t_gui_brd_arrow_up'), arrowGui.find('**/tt_t_gui_brd_arrow_down'), arrowGui.find('**/tt_t_gui_brd_arrow_hover'))
|
||||
self.hideButton = DirectButton(relief=None, text_pos=(0, 0.15), text_scale=0.06, text_align=TextNode.ALeft, text_fg=Vec4(0, 0, 0, 1), text_shadow=Vec4(1, 1, 1, 1), image=hideImageList, image_scale=(-0.35, 1, 0.5), pos=(-1.3081, 0, 0.03), scale=1.05, command=self.hide)
|
||||
self.showButton = DirectButton(relief=None, text=('', TTLocalizer.BoardingGroupShow, TTLocalizer.BoardingGroupShow), text_pos=(0.03, 0), text_scale=0.06, text_align=TextNode.ALeft, text_fg=Vec4(1, 1, 1, 1), text_shadow=Vec4(0, 0, 0, 1), image=showImageList, image_scale=(0.35, 1, 0.5), pos=(-1.3081, 0, 0.03), scale=1.05, command=self.show)
|
||||
|
||||
self.hideButton = DirectButton(relief=None, parent=base.a2dLeftCenter, text_pos=(0, 0.15), text_scale=0.06, text_align=TextNode.ALeft, text_fg=Vec4(0, 0, 0, 1), text_shadow=Vec4(1, 1, 1, 1), image=hideImageList, image_scale=(-0.35, 1, 0.5), pos=(0.025, 0, 0.03), scale=1.05, command=self.hide)
|
||||
self.showButton = DirectButton(relief=None, parent=base.a2dLeftCenter, text=('', TTLocalizer.BoardingGroupShow, TTLocalizer.BoardingGroupShow), text_pos=(0.03, 0), text_scale=0.06, text_align=TextNode.ALeft, text_fg=Vec4(1, 1, 1, 1), text_shadow=Vec4(0, 0, 0, 1), image=showImageList, image_scale=(0.35, 1, 0.5), pos=(0.025, 0, 0.03), scale=1.05, command=self.show)
|
||||
self.showButton.hide()
|
||||
self.frame.show()
|
||||
self.__makeAvatarNameScrolledList()
|
||||
|
|
|
@ -11701,171 +11701,55 @@ def getBuildingArticle(zoneId):
|
|||
def getBuildingTitle(zoneId):
|
||||
return TTLocalizer.zone2TitleDict.get(zoneId, 'Toon Building')[0]
|
||||
|
||||
# Regular NPC SOS Toons (The good ones)
|
||||
HQnpcFriends = {
|
||||
2001: (ToontownBattleGlobals.HEAL_TRACK, 5, ToontownGlobals.MaxHpLimit, 5),
|
||||
2132: (ToontownBattleGlobals.HEAL_TRACK, 5, 70, 4),
|
||||
2121: (ToontownBattleGlobals.HEAL_TRACK, 5, 45, 3),
|
||||
2011: (ToontownBattleGlobals.TRAP_TRACK, 4, 180, 5),
|
||||
3007: (ToontownBattleGlobals.TRAP_TRACK, 4, 70, 4),
|
||||
1001: (ToontownBattleGlobals.TRAP_TRACK, 4, 50, 3),
|
||||
3112: (ToontownBattleGlobals.LURE_TRACK, 5, 0, 5),
|
||||
1323: (ToontownBattleGlobals.LURE_TRACK, 5, 0, 3),
|
||||
2308: (ToontownBattleGlobals.LURE_TRACK, 5, 0, 3),
|
||||
4119: (ToontownBattleGlobals.SOUND_TRACK, 5, 80, 5),
|
||||
4219: (ToontownBattleGlobals.SOUND_TRACK, 5, 50, 4),
|
||||
4115: (ToontownBattleGlobals.SOUND_TRACK, 5, 40, 3),
|
||||
1116: (ToontownBattleGlobals.DROP_TRACK, 5, 170, 5),
|
||||
2311: (ToontownBattleGlobals.DROP_TRACK, 5, 100, 4),
|
||||
4140: (ToontownBattleGlobals.DROP_TRACK, 5, 60, 3),
|
||||
3137: (ToontownBattleGlobals.NPC_COGS_MISS, 0, 0, 4),
|
||||
4327: (ToontownBattleGlobals.NPC_COGS_MISS, 0, 0, 4),
|
||||
4230: (ToontownBattleGlobals.NPC_COGS_MISS, 0, 0, 4),
|
||||
3135: (ToontownBattleGlobals.NPC_TOONS_HIT, 0, 0, 4),
|
||||
2208: (ToontownBattleGlobals.NPC_TOONS_HIT, 0, 0, 4),
|
||||
5124: (ToontownBattleGlobals.NPC_TOONS_HIT, 0, 0, 4),
|
||||
2003: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, -1, 0, 5),
|
||||
2126: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.HEAL_TRACK, 0, 3),
|
||||
4007: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.TRAP_TRACK, 0, 3),
|
||||
1315: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.LURE_TRACK, 0, 3),
|
||||
5207: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.SQUIRT_TRACK, 0, 3),
|
||||
3129: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.THROW_TRACK, 0, 3),
|
||||
4125: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.SOUND_TRACK, 0, 3),
|
||||
1329: (ToontownBattleGlobals.NPC_RESTOCK_GAGS, ToontownBattleGlobals.DROP_TRACK, 0, 3)
|
||||
}
|
||||
|
||||
# Field Office NPC Toons (The rubbish ones)
|
||||
FOnpcFriends = {
|
||||
9310: (ToontownBattleGlobals.LURE_TRACK, 1, 0, 0),
|
||||
9311: (ToontownBattleGlobals.LURE_TRACK, 1, 0, 1),
|
||||
9312: (ToontownBattleGlobals.LURE_TRACK, 3, 0, 2),
|
||||
9307: (ToontownBattleGlobals.SOUND_TRACK, 1, 10, 0),
|
||||
9308: (ToontownBattleGlobals.SOUND_TRACK, 3, 20, 1),
|
||||
9309: (ToontownBattleGlobals.SOUND_TRACK, 4, 30, 2),
|
||||
9304: (ToontownBattleGlobals.DROP_TRACK, 1, 20, 0),
|
||||
9305: (ToontownBattleGlobals.DROP_TRACK, 2, 35, 1),
|
||||
9306: (ToontownBattleGlobals.DROP_TRACK, 3, 50, 2),
|
||||
9301: (ToontownBattleGlobals.HEAL_TRACK, 3, 10, 0),
|
||||
9302: (ToontownBattleGlobals.HEAL_TRACK, 3, 20, 1),
|
||||
9303: (ToontownBattleGlobals.HEAL_TRACK, 3, 30, 2)
|
||||
}
|
||||
|
||||
HQnpcFriends = {2001: (ToontownBattleGlobals.HEAL_TRACK,
|
||||
5,
|
||||
ToontownGlobals.MaxHpLimit,
|
||||
5),
|
||||
2132: (ToontownBattleGlobals.HEAL_TRACK,
|
||||
5,
|
||||
70,
|
||||
4),
|
||||
2121: (ToontownBattleGlobals.HEAL_TRACK,
|
||||
5,
|
||||
45,
|
||||
3),
|
||||
2011: (ToontownBattleGlobals.TRAP_TRACK,
|
||||
4,
|
||||
180,
|
||||
5),
|
||||
3007: (ToontownBattleGlobals.TRAP_TRACK,
|
||||
4,
|
||||
70,
|
||||
4),
|
||||
1001: (ToontownBattleGlobals.TRAP_TRACK,
|
||||
4,
|
||||
50,
|
||||
3),
|
||||
3112: (ToontownBattleGlobals.LURE_TRACK,
|
||||
5,
|
||||
0,
|
||||
5),
|
||||
1323: (ToontownBattleGlobals.LURE_TRACK,
|
||||
5,
|
||||
0,
|
||||
3),
|
||||
2308: (ToontownBattleGlobals.LURE_TRACK,
|
||||
5,
|
||||
0,
|
||||
3),
|
||||
4119: (ToontownBattleGlobals.SOUND_TRACK,
|
||||
5,
|
||||
80,
|
||||
5),
|
||||
4219: (ToontownBattleGlobals.SOUND_TRACK,
|
||||
5,
|
||||
50,
|
||||
4),
|
||||
4115: (ToontownBattleGlobals.SOUND_TRACK,
|
||||
5,
|
||||
40,
|
||||
3),
|
||||
1116: (ToontownBattleGlobals.DROP_TRACK,
|
||||
5,
|
||||
170,
|
||||
5),
|
||||
2311: (ToontownBattleGlobals.DROP_TRACK,
|
||||
5,
|
||||
100,
|
||||
4),
|
||||
4140: (ToontownBattleGlobals.DROP_TRACK,
|
||||
5,
|
||||
60,
|
||||
3),
|
||||
3137: (ToontownBattleGlobals.NPC_COGS_MISS,
|
||||
0,
|
||||
0,
|
||||
4),
|
||||
4327: (ToontownBattleGlobals.NPC_COGS_MISS,
|
||||
0,
|
||||
0,
|
||||
4),
|
||||
4230: (ToontownBattleGlobals.NPC_COGS_MISS,
|
||||
0,
|
||||
0,
|
||||
4),
|
||||
3135: (ToontownBattleGlobals.NPC_TOONS_HIT,
|
||||
0,
|
||||
0,
|
||||
4),
|
||||
2208: (ToontownBattleGlobals.NPC_TOONS_HIT,
|
||||
0,
|
||||
0,
|
||||
4),
|
||||
5124: (ToontownBattleGlobals.NPC_TOONS_HIT,
|
||||
0,
|
||||
0,
|
||||
4),
|
||||
2003: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
-1,
|
||||
0,
|
||||
5),
|
||||
2126: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.HEAL_TRACK,
|
||||
0,
|
||||
3),
|
||||
4007: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.TRAP_TRACK,
|
||||
0,
|
||||
3),
|
||||
1315: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.LURE_TRACK,
|
||||
0,
|
||||
3),
|
||||
5207: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.SQUIRT_TRACK,
|
||||
0,
|
||||
3),
|
||||
3129: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.THROW_TRACK,
|
||||
0,
|
||||
3),
|
||||
4125: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.SOUND_TRACK,
|
||||
0,
|
||||
3),
|
||||
1329: (ToontownBattleGlobals.NPC_RESTOCK_GAGS,
|
||||
ToontownBattleGlobals.DROP_TRACK,
|
||||
0,
|
||||
3)}
|
||||
FOnpcFriends = {9310: (ToontownBattleGlobals.LURE_TRACK,
|
||||
1,
|
||||
0,
|
||||
0),
|
||||
9311: (ToontownBattleGlobals.LURE_TRACK,
|
||||
1,
|
||||
0,
|
||||
1),
|
||||
9312: (ToontownBattleGlobals.LURE_TRACK,
|
||||
3,
|
||||
0,
|
||||
2),
|
||||
9307: (ToontownBattleGlobals.SOUND_TRACK,
|
||||
1,
|
||||
10,
|
||||
0),
|
||||
9308: (ToontownBattleGlobals.SOUND_TRACK,
|
||||
3,
|
||||
20,
|
||||
1),
|
||||
9309: (ToontownBattleGlobals.SOUND_TRACK,
|
||||
4,
|
||||
30,
|
||||
2),
|
||||
9304: (ToontownBattleGlobals.DROP_TRACK,
|
||||
1,
|
||||
20,
|
||||
0),
|
||||
9305: (ToontownBattleGlobals.DROP_TRACK,
|
||||
2,
|
||||
35,
|
||||
1),
|
||||
9306: (ToontownBattleGlobals.DROP_TRACK,
|
||||
3,
|
||||
50,
|
||||
2),
|
||||
9301: (ToontownBattleGlobals.HEAL_TRACK,
|
||||
3,
|
||||
10,
|
||||
0),
|
||||
9302: (ToontownBattleGlobals.HEAL_TRACK,
|
||||
3,
|
||||
20,
|
||||
1),
|
||||
9303: (ToontownBattleGlobals.HEAL_TRACK,
|
||||
3,
|
||||
30,
|
||||
2)}
|
||||
npcFriends = dict(HQnpcFriends)
|
||||
npcFriends.update(FOnpcFriends)
|
||||
|
||||
|
|
|
@ -489,6 +489,7 @@ class ToonAvatarPanel(AvatarPanelBase.AvatarPanelBase):
|
|||
if not base.cr.playGame.getPlace().getState() == 'elevator':
|
||||
self.confirmKickOutDialog = TTDialog.TTDialog(style=TTDialog.YesNo, text=TTLocalizer.BoardingKickOutConfirm % self.avName, command=self.__confirmKickOutCallback)
|
||||
self.confirmKickOutDialog.show()
|
||||
localAvatar.disableAvatarControls()
|
||||
|
||||
def __confirmKickOutCallback(self, value):
|
||||
if self.confirmKickOutDialog:
|
||||
|
@ -498,6 +499,7 @@ class ToonAvatarPanel(AvatarPanelBase.AvatarPanelBase):
|
|||
if self.groupButton:
|
||||
self.groupButton['state'] = DGG.DISABLED
|
||||
localAvatar.boardingParty.requestKick(self.avId)
|
||||
localAvatar.enableAvatarControls()
|
||||
return
|
||||
|
||||
def __checkGroupStatus(self):
|
||||
|
|
|
@ -469,7 +469,9 @@ class ToonHead(Actor.Actor):
|
|||
else:
|
||||
searchRoot = self.find('**/' + str(lodName))
|
||||
pumpkin = searchRoot.find('**/__Actor_head/pumpkin*')
|
||||
pumpkin.stash()
|
||||
# TODO this is a hackfix
|
||||
if not pumpkin.isEmpty():
|
||||
pumpkin.stash()
|
||||
return
|
||||
|
||||
def enablePumpkins(self, enable):
|
||||
|
@ -762,8 +764,16 @@ class ToonHead(Actor.Actor):
|
|||
else:
|
||||
openString = 'open-short'
|
||||
closedString = 'closed-short'
|
||||
self.__eyelashOpen = model.find('**/' + openString).copyTo(head)
|
||||
self.__eyelashClosed = model.find('**/' + closedString).copyTo(head)
|
||||
eyeOpen = model.find('**/' + openString)
|
||||
eyeClosed = model.find('**/' + closedString)
|
||||
if style.getAnimal() == 'dog':
|
||||
# Fix eyelash positioning on dog toons
|
||||
eyeOpen.setPos(0, -0.025, 0.025)
|
||||
eyeClosed.setPos(0, -0.025, 0.025)
|
||||
self.__eyelashOpen = eyeOpen.copyTo(head)
|
||||
self.__eyelashClosed = eyeClosed.copyTo(head)
|
||||
eyeOpen.removeNode()
|
||||
eyeClosed.removeNode()
|
||||
model.removeNode()
|
||||
return
|
||||
|
||||
|
|
|
@ -250,26 +250,23 @@ class ToonTeleportPanel(DirectFrame):
|
|||
hoodsVisited = base.localAvatar.hoodsVisited
|
||||
canonicalHoodId = ZoneUtil.getCanonicalZoneId(hoodId)
|
||||
if hoodId == ToontownGlobals.MyEstate:
|
||||
teleportNotify.debug('enterTeleport: estate')
|
||||
if shardId == base.localAvatar.defaultShard:
|
||||
shardId = None
|
||||
|
||||
place = base.cr.playGame.getPlace()
|
||||
place.requestTeleport(hoodId, zoneId, shardId, self.avId)
|
||||
unloadTeleportPanel()
|
||||
elif canonicalHoodId not in hoodsVisited + ToontownGlobals.HoodsAlwaysVisited:
|
||||
teleportNotify.debug('enterTeleport: unknownHood')
|
||||
self.fsm.request('unknownHood', [hoodId])
|
||||
elif canonicalHoodId not in base.cr.hoodMgr.getAvailableZones():
|
||||
print 'hoodId %d not ready' % hoodId
|
||||
self.fsm.request('unavailableHood', [hoodId])
|
||||
else:
|
||||
if shardId == base.localAvatar.defaultShard:
|
||||
shardId = None
|
||||
teleportNotify.debug('enterTeleport: requesting teleport')
|
||||
place = base.cr.playGame.getPlace()
|
||||
place.requestTeleport(hoodId, zoneId, shardId, self.avId)
|
||||
unloadTeleportPanel()
|
||||
return
|
||||
elif shardId == base.localAvatar.defaultShard:
|
||||
shardId = None
|
||||
|
||||
place = base.cr.playGame.getPlace()
|
||||
place.requestTeleport(hoodId, zoneId, shardId, self.avId)
|
||||
unloadTeleportPanel()
|
||||
|
||||
def exitTeleport(self):
|
||||
pass
|
||||
|
|
|
@ -732,7 +732,7 @@ QuestDialogDict = {160: {GREETING: '',
|
|||
LEAVING: '',
|
||||
GREETING: '',
|
||||
INCOMPLETE_PROGRESS: 'Have you got any grease? I need to pay the lease!'},
|
||||
1084: {QUEST: "Nope, that didn't help. This is really not funny.\x07I put the grease right there on the money!\x07That gives me an idea: before I forget it...\x07Defeat some Cashbots; bring back water to wet it.",
|
||||
1084: {QUEST: "Nope, that didn't help. This is really not funny.\x07I put the grease right there on the money!\x07That gives me an idea! Now before I forget it...\x07Defeat some Cashbots; bring back water to wet it.",
|
||||
LEAVING: '',
|
||||
GREETING: '',
|
||||
COMPLETE: "Hooray! I'm free of this quick drying glue.\x07As a reward, I have a gift for you.\x07You can laugh a little longer while battling, and then...\x07Yipes! I'm already stuck here again!",
|
||||
|
@ -746,9 +746,9 @@ QuestDialogDict = {160: {GREETING: '',
|
|||
COMPLETE: "He\'s done already?\x07Good work _avName_, we'll take this one from here.",
|
||||
LEAVING: ''},
|
||||
1090: {QUEST: 'Hey, _toNpcName_ has been looking for you.\x07They\'ve heard of your excellent Gag work around town and want to give you a bit of useful information._where_'},
|
||||
1091: {QUEST: 'Oh, hello! I bet you\'re here for the information Toon HQ told you about.\x07You see, I hear that Loony Labs is working on a sort of Cog Radar.\x07It will let you see if certain Cogs are on the street to keep better track of them.\x07That Cog Gallery in your Shticker Book is the key.\x07By defeating enough of them, you can tune into their signals and actually track where they are.\x07Based on what I\'ve heard about you, I bet it will be a huge help!\x07Keep defeating Cogs, and good luck getting that radar.',
|
||||
1091: {QUEST: 'Oh, hello! I bet you\'re here for the information Toon HQ told you about.\x07You see, I hear that Loony Labs is working on a sort of Cog Radar.\x07It will let you see if certain Cogs are on the street to keep better track of them.\x07That Cog Gallery in your Shticker Book is the key.\x07By defeating enough of them, you can tune into their signals and actually track where they are.\x07Based on what I\'ve heard about you, I bet it will be a huge help!\x07In the meantime, can you defeat a few of the bigger Cogs on the streets for me? It will certainly help with your radar.',
|
||||
COMPLETE: 'The Cog Radar, eh?\x07It\'s experimental, but definitely useful.\x07Here, you could probably use this...',
|
||||
LEAVING: ''},
|
||||
LEAVING: QuestsDefaultLeaving},
|
||||
401: {GREETING: '',
|
||||
QUEST: 'Now you get to choose the next gag track you want to learn.\x07Take your time deciding, and come back here when you are ready to choose.',
|
||||
INCOMPLETE_PROGRESS: 'Think about your decision before choosing.',
|
||||
|
@ -890,7 +890,7 @@ QuestDialogDict = {160: {GREETING: '',
|
|||
3256: {QUEST: '_toNpcName_ is investigating Sellbot Headquarters.\x07Go see if you can help._where_'},
|
||||
3257: {QUEST: '_toNpcName_ is investigating Sellbot Headquarters.\x07Go see if you can help._where_'},
|
||||
3258: {QUEST: 'There is much confusion about what the Cogs are up to in their new headquarters.\x07I need you to bring back some information directly from them.\x07If we can get four internal memos from Sellbots inside their HQ, that will clear things up.\x07Bring back your first memo to me so we can learn more.'},
|
||||
3259: {QUEST: 'Great! This let\'s see what the memo says....\x07"Attn Sellbots:"\x07"I\'ll be in my office at the top of Sellbot Towers promoting Cogs to higher levels."\x07"When you earn enough merits enter the elevator in the lobby to see me."\x07"Break time\'s over - back to work!"\x07"Signed, Sellbot V.P."\x07Aha.... Flippy will want to see this. I\'ll send it to him right now.\x07Please go get your second memo and bring it back.'},
|
||||
3259: {QUEST: 'Great! Let\'s see what the memo says....\x07"Attn Sellbots:"\x07"I\'ll be in my office at the top of Sellbot Towers promoting Cogs to higher levels."\x07"When you earn enough merits enter the elevator in the lobby to see me."\x07"Break time\'s over - back to work!"\x07"Signed, Sellbot V.P."\x07Aha.... Flippy will want to see this. I\'ll send it to him right now.\x07Please go get your second memo and bring it back.'},
|
||||
3260: {QUEST: 'Oh good, you\'re back. Let\'s see what you found....\x07"Attn Sellbots:"\x07"Sellbot Towers has installed a new security system to keep all Toons out."\x07"Toons caught in Sellbot Towers will be detained for questioning."\x07"Please meet in the lobby for appetizers to discuss."\x07"Signed, Mingler"\x07Very interesting... I\'ll pass on this information immediately.\x07Please bring a third memo back.'},
|
||||
3261: {QUEST: 'Excellent job _avName_! What does the memo say?\x07"Attn Sellbots:"\x07"Toons have somehow found a way to infiltrate Sellbot Towers."\x07"I\'ll call you tonight during dinner to give you the details."\x07"Signed, Telemarketer"\x07Hmmm... I wonder how Toons are breaking in....\x07Please bring back one more memo and I think we\'ll have enough info for now.',
|
||||
COMPLETE: 'I knew you could do it! Ok, the memo says....\x07"Attn Sellbots:"\x07"I was having lunch with Mr. Hollywood yesterday."\x07"He reports that the V.P. is very busy these days."\x07"He will only be taking appointments from Cogs that deserve a promotion."\x07"Forgot to mention, Gladhander is golfing with me on Sunday."\x07"Signed, Name Dropper"\x07Well... _avName_, this has been very helpful.\x07Here is your reward.'},
|
||||
|
|
|
@ -318,13 +318,37 @@ class ToonBase(OTPBase.OTPBase):
|
|||
self.marginManager = MarginManager()
|
||||
self.margins = self.aspect2d.attachNewNode(self.marginManager, DirectGuiGlobals.MIDGROUND_SORT_INDEX + 1)
|
||||
mm = self.marginManager
|
||||
self.leftCells = [mm.addGridCell(0, 1, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop), mm.addGridCell(0, 2, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop), mm.addGridCell(0, 3, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop)]
|
||||
self.bottomCells = [mm.addGridCell(0.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
mm.addGridCell(1.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
mm.addGridCell(2.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
mm.addGridCell(3.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
mm.addGridCell(4.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop)]
|
||||
self.rightCells = [mm.addGridCell(5, 2, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop), mm.addGridCell(5, 1, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop)]
|
||||
# TODO: Dynamicaly add more and reposition cells
|
||||
padding = 0.0225
|
||||
self.leftCells = [
|
||||
mm.addGridCell(0.2 + padding, -0.45, base.a2dTopLeft),
|
||||
mm.addGridCell(0.2 + padding, -0.9, base.a2dTopLeft),
|
||||
mm.addGridCell(0.2 + padding, -1.35, base.a2dTopLeft)
|
||||
|
||||
# mm.addGridCell(0, 1, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(0, 2, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(0, 3, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop)
|
||||
]
|
||||
self.bottomCells = [
|
||||
mm.addGridCell(-0.87, 0.2 + padding, base.a2dBottomCenter),
|
||||
mm.addGridCell(-0.43, 0.2 + padding, base.a2dBottomCenter),
|
||||
mm.addGridCell(0.01, 0.2 + padding, base.a2dBottomCenter),
|
||||
mm.addGridCell(0.45, 0.2 + padding, base.a2dBottomCenter),
|
||||
mm.addGridCell(0.89, 0.2 + padding, base.a2dBottomCenter)
|
||||
|
||||
# mm.addGridCell(0.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(1.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(2.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(3.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(4.5, 0, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop)
|
||||
]
|
||||
self.rightCells = [
|
||||
mm.addGridCell(-0.2 - padding, -0.9, base.a2dTopRight),
|
||||
mm.addGridCell(-0.2 - padding, -1.35, base.a2dTopRight)
|
||||
|
||||
# mm.addGridCell(5, 1.8, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop),
|
||||
# mm.addGridCell(5, 0.9, base.a2dLeft, base.a2dRight, base.a2dBottom, base.a2dTop)
|
||||
]
|
||||
|
||||
def setCellsAvailable(self, cell_list, available):
|
||||
for cell in cell_list:
|
||||
|
|
|
@ -1363,9 +1363,9 @@ LawbotBossBonusDuration = 20
|
|||
LawbotBossBonusToonup = 10
|
||||
LawbotBossBonusWeightMultiplier = 2
|
||||
LawbotBossChanceToDoAreaAttack = 11
|
||||
LOW_POP = 30 # This is 'Ideal' in the book (green)
|
||||
MID_POP = 70 # This is 'Full' in the book, but friends can still TP onto shard (soft red)
|
||||
HIGH_POP = 85 # Still 'Full' in book, but nobody joins this shard for any reason (hard red)
|
||||
LOW_POP = 50 # This is 'Ideal' in the book (green)
|
||||
MID_POP = 100 # This is 'Full' in the book, but friends can still TP onto shard (soft red)
|
||||
HIGH_POP = 120 # Still 'Full' in book, but nobody joins this shard for any reason (hard red)
|
||||
PinballCannonBumper = 0
|
||||
PinballCloudBumperLow = 1
|
||||
PinballCloudBumperMed = 2
|
||||
|
|
|
@ -170,7 +170,9 @@ class TutorialManagerAI(DistributedObjectAI):
|
|||
|
||||
def toonArrived(self):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
av = self.air.doId2do[avId]
|
||||
av = self.air.doId2do.get(avId)
|
||||
if not av:
|
||||
return
|
||||
if av.getTutorialAck():
|
||||
self.avId2fsm[avId].demand('CleanUp')
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='Attempted to request Toontorial when it would be impossible to do so')
|
||||
|
|
|
@ -4,6 +4,10 @@ from otp.distributed.PotentialAvatar import PotentialAvatar
|
|||
from otp.otpbase import OTPLocalizer, OTPGlobals
|
||||
from otp.margins.WhisperPopup import *
|
||||
from pandac.PandaModules import *
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
FIXED_KEY = "wedidntbuildttrinaday,thinkaboutwhatyouredoing"
|
||||
|
||||
class ClientServicesManager(DistributedObjectGlobal):
|
||||
notify = directNotify.newCategory('ClientServicesManager')
|
||||
|
@ -16,8 +20,12 @@ class ClientServicesManager(DistributedObjectGlobal):
|
|||
|
||||
cookie = self.cr.playToken or 'dev'
|
||||
|
||||
# Sign the login cookie
|
||||
key = base.config.GetString('csmud-secret', 'streetlamps') + base.config.GetString('server-version', 'no_version_set') + FIXED_KEY
|
||||
sig = hmac.new(key, cookie, hashlib.sha256).digest()
|
||||
|
||||
self.notify.debug('Sending login cookie: ' + cookie)
|
||||
self.sendUpdate('login', [cookie])
|
||||
self.sendUpdate('login', [cookie, sig])
|
||||
|
||||
def acceptLogin(self):
|
||||
messenger.send(self.doneEvent, [{'mode': 'success'}])
|
||||
|
|
|
@ -12,6 +12,7 @@ import time
|
|||
import hmac
|
||||
import hashlib
|
||||
import json
|
||||
from ClientServicesManager import FIXED_KEY
|
||||
|
||||
# --- ACCOUNT DATABASES ---
|
||||
class LocalAccountDB:
|
||||
|
@ -143,7 +144,7 @@ class LoginAccountFSM(OperationFSM):
|
|||
self.demand('RetrieveAccount')
|
||||
else:
|
||||
self.demand('CreateAccount')
|
||||
|
||||
|
||||
def __retryLookup(self):
|
||||
try:
|
||||
self.csm.air.mongodb.astron.objects.ensure_index('fields.ACCOUNT_ID')
|
||||
|
@ -151,7 +152,7 @@ class LoginAccountFSM(OperationFSM):
|
|||
except AutoReconnect:
|
||||
taskMgr.doMethodLater(simbase.config.GetInt('mongodb-retry-time', 2), self.__retryLookup, 'retryLookUp-%d' % self.databaseId, extraArgs=[])
|
||||
return
|
||||
|
||||
|
||||
if account:
|
||||
self.accountId = account['_id']
|
||||
self.demand('RetrieveAccount')
|
||||
|
@ -215,6 +216,27 @@ class LoginAccountFSM(OperationFSM):
|
|||
dg.addChannel(self.csm.GetAccountConnectionChannel(self.accountId))
|
||||
self.csm.air.send(dg)
|
||||
|
||||
# Subscribe to any "staff" channels that the account has access to.
|
||||
access = self.account.get('ADMIN_ACCESS', 0)
|
||||
if access >= 200:
|
||||
# Subscribe to the moderator channel.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||
dg.addChannel(OtpDoGlobals.OTP_MOD_CHANNEL)
|
||||
self.csm.air.send(dg)
|
||||
if access >= 400:
|
||||
# Subscribe to the administrator channel.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||
dg.addChannel(OtpDoGlobals.OTP_ADMIN_CHANNEL)
|
||||
self.csm.air.send(dg)
|
||||
if access >= 500:
|
||||
# Subscribe to the system administrator channel.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||
dg.addChannel(OtpDoGlobals.OTP_SYSADMIN_CHANNEL)
|
||||
self.csm.air.send(dg)
|
||||
|
||||
# Now set their sender channel to represent their account affiliation:
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_SET_CLIENT_ID)
|
||||
|
@ -820,16 +842,17 @@ class ClientServicesManagerUD(DistributedObjectGlobalUD):
|
|||
# Listen out for any accounts that disconnect.
|
||||
self.air.netMessenger.accept('accountDisconnected', self, self.__accountDisconnected)
|
||||
|
||||
# Attribute to test if doomsday is over...
|
||||
self.closed = False
|
||||
# This attribute determines if we want to disable logins.
|
||||
self.loginsEnabled = True
|
||||
# Listen out for any messages that tell us to disable logins.
|
||||
self.air.netMessenger.accept('enableLogins', self, self.setLoginEnabled)
|
||||
|
||||
def __accountDisconnected(self, accountId):
|
||||
def callback(dclass, fields):
|
||||
if dclass != self.air.dclassesByName['AccountUD']:
|
||||
return
|
||||
webId = fields.get('ACCOUNT_ID')
|
||||
if fields.get('BETA_KEY_QUEST') == 1:
|
||||
self.air.rpc.call('avatarExit', webAccId=webId)
|
||||
self.air.rpc.call('avatarExit', webAccId=webId)
|
||||
self.air.dbInterface.queryObject(self.air.dbId, accountId, callback)
|
||||
|
||||
def killConnection(self, connId, reason):
|
||||
|
@ -869,28 +892,36 @@ class ClientServicesManagerUD(DistributedObjectGlobalUD):
|
|||
self.account2fsm[sender] = fsmtype(self, sender)
|
||||
self.account2fsm[sender].request('Start', *args)
|
||||
|
||||
def setClosed(self, closed):
|
||||
self.notify.warning('AI %s has told us to start rejecting logins!' % str(self.air.getMsgSender()))
|
||||
self.closed = closed
|
||||
def setLoginEnabled(self, enable):
|
||||
if not enable:
|
||||
self.notify.warning('The CSMUD has been told to reject logins! All future logins will now be rejected.')
|
||||
self.loginsEnabled = enable
|
||||
|
||||
def login(self, cookie):
|
||||
def login(self, cookie, sig):
|
||||
self.notify.debug('Received login cookie %r from %d' % (cookie, self.air.getMsgSender()))
|
||||
|
||||
sender = self.air.getMsgSender()
|
||||
|
||||
if self.closed:
|
||||
# Doomsday is over... no more logging in until beta!
|
||||
if not self.loginsEnabled:
|
||||
# Logins are currently disabled... RIP!
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(sender, self.air.ourChannel, CLIENTAGENT_EJECT)
|
||||
dg.addUint16(156)
|
||||
dg.addString('Toontown Rewritten is now closed until Beta. Learn more and check out the updates on our website, toontownrewritten.com. Thanks for Alpha Testing with us!')
|
||||
dg.addUint16(200)
|
||||
dg.addString('Logins are currently disabled. Please try again later.')
|
||||
self.air.send(dg)
|
||||
|
||||
if sender>>32:
|
||||
# Oops, they have an account ID on their conneciton already!
|
||||
# Oops, they have an account ID on their connection already!
|
||||
self.killConnection(sender, 'Client is already logged in.')
|
||||
return
|
||||
|
||||
# Test the signature
|
||||
key = simbase.config.GetString('csmud-secret', 'streetlamps') + simbase.config.GetString('server-version', 'no_version_set') + FIXED_KEY
|
||||
computedSig = hmac.new(key, cookie, hashlib.sha256).digest()
|
||||
if sig != computedSig:
|
||||
self.killConnection(sender, 'The accounts database rejected your cookie')
|
||||
return
|
||||
|
||||
if sender in self.connection2fsm:
|
||||
self.killConnectionFSM(sender)
|
||||
return
|
||||
|
|
|
@ -30,6 +30,15 @@ class ToontownRPCHandler:
|
|||
self.air.ourChannel, [0])
|
||||
self.air.send(dg)
|
||||
|
||||
### UBERDOG MANAGEMENT ###
|
||||
def rpc_setEnableLogins(self, request, enable):
|
||||
"""
|
||||
Tells the ClientServicesManagerUD to enable/disable all logins.
|
||||
Also tells the CSMUD what "disconnect" message to display (only has effect
|
||||
if logins are disabled).
|
||||
"""
|
||||
self.air.netMessenger.send('enableLogins', [enable])
|
||||
|
||||
### GENERAL INFORMATION ###
|
||||
def rpc_getGSIDByAccount(self, request, accountId):
|
||||
"""Gets the GSID for a given webserver account ID, or null if invalid."""
|
||||
|
@ -46,6 +55,20 @@ class ToontownRPCHandler:
|
|||
if account and account.get('dclass') == 'Account':
|
||||
return account.get('fields',{}).get('ACCOUNT_ID')
|
||||
|
||||
def rpc_getAccountByAvatarID(self, request, avId):
|
||||
"""Gets the account ID associated to a particular avatar (account), or null if invalid."""
|
||||
def callback(dclass, fields):
|
||||
if dclass is None:
|
||||
return request.result(None)
|
||||
if dclass.getName() is None:
|
||||
return request.result(None)
|
||||
|
||||
return request.result(self.rpc_getAccountByGSID(request, fields.get('setDISLid',[-1,])[0]))
|
||||
|
||||
self.air.dbInterface.queryObject(self.air.dbId, avId, callback)
|
||||
|
||||
return request
|
||||
|
||||
def rpc_getAvatarsForGSID(self, request, gsId):
|
||||
"""Gets the set of avatars (Toons) that exist on a given gsId, or null if invalid."""
|
||||
|
||||
|
|
Loading…
Reference in a new issue