Current garden progress.

This commit is contained in:
Loudrob 2015-07-20 15:53:53 -04:00
parent c93fec2f19
commit 1236e38d62
28 changed files with 1569 additions and 1012 deletions

View file

@ -1209,46 +1209,41 @@ struct decorItem {
};
struct lawnItem {
int8 plot;
uint8 type;
uint8 species;
uint8 variety;
uint8 hardPoint;
int8 waterLevel;
int8 growthLevel;
uint16 optional;
uint64 plantedAt;
uint64 wateredAt;
};
dclass DistributedEstate : DistributedObject {
string DcObjectType db;
setEstateReady() broadcast;
setClientReady() airecv clsend;
setEstateType(uint8 type = 0) required broadcast db;
setClosestHouse(uint8) airecv clsend;
setTreasureIds(uint32[]) broadcast ram;
requestServerTime() airecv clsend;
setServerTime(uint32);
setDawnTime(uint32) required broadcast ram;
placeOnGround(uint32) broadcast ram;
setDecorData(lawnItem items[] = []) required airecv db;
setLastEpochTimeStamp(uint32 timestamp = 0) required airecv db;
setRentalTimeStamp(uint32 timestamp = 0) required airecv db;
setRentalType(uint8 type = 0) required airecv db;
setSlot0ToonId(uint32 toonId = 0) required airecv db;
setSlot0Items(lawnItem items[] = []) required broadcast ownrecv db;
setSlot0Garden(blob g) required airecv db;
setSlot1ToonId(uint32 toonId = 0) required airecv db;
setSlot1Items(lawnItem items[] = []) required broadcast ownrecv db;
setSlot1Garden(blob g) required airecv db;
setSlot2ToonId(uint32 toonId = 0) required airecv db;
setSlot2Items(lawnItem items[] = []) required broadcast ownrecv db;
setSlot2Garden(blob g) required airecv db;
setSlot3ToonId(uint32 toonId = 0) required airecv db;
setSlot3Items(lawnItem items[] = []) required broadcast ownrecv db;
setSlot3Garden(blob g) required airecv db;
setSlot4ToonId(uint32 toonId = 0) required airecv db;
setSlot4Items(lawnItem items[] = []) required broadcast ownrecv db;
setSlot4Garden(blob g) required airecv db;
setSlot5ToonId(uint32 toonId = 0) required airecv db;
setSlot5Items(lawnItem items[] = []) required broadcast ownrecv db;
setSlot5Garden(blob g) required airecv db;
setIdList(uint32 []) broadcast ram;
completeFlowerSale(uint8) airecv clsend;
completeFishSale(uint8) airecv clsend;
thankSeller(int8, int8, int8);
awardedTrophy(uint32) broadcast;
setClouds(uint8) required broadcast ram;
cannonsOver() broadcast;
@ -1283,8 +1278,7 @@ dclass DistributedHouseInterior : DistributedObject {
};
dclass DistributedGarden : DistributedObject {
sendNewProp(uint8, int16/10, int16/10, int16/10) broadcast;
setProps(uint8[]) airecv clsend;
sendNewProp(uint8 prop, int16/10 x, int16/10 y, int16/10 z) broadcast;
};
dclass DistributedParty : DistributedObject {
@ -2556,27 +2550,24 @@ dclass DistributedLawbotChair : DistributedObject {
};
dclass DistributedLawnDecor : DistributedNode {
setEstate(uint32) required broadcast ram;
setPlot(int8) required broadcast ram;
setHeading(int16/10) required broadcast ram;
setPosition(int16/10, int16/10, int16/10) required broadcast ram;
setOwnerIndex(int8) required broadcast ram;
setPosition(int16/10, int16/10, int16/10) required broadcast ram;
plotEntered() airecv clsend;
removeItem(uint32) airecv clsend;
removeItem() airecv clsend;
setMovie(uint8, uint32) broadcast ram;
movieDone() airecv clsend;
interactionDenied(uint32) broadcast ram;
setBoxDoId(uint32, uint8) broadcast ram;
};
dclass DistributedGardenPlot : DistributedLawnDecor {
plantedItem(uint32) broadcast ram;
finishPlanting(uint32) airecv clsend;
finishRemoving(uint32) airecv clsend;
plantFlower(uint8, uint8, uint32) airecv clsend;
plantGagTree(uint8, uint8, uint32) airecv clsend;
plantStatuary(uint8, uint32) airecv clsend;
plantToonStatuary(uint8, uint16, uint32) airecv clsend;
plantNothing(uint8, uint32) airecv clsend;
plantFlower(uint8, uint8) airecv clsend;
plantGagTree(uint8, uint8) airecv clsend;
plantStatuary(uint8) airecv clsend;
plantToonStatuary(uint8, uint16) airecv clsend;
plantNothing(uint8) airecv clsend;
};
dclass DistributedGardenBox : DistributedLawnDecor {
@ -2584,7 +2575,6 @@ dclass DistributedGardenBox : DistributedLawnDecor {
};
dclass DistributedStatuary : DistributedLawnDecor {
setOwnerPlot(uint32) required broadcast ram;
setTypeIndex(uint8) required broadcast ram;
setWaterLevel(int8) required broadcast ram;
setGrowthLevel(int8) required broadcast ram;
@ -2602,11 +2592,10 @@ dclass DistributedChangingStatuary : DistributedStatuary {
};
dclass DistributedPlantBase : DistributedLawnDecor {
setOwnerPlot(uint32) required broadcast ram;
setTypeIndex(uint8) required broadcast ram;
setWaterLevel(int8) required broadcast ram;
setGrowthLevel(int8) required broadcast ram;
waterPlant(uint32) airecv clsend;
waterPlant() airecv clsend;
waterPlantDone() airecv clsend;
};
@ -2617,7 +2606,8 @@ dclass DistributedFlower : DistributedPlantBase {
dclass DistributedGagTree : DistributedPlantBase {
setWilted(int8) required broadcast ram;
requestHarvest(uint32) airecv clsend;
setFruiting(bool) required broadcast ram;
requestHarvest() airecv clsend;
};
struct golfData {

View file

@ -62,10 +62,9 @@ if ':' in host:
port = int(port)
simbase.air.connect(host, port)
gc.enable()
try:
run()
gc.enable()
except SystemExit:
raise
except Exception:

View file

@ -22,6 +22,11 @@ class CatalogGardenItem(CatalogItem.CatalogItem):
else:
return 100
def reachedPurchaseLimit(self, avatar):
if self in avatar.onOrder or self in avatar.mailboxContents or self in avatar.onGiftOrder or self in avatar.awardMailboxContents or self in avatar.onAwardOrder:
return 1
return 0
def getAcceptItemErrorText(self, retcode):
if retcode == ToontownGlobals.P_ItemAvailable:
return TTLocalizer.CatalogAcceptGarden
@ -45,7 +50,7 @@ class CatalogGardenItem(CatalogItem.CatalogItem):
def getPicture(self, avatar):
photoModel = GardenGlobals.Specials[self.gardenIndex]['photoModel']
if 'photoAnimation' in GardenGlobals.Specials[self.gardenIndex]:
if GardenGlobals.Specials[self.gardenIndex].has_key('photoAnimation'):
modelPath = photoModel + GardenGlobals.Specials[self.gardenIndex]['photoAnimation'][0]
animationName = GardenGlobals.Specials[self.gardenIndex]['photoAnimation'][1]
animationPath = photoModel + animationName
@ -74,7 +79,6 @@ class CatalogGardenItem(CatalogItem.CatalogItem):
def cleanupPicture(self):
CatalogItem.CatalogItem.cleanupPicture(self)
if hasattr(self, 'model') and self.model:
self.model.detachNode()
self.model = None
return
@ -121,7 +125,7 @@ class CatalogGardenItem(CatalogItem.CatalogItem):
def getDeliveryTime(self):
if self.gardenIndex == GardenGlobals.GardenAcceleratorSpecial:
return 1
return 24 * 60
else:
return 0
@ -156,7 +160,7 @@ class CatalogGardenItem(CatalogItem.CatalogItem):
result = False
if canPlant < numBeansRequired:
result = True
if not result and self.gardenIndex in GardenGlobals.Specials and 'minSkill' in GardenGlobals.Specials[self.gardenIndex]:
if not result and GardenGlobals.Specials.has_key(self.gardenIndex) and GardenGlobals.Specials[self.gardenIndex].has_key('minSkill'):
minSkill = GardenGlobals.Specials[self.gardenIndex]['minSkill']
if avatar.shovelSkill < minSkill:
result = True

View file

@ -16,7 +16,9 @@ class CatalogGardenStarterItem(CatalogItem.CatalogItem):
return 0
def reachedPurchaseLimit(self, avatar):
return self in avatar.onOrder or self in avatar.mailboxContents or hasattr(avatar, 'gardenStarted') and avatar.getGardenStarted()
if self in avatar.onOrder or self in avatar.mailboxContents or self in avatar.onGiftOrder or self in avatar.awardMailboxContents or self in avatar.onAwardOrder or hasattr(avatar, 'gardenStarted') and avatar.getGardenStarted():
return 1
return 0
def saveHistory(self):
return 1
@ -29,13 +31,13 @@ class CatalogGardenStarterItem(CatalogItem.CatalogItem):
def recordPurchase(self, avatar, optional):
if avatar:
estate = simbase.air.estateManager.toon2estate.get(avatar)
self.notify.debug('rental -- has avatar')
estate = simbase.air.estateManager._lookupEstate(avatar)
if estate:
av = simbase.air.doId2do.get(avatar)
if av:
av.b_setGardenStarted(True)
print('garden saved')
estate.placeStarterGarden(avatar)
self.notify.debug('rental -- has estate')
estate.placeStarterGarden(avatar.doId)
else:
self.notify.warning('rental -- something not there')
return ToontownGlobals.P_ItemAvailable
def getPicture(self, avatar):

View file

@ -25,6 +25,7 @@ class CatalogToonStatueItem(CatalogGardenItem.CatalogGardenItem):
model, ival = self.makeFrameModel(toonStatuary.toon, 1)
self.pictureToonStatue = toonStatuary
self.hasPicture = True
toonStatuary.toon.setBin('gui-popup', 60)
return (model, ival)
def cleanupPicture(self):
@ -50,7 +51,7 @@ class CatalogToonStatueItem(CatalogGardenItem.CatalogGardenItem):
def getAllToonStatues(self):
self.statueList = []
for index in xrange(self.startPoseIndex, self.endPoseIndex + 1):
for index in range(self.startPoseIndex, self.endPoseIndex + 1):
self.statueList.append(CatalogToonStatueItem(index, 1, endPoseIndex=index))
return self.statueList

View file

@ -4,6 +4,3 @@ from toontown.estate.DistributedStatuaryAI import DistributedStatuaryAI
class DistributedAnimatedStatuaryAI(DistributedStatuaryAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedAnimatedStatuaryAI")
def __init__(self, air, species):
self.air = air
self.species = species

View file

@ -4,13 +4,6 @@ from toontown.estate.DistributedStatuaryAI import DistributedStatuaryAI
class DistributedChangingStatuaryAI(DistributedStatuaryAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedChangingStatuaryAI")
def __init__(self, air):
DistributedStatuaryAI.__init__(self, air)
self.air = air
self.growthLevel = -1
def setGrowthLevel(self, todo0):
pass
def setGrowthLevel(self, growthLevel):
self.growthLevel = growthLevel
def getGrowthLevel(self):
return self.growthLevel

View file

@ -1,50 +1,413 @@
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedObjectAI import DistributedObjectAI
from toontown.toonbase import ToontownGlobals
import HouseGlobals
import time, random
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 TreasurePlannerAI
from toontown.safezone import DistributedTreasureAI
from toontown.safezone import TreasureGlobals
from toontown.safezone import ButterflyGlobals
from toontown.safezone import DistributedButterflyAI
from toontown.safezone.DistributedFishingSpotAI import DistributedFishingSpotAI
from DistributedGardenBoxAI import *
from DistributedGardenPlotAI import *
from DistributedGagTreeAI import *
from DistributedFlowerAI import *
from DistributedStatuaryAI import *
from DistributedToonStatuaryAI import *
from DistributedAnimatedStatuaryAI import *
from DistributedChangingStatuaryAI import *
import GardenGlobals
from DistributedCannonAI import *
from DistributedTargetAI import *
import CannonGlobals
import TableGlobals
import HouseGlobals
import GardenGlobals
from DistributedGardenPlotAI import DistributedGardenPlotAI
from DistributedGardenBoxAI import DistributedGardenBoxAI
from DistributedFlowerAI import DistributedFlowerAI
from DistributedGagTreeAI import DistributedGagTreeAI
from DistributedStatuaryAI import DistributedStatuaryAI
from DistributedToonStatuaryAI import DistributedToonStatuaryAI
import time
import random
from toontown.fishing import FishGlobals
from toontown.parties.DistributedPartyJukeboxActivityAI import DistributedPartyJukeboxActivityAI
# planted, waterLevel, lastCheck, growthLevel, optional
NULL_PLANT = [-1, -1, 0, 0, 0]
NULL_TREES = [NULL_PLANT] * 8
NULL_FLOWERS = [NULL_PLANT] * 10
NULL_STATUARY = 0
NULL_DATA = {'trees': NULL_TREES, 'statuary': NULL_STATUARY, 'flowers': NULL_FLOWERS}
from direct.distributed.PyDatagramIterator import *
from direct.distributed.PyDatagram import *
class Garden:
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEstateAI')
WANT_FLOWERS = True # puke
WANT_TREES = True
WANT_STATUARY = True
def __init__(self, air, avId):
self.air = air
self.avId = avId
self.trees = set()
self.flowers = set()
self.objects = set()
if not self.air.dbConn:
self.notify.warning('Not using mongodb, garden data will be non-persistent')
self.data = NULL_DATA.copy()
else:
d = self.air.dbGlobalCursor.gardens.find_one({'avId': avId})
if d is None:
self.data = NULL_DATA.copy()
self.air.dbGlobalCursor.gardens.update({'avId': avId}, {'$set': NULL_DATA}, upsert=True)
else:
self.data = d
self.data.pop('_id', None)
def destroy(self):
messenger.send('garden-%d-666-going-down' % self.avId)
for tree in self.trees:
tree.requestDelete()
for flower in self.flowers:
flower.requestDelete()
for object in self.objects:
object.requestDelete()
self.air = None
self.estateMgr = None
def create(self, estateMgr):
self.estateMgr = estateMgr
if self.avId not in estateMgr.toons:
estateMgr.notify.warning('Garden associated to unknown avatar %d, deleting...' % self.avId)
return False
houseIndex = estateMgr.toons.index(self.avId)
if self.WANT_FLOWERS:
boxIndex = 0
boxes = []
boxDefs = GardenGlobals.estateBoxes[houseIndex]
for x, y, h, boxType in boxDefs:
box = DistributedGardenBoxAI(self)
box.setTypeIndex(boxType)
box.setPos(x, y, 0)
box.setH(h)
box.setOwnerIndex(houseIndex)
box.generateWithRequired(estateMgr.zoneId)
self.objects.add(box)
boxes.append(box)
boxIndex += 1
self._boxes = boxes
plots = GardenGlobals.estatePlots[houseIndex]
treeIndex = 0
flowerIndex = 0
for plot, (x, y, h, type) in enumerate(plots):
if type == GardenGlobals.GAG_TREE_TYPE and self.WANT_TREES:
data = self.data['trees'][treeIndex]
planted, waterLevel, lastCheck, growthLevel, lastHarvested = data
if planted != -1:
obj = self.plantTree(treeIndex, planted, waterLevel=waterLevel,
lastCheck=lastCheck, growthLevel=growthLevel,
lastHarvested=lastHarvested, generate=False)
self.trees.add(obj)
else:
obj = self.placePlot(treeIndex)
obj.setPos(x, y, 0)
obj.setH(h)
obj.setPlot(plot)
obj.setOwnerIndex(houseIndex)
obj.generateWithRequired(estateMgr.zoneId)
treeIndex += 1
elif type == GardenGlobals.FLOWER_TYPE and self.WANT_FLOWERS:
data = self.data['flowers'][flowerIndex]
planted, waterLevel, lastCheck, growthLevel, variety = data
if planted != -1:
obj = self.plantFlower(flowerIndex, planted, variety, waterLevel=waterLevel,
lastCheck=lastCheck, growthLevel=growthLevel,
generate=False)
else:
obj = self.placePlot(flowerIndex)
obj.flowerIndex = flowerIndex
obj.setPlot(plot)
obj.setOwnerIndex(houseIndex)
obj.generateWithRequired(estateMgr.zoneId)
index = (0, 1, 2, 2, 2, 3, 3, 3, 4, 4)[flowerIndex]
idx = (0, 0, 0, 1, 2, 0, 1, 2, 0, 1)[flowerIndex]
obj.sendUpdate('setBoxDoId', [boxes[index].doId, idx])
flowerIndex += 1
elif type == GardenGlobals.STATUARY_TYPE and self.WANT_STATUARY:
data = self.data['statuary']
if data == 0:
obj = self.placePlot(-1)
else:
obj = self.placeStatuary(data, generate=False)
obj.setPos(x, y, 0)
obj.setH(h)
obj.setPlot(plot)
obj.setOwnerIndex(houseIndex)
obj.generateWithRequired(estateMgr.zoneId)
for tree in self.trees:
tree.calcDependencies()
self.reconsiderAvatarOrganicBonus()
return True
def hasTree(self, track, index):
x = track * 7 + index
for tree in self.data['trees']:
if tree[0] == x:
return True
return False
def getTree(self, track, index):
for tree in self.trees:
if tree.typeIndex == track * 7 + index:
return tree
def plantTree(self, treeIndex, value, plot=None, waterLevel=-1,
lastCheck=0, growthLevel=0, lastHarvested=0,
ownerIndex=-1, plotId=-1, pos=None, generate=True):
if not self.air:
return
if plot:
if plot not in self.objects:
return
plot.requestDelete()
self.objects.remove(plot)
tree = DistributedGagTreeAI(self)
tree.setTypeIndex(value)
tree.setWaterLevel(waterLevel)
tree.setGrowthLevel(growthLevel)
if ownerIndex != -1:
tree.setOwnerIndex(ownerIndex)
if plotId != -1:
tree.setPlot(plotId)
if pos is not None:
pos, h = pos
tree.setPos(pos)
tree.setH(h)
tree.treeIndex = treeIndex
tree.calculate(lastHarvested, lastCheck)
self.trees.add(tree)
if generate:
tree.generateWithRequired(self.estateMgr.zoneId)
return tree
def placePlot(self, treeIndex):
obj = DistributedGardenPlotAI(self)
obj.treeIndex = treeIndex
self.objects.add(obj)
return obj
def plantFlower(self, flowerIndex, species, variety, plot=None, waterLevel=-1,
lastCheck=0, growthLevel=0, ownerIndex=-1, plotId=-1, generate=True):
if not self.air:
return
if plot:
if plot not in self.objects:
return
plot.requestDelete()
self.objects.remove(plot)
flower = DistributedFlowerAI(self)
flower.setTypeIndex(species)
flower.setVariety(variety)
flower.setWaterLevel(waterLevel)
flower.setGrowthLevel(growthLevel)
if ownerIndex != -1:
flower.setOwnerIndex(ownerIndex)
if plotId != -1:
flower.setPlot(plotId)
flower.flowerIndex = flowerIndex
flower.calculate(lastCheck)
self.flowers.add(flower)
if generate:
flower.generateWithRequired(self.estateMgr.zoneId)
return flower
def placeStatuary(self, data, plot=None, plotId=-1, ownerIndex=-1,
pos=None, generate=True):
if not self.air:
return
if plot:
if plot not in self.objects:
return
plot.requestDelete()
self.objects.remove(plot)
data, lastCheck, index, growthLevel = self.S_unpack(data)
dclass = DistributedStatuaryAI
if index in GardenGlobals.ToonStatuaryTypeIndices:
dclass = DistributedToonStatuaryAI
elif index in GardenGlobals.ChangingStatuaryTypeIndices:
dclass = DistributedChangingStatuaryAI
elif index in GardenGlobals.AnimatedStatuaryTypeIndices:
dclass = DistributedAnimatedStatuaryAI
obj = dclass(self)
obj.growthLevel = growthLevel
obj.index = index
obj.data = data
if ownerIndex != -1:
obj.setOwnerIndex(ownerIndex)
if plotId != -1:
obj.setPlot(plotId)
if pos is not None:
pos, h = pos
obj.setPos(pos)
obj.setH(h)
obj.calculate(lastCheck)
self.objects.add(obj)
if generate:
obj.announceGenerate()
return obj
# Data structure
# VERY HIGH (vh) (64-bit)
# high high (H) = data (32-bit)
# high low (L) = lastCheck (32-bit)
# VERY LOW (vl) (16-bit)
# low high (h) = index (8-bit)
# low low (l) = growthLevel (8-bit)
@staticmethod
def S_pack(data, lastCheck, index, growthLevel):
vh = data << 32 | lastCheck
vl = index << 8 | growthLevel
return vh << 16 | vl
@staticmethod
def S_unpack(x):
vh = x >> 16
vl = x & 0xFFFF
data = vh >> 32
lastCheck = vh & 0xFFFFFFFF
index = vl >> 8
growthLevel = vl & 0xFF
return data, lastCheck, index, growthLevel
def getNullPlant(self):
return NULL_PLANT
def reconsiderAvatarOrganicBonus(self):
av = self.air.doId2do.get(self.avId)
if not av:
return
bonus = [-1] * 7
for track in xrange(7):
for level in xrange(8):#7
if not self.hasTree(track, level):
break
tree = self.getTree(track, level)
if tree.getGrowthLevel() < tree.growthThresholds[1] or tree.getWilted():
break
bonus[track] = level - 1
av.b_setTrackBonusLevel(bonus)
def update(self):
if self.air.dbConn:
self.air.dbGlobalCursor.gardens.update({'avId': self.avId}, {'$set': self.data}, upsert=True)
class GardenManager:
def __init__(self, mgr):
self.mgr = mgr
self.gardens = {}
def handleSingleGarden(self, avId):
g = Garden(self.mgr.air, avId)
g.gardenMgr = self
res = g.create(self.mgr)
if res:
self.gardens[avId] = g
def destroy(self):
for garden in self.gardens.values():
garden.destroy()
del self.gardens
class Rental:
def __init__(self, estate):
self.estate = estate
self.objects = set()
def destroy(self):
del self.estate
for obj in self.objects:
if not obj.isDeleted():
obj.requestDelete()
taskMgr.remove(obj.uniqueName('delete'))
for object in self.objects:
if not object.isDeleted():
object.requestDelete()
taskMgr.remove(object.uniqueName('delete'))
self.objects = set()
class CannonRental(Rental):
def __init__(self, estate):
Rental.__init__(self, estate)
def generateObjects(self):
target = DistributedTargetAI(self.estate.air)
target.generateWithRequired(self.estate.zoneId)
@ -71,12 +434,12 @@ class CannonRental(Rental):
for i in xrange(20):
x = random.randint(100, 300) - 200
y = random.randint(100, 300) - 200
treasure = DistributedTreasureAI.DistributedTreasureAI(self.estate.air, self, 7, x, y, z)
treasure = DistributedTreasureAI.DistributedTreasureAI(self.estate.air, self, 9, x, y, z)
treasure.generateWithRequired(self.estate.zoneId)
self.objects.add(treasure)
doIds.append(treasure.doId)
self.estate.sendUpdate("setTreasureIds", [doIds])
self.estate.sendUpdate('setTreasureIds', [doIds])
def grabAttempt(self, avId, treasureId):
av = self.estate.air.doId2do.get(avId)
@ -89,6 +452,7 @@ class CannonRental(Rental):
if self.validAvatar(av):
treasure.d_setGrab(avId)
self.deleteTreasureSoon(treasure)
else:
treasure.d_setReject()
@ -106,49 +470,32 @@ class CannonRental(Rental):
av.toonUp(3)
return 1
# Once we make rental game tables.
class TableRental(Rental):
def __init__(self, estate):
Rental.__init__(self, estate)
def generateObjects(self):
for drop in TableGlobals.tableDrops:
table = None
table.setEstateId(self.estate.doId)
table.setPosHpr(*drop)
table.generateWithRequired(self.estate.zoneId)
self.objects.add(table)
def destroy(self):
Rental.destroy(self)
class DistributedEstateAI(DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedEstateAI")
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEstateAI')
def __init__(self, air):
DistributedObjectAI.__init__(self, air)
self.toons = [0, 0, 0, 0, 0, 0]
self.items = [[], [], [], [], [], []]
self.boxes = [[], [], [], [], [], []]
self.plots = [[], [], [], [], [], []]
self.decorData = []
self.estateType = 0
self.cloudType = 0
self.dawnTime = 0
self.lastEpochTimestamp = 0
self.rentalType = 0
self.rentalHandle = None
self.rentalTimestamp = 0
self.houses = [None] * 6
self.rentalType = 0
self.rentalHandle = None
self.doId2do = { }
self.pond = None
self.spots = []
self.targets = []
self.jukebox = None
self.owner = None
@property
def hostId(self):
return 1000000001
self.gardenManager = GardenManager(self)
self.__pendingGardens = {}
def generate(self):
DistributedObjectAI.generate(self)
@ -157,12 +504,15 @@ class DistributedEstateAI(DistributedObjectAI):
self.pond.setArea(ToontownGlobals.MyEstate)
self.pond.generateWithRequired(self.zoneId)
for i in xrange(FishingTargetGlobals.getNumTargets(ToontownGlobals.MyEstate)):
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)
#self.treasurePlanner = ETreasurePlannerAI.ETreasurePlannerAI(self.zoneId)
#self.treasurePlanner.start()
spot = DistributedFishingSpotAI(self.air)
spot.setPondDoId(self.pond.getDoId())
spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0)
@ -187,126 +537,59 @@ class DistributedEstateAI(DistributedObjectAI):
spot.generateWithRequired(self.zoneId)
self.spots.append(spot)
self.jukebox = DistributedPartyJukeboxActivityAI(
self.air,
self.doId,
(0, 0, 0, 0)
)
self.jukebox.generateWithRequired(self.zoneId)
self.jukebox.sendUpdate('setX', [-21.8630])
self.jukebox.sendUpdate('setY', [-154.669])
self.jukebox.sendUpdate('setH', [148.7050])
self.jukebox.sendUpdate('unloadSign')
self.createTreasurePlanner()
def generateRegisteredObjects(self, slot):
if len(self.plots[slot]) > 0:
for item in self.items[slot]:
plotData = GardenGlobals.estatePlots[slot][item[0]]
if item[1] == GardenGlobals.FLOWER_TYPE:
newItem = DistributedFlowerAI(self.air)
newItem.setEstate(self.doId)
newItem.setOwnerPlot(self.plots[slot][item[0]].doId)
newItem.setPlot(item[0])
newItem.setHeading(plotData[2])
newItem.setPosition(plotData[0], plotData[1], 1.3)
newItem.setOwnerIndex(slot)
newItem.setWaterLevel(item[4])
newItem.setGrowthLevel(item[5])
newItem.setTypeIndex(item[2])
newItem.setVariety(item[3])
elif item[1] == GardenGlobals.GAG_TREE_TYPE:
newItem = DistributedGagTreeAI(self.air)
newItem.setEstate(self.doId)
newItem.setOwnerPlot(self.plots[slot][item[0]].doId)
newItem.setPlot(item[0])
newItem.setHeading(plotData[2])
newItem.setPosition(plotData[0], plotData[1], 1.3)
newItem.setOwnerIndex(slot)
newItem.setTypeIndex(item[2])
newItem.setWaterLevel(item[4])
newItem.setGrowthLevel(item[5])
elif item[1] == GardenGlobals.STATUARY_TYPE:
newItem = DistributedStatuaryAI(self.air)
newItem.setEstate(self.doId)
newItem.setOwnerPlot(self.plots[slot][item[0]].doId)
newItem.setPlot(item[0])
newItem.setHeading(plotData[2])
newItem.setPosition(plotData[0], plotData[1], 1.3)
newItem.setOwnerIndex(slot)
newItem.setTypeIndex(item[2])
newItem.setWaterLevel(item[4])
newItem.setGrowthLevel(item[5])
elif item[1] == GardenGlobals.TOON_STATUARY_TYPE:
newItem = DistributedToonStatuaryAI(self.air)
newItem.setEstate(self.doId)
newItem.setOwnerPlot(self.plots[slot][item[0]].doId)
newItem.setPlot(item[0])
newItem.setHeading(plotData[2])
newItem.setPosition(plotData[0], plotData[1], 1.3)
newItem.setOwnerIndex(slot)
newItem.setTypeIndex(item[2])
newItem.setWaterLevel(item[4])
newItem.setGrowthLevel(item[5])
newItem.setOptional(item[6])
else:
continue
newItem.generateWithRequired(self.zoneId)
self.plots[slot][item[0]].planted = newItem
self.plots[slot][item[0]].sendUpdate('plantedItem', [newItem.doId])
self.plots[slot][item[0]].sendUpdate('setMovie', [GardenGlobals.MOVIE_PLANT, 999999999])
ButterflyGlobals.generateIndexes(self.zoneId, ButterflyGlobals.ESTATE)
for i in range(0, ButterflyGlobals.NUM_BUTTERFLY_AREAS[ButterflyGlobals.ESTATE]):
for j in range(0, ButterflyGlobals.NUM_BUTTERFLIES[ButterflyGlobals.ESTATE]):
bfly = DistributedButterflyAI.DistributedButterflyAI(self.air, ButterflyGlobals.ESTATE, i, self.zoneId)
bfly.generateWithRequired(self.zoneId)
bfly.start()
self.addDistObj(bfly)
def destroy(self):
for house in self.houses:
if house:
house.requestDelete()
del self.houses[:]
self.houses = []
if self.pond:
self.pond.requestDelete()
for spot in self.spots:
spot.requestDelete()
self.spots = []
for target in self.targets:
target.requestDelete()
self.targets = []
self.pond.requestDelete()
self.pond = None
if self.jukebox:
self.jukebox.requestDelete()
if self.treasurePlanner:
self.treasurePlanner.stop()
self.gardenManager.destroy()
if self.rentalHandle:
self.rentalHandle.destroy()
self.rentalHandle = None
self.requestDelete()
def setEstateReady(self):
pass
def addDistObj(self, distObj):
self.doId2do[distObj.doId] = distObj
def setClientReady(self):
self.sendUpdate('setEstateReady', [])
def setClosestHouse(self, todo0):
pass
def setEstateType(self, type):
self.estateType = type
def setTreasureIds(self, todo0):
pass
def d_setEstateType(self, type):
self.sendUpdate('setEstateType', [type])
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 b_setEstateType(self, type):
self.setEstateType(type)
self.d_setEstateType(type)
def getEstateType(self):
return self.estateType
def requestServerTime(self):
avId = self.air.getAvatarIdFromSender()
self.sendUpdateToAvatarId(avId, 'setServerTime', [time.time() % HouseGlobals.DAY_NIGHT_PERIOD])
def setServerTime(self, todo0):
pass
def setDawnTime(self, dawnTime):
self.dawnTime = dawnTime
@ -320,22 +603,6 @@ class DistributedEstateAI(DistributedObjectAI):
def getDawnTime(self):
return self.dawnTime
def placeOnGround(self, todo0):
pass
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):
self.lastEpochTimestamp = last
@ -367,12 +634,13 @@ class DistributedEstateAI(DistributedObjectAI):
self.setRentalType(type)
def d_setRentalType(self, type):
self.sendUpdate("setRentalType", [type])
self.sendUpdate('setRentalType', [type])
def setRentalType(self, type):
expirestamp = self.getRentalTimeStamp()
if expirestamp == 0:
expire = 0
else:
expire = int(expirestamp - time.time())
@ -380,6 +648,7 @@ class DistributedEstateAI(DistributedObjectAI):
self.rentalType = 0
self.d_setRentalType(0)
self.b_setRentalTimeStamp(0)
else:
if self.rentalType == type:
return
@ -391,8 +660,7 @@ class DistributedEstateAI(DistributedObjectAI):
if self.rentalType == ToontownGlobals.RentalCannon:
self.rentalHandle = CannonRental(self)
elif self.rentalType == ToontownGlobals.RentalGameTable:
self.rentalHandle = TableRental(self)
else:
self.notify.warning('Unknown rental %s' % self.rentalType)
return
@ -403,7 +671,6 @@ class DistributedEstateAI(DistributedObjectAI):
return self.rentalType
def rentItem(self, rentType, duration):
self.rentalType = rentType
self.b_setRentalTimeStamp(time.time() + duration * 60)
self.b_setRentalType(rentType)
@ -424,7 +691,7 @@ class DistributedEstateAI(DistributedObjectAI):
self.items[0] = items
def d_setSlot0Items(self, items):
self.sendUpdate('setSlot0Items', [items])
self.sendUpdate('setSlot5Items', [items])
def b_setSlot0Items(self, items):
self.setSlot0Items(items)
@ -450,11 +717,11 @@ class DistributedEstateAI(DistributedObjectAI):
self.items[1] = items
def d_setSlot1Items(self, items):
self.sendUpdate('setSlot1Items', [items])
self.sendUpdate('setSlot2Items', [items])
def b_setSlot1Items(self, items):
self.setSlot1Items(items)
self.d_setSlot1Items(items)
self.setSlot2Items(items)
self.d_setSlot2Items(items)
def getSlot1Items(self):
return self.items[1]
@ -564,7 +831,7 @@ class DistributedEstateAI(DistributedObjectAI):
return self.items[5]
def setIdList(self, idList):
for i in xrange(len(idList)):
for i in range(len(idList)):
if i >= 6:
return
self.toons[i] = idList[i]
@ -574,26 +841,44 @@ class DistributedEstateAI(DistributedObjectAI):
def b_setIdList(self, idList):
self.setIdList(idList)
self.d_setIdList(idList)
self.d_setIdLst(idList)
def completeFlowerSale(self, todo0):
pass
def completeFlowerSale(self, flag):
if not flag:
return
def completeFishSale(self, sell):
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId)
if av:
if sell:
trophyResult = self.air.fishManager.creditFishTank(av)
if trophyResult:
self.sendUpdateToAvatarId(avId, 'thankSeller', [ToontownGlobals.FISHSALE_TROPHY, len(av.fishCollection), FishGlobals.getTotalNumFish()])
else:
self.sendUpdateToAvatarId(avId, 'thankSeller', [ToontownGlobals.FISHSALE_COMPLETE, 0, 0])
else:
self.sendUpdateToAvatarId(avId, 'thankSeller', [ToontownGlobals.FISHSALE_NONE, 0, 0])
if not av:
return
def awardedTrophy(self, todo0):
pass
collection = av.flowerCollection
earning = 0
newSpecies = 0
for flower in av.flowerBasket.getFlower():
if collection.collectFlower(flower) == GardenGlobals.COLLECT_NEW_ENTRY:
newSpecies += 1
earning += flower.getValue()
av.b_setFlowerBasket([], [])
av.d_setFlowerCollection(*av.flowerCollection.getNetLists())
av.addMoney(earning)
oldSpecies = len(collection) - newSpecies
dt = abs(len(collection) // 10 - oldSpecies // 10)
if dt:
self.notify.info('%d is getting a gardening trophy!' % avId)
maxHp = av.getMaxHp()
maxHp = min(ToontownGlobals.MaxHpLimit, maxHp + dt)
av.b_setMaxHp(maxHp)
av.toonUp(maxHp)
self.sendUpdate('awardedTrophy', [avId])
av.b_setGardenTrophies(range(len(collection) // 10))
def setClouds(self, clouds):
self.cloudType = clouds
@ -608,67 +893,55 @@ class DistributedEstateAI(DistributedObjectAI):
def getClouds(self):
return self.cloudType
def cannonsOver(self):
pass
# Garden methods
def getToonSlot(self, avId):
if avId not in self.toons:
return
def gameTableOver(self):
pass
return self.toons.index(avId)
def placeStarterGarden(self, avatar):
# TODO: Place garden if a toon already owns one.
avId = avatar.doId
slot = self.toons.index(avId)
plotPos = GardenGlobals.estatePlots[slot]
boxPos = GardenGlobals.estateBoxes[slot]
for p, n in enumerate(boxPos):
x, y, h, i = n
newBox = DistributedGardenBoxAI(self.air)
newBox.setEstate(self.doId)
newBox.setTypeIndex(i)
newBox.setPlot(p)
newBox.setOwnerIndex(slot)
newBox.setPosition(x, y, 0)
newBox.setHeading(h)
newBox.generateWithRequired(self.zoneId)
self.boxes[slot].append(newBox)
for p, n in enumerate(plotPos):
i = n[3]
if i in [GardenGlobals.GAG_TREE_TYPE, GardenGlobals.STATUARY_TYPE]:
x, y, h = n[:3]
newPlot = DistributedGardenPlotAI(self.air)
newPlot.setEstate(self.doId)
newPlot.setPlot(p)
newPlot.setOwnerIndex(slot)
newPlot.setPosition(x, y, 0)
newPlot.setHeading(h)
newPlot.generateWithRequired(self.zoneId)
self.plots[slot].append(newPlot)
elif i == GardenGlobals.FLOWER_TYPE:
# TODO: Place flower plots more accurately.
x, y, h = n[:3]
newPlot = DistributedGardenPlotAI(self.air)
newPlot.setEstate(self.doId)
newPlot.setPlot(p)
newPlot.setOwnerIndex(slot)
newPlot.setPosition(x, y, 1.3)
newPlot.setHeading(h)
newPlot.generateWithRequired(self.zoneId)
self.plots[slot].append(newPlot)
self.generateRegisteredObjects(slot)
def setSlot0Garden(self, flag):
self.__pendingGardens[0] = flag
def updateToons(self):
self.d_setSlot0ToonId(self.toons[0])
self.d_setSlot1ToonId(self.toons[1])
self.d_setSlot2ToonId(self.toons[2])
self.d_setSlot3ToonId(self.toons[3])
self.d_setSlot4ToonId(self.toons[4])
self.d_setSlot5ToonId(self.toons[5])
def setSlot1Garden(self, flag):
self.__pendingGardens[1] = flag
def setSlot2Garden(self, flag):
self.__pendingGardens[2] = flag
def setSlot3Garden(self, flag):
self.__pendingGardens[3] = flag
def setSlot4Garden(self, flag):
self.__pendingGardens[4] = flag
def setSlot5Garden(self, flag):
self.__pendingGardens[5] = flag
def placeStarterGarden(self, avId, record=1):
av = self.air.doId2do.get(avId)
if not av:
return
slot = self.getToonSlot(avId)
if slot is None:
return
if record:
av.b_setGardenStarted(1)
self.sendUpdate('setSlot%dGarden' % slot, ['started'])
self.notify.info('placeStarterGarden %d %d' % (avId, slot))
self.gardenManager.handleSingleGarden(avId)
def announceGenerate(self):
DistributedObjectAI.announceGenerate(self)
self.sendUpdate('setIdList', [self.toons])
def updateItems(self):
self.d_setSlot0Items(self.items[0])
self.d_setSlot1Items(self.items[1])
self.d_setSlot2Items(self.items[2])
self.d_setSlot3Items(self.items[3])
self.d_setSlot4Items(self.items[4])
self.d_setSlot5Items(self.items[5])
for index, started in self.__pendingGardens.items():
if started:
self.gardenManager.handleSingleGarden(self.toons[index])
self.__pendingGardens = {}
if config.GetBool('fake-garden-started-ai', False):
self.placeStarterGarden(100000002, 0)

View file

@ -4,11 +4,15 @@ from toontown.estate import FlowerBase
from toontown.estate import GardenGlobals
from toontown.toontowngui import TTDialog
from toontown.toonbase import TTLocalizer
from DistributedGardenBox import DistributedGardenBox
DIRT_AS_WATER_INDICATOR = True
DIRT_MOUND_HEIGHT = 0.3
class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.FlowerBase):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFlower')
deferFor = 2
def __init__(self, cr):
DistributedPlantBase.DistributedPlantBase.__init__(self, cr)
@ -17,16 +21,16 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
self.stickUp = 1.07
if DIRT_AS_WATER_INDICATOR:
self.stickUp += DIRT_MOUND_HEIGHT
self.collSphereRadius = 2.8
self.collSphereRadius = 2.2
self.shadowScale = 0.5
self.collSphereOffset = 0.0
self.dirtMound = None
self.sandMound = None
self.resultDialog = None
return
def delete(self):
DistributedPlantBase.DistributedPlantBase.delete(self)
del self.dirtMound
del self.sandMound
@ -34,9 +38,6 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
DistributedPlantBase.DistributedPlantBase.setTypeIndex(self, typeIndex)
self.setSpecies(typeIndex)
def getTypeIndex(self):
return self.typeIndex
def showWiltOrBloom(self):
if not self.model:
return
@ -52,7 +53,7 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
desat = wilt.find('**/*desat*')
bloom.hide()
leaves = wilt.findAllMatches('**/*leaf*')
for leafIndex in xrange(leaves.getNumPaths()):
for leafIndex in range(leaves.getNumPaths()):
leaf = leaves.getPath(leafIndex)
leaf.setColorScale(1.0, 0.3, 0.1, 1.0)
@ -132,7 +133,7 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
base.localAvatar.removeShovelRelatedDoId(self.doId)
base.localAvatar.setInGardenAction(self)
base.cr.playGame.getPlace().detectedGardenPlotUse()
self.sendUpdate('removeItem', [base.localAvatar.doId])
self.sendUpdate('removeItem', [])
def setWaterLevel(self, waterLevel):
DistributedPlantBase.DistributedPlantBase.setWaterLevel(self, waterLevel)
@ -140,9 +141,6 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
if self.model:
self.adjustWaterIndicator()
def getWaterLevel(self):
return self.waterLevel
def setGrowthLevel(self, growthLevel):
origGrowthLevel = self.growthLevel
self.growthLevel = growthLevel
@ -150,8 +148,8 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
self.loadModel()
self.makeMovieNode()
def getGrowthLevel(self):
return self.growthLevel
if hasattr(self, '_boxDoId'):
self.setBoxDoId(*self._boxDoId)
def makeMovieNode(self):
self.movieNode = self.rotateNode.attachNewNode('moviePos')
@ -200,4 +198,17 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
self.resultDialog.destroy()
self.resultDialog = None
self.finishInteraction()
return
def setBoxDoId(self, boxId, index):
self._boxDoId = (boxId, index)
box = base.cr.doId2do[boxId]
x = GardenGlobals.FLOWER_POS[box.typeIndex][index]
self.setPos(0, 0, 0)
self.reparentTo(box)
self.setZ(1.5)
self.setX(x)
def stick2Ground(self):
pass

View file

@ -1,26 +1,145 @@
from direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedPlantBaseAI import DistributedPlantBaseAI
from otp.ai.MagicWordGlobal import *
from DistributedPlantBaseAI import DistributedPlantBaseAI
from FlowerBase import FlowerBase
# TODO: Add flower to basket when picking, give shovel skill only if the
# flower is player's tier.
import GardenGlobals
import time
class DistributedFlowerAI(DistributedPlantBaseAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedFlowerAI")
ONE_DAY = 86400
def __init__(self, air):
DistributedPlantBaseAI.__init__(self, air)
self.air = air
self.typeIndex = None
class DistributedFlowerAI(DistributedPlantBaseAI, FlowerBase):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFlowerAI')
def setTypeIndex(self, typeIndex):
DistributedPlantBaseAI.setTypeIndex(self, typeIndex)
self.typeIndex = typeIndex
def setTypeIndex(self, value):
DistributedPlantBaseAI.setTypeIndex(self, value)
FlowerBase.setSpecies(self, value)
def getTypeIndex(self):
return self.typeIndex
def calculate(self, lastCheck):
now = int(time.time())
if lastCheck == 0:
lastCheck = now
def setVariety(self, variety):
self.variety = variety
grown = 0
# Water level
elapsed = now - lastCheck
while elapsed > ONE_DAY:
if self.waterLevel >= 0:
grown += 1
elapsed -= ONE_DAY
self.waterLevel -= 1
self.waterLevel = max(self.waterLevel, -2)
# Growth level
maxGrowth = self.growthThresholds[2]
newGL = min(self.growthLevel + grown, maxGrowth)
self.setGrowthLevel(newGL)
self.lastCheck = now - elapsed
self.update()
def update(self):
mdata = map(list, self.mgr.data['flowers'])
mdata[self.flowerIndex] = [self.getSpecies(), self.waterLevel, self.lastCheck, self.getGrowthLevel(), self.getVariety()]
self.mgr.data['flowers'] = mdata
self.mgr.update()
def removeItem(self, usingSatanPickAll=0):
avId = self.air.getAvatarIdFromSender()
if not usingSatanPickAll:
if avId != self.ownerDoId:
self.air.writeServerEvent('suspicious', avId, 'tried to remove someone else\'s flower!')
return
self.d_setMovie(GardenGlobals.MOVIE_REMOVE)
action = 'remove'
if self.getGrowthLevel() >= self.growthThresholds[2]:
action = 'pick'
def _remove(task):
if not self.air:
return
av = self.air.doId2do.get(self.ownerDoId)
if not av:
return
plot = self.mgr.placePlot(self.flowerIndex)
plot.flowerIndex = self.flowerIndex
plot.setPlot(self.plot)
plot.setOwnerIndex(self.ownerIndex)
plot.generateWithRequired(self.zoneId)
index = (0, 1, 2, 2, 2, 3, 3, 3, 4, 4)[self.flowerIndex]
idx = (0, 0, 0, 1, 2, 0, 1, 2, 0, 1)[self.flowerIndex]
plot.sendUpdate('setBoxDoId', [self.mgr._boxes[index].doId, idx])
self.air.writeServerEvent('%s-flower' % action, avId, plot=self.plot)
self.requestDelete()
self.mgr.flowers.remove(self)
mdata = map(list, self.mgr.data['flowers'])
mdata[self.flowerIndex] = self.mgr.getNullPlant()
self.mgr.data['flowers'] = mdata
self.mgr.update()
if action == 'pick':
av.b_setShovelSkill(av.getShovelSkill() + self.getValue())
av.addFlowerToBasket(self.getSpecies(), self.getVariety())
if task:
return task.done
if usingSatanPickAll:
_remove(None)
else:
taskMgr.doMethodLater(7, _remove, self.uniqueName('do-remove'))
@magicWord(category=CATEGORY_PROGRAMMER)
def satanGrowFlowers():
av = spellbook.getTarget()
estate = av.air.estateManager._lookupEstate(av)
if not estate:
return 'Estate not found!'
garden = estate.gardenManager.gardens.get(av.doId)
if not garden:
return 'Garden not found!'
now = int(time.time())
i = 0
for flower in garden.flowers:
flower.b_setWaterLevel(5)
flower.b_setGrowthLevel(2)
flower.update()
i += 1
return '%d disgusting flowers grown' % i
@magicWord(category=CATEGORY_PROGRAMMER)
def satanPickAll():
av = spellbook.getTarget()
estate = av.air.estateManager._lookupEstate(av)
if not estate:
return 'Estate not found!'
garden = estate.gardenManager.gardens.get(av.doId)
if not garden:
return 'Garden not found!'
i = 0
for flower in garden.flowers.copy():
if flower.getGrowthLevel() >= flower.growthThresholds[2]:
flower.removeItem(1)
i += 1
return '%d disgusting flowers picked' % i
def getVariety(self):
return self.variety

View file

@ -29,7 +29,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.backupFruits = []
self.signHasBeenStuck2Ground = False
self.setName('DistributedGagTree')
return
self.fruiting = 0
def delete(self):
DistributedPlantBase.DistributedPlantBase.delete(self)
@ -79,7 +79,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.model.reparentTo(self.rotateNode)
if self.isFruiting() and not self.isWilted():
self.fruits = []
for i in xrange(1, self.maxFruit + 1):
for i in range(1, self.maxFruit + 1):
pos = self.model.find('**/locator' + str(i))
if pos and not pos.isEmpty():
fruit = self.prop.copyTo(self.model)
@ -141,8 +141,6 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.confirmDialog.destroy()
self.confirmDialog = None
if value > 0:
base.localAvatar.showGardeningGui()
base.localAvatar.removeShovelRelatedDoId(self.doId)
self.doPicking()
else:
self.finishInteraction()
@ -151,7 +149,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
def doPicking(self):
if not self.canBePicked():
return
self.sendUpdate('removeItem', [base.localAvatar.doId])
self.sendUpdate('removeItem', [])
def createBackupFruits(self):
if not hasattr(self, 'fruits'):
@ -175,6 +173,11 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.backupFruits.append(newFruit)
def clearBackupFruits(self):
if self.fruits:
for fruit in self.fruits:
fruit.removeNode()
self.fruits = None
self.backupFruits = []
def doHarvesting(self):
@ -184,14 +187,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
for fruit in self.backupFruits:
fruit.show()
self.sendUpdate('requestHarvest', [base.localAvatar.doId])
def hideItems(self):
if hasattr(self, 'fruits') and self.fruits:
seq = Parallel()
for item in self.fruits:
seq.append(LerpFunc(item.setAlphaScale, fromData=1, toData=0, duration=1))
seq.start()
self.sendUpdate('requestHarvest', [])
def getTrack(self):
return self.gagTrack
@ -268,7 +264,6 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.movie.append(Func(toon.loop, 'neutral'))
if avId == localAvatar.doId:
self.movie.append(Func(self.finishInteraction))
self.movie.append(Func(self.hideItems))
self.movie.append(Func(self.movieDone))
self.movie.append(Func(self.doResultDialog))
self.movie.start()
@ -299,7 +294,6 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
for fruit in self.backupFruits:
fruitTrack.append(Sequence(Func(fruit.show), LerpPosInterval(fruit, 1.5, pos, startPos=Point3(fruit.getX(), fruit.getY(), fruit.getZ() + self.model.getZ())), Func(fruit.removeNode)))
self.fruits = None
harvestTrack = Sequence(fruitTrack, Func(self.clearBackupFruits))
return harvestTrack
@ -343,7 +337,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
picker.traverse(render)
if queue.getNumEntries() > 0:
queue.sortEntries()
for index in xrange(queue.getNumEntries()):
for index in range(queue.getNumEntries()):
entry = queue.getEntry(index)
if DistributedLawnDecor.recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.signModel.wrtReparentTo(render)
@ -356,25 +350,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
return Task.done
def canBeHarvested(self):
myTrack, myLevel = GardenGlobals.getTreeTrackAndLevel(self.typeIndex)
levelsInTrack = []
levelTreeDict = {}
allGagTrees = base.cr.doFindAll('DistributedGagTree')
for gagTree in allGagTrees:
if gagTree.getOwnerId() == localAvatar.doId:
curTrack, curLevel = GardenGlobals.getTreeTrackAndLevel(gagTree.typeIndex)
if curTrack == myTrack:
levelsInTrack.append(curLevel)
levelTreeDict[curLevel] = gagTree
for levelToTest in xrange(myLevel):
if levelToTest not in levelsInTrack:
return False
curTree = levelTreeDict[levelToTest]
if not curTree.isGTEFullGrown():
return False
return True
return self.isFruiting()
def hasDependentTrees(self):
myTrack, myLevel = GardenGlobals.getTreeTrackAndLevel(self.typeIndex)
@ -403,8 +379,14 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.finishInteraction()
return
def velvetRoped(self):
return not base.cr.isPaid() and ToontownBattleGlobals.gagIsPaidOnly(self.gagTrack, self.gagLevel)
def allowedToPick(self):
return True
retval = True
if self.velvetRoped():
retval = False
return retval
def unlockPick(self):
retval = True
@ -417,3 +399,15 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
if inventory.numItem(self.gagTrack, self.gagLevel) >= inventory.getMax(self.gagTrack, self.gagLevel):
retval = False
return retval
def setFruiting(self, fruiting):
self.fruiting = fruiting
if self.model:
self.model.removeNode()
self.loadModel()
self.adjustWaterIndicator()
self.stick2Ground()
def isFruiting(self):
return self.fruiting

View file

@ -1,35 +1,223 @@
from direct.directnotify import DirectNotifyGlobal
from otp.ai.MagicWordGlobal import *
from toontown.estate.DistributedPlantBaseAI import DistributedPlantBaseAI
import GardenGlobals
import GardenGlobals, time
ONE_DAY = 86400
PROBLEM_WILTED = 1
PROBLEM_NOT_GROWN = 2
PROBLEM_HARVESTED_LATELY = 4
class DistributedGagTreeAI(DistributedPlantBaseAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGagTreeAI")
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGagTreeAI')
GrowRate = config.GetBool('trees-grow-rate', 2)
def __init__(self, air):
DistributedPlantBaseAI.__init__(self, air)
self.air = air
def __init__(self, mgr):
DistributedPlantBaseAI.__init__(self, mgr)
self.wilted = 0
def announceGenerate(self):
DistributedPlantBaseAI.announceGenerate(self)
def delete(self):
DistributedPlantBaseAI.delete(self)
def disable(self):
DistributedPlantBaseAI.disable(self)
messenger.send(self.getEventName('generate'))
def setWilted(self, wilted):
self.wilted = wilted
def d_setWilted(self, wilted):
self.sendUpdate('setWilted', [wilted])
def b_setWilted(self, wilted):
self.setWilted(wilted)
self.d_setWilted(wilted)
def getWilted(self):
return self.wilted
def requestHarvest(self, doId):
# TODO: Actually harvest the gags and add them to toon inventory.
av = simbase.air.doId2do.get(doId)
def calculate(self, lastHarvested, lastCheck):
now = int(time.time())
if lastCheck == 0:
lastCheck = now
grown = 0
# Water level
elapsed = now - lastCheck
while elapsed > ONE_DAY:
if self.waterLevel >= 0:
grown += self.GrowRate
elapsed -= ONE_DAY
self.waterLevel -= 1
self.waterLevel = max(self.waterLevel, -2)
# Growth level
maxGrowth = self.growthThresholds[2]
newGL = min(self.growthLevel + grown, maxGrowth)
self.setGrowthLevel(newGL)
self.setWilted(self.waterLevel == -2)
self.lastCheck = now - elapsed
self.lastHarvested = lastHarvested
self.update()
def calcDependencies(self):
if self.getWilted():
return
missingPrevIndex = 0
track, value = GardenGlobals.getTreeTrackAndLevel(self.typeIndex)
while value:
value -= 1
if not self.mgr.hasTree(track, value):
self.b_setWilted(1)
continue
tree = self.mgr.getTree(track, value)
if not tree:
self.b_setWilted(1)
continue
self.accept(self.getEventName('going-down', 666), self.ignoreAll)
self.accept(self.getEventName('remove', track * 7 + value), self.calcDependencies)
def getEventName(self, string, typeIndex=None):
typeIndex = typeIndex if typeIndex is not None else self.typeIndex
return 'garden-%d-%d-%s' % (self.ownerDoId, typeIndex, string)
def delete(self):
messenger.send(self.getEventName('remove'))
self.ignoreAll()
DistributedPlantBaseAI.delete(self)
def update(self):
mdata = map(list, self.mgr.data['trees'])
mdata[self.treeIndex] = [self.typeIndex, self.waterLevel, self.lastCheck, self.getGrowthLevel(), self.lastHarvested]
self.mgr.data['trees'] = mdata
self.mgr.update()
def isFruiting(self):
problem = 0
if self.getWilted():
problem |= PROBLEM_WILTED
if self.getGrowthLevel() < self.growthThresholds[2]:
problem |= PROBLEM_NOT_GROWN
if (self.lastCheck - self.lastHarvested) < ONE_DAY:
problem |= PROBLEM_HARVESTED_LATELY
return problem
def getFruiting(self):
return self.isFruiting() == 0
def requestHarvest(self):
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId)
if not av:
return
if avId != self.ownerDoId:
self.air.writeServerEvent('suspicious', avId, 'tried to harvest someone else\'s tree!')
return
problem = self.isFruiting()
if problem:
self.air.writeServerEvent('suspicious', avId, 'tried to harvest a tree that\'s not fruiting!', problem=problem)
return
harvested = 0
track, level = GardenGlobals.getTreeTrackAndLevel(self.typeIndex)
while av.inventory.addItem(track, level) > 0 and harvested < 10:
harvested += 1
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_HARVEST, doId])
av.d_setInventory(av.getInventory())
self.lastHarvested = int(time.time())
self.sendUpdate('setFruiting', [self.getFruiting()])
self.d_setMovie(GardenGlobals.MOVIE_HARVEST)
self.update()
def removeItem(self):
avId = self.air.getAvatarIdFromSender()
self.d_setMovie(GardenGlobals.MOVIE_REMOVE)
def _remove(task):
if not self.air:
return
plot = self.mgr.placePlot(self.treeIndex)
plot.setPlot(self.plot)
plot.setPos(self.getPos())
plot.setH(self.getH())
plot.setOwnerIndex(self.ownerIndex)
plot.generateWithRequired(self.zoneId)
self.air.writeServerEvent('remove-tree', avId, plot=self.plot)
self.requestDelete()
self.mgr.trees.remove(self)
mdata = map(list, self.mgr.data['trees'])
mdata[self.treeIndex] = self.mgr.getNullPlant()
self.mgr.data['trees'] = mdata
self.mgr.update()
self.mgr.reconsiderAvatarOrganicBonus()
return task.done
taskMgr.doMethodLater(7, _remove, self.uniqueName('do-remove'))
def doGrow(self, grown):
maxGrowth = self.growthThresholds[2]
newGL = max(0, min(self.growthLevel + grown, maxGrowth))
oldGrowthLevel = self.growthLevel
self.b_setGrowthLevel(newGL)
self.update()
return newGL - oldGrowthLevel
@magicWord(category=CATEGORY_PROGRAMMER, types=[int, int, int])
def satanGrow(track, index, grown=21):
av = spellbook.getTarget()
estate = av.air.estateManager._lookupEstate(av)
if not estate:
return 'Estate not found!'
garden = estate.gardenManager.gardens.get(av.doId)
if not garden:
return 'Garden not found!'
tree = garden.getTree(track, index)
if not tree:
return 'Tree not found!'
result = tree.doGrow(grown)
return 'Satan has grown %d units!' % result
@magicWord(category=CATEGORY_PROGRAMMER, types=[int, int])
def satanFruit(track, index):
av = spellbook.getTarget()
estate = av.air.estateManager._lookupEstate(av)
if not estate:
return 'Estate not found!'
garden = estate.gardenManager.gardens.get(av.doId)
if not garden:
return 'Garden not found!'
tree = garden.getTree(track, index)
if not tree:
return 'Tree not found!'
tree.calculate(0, tree.lastCheck)
tree.sendUpdate('setFruiting', [tree.getFruiting()])
return 'Satan is now fruiting!'

View file

@ -1,9 +1,22 @@
from panda3d.core import *
from direct.distributed import DistributedObject
from direct.distributed.ClockDelta import *
from direct.directnotify import DirectNotifyGlobal
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from toontown.toonbase.ToonBaseGlobal import *
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from direct.distributed.ClockDelta import *
from toontown.toonbase import ToontownGlobals
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from direct.fsm import ClassicFSM
from direct.fsm import State
from toontown.toon import Toon
from direct.showbase import RandomNumGen
from toontown.toonbase import TTLocalizer
import random
import random
import cPickle
from direct.showbase import PythonUtil
from toontown.hood import Place
import Estate
import HouseGlobals
class DistributedGarden(DistributedObject.DistributedObject):
@ -18,7 +31,7 @@ class DistributedGarden(DistributedObject.DistributedObject):
self.radius = 0
self.gridCells = 20
self.propTable = [None] * self.gridCells
for i in xrange(len(self.propTable)):
for i in range(len(self.propTable)):
self.propTable[i] = [None] * self.gridCells
self.dx = 1.0 / self.gridCells

View file

@ -4,25 +4,6 @@ from direct.distributed.DistributedObjectAI import DistributedObjectAI
class DistributedGardenAI(DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGardenAI")
def __init__(self, air):
DistributedObjectAI.__init__(self, air)
self.air = air
self.props = []
def sendNewProp(self, todo0, todo1, todo2, todo3):
pass
def generate(self):
DistributedObjectAI.generate(self)
def announceGenerate(self):
DistributedObjectAI.announceGenerate(self)
def disable(self):
DistributedObjectAI.disable(self)
def delete(self):
DistributedObjectAI.delete(self)
def setProps(self, props):
self.props = props
def d_sendNewProp(self, prop, x, y, z):
self.sendUpdate('sendNewProp', [prop, x, y, z])

View file

@ -20,17 +20,13 @@ class DistributedGardenBox(DistributedLawnDecor.DistributedLawnDecor):
self.plantingGuiDoneEvent = 'plantingGuiDone'
self.defaultModel = 'phase_5.5/models/estate/planterC'
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedLawnDecor.DistributedLawnDecor.announceGenerate(self)
def doModelSetup(self):
if self.typeIndex == GardenGlobals.BOX_THREE:
self.defaultModel = 'phase_5.5/models/estate/planterA'
elif self.typeIndex == GardenGlobals.BOX_TWO:
self.defaultModel = 'phase_5.5/models/estate/planterC'
else:
self.defaultModel = 'phase_5.5/models/estate/planterB'
self.defaultModel = 'phase_5.5/models/estate/planterD'
self.collSphereOffset = 0.0
self.collSphereRadius = self.collSphereRadius * 1.41
self.plotScale = Vec3(1.0, 1.0, 1.0)
@ -45,7 +41,6 @@ class DistributedGardenBox(DistributedLawnDecor.DistributedLawnDecor):
self.model.setScale(self.plotScale)
self.model.reparentTo(self.rotateNode)
self.stick2Ground()
return
def handleEnterPlot(self, entry = None):
pass
@ -55,3 +50,4 @@ class DistributedGardenBox(DistributedLawnDecor.DistributedLawnDecor):
def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex

View file

@ -4,13 +4,9 @@ from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI
class DistributedGardenBoxAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGardenBoxAI")
def __init__(self, air):
DistributedLawnDecorAI.__init__(self, air)
self.air = air
self.typeIndex = 0
def setTypeIndex(self, index):
self.typeIndex = index
self.index = index
def getTypeIndex(self):
return self.typeIndex
return self.index

View file

@ -2,6 +2,7 @@ import DistributedLawnDecor
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.ShowBase import *
from direct.interval.IntervalGlobal import *
from DistributedGardenBox import DistributedGardenBox
import GardenGlobals
from toontown.toonbase import TTLocalizer
from toontown.estate import PlantingGUI
@ -14,6 +15,7 @@ import types
class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGardenPlot')
deferFor = 2
def __init__(self, cr):
DistributedLawnDecor.DistributedLawnDecor.__init__(self, cr)
@ -25,7 +27,6 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.defaultModel = 'phase_5.5/models/estate/dirt_mound'
self.colorScaler = Vec4(1, 1, 1, 1)
self.plantingGui = None
self.planted = None
return
def delete(self):
@ -84,8 +85,6 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
return self.getPlantingText()
def handleEnterPlot(self, entry = None):
#Force Gardens -Zach
base.localAvatar.setGardenStarted(True)
dist = self.getDistance(localAvatar)
if self.canBePlanted():
base.localAvatar.addShovelRelatedDoId(self.doId)
@ -110,12 +109,7 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
return plantText
def canBePlanted(self):
retval = True
if not base.localAvatar.doId == self.getOwnerId():
retval = False
if hasattr(self, 'planted') and self.planted:
retval = False
return retval
return base.localAvatar.doId == self.getOwnerId()
def plantSomething(self):
whatCanBePlanted = GardenGlobals.whatCanBePlanted(self.ownerIndex, self.plot)
@ -143,13 +137,14 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
recipeKey = GardenGlobals.getRecipeKey(recipeStr, special)
if recipeKey >= 0:
species, variety = GardenGlobals.getSpeciesVarietyGivenRecipe(recipeKey)
print 'RK>0', species, variety
if species >= 0 and variety >= 0:
self.sendUpdate('plantFlower', [species, variety, base.localAvatar.doId])
self.sendUpdate('plantFlower', [species, variety])
successPlanting = True
else:
self.notify.debug('%s %d is not a valid recipe' % (recipeStr, special))
burntBeans = len(recipeStr)
self.sendUpdate('plantNothing', [burntBeans, base.localAvatar.doId])
self.sendUpdate('plantNothing', [burntBeans])
if successPlanting:
flowerName = GardenGlobals.getFlowerVarietyName(species, variety)
stringToShow = TTLocalizer.getResultPlantedSomethingSentence(flowerName)
@ -209,11 +204,11 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
if species >= 205 and species <= 208:
successToonStatue = True
else:
self.sendUpdate('plantStatuary', [species, base.localAvatar.doId])
self.sendUpdate('plantStatuary', [species])
else:
self.notify.debug('%s %d is not a valid recipe' % (recipeStr, special))
burntBeans = len(recipeStr)
self.sendUpdate('plantNothing', [burntBeans, base.localAvatar.doId])
self.sendUpdate('plantNothing', [burntBeans])
if successPlanting:
itemName = GardenGlobals.PlantAttributes[species]['name']
stringToShow = TTLocalizer.getResultPlantedSomethingSentence(itemName)
@ -252,7 +247,7 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
base.localAvatar.showGardeningGui()
base.localAvatar.removeShovelRelatedDoId(self.doId)
if willPlant:
self.sendUpdate('plantToonStatuary', [species, dnaCode, base.localAvatar.doId])
self.sendUpdate('plantToonStatuary', [species, dnaCode])
else:
self.popupItemPlantingGui()
return
@ -271,21 +266,11 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
base.localAvatar.showGardeningGui()
base.localAvatar.removeShovelRelatedDoId(self.doId)
if willPlant:
self.sendUpdate('plantGagTree', [gagTrack, gagLevel, base.localAvatar.doId])
self.sendUpdate('plantGagTree', [gagTrack, gagLevel])
else:
self.finishInteraction()
return
def plantedItem(self, doId):
self.planted = doId
def removePlanted(self):
if self.planted:
item = base.cr.doId2do.get(self.planted)
if item:
item.delete()
self.planted = None
def setMovie(self, mode, avId):
if mode == GardenGlobals.MOVIE_PLANT:
self.doPlaceItemTrack(avId)
@ -316,8 +301,8 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.movie.append(Func(toon.detachShovel))
if self.model:
pos = self.model.getPos()
pos.setZ(pos[2] + 1)
animProp = LerpPosInterval(self.model, 3, pos, self.model.getPos())
pos.setZ(pos[2] - 1)
animProp = LerpPosInterval(self.model, 3, self.model.getPos(), pos)
shrinkProp = LerpScaleInterval(self.model, 3, scale=self.plotScale, startScale=0.01)
objAnimShrink = ParallelEndTogether(animProp, shrinkProp)
self.movie.append(objAnimShrink)
@ -325,16 +310,10 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.movie.append(Func(toon.loop, 'neutral'))
if avId == localAvatar.doId:
self.movie.append(Func(self.finishInteraction))
self.movie.append(Func(self.removePlanted))
self.movie.append(Func(self.movieDone))
self.movie.start()
def doPlaceItemTrack(self, avId, item = None):
if avId == 999999999:
pos = self.model.getPos()
pos.setZ(pos[2] - 1)
self.model.setPos(pos)
self.model.setScale(0.01)
return
toon = base.cr.doId2do.get(avId)
if not toon:
return
@ -348,24 +327,14 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), placeItemTrack)
if avId == localAvatar.doId:
self.expectingReplacement = 1
self.movie.append(Func(self.sendUpdate, 'finishPlanting', [avId]))
self.movie.append(Func(self.movieDone))
self.movie.start()
def generatePlaceItemTrack(self, toon, item):
sound = loader.loadSfx('phase_5.5/audio/sfx/burrow.ogg')
sound.setPlayRate(0.5)
placeItemTrack = Parallel()
placeItemTrack.append(Sequence(ActorInterval(toon, 'start-dig'),
Parallel(ActorInterval(toon, 'loop-dig', loop=1, duration=5.13),
Sequence(Wait(0.25),
SoundInterval(sound, node=toon, duration=0.55),
Wait(0.8),
SoundInterval(sound, node=toon, duration=0.55),
Wait(1.35),
SoundInterval(sound, node=toon, duration=0.55))),
ActorInterval(toon, 'start-dig', playRate=-1),
Func(toon.loop, 'neutral'),
Func(toon.detachShovel)))
placeItemTrack.append(Sequence(ActorInterval(toon, 'start-dig'), Parallel(ActorInterval(toon, 'loop-dig', loop=1, duration=5.13), Sequence(Wait(0.25), SoundInterval(sound, node=toon, duration=0.55), Wait(0.8), SoundInterval(sound, node=toon, duration=0.55), Wait(1.35), SoundInterval(sound, node=toon, duration=0.55))), ActorInterval(toon, 'start-dig', playRate=-1), Func(toon.loop, 'neutral'), Func(toon.detachShovel)))
if self.model:
pos = self.model.getPos()
pos.setZ(pos[2] - 1)
@ -374,12 +343,7 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
objAnimShrink = ParallelEndTogether(animProp, shrinkProp)
placeItemTrack.append(objAnimShrink)
if item:
placeItemTrack.append(Sequence(Func(item.reparentTo, toon.rightHand),
Wait(0.55),
Func(item.wrtReparentTo, render),
Parallel(LerpHprInterval(item, hpr=self.getHpr(render), duration=1.2),
ProjectileInterval(item, endPos=self.getPos(render), duration=1.2, gravityMult=0.45)),
Func(item.removeNode)))
placeItemTrack.append(Sequence(Func(item.reparentTo, toon.rightHand), Wait(0.55), Func(item.wrtReparentTo, render), Parallel(LerpHprInterval(item, hpr=self.getHpr(render), duration=1.2), ProjectileInterval(item, endPos=self.getPos(render), duration=1.2, gravityMult=0.45)), Func(item.removeNode)))
return placeItemTrack
def makeMovieNode(self):
@ -390,3 +354,20 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.stick2Ground()
else:
DistributedLawnDecor.DistributedLawnDecor.makeMovieNode(self)
def setBoxDoId(self, boxId, index):
box = base.cr.doId2do[boxId]
x = GardenGlobals.FLOWER_POS[box.typeIndex][index]
self.setPos(0, 0, 0)
self.reparentTo(box)
self.setZ(1.2)
self.setX(x)
def stick2Ground(self, *args, **kwargs):
plotType = GardenGlobals.whatCanBePlanted(self.ownerIndex, self.plot)
if plotType == GardenGlobals.FLOWER_TYPE:
return
return DistributedLawnDecor.DistributedLawnDecor.stick2Ground(self, *args, **kwargs)

View file

@ -1,189 +1,249 @@
from direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI
from DistributedToonStatuaryAI import DistributedToonStatuaryAI
from DistributedStatuaryAI import DistributedStatuaryAI
from DistributedGagTreeAI import DistributedGagTreeAI
from DistributedFlowerAI import DistributedFlowerAI
from otp.ai.MagicWordGlobal import *
from DistributedLawnDecorAI import DistributedLawnDecorAI
import GardenGlobals
import datetime
slots2plots = {
0: GardenGlobals.plots0,
1: GardenGlobals.plots1,
2: GardenGlobals.plots2,
3: GardenGlobals.plots3,
4: GardenGlobals.plots4,
5: GardenGlobals.plots5
}
class DistributedGardenPlotAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGardenPlotAI")
def __init__(self, air):
DistributedLawnDecorAI.__init__(self, air)
self.air = air
self.planted = None
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGardenPlotAI')
def announceGenerate(self):
DistributedLawnDecorAI.announceGenerate(self)
self.plotType = GardenGlobals.whatCanBePlanted(self.ownerIndex, self.plot)
self.__plantingAvId = 0
def delete(self):
DistributedLawnDecorAI.delete(self)
def disable(self):
DistributedLawnDecorAI.disable(self)
def finishPlanting(self, avId):
self.planted.generateWithRequired(self.zoneId)
self.addData()
self.sendUpdate('plantedItem', [self.planted.doId])
self.planted.sendUpdate('setMovie', [GardenGlobals.MOVIE_FINISHPLANTING, avId])
def finishRemoving(self, avId):
self.removeData()
self.planted.removeNode()
self.planted.delete()
simbase.air.removeObject(self.planted.doId)
self.planted = None
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_FINISHREMOVING, avId])
def addData(self):
estate = simbase.air.doId2do.get(self.getEstate())
plantedAt = int(datetime.datetime.now().strftime('%Y%m%d%H%M')) # TODO: Possibly store this in mongodb/cPickle instead.
if isinstance(self.planted, DistributedFlowerAI):
data = [
self.getPlot(),
GardenGlobals.FLOWER_TYPE,
self.planted.getTypeIndex(),
self.planted.getVariety(),
self.planted.getWaterLevel(),
self.planted.getGrowthLevel(),
0,
plantedAt,
plantedAt
]
elif isinstance(self.planted, DistributedGagTreeAI):
data = [
self.getPlot(),
GardenGlobals.GAG_TREE_TYPE,
self.planted.getTypeIndex(),
0,
self.planted.getWaterLevel(),
self.planted.getGrowthLevel(),
0,
plantedAt,
plantedAt
]
elif isinstance(self.planted, DistributedToonStatuaryAI):
data = [
self.getPlot(),
GardenGlobals.TOON_STATUARY_TYPE,
self.planted.getTypeIndex(),
0,
self.planted.getWaterLevel(),
self.planted.getGrowthLevel(),
self.planted.getOptional(),
plantedAt,
plantedAt
]
elif isinstance(self.planted, DistributedStatuaryAI):
data = [
self.getPlot(),
GardenGlobals.STATUARY_TYPE,
self.planted.getTypeIndex(),
0,
self.planted.getWaterLevel(),
self.planted.getGrowthLevel(),
0,
plantedAt,
plantedAt
]
else:
def __initialSanityCheck(self, wantedType=None, forceOwner=False):
if self.__plantingAvId:
# Busy, silently ignore
return
estate.items[self.getOwnerIndex()].append(tuple(data))
estate.updateItems()
def removeData(self):
estate = simbase.air.doId2do.get(self.getEstate())
dataIndex = -1
for n, item in enumerate(estate.items[self.getOwnerIndex()]):
if item[0] == self.getPlot():
dataIndex = n
if dataIndex >= 0:
del estate.items[self.getOwnerIndex()][dataIndex]
estate.updateItems()
avId = self.air.getAvatarIdFromSender()
def plantFlower(self, species, variety, toon):
#free for now
#av = simbase.air.doId2do.get(toon)
#av.takeMoney(GardenGlobals.getNumBeansRequired(species, variety))
self.planted = DistributedFlowerAI(self.air)
self.planted.setEstate(self.getEstate())
self.planted.setOwnerPlot(self.doId)
self.planted.setPlot(self.getPlot())
self.planted.setHeading(self.getHeading())
self.planted.setPosition(*self.getPosition())
self.planted.setOwnerIndex(self.getOwnerIndex())
self.planted.setWaterLevel(0)
self.planted.setGrowthLevel(0)
self.planted.setTypeIndex(species)
self.planted.setVariety(variety)
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_PLANT, toon])
av = self.air.doId2do.get(avId)
if not av:
self.air.writeServerEvent('suspicious', avId, 'called DistributedGardenPlotAI method outside shard!')
return
def plantGagTree(self, track, level, toon):
#free for now
#av = simbase.air.doId2do.get(toon)
#av.inventory.useItem(track, level)
#av.d_setInventory(av.inventory.makeNetString())
self.planted = DistributedGagTreeAI(self.air)
self.planted.setEstate(self.getEstate())
self.planted.setOwnerPlot(self.doId)
self.planted.setPlot(self.getPlot())
self.planted.setHeading(self.getHeading())
self.planted.setPosition(*self.getPosition())
self.planted.setOwnerIndex(self.getOwnerIndex())
self.planted.setTypeIndex(GardenGlobals.getTreeTypeIndex(track, level))
self.planted.setWaterLevel(0)
self.planted.setGrowthLevel(0)
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_PLANT, toon])
if wantedType is not None and self.plotType != wantedType:
self.air.writeServerEvent('suspicious', avId, 'called incorrect DistributedGardenPlotAI method!', plotType=self.plotType,
wantedType=wantedType)
return self.d_interactionDenied()
def plantStatuary(self, species, toon):
#free for now
#av = simbase.air.doId2do.get(toon)
#av.takeMoney(GardenGlobals.getNumBeansRequired(species, 0))
self.planted = DistributedStatuaryAI(self.air)
self.planted.setEstate(self.getEstate())
self.planted.setOwnerPlot(self.doId)
self.planted.setPlot(self.getPlot())
self.planted.setHeading(self.getHeading())
self.planted.setPosition(*self.getPosition())
self.planted.setOwnerIndex(self.getOwnerIndex())
self.planted.setTypeIndex(species)
self.planted.setWaterLevel(0)
self.planted.setGrowthLevel(0)
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_PLANT, toon])
def plantToonStatuary(self, species, dnaCode, toon):
#free for now
#av = simbase.air.doId2do.get(toon)
#av.takeMoney(GardenGlobals.getNumBeansRequired(species, 0))
self.planted = DistributedToonStatuaryAI(self.air)
self.planted.setEstate(self.getEstate())
self.planted.setOwnerPlot(self.doId)
self.planted.setPlot(self.getPlot())
self.planted.setHeading(self.getHeading())
self.planted.setPosition(*self.getPosition())
self.planted.setOwnerIndex(self.getOwnerIndex())
self.planted.setTypeIndex(species)
self.planted.setWaterLevel(0)
self.planted.setGrowthLevel(0)
self.planted.setOptional(dnaCode)
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_PLANT, toon])
if avId != self.ownerDoId and not forceOwner:
self.air.writeServerEvent('suspicious', avId, 'called someone else\'s DistributedGardenPlotAI plant method!',
ownerDoId=self.ownerDoId)
return self.d_interactionDenied()
def plantNothing(self, burntBeans, toon):
# TODO: Fix exploit.
sendAvId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(sendAvId)
return av
def plantFlower(self, species, variety, usingSatanFlowerAll=0):
av = self.__initialSanityCheck(GardenGlobals.FLOWER_TYPE if not usingSatanFlowerAll else None, usingSatanFlowerAll)
if not av:
return
def invalid(problem):
msg = 'tried to plant flower but something went wrong: %s' % problem
self.notify.warning('%d %s' % (av.doId, msg))
self.air.writeServerEvent('suspicious', av.doId, msg)
if not usingSatanFlowerAll:
return self.d_setMovie(GardenGlobals.MOVIE_PLANT_REJECTED)
attr = GardenGlobals.PlantAttributes.get(species, {})
if attr.get('plantType') != GardenGlobals.FLOWER_TYPE:
return invalid('invalid species: %d' % species)
if variety >= len(attr['varieties']):
return invalid('invalid variety: %d' % variety)
if not usingSatanFlowerAll:
cost = len(GardenGlobals.Recipes[attr['varieties'][variety][0]]['beans'])
av.takeMoney(cost)
self.d_setMovie(GardenGlobals.MOVIE_PLANT)
def _plant(task):
flower = self.mgr.plantFlower(self.flowerIndex, species, variety, plot=self,
ownerIndex=self.ownerIndex, plotId=self.plot,
waterLevel=0)
index = (0, 1, 2, 2, 2, 3, 3, 3, 4, 4)[self.flowerIndex]
idx = (0, 0, 0, 1, 2, 0, 1, 2, 0, 1)[self.flowerIndex]
flower.sendUpdate('setBoxDoId', [self.mgr._boxes[index].doId, idx])
if not usingSatanFlowerAll:
flower.d_setMovie(GardenGlobals.MOVIE_FINISHPLANTING, self.__plantingAvId)
flower.d_setMovie(GardenGlobals.MOVIE_CLEAR, self.__plantingAvId)
self.air.writeServerEvent('plant-flower', self.__plantingAvId, species=species, variety=variety,
plot=self.plot, name=attr.get('name', 'unknown satan flower'))
if task:
return task.done
if usingSatanFlowerAll:
_plant(None)
else:
taskMgr.doMethodLater(7, _plant, self.uniqueName('do-plant'))
self.__plantingAvId = av.doId
return 1
def plantGagTree(self, track, index):
av = self.__initialSanityCheck(GardenGlobals.GAG_TREE_TYPE)
if not av:
return
for i in xrange(index):
if not self.mgr.hasTree(track, i):
msg = 'tried to plant tree but an index is missing: %d' % index
self.notify.warning('%d %s' % (av.doId, msg))
self.air.writeServerEvent('suspicious', av.doId, msg)
return self.d_setMovie(GardenGlobals.MOVIE_PLANT_REJECTED)
if self.mgr.hasTree(track, index):
msg = 'tried to plant tree but gag already planted'
self.notify.warning('%d %s' % (av.doId, msg))
self.air.writeServerEvent('suspicious', av.doId, msg)
return self.d_setMovie(GardenGlobals.MOVIE_PLANT_REJECTED)
if av.inventory.useItem(track, index) == -1:
msg = 'tried to plant tree but not carrying selected gag'
self.notify.warning('%d %s' % (av.doId, msg))
self.air.writeServerEvent('suspicious', av.doId, msg)
return self.d_setMovie(GardenGlobals.MOVIE_PLANT_REJECTED)
av.d_setInventory(av.getInventory())
self.d_setMovie(GardenGlobals.MOVIE_PLANT)
def _plant(task):
if not self.air:
return
tree = self.mgr.plantTree(self.treeIndex, track * 7 + index, plot=self, ownerIndex=self.ownerIndex,
plotId=self.plot, pos=(self.getPos(), self.getH()))
tree.d_setMovie(GardenGlobals.MOVIE_FINISHPLANTING, self.__plantingAvId)
tree.d_setMovie(GardenGlobals.MOVIE_CLEAR, self.__plantingAvId)
self.air.writeServerEvent('plant-tree', self.__plantingAvId, track=track, index=index, plot=self.plot)
return task.done
taskMgr.doMethodLater(7, _plant, self.uniqueName('do-plant'))
self.__plantingAvId = av.doId
def plantStatuary(self, species):
av = self.__initialSanityCheck(GardenGlobals.STATUARY_TYPE)
if not av:
return
def invalid(problem):
msg = 'tried to plant statuary but something went wrong: %s' % problem
self.notify.warning('%d %s' % (av.doId, msg))
self.air.writeServerEvent('suspicious', av.doId, msg)
return self.d_setMovie(GardenGlobals.MOVIE_PLANT_REJECTED)
attr = GardenGlobals.PlantAttributes.get(species, {})
if attr.get('plantType') != GardenGlobals.STATUARY_TYPE:
return invalid('invalid species: %d' % species)
it = species - 100
if it == 134:
it = 135
if not av.removeGardenItem(it, 1):
return invalid('av doesn\'t own item: %d' % species)
self.d_setMovie(GardenGlobals.MOVIE_PLANT)
def _plant(task):
if not self.air:
return
statuary = self.mgr.placeStatuary(self.mgr.S_pack(0, 0, species, 0), plot=self,
ownerIndex=self.ownerIndex, plotId=self.plot,
pos=(self.getPos(), self.getH()), generate=False)
statuary.generateWithRequired(self.zoneId)
statuary.d_setMovie(GardenGlobals.MOVIE_FINISHPLANTING, self.__plantingAvId)
statuary.d_setMovie(GardenGlobals.MOVIE_CLEAR, self.__plantingAvId)
self.air.writeServerEvent('plant-statuary', self.__plantingAvId, species=species, plot=self.plot)
return task.done
taskMgr.doMethodLater(7, _plant, self.uniqueName('do-plant'))
self.__plantingAvId = av.doId
def plantToonStatuary(self, species, dnaCode):
av = self.__initialSanityCheck(GardenGlobals.STATUARY_TYPE)
if not av:
return
def invalid(problem):
msg = 'tried to plant statuary but something went wrong: %s' % problem
self.notify.warning('%d %s' % (av.doId, msg))
self.air.writeServerEvent('suspicious', av.doId, msg)
return self.d_setMovie(GardenGlobals.MOVIE_PLANT_REJECTED)
attr = GardenGlobals.PlantAttributes.get(species, {})
if attr.get('plantType') != GardenGlobals.STATUARY_TYPE:
return invalid('invalid species: %d' % species)
if not av.removeGardenItem(species - 100, 1):
return invalid('av doesn\'t own item: %d' % species)
self.d_setMovie(GardenGlobals.MOVIE_PLANT)
def _plant(task):
if not self.air:
return
statuary = self.mgr.placeStatuary(self.mgr.S_pack(dnaCode, 0, species, 0), plot=self,
ownerIndex=self.ownerIndex, plotId=self.plot,
pos=(self.getPos(), self.getH()), generate=False)
statuary.generateWithRequired(self.zoneId)
statuary.d_setMovie(GardenGlobals.MOVIE_FINISHPLANTING, self.__plantingAvId)
self.air.writeServerEvent('plant-statuary', self.__plantingAvId, species=species, plot=self.plot)
return task.done
taskMgr.doMethodLater(7, _plant, self.uniqueName('do-plant'))
self.__plantingAvId = av.doId
def plantNothing(self, burntBeans):
av = self.__initialSanityCheck()
if av:
av.takeMoney(burntBeans)
self.planted = None
@magicWord(category=CATEGORY_PROGRAMMER, types=[int, int])
def satanFlowerAll(species=49, variety=0):
invoker = spellbook.getInvoker()
av = spellbook.getTarget()
estate = av.air.estateManager._lookupEstate(av)
if not estate:
return 'Estate not found!'
garden = estate.gardenManager.gardens.get(av.doId)
if not garden:
return 'Garden not found!'
i = 0
for obj in garden.objects.copy():
if isinstance(obj, DistributedGardenPlotAI):
if obj.plotType != GardenGlobals.FLOWER_TYPE:
continue
if not obj.plantFlower(species, variety, 1):
return 'Error on plot %d' % i
i += 1
def troll(task):
channel = invoker.GetPuppetConnectionChannel(invoker.doId)
av.air.sendSysMsg('OMG YOU SOLD YOUR SOUL NOOOOOOOOOOOOOOOOOOOO', channel)
return task.done
taskMgr.doMethodLater(6.66, troll, 'satan-troll')
return '%d disgusting flowers planted' % i
@magicWord(category=CATEGORY_PROGRAMMER)
def gibSpecials():
av = spellbook.getTarget()
av.gardenSpecials = []
for x in (100, 101, 103, 105, 106, 107, 108, 130, 131, 135):
av.addGardenItem(x, 99)

View file

@ -1,4 +1,4 @@
from panda3d.core import *
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.distributed import ClockDelta
from direct.showbase.PythonUtil import lerp
@ -16,6 +16,7 @@ from otp.otpbase import OTPGlobals
from toontown.estate import GardenGlobals
def recurseParent(intoNode, ParentName):
# funny fact: cogtown had a func like this
parent = intoNode.getParent(0)
if not parent or parent.getName() == 'render':
return 0
@ -50,6 +51,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
return
def setHeading(self, h):
self.notify.debug('setting h')
DistributedNode.DistributedNode.setH(self, h)
def generateInit(self):
@ -93,6 +95,11 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
if not self.rotateNode:
self.rotateNode = self.plantPath.attachNewNode('rotate')
self.model = None
if __dev__:
self.model = loader.loadModel(self.defaultModel)
self.model.setScale(0.4, 0.4, 0.1)
self.model.reparentTo(self.rotateNode)
return
def setupShadow(self):
self.shadowJoint = self.rotateNode.attachNewNode('shadow')
@ -121,6 +128,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
self.accept(self.exitMessageName, self.handleExitPlot)
def handleEnterPlot(self, optional = None):
self.notify.debug('handleEnterPlot %d' % self.doId)
self.sendUpdate('plotEntered', [])
def handleExitPlot(self, optional = None):
@ -142,12 +150,6 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
taskMgr.remove(self.uniqueName('adjust tree'))
return
def setEstate(self, estate):
self.estate = estate
def getEstate(self):
return self.estate
def setPos(self, x, y, z):
DistributedNode.DistributedNode.setPos(self, x, y, z)
self.stick2Ground()
@ -175,7 +177,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
picker.traverse(render)
if queue.getNumEntries() > 0:
queue.sortEntries()
for index in xrange(queue.getNumEntries()):
for index in range(queue.getNumEntries()):
entry = queue.getEntry(index)
if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.movieNode.setZ(entry.getSurfacePoint(self)[2])
@ -184,7 +186,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
picker.traverse(render)
if queue.getNumEntries() > 0:
queue.sortEntries()
for index in xrange(queue.getNumEntries()):
for index in range(queue.getNumEntries()):
entry = queue.getEntry(index)
if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.setZ(entry.getSurfacePoint(render)[2] + self.stickUp + 0.1)
@ -197,12 +199,12 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
def stickParts(self):
pass
def setH(self, h):
DistributedNode.DistributedNode.setH(self, h)
def setPlot(self, plot):
self.plot = plot
def setH(self, h):
DistributedNode.DistributedNode.setH(self, h)
def getPlot(self):
return self.plot
@ -242,7 +244,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
base.localAvatar.hideShovelButton()
base.localAvatar.hideWateringCanButton()
self.startInteraction()
self.sendUpdate('removeItem', [base.localAvatar.doId])
self.sendUpdate('removeItem', [])
def generateToonMoveTrack(self, toon):
node = NodePath('tempNode')
@ -261,10 +263,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
finalY = node.getY(render)
finalZ = node.getZ(render)
node.removeNode()
toonTrack = Sequence(Parallel(ActorInterval(toon, 'walk', loop=True, duration=1),
Parallel(LerpPosInterval(toon, 1.0, Point3(finalX, finalY, toon.getZ(render)), fluid=True, bakeInStart=False)),
LerpHprInterval(toon, 1.0, hpr=hpr)),
Func(toon.loop, 'neutral'))
toonTrack = Sequence(Parallel(ActorInterval(toon, 'walk', loop=True, duration=1), Parallel(LerpPosInterval(toon, 1.0, Point3(finalX, finalY, toon.getZ(render)), fluid=True, bakeInStart=False)), LerpHprInterval(toon, 1.0, hpr=hpr)), Func(toon.loop, 'neutral'))
return toonTrack
def unprint(self, string):
@ -288,16 +287,13 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
def startCamIval(self, avId):
track = Sequence()
if avId == localAvatar.doId:
track = Sequence(Func(base.localAvatar.disableSmartCameraViews),
Func(base.localAvatar.setCameraPosForPetInteraction))
track = Sequence(Func(base.localAvatar.disableSmartCameraViews), Func(base.localAvatar.setCameraPosForPetInteraction))
return track
def stopCamIval(self, avId):
track = Sequence()
if avId == localAvatar.doId:
track = Sequence(Func(base.localAvatar.unsetCameraPosForPetInteraction),
Wait(0.8),
Func(base.localAvatar.enableSmartCameraViews))
track = Sequence(Func(base.localAvatar.unsetCameraPosForPetInteraction), Wait(0.8), Func(base.localAvatar.enableSmartCameraViews))
return track
def canBeWatered(self):
@ -332,8 +328,6 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
if not toon:
return
self.finishMovies()
if avId == localAvatar.doId:
self.startInteraction()
self.model.setTransparency(1)
self.model.setAlphaScale(1)
shovel = toon.attachShovel()
@ -341,11 +335,9 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
moveTrack = self.generateToonMoveTrack(toon)
digupTrack = self.generateDigupTrack(toon)
self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), digupTrack)
self.movie.append(Func(base.cr.removeObject, self.doId))
if avId == localAvatar.doId:
self.expectingReplacement = 1
plotAv = base.cr.doId2do.get(self.getOwnerPlot())
self.movie.append(Func(plotAv.sendUpdate, 'finishRemoving', [avId]))
# self.expectingReplacement = 1
self.movie.append(Func(self.movieDone))
self.movie.start()
def generateDigupTrack(self, toon):
@ -354,22 +346,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
pos = self.model.getPos()
pos.setZ(pos[2] - 1)
track = Parallel()
sq = Sequence(ActorInterval(toon, 'start-dig'),
Parallel(ActorInterval(toon, 'loop-dig', loop=1, duration=5.13),
Sequence(Wait(0.25),
SoundInterval(sound, node=toon, duration=0.55),
Wait(0.8),
SoundInterval(sound, node=toon, duration=0.55),
Wait(1.35),
SoundInterval(sound, node=toon, duration=0.55))),
ActorInterval(toon, 'start-dig', playRate=-1),
LerpFunc(self.model.setAlphaScale, fromData=1, toData=0, duration=1))
if hasattr(self, 'signModel'):
sq.append(Parallel(LerpFunc(self.signModel.setAlphaScale, fromData=1, toData=0, duration=1),
LerpScaleInterval(self.signModel, 1, 0, 1)))
sq.append(Func(toon.loop, 'neutral'))
sq.append(Func(toon.detachShovel))
track.append(sq)
track.append(Sequence(ActorInterval(toon, 'start-dig'), Parallel(ActorInterval(toon, 'loop-dig', loop=1, duration=5.13), Sequence(Wait(0.25), SoundInterval(sound, node=toon, duration=0.55), Wait(0.8), SoundInterval(sound, node=toon, duration=0.55), Wait(1.35), SoundInterval(sound, node=toon, duration=0.55))), ActorInterval(toon, 'start-dig', playRate=-1), LerpFunc(self.model.setAlphaScale, fromData=1, toData=0, duration=1), Func(toon.loop, 'neutral'), Func(toon.detachShovel)))
return track
def doFinishPlantingTrack(self, avId):

View file

@ -1,30 +1,14 @@
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedNodeAI import DistributedNodeAI
import GardenGlobals
class DistributedLawnDecorAI(DistributedNodeAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedLawnDecorAI")
def __init__(self, air):
DistributedNodeAI.__init__(self, air)
self.air = air
self.plot = None
self.ownerIndex = None
def announceGenerate(self):
DistributedNodeAI.announceGenerate(self)
def delete(self):
DistributedNodeAI.delete(self)
def disable(self):
DistributedNodeAI.disable(self)
def setEstate(self, estate):
self.estate = estate
def getEstate(self):
return self.estate
def __init__(self, mgr):
self.mgr = mgr
DistributedNodeAI.__init__(self, self.mgr.air)
self.plot = 0
self.ownerIndex = 0
def setPlot(self, plot):
self.plot = plot
@ -32,37 +16,25 @@ class DistributedLawnDecorAI(DistributedNodeAI):
def getPlot(self):
return self.plot
def setOwnerIndex(self, index):
self.ownerIndex = index
def getHeading(self):
return self.getH()
def getPosition(self):
return self.getPos()
def setOwnerIndex(self, ownerIndex):
self.ownerIndex = ownerIndex
self.ownerDoId = self.mgr.gardenMgr.mgr.toons[ownerIndex]
self.owner = self.air.doId2do.get(self.ownerDoId)
def getOwnerIndex(self):
return self.ownerIndex
def setPosition(self, x, y, z):
self.position = (x, y, z)
def d_setMovie(self, mode, avId=None):
if avId is None:
avId = self.air.getAvatarIdFromSender()
def getPosition(self):
return self.position
def setHeading(self, heading):
self.heading = heading
def getHeading(self):
return self.heading
def plotEntered(self):
pass
def removeItem(self, avId):
self.inUseBy = avId
self.d_setMovie(GardenGlobals.MOVIE_REMOVE, avId)
def d_setMovie(self, mode, avId):
self.sendUpdate('setMovie', [mode, avId])
def movieDone(self):
if hasattr(self, 'inUseBy'):
del self.inUseBy
def interactionDenied(self, todo0):
pass
def d_interactionDenied(self):
self.sendUpdate('interactionDenied', [self.air.getAvatarIdFromSender()])

View file

@ -44,12 +44,6 @@ class DistributedPlantBase(DistributedLawnDecor.DistributedLawnDecor):
DistributedLawnDecor.DistributedLawnDecor.setupShadow(self)
self.adjustWaterIndicator()
def setOwnerPlot(self, owner):
self.ownerPlot = owner
def getOwnerPlot(self):
return self.ownerPlot
def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex
self.attributes = GardenGlobals.PlantAttributes[typeIndex]
@ -69,9 +63,7 @@ class DistributedPlantBase(DistributedLawnDecor.DistributedLawnDecor):
self.waterLevel = waterLevel
def getWaterLevel(self):
if hasattr(self, 'waterLevel'):
return self.waterLevel
return 0
def setGrowthLevel(self, growthLevel):
self.growthLevel = growthLevel
@ -105,11 +97,11 @@ class DistributedPlantBase(DistributedLawnDecor.DistributedLawnDecor):
def handleWatering(self):
self.startInteraction()
self.sendUpdate('waterPlant', [localAvatar.doId])
self.sendUpdate('waterPlant')
def __handleWatering(self, plantToWaterId):
if plantToWaterId == self.doId:
self.sendUpdate('waterPlant', [localAvatar.doId])
self.sendUpdate('waterPlant')
else:
self.notify.debug('not sending water plant')

View file

@ -1,84 +1,81 @@
from direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI
import GardenGlobals
import datetime
class DistributedPlantBaseAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedPlantBaseAI")
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPlantBaseAI')
def __init__(self, air):
DistributedLawnDecorAI.__init__(self, air)
self.air = air
self.growthLevel = -1
def announceGenerate(self):
DistributedLawnDecorAI.announceGenerate(self)
def delete(self):
DistributedLawnDecorAI.delete(self)
def disable(self):
DistributedLawnDecorAI.disable(self)
def setOwnerPlot(self, owner):
self.ownerPlot = owner
def getOwnerPlot(self):
return self.ownerPlot
def __init__(self, mgr):
DistributedLawnDecorAI.__init__(self, mgr)
self.typeIndex = 0
self.waterLevel = 0
self.growthLevel = 0
def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex
self.attributes = GardenGlobals.PlantAttributes[typeIndex]
self.name = self.attributes['name']
self.plantType = self.attributes['plantType']
self.growthThresholds = self.attributes['growthThresholds']
self.maxWaterLevel = self.attributes['maxWaterLevel']
self.minWaterLevel = self.attributes['minWaterLevel']
def d_setTypeIndex(self, typeIndex):
self.sendUpdate('setTypeIndex', [typeIndex])
def b_setTypeIndex(self, typeIndex):
self.setTypeIndex(typeIndex)
self.d_setTypeIndex(typeIndex)
def getTypeIndex(self):
return self.typeIndex
def setWaterLevel(self, water):
self.waterLevel = water
def setWaterLevel(self, waterLevel):
self.waterLevel = waterLevel
def d_setWaterLevel(self, waterLevel):
self.sendUpdate('setWaterLevel', [waterLevel])
def b_setWaterLevel(self, waterLevel):
self.setWaterLevel(waterLevel)
self.d_setWaterLevel(waterLevel)
def getWaterLevel(self):
return self.waterLevel
def setGrowthLevel(self, growth):
self.growthLevel = growth
def setGrowthLevel(self, growthLevel):
self.growthLevel = growthLevel
def d_setGrowthLevel(self, growthLevel):
self.sendUpdate('setGrowthLevel', [growthLevel])
def b_setGrowthLevel(self, growthLevel):
self.setGrowthLevel(growthLevel)
self.d_setGrowthLevel(growthLevel)
def getGrowthLevel(self):
return self.growthLevel
def waterPlant(self, avId):
# TODO: Proper water threshold for watering can type.
# Not supposed to be 16 for all watering cans.
self.lastWateredBy = avId
newLevel = self.waterLevel + 1
if newLevel > self.maxWaterLevel:
self.setWaterLevel(self.maxWaterLevel)
else:
self.setWaterLevel(newLevel)
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_WATER, avId])
self.sendUpdate('setWaterLevel', [self.getWaterLevel()])
def waterPlant(self):
av = self.air.doId2do.get(self.air.getAvatarIdFromSender())
if not av:
return
level = max(1, self.getWaterLevel() + av.getWateringCan() + 1)
level = min(20, level)
self.b_setWaterLevel(level)
self.d_setMovie(GardenGlobals.MOVIE_WATER)
self.update()
def waterPlantDone(self):
if hasattr(self, 'lastWateredBy'):
av = simbase.air.doId2do.get(self.lastWateredBy)
skill = av.getWateringCanSkill()
skill += GardenGlobals.WateringCanAttributes[av.wateringCan]['skillPts'] / 100
av.b_setWateringCanSkill(skill)
del self.lastWateredBy
estate = simbase.air.doId2do.get(self.getEstate())
dataIndex = -1
# TODO: Possibly store this in mongodb/cPickle instead.
for n, item in enumerate(estate.items[self.getOwnerIndex()]):
if item[0] == self.getPlot():
dataIndex = n
if dataIndex >= 0:
dtime = int(datetime.datetime.now().strftime('%Y%m%d%H%M'))
data = list(estate.items[self.getOwnerIndex()][dataIndex])
data[4] = self.getWaterLevel()
data[8] = dtime
estate.items[self.getOwnerIndex()][dataIndex] = tuple(data)
estate.updateItems()
av = self.air.doId2do.get(self.air.getAvatarIdFromSender())
if not av:
return
if self.waterLevel < 6:
av.b_setWateringCanSkill(av.getWateringCanSkill() + 1)
else:
av.b_setWateringCanSkill(av.getWateringCanSkill())
self.d_setMovie(GardenGlobals.MOVIE_CLEAR)
def update(self):
pass

View file

@ -37,22 +37,16 @@ class DistributedStatuary(DistributedLawnDecor.DistributedLawnDecor):
attrib = GardenGlobals.PlantAttributes[self.typeIndex]
self.stick2Ground()
def setOwnerPlot(self, owner):
self.ownerPlot = owner
def getOwnerPlot(self):
return self.ownerPlot
def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex
self.name = GardenGlobals.PlantAttributes[typeIndex]['name']
self.plantType = GardenGlobals.PlantAttributes[typeIndex]['plantType']
self.modelPath = GardenGlobals.PlantAttributes[typeIndex]['model']
self.pinballScore = None
if 'pinballScore' in GardenGlobals.PlantAttributes[typeIndex]:
if GardenGlobals.PlantAttributes[typeIndex].has_key('pinballScore'):
self.pinballScore = GardenGlobals.PlantAttributes[typeIndex]['pinballScore']
self.worldScale = 1.0
if 'worldScale' in GardenGlobals.PlantAttributes[typeIndex]:
if GardenGlobals.PlantAttributes[typeIndex].has_key('worldScale'):
self.worldScale = GardenGlobals.PlantAttributes[typeIndex]['worldScale']
return

View file

@ -1,33 +1,66 @@
from direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI
from DistributedLawnDecorAI import DistributedLawnDecorAI
import GardenGlobals
import time
FOUR_DAYS = 86400 * 4
class DistributedStatuaryAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedStatuaryAI")
def __init__(self, air):
DistributedLawnDecorAI.__init__(self, air)
self.air = air
def calculate(self, lastCheck):
self.attributes = GardenGlobals.PlantAttributes[self.index]
self.growthThresholds = self.attributes.get('growthThresholds', (0, 0))
def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex
now = int(time.time())
self.lastCheck = lastCheck
if self.lastCheck == 0:
self.lastCheck = now
self.growthLevel = min((now - self.lastCheck) // FOUR_DAYS, self.growthThresholds[-1] + 1)
self.update()
def getTypeIndex(self):
return self.typeIndex
def setOwnerPlot(self, owner):
self.ownerPlot = owner
def getOwnerPlot(self):
return self.ownerPlot
def setWaterLevel(self, waterLevel):
self.waterLevel = waterLevel
return self.index
def getWaterLevel(self):
return self.waterLevel
def setGrowthLevel(self, growthLevel):
self.growthLevel = growthLevel
return 1
def getGrowthLevel(self):
return self.growthLevel
def getOptional(self):
return self.data
def update(self):
self.mgr.data['statuary'] = self.mgr.S_pack(self.data, self.lastCheck, self.index, self.growthLevel)
self.mgr.update()
def removeItem(self):
avId = self.air.getAvatarIdFromSender()
self.d_setMovie(GardenGlobals.MOVIE_REMOVE)
def _remove(task):
if not self.air:
return
plot = self.mgr.placePlot(-1)
plot.setPlot(self.plot)
plot.setPos(self.getPos())
plot.setH(self.getH())
plot.setOwnerIndex(self.ownerIndex)
plot.generateWithRequired(self.zoneId)
self.air.writeServerEvent('remove-statuary', avId, plot=self.plot)
self.requestDelete()
self.mgr.objects.remove(self)
self.mgr.data['statuary'] = 0
self.mgr.update()
return task.done
taskMgr.doMethodLater(7, _remove, self.uniqueName('do-remove'))

View file

@ -2,7 +2,7 @@ from toontown.estate import DistributedStatuary
from toontown.estate import DistributedLawnDecor
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.ShowBase import *
from panda3d.core import *
from pandac.PandaModules import *
from toontown.toon import Toon
from toontown.toon import ToonDNA
import GardenGlobals
@ -46,7 +46,7 @@ class DistributedToonStatuary(DistributedStatuary.DistributedStatuary):
self.model.setScale(self.worldScale * 1.5, self.worldScale * 1.5, self.worldScale)
self.getToonPropertiesFromOptional()
dna = ToonDNA.ToonDNA()
dna.newToonFromProperties(self.headType, self.torsoType, self.legType, self.gender, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
dna.newToonFromProperties(self.headType, self.torsoType, self.legType, self.gender, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
self.setupStoneToon(dna)
self.poseToonFromTypeIndex(self.typeIndex)
self.toon.reparentTo(self.model)
@ -112,7 +112,7 @@ class DistributedToonStatuary(DistributedStatuary.DistributedStatuary):
if sleeves:
sleeves.setTexture(desatSleeveTex, 1)
bottoms = torso.findAllMatches('**/torso-bot*')
for bottomNum in xrange(0, bottoms.getNumPaths()):
for bottomNum in range(0, bottoms.getNumPaths()):
bottom = bottoms.getPath(bottomNum)
if bottom:
if self.toon.style.torso[1] == 's':

View file

@ -4,12 +4,6 @@ from toontown.estate.DistributedStatuaryAI import DistributedStatuaryAI
class DistributedToonStatuaryAI(DistributedStatuaryAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedToonStatuaryAI")
def __init__(self, air):
DistributedStatuaryAI.__init__(self, air)
self.air = air
def setOptional(self, todo0):
pass
def setOptional(self, optional):
self.optional = optional
def getOptional(self):
return self.optional

View file

@ -239,7 +239,7 @@ class LoadEstateFSM(FSM):
estate.pets = []
self.estate.toons = self.toonIds
self.estate.updateToons()
#self.estate.updateToons()
# Gotcha! Now we need to load houses:
self.demand('LoadHouses')

View file

@ -12,7 +12,6 @@ INVALID_TYPE = -1
GAG_TREE_TYPE = 0
FLOWER_TYPE = 1
STATUARY_TYPE = 2
TOON_STATUARY_TYPE = 3
WATERING_CAN_SMALL = 0
WATERING_CAN_MEDIUM = 1
WATERING_CAN_LARGE = 2
@ -34,7 +33,7 @@ WateringMult = 2
def getWateringCanPower(wateringCan, wateringCanSkill):
numBoxes = 0
for curWateringCan in xrange(wateringCan + 1):
for curWateringCan in range(wateringCan + 1):
wateringCanAttrib = WateringCanAttributes[curWateringCan]
curBoxes = wateringCanAttrib['numBoxes']
skill = wateringCanAttrib['skillPts']
@ -309,7 +308,7 @@ def getTreeTypeIndex(track, level):
NUM_GAGS = 7 * 7
for i in xrange(NUM_GAGS):
for i in range(NUM_GAGS):
track, level = getTreeTrackAndLevel(i)
if level <= 6:
name = TTLocalizer.BattleGlobalAvPropStrings[track][level] + TTLocalizer.GardenGagTree
@ -495,7 +494,7 @@ ShovelAttributes = {0: {'numBoxes': 2,
def getShovelPower(shovel, shovelSkill):
numBoxes = 0
for curShovel in xrange(shovel + 1):
for curShovel in range(shovel + 1):
shovelAttrib = ShovelAttributes[curShovel]
curBoxes = shovelAttrib['numBoxes']
skill = shovelAttrib['skillPts']
@ -597,8 +596,8 @@ def getSpeciesVarietyGivenRecipe(recipeKey):
attrib = PlantAttributes[species]
if attrib['plantType'] == GAG_TREE_TYPE:
continue
if 'varieties' in attrib:
for variety in xrange(len(attrib['varieties'])):
if attrib.has_key('varieties'):
for variety in range(len(attrib['varieties'])):
if attrib['varieties'][variety][0] == recipeKey:
return (species, variety)
@ -609,14 +608,14 @@ def getNumBeansRequired(species, variety):
retval = -1
if not PlantAttributes.get(species):
return retval
if 'varieties' not in PlantAttributes[species]:
if not PlantAttributes[species].has_key('varieties'):
return retval
if variety >= len(PlantAttributes[species]['varieties']):
return -1
recipeKey = PlantAttributes[species]['varieties'][variety][0]
recipe = Recipes.get(recipeKey)
if recipe:
if 'beans' in recipe:
if recipe.has_key('beans'):
retval = len(recipe['beans'])
return retval
@ -653,7 +652,7 @@ def validateRecipes(notify):
def validatePlantAttributes(notify):
uniqueRecipes = []
flowerRecipeDistribution = []
for i in xrange(getNumberOfShovelBoxes() + 1):
for i in range(getNumberOfShovelBoxes() + 1):
flowerRecipeDistribution.append([])
for key in PlantAttributes.keys():
@ -675,7 +674,7 @@ def validatePlantAttributes(notify):
newInfo = (getFlowerVarietyName(key, list(varieties).index(variety)), Recipes[recipeNum]['beans'], TTLocalizer.FlowerColorStrings[variety[1]])
flowerRecipeDistribution[recipeLength].append(newInfo)
for numBeans in xrange(len(flowerRecipeDistribution)):
for numBeans in range(len(flowerRecipeDistribution)):
notify.debug('%d flowers with %d beans' % (len(flowerRecipeDistribution[numBeans]), numBeans))
for flower in flowerRecipeDistribution[numBeans]:
notify.debug(' %s, beans = %s, color=%s' % (flower[0], flower[1], flower[2]))
@ -683,7 +682,7 @@ def validatePlantAttributes(notify):
notify.debug('plant attributes are ok')
plots0 = [(0,
plots0 = ((0,
0,
0.0,
FLOWER_TYPE),
@ -758,45 +757,45 @@ plots0 = [(0,
(-100,
-43,
-90.0,
STATUARY_TYPE)]
plots1 = [(85.0,
-67.0,
STATUARY_TYPE))
plots1 = ((0,
0,
0.0,
FLOWER_TYPE),
(75,
-72,
(1,
0,
0.0,
FLOWER_TYPE),
(89.865,
-71.7725,
(2,
0,
0.0,
FLOWER_TYPE),
(91.0,
-74.0,
(2,
1,
0.0,
FLOWER_TYPE),
(92.135,
-76.2275,
(2,
2,
0.0,
FLOWER_TYPE),
(75.865,
-78.7725,
(3,
0,
0.0,
FLOWER_TYPE),
(77,
-81,
(3,
1,
0.0,
FLOWER_TYPE),
(78.135,
-83.2275,
(3,
2,
0.0,
FLOWER_TYPE),
(86.6518,
-86.6576,
(4,
0,
0.0,
FLOWER_TYPE),
(89.3482,
-85.3424,
(4,
1,
0.0,
FLOWER_TYPE),
(62,
@ -834,8 +833,8 @@ plots1 = [(85.0,
(47,
-82,
-30.0,
STATUARY_TYPE)]
plots2 = [(0,
STATUARY_TYPE))
plots2 = ((0,
0,
0.0,
FLOWER_TYPE),
@ -910,8 +909,8 @@ plots2 = [(0,
(-97,
-114,
-60.0,
STATUARY_TYPE)]
plots3 = [(0,
STATUARY_TYPE))
plots3 = ((0,
0,
0.0,
FLOWER_TYPE),
@ -986,8 +985,8 @@ plots3 = [(0,
(117,
27,
102.0,
STATUARY_TYPE)]
plots4 = [(0,
STATUARY_TYPE))
plots4 = ((0,
0,
0.0,
FLOWER_TYPE),
@ -1062,8 +1061,8 @@ plots4 = [(0,
(16,
87,
-140.0,
STATUARY_TYPE)]
plots5 = [(0,
STATUARY_TYPE))
plots5 = ((0,
0,
0.0,
FLOWER_TYPE),
@ -1138,7 +1137,7 @@ plots5 = [(0,
(-55,
70,
213.0,
STATUARY_TYPE)]
STATUARY_TYPE))
estatePlots = (plots0,
plots1,
plots2,
@ -1148,7 +1147,8 @@ estatePlots = (plots0,
BOX_ONE = 1
BOX_TWO = 2
BOX_THREE = 3
flowerBoxes0 = [(-62.5,
FLOWER_POS = (None, (0,), (-1.5, 1.5), (-3.5, 0, 3.5))
flowerBoxes0 = ((-62.5,
-52.5,
182.0,
BOX_ONE),
@ -1167,8 +1167,8 @@ flowerBoxes0 = [(-62.5,
(-57,
-33,
0.0,
BOX_TWO)]
flowerBoxes1 = [(85.0,
BOX_TWO))
flowerBoxes1 = ((85.0,
-67.0,
26.0,
BOX_ONE),
@ -1187,8 +1187,8 @@ flowerBoxes1 = [(85.0,
(88,
-86,
206.0,
BOX_TWO)]
flowerBoxes2 = [(-62,
BOX_TWO))
flowerBoxes2 = ((-62,
-112,
350.0,
BOX_ONE),
@ -1207,8 +1207,8 @@ flowerBoxes2 = [(-62,
(-71,
-129,
169.0,
BOX_TWO)]
flowerBoxes3 = [(72,
BOX_TWO))
flowerBoxes3 = ((72,
5,
265.0,
BOX_ONE),
@ -1227,8 +1227,8 @@ flowerBoxes3 = [(72,
(54,
12,
86.0,
BOX_TWO)]
flowerBoxes4 = [(35.5,
BOX_TWO))
flowerBoxes4 = ((35.5,
70,
152.0,
BOX_ONE),
@ -1247,8 +1247,8 @@ flowerBoxes4 = [(35.5,
(47,
86,
-19.0,
BOX_TWO)]
flowerBoxes5 = [(-26.5,
BOX_TWO))
flowerBoxes5 = ((-26.5,
37.5,
318.0,
BOX_ONE),
@ -1267,7 +1267,7 @@ flowerBoxes5 = [(-26.5,
(-45,
31,
124.0,
BOX_TWO)]
BOX_TWO))
estateBoxes = (flowerBoxes0,
flowerBoxes1,
flowerBoxes2,