Merge remote-tracking branch 'origin/beta-wip' into estates
Conflicts: config/dev.prc deployment/server.prc toontown/estate/DistributedEstateAI.py
This commit is contained in:
commit
8531534aa8
55 changed files with 1050 additions and 426 deletions
|
@ -71,8 +71,7 @@ roles:
|
|||
min: 100000000
|
||||
max: 399999999
|
||||
backend:
|
||||
type: yaml
|
||||
foldername: ../databases/astrondb
|
||||
type: mongodb
|
||||
|
||||
- type: dbss
|
||||
database: 4003
|
||||
|
|
|
@ -8,6 +8,7 @@ server-version dev
|
|||
sync-video #f
|
||||
want-dev #f
|
||||
preload-avatars #t
|
||||
texture-anisotropic-degree 16
|
||||
|
||||
|
||||
# Resource settings
|
||||
|
@ -32,7 +33,6 @@ default-model-extension .bam
|
|||
want-rpc-server #f
|
||||
rpc-server-endpoint http://localhost:8080/
|
||||
eventlog-host 127.0.0.1
|
||||
want-parties #f
|
||||
want-cheesy-expirations #t
|
||||
|
||||
|
||||
|
@ -47,10 +47,12 @@ dc-file config/otp.dc
|
|||
want-pets #f
|
||||
want-news-tab #f
|
||||
want-news-page #f
|
||||
want-old-fireworks #t
|
||||
want-accessories #f
|
||||
want-parties #f
|
||||
want-gardening #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
|
||||
want-keep-alive #f
|
||||
|
||||
|
||||
# Developer Modifications
|
||||
|
@ -69,3 +71,4 @@ force-player-understandable #t
|
|||
|
||||
# Holidays and Events
|
||||
force-holiday-decorations 6
|
||||
want-arg-manager #t
|
||||
|
|
|
@ -9,6 +9,7 @@ audio-library-name p3openal_audio
|
|||
sync-video #f
|
||||
want-dev #f
|
||||
preload-avatars #t
|
||||
texture-anisotropic-degree 16
|
||||
language LANGUAGE_HERE
|
||||
|
||||
# Resources settings
|
||||
|
@ -46,13 +47,16 @@ csmud-secret Yv1JrpTUdkX6M86h44Z9q4AUaQYdFnectDgl2I5HOQf8CBh7LUZWpzKB9FBD
|
|||
want-pets #f
|
||||
want-news-tab #f
|
||||
want-news-page #f
|
||||
want-old-fireworks #t
|
||||
want-gardening #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
|
||||
want-keep-alive #f
|
||||
|
||||
|
||||
# Holidays and Events
|
||||
force-holiday-decorations 6
|
||||
want-arg-manager #t
|
||||
|
||||
|
||||
# Chat
|
||||
force-avatar-understandable #t
|
||||
|
|
|
@ -630,10 +630,8 @@ dclass DistributedToon : DistributedPlayer {
|
|||
magicTeleportRequest(uint32 requesterId) ownrecv;
|
||||
magicTeleportResponse(uint32 requesterId, uint32 hoodId) ownsend airecv;
|
||||
magicTeleportInitiate(uint32 hoodId, uint32 zoneId) ownrecv;
|
||||
|
||||
// Temporary ping-pong fields.
|
||||
ping(string data) ownrecv;
|
||||
pong(string data) ownsend airecv;
|
||||
keepAlive() ownsend airecv;
|
||||
setLastSeen(uint32 timestamp = 0) required db;
|
||||
};
|
||||
|
||||
dclass DistributedCCharBase : DistributedObject {
|
||||
|
@ -1189,9 +1187,9 @@ dclass DistributedCatchGame : DistributedMinigame {
|
|||
dclass DistributedDivingGame : DistributedMinigame {
|
||||
pickupTreasure(uint32 chestId) airecv clsend;
|
||||
setTreasureGrabbed(uint32 avId, uint32 chestId) broadcast;
|
||||
handleFishCollision(uint32 avId, uint32 spawnId, uint32 spawnerId, char status[0-256]) airecv clsend;
|
||||
handleFishCollision(uint32 spawnId, uint32 spawnerId, char status[0-256]) airecv clsend;
|
||||
performFishCollision(uint32 avId, uint32 spawnId, uint32 spawnerId, int16 timestamp) broadcast;
|
||||
handleCrabCollision(uint32 avId, char status[0-256]) airecv clsend;
|
||||
handleCrabCollision(char status[0-256]) airecv clsend;
|
||||
performCrabCollision(uint32 avId, int16 timestamp) broadcast;
|
||||
setTreasureDropped(uint32 avId, int16 timestamp) broadcast;
|
||||
fishSpawn(int16 timestamp, uint32 fishcode, uint32 spawnerId, uint16 offset) broadcast;
|
||||
|
@ -1199,6 +1197,7 @@ dclass DistributedDivingGame : DistributedMinigame {
|
|||
getCrabMoving(uint32 crabId, int16 crabX, int8 dir) airecv clsend;
|
||||
setCrabMoving(uint32 crabId, int16 timestamp, int8 rand1, int8 rand2, int16 crabX, int8 dir) broadcast;
|
||||
treasureRecovered() airecv clsend;
|
||||
dropTreasure() airecv clsend;
|
||||
incrementScore(uint32 avId, uint32 newSpot, int16 timestamp) broadcast;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,11 +2,35 @@ This deployment folder contains files that describe how a release of TTR should
|
|||
|
||||
uberdogs.yml contains the 'uberdogs' section of an astrond.yml. Please keep it updated, or else you'll break prod!
|
||||
|
||||
deploy.json describes a specific release of TTR. It contains the version of astron to use as well as the version of Panda3D to use.
|
||||
deploy.json also contains a version prefix. For releases, a commit should be made that updates deploy.json to state the new version prefix.
|
||||
deploy.json describes a the environment for a release of TTR. It contains the version of astron to use as well as the version of Panda3D to use.
|
||||
deploy.json also contains a version prefix. This is used to generate dev version strings on the development server (which are probably something like ttr-beta-dev-gabcdef0).
|
||||
When we deploy a release to prod, we push a git tag named after the version to the repository (i.e. ttr-beta-v1.3.7). It is required that the tag's name contain the version prefix specified in deploy.json.
|
||||
The key 'server-resources' maps to a list of file extensions of files in the resources directory that are necessary to be used server-side. We do not package and deploy art assets onto servers.
|
||||
For example:
|
||||
deploy.json resides at prefix ttr-v1.0.1-
|
||||
Git commit 6ebecf60d contains all the code that we want to push in v1.0.2
|
||||
Whomever is making the release should create a single commit changing deploy.json's version prefix to ttr-v1.0.2-. Don't put anything else in that commit. Say it has commit hash 102bea8c9.
|
||||
The final rendered version number, after deploy scripts are run, would be ttr-v1.0.2-102bea8.
|
||||
|
||||
Last, server.prc is the configuration file we use for specifying config vars related to gameplay (a variable like want-sbhq should be put in server.prc, while a variable like air-stateserver does not belong here). server.prc is the last portion added to generated configuration files.
|
||||
We also have a tag system to allow certain blocks of configuration to be used only in a certain environment. This allows us to generate releases that behaive differently depending on the environment that they are deployed in. For example:
|
||||
|
||||
-----
|
||||
want-toontowncentral #t
|
||||
#<prod>
|
||||
want-bbhq #f
|
||||
#</prod>
|
||||
|
||||
#<dev>
|
||||
want-bbhq #t
|
||||
#</dev>
|
||||
-----
|
||||
|
||||
In prod, the parsed config file would look like this:
|
||||
|
||||
-----
|
||||
want-toontowncentral #t
|
||||
#<prod>
|
||||
want-bbhq #f
|
||||
#</prod>
|
||||
|
||||
#<dev>
|
||||
##UNUSED SECTION
|
||||
##want-bbhq #t
|
||||
#</dev>
|
||||
-----
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"__fyi__": "If you use anything other than the first 7 characters of the git hash, you just broke everything",
|
||||
"astron": "a0608a9",
|
||||
"astron": "b467639",
|
||||
"panda3d": "d048f43",
|
||||
"version-prefix": "ttr-beta-",
|
||||
"server-resources": ["dna", "xml", "txt", "dat", "bam"]
|
||||
|
|
|
@ -10,16 +10,14 @@ want-cheesy-expirations #t
|
|||
# ##### 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 #t
|
||||
want-lbhq #t
|
||||
want-bbhq #f
|
||||
want-pets #f
|
||||
want-old-fireworks #t
|
||||
want-parties #f
|
||||
want-accessories #f
|
||||
want-golf #f
|
||||
want-gardening #f
|
||||
want-keep-alive #f
|
||||
|
||||
# Holidays and Events
|
||||
|
|
|
@ -164,10 +164,23 @@ class AIBase:
|
|||
self.taskMgr.add(self.__resetPrevTransform, 'resetPrevTransform', priority=-51)
|
||||
self.taskMgr.add(self.__ivalLoop, 'ivalLoop', priority=20)
|
||||
self.taskMgr.add(self.__igLoop, 'igLoop', priority=50)
|
||||
if self.config.GetBool('garbage-collect-states', 1):
|
||||
self.taskMgr.add(self.__garbageCollectStates, 'garbageCollectStates', priority=46)
|
||||
if self.AISleep >= 0 and (not self.AIRunningNetYield or self.AIForceSleep):
|
||||
self.taskMgr.add(self.__sleepCycleTask, 'aiSleep', priority=55)
|
||||
self.eventMgr.restart()
|
||||
|
||||
def __garbageCollectStates(self, state):
|
||||
""" This task is started only when we have
|
||||
garbage-collect-states set in the Config.prc file, in which
|
||||
case we're responsible for taking out Panda's garbage from
|
||||
time to time. This is not to be confused with Python's
|
||||
garbage collection. """
|
||||
|
||||
TransformState.garbageCollect()
|
||||
RenderState.garbageCollect()
|
||||
return Task.cont
|
||||
|
||||
def getRepository(self):
|
||||
return self.air
|
||||
|
||||
|
|
69
otp/ai/DiagnosticMagicWords.py
Normal file
69
otp/ai/DiagnosticMagicWords.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
from MagicWordGlobal import *
|
||||
from direct.showbase.GarbageReport import GarbageLogger
|
||||
from direct.showbase.ContainerReport import ContainerReport
|
||||
from direct.directnotify.DirectNotifyGlobal import *
|
||||
import gc
|
||||
|
||||
category = CATEGORY_SYSADMIN if game.process == 'server' else CATEGORY_DEBUG
|
||||
|
||||
notify = directNotify.newCategory('DiagnosticMagicWords')
|
||||
|
||||
def aiPrefix(func):
|
||||
"""Prefixes `func`'s name with 'ai' if this is an AI server."""
|
||||
if game.process == 'server':
|
||||
func.func_name = 'ai' + func.func_name
|
||||
return func
|
||||
|
||||
@magicWord(category=category)
|
||||
@aiPrefix
|
||||
def garbage(arg=''):
|
||||
"""Reports the total garbage use for this process."""
|
||||
|
||||
flags = arg.split()
|
||||
|
||||
GarbageLogger('~garbage', fullReport=('full' in flags), threaded=True,
|
||||
safeMode=('safe' in flags), delOnly=('delonly' in flags))
|
||||
|
||||
return 'Garbage report is now being written to log...'
|
||||
|
||||
@magicWord(category=category)
|
||||
@aiPrefix
|
||||
def heap():
|
||||
"""Counts the number of objects in Python's object memory."""
|
||||
|
||||
return '%d active objects (%d garbage)' % (len(gc.get_objects()),
|
||||
len(gc.garbage))
|
||||
|
||||
|
||||
@magicWord(category=category, types=[int])
|
||||
@aiPrefix
|
||||
def objects(minimum=30):
|
||||
"""Write the objects down to log."""
|
||||
|
||||
cls_counts = {}
|
||||
|
||||
objs = gc.get_objects()
|
||||
for obj in objs:
|
||||
cls = getattr(obj, '__class__', None) or type(obj)
|
||||
|
||||
cls_counts[cls] = cls_counts.get(cls, 0) + 1
|
||||
|
||||
classes = cls_counts.keys()
|
||||
classes.sort(key=lambda x: cls_counts[x], reverse=True)
|
||||
|
||||
notify.info('=== OBJECT TYPES REPORT: ===')
|
||||
for cls in classes:
|
||||
if cls_counts[cls] < minimum: continue # Not notable enough...
|
||||
notify.info('%s: %s' % (repr(cls), cls_counts[cls]))
|
||||
notify.info('============================')
|
||||
|
||||
return 'Wrote object types to log.'
|
||||
|
||||
@magicWord(category=category, types=[int])
|
||||
@aiPrefix
|
||||
def containers(limit=30):
|
||||
"""Write the container report to log."""
|
||||
|
||||
ContainerReport('~containers', log=True, limit=limit, threaded=True)
|
||||
|
||||
return 'Writing container report to log...'
|
|
@ -418,6 +418,11 @@ class DistributedPlayer(DistributedAvatar.DistributedAvatar, PlayerBase.PlayerBa
|
|||
return
|
||||
|
||||
def b_teleportGreeting(self, avId):
|
||||
if hasattr(self, 'ghostMode') and self.ghostMode:
|
||||
# If we're in ghost mode, we don't want to greet the person we're
|
||||
# teleporting to. On another note, why the hell is Toontown-specific
|
||||
# stuff in here? :S ...
|
||||
return
|
||||
self.d_teleportGreeting(avId)
|
||||
self.teleportGreeting(avId)
|
||||
|
||||
|
|
|
@ -2017,7 +2017,10 @@ class OTPClientRepository(ClientRepositoryBase):
|
|||
for dg in self.__pendingMessages[handle]:
|
||||
di = DatagramIterator(dg)
|
||||
msgType = di.getUint16()
|
||||
self.handler(msgType, di)
|
||||
if self.handler == None:
|
||||
self.handleMessageType(msgType, di)
|
||||
else:
|
||||
self.handler(msgType, di)
|
||||
|
||||
del self.__pendingMessages[handle]
|
||||
|
||||
|
|
|
@ -188,6 +188,7 @@ CRBootedReasons = {1: 'Yikes - An unexpected problem occured. Your connection h
|
|||
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.',
|
||||
128: 'There appears to have been a hiccup in your connection to Toontown. Don\'t worry -- we\'re working on straightening it out. You should be able to connect again and go right back into Toontown.',
|
||||
151: 'You were kicked out by one of the developers working on the servers.',
|
||||
152: "You have been banned from the game for a reported violation of our Terms of Use connected to '%(name)s'. For more details, please check the Toontown Rewritten website.",
|
||||
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.',
|
||||
|
@ -639,16 +640,17 @@ SuitFaceoffTaunts = {'b': ['Would you like to make a donation?',
|
|||
'mh': ['Are you ready for my take?',
|
||||
'Lights, camera, action!',
|
||||
"Let's get this show rolling.",
|
||||
"There you are! Today, you'll be playing the role of the defeated toon.",
|
||||
"There you are! Today, you'll be playing the role of the defeated Toon.",
|
||||
'This scene will go on the cutting room floor.',
|
||||
'I already know my motivation for this scene.',
|
||||
'Are you ready for your final scene?',
|
||||
"If you don't cooperate we'll need cut you from the credits.",
|
||||
"I'm afraid I need to cut you from the credits.",
|
||||
"I'm ready to roll your end credits.",
|
||||
'I told you not to call me.',
|
||||
"Let's get on with the show.",
|
||||
"There's no business like Hollywood.",
|
||||
"There's no business like it!",
|
||||
"This will be the best act yet.",
|
||||
"I hope you don't forget your lines."],
|
||||
"I hope you haven't forgotten your lines."],
|
||||
'nc': ['Looks like your number is up.',
|
||||
'I hope you prefer extra crunchy.',
|
||||
"Now you're really in a crunch.",
|
||||
|
@ -816,9 +818,8 @@ SuitFaceoffTaunts = {'b': ['Would you like to make a donation?',
|
|||
"Have I mentioned I know 'The Mingler?'",
|
||||
"You'll never forget me.",
|
||||
'I know all the right people to bring you down.',
|
||||
"How convienient of you to drop in.",
|
||||
"The VP has given me plenty of promotions. Where's yours?",
|
||||
"Even the Chairman knows my name.",
|
||||
"How convenient of you to drop in.",
|
||||
"Even the boss knows my name.",
|
||||
"You name it, I've dropped it."],
|
||||
'gh': ['Put it there, Toon.',
|
||||
"Let's shake on it.",
|
||||
|
|
|
@ -4,19 +4,19 @@ class Settings:
|
|||
"""
|
||||
This is the class that reads JSON formatted settings files, and
|
||||
returns the values back to whatever requested them.
|
||||
|
||||
|
||||
This class should be generated in the OTPBase, and then accessed
|
||||
via base.settings
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.fileName = 'settings.json'
|
||||
try:
|
||||
with open(self.fileName, 'r') as file:
|
||||
self.settings = json.load(file)
|
||||
except IOError:
|
||||
except:
|
||||
self.settings = {}
|
||||
|
||||
|
||||
def updateSetting(self, type, attribute, value):
|
||||
"""
|
||||
Update the json file with the new data specified.
|
||||
|
@ -26,13 +26,13 @@ class Settings:
|
|||
self.settings[type] = {}
|
||||
self.settings[type][attribute] = value
|
||||
json.dump(self.settings, file)
|
||||
|
||||
|
||||
def getOption(self, type, attribute, default):
|
||||
"""
|
||||
Generic method to fetch the saved configuration settings.
|
||||
"""
|
||||
return self.settings.get(type, {}).get(attribute, default)
|
||||
|
||||
|
||||
def getString(self, type, attribute, default=''):
|
||||
"""
|
||||
Fetch a string type from the json file, but use default if it
|
||||
|
@ -43,7 +43,7 @@ class Settings:
|
|||
return value
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
def getInt(self, type, attribute, default=0):
|
||||
"""
|
||||
Fetch a integer type from the json file, but use default if it
|
||||
|
@ -54,7 +54,7 @@ class Settings:
|
|||
return int(value)
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
def getBool(self, type, attribute, default=False):
|
||||
"""
|
||||
Fetch a boolean type from the json file, but use default if it
|
||||
|
@ -65,7 +65,7 @@ class Settings:
|
|||
return value
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
def getList(self, type, attribute, default=[], expectedLength=2):
|
||||
"""
|
||||
Fetch a list type from the json file, but use default if it
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f98377694b2c0580659acd748d99b93e42cc5ed2
|
||||
Subproject commit 74f4c40fe74041265835cf9766bdb928624f0b97
|
|
@ -1,7 +1,67 @@
|
|||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.distributed.ClockDelta import *
|
||||
from direct.task import Task
|
||||
|
||||
from toontown.toonbase import ToontownGlobals
|
||||
from toontown.parties import PartyGlobals
|
||||
|
||||
from toontown.effects.DistributedFireworkShowAI import DistributedFireworkShowAI
|
||||
from toontown.effects import FireworkShows
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
class HolidayManagerAI:
|
||||
def __init__(self):
|
||||
# notify = directNotify.newCategory('HolidayManagerAI')
|
||||
def __init__(self, air):
|
||||
self.air = air
|
||||
self.currentHolidays = []
|
||||
|
||||
|
||||
# TODO: Properly create a holiday manager to run this.
|
||||
if config.GetBool('want-hourly-fireworks', False):
|
||||
self.__startFireworksTick()
|
||||
|
||||
"""
|
||||
Fireworks Stuff
|
||||
"""
|
||||
def __startFireworksTick(self):
|
||||
# Check seconds until next hour.
|
||||
ts = time.time()
|
||||
nextHour = 3600 - (ts % 3600)
|
||||
taskMgr.doMethodLater(nextHour, self.__fireworksTick, 'hourly-fireworks')
|
||||
|
||||
def __fireworksTick(self, task):
|
||||
# The next tick will occur in exactly an hour.
|
||||
task.delayTime = 3600
|
||||
|
||||
showName = config.GetString('hourly-fireworks-type', 'july4')
|
||||
|
||||
if showName == 'july4':
|
||||
showType = ToontownGlobals.JULY4_FIREWORKS
|
||||
|
||||
elif showName == 'newyears':
|
||||
showType = ToontownGlobals.NEWYEARS_FIREWORKS
|
||||
|
||||
elif showName == 'summer':
|
||||
showType = PartyGlobals.FireworkShows.Summer
|
||||
|
||||
elif showName == 'random':
|
||||
shows = [ToontownGlobals.JULY4_FIREWORKS, ToontownGlobals.NEWYEARS_FIREWORKS, PartyGlobals.FireworkShows.Summer]
|
||||
showType = random.choice(shows)
|
||||
else:
|
||||
raise AttributeError('%s is an invalid firework type' % showName)
|
||||
return
|
||||
|
||||
numShows = len(FireworkShows.shows.get(showType, []))
|
||||
showIndex = random.randint(0, numShows - 1)
|
||||
for hood in self.air.hoods:
|
||||
if hood.HOOD == ToontownGlobals.GolfZone:
|
||||
continue
|
||||
fireworksShow = DistributedFireworkShowAI(self.air)
|
||||
fireworksShow.generateWithRequired(hood.HOOD)
|
||||
fireworksShow.b_startShow(showType, showIndex, globalClockDelta.getRealNetworkTime())
|
||||
return task.again
|
||||
|
||||
def isHolidayRunning(self, *args):
|
||||
return True
|
||||
#TODO: this function needs to actually check holidays
|
||||
|
|
|
@ -62,6 +62,7 @@ from toontown.catalog.CatalogManagerAI import CatalogManagerAI
|
|||
# Magic Words!
|
||||
from panda3d.core import PStatClient
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
import otp.ai.DiagnosticMagicWords
|
||||
|
||||
class ToontownAIRepository(ToontownInternalRepository):
|
||||
def __init__(self, baseChannel, serverId, districtName):
|
||||
|
@ -83,7 +84,7 @@ class ToontownAIRepository(ToontownInternalRepository):
|
|||
self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
|
||||
self.doLiveUpdates = self.config.GetBool('want-live-updates', True)
|
||||
|
||||
self.holidayManager = HolidayManagerAI()
|
||||
self.holidayManager = HolidayManagerAI(self)
|
||||
|
||||
self.fishManager = FishManagerAI()
|
||||
self.questManager = QuestManagerAI(self)
|
||||
|
@ -124,10 +125,11 @@ class ToontownAIRepository(ToontownInternalRepository):
|
|||
self.createGlobals()
|
||||
self.createZones()
|
||||
|
||||
self.distributedDistrict.b_setAvailable(1)
|
||||
|
||||
self.statusSender.start()
|
||||
|
||||
self.distributedDistrict.b_setAvailable(1)
|
||||
self.notify.info('District is now ready.')
|
||||
|
||||
def incrementPopulation(self):
|
||||
self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() + 1)
|
||||
self.statusSender.sendStatus()
|
||||
|
|
|
@ -316,6 +316,10 @@ class PropPool:
|
|||
tie.getChild(0).setHpr(23.86, -16.03, 9.18)
|
||||
elif name == 'small-magnet':
|
||||
self.props[name].setScale(0.5)
|
||||
tex = loader.loadTexture('phase_5/maps/battle_props_palette_4amla_2.jpg')
|
||||
tex.setMinfilter(Texture.FTLinearMipmapLinear)
|
||||
tex.setMagfilter(Texture.FTLinear)
|
||||
self.props[name].setTexture(tex, 1)
|
||||
elif name == 'shredder-paper':
|
||||
paper = self.props[name]
|
||||
paper.setPosHpr(2.22, -0.95, 1.16, -48.61, 26.57, -111.51)
|
||||
|
|
|
@ -24,8 +24,13 @@ class RewardPanel(DirectFrame):
|
|||
SkipBattleMovieEvent = 'skip-battle-movie-event'
|
||||
|
||||
def __init__(self, name):
|
||||
gscale = (TTLocalizer.RPdirectFrame[0], TTLocalizer.RPdirectFrame[1], TTLocalizer.RPdirectFrame[2] * 1.1)
|
||||
DirectFrame.__init__(self, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=ToontownGlobals.GlobalDialogColor, geom_pos=Point3(0, 0, -.05), geom_scale=gscale, pos=(0, 0, 0.587))
|
||||
if base.config.GetBool('want-skip-button', 0):
|
||||
gscale = (TTLocalizer.RPdirectFrame[0], TTLocalizer.RPdirectFrame[1], TTLocalizer.RPdirectFrame[2] * 1.1)
|
||||
gpos = Point3(0, 0, -0.05)
|
||||
else:
|
||||
gscale = TTLocalizer.RPdirectFrame
|
||||
gpos = Point3(0, 0, 0)
|
||||
DirectFrame.__init__(self, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=ToontownGlobals.GlobalDialogColor, geom_pos=gpos, geom_scale=gscale, pos=(0, 0, 0.587))
|
||||
self.initialiseoptions(RewardPanel)
|
||||
self.avNameLabel = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.3), text=name, text_scale=0.08)
|
||||
self.gagExpFrame = DirectFrame(parent=self, relief=None, pos=(-0.32, 0, 0.24))
|
||||
|
@ -450,14 +455,14 @@ class RewardPanel(DirectFrame):
|
|||
def getTrackIntervalList(self, toon, track, origSkill, earnedSkill, hasUber, guestWaste = 0):
|
||||
if hasUber < 0:
|
||||
print (toon.doId, 'Reward Panel received an invalid hasUber from an uberList')
|
||||
tickDelay = 1.0 / 30
|
||||
tickDelay = 0.1
|
||||
intervalList = []
|
||||
if origSkill + earnedSkill >= ToontownBattleGlobals.UnpaidMaxSkills[track] and toon.getGameAccess() != OTPGlobals.AccessFull:
|
||||
lostExp = origSkill + earnedSkill - ToontownBattleGlobals.UnpaidMaxSkills[track]
|
||||
intervalList.append(Func(self.showTrackIncLabel, track, lostExp, 1))
|
||||
else:
|
||||
intervalList.append(Func(self.showTrackIncLabel, track, earnedSkill))
|
||||
barTime = 1.0
|
||||
barTime = math.log(earnedSkill + 0.5)
|
||||
numTicks = int(math.ceil(barTime / tickDelay))
|
||||
for i in range(numTicks):
|
||||
t = (i + 1) / float(numTicks)
|
||||
|
@ -466,7 +471,7 @@ class RewardPanel(DirectFrame):
|
|||
intervalList.append(Wait(tickDelay))
|
||||
|
||||
intervalList.append(Func(self.resetBarColor, track))
|
||||
intervalList.append(Wait(0.1))
|
||||
intervalList.append(Wait(0.3))
|
||||
nextExpValue = self.getNextExpValue(origSkill, track)
|
||||
finalGagFlag = 0
|
||||
while origSkill + earnedSkill >= nextExpValue and origSkill < nextExpValue and not finalGagFlag:
|
||||
|
@ -485,9 +490,9 @@ class RewardPanel(DirectFrame):
|
|||
uberSkill = ToontownBattleGlobals.UberSkill + ToontownBattleGlobals.Levels[track][ToontownBattleGlobals.LAST_REGULAR_GAG_LEVEL + 1]
|
||||
if currentSkill >= uberSkill and not hasUber > 0:
|
||||
intervalList += self.getUberGagIntervalList(toon, track, ToontownBattleGlobals.LAST_REGULAR_GAG_LEVEL + 1)
|
||||
intervalList.append(Wait(0.1))
|
||||
intervalList.append(Wait(0.3))
|
||||
skillDiff = currentSkill - ToontownBattleGlobals.Levels[track][ToontownBattleGlobals.LAST_REGULAR_GAG_LEVEL + 1]
|
||||
barTime = math.log(skillDiff + 1)
|
||||
barTime = math.log(skillDiff + 0.5)
|
||||
numTicks = int(math.ceil(barTime / tickDelay))
|
||||
displayedSkillDiff = skillDiff
|
||||
if displayedSkillDiff > ToontownBattleGlobals.UberSkill:
|
||||
|
@ -497,20 +502,20 @@ class RewardPanel(DirectFrame):
|
|||
t = (i + 1) / float(numTicks)
|
||||
newValue = int(currentSkill - t * skillDiff + 0.5)
|
||||
intervalList.append(Func(self.incrementExp, track, newValue, toon))
|
||||
intervalList.append(Wait(tickDelay * 0.7))
|
||||
intervalList.append(Wait(tickDelay * 0.5))
|
||||
|
||||
intervalList.append(Wait(0.1))
|
||||
intervalList.append(Wait(0.3))
|
||||
return intervalList
|
||||
|
||||
def getMeritIntervalList(self, toon, dept, origMerits, earnedMerits):
|
||||
tickDelay = 1.0 / 60
|
||||
tickDelay = 0.08
|
||||
intervalList = []
|
||||
totalMerits = CogDisguiseGlobals.getTotalMerits(toon, dept)
|
||||
neededMerits = 0
|
||||
if totalMerits and origMerits != totalMerits:
|
||||
neededMerits = totalMerits - origMerits
|
||||
intervalList.append(Func(self.showMeritIncLabel, dept, min(neededMerits, earnedMerits)))
|
||||
barTime = 1.0
|
||||
barTime = math.log(earnedMerits + 1)
|
||||
numTicks = int(math.ceil(barTime / tickDelay))
|
||||
for i in range(numTicks):
|
||||
t = (i + 1) / float(numTicks)
|
||||
|
@ -519,10 +524,10 @@ class RewardPanel(DirectFrame):
|
|||
intervalList.append(Wait(tickDelay))
|
||||
|
||||
intervalList.append(Func(self.resetMeritBarColor, dept))
|
||||
intervalList.append(Wait(0.1))
|
||||
intervalList.append(Wait(0.3))
|
||||
if toon.cogLevels[dept] < ToontownGlobals.MaxCogSuitLevel:
|
||||
if neededMerits and toon.readyForPromotion(dept):
|
||||
intervalList.append(Wait(0.4))
|
||||
intervalList.append(Wait(0.3))
|
||||
intervalList += self.getPromotionIntervalList(toon, dept)
|
||||
return intervalList
|
||||
|
||||
|
@ -570,7 +575,7 @@ class RewardPanel(DirectFrame):
|
|||
|
||||
def getQuestIntervalList(self, toon, deathList, toonList, origQuestsList, itemList, helpfulToonsList = []):
|
||||
avId = toon.getDoId()
|
||||
tickDelay = 0.5
|
||||
tickDelay = 0.2
|
||||
intervalList = []
|
||||
toonShortList = []
|
||||
for t in toonList:
|
||||
|
@ -659,7 +664,7 @@ class RewardPanel(DirectFrame):
|
|||
if earned > 0:
|
||||
earned = min(earned, quest.getNumQuestItems() - questDesc[4])
|
||||
if earned > 0 or base.localAvatar.tutorialAck == 0 and num == 1:
|
||||
barTime = 1.0
|
||||
barTime = math.log(earned + 1)
|
||||
numTicks = int(math.ceil(barTime / tickDelay))
|
||||
for i in range(numTicks):
|
||||
t = (i + 1) / float(numTicks)
|
||||
|
@ -721,19 +726,19 @@ class RewardPanel(DirectFrame):
|
|||
if meritList[dept]:
|
||||
track += self.getMeritIntervalList(toon, dept, origMeritList[dept], meritList[dept])
|
||||
|
||||
track.append(Wait(0.75))
|
||||
track.append(Wait(1.0))
|
||||
itemInterval = self.getItemIntervalList(toon, itemList)
|
||||
if itemInterval:
|
||||
track.append(Func(self.initItemFrame, toon))
|
||||
track.append(Wait(0.25))
|
||||
track.append(Wait(1.0))
|
||||
track += itemInterval
|
||||
track.append(Wait(0.5))
|
||||
track.append(Wait(1.0))
|
||||
missedItemInterval = self.getMissedItemIntervalList(toon, missedItemList)
|
||||
if missedItemInterval:
|
||||
track.append(Func(self.initMissedItemFrame, toon))
|
||||
track.append(Wait(0.25))
|
||||
track.append(Wait(1.0))
|
||||
track += missedItemInterval
|
||||
track.append(Wait(0.5))
|
||||
track.append(Wait(1.0))
|
||||
self.notify.debug('partList = %s' % partList)
|
||||
newPart = 0
|
||||
for part in partList:
|
||||
|
@ -745,9 +750,9 @@ class RewardPanel(DirectFrame):
|
|||
partList = self.getCogPartIntervalList(toon, partList)
|
||||
if partList:
|
||||
track.append(Func(self.initCogPartFrame, toon))
|
||||
track.append(Wait(0.25))
|
||||
track.append(Wait(1.0))
|
||||
track += partList
|
||||
track.append(Wait(0.5))
|
||||
track.append(Wait(1.0))
|
||||
questList = self.getQuestIntervalList(toon, deathList, toonList, origQuestsList, itemList, helpfulToonsList)
|
||||
if questList:
|
||||
avQuests = []
|
||||
|
@ -755,9 +760,9 @@ class RewardPanel(DirectFrame):
|
|||
avQuests.append(origQuestsList[i:i + 5])
|
||||
|
||||
track.append(Func(self.initQuestFrame, toon, copy.deepcopy(avQuests)))
|
||||
track.append(Wait(0.25))
|
||||
track.append(Wait(1.0))
|
||||
track += questList
|
||||
track.append(Wait(0.5))
|
||||
track.append(Wait(2.0))
|
||||
track.append(Wait(0.25))
|
||||
if trackEnded:
|
||||
track.append(Func(self.vanishFrames))
|
||||
|
|
|
@ -116,12 +116,12 @@ class DistributedElevator(DistributedObject.DistributedObject):
|
|||
del self.openDoors
|
||||
if hasattr(self, 'closeDoors'):
|
||||
del self.closeDoors
|
||||
self.offsetNP.removeNode()
|
||||
del self.fsm
|
||||
del self.openSfx
|
||||
del self.closeSfx
|
||||
self.isSetup = 0
|
||||
self.fillSlotTrack = None
|
||||
self.offsetNP.removeNode()
|
||||
if hasattr(base.localAvatar, 'elevatorNotifier'):
|
||||
base.localAvatar.elevatorNotifier.cleanup()
|
||||
DistributedObject.DistributedObject.delete(self)
|
||||
|
|
|
@ -131,6 +131,8 @@ class SuitPlannerInteriorAI:
|
|||
suitType = SuitDNA.getSuitType(suitName)
|
||||
bldgTrack = SuitDNA.getSuitDept(suitName)
|
||||
suitLevel = min(max(suitLevel, suitType), suitType + 4)
|
||||
if not self.respectInvasions:
|
||||
specialSuit = 0
|
||||
dna = SuitDNA.SuitDNA()
|
||||
dna.newSuitRandom(suitType, bldgTrack)
|
||||
suit.dna = dna
|
||||
|
|
|
@ -2,6 +2,8 @@ import time
|
|||
from panda3d.core import *
|
||||
from toontown.toonbase import TTLocalizer
|
||||
from toontown.battle import SuitBattleGlobals
|
||||
import gc
|
||||
import thread
|
||||
|
||||
# If we don't have PSUTIL, don't return system statistics.
|
||||
try:
|
||||
|
@ -14,6 +16,10 @@ shard_status_interval = ConfigVariableInt(
|
|||
'shard-status-interval', 20,
|
||||
'How often to send shard status update messages.')
|
||||
|
||||
shard_heap_interval = ConfigVariableInt(
|
||||
'shard-status-interval', 60,
|
||||
'How often to recount objects on the heap (and in garbage).')
|
||||
|
||||
shard_status_timeout = ConfigVariableInt(
|
||||
'shard-status-timeout', 30,
|
||||
'The maximum time between receiving shard status update messages before'
|
||||
|
@ -26,6 +32,20 @@ class ShardStatusSender:
|
|||
|
||||
self.interval = None
|
||||
|
||||
# This is updated from a separate thread periodically:
|
||||
self.heap_status = {'objects': 0, 'garbage': 0}
|
||||
|
||||
def update_heap(self):
|
||||
lastUpdate = 0
|
||||
while taskMgr.running:
|
||||
if lastUpdate < time.time() - shard_heap_interval.getValue():
|
||||
self.heap_status = {'objects': len(gc.get_objects()),
|
||||
'garbage': len(gc.garbage)}
|
||||
lastUpdate = time.time()
|
||||
|
||||
# Don't consume CPU, but don't lay dormant for a long time either:
|
||||
time.sleep(1.0)
|
||||
|
||||
def start(self):
|
||||
# Set the average frame rate interval to match shard status interval.
|
||||
globalClock.setAverageFrameRateInterval(shard_status_interval.getValue())
|
||||
|
@ -37,6 +57,8 @@ class ShardStatusSender:
|
|||
dg = self.air.netMessenger.prepare('shardStatus', [offlineStatus])
|
||||
self.air.addPostRemove(dg)
|
||||
|
||||
thread.start_new_thread(self.update_heap, ())
|
||||
|
||||
# Fire off the first status, which also starts the interval:
|
||||
self.sendStatus()
|
||||
|
||||
|
@ -61,7 +83,8 @@ class ShardStatusSender:
|
|||
'districtName': self.air.distributedDistrict.name,
|
||||
'population': self.air.districtStats.getAvatarCount(),
|
||||
'avg-frame-rate': round(globalClock.getAverageFrameRate(), 5),
|
||||
'invasion': invasion
|
||||
'invasion': invasion,
|
||||
'heap': self.heap_status
|
||||
}
|
||||
if HAS_PSUTIL:
|
||||
status['cpu-usage'] = cpu_percent(interval=None, percpu=True)
|
||||
|
|
|
@ -94,7 +94,6 @@ class ToontownClientRepository(OTPClientRepository.OTPClientRepository):
|
|||
self.whitelistMgr = None
|
||||
|
||||
self.toontownTimeManager = ToontownTimeManager.ToontownTimeManager()
|
||||
|
||||
self.csm = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_CLIENT_SERVICES_MANAGER, 'ClientServicesManager')
|
||||
self.avatarFriendsManager = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_AVATAR_FRIENDS_MANAGER, 'AvatarFriendsManager')
|
||||
self.playerFriendsManager = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_PLAYER_FRIENDS_MANAGER, 'TTPlayerFriendsManager')
|
||||
|
@ -103,7 +102,8 @@ class ToontownClientRepository(OTPClientRepository.OTPClientRepository):
|
|||
self.deliveryManager = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER, 'DistributedDeliveryManager')
|
||||
if config.GetBool('want-code-redemption', 1):
|
||||
self.codeRedemptionManager = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_TOONTOWN_CODE_REDEMPTION_MANAGER, 'TTCodeRedemptionMgr')
|
||||
self.argManager = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_TTR_ARG_MANAGER, 'ARGManager')
|
||||
if config.GetBool('want-arg-manager', 0):
|
||||
self.argManager = self.generateGlobalObject(OtpDoGlobals.OTP_DO_ID_TTR_ARG_MANAGER, 'ARGManager')
|
||||
|
||||
self.streetSign = None
|
||||
self.furnitureManager = None
|
||||
|
@ -1037,7 +1037,7 @@ class ToontownClientRepository(OTPClientRepository.OTPClientRepository):
|
|||
return True
|
||||
|
||||
def sendQuietZoneRequest(self):
|
||||
self.sendSetZoneMsg(OTPGlobals.QuietZone)
|
||||
self.sendSetZoneMsg(OTPGlobals.QuietZone, [])
|
||||
|
||||
def handleQuietZoneGenerateWithRequired(self, di):
|
||||
doId = di.getUint32()
|
||||
|
|
|
@ -5,12 +5,21 @@ from direct.distributed.PyDatagram import PyDatagram
|
|||
from direct.distributed.MsgTypes import *
|
||||
from panda3d.core import *
|
||||
import pymongo, urlparse
|
||||
import signal
|
||||
|
||||
mongodb_url = ConfigVariableString('mongodb-url', 'mongodb://localhost',
|
||||
'Specifies the URL of the MongoDB server that'
|
||||
'stores all gameserver data.')
|
||||
' stores all gameserver data.')
|
||||
mongodb_replicaset = ConfigVariableString('mongodb-replicaset', '', 'Specifies the replica set of the gameserver data DB.')
|
||||
|
||||
ai_watchdog = ConfigVariableInt('ai-watchdog', 15,
|
||||
'Specifies the maximum amount of time that a'
|
||||
' frame may take before the process kills itself.')
|
||||
|
||||
class WatchdogError(Exception): pass
|
||||
def watchdogExhausted(signum, frame):
|
||||
raise WatchdogError('The process has stalled!')
|
||||
|
||||
class ToontownInternalRepository(AstronInternalRepository):
|
||||
GameGlobalsId = OTP_DO_ID_TOONTOWN
|
||||
dbId = 4003
|
||||
|
@ -39,6 +48,15 @@ class ToontownInternalRepository(AstronInternalRepository):
|
|||
self.netMessenger.register(3, 'avatarOffline')
|
||||
self.netMessenger.register(4, 'enableLogins')
|
||||
|
||||
if hasattr(signal, 'alarm'):
|
||||
signal.signal(signal.SIGALRM, watchdogExhausted)
|
||||
|
||||
self.__watchdog = taskMgr.add(self.__resetWatchdog, 'watchdog')
|
||||
|
||||
def __resetWatchdog(self, task):
|
||||
signal.alarm(ai_watchdog.getValue())
|
||||
return task.cont
|
||||
|
||||
def getAvatarIdFromSender(self):
|
||||
return self.getMsgSender() & 0xFFFFFFFF
|
||||
|
||||
|
|
|
@ -1,8 +1,37 @@
|
|||
from DNAParser import *
|
||||
import DNAStoreSuitPoint
|
||||
from collections import deque
|
||||
|
||||
class DNASuitGraph:
|
||||
# Helpers for uint16 bytearray access:
|
||||
try:
|
||||
import ctypes
|
||||
|
||||
except ImportError:
|
||||
# No ctypes! Use a slightly slower class based on bytearray().
|
||||
|
||||
class uint16array(object):
|
||||
def __init__(self, size, initial=None):
|
||||
if initial is None:
|
||||
self.__array = bytearray(size * 2)
|
||||
else:
|
||||
self.__array = bytearray(initial for x in xrange(size * 2))
|
||||
|
||||
def __getitem__(self, index):
|
||||
hi, lo = self.__array[index*2:index*2+2]
|
||||
return hi*256 + lo
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self.__array[index*2:index*2+2] = divmod(value, 256)
|
||||
|
||||
else:
|
||||
# ctypes! Wrap the uint16 array type in a convenience function:
|
||||
|
||||
def uint16array(size, initial=None):
|
||||
array = (ctypes.c_uint16 * size)()
|
||||
if initial is not None:
|
||||
ctypes.memset(array, initial, ctypes.sizeof(array))
|
||||
return array
|
||||
|
||||
class DNASuitGraph(object):
|
||||
def __init__(self, points, edges):
|
||||
self.points = points
|
||||
self.edges = edges
|
||||
|
@ -11,8 +40,15 @@ class DNASuitGraph:
|
|||
self._point2outboundEdges = {}
|
||||
self._point2inboundEdges = {}
|
||||
|
||||
for point in points:
|
||||
self._table = uint16array(4 * len(points)*len(points), 0xFF)
|
||||
|
||||
if points:
|
||||
highestId = max(point.id for point in points)
|
||||
self._id2index = uint16array(highestId+1)
|
||||
|
||||
for i,point in enumerate(points):
|
||||
self._pointId2point[point.id] = point
|
||||
self._id2index[point.id] = i
|
||||
|
||||
for edge in edges:
|
||||
try:
|
||||
|
@ -24,6 +60,44 @@ class DNASuitGraph:
|
|||
self._point2outboundEdges.setdefault(a, []).append(edge)
|
||||
self._point2inboundEdges.setdefault(b, []).append(edge)
|
||||
|
||||
visited = bytearray(len(points))
|
||||
for i, point in enumerate(points):
|
||||
for neighbor in self.getOriginPoints(point):
|
||||
self.addLink(neighbor, point, 1, point, False, visited)
|
||||
|
||||
def addLink(self, point, neighbor, distance, destination, unbounded, visited):
|
||||
pointIndex = self._id2index[point.id]
|
||||
neighborIndex = self._id2index[neighbor.id]
|
||||
destinationIndex = self._id2index[destination.id]
|
||||
|
||||
if visited[pointIndex]:
|
||||
# Loop detected! Modify the unbounded route:
|
||||
unbounded = True
|
||||
|
||||
visited[pointIndex] += 1
|
||||
|
||||
entry = pointIndex*len(self.points) + destinationIndex
|
||||
|
||||
existingDistance = self._table[entry*4 + 3] if unbounded else self._table[entry*4 + 1]
|
||||
if distance < existingDistance:
|
||||
if not unbounded:
|
||||
self._table[entry*4 + 0] = neighborIndex
|
||||
self._table[entry*4 + 1] = distance
|
||||
else:
|
||||
self._table[entry*4 + 2] = neighborIndex
|
||||
self._table[entry*4 + 3] = distance
|
||||
|
||||
# We've just updated our link. If we're traversable, announce the
|
||||
# new route to all of our neighbors:
|
||||
traversable = point.type in (DNAStoreSuitPoint.STREETPOINT,
|
||||
DNAStoreSuitPoint.COGHQINPOINT,
|
||||
DNAStoreSuitPoint.COGHQOUTPOINT)
|
||||
if traversable:
|
||||
for neighbor in self.getOriginPoints(point):
|
||||
self.addLink(neighbor, point, distance+1, destination, unbounded, visited)
|
||||
|
||||
visited[pointIndex] -= 1
|
||||
|
||||
def getEdgeEndpoints(self, edge):
|
||||
return self._pointId2point[edge.a], self._pointId2point[edge.b]
|
||||
|
||||
|
@ -44,51 +118,35 @@ class DNASuitGraph:
|
|||
return self.getEdgeZone(edges[0])
|
||||
|
||||
def getSuitPath(self, startPoint, endPoint, minPathLen, maxPathLen):
|
||||
# Performs a BFS in order to find a path from startPoint to endPoint,
|
||||
# the minimum length will be minPathLen, and the maximum will be
|
||||
# maxPathLen. N.B. these values indicate the length in edges, not
|
||||
# vertices, so the returned list will be:
|
||||
# minPathLen+1 <= len(list) <= maxPathLen+1
|
||||
start = self._id2index[startPoint.id]
|
||||
end = self._id2index[endPoint.id]
|
||||
|
||||
# The queue of paths to consider:
|
||||
# The format is a tuple: (prevPath, depth, point)
|
||||
pathDeque = deque()
|
||||
pathDeque.append((None, 0, startPoint))
|
||||
while pathDeque:
|
||||
path = pathDeque.popleft()
|
||||
prevPath, depth, point = path
|
||||
at = start
|
||||
path = [startPoint]
|
||||
|
||||
newDepth = depth + 1
|
||||
if newDepth > maxPathLen:
|
||||
# This path has grown too long, prune it.
|
||||
continue
|
||||
while at != end or minPathLen > 0:
|
||||
entry = at*len(self.points) + end
|
||||
|
||||
for adj in self.getAdjacentPoints(point):
|
||||
if adj == endPoint and newDepth >= minPathLen:
|
||||
# Hey, we found the end! Let's return it:
|
||||
points = deque()
|
||||
points.appendleft(adj)
|
||||
while path:
|
||||
points.appendleft(path[-1])
|
||||
path, _, _ = path
|
||||
return list(points)
|
||||
if minPathLen <= self._table[entry*4 + 1] <= maxPathLen:
|
||||
at = self._table[entry*4 + 0]
|
||||
elif self._table[entry*4 + 3] <= maxPathLen:
|
||||
at = self._table[entry*4 + 2]
|
||||
else:
|
||||
# No path exists!
|
||||
return None
|
||||
|
||||
# We're not at the end yet... Let's see if we can traverse this
|
||||
# point:
|
||||
if adj.type not in (DNAStoreSuitPoint.STREETPOINT,
|
||||
DNAStoreSuitPoint.COGHQINPOINT,
|
||||
DNAStoreSuitPoint.COGHQOUTPOINT):
|
||||
# This is some other special point that we cannot walk
|
||||
# across.
|
||||
continue
|
||||
|
||||
# Append this point to the paths we are considering:
|
||||
pathDeque.append((path, newDepth, adj))
|
||||
path.append(self.points[at])
|
||||
minPathLen -= 1
|
||||
maxPathLen -= 1
|
||||
|
||||
return path
|
||||
|
||||
def getAdjacentPoints(self, point):
|
||||
return [self.getPointFromIndex(edge.b) for edge in self.getEdgesFrom(point)]
|
||||
|
||||
def getOriginPoints(self, point):
|
||||
return [self.getPointFromIndex(edge.a) for edge in self.getEdgesTo(point)]
|
||||
|
||||
def getConnectingEdge(self, pointA, pointB):
|
||||
assert isinstance(pointA, DNAStoreSuitPoint.DNAStoreSuitPoint)
|
||||
assert isinstance(pointB, DNAStoreSuitPoint.DNAStoreSuitPoint)
|
||||
|
|
|
@ -11,20 +11,21 @@ from toontown.parties import PartyGlobals
|
|||
|
||||
import FireworkShows
|
||||
import random
|
||||
import time
|
||||
|
||||
class DistributedFireworkShowAI(DistributedObjectAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedFireworkShowAI")
|
||||
|
||||
|
||||
def __init__(self, air):
|
||||
DistributedObjectAI.__init__(self, air)
|
||||
self.air = air
|
||||
|
||||
|
||||
def startShow(self, eventId, style, timeStamp):
|
||||
taskMgr.doMethodLater(FireworkShows.getShowDuration(eventId, style), self.requestDelete, 'delete%i' % self.doId, [])
|
||||
|
||||
|
||||
def d_startShow(self, eventId, style, timeStamp):
|
||||
self.sendUpdate('startShow', [eventId, style, random.randint(0,1), timeStamp])
|
||||
|
||||
|
||||
def b_startShow(self, eventId, style, timeStamp):
|
||||
self.startShow(eventId, style, timeStamp)
|
||||
self.d_startShow(eventId, style, timeStamp)
|
||||
|
@ -49,9 +50,9 @@ def fireworks(showName='july4'):
|
|||
numShows = len(FireworkShows.shows.get(showType, []))
|
||||
showIndex = random.randint(0, numShows - 1)
|
||||
for hood in simbase.air.hoods:
|
||||
if hood.safezone == ToontownGlobals.GolfZone:
|
||||
if hood.HOOD == ToontownGlobals.GolfZone:
|
||||
continue
|
||||
fireworksShow = DistributedFireworkShowAI(simbase.air)
|
||||
fireworksShow.generateWithRequired(hood.safezone)
|
||||
fireworksShow.generateWithRequired(hood.HOOD)
|
||||
fireworksShow.b_startShow(showType, showIndex, globalClockDelta.getRealNetworkTime())
|
||||
return 'Started fireworks in all playgrounds!'
|
||||
return 'Started fireworks in all playgrounds!'
|
||||
|
|
|
@ -99,24 +99,8 @@ class FireworkEffect(NodePath):
|
|||
elif self.trailTypeId == FireworkTrailType.Polygonal:
|
||||
r = 0.75
|
||||
mColor = Vec4(1, 1, 1, 1)
|
||||
vertex_list = [Vec4(r, 0.0, r, 1.0),
|
||||
Vec4(r, 0.0, -r, 1.0),
|
||||
Vec4(-r, 0.0, -r, 1.0),
|
||||
Vec4(-r, 0.0, r, 1.0),
|
||||
Vec4(r, 0.0, r, 1.0)]
|
||||
motion_color = [mColor,
|
||||
mColor,
|
||||
mColor,
|
||||
mColor,
|
||||
mColor]
|
||||
trailEffect = PolyTrail(None, vertex_list, motion_color, 0.5)
|
||||
trailEffect.setUnmodifiedVertexColors(motion_color)
|
||||
trailEffect.reparentTo(self.effectsNode)
|
||||
trailEffect.motion_trail.geom_node_path.setTwoSided(False)
|
||||
trailEffect.setBlendModeOn()
|
||||
trailEffect.setLightOff()
|
||||
self.trailEffects.append(trailEffect)
|
||||
self.trailEffectsIval.append(Func(trailEffect.beginTrail))
|
||||
vertex_list = [Vec4(r, 0.0, r, 1.0), Vec4(r, 0.0, -r, 1.0), Vec4(-r, 0.0, -r, 1.0), Vec4(-r, 0.0, r, 1.0), Vec4(r, 0.0, r, 1.0)]
|
||||
motion_color = [mColor, mColor, mColor, mColor, mColor]
|
||||
elif self.trailTypeId == FireworkTrailType.Glow:
|
||||
trailEffect = GlowTrail.getEffect()
|
||||
if trailEffect:
|
||||
|
|
|
@ -42,7 +42,7 @@ class FireworkShowMixin:
|
|||
self.getSky().clearColorScale()
|
||||
if hasattr(base, 'localAvatar') and base.localAvatar:
|
||||
base.localAvatar.clearColorScale()
|
||||
base.setBackgroundColor(DefaultBackgroundColor)
|
||||
self.trySettingBackground(1)
|
||||
self.ignoreAll()
|
||||
return
|
||||
|
||||
|
@ -61,7 +61,7 @@ class FireworkShowMixin:
|
|||
self.timestamp = timestamp
|
||||
self.showMusic = None
|
||||
self.eventId = eventId
|
||||
if base.config.GetBool('want-old-fireworks', 0):
|
||||
if base.config.GetBool('want-old-fireworks', False):
|
||||
self.currentShow = self.getFireworkShowIval(eventId, style, songId, t)
|
||||
if self.currentShow:
|
||||
self.currentShow.start(t)
|
||||
|
@ -69,10 +69,21 @@ class FireworkShowMixin:
|
|||
self.createFireworkShow()
|
||||
if t > self.fireworkShow.getShowDuration():
|
||||
return
|
||||
|
||||
preShow = self.preShow(eventId, songId, t)
|
||||
postShow = self.postShow(eventId)
|
||||
beginFireworkShow = Func(self.beginFireworkShow, max(0, t), root)
|
||||
self.currentShow = Sequence(preShow, beginFireworkShow, Wait(max(0, self.fireworkShow.getShowDuration() - max(0, t))), postShow)
|
||||
|
||||
# TODO: Fix this properly. Hack-fixed for July 4th
|
||||
delay = Wait(max(0, self.fireworkShow.getShowDuration() - max(0, t)))
|
||||
if eventId == JULY4_FIREWORKS:
|
||||
delay = Wait(max(0, self.fireworkShow.getShowDuration() - max(0, t)) - 9.5)
|
||||
elif eventId == NEWYEARS_FIREWORKS:
|
||||
delay = Wait(max(0, self.fireworkShow.getShowDuration() - max(0, t)) + 1.0)
|
||||
elif eventId == PartyGlobals.FireworkShows.Summer:
|
||||
delay = Wait(max(0, self.fireworkShow.getShowDuration() - max(0, t)) - 5.0)
|
||||
|
||||
self.currentShow = Sequence(preShow, beginFireworkShow, delay, postShow)
|
||||
self.currentShow.start()
|
||||
return
|
||||
|
||||
|
@ -132,17 +143,22 @@ class FireworkShowMixin:
|
|||
if self.fireworkShow and not self.fireworkShow.isEmpty():
|
||||
self.fireworkShow.setColorScaleOff(0)
|
||||
return
|
||||
# Election Only
|
||||
self.electionFloor = base.render.find('**/ShowFloor')
|
||||
self.slappyBalloon = base.render.find('**/airballoon.egg')
|
||||
if self.__checkHoodValidity() and hasattr(base.cr.playGame, 'hood') and base.cr.playGame.hood and hasattr(base.cr.playGame.hood, 'sky') and base.cr.playGame.hood.sky:
|
||||
# Election Only
|
||||
hood = self.getHood()
|
||||
if hood.id == ToontownCentral:
|
||||
preShow = Sequence(Func(base.localAvatar.setSystemMessage, 0, startMessage), Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(0.0, 0.0, 0.0, 1.0)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(0.25, 0.25, 0.35, 1)), LerpColorScaleInterval(self.electionFloor, 2.5, Vec4(0.25, 0.25, 0.35, 1)), LerpColorScaleInterval(self.slappyBalloon, 2.5, Vec4(0.55, 0.55, 0.65, 1)), LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(0.85, 0.85, 0.85, 1)), Func(__lightDecorationOn__)), Func(base.setBackgroundColor, Vec4(0, 0, 0, 1)), Func(self.__checkDDFog), Func(base.camLens.setFar, 1000.0), Func(base.cr.playGame.hood.sky.hide), Func(base.localAvatar.setSystemMessage, 0, instructionMessage), Func(self.getLoader().music.stop), Wait(2.0), Func(base.playMusic, self.showMusic, 0, 1, 0.8, max(0, startT)))
|
||||
else:
|
||||
preShow = Sequence(Func(base.localAvatar.setSystemMessage, 0, startMessage), Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(0.0, 0.0, 0.0, 1.0)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(0.25, 0.25, 0.35, 1)), LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(0.85, 0.85, 0.85, 1)), Func(__lightDecorationOn__)), Func(base.setBackgroundColor, Vec4(0, 0, 0, 1)), Func(self.__checkDDFog), Func(base.camLens.setFar, 1000.0), Func(base.cr.playGame.hood.sky.hide), Func(base.localAvatar.setSystemMessage, 0, instructionMessage), Func(self.getLoader().music.stop), Wait(2.0), Func(base.playMusic, self.showMusic, 0, 1, 0.8, max(0, startT)))
|
||||
#preShow = Sequence(Func(base.localAvatar.setSystemMessage, 0, startMessage), Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(0.0, 0.0, 0.0, 1.0)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(0.25, 0.25, 0.35, 1)), LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(0.85, 0.85, 0.85, 1)), Func(__lightDecorationOn__)), Func(base.setBackgroundColor, Vec4(0, 0, 0, 1)), Func(self.__checkDDFog), Func(base.camLens.setFar, 1000.0), Func(base.cr.playGame.hood.sky.hide), Func(base.localAvatar.setSystemMessage, 0, instructionMessage), Func(self.getLoader().music.stop), Wait(2.0), Func(base.playMusic, self.showMusic, 0, 1, 0.8, max(0, startT)))
|
||||
preShow = Sequence(
|
||||
Func(base.localAvatar.setSystemMessage, 0, startMessage),
|
||||
Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(0.0, 0.0, 0.0, 1.0)),
|
||||
LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(0.25, 0.25, 0.35, 1)),
|
||||
LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(0.85, 0.85, 0.85, 1)),
|
||||
Func(__lightDecorationOn__)),
|
||||
Func(self.trySettingBackground, 0),
|
||||
Func(self.__checkDDFog),
|
||||
Func(base.camLens.setFar, 1000.0),
|
||||
Func(base.cr.playGame.hood.sky.hide),
|
||||
Func(base.localAvatar.setSystemMessage, 0, instructionMessage),
|
||||
Func(self.getLoader().music.stop),
|
||||
Wait(2.0),
|
||||
Func(base.playMusic, self.showMusic, 0, 1, 0.8, max(0, startT))
|
||||
)
|
||||
return preShow
|
||||
return None
|
||||
|
||||
|
@ -154,6 +170,16 @@ class FireworkShowMixin:
|
|||
else:
|
||||
base.camLens.setFar(DefaultCameraFar)
|
||||
|
||||
def trySettingBackground(self, color):
|
||||
if base.localAvatar.isBookOpen():
|
||||
# Our Shtickerbook is open with a custom background already set,
|
||||
# so we don't want to screw that up.
|
||||
pass
|
||||
elif color == 0:
|
||||
base.setBackgroundColor(Vec4(0, 0, 0, 1))
|
||||
else:
|
||||
base.setBackgroundColor(DefaultBackgroundColor)
|
||||
|
||||
def postShow(self, eventId):
|
||||
if eventId == JULY4_FIREWORKS:
|
||||
endMessage = TTLocalizer.FireworksJuly4Ending
|
||||
|
@ -168,13 +194,20 @@ class FireworkShowMixin:
|
|||
return None
|
||||
|
||||
if self.__checkHoodValidity() and hasattr(base.cr.playGame.hood, 'sky') and base.cr.playGame.hood.sky:
|
||||
# Election Only
|
||||
hood = self.getHood()
|
||||
if hood.id == ToontownCentral:
|
||||
postShow = Sequence(Func(base.cr.playGame.hood.sky.show), Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(self.electionFloor, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(self.slappyBalloon, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(1, 1, 1, 1))), Func(self.__restoreDDFog), Func(self.restoreCameraLens), Func(base.setBackgroundColor, DefaultBackgroundColor), Func(self.showMusic.stop), Func(base.localAvatar.setSystemMessage, 0, endMessage))
|
||||
else:
|
||||
postShow = Sequence(Func(base.cr.playGame.hood.sky.show), Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(1, 1, 1, 1))), Func(self.__restoreDDFog), Func(self.restoreCameraLens), Func(base.setBackgroundColor, DefaultBackgroundColor), Func(self.showMusic.stop), Func(base.localAvatar.setSystemMessage, 0, endMessage))
|
||||
#postShow = Sequence(Func(base.cr.playGame.hood.sky.show), Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(1, 1, 1, 1))), Func(self.__restoreDDFog), Func(self.restoreCameraLens), Func(base.setBackgroundColor, DefaultBackgroundColor), Func(self.showMusic.stop), Func(base.localAvatar.setSystemMessage, 0, endMessage))
|
||||
postShow = Sequence(
|
||||
Func(base.cr.playGame.hood.sky.show),
|
||||
Parallel(
|
||||
LerpColorScaleInterval(base.cr.playGame.hood.sky, 2.5, Vec4(1, 1, 1, 1)),
|
||||
LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(1, 1, 1, 1)),
|
||||
LerpColorScaleInterval(base.localAvatar, 2.5, Vec4(1, 1, 1, 1))
|
||||
),
|
||||
Func(self.__restoreDDFog),
|
||||
Func(self.restoreCameraLens),
|
||||
Func(self.trySettingBackground, 1),
|
||||
Func(self.showMusic.stop),
|
||||
Func(base.localAvatar.setSystemMessage, 0, endMessage)
|
||||
)
|
||||
|
||||
if self.restorePlaygroundMusic:
|
||||
postShow.append(Wait(2.0))
|
||||
postShow.append(Func(base.playMusic, self.getLoader().music, 1, 1, 0.8))
|
||||
|
@ -195,6 +228,18 @@ class FireworkShowMixin:
|
|||
self.fireworkShow.begin(timeStamp)
|
||||
self.fireworkShow.reparentTo(root)
|
||||
hood = self.getHood()
|
||||
|
||||
# Dammit disney
|
||||
from toontown.hood import TTHood
|
||||
from toontown.hood import DDHood
|
||||
from toontown.hood import MMHood
|
||||
from toontown.hood import BRHood
|
||||
from toontown.hood import DGHood
|
||||
from toontown.hood import DLHood
|
||||
from toontown.hood import GSHood
|
||||
from toontown.hood import OZHood
|
||||
from toontown.hood import GZHood
|
||||
|
||||
if isinstance(hood, TTHood.TTHood):
|
||||
self.fireworkShow.setPos(150, 0, 80)
|
||||
self.fireworkShow.setHpr(90, 0, 0)
|
||||
|
|
|
@ -4,12 +4,13 @@ from toontown.toonbase import ToontownGlobals
|
|||
import HouseGlobals
|
||||
import GardenGlobals
|
||||
import time
|
||||
|
||||
from toontown.fishing.DistributedFishingPondAI import DistributedFishingPondAI
|
||||
from toontown.fishing.DistributedFishingTargetAI import DistributedFishingTargetAI
|
||||
from toontown.fishing.DistributedPondBingoManagerAI import DistributedPondBingoManagerAI
|
||||
from toontown.fishing import FishingTargetGlobals
|
||||
from toontown.safezone.DistributedFishingSpotAI import DistributedFishingSpotAI
|
||||
from toontown.safezone.SZTreasurePlannerAI import SZTreasurePlannerAI
|
||||
from toontown.safezone import TreasureGlobals
|
||||
|
||||
from toontown.estate.DistributedGardenBoxAI import DistributedGardenBoxAI
|
||||
from toontown.estate.DistributedGardenPlotAI import DistributedGardenPlotAI
|
||||
|
@ -28,27 +29,28 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
self.lastEpochTimestamp = 0
|
||||
self.rentalTimestamp = 0
|
||||
self.houses = [None] * 6
|
||||
|
||||
|
||||
self.pond = None
|
||||
self.spots = []
|
||||
|
||||
|
||||
self.targets = []
|
||||
|
||||
self.owner = None
|
||||
|
||||
|
||||
def generate(self):
|
||||
DistributedObjectAI.generate(self)
|
||||
|
||||
|
||||
# Gone fishin'
|
||||
self.pond = DistributedFishingPondAI(simbase.air)
|
||||
self.pond.setArea(ToontownGlobals.MyEstate)
|
||||
self.pond.generateWithRequired(self.zoneId)
|
||||
|
||||
|
||||
for i in range(FishingTargetGlobals.getNumTargets(ToontownGlobals.MyEstate)):
|
||||
target = DistributedFishingTargetAI(self.air)
|
||||
target.setPondDoId(self.pond.getDoId())
|
||||
target.generateWithRequired(self.zoneId)
|
||||
self.targets.append(target)
|
||||
|
||||
|
||||
for i in xrange(6):
|
||||
avItems = self.items[i]
|
||||
for item in avItems:
|
||||
|
@ -86,10 +88,12 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
spot.setPosHpr(46.8254, -113.682, 0.46015, 135, 0, 0)
|
||||
spot.generateWithRequired(self.zoneId)
|
||||
self.spots.append(spot)
|
||||
|
||||
|
||||
def rentItem(self, type, duration):
|
||||
pass # TODO - implement this
|
||||
|
||||
# Let's place some popsicles
|
||||
self.createTreasurePlanner()
|
||||
|
||||
def destroy(self):
|
||||
for house in self.houses:
|
||||
|
@ -102,9 +106,10 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
spot.requestDelete()
|
||||
for target in self.targets:
|
||||
target.requestDelete()
|
||||
del self.targets[:]
|
||||
del self.spots[:]
|
||||
del self.pond
|
||||
|
||||
if self.treasurePlanner:
|
||||
self.treasurePlanner.stop()
|
||||
|
||||
self.requestDelete()
|
||||
|
||||
def setEstateReady(self):
|
||||
|
@ -115,23 +120,28 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def setEstateType(self, type):
|
||||
self.estateType = type
|
||||
|
||||
|
||||
def d_setEstateType(self, type):
|
||||
self.sendUpdate('setEstateType', [type])
|
||||
|
||||
|
||||
def b_setEstateType(self, type):
|
||||
self.setEstateType(type)
|
||||
self.d_setEstateType(type)
|
||||
|
||||
def getEstateType(self):
|
||||
return self.estateType
|
||||
|
||||
|
||||
def setClosestHouse(self, todo0):
|
||||
pass
|
||||
|
||||
def setTreasureIds(self, todo0):
|
||||
pass
|
||||
|
||||
def createTreasurePlanner(self):
|
||||
treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = TreasureGlobals.SafeZoneTreasureSpawns[ToontownGlobals.MyEstate]
|
||||
self.treasurePlanner = SZTreasurePlannerAI(self.zoneId, treasureType, healAmount, spawnPoints, spawnRate, maxTreasures)
|
||||
self.treasurePlanner.start()
|
||||
|
||||
def requestServerTime(self):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.sendUpdateToAvatarId(avId, 'setServerTime', [time.time() % HouseGlobals.DAY_NIGHT_PERIOD])
|
||||
|
@ -141,14 +151,14 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def setDawnTime(self, dawnTime):
|
||||
self.dawnTime = dawnTime
|
||||
|
||||
|
||||
def d_setDawnTime(self, dawnTime):
|
||||
self.sendUpdate('setDawnTime', [dawnTime])
|
||||
|
||||
|
||||
def b_setDawnTime(self, dawnTime):
|
||||
self.setDawnTime(dawnTime)
|
||||
self.d_setDawnTime(dawnTime)
|
||||
|
||||
|
||||
def getDawnTime(self):
|
||||
return self.dawnTime
|
||||
|
||||
|
@ -157,59 +167,59 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def setDecorData(self, decorData):
|
||||
self.decorData = decorData
|
||||
|
||||
|
||||
def d_setDecorData(self, decorData):
|
||||
self.sendUpdate('setDecorData', [decorData])
|
||||
|
||||
|
||||
def b_setDecorData(self, decorData):
|
||||
self.setDecorData(decorData)
|
||||
self.d_setDecorData(decorData)
|
||||
|
||||
|
||||
def getDecorData(self):
|
||||
return self.decorData
|
||||
|
||||
def setLastEpochTimeStamp(self, last): #how do I do this
|
||||
self.lastEpochTimestamp = last
|
||||
|
||||
|
||||
def d_setLastEpochTimeStamp(self, last):
|
||||
self.sendUpdate('setLastEpochTimeStamp', [last])
|
||||
|
||||
|
||||
def b_setLastEpochTimeStamp(self, last):
|
||||
self.setLastEpochTimeStamp(last)
|
||||
self.d_setLastEpochTimeStamp(last)
|
||||
|
||||
|
||||
def getLastEpochTimeStamp(self):
|
||||
return self.lastEpochTimestamp
|
||||
|
||||
def setRentalTimeStamp(self, rental):
|
||||
self.rentalTimestamp = rental
|
||||
|
||||
|
||||
def d_setRentalTimeStamp(self, rental):
|
||||
self.sendUpdate('setRentalTimeStamp', [rental])
|
||||
|
||||
|
||||
def b_setRentalTimeStamp(self, rental):
|
||||
self.setRentalTimeStamp(self, rental)
|
||||
self.b_setRentalTimeStamp(self, rental)
|
||||
|
||||
|
||||
def getRentalTimeStamp(self):
|
||||
return self.rentalTimestamp
|
||||
|
||||
def setRentalType(self, todo0):
|
||||
pass
|
||||
|
||||
|
||||
def getRentalType(self):
|
||||
return 0
|
||||
|
||||
def setSlot0ToonId(self, id):
|
||||
self.toons[0] = id
|
||||
|
||||
|
||||
def d_setSlot0ToonId(self, id):
|
||||
self.sendUpdate('setSlot0ToonId', [id])
|
||||
|
||||
|
||||
def b_setSlot0ToonId(self, id):
|
||||
self.setSlot0ToonId(id)
|
||||
self.d_setSlot0ToonId(id)
|
||||
|
||||
|
||||
def getSlot0ToonId(self):
|
||||
return self.toons[0]
|
||||
|
||||
|
@ -218,37 +228,37 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def d_setSlot0Items(self, items):
|
||||
self.sendUpdate('setSlot5Items', [items])
|
||||
|
||||
|
||||
def b_setSlot0Items(self, items):
|
||||
self.setSlot0Items(items)
|
||||
self.d_setSlot0Items(items)
|
||||
|
||||
|
||||
def getSlot0Items(self):
|
||||
return self.items[0]
|
||||
|
||||
|
||||
def setSlot1ToonId(self, id):
|
||||
self.toons[1] = id
|
||||
|
||||
def d_setSlot1ToonId(self, id):
|
||||
self.sendUpdate('setSlot1ToonId', [id])
|
||||
|
||||
|
||||
def b_setSlot1ToonId(self, id):
|
||||
self.setSlot1ToonId(id)
|
||||
self.d_setSlot1ToonId(id)
|
||||
|
||||
|
||||
def getSlot1ToonId(self):
|
||||
return self.toons[1]
|
||||
|
||||
|
||||
def setSlot1Items(self, items):
|
||||
self.items[1] = items
|
||||
|
||||
|
||||
def d_setSlot1Items(self, items):
|
||||
self.sendUpdate('setSlot2Items', [items])
|
||||
|
||||
|
||||
def b_setSlot1Items(self, items):
|
||||
self.setSlot2Items(items)
|
||||
self.d_setSlot2Items(items)
|
||||
|
||||
|
||||
def getSlot1Items(self):
|
||||
return self.items[1]
|
||||
|
||||
|
@ -257,11 +267,11 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def d_setSlot2ToonId(self, id):
|
||||
self.sendUpdate('setSlot2ToonId', [id])
|
||||
|
||||
|
||||
def b_setSlot2ToonId(self, id):
|
||||
self.setSlot2ToonId(id)
|
||||
self.d_setSlot2ToonId(id)
|
||||
|
||||
|
||||
def getSlot2ToonId(self):
|
||||
return self.toons[2]
|
||||
|
||||
|
@ -270,90 +280,90 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def d_setSlot2Items(self, items):
|
||||
self.sendUpdate('setSlot2Items', [items])
|
||||
|
||||
|
||||
def b_setSlot2Items(self, items):
|
||||
self.setSlot2Items(items)
|
||||
self.d_setSlot2Items(items)
|
||||
|
||||
|
||||
def getSlot2Items(self):
|
||||
return self.items[2]
|
||||
|
||||
def setSlot3ToonId(self, id):
|
||||
self.toons[3] = id
|
||||
|
||||
|
||||
def d_setSlot3ToonId(self, id):
|
||||
self.sendUpdate('setSlot3ToonId', [id])
|
||||
|
||||
|
||||
def b_setSlot3ToonId(self, id):
|
||||
self.setSlot3ToonId(id)
|
||||
self.d_setSlot3ToonId(id)
|
||||
|
||||
|
||||
def getSlot3ToonId(self):
|
||||
return self.toons[3]
|
||||
|
||||
def setSlot3Items(self, items):
|
||||
self.items[3] = items
|
||||
|
||||
|
||||
def d_setSlot3Items(self, items):
|
||||
self.sendUpdate('setSlot3Items', [items])
|
||||
|
||||
|
||||
def b_setSlot3Items(self, items):
|
||||
self.setSlot3Items(items)
|
||||
self.d_setSlot3Items(items)
|
||||
|
||||
|
||||
def getSlot3Items(self):
|
||||
return self.items[3]
|
||||
|
||||
def setSlot4ToonId(self, id):
|
||||
self.toons[4] = id
|
||||
|
||||
|
||||
def d_setSlot4ToonId(self, id):
|
||||
self.sendUpdate('setSlot4ToonId', [id])
|
||||
|
||||
|
||||
def b_setSlot5ToonId(self, id):
|
||||
self.setSlot4ToonId(id)
|
||||
self.d_setSlot4ToonId(id)
|
||||
|
||||
|
||||
def getSlot4ToonId(self):
|
||||
return self.toons[4]
|
||||
|
||||
|
||||
def setSlot4Items(self, items):
|
||||
self.items[4] = items
|
||||
|
||||
|
||||
def d_setSlot4Items(self, items):
|
||||
self.sendUpdate('setSlot4Items', [items])
|
||||
|
||||
|
||||
def b_setSlot4Items(self, items):
|
||||
self.setSlot4Items(items)
|
||||
self.d_setSlot4Items(items)
|
||||
|
||||
|
||||
def getSlot4Items(self):
|
||||
return self.items[4]
|
||||
|
||||
def setSlot5ToonId(self, id):
|
||||
self.toons[5] = id
|
||||
|
||||
|
||||
def d_setSlot5ToonId(self, id):
|
||||
self.sendUpdate('setSlot5ToonId', [id])
|
||||
|
||||
|
||||
def b_setSlot5ToonId(self, id):
|
||||
self.setSlot5ToonId(id)
|
||||
self.d_setSlot5ToonId(id)
|
||||
|
||||
|
||||
def getSlot5ToonId(self):
|
||||
return self.toons[5]
|
||||
|
||||
def setSlot5Items(self, items):
|
||||
self.items[5] = items
|
||||
|
||||
|
||||
def d_setSlot5Items(self, items):
|
||||
self.sendUpdate('setSlot5Items', [items])
|
||||
|
||||
|
||||
def b_setSlot5Items(self, items):
|
||||
self.setSlot5Items(items)
|
||||
self.d_setSlot5Items(items)
|
||||
|
||||
|
||||
def getSlot5Items(self):
|
||||
return self.items[5]
|
||||
|
||||
|
@ -362,14 +372,14 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
if i >= 6:
|
||||
return
|
||||
self.toons[i] = idList[i]
|
||||
|
||||
|
||||
def d_setIdList(self, idList):
|
||||
self.sendUpdate('setIdList', [idList])
|
||||
|
||||
|
||||
def b_setIdList(self, idList):
|
||||
self.setIdList(idList)
|
||||
self.d_setIdLst(idList)
|
||||
|
||||
|
||||
def completeFlowerSale(self, todo0):
|
||||
pass
|
||||
|
||||
|
@ -378,14 +388,14 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def setClouds(self, clouds):
|
||||
self.cloudType = clouds
|
||||
|
||||
|
||||
def d_setClouds(self, clouds):
|
||||
self.sendUpdate('setClouds', [clouds])
|
||||
|
||||
|
||||
def b_setClouds(self, clouds):
|
||||
self.setClouds(clouds)
|
||||
self.d_setClouds(clouds)
|
||||
|
||||
|
||||
def getClouds(self):
|
||||
return self.cloudType
|
||||
|
||||
|
@ -394,7 +404,7 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
|
||||
def gameTableOver(self):
|
||||
pass
|
||||
|
||||
|
||||
def updateToons(self):
|
||||
self.d_setSlot0ToonId(self.toons[0])
|
||||
self.d_setSlot1ToonId(self.toons[1])
|
||||
|
@ -403,7 +413,7 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
self.d_setSlot4ToonId(self.toons[4])
|
||||
self.d_setSlot5ToonId(self.toons[5])
|
||||
self.sendUpdate('setIdList', [self.toons])
|
||||
|
||||
|
||||
def updateItems(self):
|
||||
self.d_setSlot0Items(self.items[0])
|
||||
self.d_setSlot1Items(self.items[1])
|
||||
|
@ -440,4 +450,4 @@ class DistributedEstateAI(DistributedObjectAI):
|
|||
plot.generateWithRequired(self.zoneId)
|
||||
self.items[houseIndex] = items
|
||||
self.updateItems()
|
||||
avatar.b_setGardenStarted(1)
|
||||
avatar.b_setGardenStarted(1)
|
||||
|
|
|
@ -324,7 +324,6 @@ class EstateManagerAI(DistributedObjectAI):
|
|||
if not toon:
|
||||
self.air.writeServerEvent('suspicious', avId=senderId, issue='Sent exitEstate() but not on district!')
|
||||
return
|
||||
|
||||
self._unmapFromEstate(toon)
|
||||
self._unloadEstate(toon)
|
||||
|
||||
|
|
|
@ -489,5 +489,6 @@ class TTRFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
['setDefaultShard' , fields['setDefaultShard'][0]],
|
||||
['setLastHood' , fields['setLastHood'][0]],
|
||||
['setDNAString' , fields['setDNAString'][0]],
|
||||
['setLastSeen' , fields.get('setLastSeen', [0])[0]],
|
||||
]
|
||||
self.sendUpdateToAvatarId(requesterId, 'friendDetails', [fields['ID'], cPickle.dumps(details)])
|
||||
|
|
|
@ -10,5 +10,19 @@ class DGHoodAI(SZHoodAI):
|
|||
|
||||
def createZone(self):
|
||||
SZHoodAI.createZone(self)
|
||||
|
||||
self.butterflies = []
|
||||
self.spawnObjects()
|
||||
|
||||
self.flower = DistributedDGFlowerAI(self.air)
|
||||
self.flower.generateWithRequired(self.HOOD)
|
||||
self.createButterflies()
|
||||
|
||||
def createButterflies(self):
|
||||
playground = ButterflyGlobals.DG
|
||||
for area in range(ButterflyGlobals.NUM_BUTTERFLY_AREAS[playground]):
|
||||
for b in range(ButterflyGlobals.NUM_BUTTERFLIES[playground]):
|
||||
butterfly = DistributedButterflyAI(self.air)
|
||||
butterfly.setArea(playground, area)
|
||||
butterfly.setState(0, 0, 0, 1, 1)
|
||||
butterfly.generateWithRequired(self.HOOD)
|
||||
self.butterflies.append(butterfly)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from toontown.toonbase import ToontownGlobals
|
||||
from toontown.hood import HoodAI
|
||||
from toontown.building.DistributedBuildingMgrAI import DistributedBuildingMgrAI
|
||||
|
||||
class GSHoodAI(HoodAI.HoodAI):
|
||||
HOOD = 8000
|
||||
HOOD = ToontownGlobals.GoofySpeedway
|
||||
|
||||
def __init__(self, air):
|
||||
HoodAI.HoodAI.__init__(self, air)
|
||||
|
|
|
@ -543,6 +543,9 @@ class Place(StateData.StateData, FriendsListManager.FriendsListManager):
|
|||
def enterDoorIn(self, requestStatus):
|
||||
NametagGlobals.setMasterArrowsOn(0)
|
||||
door = base.cr.doId2do.get(requestStatus['doorDoId'])
|
||||
if door is None:
|
||||
# We're about to die anyway because door is None, so raise a StandardError with more information
|
||||
raise StandardError("Place's door is None! Place: %s, requestStatus: %s" % (str(self.__class__)), str(requestStatus))
|
||||
door.readyToExit()
|
||||
base.localAvatar.obscureMoveFurnitureButton(1)
|
||||
base.localAvatar.startQuestMap()
|
||||
|
|
|
@ -6,7 +6,7 @@ from pandac.PandaModules import *
|
|||
from MakeAToonGlobals import *
|
||||
from toontown.toonbase import TTLocalizer
|
||||
import ShuffleButton
|
||||
import random
|
||||
from random import random, choice
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
|
||||
class ColorShop(StateData.StateData):
|
||||
|
@ -15,7 +15,6 @@ class ColorShop(StateData.StateData):
|
|||
def __init__(self, doneEvent):
|
||||
StateData.StateData.__init__(self, doneEvent)
|
||||
self.toon = None
|
||||
self.colorAll = 1
|
||||
return
|
||||
|
||||
def getGenderColorList(self, dna):
|
||||
|
@ -34,9 +33,9 @@ class ColorShop(StateData.StateData):
|
|||
self.armChoice = colorList.index(self.dna.armColor)
|
||||
self.legChoice = colorList.index(self.dna.legColor)
|
||||
except:
|
||||
self.headChoice = random.choice(colorList)
|
||||
self.armChoice = self.headChoice
|
||||
self.legChoice = self.headChoice
|
||||
self.headChoice = choice(colorList)
|
||||
self.armChoice = choice(colorList)
|
||||
self.legChoice = choice(colorList)
|
||||
self.__swapHeadColor(0)
|
||||
self.__swapArmColor(0)
|
||||
self.__swapLegColor(0)
|
||||
|
@ -44,7 +43,7 @@ class ColorShop(StateData.StateData):
|
|||
self.startColor = 0
|
||||
self.acceptOnce('last', self.__handleBackward)
|
||||
self.acceptOnce('next', self.__handleForward)
|
||||
choicePool = [self.getGenderColorList(self.dna), self.getGenderColorList(self.dna), self.getGenderColorList(self.dna)]
|
||||
choicePool = [colorList, colorList, colorList]
|
||||
self.shuffleButton.setChoicePool(choicePool)
|
||||
self.accept(self.shuffleFetchMsg, self.changeColor)
|
||||
self.acceptOnce('MAT-newToonCreated', self.shuffleButton.cleanHistory)
|
||||
|
@ -219,12 +218,14 @@ class ColorShop(StateData.StateData):
|
|||
oldArmColorIndex = colorList.index(self.toon.style.armColor)
|
||||
oldLegColorIndex = colorList.index(self.toon.style.legColor)
|
||||
self.__swapHeadColor(newHeadColorIndex - oldHeadColorIndex)
|
||||
if self.colorAll:
|
||||
self.__swapArmColor(newHeadColorIndex - oldArmColorIndex)
|
||||
self.__swapLegColor(newHeadColorIndex - oldLegColorIndex)
|
||||
else:
|
||||
# We want colors to shuffle all parts of the body sometimes, but we want some solid
|
||||
# colors thrown in there as well. We'll increase the chances of that happening.
|
||||
if config.GetBool('want-shuffle-colors', 1) and random() <= 0.4:
|
||||
self.__swapArmColor(newArmColorIndex - oldArmColorIndex)
|
||||
self.__swapLegColor(newLegColorIndex - oldLegColorIndex)
|
||||
else:
|
||||
self.__swapArmColor(newHeadColorIndex - oldArmColorIndex)
|
||||
self.__swapLegColor(newHeadColorIndex - oldLegColorIndex)
|
||||
|
||||
def getCurrToonSetting(self):
|
||||
return [self.dna.headColor, self.dna.armColor, self.dna.legColor]
|
||||
|
|
|
@ -161,17 +161,17 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
|
||||
def fishCollision(self, collEntry):
|
||||
avId = int(collEntry.getFromNodePath().getName())
|
||||
if avId != self.localAvId:
|
||||
return # This collision event doesn't involve me. ???
|
||||
toonSD = self.toonSDs[avId]
|
||||
name = collEntry.getIntoNodePath().getName()
|
||||
if len(name) >= 7:
|
||||
if name[0:6] == 'crabby':
|
||||
self.sendUpdate('handleCrabCollision', [avId, toonSD.status])
|
||||
if name.startswith('crabby'):
|
||||
self.sendUpdate('handleCrabCollision', [toonSD.status])
|
||||
else:
|
||||
spawnerId = int(name[2])
|
||||
spawnId = int(name[3:len(name)])
|
||||
if self.spawners[spawnerId].fishArray.has_key(spawnId):
|
||||
self.sendUpdate('handleFishCollision', [avId,
|
||||
spawnId,
|
||||
self.sendUpdate('handleFishCollision', [spawnId,
|
||||
spawnerId,
|
||||
toonSD.status])
|
||||
|
||||
|
@ -780,21 +780,32 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
def setTreasureGrabbed(self, avId, chestId):
|
||||
if not self.hasLocalToon:
|
||||
return
|
||||
|
||||
if self.grabbingTreasure == chestId:
|
||||
self.grabbingTreasure = -1
|
||||
|
||||
toonSD = self.toonSDs.get(avId)
|
||||
if toonSD and toonSD.status == 'normal':
|
||||
toonSD.fsm.request('treasure')
|
||||
self.treasures[chestId].moveLerp.pause()
|
||||
self.treasures[chestId].moveLerp = Sequence()
|
||||
self.treasures[chestId].chestNode.setIntoCollideMask(BitMask32.allOff())
|
||||
self.treasures[chestId].treasureNode.reparentTo(self.getAvatar(avId))
|
||||
headparts = self.getAvatar(avId).getHeadParts()
|
||||
pos = headparts[2].getPos()
|
||||
self.treasures[chestId].treasureNode.setPos(pos + Point3(0, 0.2, 3))
|
||||
self.treasures[chestId].grabbedId = avId
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
self.playSound('getGold')
|
||||
if not toonSD:
|
||||
return # Not an avId we know about??? Oh well.
|
||||
|
||||
if avId == self.localAvId and toonSD.status == 'freeze':
|
||||
# It's great that we were given a treasure and all, but because
|
||||
# we're currently stunned by a fish (that we hit just before touching
|
||||
# the treasure), we can't keep it...
|
||||
self.sendUpdate('dropTreasure', [])
|
||||
return
|
||||
|
||||
toonSD.fsm.request('treasure')
|
||||
self.treasures[chestId].moveLerp.pause()
|
||||
self.treasures[chestId].moveLerp = Sequence()
|
||||
self.treasures[chestId].chestNode.setIntoCollideMask(BitMask32.allOff())
|
||||
self.treasures[chestId].treasureNode.reparentTo(self.getAvatar(avId))
|
||||
headparts = self.getAvatar(avId).getHeadParts()
|
||||
pos = headparts[2].getPos()
|
||||
self.treasures[chestId].treasureNode.setPos(pos + Point3(0, 0.2, 3))
|
||||
self.treasures[chestId].grabbedId = avId
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
self.playSound('getGold')
|
||||
|
||||
def __spawnCrabTask(self):
|
||||
taskMgr.remove(self.CRAB_TASK)
|
||||
|
@ -844,12 +855,12 @@ class DistributedDivingGame(DistributedMinigame):
|
|||
if distance < soundRange:
|
||||
crabVolume = (soundRange - distance) / soundRange
|
||||
crabSoundInterval = SoundInterval(self.crabSound, loop=0, duration=1.6, startTime=0.0)
|
||||
seq = Sequence(Wait(wait), LerpPosInterval(crab, duration=xTime, startPos=Point3(crabX, 0, -40), pos=Point3(goalX, 0, -40), blendType='easeIn'), Parallel(Func(self.grabCrapVolume, crab), LerpPosInterval(crab, duration=zTime, startPos=Point3(goalX, 0, -40), pos=Point3(goalX, 0, goalZ), blendType='easeOut')), LerpPosInterval(crab, duration=zTime, startPos=Point3(goalX, 0, goalZ), pos=Point3(goalX, 0, -40), blendType='easeInOut'))
|
||||
seq = Sequence(Wait(wait), LerpPosInterval(crab, duration=xTime, startPos=Point3(crabX, 0, -40), pos=Point3(goalX, 0, -40), blendType='easeIn'), Parallel(Func(self.grabCrabVolume, crab), LerpPosInterval(crab, duration=zTime, startPos=Point3(goalX, 0, -40), pos=Point3(goalX, 0, goalZ), blendType='easeOut')), LerpPosInterval(crab, duration=zTime, startPos=Point3(goalX, 0, goalZ), pos=Point3(goalX, 0, -40), blendType='easeInOut'))
|
||||
crab.moveLerp.pause()
|
||||
crab.moveLerp = seq
|
||||
crab.moveLerp.start(ts)
|
||||
|
||||
def grabCrapVolume(self, crab):
|
||||
def grabCrabVolume(self, crab):
|
||||
if crab:
|
||||
distance = base.localAvatar.getDistance(crab)
|
||||
self.crabVolume = 0
|
||||
|
|
|
@ -427,38 +427,37 @@ class DistributedDivingGameAI(DistributedMinigameAI):
|
|||
offset])
|
||||
return
|
||||
|
||||
def handleCrabCollision(self, avId, status):
|
||||
def handleCrabCollision(self, status):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if avId not in self.avIdList:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='DivingGameAI.handleCrabCollision: invalid avId')
|
||||
return
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
self.sendUpdate('setTreasureDropped', [avId, timestamp])
|
||||
self.scoreTracking[avId][1] += 1
|
||||
if status == 'normal' or status == 'treasure':
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
self.sendUpdate('performCrabCollision', [avId, timestamp])
|
||||
if status == 'treasure':
|
||||
if avId in self.treasureHolders:
|
||||
self.treasureHolders[self.treasureHolders.index(avId)] = 0
|
||||
self.scoreTracking[avId][3] += 1
|
||||
else:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='DivingGameAI.handleCrabCollision: reported "treasure drop" without holding treasure')
|
||||
|
||||
def handleFishCollision(self, avId, spawnId, spawnerId, status):
|
||||
self.dropTreasure()
|
||||
|
||||
def handleFishCollision(self, spawnId, spawnerId, status):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
if avId not in self.avIdList:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='DivingGameAI.handleFishCollision: invalid avId')
|
||||
return
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
self.sendUpdate('setTreasureDropped', [avId, timestamp])
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
self.scoreTracking[avId][0] += 1
|
||||
if status == 'treasure':
|
||||
if avId in self.treasureHolders:
|
||||
self.treasureHolders[self.treasureHolders.index(avId)] = 0
|
||||
self.scoreTracking[avId][3] += 1
|
||||
else:
|
||||
self.air.writeServerEvent('suspicious', avId=avId, issue='DivingGameAI.handleFishCollision: reported "treasure drop" without holding treasure')
|
||||
self.sendUpdate('performFishCollision', [avId,
|
||||
spawnId,
|
||||
spawnerId,
|
||||
timestamp])
|
||||
|
||||
self.dropTreasure()
|
||||
|
||||
def dropTreasure(self):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
timestamp = globalClockDelta.getFrameNetworkTime()
|
||||
if avId in self.treasureHolders:
|
||||
self.treasureHolders[self.treasureHolders.index(avId)] = 0
|
||||
self.scoreTracking[avId][3] += 1
|
||||
self.sendUpdate('setTreasureDropped', [avId, timestamp])
|
||||
|
|
|
@ -261,10 +261,12 @@ class QuestManagerAI:
|
|||
tier = toon.getRewardHistory()[0]
|
||||
if Quests.avatarHasAllRequiredRewards(toon, tier):
|
||||
# They have all the rewards needed for the next tier.
|
||||
if not Quests.avatarWorkingOnRequiredRewards(toon) and tier != Quests.ELDER_TIER:
|
||||
# They have no ToonTasks in their current tier, and they're also
|
||||
# not an old peasant.
|
||||
tier += 1
|
||||
if not Quests.avatarWorkingOnRequiredRewards(toon):
|
||||
# Check to make sure they are not on the LOOPING_FINAL_TIER
|
||||
if tier != Quests.LOOPING_FINAL_TIER:
|
||||
tier += 1
|
||||
|
||||
# Set the tier
|
||||
toon.b_setRewardHistory(tier, [])
|
||||
else:
|
||||
# They're eligible for a tier upgrade, but haven't finished all
|
||||
|
@ -368,4 +370,22 @@ class QuestManagerAI:
|
|||
# only catch one item at a time via fishing.
|
||||
return quest.getItem()
|
||||
# Nope, no fishing quests, or we're out of luck. Too bad.
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def hasTailorClothingTicket(self, toon, npc):
|
||||
for index, quest in enumerate(self.__toonQuestsList2Quests(toon.quests)):
|
||||
isComplete = quest.getCompletionStatus(toon, toon.quests[index], npc)
|
||||
if isComplete == Quests.COMPLETE:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def removeClothingTicket(self, toon, npc):
|
||||
for index, quest in enumerate(self.__toonQuestsList2Quests(toon.quests)):
|
||||
questId, fromNpcId, toNpcId, rewardId, toonProgress = toon.quests[index]
|
||||
isComplete = quest.getCompletionStatus(toon, toon.quests[index], npc)
|
||||
if isComplete == Quests.COMPLETE:
|
||||
toon.removeQuest(questId)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
|
@ -7,6 +7,7 @@ TreasureBR = 3
|
|||
TreasureMM = 4
|
||||
TreasureDL = 5
|
||||
TreasureOZ = 6
|
||||
TreasureE = 7
|
||||
|
||||
TreasureModels = {
|
||||
TreasureTT: (
|
||||
|
@ -37,6 +38,10 @@ TreasureModels = {
|
|||
'phase_6/models/props/acorn_treasure',
|
||||
'phase_4/audio/sfx/SZ_DD_treasure.ogg',
|
||||
),
|
||||
TreasureE: (
|
||||
'phase_5.5/models/props/popsicle_treasure',
|
||||
'phase_4/audio/sfx/SZ_DD_treasure.ogg',
|
||||
),
|
||||
}
|
||||
|
||||
SafeZoneTreasureSpawns = {
|
||||
|
@ -225,4 +230,26 @@ SafeZoneTreasureSpawns = {
|
|||
10, # Rate
|
||||
5 # Maximum
|
||||
),
|
||||
ToontownGlobals.MyEstate: (
|
||||
TreasureE, 2, # +2 laff
|
||||
[
|
||||
(102.9, 14.17, 0.57),
|
||||
(131.3, 45.31, 0.42),
|
||||
(24.58, -1.28, 11.75),
|
||||
(-1.5, -99.63, 4.3),
|
||||
(14.04, -133.65, -10.0),
|
||||
(-89.45, -134.26, 0.42),
|
||||
(-99.15, -87.3407, 0.52),
|
||||
(-132.528, 31.255, 0.42),
|
||||
(-44.8, 42.61, 11.8),
|
||||
(1.31, 65.17, 5.2),
|
||||
(56.9, 13.06, 29.1),
|
||||
(-57.5, 14.0, 2.88),
|
||||
(17.88, 93.89, 0.4),
|
||||
(-14.39, -164.3, 0.5),
|
||||
(-125.6, -64.82, 0.5),
|
||||
],
|
||||
10, # Rate
|
||||
4 # Maximum
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1148,7 +1148,7 @@ class DistributedSuitPlannerAI(DistributedObjectAI.DistributedObjectAI, SuitPlan
|
|||
self.notify.info('No more room for buildings, with %s still to assign.' % numToAssign)
|
||||
return
|
||||
buildingHeight = random.choice(smallestHeights)
|
||||
self.notify.info('Existing buildings are (%s, %s), choosing from (%s, %s), chose %s, %s.' % (self.formatNumSuitsPerTrack(numPerTrack),
|
||||
self.notify.debug('Existing buildings are (%s, %s), choosing from (%s, %s), chose %s, %s.' % (self.formatNumSuitsPerTrack(numPerTrack),
|
||||
self.formatNumSuitsPerTrack(numPerHeight),
|
||||
smallestTracks,
|
||||
smallestHeights,
|
||||
|
@ -1195,7 +1195,7 @@ class DistributedSuitPlannerAI(DistributedObjectAI.DistributedObjectAI, SuitPlan
|
|||
sp.targetNumSuitBuildings += 1
|
||||
sp.pendingBuildingTracks.append(buildingTrack)
|
||||
sp.pendingBuildingHeights.append(buildingHeight)
|
||||
self.notify.info('Assigning building to zone %d, pending tracks = %s, pending heights = %s' % (zoneId, sp.pendingBuildingTracks, sp.pendingBuildingHeights))
|
||||
self.notify.debug('Assigning building to zone %d, pending tracks = %s, pending heights = %s' % (zoneId, sp.pendingBuildingTracks, sp.pendingBuildingHeights))
|
||||
numPerTrack[buildingTrack] += 1
|
||||
numPerHeight[buildingHeight] += 1
|
||||
numToAssign -= 1
|
||||
|
|
|
@ -26,9 +26,23 @@ class SuitInvasionManagerAI:
|
|||
self.suitName = None
|
||||
self.numSuits = 0
|
||||
self.spawnedSuits = 0
|
||||
self.randomInvasionProbability = 0.5
|
||||
if config.GetBool('want-random-invasions', True):
|
||||
taskMgr.doMethodLater(randint(1800, 7200), self.__randomInvasionTick, 'random-invasion-tick')
|
||||
|
||||
if config.GetBool('want-mega-invasions', False):
|
||||
# Mega invasion configuration.
|
||||
self.randomInvasionProbability = config.GetFloat('mega-invasion-probability', 0.65)
|
||||
self.megaInvasionCog = config.GetString('mega-invasion-cog-type', '')
|
||||
if not self.megaInvasionCog:
|
||||
raise AttributeError("No mega invasion cog specified, but mega invasions are on!")
|
||||
if self.megaInvasionCog not in SuitDNA.suitHeadTypes:
|
||||
raise AttributeError("Invalid cog type specified for mega invasion!")
|
||||
# Start ticking.
|
||||
taskMgr.doMethodLater(randint(1800, 5400), self.__randomInvasionTick, 'random-invasion-tick')
|
||||
|
||||
elif config.GetBool('want-random-invasions', True):
|
||||
# Random invasion configuration.
|
||||
self.randomInvasionProbability = config.GetFloat('random-invasion-probability', 0.4)
|
||||
# Start ticking.
|
||||
taskMgr.doMethodLater(randint(1800, 5400), self.__randomInvasionTick, 'random-invasion-tick')
|
||||
|
||||
def __randomInvasionTick(self, task=None):
|
||||
"""
|
||||
|
@ -42,7 +56,7 @@ class SuitInvasionManagerAI:
|
|||
on-going.
|
||||
"""
|
||||
# Generate a new tick delay.
|
||||
task.delayTime = randint(1800, 7200)
|
||||
task.delayTime = randint(1800, 5400)
|
||||
if self.getInvading():
|
||||
# We're already running an invasion. Don't start a new one.
|
||||
self.notify.debug('Invasion tested but already running invasion!')
|
||||
|
@ -50,9 +64,20 @@ class SuitInvasionManagerAI:
|
|||
if random() <= self.randomInvasionProbability:
|
||||
# We want an invasion!
|
||||
self.notify.debug('Invasion probability hit! Starting invasion.')
|
||||
suitName = choice(SuitDNA.suitHeadTypes)
|
||||
numSuits = randint(500, 2000)
|
||||
self.startInvasion(suitName, numSuits, False)
|
||||
# We want to test if we get a mega invasion or a normal invasion.
|
||||
# Take the mega invasion probability and test it. If we get lucky
|
||||
# a second time, spawn a mega invasion, otherwise spawn a normal
|
||||
# invasion.
|
||||
if config.GetBool('want-mega-invasions', False) and random() <= self.randomInvasionProbability:
|
||||
# N.B.: randomInvasionProbability = mega invasion probability.
|
||||
suitName = self.megaInvasionCog
|
||||
numSuits = randint(1500, 15000)
|
||||
specialSuit = randint(0, 2)
|
||||
else:
|
||||
suitName = choice(SuitDNA.suitHeadTypes)
|
||||
numSuits = randint(1000, 3000)
|
||||
specialSuit = False
|
||||
self.startInvasion(suitName, numSuits, specialSuit)
|
||||
return task.again
|
||||
|
||||
def getInvading(self):
|
||||
|
@ -121,8 +146,10 @@ class SuitInvasionManagerAI:
|
|||
])
|
||||
# If the cogs aren't defeated in a set amount of time, the invasion will
|
||||
# simply timeout. This was calculated by judging that 1000 cogs should
|
||||
# take around 20 minutes, thus becoming 1.2 seconds per cog.
|
||||
taskMgr.doMethodLater(1.2 * numSuits, self.stopInvasion, 'invasion-timeout')
|
||||
# take around 20 minutes, becoming 1.2 seconds per cog.
|
||||
# We added in a bit of a grace period, making it 1.5 seconds per cog, or 25 minutes.
|
||||
timePerCog = config.GetFloat('invasion-time-per-cog', 1.5)
|
||||
taskMgr.doMethodLater(timePerCog * numSuits, self.stopInvasion, 'invasion-timeout')
|
||||
self.__spAllCogsSupaFly()
|
||||
return True
|
||||
|
||||
|
|
|
@ -488,6 +488,11 @@ class SuitPlannerBase:
|
|||
self.pointIndexes = {}
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
del self.dnaStore
|
||||
if hasattr(self, 'dnaData'):
|
||||
del self.dnaData
|
||||
|
||||
def setupDNA(self):
|
||||
if self.dnaStore:
|
||||
return None
|
||||
|
|
|
@ -56,12 +56,10 @@ class DistributedNPCTailorAI(DistributedNPCToonBaseAI):
|
|||
|
||||
if self.freeClothes:
|
||||
flag = NPCToons.PURCHASE_MOVIE_START
|
||||
elif self.air.questManager.hasTailorClothingTicket(av, self):
|
||||
flag = NPCToons.PURCHASE_MOVIE_START
|
||||
elif self.useJellybeans and self.hasEnoughJbs(av):
|
||||
flag = NPCToons.PURCHASE_MOVIE_START
|
||||
'''elif self.air.questManager.hasTailorClothingTicket(av, self) == 1:
|
||||
flag = NPCToons.PURCHASE_MOVIE_START
|
||||
elif self.air.questManager.hasTailorClothingTicket(av, self) == 2:
|
||||
flag = NPCToons.PURCHASE_MOVIE_START'''
|
||||
|
||||
if self.housingEnabled and self.isClosetAlmostFull(av):
|
||||
flag = NPCToons.PURCHASE_MOVIE_START_NOROOM
|
||||
|
@ -139,7 +137,7 @@ class DistributedNPCTailorAI(DistributedNPCToonBaseAI):
|
|||
if self.air.doId2do.has_key(avId):
|
||||
av = self.air.doId2do[avId]
|
||||
if finished == 2 and which > 0:
|
||||
if self.freeClothes or av.takeMoney(self.jbCost, bUseBank = True):#self.hasEnoughJbs(av): # self.air.questManager.removeClothingTicket(av, self) == 1
|
||||
if self.freeClothes or self.air.questManager.removeClothingTicket(av, self) or av.takeMoney(self.jbCost, bUseBank = True):
|
||||
av.b_setDNAString(blob)
|
||||
if which & ClosetGlobals.SHIRT:
|
||||
if av.addToClothesTopsList(self.customerDNA.topTex, self.customerDNA.topTexColor, self.customerDNA.sleeveTex, self.customerDNA.sleeveTexColor) == 1:
|
||||
|
|
|
@ -191,6 +191,7 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute
|
|||
self.gmNameTagColor = 'whiteGM'
|
||||
self.gmNameTagString = ''
|
||||
self._lastZombieContext = None
|
||||
self.lastSeen = 0
|
||||
return
|
||||
|
||||
def disable(self):
|
||||
|
@ -2707,9 +2708,12 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute
|
|||
}]
|
||||
base.cr.playGame.getPlace().fsm.forceTransition('teleportOut', requestStatus)
|
||||
|
||||
def ping(self, data):
|
||||
# Server sent a ping, better respond before we get booted!
|
||||
self.sendUpdate("pong", [data[::-1]])
|
||||
def setLastSeen(self, timestamp):
|
||||
self.lastSeen = timestamp
|
||||
|
||||
def getLastSeen(self):
|
||||
return self.lastSeen
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_MODERATION)
|
||||
def globaltp():
|
||||
|
|
|
@ -47,6 +47,7 @@ from toontown.toonbase import TTLocalizer
|
|||
from toontown.catalog import CatalogAccessoryItem
|
||||
from toontown.minigame import MinigameCreatorAI
|
||||
import ModuleListAI
|
||||
import time
|
||||
|
||||
# Magic Word imports
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
|
@ -261,9 +262,17 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
from toontown.toon.DistributedNPCToonBaseAI import DistributedNPCToonBaseAI
|
||||
if not isinstance(self, DistributedNPCToonBaseAI):
|
||||
self.sendUpdate('setDefaultShard', [self.air.districtId])
|
||||
# Begin ping-pong.
|
||||
if self.isPlayerControlled():
|
||||
self.ping()
|
||||
# Begin checking if clients are still alive
|
||||
if config.GetBool('want-keep-alive', True):
|
||||
taskMgr.doMethodLater(config.GetInt('keep-alive-timeout-delay', 300), self.__noKeepAlive, self.uniqueName('KeepAliveTimeout'), extraArgs=[])
|
||||
|
||||
if self.getAdminAccess() < 500:
|
||||
# Ensure they have the correct laff.
|
||||
# We don't test admins, as they can modify their stats at will.
|
||||
# N.B.: To test this, you must bump up this access! Local servers default at
|
||||
# access 500!
|
||||
self.correctToonLaff()
|
||||
|
||||
def setLocation(self, parentId, zoneId):
|
||||
messenger.send('toon-left-%s' % self.zoneId, [self])
|
||||
|
@ -321,6 +330,7 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
self._dbCheckDoLater = None
|
||||
if self.isPlayerControlled():
|
||||
messenger.send('avatarExited', [self])
|
||||
self.d_setLastSeen(time.time())
|
||||
if simbase.wantPets:
|
||||
if self.isInEstate():
|
||||
print 'ToonAI - Exit estate toonId:%s' % self.doId
|
||||
|
@ -337,8 +347,7 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
taskMgr.remove(taskName)
|
||||
taskName = 'next-bothDelivery-%s' % self.doId
|
||||
taskMgr.remove(taskName)
|
||||
taskMgr.remove(self.uniqueName('PingTimeout'))
|
||||
taskMgr.remove(self.uniqueName('PingCooldown'))
|
||||
taskMgr.remove(self.uniqueName('KeepAliveTimeout'))
|
||||
self.stopToonUp()
|
||||
del self.dna
|
||||
if self.inventory:
|
||||
|
@ -361,8 +370,7 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
self.experience = None
|
||||
taskName = self.uniqueName('next-catalog')
|
||||
taskMgr.remove(taskName)
|
||||
taskMgr.remove(self.uniqueName('PingTimeout'))
|
||||
taskMgr.remove(self.uniqueName('PingCooldown'))
|
||||
taskMgr.remove(self.uniqueName('KeepAliveTimeout'))
|
||||
return
|
||||
|
||||
def ban(self, comment):
|
||||
|
@ -1166,6 +1174,9 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
self.sendUpdate('catalogGenAccessories', [self.doId])
|
||||
|
||||
def takeDamage(self, hpLost, quietly = 0, sendTotal = 1):
|
||||
# Assume that if they took damage, they're not in a safe zone.
|
||||
self.stopToonUp()
|
||||
|
||||
if not self.immortalMode:
|
||||
if not quietly:
|
||||
self.sendUpdate('takeDamage', [hpLost])
|
||||
|
@ -1197,6 +1208,93 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
maxHp = min(maxHp, ToontownGlobals.MaxHpLimit)
|
||||
DistributedAvatarAI.DistributedAvatarAI.b_setMaxHp(self, maxHp)
|
||||
|
||||
def correctToonLaff(self):
|
||||
# Init our counters to 0.
|
||||
gained_quest = 0
|
||||
gained_racing = 0
|
||||
gained_fishing = 0
|
||||
gained_suit = 0
|
||||
gained_gardening = 0
|
||||
gained_golf = 0
|
||||
|
||||
# First we need to check all the quests we have completed.
|
||||
# We only want unique quests. Storyline quests can only be completed once.
|
||||
for questId in list(set(self.getQuestHistory())):
|
||||
# Get all the questIds.
|
||||
currentQuests = self.getQuests()
|
||||
if questId in currentQuests:
|
||||
# We're still working on the quest.
|
||||
continue
|
||||
reward = Quests.findFinalRewardId(questId)
|
||||
if reward == -1:
|
||||
# Returns -1 instead of a tuple if error occurs.
|
||||
continue
|
||||
rewardId, remainingSteps = reward
|
||||
if not rewardId:
|
||||
# This quest has no reward. Skip.
|
||||
continue
|
||||
if remainingSteps > 1:
|
||||
# This isn't the end of the toontask, skip.
|
||||
continue
|
||||
if rewardId in range(100, 110): # [100..109]
|
||||
gained_quest += rewardId - 99 # Corresponds to Quest rewards.
|
||||
|
||||
# We have to calculate the total laff points we're supposed to have
|
||||
# for each "side" activity.
|
||||
gained_fishing += len(self.getFishingTrophies()) # fishing (1 boost per trophy)
|
||||
|
||||
num_racing_trophies = 0
|
||||
for value in self.getKartingTrophies():
|
||||
if value:
|
||||
num_racing_trophies += 1
|
||||
gained_racing += int(num_racing_trophies/10) # racing (1 boost every 10 trophies)
|
||||
|
||||
golf_trophies = GolfGlobals.calcTrophyListFromHistory(self.golfHistory)
|
||||
num_golf_trophies = 0
|
||||
for value in golf_trophies:
|
||||
if value:
|
||||
num_golf_trophies += 1
|
||||
gained_golf += int(num_golf_trophies/10) # golf (1 boost every 10 trophies)
|
||||
|
||||
gained_gardening += int(len(self.getGardenTrophies())/2) # gardening (1 boost every 2 trophies)
|
||||
|
||||
# Finally, we calculate the total amount of boosts from boss battles.
|
||||
for x in xrange(4): # 0 to 3
|
||||
if self.getCogTypes()[x] != 7:
|
||||
# We're not the last cog type, skip.
|
||||
continue
|
||||
levels = [15, 20, 30, 40, 50]
|
||||
# Iterate through the above list, and check if we're above or equal to the level.
|
||||
# If we are, we get 1 boost per level that we've passed.
|
||||
for level in levels:
|
||||
if self.getCogLevels()[x] >= level - 1: # 0-49, pfft.
|
||||
gained_suit += 1
|
||||
|
||||
# Calculate the total hp from the "gained" counters.
|
||||
hp = 15 + gained_quest + gained_fishing + gained_racing + gained_golf + gained_gardening + gained_suit
|
||||
|
||||
# If the calculated HP differs from our current maxHp, we need to bump our maxHp.
|
||||
if hp != self.getMaxHp():
|
||||
log_only_mode = config.GetBool('want-hp-correction-log-only', True) # Defaults to true so we don't break prod.
|
||||
# Log the details.
|
||||
self.air.writeServerEvent('corrected-toon-laff', avId=self.getDoId(),
|
||||
info = "Corrected HP mismatch %d compared to old maxHp %d." % (hp, self.getMaxHp()),
|
||||
questlaff = gained_quest,
|
||||
fishinglaff = gained_fishing,
|
||||
racinglaff = gained_racing,
|
||||
golflaff = gained_golf,
|
||||
gardenlaff = gained_gardening,
|
||||
suitlaff = gained_suit,
|
||||
log_only = log_only_mode
|
||||
)
|
||||
|
||||
# If we're not in log only mode, actually modify their HP.
|
||||
if not log_only_mode:
|
||||
if self.getHp() > hp:
|
||||
# Bump their hp down if they have more than the calculated max.
|
||||
self.b_setHp(hp)
|
||||
self.b_setMaxHp(hp)
|
||||
|
||||
def b_setTutorialAck(self, tutorialAck):
|
||||
self.d_setTutorialAck(tutorialAck)
|
||||
self.setTutorialAck(tutorialAck)
|
||||
|
@ -2718,14 +2816,16 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
def considerToonUp(self, zoneId):
|
||||
if zoneId == OTPGlobals.QuietZone:
|
||||
# Don't consider anything, we're in the QuietZone. Shh!
|
||||
return
|
||||
return None
|
||||
if self.shouldToonUp(zoneId):
|
||||
if taskMgr.hasTaskNamed(self.uniqueName('safeZoneToonUp')):
|
||||
# Do nothing, we were already in a safezone!
|
||||
return
|
||||
return None
|
||||
self.startToonUp(ToontownGlobals.SafezoneToonupFrequency)
|
||||
return True
|
||||
else:
|
||||
self.stopToonUp()
|
||||
return False
|
||||
|
||||
def startToonUp(self, healFrequency):
|
||||
self.stopToonUp()
|
||||
|
@ -2736,6 +2836,9 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
taskMgr.doMethodLater(self.healFrequency, self.toonUpTask, self.uniqueName('safeZoneToonUp'))
|
||||
|
||||
def toonUpTask(self, task):
|
||||
considered = self.considerToonUp(self.zoneId)
|
||||
if not considered and considered is not None:
|
||||
return Task.done
|
||||
self.toonUp(1)
|
||||
self.__waitForNextToonUp()
|
||||
return Task.done
|
||||
|
@ -3782,6 +3885,11 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
(102, 1)])
|
||||
|
||||
def reqUseSpecial(self, special):
|
||||
# This is for gardening.
|
||||
if not config.GetBool('want-gardening', True):
|
||||
self.air.writeServerEvent('suspicious', avId=self.doId, issue='Tried to plant a special item while gardening is not implemented!')
|
||||
self.sendUpdate('useSpecialResponse', ['badlocation'])
|
||||
return
|
||||
response = self.tryToUseSpecial(special)
|
||||
self.sendUpdate('useSpecialResponse', [response])
|
||||
|
||||
|
@ -4481,29 +4589,30 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
|
|||
def getWebAccountId(self):
|
||||
return self.webAccountId
|
||||
|
||||
def ping(self):
|
||||
self.notify.debug("Pinging %s (%d)." % (self.getName(), self.getDoId()))
|
||||
self.sendUpdate('ping', ["mooBseoGkcauQcM"])
|
||||
taskMgr.doMethodLater(config.GetInt('toon-ping-timeout-delay', 30), self.__noPong, self.uniqueName('PingTimeout'), extraArgs=[])
|
||||
# Keep Alive
|
||||
def keepAlive(self):
|
||||
# We received the Keep Alive response
|
||||
self.notify.debug("Received keep alive response %s (%d)." % (self.getName(), self.getDoId()))
|
||||
taskMgr.remove(self.uniqueName('KeepAliveTimeout'))
|
||||
taskMgr.doMethodLater(config.GetInt('keep-alive-timeout-delay', 300), self.__noKeepAlive, self.uniqueName('KeepAliveTimeout'), extraArgs=[])
|
||||
|
||||
def __noPong(self):
|
||||
# No response from the client. Assume this avatar is a ghost.
|
||||
self.notify.debug("Ping timeout %s (%d)." % (self.getName(), self.getDoId()))
|
||||
self.__failedPing = True
|
||||
def __noKeepAlive(self):
|
||||
# Log everything just so we have a record of it
|
||||
self.notify.debug("No keep alive response %s (%d)." % (self.getName(), self.getDoId()))
|
||||
self.air.writeServerEvent("keep-alive", avId=self.getDoId(), message="Avatar failed to respond to Keep Alive.")
|
||||
|
||||
# We failed to recieve a reponse from the client
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.GetPuppetConnectionChannel(self.getDoId()), self.air.ourChannel, CLIENTAGENT_EJECT)
|
||||
dg.addUint16(128)
|
||||
dg.addString('Link renegotiation timed out.')
|
||||
self.air.send(dg)
|
||||
|
||||
# RIP
|
||||
self.requestDelete()
|
||||
|
||||
def pong(self, data):
|
||||
if hasattr(self, "__failedPing") and self.__failedPing:
|
||||
# Too late to respond, we already failed to respond on time.
|
||||
self.notify.debug("Pong after timeout %s (%d)." % (self.getName(), self.getDoId()))
|
||||
return
|
||||
if data != "McQuackGoesBoom":
|
||||
self.air.writeServerEvent("suspicious", avId=self.getDoId(), issue="Avatar failed to respond to ping with correct data.")
|
||||
self.requestDelete()
|
||||
return
|
||||
self.notify.debug("Pong received from %s (%d) successfully." % (self.getName(), self.getDoId()))
|
||||
taskMgr.remove(self.uniqueName('PingTimeout'))
|
||||
taskMgr.doMethodLater(config.GetInt('toon-ping-cooldown', 120), self.ping, self.uniqueName('PingCooldown'), extraArgs=[])
|
||||
def d_setLastSeen(self, timestamp):
|
||||
self.sendUpdate('setLastSeen', [int(timestamp)])
|
||||
|
||||
@magicWord(category=CATEGORY_CHARACTERSTATS, types=[int, int, int])
|
||||
def setCE(CEValue, CEHood=0, CEExpire=0):
|
||||
|
@ -5235,3 +5344,13 @@ def dump_doId2do():
|
|||
for name, size in sorted_objSizes:
|
||||
file.write('OBJ: %s | SIZE: %d\n' % (name, size))
|
||||
return "Dumped doId2do sizes (grouped by class) to '%s'." % temp_file[1]
|
||||
|
||||
@magicWord(category=CATEGORY_CHARACTERSTATS)
|
||||
def correctlaff():
|
||||
"""
|
||||
A magic word that attempts to correct a toons laff. This includes any external,
|
||||
admin modifications to the toon (such as setMaxHp).
|
||||
"""
|
||||
av = spellbook.getTarget()
|
||||
av.correctToonLaff()
|
||||
return "Corrected %s's laff successfully." % av.getName()
|
||||
|
|
|
@ -255,6 +255,9 @@ class LocalToon(DistributedToon.DistributedToon, LocalAvatar.LocalAvatar):
|
|||
if self.adminAccess >= 300:
|
||||
self.seeGhosts = 1
|
||||
|
||||
if base.config.GetBool('want-keep-alive', True):
|
||||
taskMgr.doMethodLater(config.GetInt('keep-alive-delay', 30), self.keepAliveCheck, self.uniqueName('KeepAliveTimeout'), extraArgs=[])
|
||||
|
||||
def disable(self):
|
||||
self.laffMeter.destroy()
|
||||
del self.laffMeter
|
||||
|
@ -284,6 +287,7 @@ class LocalToon(DistributedToon.DistributedToon, LocalAvatar.LocalAvatar):
|
|||
self.nametag.unmanage(base.marginManager)
|
||||
self.ignoreAll()
|
||||
DistributedToon.DistributedToon.disable(self)
|
||||
taskMgr.remove(self.uniqueName('KeepAliveTimeout'))
|
||||
return
|
||||
|
||||
def disableBodyCollisions(self):
|
||||
|
@ -328,6 +332,8 @@ class LocalToon(DistributedToon.DistributedToon, LocalAvatar.LocalAvatar):
|
|||
self.__catalogNotifyDialog.cleanup()
|
||||
del self.__catalogNotifyDialog
|
||||
|
||||
taskMgr.remove('KeepAliveTimeout')
|
||||
|
||||
return
|
||||
|
||||
def initInterface(self):
|
||||
|
@ -357,10 +363,6 @@ class LocalToon(DistributedToon.DistributedToon, LocalAvatar.LocalAvatar):
|
|||
self.suitPage = SuitPage.SuitPage()
|
||||
self.suitPage.load()
|
||||
self.book.addPage(self.suitPage, pageName=TTLocalizer.SuitPageTitle)
|
||||
if base.config.GetBool('want-photo-album', 0):
|
||||
self.photoAlbumPage = PhotoAlbumPage.PhotoAlbumPage()
|
||||
self.photoAlbumPage.load()
|
||||
self.book.addPage(self.photoAlbumPage, pageName=TTLocalizer.PhotoPageTitle)
|
||||
self.fishPage = FishPage.FishPage()
|
||||
self.fishPage.setAvatar(self)
|
||||
self.fishPage.load()
|
||||
|
@ -1923,6 +1925,15 @@ class LocalToon(DistributedToon.DistributedToon, LocalAvatar.LocalAvatar):
|
|||
result = True
|
||||
return result
|
||||
|
||||
def isBookOpen(self):
|
||||
result = False
|
||||
if base.cr and base.cr.playGame and base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm') and base.cr.playGame.getPlace().fsm:
|
||||
fsm = base.cr.playGame.getPlace().fsm
|
||||
curState = fsm.getCurrentState().getName()
|
||||
if curState == 'stickerBook':
|
||||
result = True
|
||||
return result
|
||||
|
||||
def doTeleportResponse(self, fromAvatar, toAvatar, avId, available, shardId, hoodId, zoneId, sendToId):
|
||||
localAvatar.d_teleportResponse(avId, available, shardId, hoodId, zoneId, sendToId)
|
||||
|
||||
|
@ -1958,3 +1969,10 @@ class LocalToon(DistributedToon.DistributedToon, LocalAvatar.LocalAvatar):
|
|||
|
||||
def _stopZombieCheck(self):
|
||||
pass
|
||||
|
||||
# KeepAlive stuff
|
||||
def keepAliveCheck(self):
|
||||
self.notify.debug("Checking to make sure the avatar is still alive")
|
||||
self.sendUpdate('keepAlive', [])
|
||||
taskMgr.remove(self.uniqueName('KeepAliveTimeout'))
|
||||
taskMgr.doMethodLater(config.GetInt('keep-alive-delay', 30), self.keepAliveCheck, self.uniqueName('KeepAliveTimeout'), extraArgs=[])
|
||||
|
|
|
@ -1789,7 +1789,7 @@ class Toon(Avatar.Avatar, ToonHead):
|
|||
|
||||
holes = self.getHoleActors()
|
||||
hands = self.getRightHands()
|
||||
holeTrack = Track((0.0, Func(showHoles, holes, hands)), (0.5, SoundInterval(self.getSoundTeleport(), node=self)), (1.708, Func(reparentHoles, holes, self)), (2.9, Func(self.dropShadow.hide)), (3.4, Func(cleanupHoles, holes)))
|
||||
holeTrack = Track((0.0, Func(showHoles, holes, hands)), (0.5, SoundInterval(self.getSoundTeleport(), node=self)), (1.708, Func(reparentHoles, holes, self)), (2.9, Func(self.dropShadow.hide)), (3.4, Parallel(Func(self.nametag3d.hide), Func(cleanupHoles, holes))))
|
||||
if hasattr(self, 'uniqueName'):
|
||||
trackName = self.uniqueName('teleportOut')
|
||||
else:
|
||||
|
@ -1829,14 +1829,6 @@ class Toon(Avatar.Avatar, ToonHead):
|
|||
self.holeClipPath = self.attachNewNode(holeClip)
|
||||
self.getGeomNode().setClipPlane(self.holeClipPath)
|
||||
self.nametag3d.setClipPlane(self.holeClipPath)
|
||||
self.nametagLods = []
|
||||
for hi in range(self.headParts.getNumPaths()):
|
||||
head = self.headParts[hi]
|
||||
nameNode = head.attachNewNode('nameNode')
|
||||
self.nametagLods.append(nameNode)
|
||||
tag = self.nametag3d.copyTo(self)
|
||||
tag.wrtReparentTo(nameNode)
|
||||
self.nametag3d.hide()
|
||||
self.track.start(ts)
|
||||
self.setActiveShadow(0)
|
||||
|
||||
|
@ -1870,9 +1862,6 @@ class Toon(Avatar.Avatar, ToonHead):
|
|||
self.getGeomNode().clearClipPlane()
|
||||
if self.nametag3d and not self.nametag3d.isEmpty():
|
||||
self.nametag3d.clearClipPlane()
|
||||
if self.nametagLods:
|
||||
for tag in self.nametagLods:
|
||||
tag.removeNode()
|
||||
if self.holeClipPath:
|
||||
self.holeClipPath.removeNode()
|
||||
self.holeClipPath = None
|
||||
|
|
|
@ -179,7 +179,7 @@ class ToonAvatarDetailPanel(DirectFrame):
|
|||
text = TTLocalizer.AvatarDetailPanelOnline % {'district': shardName,
|
||||
'location': hoodName}
|
||||
else:
|
||||
text = TTLocalizer.AvatarDetailPanelOffline
|
||||
text = TTLocalizer.AvatarDetailPanelOffline % {'last_seen': TTLocalizer.getLastSeenString(self.avatar.getLastSeen())}
|
||||
self.dataText['text'] = text
|
||||
self.__updateTrackInfo()
|
||||
self.__updateTrophyInfo()
|
||||
|
|
|
@ -2706,10 +2706,7 @@ class ToonDNA(AvatarDNA.AvatarDNA):
|
|||
self.sleeveTexColor = sleeveColor
|
||||
self.botTex = bottom
|
||||
self.botTexColor = bottomColor
|
||||
color = generator.choice(defaultBoyColorList)
|
||||
self.armColor = color
|
||||
self.legColor = color
|
||||
self.headColor = color
|
||||
self.getRandomColor(defaultBoyColorList, generator)
|
||||
else:
|
||||
self.torso = generator.choice(toonTorsoTypes[:6])
|
||||
self.topTex = top
|
||||
|
@ -2722,11 +2719,26 @@ class ToonDNA(AvatarDNA.AvatarDNA):
|
|||
bottom, bottomColor = getRandomBottom(gender, generator=generator, girlBottomType=SHORTS)
|
||||
self.botTex = bottom
|
||||
self.botTexColor = bottomColor
|
||||
color = generator.choice(defaultGirlColorList)
|
||||
self.getRandomColor(defaultGirlColorList, generator)
|
||||
self.gloveColor = 0
|
||||
|
||||
def getRandomColor(self, choices, generator=None):
|
||||
if not generator:
|
||||
generator = random
|
||||
# We want colors to shuffle all parts of the body sometimes, but we want some solid
|
||||
# colors thrown in there as well. We'll increase the chances of that happening.
|
||||
if config.GetBool('want-shuffle-colors', 1) and random.random() <= 0.3:
|
||||
colorArm = generator.choice(choices)
|
||||
colorLeg = generator.choice(choices)
|
||||
colorHead = generator.choice(choices)
|
||||
self.armColor = colorArm
|
||||
self.legColor = colorLeg
|
||||
self.headColor = colorHead
|
||||
else:
|
||||
color = generator.choice(choices)
|
||||
self.armColor = color
|
||||
self.legColor = color
|
||||
self.headColor = color
|
||||
self.gloveColor = 0
|
||||
|
||||
def asTuple(self):
|
||||
return (self.head,
|
||||
|
|
|
@ -31,6 +31,13 @@ class DisplayOptions:
|
|||
sfxVol = self.settings.getInt('game', 'sfx-vol', 100) / 100.0
|
||||
res = self.settings.getList('game', 'resolution', default=[800, 600], expectedLength=2)
|
||||
embed = self.settings.getBool('game', 'embed', False)
|
||||
antialias = self.settings.getInt('game', 'antialiasing', 0)
|
||||
if antialias:
|
||||
loadPrcFileData('toonBase Settings Framebuffer MSAA', 'framebuffer-multisample 1')
|
||||
loadPrcFileData('toonBase Settings MSAA Level', 'multisamples %i' % antialias)
|
||||
else:
|
||||
self.settings.updateSetting('game', 'antialiasing', antialias)
|
||||
loadPrcFileData('toonBase Settings Framebuffer MSAA', 'framebuffer-multisample 0')
|
||||
self.notify.debug('before prc settings embedded mode=%s' % str(embed))
|
||||
self.notify.debug('before prc settings full screen mode=%s' % str(mode))
|
||||
loadPrcFileData('toonBase Settings Window Res', 'win-size %s %s' % (res[0], res[1]))
|
||||
|
@ -46,6 +53,7 @@ class DisplayOptions:
|
|||
self.settingsWidth = res[0]
|
||||
self.settingsHeight = res[1]
|
||||
self.settingsEmbedded = embed
|
||||
self.antialias = antialias
|
||||
self.notify.debug('settings embedded mode=%s' % str(self.settingsEmbedded))
|
||||
self.notify.info('settingsFullScreen = %s, embedded = %s width=%d height=%d' % (self.settingsFullScreen,
|
||||
self.settingsEmbedded,
|
||||
|
|
|
@ -1920,7 +1920,41 @@ AvatarDetailPanelPlayerShort = '%(player)s\nWorld: %(world)s\nLocation: %(locati
|
|||
AvatarDetailPanelRealLife = 'Offline'
|
||||
AvatarDetailPanelOnline = 'District: %(district)s\nLocation: %(location)s'
|
||||
AvatarDetailPanelOnlinePlayer = 'District: %(district)s\nLocation: %(location)s\nPlayer: %(player)s'
|
||||
AvatarDetailPanelOffline = 'District: offline\nLocation: offline'
|
||||
AvatarDetailPanelOffline = 'District: offline\nLocation: offline\nLast Seen: %(last_seen)s'
|
||||
|
||||
import time
|
||||
def getLastSeenString(timestamp):
|
||||
# use int() to round down
|
||||
seconds_passed = int(time.time()) - int(timestamp)
|
||||
if timestamp == 0:
|
||||
# This is the default. It means the db never had an update for lastSeen.
|
||||
return "Never"
|
||||
elif seconds_passed < 60:
|
||||
return "Less than a minute ago"
|
||||
elif seconds_passed < 60*2: # less than 2 minutes
|
||||
return "1 minute ago"
|
||||
elif seconds_passed < 60*60: # less than 1 hour
|
||||
return "%d minutes ago" % int(seconds_passed/60)
|
||||
elif seconds_passed < 60*60*2: # less than 2 hours
|
||||
return "1 hour ago"
|
||||
elif seconds_passed < 60*60*24: # less than 1 day
|
||||
return "%d hours ago" % int(seconds_passed/(60*60))
|
||||
elif seconds_passed < 60*60*24*2: # less than 2 days
|
||||
return "1 day ago"
|
||||
# optional: at this stage we could do weeks, but seems pointless.
|
||||
# we also now pretend that each month always has 30 days.
|
||||
elif seconds_passed < 60*60*24*30: # less than a month
|
||||
return "%d days ago" % int(seconds_passed/(60*60*24))
|
||||
elif seconds_passed < 60*60*24*30*2: # less than 2 months
|
||||
return "1 month ago"
|
||||
# assume 1 year = 365 days (ignoring .25 / leap years)
|
||||
elif seconds_passed < 60*60*24*365: # less than a year
|
||||
return "%d months ago" % int(seconds_passed/(60*60*24*30))
|
||||
elif seconds_passed < 60*60*24*365*2: # less than 2 years
|
||||
return "1 year ago"
|
||||
else:
|
||||
return "A very long time ago... :("
|
||||
|
||||
AvatarShowPlayer = 'Show Player'
|
||||
OfflineLocation = 'Offline'
|
||||
PlayerToonName = 'Toon: %(toonname)s'
|
||||
|
@ -5601,13 +5635,13 @@ STOREOWNER_CONFIRM_LOSS = 'Your closet is full. You will lose the clothes you w
|
|||
STOREOWNER_OK = lOK
|
||||
STOREOWNER_CANCEL = lCancel
|
||||
STOREOWNER_TROPHY = 'Wow! You collected %s of %s fish. That deserves a trophy and a Laff boost!'
|
||||
SuitInvasionBegin1 = lToonHQ + ': A Cog Invasion has begun!!!'
|
||||
SuitInvasionBegin1 = lToonHQ + ': A Cog Invasion has begun...'
|
||||
SuitInvasionBegin2 = lToonHQ + ': %s have taken over Toontown!!!'
|
||||
SuitInvasionEnd1 = lToonHQ + ': The %s Invasion has ended!!!'
|
||||
SuitInvasionEnd2 = lToonHQ + ': The Toons have saved the day once again!!!'
|
||||
SuitInvasionUpdate1 = lToonHQ + ': The Cog Invasion is now at %s Cogs!!!'
|
||||
SuitInvasionUpdate2 = lToonHQ + ': We must defeat those %s!!!'
|
||||
SuitInvasionBulletin1 = lToonHQ + ': There is a Cog Invasion in progress!!!'
|
||||
SuitInvasionBulletin1 = lToonHQ + ': There is a Cog Invasion in progress...'
|
||||
SuitInvasionBulletin2 = lToonHQ + ': %s have taken over Toontown!!!'
|
||||
LeaderboardTitle = 'Toon Platoon'
|
||||
QuestScriptTutorialMickey_1 = 'Toontown has a new citizen! Do you have some extra gags?'
|
||||
|
@ -8301,20 +8335,27 @@ PetTrait2descriptions = {'hungerThreshold': ('Always Hungry',
|
|||
'Sometimes Affectionate',
|
||||
'Often Affectionate',
|
||||
'Always Affectionate')}
|
||||
FireworksInstructions = 'Flippy: Look up using the "Page Up" key to see, or hop in Slappy\'s Balloon for a ride over the sky!'
|
||||
startFireworksResponse = "Usage: startFireworksShow ['num']\n 'num' = %s - New Years\n %s - Party Summer \n %s - 4th of July"
|
||||
#FireworksJuly4Beginning = lToonHQ + ': Welcome to summer fireworks! Enjoy the show!'
|
||||
#FireworksJuly4Ending = lToonHQ + ': Hope you enjoyed the show! Have a great summer!'
|
||||
#FireworksNewYearsEveBeginning = lToonHQ + ': Happy New Year! Enjoy the fireworks show, sponsored by Flippy!'
|
||||
#FireworksNewYearsEveEnding = lToonHQ + ': Hope you enjoyed the show! Have a Toontastic New Year!'
|
||||
#FireworksComboBeginning = lToonHQ + ': Enjoy lots of Laffs with Toon fireworks!'
|
||||
#FireworksComboEnding = lToonHQ + ': Thank you, Toons! Hope you enjoyed the show!'
|
||||
FireworksJuly4Beginning = 'Flippy: Hiya, Toons! Get ready to see some fireworks to celebrate this last week of the election!'
|
||||
FireworksJuly4Ending = 'Flippy: Hope you enjoyed the show. Don\'t forget to stop by Toontown Central for some pies!'
|
||||
FireworksNewYearsEveBeginning = 'Flippy: Hiya, Toons! Get ready to see some fireworks to celebrate this last week of the election!'
|
||||
FireworksNewYearsEveEnding = 'Flippy: Hope you enjoyed the show. Don\'t forget to stop by Toontown Central for some pies!'
|
||||
FireworksComboBeginning = 'Flippy: Hiya, Toons! Get ready to see some fireworks to celebrate this last week of the election!'
|
||||
FireworksComboEnding = 'Flippy: Hope you enjoyed the show. Don\'t forget to stop by Toontown Central for some pies!'
|
||||
|
||||
# Election stuff
|
||||
# FireworksInstructions = 'Flippy: Look up using the "Page Up" key to see, or hop in Slappy\'s Balloon for a ride over the sky!'
|
||||
# startFireworksResponse = "Usage: startFireworksShow ['num']\n 'num' = %s - New Years\n %s - Party Summer \n %s - 4th of July"
|
||||
# FireworksJuly4Beginning = 'Flippy: Hiya, Toons! Get ready to see some fireworks to celebrate this last week of the election!'
|
||||
# FireworksJuly4Ending = 'Flippy: Hope you enjoyed the show. Don\'t forget to stop by Toontown Central for some pies!'
|
||||
# FireworksNewYearsEveBeginning = 'Flippy: Hiya, Toons! Get ready to see some fireworks to celebrate this last week of the election!'
|
||||
# FireworksNewYearsEveEnding = 'Flippy: Hope you enjoyed the show. Don\'t forget to stop by Toontown Central for some pies!'
|
||||
# FireworksComboBeginning = 'Flippy: Hiya, Toons! Get ready to see some fireworks to celebrate this last week of the election!'
|
||||
# FireworksComboEnding = 'Flippy: Hope you enjoyed the show. Don\'t forget to stop by Toontown Central for some pies!'
|
||||
|
||||
# Regular fireworks stuff
|
||||
FireworksInstructions = lToonHQ + ': Hit the "Page Up" key to see better.'
|
||||
startFireworksResponse = "Usage: startFireworksShow ['num']\n 'num' = %s - New Years\n %s - Party Summer \n %s - 4th of July"
|
||||
FireworksJuly4Beginning = lToonHQ + ': Welcome to summer fireworks! Enjoy the show!'
|
||||
FireworksJuly4Ending = lToonHQ + ': Hope you enjoyed the show! Have a great summer!'
|
||||
FireworksNewYearsEveBeginning = lToonHQ + ': Happy New Year! Enjoy the fireworks show!'
|
||||
FireworksNewYearsEveEnding = lToonHQ + ': Hope you enjoyed the show! Have a Toontastic New Year!'
|
||||
FireworksComboBeginning = lToonHQ + ': Enjoy lots of Laffs with Toon fireworks!'
|
||||
FireworksComboEnding = lToonHQ + ': Thank you, Toons! Hope you enjoyed the show!'
|
||||
|
||||
BlockerTitle = 'LOADING TOONTOWN...'
|
||||
BlockerLoadingTexts = ['Rewriting history',
|
||||
'Baking pie crusts',
|
||||
|
|
|
@ -9,6 +9,7 @@ from direct.gui import DirectGuiGlobals
|
|||
from direct.gui.DirectGui import *
|
||||
from direct.showbase.Transitions import Transitions
|
||||
from pandac.PandaModules import *
|
||||
from direct.interval.IntervalGlobal import Sequence, Func, Wait
|
||||
from otp.nametag.ChatBalloon import ChatBalloon
|
||||
from otp.nametag import NametagGlobals
|
||||
from otp.margins.MarginManager import MarginManager
|
||||
|
@ -25,6 +26,7 @@ from toontown.launcher import ToontownDownloadWatcher
|
|||
from toontown.toontowngui import TTDialog
|
||||
from sys import platform
|
||||
from DisplayOptions import DisplayOptions
|
||||
import otp.ai.DiagnosticMagicWords
|
||||
|
||||
class ToonBase(OTPBase.OTPBase):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ToonBase')
|
||||
|
@ -57,6 +59,8 @@ class ToonBase(OTPBase.OTPBase):
|
|||
tpm.setProperties('candidate_inactive', candidateInactive)
|
||||
self.transitions.IrisModelName = 'phase_3/models/misc/iris'
|
||||
self.transitions.FadeModelName = 'phase_3/models/misc/fade'
|
||||
self.snapshotSfx = base.loadSfx('phase_4/audio/sfx/Photo_shutter.ogg')
|
||||
self.flashTrack = None
|
||||
self.exitFunc = self.userExit
|
||||
if __builtins__.has_key('launcher') and launcher:
|
||||
launcher.setPandaErrorCode(11)
|
||||
|
@ -243,7 +247,6 @@ class ToonBase(OTPBase.OTPBase):
|
|||
if not os.path.exists(TTLocalizer.ScreenshotPath):
|
||||
os.mkdir(TTLocalizer.ScreenshotPath)
|
||||
self.notify.info('Made new directory to save screenshots.')
|
||||
|
||||
namePrefix = TTLocalizer.ScreenshotPath + launcher.logPrefix + 'screenshot'
|
||||
timedif = globalClock.getRealTime() - self.lastScreenShotTime
|
||||
if self.glitchCount > 10 and self.walking:
|
||||
|
@ -255,6 +258,9 @@ class ToonBase(OTPBase.OTPBase):
|
|||
self.screenshot(namePrefix=namePrefix)
|
||||
self.lastScreenShotTime = globalClock.getRealTime()
|
||||
return
|
||||
if self.flashTrack and self.flashTrack.isPlaying():
|
||||
self.flashTrack.finish()
|
||||
self.transitions.noFade()
|
||||
coordOnScreen = self.config.GetBool('screenshot-coords', 0)
|
||||
self.localAvatar.stopThisFrame = 1
|
||||
ctext = self.localAvatar.getAvPosStr()
|
||||
|
@ -270,11 +276,16 @@ class ToonBase(OTPBase.OTPBase):
|
|||
self.graphicsEngine.renderFrame()
|
||||
self.screenshot(namePrefix=namePrefix, imageComment=ctext + ' ' + self.screenshotStr)
|
||||
self.lastScreenShotTime = globalClock.getRealTime()
|
||||
self.transitions.fadeScreenColor(1)
|
||||
self.transitions.setFadeColor(1, 1, 1)
|
||||
self.transitions.fadeIn(0.8)
|
||||
self.snapshotSfx = base.loadSfx('phase_4/audio/sfx/Photo_shutter.ogg')
|
||||
base.playSfx(self.snapshotSfx)
|
||||
self.flashTrack = Sequence(
|
||||
Func(base.playSfx, self.snapshotSfx),
|
||||
Func(self.transitions.fadeOut, 0.15),
|
||||
Wait(0.2),
|
||||
Func(self.transitions.fadeIn, 0.8),
|
||||
Wait(1.0),
|
||||
Func(self.transitions.setFadeColor, 0, 0, 0)
|
||||
)
|
||||
self.flashTrack.start()
|
||||
if coordOnScreen:
|
||||
if strTextLabel is not None:
|
||||
strTextLabel.destroy()
|
||||
|
@ -369,6 +380,8 @@ class ToonBase(OTPBase.OTPBase):
|
|||
|
||||
def startShow(self, cr, launcherServer = None):
|
||||
self.cr = cr
|
||||
if self.display.antialias:
|
||||
render.setAntialias(AntialiasAttrib.MAuto)
|
||||
base.graphicsEngine.renderFrame()
|
||||
self.downloadWatcher = ToontownDownloadWatcher.ToontownDownloadWatcher(TTLocalizer.LauncherPhaseNames)
|
||||
if launcher.isDownloadComplete():
|
||||
|
|
|
@ -59,7 +59,7 @@ UnpaidMaxSkills = [Levels[0][1] - 1,
|
|||
Levels[4][4] - 1,
|
||||
Levels[5][4] - 1,
|
||||
Levels[6][1] - 1]
|
||||
ExperienceCap = 200
|
||||
ExperienceCap = 300
|
||||
|
||||
def gagIsPaidOnly(track, level):
|
||||
return Levels[track][level] > UnpaidMaxSkills[track]
|
||||
|
|
|
@ -1363,9 +1363,9 @@ LawbotBossBonusDuration = 20
|
|||
LawbotBossBonusToonup = 10
|
||||
LawbotBossBonusWeightMultiplier = 2
|
||||
LawbotBossChanceToDoAreaAttack = 11
|
||||
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)
|
||||
LOW_POP = 80 # This is 'Ideal' in the book (green)
|
||||
MID_POP = 150 # This is 'Full' in the book, but friends can still TP onto shard (soft red)
|
||||
HIGH_POP = 170 # Still 'Full' in book, but nobody joins this shard for any reason (hard red)
|
||||
PinballCannonBumper = 0
|
||||
PinballCloudBumperLow = 1
|
||||
PinballCloudBumperMed = 2
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from pandac.PandaModules import *
|
||||
import __builtin__
|
||||
import os
|
||||
|
||||
if __debug__:
|
||||
# __debug__ is only 1 in dev builds; Mirai's builder will set it to 0
|
||||
|
@ -17,7 +18,14 @@ for mount in mounts:
|
|||
|
||||
import glob
|
||||
for file in glob.glob('resources/*.mf'):
|
||||
vfs.mount(Filename(file), Filename('/'), 0)
|
||||
mf = Multifile()
|
||||
mf.openReadWrite(Filename(file))
|
||||
names = mf.getSubfileNames()
|
||||
for name in names:
|
||||
ext = os.path.splitext(name)[1]
|
||||
if ext not in ['.jpg', '.jpeg', '.ogg', '.rgb']:
|
||||
mf.removeSubfile(name)
|
||||
vfs.mount(mf, Filename('/'), 0)
|
||||
|
||||
class game:
|
||||
name = 'toontown'
|
||||
|
@ -26,7 +34,6 @@ class game:
|
|||
|
||||
__builtin__.game = game()
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
import __builtin__
|
||||
|
|
|
@ -6,29 +6,24 @@ from toontown.hood import ZoneUtil
|
|||
from pandac.PandaModules import Vec3
|
||||
|
||||
# Portable Hole settings
|
||||
POSITION_TOLERANCE = 10
|
||||
Hood2Details = {
|
||||
# hood : [pos, speedchatIndex, destination]
|
||||
ToontownGlobals.DonaldsDock: [(-23, 5, 6), 1522, 2714], # Bring it on!
|
||||
ToontownGlobals.ToontownCentral: [(93, -106, 3), 1603, 3823], # I like this game!
|
||||
ToontownGlobals.TheBrrrgh: [(-111, -41, 9), 1003, 4612], # Follow me.
|
||||
ToontownGlobals.MinniesMelodyland: [(0, -20, -16), 1209, 5602], # I found what you need.
|
||||
ToontownGlobals.DaisyGardens: [(1, 91, 0), 1134, 9501], # Don't wait for me.
|
||||
ToontownGlobals.DonaldsDreamland: [(48, -96, 0), 5500, 17000], # :)
|
||||
ToontownGlobals.OutdoorZone: [(-46, -140, 0), 1556, 11000], # Go for the weakest Cog first.
|
||||
ToontownGlobals.SellbotHQ: [(39, -37, 10), 1555, 12000], # Let's all go for the same Cog.
|
||||
ToontownGlobals.CashbotHQ: [(-78, -134, -63), 1558, 13000], # Save your powerful Gags.
|
||||
2665: [(6, 7, 9), 103, 2665], # TTC, Howdy!
|
||||
1832: [(6, 7, 9), 103, 1832], # Howdy!
|
||||
5502: [(6, 7, 9), 103, 5502], # Howdy!
|
||||
4612: [(6, 7, 9), 103, 4612], # Howdy!
|
||||
3636: [(6, 7, 9), 103, 3636], # Howdy!
|
||||
9705: [(6, 7, 9), 103, 9705], # Howdy!
|
||||
3823: [(6, 7, 9), 103, 3823], # Howdy!
|
||||
}
|
||||
Interior2Messages = {
|
||||
3823: ["Welcome, Doctor Surlee! You are on your way to see KOOKY CINEPLEX", "-4"], # DD to TTC
|
||||
5602: ["Hello, Doctor Surlee! Taking you to the PRECIPITATION FOUNDATION", "6,"], # TTC to TB
|
||||
4612: ["Hi, Doctor Surlee! Sending you to DR. FRET'S DENTISTRY", ","], # TB to MML
|
||||
2714: ["Welcome, Dr. Surlee! You are on route to ARTIE CHOKE'S NECKTIES", "-1"], # MML to DG
|
||||
9501: ["Good afternoon, Doctor Surlee! Setting destination to the LULLABY LIBRARY", "4"], # DG to DDL
|
||||
17000: ["Good evening, Dr. Surlee! You are on route to CHIP 'N DALE'S MINIGOLF", "0"], # DDL to AA
|
||||
11000: ["Greetings, Doctor Surlee. You will soon arrive at SELLBOT HQ.", "Do you think they're going too far?"],
|
||||
12000: ["Greetings, Doctor Surlee. You are now going to CASHBOT HQ.", "Well there's certainly no stopping them now."],
|
||||
13000: ["Greetings, Doctor Surlee. Taking you to ERROR: UNKNOWN LOCATION", "They are indeed quite clever."], # CBHQ (unlocks LBHQ)
|
||||
2665: ["Mary: Oh, Hello! Oh, Hello! Say, that's the keyword that Doctor Surlee told myself and other shopkeepers just like me to remember. I take it he sent you?", "Mary: The word I'm supposed to remember is 'Sillyness'"], # DD to TTC
|
||||
1832: ["Melville: Say, you don't look like Doctor Surlee. That is the trigger phrase, though...", "Melville: He told me to remember 'Lafter'"], # TTC to TB
|
||||
5502: ["HQ Officer: Oh, Surlee sent you? Keep this key safe, he said it's going to be important later on.", "HQ Officer: The word is 'Springy Partlicles' -- Whatever that means."], # TB to MML
|
||||
4612: ["Dr. Fret: Aahhh, brilliant. Surlee is up to something again, I'm sure.", "Dr. Fret: He told me to remember 'Creating Equiment'"], # MML to DG
|
||||
3636: ["Gus Gooseburger: Keep it down! Surlee didn't give me these gloves to just give the word away.", "Gus Gooseburger: Just kidding! I have no idea why he wanted me to remember this word. It's 'Portil'"], # DG to DDL
|
||||
9705: ["Drowsy Dave: Huh? Oh, oh! Hi. Surlee's word, right. Uhh...", "Drowsy Dave: I seem to have dozed off... Professor Flake is a good friend of the Doc, though. I bet he knows."], # DDL to AA
|
||||
3823: ["Professor Flake: Hmm? So soon? Surlee told me that something big would be happening whenever he needed this...", "Professor Flake: I hope that you have a photographic memory like myself, because this is a long one."], # DDL to AA
|
||||
}
|
||||
|
||||
class ARGManager(DistributedObjectGlobal):
|
||||
|
@ -58,32 +53,14 @@ class ARGManager(DistributedObjectGlobal):
|
|||
return
|
||||
if speedchatIndex != phraseId:
|
||||
return
|
||||
dummyNode = base.cr.playGame.getPlace().loader.geom.attachNewNode("arg_dummy")
|
||||
dummyNode.setPos(*position)
|
||||
if Vec3(base.localAvatar.getPos(dummyNode)).length() > POSITION_TOLERANCE:
|
||||
return
|
||||
dummyNode.removeNode()
|
||||
msgBefore, msgAfter = Interior2Messages.get(destination, [None, None])
|
||||
if not msgBefore:
|
||||
self.notify.warning("Interior %d has no message definitions!" % destination)
|
||||
return
|
||||
base.localAvatar.setSystemMessage(0, msgBefore)
|
||||
requestStatus = [{
|
||||
'loader': ZoneUtil.getBranchLoaderName(destination),
|
||||
'where': ZoneUtil.getToonWhereName(destination),
|
||||
'how': 'teleportIn',
|
||||
'hoodId': ZoneUtil.getCanonicalHoodId(destination),
|
||||
'zoneId': destination,
|
||||
'shardId': None,
|
||||
'avId': -1,
|
||||
}]
|
||||
base.cr.playGame.getPlace().fsm.forceTransition('teleportOut', requestStatus)
|
||||
# NOTE: This is somewhat hacky. A better solution would be to fire this once the placeFSM
|
||||
# successfully loads the destination. Perhaps this can be fired off upon zone change?
|
||||
taskMgr.doMethodLater(10, base.localAvatar.setSystemMessage, self.uniqueName("arg-after-msg"), extraArgs=[0, msgAfter])
|
||||
if destination == 13000:
|
||||
taskMgr.doMethodLater(15, base.localAvatar.setSystemMessage, self.uniqueName("arg-after-msg"), extraArgs=[0, "Perhaps, however I don't believe they realize what they have unfolded."])
|
||||
taskMgr.doMethodLater(20, base.localAvatar.setSystemMessage, self.uniqueName("arg-after-msg"), extraArgs=[0, "I don't think you have either."])
|
||||
taskMgr.doMethodLater(2, base.localAvatar.setSystemMessage, self.uniqueName("arg-before-msg"), extraArgs=[0, msgBefore])
|
||||
taskMgr.doMethodLater(7, base.localAvatar.setSystemMessage, self.uniqueName("arg-after-msg"), extraArgs=[0, msgAfter])
|
||||
if destination == 3823:
|
||||
taskMgr.doMethodLater(15, base.localAvatar.setSystemMessage, self.uniqueName("arg-after-after-msg"), extraArgs=[0, "'ttr://assets/LL-memo-607630003555.txt'. Keep it safe. I have no idea what it means, but Surlee certainly will."])
|
||||
self.accept(SpeedChatGlobals.SCStaticTextMsgEvent, phraseSaid)
|
||||
|
||||
def cleanupPortableHoleEvent(self):
|
||||
|
|
Loading…
Reference in a new issue