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

View file

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

View file

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

View file

@ -16,7 +16,9 @@ class CatalogGardenStarterItem(CatalogItem.CatalogItem):
return 0 return 0
def reachedPurchaseLimit(self, avatar): 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): def saveHistory(self):
return 1 return 1
@ -29,13 +31,13 @@ class CatalogGardenStarterItem(CatalogItem.CatalogItem):
def recordPurchase(self, avatar, optional): def recordPurchase(self, avatar, optional):
if avatar: if avatar:
estate = simbase.air.estateManager.toon2estate.get(avatar) self.notify.debug('rental -- has avatar')
estate = simbase.air.estateManager._lookupEstate(avatar)
if estate: if estate:
av = simbase.air.doId2do.get(avatar) self.notify.debug('rental -- has estate')
if av: estate.placeStarterGarden(avatar.doId)
av.b_setGardenStarted(True) else:
print('garden saved') self.notify.warning('rental -- something not there')
estate.placeStarterGarden(avatar)
return ToontownGlobals.P_ItemAvailable return ToontownGlobals.P_ItemAvailable
def getPicture(self, avatar): def getPicture(self, avatar):

View file

@ -25,6 +25,7 @@ class CatalogToonStatueItem(CatalogGardenItem.CatalogGardenItem):
model, ival = self.makeFrameModel(toonStatuary.toon, 1) model, ival = self.makeFrameModel(toonStatuary.toon, 1)
self.pictureToonStatue = toonStatuary self.pictureToonStatue = toonStatuary
self.hasPicture = True self.hasPicture = True
toonStatuary.toon.setBin('gui-popup', 60)
return (model, ival) return (model, ival)
def cleanupPicture(self): def cleanupPicture(self):
@ -50,7 +51,7 @@ class CatalogToonStatueItem(CatalogGardenItem.CatalogGardenItem):
def getAllToonStatues(self): def getAllToonStatues(self):
self.statueList = [] 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)) self.statueList.append(CatalogToonStatueItem(index, 1, endPoseIndex=index))
return self.statueList return self.statueList

View file

@ -4,6 +4,3 @@ from toontown.estate.DistributedStatuaryAI import DistributedStatuaryAI
class DistributedAnimatedStatuaryAI(DistributedStatuaryAI): class DistributedAnimatedStatuaryAI(DistributedStatuaryAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedAnimatedStatuaryAI") 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): class DistributedChangingStatuaryAI(DistributedStatuaryAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedChangingStatuaryAI") notify = DirectNotifyGlobal.directNotify.newCategory("DistributedChangingStatuaryAI")
def __init__(self, air): def setGrowthLevel(self, todo0):
DistributedStatuaryAI.__init__(self, air) pass
self.air = air
self.growthLevel = -1
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.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedObjectAI import DistributedObjectAI from direct.distributed.DistributedObjectAI import DistributedObjectAI
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals
import HouseGlobals
import time, random
from toontown.fishing.DistributedFishingPondAI import DistributedFishingPondAI from toontown.fishing.DistributedFishingPondAI import DistributedFishingPondAI
from toontown.fishing.DistributedFishingTargetAI import DistributedFishingTargetAI from toontown.fishing.DistributedFishingTargetAI import DistributedFishingTargetAI
from toontown.fishing.DistributedPondBingoManagerAI import DistributedPondBingoManagerAI from toontown.fishing.DistributedPondBingoManagerAI import DistributedPondBingoManagerAI
from toontown.fishing import FishingTargetGlobals from toontown.fishing import FishingTargetGlobals
from toontown.safezone.DistributedFishingSpotAI import DistributedFishingSpotAI from toontown.safezone import TreasurePlannerAI
from toontown.safezone.SZTreasurePlannerAI import SZTreasurePlannerAI
from toontown.safezone import DistributedTreasureAI 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 DistributedCannonAI import *
from DistributedTargetAI import * from DistributedTargetAI import *
import CannonGlobals import CannonGlobals
import TableGlobals
import HouseGlobals # planted, waterLevel, lastCheck, growthLevel, optional
import GardenGlobals NULL_PLANT = [-1, -1, 0, 0, 0]
from DistributedGardenPlotAI import DistributedGardenPlotAI NULL_TREES = [NULL_PLANT] * 8
from DistributedGardenBoxAI import DistributedGardenBoxAI NULL_FLOWERS = [NULL_PLANT] * 10
from DistributedFlowerAI import DistributedFlowerAI NULL_STATUARY = 0
from DistributedGagTreeAI import DistributedGagTreeAI
from DistributedStatuaryAI import DistributedStatuaryAI NULL_DATA = {'trees': NULL_TREES, 'statuary': NULL_STATUARY, 'flowers': NULL_FLOWERS}
from DistributedToonStatuaryAI import DistributedToonStatuaryAI
import time from direct.distributed.PyDatagramIterator import *
import random from direct.distributed.PyDatagram import *
from toontown.fishing import FishGlobals
from toontown.parties.DistributedPartyJukeboxActivityAI import DistributedPartyJukeboxActivityAI 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: class Rental:
def __init__(self, estate): def __init__(self, estate):
self.estate = estate self.estate = estate
self.objects = set() self.objects = set()
def destroy(self): def destroy(self):
del self.estate del self.estate
for obj in self.objects: for object in self.objects:
if not obj.isDeleted(): if not object.isDeleted():
obj.requestDelete() object.requestDelete()
taskMgr.remove(obj.uniqueName('delete')) taskMgr.remove(object.uniqueName('delete'))
self.objects = set() self.objects = set()
class CannonRental(Rental): class CannonRental(Rental):
def __init__(self, estate):
Rental.__init__(self, estate)
def generateObjects(self): def generateObjects(self):
target = DistributedTargetAI(self.estate.air) target = DistributedTargetAI(self.estate.air)
target.generateWithRequired(self.estate.zoneId) target.generateWithRequired(self.estate.zoneId)
@ -71,12 +434,12 @@ class CannonRental(Rental):
for i in xrange(20): for i in xrange(20):
x = random.randint(100, 300) - 200 x = random.randint(100, 300) - 200
y = 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) treasure.generateWithRequired(self.estate.zoneId)
self.objects.add(treasure) self.objects.add(treasure)
doIds.append(treasure.doId) doIds.append(treasure.doId)
self.estate.sendUpdate("setTreasureIds", [doIds]) self.estate.sendUpdate('setTreasureIds', [doIds])
def grabAttempt(self, avId, treasureId): def grabAttempt(self, avId, treasureId):
av = self.estate.air.doId2do.get(avId) av = self.estate.air.doId2do.get(avId)
@ -89,6 +452,7 @@ class CannonRental(Rental):
if self.validAvatar(av): if self.validAvatar(av):
treasure.d_setGrab(avId) treasure.d_setGrab(avId)
self.deleteTreasureSoon(treasure) self.deleteTreasureSoon(treasure)
else: else:
treasure.d_setReject() treasure.d_setReject()
@ -106,49 +470,32 @@ class CannonRental(Rental):
av.toonUp(3) av.toonUp(3)
return 1 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): class DistributedEstateAI(DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedEstateAI") notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEstateAI')
def __init__(self, air): def __init__(self, air):
DistributedObjectAI.__init__(self, air) DistributedObjectAI.__init__(self, air)
self.toons = [0, 0, 0, 0, 0, 0] self.toons = [0, 0, 0, 0, 0, 0]
self.items = [[], [], [], [], [], []] self.items = [[], [], [], [], [], []]
self.boxes = [[], [], [], [], [], []] self.estateType = 0
self.plots = [[], [], [], [], [], []]
self.decorData = []
self.cloudType = 0 self.cloudType = 0
self.dawnTime = 0 self.dawnTime = 0
self.lastEpochTimestamp = 0 self.lastEpochTimestamp = 0
self.rentalType = 0
self.rentalHandle = None
self.rentalTimestamp = 0 self.rentalTimestamp = 0
self.houses = [None] * 6 self.houses = [None] * 6
self.rentalType = 0
self.rentalHandle = None
self.doId2do = { }
self.pond = None self.pond = None
self.spots = [] self.spots = []
self.targets = [] self.targets = []
self.jukebox = None
self.owner = None self.owner = None
@property self.gardenManager = GardenManager(self)
def hostId(self): self.__pendingGardens = {}
return 1000000001
def generate(self): def generate(self):
DistributedObjectAI.generate(self) DistributedObjectAI.generate(self)
@ -157,12 +504,15 @@ class DistributedEstateAI(DistributedObjectAI):
self.pond.setArea(ToontownGlobals.MyEstate) self.pond.setArea(ToontownGlobals.MyEstate)
self.pond.generateWithRequired(self.zoneId) 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 = DistributedFishingTargetAI(self.air)
target.setPondDoId(self.pond.getDoId()) target.setPondDoId(self.pond.getDoId())
target.generateWithRequired(self.zoneId) target.generateWithRequired(self.zoneId)
self.targets.append(target) self.targets.append(target)
#self.treasurePlanner = ETreasurePlannerAI.ETreasurePlannerAI(self.zoneId)
#self.treasurePlanner.start()
spot = DistributedFishingSpotAI(self.air) spot = DistributedFishingSpotAI(self.air)
spot.setPondDoId(self.pond.getDoId()) spot.setPondDoId(self.pond.getDoId())
spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0) spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0)
@ -187,126 +537,59 @@ class DistributedEstateAI(DistributedObjectAI):
spot.generateWithRequired(self.zoneId) spot.generateWithRequired(self.zoneId)
self.spots.append(spot) self.spots.append(spot)
self.jukebox = DistributedPartyJukeboxActivityAI( ButterflyGlobals.generateIndexes(self.zoneId, ButterflyGlobals.ESTATE)
self.air, for i in range(0, ButterflyGlobals.NUM_BUTTERFLY_AREAS[ButterflyGlobals.ESTATE]):
self.doId, for j in range(0, ButterflyGlobals.NUM_BUTTERFLIES[ButterflyGlobals.ESTATE]):
(0, 0, 0, 0) bfly = DistributedButterflyAI.DistributedButterflyAI(self.air, ButterflyGlobals.ESTATE, i, self.zoneId)
) bfly.generateWithRequired(self.zoneId)
self.jukebox.generateWithRequired(self.zoneId) bfly.start()
self.jukebox.sendUpdate('setX', [-21.8630]) self.addDistObj(bfly)
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])
def destroy(self): def destroy(self):
for house in self.houses: for house in self.houses:
if house: if house:
house.requestDelete() house.requestDelete()
del self.houses[:] self.houses = []
if self.pond: if self.pond:
self.pond.requestDelete()
for spot in self.spots: for spot in self.spots:
spot.requestDelete() spot.requestDelete()
self.spots = []
for target in self.targets: for target in self.targets:
target.requestDelete() target.requestDelete()
self.targets = []
self.pond.requestDelete()
self.pond = None
if self.jukebox: self.gardenManager.destroy()
self.jukebox.requestDelete()
if self.treasurePlanner:
self.treasurePlanner.stop()
if self.rentalHandle: if self.rentalHandle:
self.rentalHandle.destroy() self.rentalHandle.destroy()
self.rentalHandle = None self.rentalHandle = None
self.requestDelete() self.requestDelete()
def setEstateReady(self): def addDistObj(self, distObj):
pass self.doId2do[distObj.doId] = distObj
def setClientReady(self): def setClientReady(self):
self.sendUpdate('setEstateReady', []) self.sendUpdate('setEstateReady', [])
def setClosestHouse(self, todo0): def setEstateType(self, type):
pass self.estateType = type
def setTreasureIds(self, todo0): def d_setEstateType(self, type):
pass self.sendUpdate('setEstateType', [type])
def createTreasurePlanner(self): def b_setEstateType(self, type):
treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = TreasureGlobals.SafeZoneTreasureSpawns[ToontownGlobals.MyEstate] self.setEstateType(type)
self.treasurePlanner = SZTreasurePlannerAI(self.zoneId, treasureType, healAmount, spawnPoints, spawnRate, maxTreasures) self.d_setEstateType(type)
self.treasurePlanner.start()
def getEstateType(self):
return self.estateType
def requestServerTime(self): def requestServerTime(self):
avId = self.air.getAvatarIdFromSender() avId = self.air.getAvatarIdFromSender()
self.sendUpdateToAvatarId(avId, 'setServerTime', [time.time() % HouseGlobals.DAY_NIGHT_PERIOD]) self.sendUpdateToAvatarId(avId, 'setServerTime', [time.time() % HouseGlobals.DAY_NIGHT_PERIOD])
def setServerTime(self, todo0):
pass
def setDawnTime(self, dawnTime): def setDawnTime(self, dawnTime):
self.dawnTime = dawnTime self.dawnTime = dawnTime
@ -320,22 +603,6 @@ class DistributedEstateAI(DistributedObjectAI):
def getDawnTime(self): def getDawnTime(self):
return self.dawnTime 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): def setLastEpochTimeStamp(self, last):
self.lastEpochTimestamp = last self.lastEpochTimestamp = last
@ -367,12 +634,13 @@ class DistributedEstateAI(DistributedObjectAI):
self.setRentalType(type) self.setRentalType(type)
def d_setRentalType(self, type): def d_setRentalType(self, type):
self.sendUpdate("setRentalType", [type]) self.sendUpdate('setRentalType', [type])
def setRentalType(self, type): def setRentalType(self, type):
expirestamp = self.getRentalTimeStamp() expirestamp = self.getRentalTimeStamp()
if expirestamp == 0: if expirestamp == 0:
expire = 0 expire = 0
else: else:
expire = int(expirestamp - time.time()) expire = int(expirestamp - time.time())
@ -380,6 +648,7 @@ class DistributedEstateAI(DistributedObjectAI):
self.rentalType = 0 self.rentalType = 0
self.d_setRentalType(0) self.d_setRentalType(0)
self.b_setRentalTimeStamp(0) self.b_setRentalTimeStamp(0)
else: else:
if self.rentalType == type: if self.rentalType == type:
return return
@ -391,8 +660,7 @@ class DistributedEstateAI(DistributedObjectAI):
if self.rentalType == ToontownGlobals.RentalCannon: if self.rentalType == ToontownGlobals.RentalCannon:
self.rentalHandle = CannonRental(self) self.rentalHandle = CannonRental(self)
elif self.rentalType == ToontownGlobals.RentalGameTable:
self.rentalHandle = TableRental(self)
else: else:
self.notify.warning('Unknown rental %s' % self.rentalType) self.notify.warning('Unknown rental %s' % self.rentalType)
return return
@ -403,7 +671,6 @@ class DistributedEstateAI(DistributedObjectAI):
return self.rentalType return self.rentalType
def rentItem(self, rentType, duration): def rentItem(self, rentType, duration):
self.rentalType = rentType
self.b_setRentalTimeStamp(time.time() + duration * 60) self.b_setRentalTimeStamp(time.time() + duration * 60)
self.b_setRentalType(rentType) self.b_setRentalType(rentType)
@ -424,7 +691,7 @@ class DistributedEstateAI(DistributedObjectAI):
self.items[0] = items self.items[0] = items
def d_setSlot0Items(self, items): def d_setSlot0Items(self, items):
self.sendUpdate('setSlot0Items', [items]) self.sendUpdate('setSlot5Items', [items])
def b_setSlot0Items(self, items): def b_setSlot0Items(self, items):
self.setSlot0Items(items) self.setSlot0Items(items)
@ -450,11 +717,11 @@ class DistributedEstateAI(DistributedObjectAI):
self.items[1] = items self.items[1] = items
def d_setSlot1Items(self, items): def d_setSlot1Items(self, items):
self.sendUpdate('setSlot1Items', [items]) self.sendUpdate('setSlot2Items', [items])
def b_setSlot1Items(self, items): def b_setSlot1Items(self, items):
self.setSlot1Items(items) self.setSlot2Items(items)
self.d_setSlot1Items(items) self.d_setSlot2Items(items)
def getSlot1Items(self): def getSlot1Items(self):
return self.items[1] return self.items[1]
@ -564,7 +831,7 @@ class DistributedEstateAI(DistributedObjectAI):
return self.items[5] return self.items[5]
def setIdList(self, idList): def setIdList(self, idList):
for i in xrange(len(idList)): for i in range(len(idList)):
if i >= 6: if i >= 6:
return return
self.toons[i] = idList[i] self.toons[i] = idList[i]
@ -574,26 +841,44 @@ class DistributedEstateAI(DistributedObjectAI):
def b_setIdList(self, idList): def b_setIdList(self, idList):
self.setIdList(idList) self.setIdList(idList)
self.d_setIdList(idList) self.d_setIdLst(idList)
def completeFlowerSale(self, todo0): def completeFlowerSale(self, flag):
pass if not flag:
return
def completeFishSale(self, sell):
avId = self.air.getAvatarIdFromSender() avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId) av = self.air.doId2do.get(avId)
if av: if not av:
if sell: return
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])
def awardedTrophy(self, todo0): collection = av.flowerCollection
pass
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): def setClouds(self, clouds):
self.cloudType = clouds self.cloudType = clouds
@ -608,67 +893,55 @@ class DistributedEstateAI(DistributedObjectAI):
def getClouds(self): def getClouds(self):
return self.cloudType return self.cloudType
def cannonsOver(self): # Garden methods
pass def getToonSlot(self, avId):
if avId not in self.toons:
return
def gameTableOver(self): return self.toons.index(avId)
pass
def placeStarterGarden(self, avatar): def setSlot0Garden(self, flag):
# TODO: Place garden if a toon already owns one. self.__pendingGardens[0] = flag
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 updateToons(self): def setSlot1Garden(self, flag):
self.d_setSlot0ToonId(self.toons[0]) self.__pendingGardens[1] = flag
self.d_setSlot1ToonId(self.toons[1])
self.d_setSlot2ToonId(self.toons[2]) def setSlot2Garden(self, flag):
self.d_setSlot3ToonId(self.toons[3]) self.__pendingGardens[2] = flag
self.d_setSlot4ToonId(self.toons[4])
self.d_setSlot5ToonId(self.toons[5]) 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]) self.sendUpdate('setIdList', [self.toons])
def updateItems(self): for index, started in self.__pendingGardens.items():
self.d_setSlot0Items(self.items[0]) if started:
self.d_setSlot1Items(self.items[1]) self.gardenManager.handleSingleGarden(self.toons[index])
self.d_setSlot2Items(self.items[2])
self.d_setSlot3Items(self.items[3]) self.__pendingGardens = {}
self.d_setSlot4Items(self.items[4]) if config.GetBool('fake-garden-started-ai', False):
self.d_setSlot5Items(self.items[5]) self.placeStarterGarden(100000002, 0)

View file

@ -4,11 +4,15 @@ from toontown.estate import FlowerBase
from toontown.estate import GardenGlobals from toontown.estate import GardenGlobals
from toontown.toontowngui import TTDialog from toontown.toontowngui import TTDialog
from toontown.toonbase import TTLocalizer from toontown.toonbase import TTLocalizer
from DistributedGardenBox import DistributedGardenBox
DIRT_AS_WATER_INDICATOR = True DIRT_AS_WATER_INDICATOR = True
DIRT_MOUND_HEIGHT = 0.3 DIRT_MOUND_HEIGHT = 0.3
class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.FlowerBase): class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.FlowerBase):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFlower') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFlower')
deferFor = 2
def __init__(self, cr): def __init__(self, cr):
DistributedPlantBase.DistributedPlantBase.__init__(self, cr) DistributedPlantBase.DistributedPlantBase.__init__(self, cr)
@ -17,16 +21,16 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
self.stickUp = 1.07 self.stickUp = 1.07
if DIRT_AS_WATER_INDICATOR: if DIRT_AS_WATER_INDICATOR:
self.stickUp += DIRT_MOUND_HEIGHT self.stickUp += DIRT_MOUND_HEIGHT
self.collSphereRadius = 2.8 self.collSphereRadius = 2.2
self.shadowScale = 0.5 self.shadowScale = 0.5
self.collSphereOffset = 0.0 self.collSphereOffset = 0.0
self.dirtMound = None self.dirtMound = None
self.sandMound = None self.sandMound = None
self.resultDialog = None self.resultDialog = None
return
def delete(self): def delete(self):
DistributedPlantBase.DistributedPlantBase.delete(self) DistributedPlantBase.DistributedPlantBase.delete(self)
del self.dirtMound del self.dirtMound
del self.sandMound del self.sandMound
@ -34,9 +38,6 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
DistributedPlantBase.DistributedPlantBase.setTypeIndex(self, typeIndex) DistributedPlantBase.DistributedPlantBase.setTypeIndex(self, typeIndex)
self.setSpecies(typeIndex) self.setSpecies(typeIndex)
def getTypeIndex(self):
return self.typeIndex
def showWiltOrBloom(self): def showWiltOrBloom(self):
if not self.model: if not self.model:
return return
@ -52,7 +53,7 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
desat = wilt.find('**/*desat*') desat = wilt.find('**/*desat*')
bloom.hide() bloom.hide()
leaves = wilt.findAllMatches('**/*leaf*') leaves = wilt.findAllMatches('**/*leaf*')
for leafIndex in xrange(leaves.getNumPaths()): for leafIndex in range(leaves.getNumPaths()):
leaf = leaves.getPath(leafIndex) leaf = leaves.getPath(leafIndex)
leaf.setColorScale(1.0, 0.3, 0.1, 1.0) 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.removeShovelRelatedDoId(self.doId)
base.localAvatar.setInGardenAction(self) base.localAvatar.setInGardenAction(self)
base.cr.playGame.getPlace().detectedGardenPlotUse() base.cr.playGame.getPlace().detectedGardenPlotUse()
self.sendUpdate('removeItem', [base.localAvatar.doId]) self.sendUpdate('removeItem', [])
def setWaterLevel(self, waterLevel): def setWaterLevel(self, waterLevel):
DistributedPlantBase.DistributedPlantBase.setWaterLevel(self, waterLevel) DistributedPlantBase.DistributedPlantBase.setWaterLevel(self, waterLevel)
@ -140,9 +141,6 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
if self.model: if self.model:
self.adjustWaterIndicator() self.adjustWaterIndicator()
def getWaterLevel(self):
return self.waterLevel
def setGrowthLevel(self, growthLevel): def setGrowthLevel(self, growthLevel):
origGrowthLevel = self.growthLevel origGrowthLevel = self.growthLevel
self.growthLevel = growthLevel self.growthLevel = growthLevel
@ -150,8 +148,8 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
self.loadModel() self.loadModel()
self.makeMovieNode() self.makeMovieNode()
def getGrowthLevel(self): if hasattr(self, '_boxDoId'):
return self.growthLevel self.setBoxDoId(*self._boxDoId)
def makeMovieNode(self): def makeMovieNode(self):
self.movieNode = self.rotateNode.attachNewNode('moviePos') self.movieNode = self.rotateNode.attachNewNode('moviePos')
@ -200,4 +198,17 @@ class DistributedFlower(DistributedPlantBase.DistributedPlantBase, FlowerBase.Fl
self.resultDialog.destroy() self.resultDialog.destroy()
self.resultDialog = None self.resultDialog = None
self.finishInteraction() 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 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 import GardenGlobals
# flower is player's tier. import time
class DistributedFlowerAI(DistributedPlantBaseAI): ONE_DAY = 86400
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedFlowerAI")
def __init__(self, air): class DistributedFlowerAI(DistributedPlantBaseAI, FlowerBase):
DistributedPlantBaseAI.__init__(self, air) notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFlowerAI')
self.air = air
self.typeIndex = None
def setTypeIndex(self, typeIndex): def setTypeIndex(self, value):
DistributedPlantBaseAI.setTypeIndex(self, typeIndex) DistributedPlantBaseAI.setTypeIndex(self, value)
self.typeIndex = typeIndex FlowerBase.setSpecies(self, value)
def getTypeIndex(self): def calculate(self, lastCheck):
return self.typeIndex now = int(time.time())
if lastCheck == 0:
lastCheck = now
def setVariety(self, variety): grown = 0
self.variety = variety
# 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.backupFruits = []
self.signHasBeenStuck2Ground = False self.signHasBeenStuck2Ground = False
self.setName('DistributedGagTree') self.setName('DistributedGagTree')
return self.fruiting = 0
def delete(self): def delete(self):
DistributedPlantBase.DistributedPlantBase.delete(self) DistributedPlantBase.DistributedPlantBase.delete(self)
@ -79,7 +79,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.model.reparentTo(self.rotateNode) self.model.reparentTo(self.rotateNode)
if self.isFruiting() and not self.isWilted(): if self.isFruiting() and not self.isWilted():
self.fruits = [] 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)) pos = self.model.find('**/locator' + str(i))
if pos and not pos.isEmpty(): if pos and not pos.isEmpty():
fruit = self.prop.copyTo(self.model) fruit = self.prop.copyTo(self.model)
@ -141,8 +141,6 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.confirmDialog.destroy() self.confirmDialog.destroy()
self.confirmDialog = None self.confirmDialog = None
if value > 0: if value > 0:
base.localAvatar.showGardeningGui()
base.localAvatar.removeShovelRelatedDoId(self.doId)
self.doPicking() self.doPicking()
else: else:
self.finishInteraction() self.finishInteraction()
@ -151,7 +149,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
def doPicking(self): def doPicking(self):
if not self.canBePicked(): if not self.canBePicked():
return return
self.sendUpdate('removeItem', [base.localAvatar.doId]) self.sendUpdate('removeItem', [])
def createBackupFruits(self): def createBackupFruits(self):
if not hasattr(self, 'fruits'): if not hasattr(self, 'fruits'):
@ -175,6 +173,11 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.backupFruits.append(newFruit) self.backupFruits.append(newFruit)
def clearBackupFruits(self): def clearBackupFruits(self):
if self.fruits:
for fruit in self.fruits:
fruit.removeNode()
self.fruits = None
self.backupFruits = [] self.backupFruits = []
def doHarvesting(self): def doHarvesting(self):
@ -184,14 +187,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
for fruit in self.backupFruits: for fruit in self.backupFruits:
fruit.show() fruit.show()
self.sendUpdate('requestHarvest', [base.localAvatar.doId]) self.sendUpdate('requestHarvest', [])
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()
def getTrack(self): def getTrack(self):
return self.gagTrack return self.gagTrack
@ -268,7 +264,6 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.movie.append(Func(toon.loop, 'neutral')) self.movie.append(Func(toon.loop, 'neutral'))
if avId == localAvatar.doId: if avId == localAvatar.doId:
self.movie.append(Func(self.finishInteraction)) self.movie.append(Func(self.finishInteraction))
self.movie.append(Func(self.hideItems))
self.movie.append(Func(self.movieDone)) self.movie.append(Func(self.movieDone))
self.movie.append(Func(self.doResultDialog)) self.movie.append(Func(self.doResultDialog))
self.movie.start() self.movie.start()
@ -299,7 +294,6 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
for fruit in self.backupFruits: 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))) 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)) harvestTrack = Sequence(fruitTrack, Func(self.clearBackupFruits))
return harvestTrack return harvestTrack
@ -343,7 +337,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
picker.traverse(render) picker.traverse(render)
if queue.getNumEntries() > 0: if queue.getNumEntries() > 0:
queue.sortEntries() queue.sortEntries()
for index in xrange(queue.getNumEntries()): for index in range(queue.getNumEntries()):
entry = queue.getEntry(index) entry = queue.getEntry(index)
if DistributedLawnDecor.recurseParent(entry.getIntoNode(), 'terrain_DNARoot'): if DistributedLawnDecor.recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.signModel.wrtReparentTo(render) self.signModel.wrtReparentTo(render)
@ -356,25 +350,7 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
return Task.done return Task.done
def canBeHarvested(self): def canBeHarvested(self):
myTrack, myLevel = GardenGlobals.getTreeTrackAndLevel(self.typeIndex) return self.isFruiting()
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
def hasDependentTrees(self): def hasDependentTrees(self):
myTrack, myLevel = GardenGlobals.getTreeTrackAndLevel(self.typeIndex) myTrack, myLevel = GardenGlobals.getTreeTrackAndLevel(self.typeIndex)
@ -403,8 +379,14 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
self.finishInteraction() self.finishInteraction()
return return
def velvetRoped(self):
return not base.cr.isPaid() and ToontownBattleGlobals.gagIsPaidOnly(self.gagTrack, self.gagLevel)
def allowedToPick(self): def allowedToPick(self):
return True retval = True
if self.velvetRoped():
retval = False
return retval
def unlockPick(self): def unlockPick(self):
retval = True retval = True
@ -417,3 +399,15 @@ class DistributedGagTree(DistributedPlantBase.DistributedPlantBase):
if inventory.numItem(self.gagTrack, self.gagLevel) >= inventory.getMax(self.gagTrack, self.gagLevel): if inventory.numItem(self.gagTrack, self.gagLevel) >= inventory.getMax(self.gagTrack, self.gagLevel):
retval = False retval = False
return retval 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 direct.directnotify import DirectNotifyGlobal
from otp.ai.MagicWordGlobal import *
from toontown.estate.DistributedPlantBaseAI import DistributedPlantBaseAI 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): class DistributedGagTreeAI(DistributedPlantBaseAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGagTreeAI") notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGagTreeAI')
GrowRate = config.GetBool('trees-grow-rate', 2)
def __init__(self, air): def __init__(self, mgr):
DistributedPlantBaseAI.__init__(self, air) DistributedPlantBaseAI.__init__(self, mgr)
self.air = air
self.wilted = 0 self.wilted = 0
def announceGenerate(self): def announceGenerate(self):
DistributedPlantBaseAI.announceGenerate(self) DistributedPlantBaseAI.announceGenerate(self)
messenger.send(self.getEventName('generate'))
def delete(self):
DistributedPlantBaseAI.delete(self)
def disable(self):
DistributedPlantBaseAI.disable(self)
def setWilted(self, wilted): def setWilted(self, wilted):
self.wilted = 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): def getWilted(self):
return self.wilted return self.wilted
def requestHarvest(self, doId): def calculate(self, lastHarvested, lastCheck):
# TODO: Actually harvest the gags and add them to toon inventory. now = int(time.time())
av = simbase.air.doId2do.get(doId) 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 harvested = 0
track, level = GardenGlobals.getTreeTrackAndLevel(self.typeIndex) track, level = GardenGlobals.getTreeTrackAndLevel(self.typeIndex)
while av.inventory.addItem(track, level) > 0 and harvested < 10: while av.inventory.addItem(track, level) > 0 and harvested < 10:
harvested += 1 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 pandac.PandaModules import *
from direct.distributed import DistributedObject
from direct.distributed.ClockDelta import *
from direct.directnotify import DirectNotifyGlobal
from direct.gui.DirectGui import *
from toontown.toonbase.ToonBaseGlobal 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 import HouseGlobals
class DistributedGarden(DistributedObject.DistributedObject): class DistributedGarden(DistributedObject.DistributedObject):
@ -18,7 +31,7 @@ class DistributedGarden(DistributedObject.DistributedObject):
self.radius = 0 self.radius = 0
self.gridCells = 20 self.gridCells = 20
self.propTable = [None] * self.gridCells 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.propTable[i] = [None] * self.gridCells
self.dx = 1.0 / self.gridCells self.dx = 1.0 / self.gridCells

View file

@ -4,25 +4,6 @@ from direct.distributed.DistributedObjectAI import DistributedObjectAI
class DistributedGardenAI(DistributedObjectAI): class DistributedGardenAI(DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGardenAI") notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGardenAI")
def __init__(self, air): def sendNewProp(self, todo0, todo1, todo2, todo3):
DistributedObjectAI.__init__(self, air) pass
self.air = air
self.props = []
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.plantingGuiDoneEvent = 'plantingGuiDone'
self.defaultModel = 'phase_5.5/models/estate/planterC' self.defaultModel = 'phase_5.5/models/estate/planterC'
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedLawnDecor.DistributedLawnDecor.announceGenerate(self)
def doModelSetup(self): def doModelSetup(self):
if self.typeIndex == GardenGlobals.BOX_THREE: if self.typeIndex == GardenGlobals.BOX_THREE:
self.defaultModel = 'phase_5.5/models/estate/planterA' self.defaultModel = 'phase_5.5/models/estate/planterA'
elif self.typeIndex == GardenGlobals.BOX_TWO: elif self.typeIndex == GardenGlobals.BOX_TWO:
self.defaultModel = 'phase_5.5/models/estate/planterC' self.defaultModel = 'phase_5.5/models/estate/planterC'
else: else:
self.defaultModel = 'phase_5.5/models/estate/planterB' self.defaultModel = 'phase_5.5/models/estate/planterD'
self.collSphereOffset = 0.0 self.collSphereOffset = 0.0
self.collSphereRadius = self.collSphereRadius * 1.41 self.collSphereRadius = self.collSphereRadius * 1.41
self.plotScale = Vec3(1.0, 1.0, 1.0) self.plotScale = Vec3(1.0, 1.0, 1.0)
@ -45,7 +41,6 @@ class DistributedGardenBox(DistributedLawnDecor.DistributedLawnDecor):
self.model.setScale(self.plotScale) self.model.setScale(self.plotScale)
self.model.reparentTo(self.rotateNode) self.model.reparentTo(self.rotateNode)
self.stick2Ground() self.stick2Ground()
return
def handleEnterPlot(self, entry = None): def handleEnterPlot(self, entry = None):
pass pass
@ -55,3 +50,4 @@ class DistributedGardenBox(DistributedLawnDecor.DistributedLawnDecor):
def setTypeIndex(self, typeIndex): def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex self.typeIndex = typeIndex

View file

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

View file

@ -2,6 +2,7 @@ import DistributedLawnDecor
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.showbase.ShowBase import * from direct.showbase.ShowBase import *
from direct.interval.IntervalGlobal import * from direct.interval.IntervalGlobal import *
from DistributedGardenBox import DistributedGardenBox
import GardenGlobals import GardenGlobals
from toontown.toonbase import TTLocalizer from toontown.toonbase import TTLocalizer
from toontown.estate import PlantingGUI from toontown.estate import PlantingGUI
@ -14,6 +15,7 @@ import types
class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor): class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGardenPlot') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGardenPlot')
deferFor = 2
def __init__(self, cr): def __init__(self, cr):
DistributedLawnDecor.DistributedLawnDecor.__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.defaultModel = 'phase_5.5/models/estate/dirt_mound'
self.colorScaler = Vec4(1, 1, 1, 1) self.colorScaler = Vec4(1, 1, 1, 1)
self.plantingGui = None self.plantingGui = None
self.planted = None
return return
def delete(self): def delete(self):
@ -84,8 +85,6 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
return self.getPlantingText() return self.getPlantingText()
def handleEnterPlot(self, entry = None): def handleEnterPlot(self, entry = None):
#Force Gardens -Zach
base.localAvatar.setGardenStarted(True)
dist = self.getDistance(localAvatar) dist = self.getDistance(localAvatar)
if self.canBePlanted(): if self.canBePlanted():
base.localAvatar.addShovelRelatedDoId(self.doId) base.localAvatar.addShovelRelatedDoId(self.doId)
@ -110,12 +109,7 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
return plantText return plantText
def canBePlanted(self): def canBePlanted(self):
retval = True return base.localAvatar.doId == self.getOwnerId()
if not base.localAvatar.doId == self.getOwnerId():
retval = False
if hasattr(self, 'planted') and self.planted:
retval = False
return retval
def plantSomething(self): def plantSomething(self):
whatCanBePlanted = GardenGlobals.whatCanBePlanted(self.ownerIndex, self.plot) whatCanBePlanted = GardenGlobals.whatCanBePlanted(self.ownerIndex, self.plot)
@ -143,13 +137,14 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
recipeKey = GardenGlobals.getRecipeKey(recipeStr, special) recipeKey = GardenGlobals.getRecipeKey(recipeStr, special)
if recipeKey >= 0: if recipeKey >= 0:
species, variety = GardenGlobals.getSpeciesVarietyGivenRecipe(recipeKey) species, variety = GardenGlobals.getSpeciesVarietyGivenRecipe(recipeKey)
print 'RK>0', species, variety
if species >= 0 and variety >= 0: if species >= 0 and variety >= 0:
self.sendUpdate('plantFlower', [species, variety, base.localAvatar.doId]) self.sendUpdate('plantFlower', [species, variety])
successPlanting = True successPlanting = True
else: else:
self.notify.debug('%s %d is not a valid recipe' % (recipeStr, special)) self.notify.debug('%s %d is not a valid recipe' % (recipeStr, special))
burntBeans = len(recipeStr) burntBeans = len(recipeStr)
self.sendUpdate('plantNothing', [burntBeans, base.localAvatar.doId]) self.sendUpdate('plantNothing', [burntBeans])
if successPlanting: if successPlanting:
flowerName = GardenGlobals.getFlowerVarietyName(species, variety) flowerName = GardenGlobals.getFlowerVarietyName(species, variety)
stringToShow = TTLocalizer.getResultPlantedSomethingSentence(flowerName) stringToShow = TTLocalizer.getResultPlantedSomethingSentence(flowerName)
@ -209,11 +204,11 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
if species >= 205 and species <= 208: if species >= 205 and species <= 208:
successToonStatue = True successToonStatue = True
else: else:
self.sendUpdate('plantStatuary', [species, base.localAvatar.doId]) self.sendUpdate('plantStatuary', [species])
else: else:
self.notify.debug('%s %d is not a valid recipe' % (recipeStr, special)) self.notify.debug('%s %d is not a valid recipe' % (recipeStr, special))
burntBeans = len(recipeStr) burntBeans = len(recipeStr)
self.sendUpdate('plantNothing', [burntBeans, base.localAvatar.doId]) self.sendUpdate('plantNothing', [burntBeans])
if successPlanting: if successPlanting:
itemName = GardenGlobals.PlantAttributes[species]['name'] itemName = GardenGlobals.PlantAttributes[species]['name']
stringToShow = TTLocalizer.getResultPlantedSomethingSentence(itemName) stringToShow = TTLocalizer.getResultPlantedSomethingSentence(itemName)
@ -252,7 +247,7 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
base.localAvatar.showGardeningGui() base.localAvatar.showGardeningGui()
base.localAvatar.removeShovelRelatedDoId(self.doId) base.localAvatar.removeShovelRelatedDoId(self.doId)
if willPlant: if willPlant:
self.sendUpdate('plantToonStatuary', [species, dnaCode, base.localAvatar.doId]) self.sendUpdate('plantToonStatuary', [species, dnaCode])
else: else:
self.popupItemPlantingGui() self.popupItemPlantingGui()
return return
@ -271,21 +266,11 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
base.localAvatar.showGardeningGui() base.localAvatar.showGardeningGui()
base.localAvatar.removeShovelRelatedDoId(self.doId) base.localAvatar.removeShovelRelatedDoId(self.doId)
if willPlant: if willPlant:
self.sendUpdate('plantGagTree', [gagTrack, gagLevel, base.localAvatar.doId]) self.sendUpdate('plantGagTree', [gagTrack, gagLevel])
else: else:
self.finishInteraction() self.finishInteraction()
return 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): def setMovie(self, mode, avId):
if mode == GardenGlobals.MOVIE_PLANT: if mode == GardenGlobals.MOVIE_PLANT:
self.doPlaceItemTrack(avId) self.doPlaceItemTrack(avId)
@ -316,8 +301,8 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.movie.append(Func(toon.detachShovel)) self.movie.append(Func(toon.detachShovel))
if self.model: if self.model:
pos = self.model.getPos() pos = self.model.getPos()
pos.setZ(pos[2] + 1) pos.setZ(pos[2] - 1)
animProp = LerpPosInterval(self.model, 3, pos, self.model.getPos()) animProp = LerpPosInterval(self.model, 3, self.model.getPos(), pos)
shrinkProp = LerpScaleInterval(self.model, 3, scale=self.plotScale, startScale=0.01) shrinkProp = LerpScaleInterval(self.model, 3, scale=self.plotScale, startScale=0.01)
objAnimShrink = ParallelEndTogether(animProp, shrinkProp) objAnimShrink = ParallelEndTogether(animProp, shrinkProp)
self.movie.append(objAnimShrink) self.movie.append(objAnimShrink)
@ -325,16 +310,10 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.movie.append(Func(toon.loop, 'neutral')) self.movie.append(Func(toon.loop, 'neutral'))
if avId == localAvatar.doId: if avId == localAvatar.doId:
self.movie.append(Func(self.finishInteraction)) self.movie.append(Func(self.finishInteraction))
self.movie.append(Func(self.removePlanted)) self.movie.append(Func(self.movieDone))
self.movie.start() self.movie.start()
def doPlaceItemTrack(self, avId, item = None): 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) toon = base.cr.doId2do.get(avId)
if not toon: if not toon:
return return
@ -348,24 +327,14 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), placeItemTrack) self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), placeItemTrack)
if avId == localAvatar.doId: if avId == localAvatar.doId:
self.expectingReplacement = 1 self.expectingReplacement = 1
self.movie.append(Func(self.sendUpdate, 'finishPlanting', [avId])) self.movie.append(Func(self.movieDone))
self.movie.start() self.movie.start()
def generatePlaceItemTrack(self, toon, item): def generatePlaceItemTrack(self, toon, item):
sound = loader.loadSfx('phase_5.5/audio/sfx/burrow.ogg') sound = loader.loadSfx('phase_5.5/audio/sfx/burrow.ogg')
sound.setPlayRate(0.5) sound.setPlayRate(0.5)
placeItemTrack = Parallel() placeItemTrack = Parallel()
placeItemTrack.append(Sequence(ActorInterval(toon, 'start-dig'), 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)))
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: if self.model:
pos = self.model.getPos() pos = self.model.getPos()
pos.setZ(pos[2] - 1) pos.setZ(pos[2] - 1)
@ -374,12 +343,7 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
objAnimShrink = ParallelEndTogether(animProp, shrinkProp) objAnimShrink = ParallelEndTogether(animProp, shrinkProp)
placeItemTrack.append(objAnimShrink) placeItemTrack.append(objAnimShrink)
if item: if item:
placeItemTrack.append(Sequence(Func(item.reparentTo, toon.rightHand), 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)))
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 return placeItemTrack
def makeMovieNode(self): def makeMovieNode(self):
@ -390,3 +354,20 @@ class DistributedGardenPlot(DistributedLawnDecor.DistributedLawnDecor):
self.stick2Ground() self.stick2Ground()
else: else:
DistributedLawnDecor.DistributedLawnDecor.makeMovieNode(self) 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 direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI from otp.ai.MagicWordGlobal import *
from DistributedToonStatuaryAI import DistributedToonStatuaryAI from DistributedLawnDecorAI import DistributedLawnDecorAI
from DistributedStatuaryAI import DistributedStatuaryAI
from DistributedGagTreeAI import DistributedGagTreeAI
from DistributedFlowerAI import DistributedFlowerAI
import GardenGlobals 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): class DistributedGardenPlotAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedGardenPlotAI") notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGardenPlotAI')
def __init__(self, air):
DistributedLawnDecorAI.__init__(self, air)
self.air = air
self.planted = None
def announceGenerate(self): def announceGenerate(self):
DistributedLawnDecorAI.announceGenerate(self) DistributedLawnDecorAI.announceGenerate(self)
self.plotType = GardenGlobals.whatCanBePlanted(self.ownerIndex, self.plot)
self.__plantingAvId = 0
def delete(self): def __initialSanityCheck(self, wantedType=None, forceOwner=False):
DistributedLawnDecorAI.delete(self) if self.__plantingAvId:
# Busy, silently ignore
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:
return return
estate.items[self.getOwnerIndex()].append(tuple(data))
estate.updateItems()
def removeData(self): avId = self.air.getAvatarIdFromSender()
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()
def plantFlower(self, species, variety, toon): av = self.air.doId2do.get(avId)
#free for now if not av:
#av = simbase.air.doId2do.get(toon) self.air.writeServerEvent('suspicious', avId, 'called DistributedGardenPlotAI method outside shard!')
#av.takeMoney(GardenGlobals.getNumBeansRequired(species, variety)) return
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])
def plantGagTree(self, track, level, toon): if wantedType is not None and self.plotType != wantedType:
#free for now self.air.writeServerEvent('suspicious', avId, 'called incorrect DistributedGardenPlotAI method!', plotType=self.plotType,
#av = simbase.air.doId2do.get(toon) wantedType=wantedType)
#av.inventory.useItem(track, level) return self.d_interactionDenied()
#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])
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): if avId != self.ownerDoId and not forceOwner:
#free for now self.air.writeServerEvent('suspicious', avId, 'called someone else\'s DistributedGardenPlotAI plant method!',
#av = simbase.air.doId2do.get(toon) ownerDoId=self.ownerDoId)
#av.takeMoney(GardenGlobals.getNumBeansRequired(species, 0)) return self.d_interactionDenied()
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])
def plantNothing(self, burntBeans, toon): return av
# TODO: Fix exploit.
sendAvId = self.air.getAvatarIdFromSender() def plantFlower(self, species, variety, usingSatanFlowerAll=0):
av = self.air.doId2do.get(sendAvId) 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: if av:
av.takeMoney(burntBeans) 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.interval.IntervalGlobal import *
from direct.distributed import ClockDelta from direct.distributed import ClockDelta
from direct.showbase.PythonUtil import lerp from direct.showbase.PythonUtil import lerp
@ -16,6 +16,7 @@ from otp.otpbase import OTPGlobals
from toontown.estate import GardenGlobals from toontown.estate import GardenGlobals
def recurseParent(intoNode, ParentName): def recurseParent(intoNode, ParentName):
# funny fact: cogtown had a func like this
parent = intoNode.getParent(0) parent = intoNode.getParent(0)
if not parent or parent.getName() == 'render': if not parent or parent.getName() == 'render':
return 0 return 0
@ -50,6 +51,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
return return
def setHeading(self, h): def setHeading(self, h):
self.notify.debug('setting h')
DistributedNode.DistributedNode.setH(self, h) DistributedNode.DistributedNode.setH(self, h)
def generateInit(self): def generateInit(self):
@ -93,6 +95,11 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
if not self.rotateNode: if not self.rotateNode:
self.rotateNode = self.plantPath.attachNewNode('rotate') self.rotateNode = self.plantPath.attachNewNode('rotate')
self.model = None 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): def setupShadow(self):
self.shadowJoint = self.rotateNode.attachNewNode('shadow') self.shadowJoint = self.rotateNode.attachNewNode('shadow')
@ -121,6 +128,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
self.accept(self.exitMessageName, self.handleExitPlot) self.accept(self.exitMessageName, self.handleExitPlot)
def handleEnterPlot(self, optional = None): def handleEnterPlot(self, optional = None):
self.notify.debug('handleEnterPlot %d' % self.doId)
self.sendUpdate('plotEntered', []) self.sendUpdate('plotEntered', [])
def handleExitPlot(self, optional = None): def handleExitPlot(self, optional = None):
@ -142,12 +150,6 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
taskMgr.remove(self.uniqueName('adjust tree')) taskMgr.remove(self.uniqueName('adjust tree'))
return return
def setEstate(self, estate):
self.estate = estate
def getEstate(self):
return self.estate
def setPos(self, x, y, z): def setPos(self, x, y, z):
DistributedNode.DistributedNode.setPos(self, x, y, z) DistributedNode.DistributedNode.setPos(self, x, y, z)
self.stick2Ground() self.stick2Ground()
@ -175,7 +177,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
picker.traverse(render) picker.traverse(render)
if queue.getNumEntries() > 0: if queue.getNumEntries() > 0:
queue.sortEntries() queue.sortEntries()
for index in xrange(queue.getNumEntries()): for index in range(queue.getNumEntries()):
entry = queue.getEntry(index) entry = queue.getEntry(index)
if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'): if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.movieNode.setZ(entry.getSurfacePoint(self)[2]) self.movieNode.setZ(entry.getSurfacePoint(self)[2])
@ -184,7 +186,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
picker.traverse(render) picker.traverse(render)
if queue.getNumEntries() > 0: if queue.getNumEntries() > 0:
queue.sortEntries() queue.sortEntries()
for index in xrange(queue.getNumEntries()): for index in range(queue.getNumEntries()):
entry = queue.getEntry(index) entry = queue.getEntry(index)
if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'): if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.setZ(entry.getSurfacePoint(render)[2] + self.stickUp + 0.1) self.setZ(entry.getSurfacePoint(render)[2] + self.stickUp + 0.1)
@ -197,12 +199,12 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
def stickParts(self): def stickParts(self):
pass pass
def setH(self, h):
DistributedNode.DistributedNode.setH(self, h)
def setPlot(self, plot): def setPlot(self, plot):
self.plot = plot self.plot = plot
def setH(self, h):
DistributedNode.DistributedNode.setH(self, h)
def getPlot(self): def getPlot(self):
return self.plot return self.plot
@ -242,7 +244,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
base.localAvatar.hideShovelButton() base.localAvatar.hideShovelButton()
base.localAvatar.hideWateringCanButton() base.localAvatar.hideWateringCanButton()
self.startInteraction() self.startInteraction()
self.sendUpdate('removeItem', [base.localAvatar.doId]) self.sendUpdate('removeItem', [])
def generateToonMoveTrack(self, toon): def generateToonMoveTrack(self, toon):
node = NodePath('tempNode') node = NodePath('tempNode')
@ -261,10 +263,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
finalY = node.getY(render) finalY = node.getY(render)
finalZ = node.getZ(render) finalZ = node.getZ(render)
node.removeNode() node.removeNode()
toonTrack = Sequence(Parallel(ActorInterval(toon, 'walk', loop=True, duration=1), 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'))
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 return toonTrack
def unprint(self, string): def unprint(self, string):
@ -288,16 +287,13 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
def startCamIval(self, avId): def startCamIval(self, avId):
track = Sequence() track = Sequence()
if avId == localAvatar.doId: if avId == localAvatar.doId:
track = Sequence(Func(base.localAvatar.disableSmartCameraViews), track = Sequence(Func(base.localAvatar.disableSmartCameraViews), Func(base.localAvatar.setCameraPosForPetInteraction))
Func(base.localAvatar.setCameraPosForPetInteraction))
return track return track
def stopCamIval(self, avId): def stopCamIval(self, avId):
track = Sequence() track = Sequence()
if avId == localAvatar.doId: if avId == localAvatar.doId:
track = Sequence(Func(base.localAvatar.unsetCameraPosForPetInteraction), track = Sequence(Func(base.localAvatar.unsetCameraPosForPetInteraction), Wait(0.8), Func(base.localAvatar.enableSmartCameraViews))
Wait(0.8),
Func(base.localAvatar.enableSmartCameraViews))
return track return track
def canBeWatered(self): def canBeWatered(self):
@ -332,8 +328,6 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
if not toon: if not toon:
return return
self.finishMovies() self.finishMovies()
if avId == localAvatar.doId:
self.startInteraction()
self.model.setTransparency(1) self.model.setTransparency(1)
self.model.setAlphaScale(1) self.model.setAlphaScale(1)
shovel = toon.attachShovel() shovel = toon.attachShovel()
@ -341,11 +335,9 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
moveTrack = self.generateToonMoveTrack(toon) moveTrack = self.generateToonMoveTrack(toon)
digupTrack = self.generateDigupTrack(toon) digupTrack = self.generateDigupTrack(toon)
self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), digupTrack) self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), digupTrack)
self.movie.append(Func(base.cr.removeObject, self.doId))
if avId == localAvatar.doId: if avId == localAvatar.doId:
self.expectingReplacement = 1 # self.expectingReplacement = 1
plotAv = base.cr.doId2do.get(self.getOwnerPlot()) self.movie.append(Func(self.movieDone))
self.movie.append(Func(plotAv.sendUpdate, 'finishRemoving', [avId]))
self.movie.start() self.movie.start()
def generateDigupTrack(self, toon): def generateDigupTrack(self, toon):
@ -354,22 +346,7 @@ class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCast
pos = self.model.getPos() pos = self.model.getPos()
pos.setZ(pos[2] - 1) pos.setZ(pos[2] - 1)
track = Parallel() track = Parallel()
sq = Sequence(ActorInterval(toon, 'start-dig'), 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)))
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)
return track return track
def doFinishPlantingTrack(self, avId): def doFinishPlantingTrack(self, avId):

View file

@ -1,30 +1,14 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedNodeAI import DistributedNodeAI from direct.distributed.DistributedNodeAI import DistributedNodeAI
import GardenGlobals
class DistributedLawnDecorAI(DistributedNodeAI): class DistributedLawnDecorAI(DistributedNodeAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedLawnDecorAI") notify = DirectNotifyGlobal.directNotify.newCategory("DistributedLawnDecorAI")
def __init__(self, air): def __init__(self, mgr):
DistributedNodeAI.__init__(self, air) self.mgr = mgr
self.air = air DistributedNodeAI.__init__(self, self.mgr.air)
self.plot = None self.plot = 0
self.ownerIndex = None self.ownerIndex = 0
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 setPlot(self, plot): def setPlot(self, plot):
self.plot = plot self.plot = plot
@ -32,37 +16,25 @@ class DistributedLawnDecorAI(DistributedNodeAI):
def getPlot(self): def getPlot(self):
return self.plot return self.plot
def setOwnerIndex(self, index): def getHeading(self):
self.ownerIndex = index 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): def getOwnerIndex(self):
return self.ownerIndex return self.ownerIndex
def setPosition(self, x, y, z): def d_setMovie(self, mode, avId=None):
self.position = (x, y, z) 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]) self.sendUpdate('setMovie', [mode, avId])
def movieDone(self): def d_interactionDenied(self):
if hasattr(self, 'inUseBy'): self.sendUpdate('interactionDenied', [self.air.getAvatarIdFromSender()])
del self.inUseBy
def interactionDenied(self, todo0):
pass

View file

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

View file

@ -1,84 +1,81 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI from toontown.estate.DistributedLawnDecorAI import DistributedLawnDecorAI
import GardenGlobals import GardenGlobals
import datetime
class DistributedPlantBaseAI(DistributedLawnDecorAI): class DistributedPlantBaseAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedPlantBaseAI") notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPlantBaseAI')
def __init__(self, air): def __init__(self, mgr):
DistributedLawnDecorAI.__init__(self, air) DistributedLawnDecorAI.__init__(self, mgr)
self.air = air self.typeIndex = 0
self.growthLevel = -1 self.waterLevel = 0
self.growthLevel = 0
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 setTypeIndex(self, typeIndex): def setTypeIndex(self, typeIndex):
self.typeIndex = typeIndex self.typeIndex = typeIndex
self.attributes = GardenGlobals.PlantAttributes[typeIndex] self.attributes = GardenGlobals.PlantAttributes[typeIndex]
self.name = self.attributes['name']
self.plantType = self.attributes['plantType']
self.growthThresholds = self.attributes['growthThresholds'] 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): def getTypeIndex(self):
return self.typeIndex return self.typeIndex
def setWaterLevel(self, water): def setWaterLevel(self, waterLevel):
self.waterLevel = water 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): def getWaterLevel(self):
return self.waterLevel return self.waterLevel
def setGrowthLevel(self, growth): def setGrowthLevel(self, growthLevel):
self.growthLevel = growth 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): def getGrowthLevel(self):
return self.growthLevel return self.growthLevel
def waterPlant(self, avId): def waterPlant(self):
# TODO: Proper water threshold for watering can type. av = self.air.doId2do.get(self.air.getAvatarIdFromSender())
# Not supposed to be 16 for all watering cans. if not av:
self.lastWateredBy = avId return
newLevel = self.waterLevel + 1
if newLevel > self.maxWaterLevel: level = max(1, self.getWaterLevel() + av.getWateringCan() + 1)
self.setWaterLevel(self.maxWaterLevel) level = min(20, level)
else: self.b_setWaterLevel(level)
self.setWaterLevel(newLevel)
self.sendUpdate('setMovie', [GardenGlobals.MOVIE_WATER, avId]) self.d_setMovie(GardenGlobals.MOVIE_WATER)
self.sendUpdate('setWaterLevel', [self.getWaterLevel()]) self.update()
def waterPlantDone(self): def waterPlantDone(self):
if hasattr(self, 'lastWateredBy'): av = self.air.doId2do.get(self.air.getAvatarIdFromSender())
av = simbase.air.doId2do.get(self.lastWateredBy) if not av:
skill = av.getWateringCanSkill() return
skill += GardenGlobals.WateringCanAttributes[av.wateringCan]['skillPts'] / 100
av.b_setWateringCanSkill(skill) if self.waterLevel < 6:
del self.lastWateredBy av.b_setWateringCanSkill(av.getWateringCanSkill() + 1)
estate = simbase.air.doId2do.get(self.getEstate()) else:
dataIndex = -1 av.b_setWateringCanSkill(av.getWateringCanSkill())
# TODO: Possibly store this in mongodb/cPickle instead.
for n, item in enumerate(estate.items[self.getOwnerIndex()]): self.d_setMovie(GardenGlobals.MOVIE_CLEAR)
if item[0] == self.getPlot():
dataIndex = n def update(self):
if dataIndex >= 0: pass
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()

View file

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

View file

@ -1,33 +1,66 @@
from direct.directnotify import DirectNotifyGlobal 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): class DistributedStatuaryAI(DistributedLawnDecorAI):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedStatuaryAI") notify = DirectNotifyGlobal.directNotify.newCategory("DistributedStatuaryAI")
def __init__(self, air): def calculate(self, lastCheck):
DistributedLawnDecorAI.__init__(self, air) self.attributes = GardenGlobals.PlantAttributes[self.index]
self.air = air self.growthThresholds = self.attributes.get('growthThresholds', (0, 0))
def setTypeIndex(self, typeIndex): now = int(time.time())
self.typeIndex = typeIndex 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): def getTypeIndex(self):
return self.typeIndex return self.index
def setOwnerPlot(self, owner):
self.ownerPlot = owner
def getOwnerPlot(self):
return self.ownerPlot
def setWaterLevel(self, waterLevel):
self.waterLevel = waterLevel
def getWaterLevel(self): def getWaterLevel(self):
return self.waterLevel return 1
def setGrowthLevel(self, growthLevel):
self.growthLevel = growthLevel
def getGrowthLevel(self): def getGrowthLevel(self):
return self.growthLevel 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 toontown.estate import DistributedLawnDecor
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.showbase.ShowBase import * from direct.showbase.ShowBase import *
from panda3d.core import * from pandac.PandaModules import *
from toontown.toon import Toon from toontown.toon import Toon
from toontown.toon import ToonDNA from toontown.toon import ToonDNA
import GardenGlobals import GardenGlobals
@ -46,7 +46,7 @@ class DistributedToonStatuary(DistributedStatuary.DistributedStatuary):
self.model.setScale(self.worldScale * 1.5, self.worldScale * 1.5, self.worldScale) self.model.setScale(self.worldScale * 1.5, self.worldScale * 1.5, self.worldScale)
self.getToonPropertiesFromOptional() self.getToonPropertiesFromOptional()
dna = ToonDNA.ToonDNA() 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.setupStoneToon(dna)
self.poseToonFromTypeIndex(self.typeIndex) self.poseToonFromTypeIndex(self.typeIndex)
self.toon.reparentTo(self.model) self.toon.reparentTo(self.model)
@ -112,7 +112,7 @@ class DistributedToonStatuary(DistributedStatuary.DistributedStatuary):
if sleeves: if sleeves:
sleeves.setTexture(desatSleeveTex, 1) sleeves.setTexture(desatSleeveTex, 1)
bottoms = torso.findAllMatches('**/torso-bot*') bottoms = torso.findAllMatches('**/torso-bot*')
for bottomNum in xrange(0, bottoms.getNumPaths()): for bottomNum in range(0, bottoms.getNumPaths()):
bottom = bottoms.getPath(bottomNum) bottom = bottoms.getPath(bottomNum)
if bottom: if bottom:
if self.toon.style.torso[1] == 's': if self.toon.style.torso[1] == 's':

View file

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

View file

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

View file

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