Example #1
0
 def showWinImage(self, fish):
     self.hideGui(['meterFrame', 'fishingHandleBaseFrame'])
     result = fish.myData['name'].split(' ')
     fileName = str(result[0]).capitalize()
     imgName = 'pir_t_gui_fsh_render%s' % fileName
     self.actorAnim[
         'swimIdleOpposite'] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (
             fish.myData['model'], 'swimIdleOpposite')
     self.fishActor = BlendActor(
         'models/char/pir_r_gam_fsh_%s.bam' % fish.myData['model'],
         self.actorAnim, FishingGlobals.defaultFishBlendTime,
         FishingGlobals.fishBlendTimeDict)
     self.fishActor.setPlayRate(
         fish.myData['speed'] * fish.myData['swimAnimationMultiplier'],
         'swimIdleOpposite')
     self.fishActor.changeAnimationTo('swimIdleOpposite')
     self.fishActor.reparentTo(self.winImagePanel)
     self.fishActor.setScale(self.scaleSize[fish.myData['id']])
     self.fishActor.setPos(1.7, 0, 1.0)
     self.fishActor.setHpr(0, 0, 35)
     self.fishActor.setDepthWrite(True)
     self.fishActor.setDepthTest(True)
     self.wholeStoryTextNode.setText(
         PLocalizer.LegendSelectionGui['wholeStory'][fish.myData['id']])
     self.winImagePanel.show()
Example #2
0
    def initActor(self):
        self.animDict = {}
        for anim in FishingGlobals.fishAnimations:
            self.animDict[anim] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (
                self.myData['model'], anim)

        self.actor = BlendActor(
            'models/char/pir_r_gam_fsh_%s.bam' % self.myData['model'],
            self.animDict, FishingGlobals.defaultFishBlendTime,
            FishingGlobals.fishBlendTimeDict)
        self.actor.reparentTo(self)
        self.actor.setScale(self.adjustedScale)
        self.mouthJoint = self.actor.exposeJoint(None, 'modelRoot',
                                                 'hookAttach')
        self.attractionPoint = NodePath('AttractionPoint')
        self.attractionPoint.reparentTo(self.mouthJoint)
        self.attractionPoint.setPos(0.0, 0.0, 0.0)
        self.actor.setPlayRate(
            self.myData['speed'] * self.myData['swimAnimationMultiplier'],
            'swimIdle')
        self.actor.setPlayRate(
            self.myData['speed'] * self.myData['swimAnimationMultiplier'],
            'swimIdleOpposite')
        self.actor.setPlayRate(
            self.myData['speed'] * self.myData['turnAnimationMultiplier'],
            'turn')
        self.actor.setPlayRate(
            self.myData['speed'] * self.myData['turnAnimationMultiplier'],
            'turnOpposite')
        if not self.trophy:
            self.setBin('fishingGame', 10)
 def initActor(self):
     self.animDict = { }
     for anim in FishingGlobals.fishAnimations:
         self.animDict[anim] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (self.myData['model'], anim)
     
     self.actor = BlendActor('models/char/pir_r_gam_fsh_%s.bam' % self.myData['model'], self.animDict, FishingGlobals.defaultFishBlendTime, FishingGlobals.fishBlendTimeDict)
     self.actor.reparentTo(self)
     self.actor.setScale(self.adjustedScale)
     self.mouthJoint = self.actor.exposeJoint(None, 'modelRoot', 'hookAttach')
     self.attractionPoint = NodePath('AttractionPoint')
     self.attractionPoint.reparentTo(self.mouthJoint)
     self.attractionPoint.setPos(0.0, 0.0, 0.0)
     self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdle')
     self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
     self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turn')
     self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turnOpposite')
     if not self.trophy:
         self.setBin('fishingGame', 10)
 def showWinImage(self, fish):
     self.hideGui([
         'meterFrame',
         'fishingHandleBaseFrame'])
     result = fish.myData['name'].split(' ')
     fileName = str(result[0]).capitalize()
     imgName = 'pir_t_gui_fsh_render%s' % fileName
     self.actorAnim['swimIdleOpposite'] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (fish.myData['model'], 'swimIdleOpposite')
     self.fishActor = BlendActor('models/char/pir_r_gam_fsh_%s.bam' % fish.myData['model'], self.actorAnim, FishingGlobals.defaultFishBlendTime, FishingGlobals.fishBlendTimeDict)
     self.fishActor.setPlayRate(fish.myData['speed'] * fish.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
     self.fishActor.changeAnimationTo('swimIdleOpposite')
     self.fishActor.reparentTo(self.winImagePanel)
     self.fishActor.setScale(self.scaleSize[fish.myData['id']])
     self.fishActor.setPos(1.7, 0, 1.0)
     self.fishActor.setHpr(0, 0, 35)
     self.fishActor.setDepthWrite(True)
     self.fishActor.setDepthTest(True)
     self.wholeStoryTextNode.setText(PLocalizer.LegendSelectionGui['wholeStory'][fish.myData['id']])
     self.winImagePanel.show()
Example #5
0
class LegendaryFishingGameGUI:
    def __init__(self, gameObject=None):
        base.loadingScreen.beginStep('LegendaryGameGUI', 4, 20)
        self.gameObject = gameObject
        self.guiImage = loader.loadModel(
            'models/minigames/pir_m_gam_fsh_legendaryGui')
        self.UICompoments = {}
        self.uiBaseNode = NodePath('baseNode')
        self.uiBaseNode.reparentTo(aspect2d)
        self.uiBaseNode.show()
        self.leftBaseNode = NodePath('leftBaseNode')
        self.leftBaseNode.reparentTo(base.a2dLeftCenter)
        self.leftBaseNode.show()
        self.fishActor = None
        self.actorAnim = {}
        self.scaleSize = {
            InventoryType.Collection_Set11_Part1: 0.059999999999999998,
            InventoryType.Collection_Set11_Part2: 0.055,
            InventoryType.Collection_Set11_Part3: 0.12,
            InventoryType.Collection_Set11_Part4: 0.086999999999999994,
            InventoryType.Collection_Set11_Part5: 0.080000000000000002
        }
        self.meterFrame = DirectFrame(
            parent=self.leftBaseNode,
            frameSize=(-0.29999999999999999, 0.29999999999999999, -1.0, 0.0),
            frameColor=(1.0, 1.0, 1.0, 0.0),
            relief=None,
            state=DGG.DISABLED,
            pos=(1.0, 0.0, -0.45000000000000001),
            hpr=(0, 0, 0),
            scale=(1.3, 0.0, 1.3),
            image=self.guiImage.find('**/pir_t_gui_fsh_meter'),
            image_scale=(0.20000000000000001, 0.0, 0.80000000000000004),
            image_pos=(0, 0, 0),
            text='',
            textMayChange=1,
            text_scale=PiratesGuiGlobals.TextScaleTitleLarge,
            text_pos=(-0.55000000000000004, 0.10000000000000001),
            text_shadow=PiratesGuiGlobals.TextShadow)
        self.UICompoments['meterFrame'] = self.meterFrame
        self.fishingRod = DirectFrame(
            parent=self.meterFrame,
            frameSize=(-0.29999999999999999, 0.29999999999999999, -1.0, 0.0),
            relief=None,
            state=DGG.DISABLED,
            pos=FishingGlobals.fishingRodScreenPosition,
            image=self.guiImage.find('**/pir_t_gui_fsh_fullRod'),
            image_scale=(1.0, 0.0, 0.125),
            image_pos=(0.20000000000000001, 0, 0))
        self.fishingRod.setR(FishingGlobals.fishingRodInitSlope)
        self.UICompoments['fishingRod'] = self.fishingRod
        base.loadingScreen.tick()
        self.fishingHandleBaseFrame = DirectFrame(
            parent=self.uiBaseNode,
            frameSize=(-0.29999999999999999, 0.29999999999999999, -1.5, 1.5),
            frameColor=(1.0, 1.0, 1.0, 0.0),
            relief=None,
            state=DGG.DISABLED,
            pos=(0.0, 0.0, 0.0),
            hpr=(0, 0, 0),
            scale=(0.71999999999999997, 0.0, 0.71999999999999997),
            image=self.guiImage.find('**/pir_t_gui_fsh_partialRod'),
            image_scale=(3.7999999999999998, 0.0, 1.8999999999999999),
            image_pos=(0, 0, 0),
            image_hpr=(0.0, 0.0, 0))
        self.fishingHandleBaseFrame.hide()
        self.UICompoments[
            'fishingHandleBaseFrame'] = self.fishingHandleBaseFrame
        self.fishingHandle = DirectFrame(
            parent=self.fishingHandleBaseFrame,
            frameSize=(-0.080000000000000002, 0.080000000000000002,
                       -0.20000000000000001, 0.20000000000000001),
            relief=None,
            state=DGG.DISABLED,
            pos=(-0.10000000000000001, 0.0, -0.050000000000000003),
            hpr=(0, 0, 0),
            image=self.guiImage.find('**/pir_t_gui_fsh_handleArm'),
            image_scale=(1.0, 0.0, 1.0),
            image_pos=(-0.042000000000000003, 0, -0.115),
            image_hpr=(0.0, 0.0, 0))
        self.UICompoments['fishingHandle'] = self.fishingHandle
        self.arrowImage = DirectFrame(
            parent=self.fishingHandleBaseFrame,
            frameSize=(-0.40000000000000002, 0.40000000000000002,
                       -0.40000000000000002, 0.40000000000000002),
            relief=None,
            state=DGG.DISABLED,
            pos=(0.0, 0.0, 0.0),
            hpr=(0, 0, 0),
            scale=(1.2, 0.0, 1.2),
            image=self.guiImage.find('**/pir_t_gui_fsh_arrow'),
            image_scale=(1.0, 0.0, 1.0),
            image_pos=(0.0, 0, 0.0),
            image_hpr=(0.0, 0.0, 0.0))
        self.arrowImage.hide()
        self.UICompoments['arrowImage'] = self.arrowImage
        btnGeom = (self.guiImage.find('**/pir_t_gui_fsh_handle'),
                   self.guiImage.find('**/pir_t_gui_fsh_handle'),
                   self.guiImage.find('**/pir_t_gui_fsh_handleOn'))
        self.fishingHandleButton = GuiButton(pos=(-0.29999999999999999, 0,
                                                  -0.55000000000000004),
                                             hpr=(0, 0, 0),
                                             scale=0.45000000000000001,
                                             image=btnGeom,
                                             image_pos=(0, 0, 0),
                                             image_scale=1.0,
                                             sortOrder=2)
        self.fishingHandleButton.bind(DGG.B1PRESS, self.handleButtonClicked)
        self.fishingHandleButton.reparentTo(self.fishingHandle)
        self.UICompoments['fishingHandleButton'] = self.fishingHandleButton
        self.fishingHandleBaseFrame.setTransparency(TransparencyAttrib.MAlpha)
        self.meterFrame.setTransparency(TransparencyAttrib.MAlpha)
        self.lineOneTransitTextNode = TextNode('lineOneTransitText')
        self.lineOneTransitTextNode.setFont(PiratesGlobals.getPirateFont())
        self.lineOneTransitTextNode.setText('')
        self.lineOneTransitTextNode.setAlign(TextNode.ACenter)
        self.lineOneTransitTextNode.setTextColor(1.0, 1.0, 1.0, 0.5)
        self.lineOneTransitTextNodePath = NodePath(self.lineOneTransitTextNode)
        self.lineOneTransitTextNodePath.setPos(0.0, 0.0, -0.80000000000000004)
        self.lineOneTransitTextNodePath.setScale(0.34999999999999998,
                                                 0.34999999999999998,
                                                 0.34999999999999998)
        self.lineOneTransitTextNodePath.reparentTo(self.uiBaseNode)
        self.lineOneTransitTextNodePath.hide()
        self.UICompoments[
            'lineOneTransitText'] = self.lineOneTransitTextNodePath
        self.lineTwoTransitTextNode = TextNode('lineTwoTransitText')
        self.lineTwoTransitTextNode.setFont(PiratesGlobals.getPirateFont())
        self.lineTwoTransitTextNode.setText('')
        self.lineTwoTransitTextNode.setAlign(TextNode.ACenter)
        self.lineTwoTransitTextNode.setTextColor(1.0, 1.0, 1.0, 0.5)
        self.lineTwoTransitTextNodePath = NodePath(self.lineTwoTransitTextNode)
        self.lineTwoTransitTextNodePath.setPos(-0.40000000000000002, 0.0,
                                               -0.94999999999999996)
        self.lineTwoTransitTextNodePath.setScale(0.12, 0.12, 0.12)
        self.lineTwoTransitTextNodePath.reparentTo(self.uiBaseNode)
        self.lineTwoTransitTextNodePath.hide()
        self.UICompoments[
            'lineTwoTransitText'] = self.lineTwoTransitTextNodePath
        base.loadingScreen.tick()
        self.test_guiImage = loader.loadModel('models/gui/toplevel_gui')
        self.buttonIcon = (
            self.test_guiImage.find('**/treasure_chest_closed'),
            self.test_guiImage.find('**/treasure_chest_closed'),
            self.test_guiImage.find('**/treasure_chest_closed_over'))
        self.winImagePanel = GuiPanel.GuiPanel('', 2.6000000000000001,
                                               1.8999999999999999, True)
        self.winImagePanel.setPos(-1.3, 0.0, -0.94999999999999996)
        self.winImagePanel.reparentTo(self.uiBaseNode)
        self.winImagePanel.background = OnscreenImage(
            parent=self.winImagePanel,
            scale=(2.3999999999999999, 0, 1.8),
            image=self.guiImage.find('**/pir_t_gui_fsh_posterBackground'),
            hpr=(0, 0, 0),
            pos=(1.3, 0, 0.94999999999999996))
        self.winImagePanel.setBin('gui-popup', -4)
        self.winTitleTextNode = TextNode('winTitleTextNode')
        self.winTitleTextNode.setText('Congratulations!')
        self.winTitleTextNode.setAlign(TextNode.ACenter)
        self.winTitleTextNode.setFont(PiratesGlobals.getPirateFont())
        self.winTitleTextNode.setTextColor(0.23000000000000001,
                                           0.089999999999999997,
                                           0.029999999999999999, 1.0)
        self.winTitleTextNodePath = NodePath(self.winTitleTextNode)
        self.winTitleTextNodePath.setPos(1.3500000000000001, 0.0,
                                         1.6699999999999999)
        self.winTitleTextNodePath.setScale(0.17999999999999999)
        self.winTitleTextNodePath.reparentTo(self.winImagePanel)
        self.wholeStoryTextNode = TextNode('storyTextNode')
        self.wholeStoryTextNode.setText('')
        self.wholeStoryTextNode.setWordwrap(19.0)
        self.wholeStoryTextNode.setTextColor(0.23000000000000001,
                                             0.089999999999999997,
                                             0.029999999999999999, 1.0)
        self.wholeStoryTextNodePath = NodePath(self.wholeStoryTextNode)
        self.wholeStoryTextNodePath.setPos(0.33000000000000002, 0.0,
                                           1.6399999999999999)
        self.wholeStoryTextNodePath.setScale(0.050000000000000003)
        self.wholeStoryTextNodePath.reparentTo(self.winImagePanel)
        self.winImagePanel.closeButton[
            'command'] = self.closeDialogGotNextState
        self.winImagePanel.closeButton['extraArgs'] = [
            'winImagePanel', 'FarewellLegendaryFish', False
        ]
        self.UICompoments['winImagePanel'] = self.winImagePanel
        self.winImagePanel.hide()
        self.luiCloseDialogSequence = Sequence()
        self.arrowImageRotationInterval = LerpHprInterval(
            self.arrowImage, 2.2000000000000002,
            self.arrowImage.getHpr() + Point3(0.0, 0.0, 280.0),
            self.arrowImage.getHpr())
        self.luiArrowRotatingSequence = Sequence(
            Func(self.showGui, ['arrowImage']),
            Parallel(Func(self.arrowImageRotationInterval.start),
                     Wait(2.2000000000000002)),
            Func(self.hideGui, ['arrowImage']),
            Func(self.arrowImage.setHpr,
                 self.arrowImage.getHpr() + Point3(0.0, 0.0, 5.0)),
            name=self.gameObject.distributedFishingSpot.uniqueName(
                'luiArrowRotatingSequence'))
        self.lineOneColorChange = LerpColorScaleInterval(
            self.lineOneTransitTextNodePath,
            FishingGlobals.legendaryTransitionTextDuration,
            (1.0, 1.0, 1.0, 0.0), (1.0, 1.0, 1.0, 1.0),
            blendType='easeOut')
        self.lineOnePosChange = LerpPosInterval(
            self.lineOneTransitTextNodePath,
            FishingGlobals.legendaryTransitionTextDuration,
            (0.0, 0.0, -0.20000000000000001), (0.0, 0.0, -0.80000000000000004),
            blendType='easeOut')
        self.lineTwoCholorChange = LerpColorScaleInterval(
            self.lineTwoTransitTextNodePath,
            FishingGlobals.legendaryTransitionTextDuration,
            (1.0, 1.0, 1.0, 1.0), (1.0, 1.0, 1.0, 1.0),
            blendType='easeOut')
        self.lineTwoPosChange = LerpPosInterval(
            self.lineTwoTransitTextNodePath,
            FishingGlobals.legendaryTransitionTextDuration,
            (0.0, 0.0, -0.32000000000000001), (0.0, 0.0, -0.94999999999999996),
            blendType='easeOut')
        self.transitionTextMovingSequence = Sequence(
            Func(self.lineOneTransitTextNodePath.show),
            Func(self.lineTwoTransitTextNodePath.show),
            Parallel(self.lineOnePosChange, self.lineTwoPosChange,
                     self.lineOneColorChange, self.lineTwoCholorChange),
            Func(self.lineOneTransitTextNodePath.hide),
            Func(self.lineTwoTransitTextNodePath.hide),
            name=self.gameObject.distributedFishingSpot.uniqueName(
                'transitionTextMovingSequence'))
        self.meterFadeInInterval = Sequence(
            Func(self.meterFrame.show),
            LerpColorScaleInterval(
                self.meterFrame,
                FishingGlobals.legendaryTransitionTextDuration,
                colorScale=(1.0, 1.0, 1.0, 1.0),
                startColorScale=(1.0, 1.0, 1.0, 0.0),
                blendType='easeOut'),
            name='FadeInLegendaryMeter')
        self.meterFadeOutInterval = Sequence(LerpColorScaleInterval(
            self.meterFrame,
            FishingGlobals.legendaryTransitionTextDuration,
            colorScale=(1.0, 1.0, 1.0, 0.0),
            startColorScale=(1.0, 1.0, 1.0, 1.0),
            blendType='easeOut'),
                                             Func(self.meterFrame.hide),
                                             name='FadeOutLegendaryMeter')
        self.rodFadeInInterval = Sequence(
            Func(self.fishingHandleBaseFrame.show),
            LerpColorScaleInterval(
                self.fishingHandleBaseFrame,
                FishingGlobals.legendaryTransitionTextDuration,
                colorScale=(1.0, 1.0, 1.0, 1.0),
                startColorScale=(1.0, 1.0, 1.0, 0.0),
                blendType='easeOut'),
            name='FadeInLegendaryRodInterface')
        self.rodFadeOutInterval = Sequence(
            LerpColorScaleInterval(
                self.fishingHandleBaseFrame,
                FishingGlobals.legendaryTransitionTextDuration,
                colorScale=(1.0, 1.0, 1.0, 0.0),
                startColorScale=(1.0, 1.0, 1.0, 1.0),
                blendType='easeOut'),
            Func(self.fishingHandleBaseFrame.hide),
            name='FadeOutLegendaryRodInterface')
        base.loadingScreen.tick()
        smallScale = self.fishingHandleButton['scale']
        bigScale = self.fishingHandleButton['scale'] * 1.2
        self.buttonGrowUpInterval = LerpScaleInterval(self.fishingHandleButton,
                                                      1.0, bigScale,
                                                      smallScale)
        self.luiFightTransitSequence = Sequence(
            Parallel(Func(self.fishingHandleBaseFrame.show),
                     Func(self.meterFadeOutInterval.start),
                     Func(self.rodFadeInInterval.start),
                     Func(self.buttonGrowUpInterval.start)),
            Wait(1.0),
            Func(self.meterFrame.hide),
            name=self.gameObject.distributedFishingSpot.uniqueName(
                'luiFightTransitSequence'))
        self.luiReelTransitSequence = Sequence(
            Parallel(Func(self.fishingHandleBaseFrame.show),
                     Func(self.meterFadeOutInterval.start),
                     Func(self.rodFadeInInterval.start)),
            Wait(1.0),
            Func(self.meterFrame.hide),
            name=self.gameObject.distributedFishingSpot.uniqueName(
                'luiReelTransitSequence'))
        self.luiStruggleTransitSequence = Sequence(
            Parallel(Func(self.meterFrame.show), Func(self.resetFishingRod),
                     self.meterFadeInInterval, self.rodFadeOutInterval),
            Wait(1.0),
            Func(self.fishingHandleBaseFrame.hide),
            name=self.gameObject.distributedFishingSpot.uniqueName(
                'luiStruggleTransitSequence'))
        self.meterFadeOutInterval.start()
        self.rodFadeOutInterval.start()
        self.hideAllGUI()
        base.loadingScreen.endStep('LegendaryGameGUI')

    def hideAllGUI(self):
        self.uiBaseNode.reparentTo(hidden)
        self.leftBaseNode.reparentTo(hidden)

    def showAllGUI(self):
        self.uiBaseNode.reparentTo(aspect2d)
        self.leftBaseNode.reparentTo(base.a2dLeftCenter)

    def hideGui(self, nameList):
        for ui in nameList:
            self.UICompoments[ui].hide()

    def showGui(self, nameList):
        for ui in nameList:
            self.UICompoments[ui].show()

    def destroy(self):
        self.arrowImageRotationInterval.pause()
        self.arrowImageRotationInterval.clearToInitial()
        self.luiArrowRotatingSequence.pause()
        self.luiArrowRotatingSequence.clearToInitial()
        self.luiCloseDialogSequence.pause()
        self.luiCloseDialogSequence.clearToInitial()
        totalKey = self.UICompoments.keys()
        for iKey in totalKey:
            del self.UICompoments[iKey]

        self.fishingHandle = None
        self.fishingHandleButton = None
        self.fishingRod.removeNode()
        self.leftBaseNode.removeNode()
        self.uiBaseNode.removeNode()
        if self.fishActor:
            self.fishActor.destroy()
            self.fishActor = None

    def handleButtonClicked(self, mouseKey):
        if self.gameObject.lfgFsm.getCurrentOrNextState() in ['CatchIt']:
            self.gameObject.lfgFsm.request('Transition', 'Struggle')
            self.gameObject.sfx['legendaryGreen'].play()

    def setTransitionText(self, state):
        self.lineOneTransitTextNode.setText(
            PLocalizer.LegendaryFishingGui[state][0])
        self.lineTwoTransitTextNode.setText(
            PLocalizer.LegendaryFishingGui[state][1])

    def resetInterval(self):
        self.transitionTextMovingSequence.pause()
        self.transitionTextMovingSequence.clearToInitial()
        self.lineOneColorChange.pause()
        self.lineOneColorChange.clearToInitial()
        self.lineOnePosChange.pause()
        self.lineOnePosChange.clearToInitial()
        self.lineTwoCholorChange.pause()
        self.lineTwoCholorChange.clearToInitial()
        self.lineTwoPosChange.pause()
        self.lineTwoPosChange.clearToInitial()
        self.luiReelTransitSequence.pause()
        self.luiReelTransitSequence.clearToInitial()
        self.luiStruggleTransitSequence.pause()
        self.luiStruggleTransitSequence.clearToInitial()
        self.luiFightTransitSequence.pause()
        self.luiFightTransitSequence.clearToInitial()
        self.buttonGrowUpInterval.pause()
        self.buttonGrowUpInterval.clearToInitial()
        self.meterFadeOutInterval.pause()
        self.meterFadeOutInterval.clearToInitial()
        self.rodFadeInInterval.pause()
        self.rodFadeInInterval.clearToInitial()
        self.meterFadeInInterval.pause()
        self.meterFadeInInterval.clearToInitial()
        self.rodFadeOutInterval.pause()
        self.rodFadeOutInterval.clearToInitial()

    def fightingTransit(self):
        self.luiFightTransitSequence.start()

    def reelTransit(self):
        self.luiReelTransitSequence.start()

    def struggleTransit(self):
        self.luiStruggleTransitSequence.start()

    def resetFishingRod(self):
        self.fishingRod.setR(FishingGlobals.fishingRodInitSlope)

    def showWinImage(self, fish):
        self.hideGui(['meterFrame', 'fishingHandleBaseFrame'])
        result = fish.myData['name'].split(' ')
        fileName = str(result[0]).capitalize()
        imgName = 'pir_t_gui_fsh_render%s' % fileName
        self.actorAnim[
            'swimIdleOpposite'] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (
                fish.myData['model'], 'swimIdleOpposite')
        self.fishActor = BlendActor(
            'models/char/pir_r_gam_fsh_%s.bam' % fish.myData['model'],
            self.actorAnim, FishingGlobals.defaultFishBlendTime,
            FishingGlobals.fishBlendTimeDict)
        self.fishActor.setPlayRate(
            fish.myData['speed'] * fish.myData['swimAnimationMultiplier'],
            'swimIdleOpposite')
        self.fishActor.changeAnimationTo('swimIdleOpposite')
        self.fishActor.reparentTo(self.winImagePanel)
        self.fishActor.setScale(self.scaleSize[fish.myData['id']])
        self.fishActor.setPos(1.7, 0, 1.0)
        self.fishActor.setHpr(0, 0, 35)
        self.fishActor.setDepthWrite(True)
        self.fishActor.setDepthTest(True)
        self.wholeStoryTextNode.setText(
            PLocalizer.LegendSelectionGui['wholeStory'][fish.myData['id']])
        self.winImagePanel.show()

    def closeDialogGotNextState(self, object, targetState, ifFadeInAgain):
        if self.fishActor:
            self.fishActor.destroy()
            self.fishActor = None

        self.luiCloseDialogSequence = Sequence(
            Func(self.gameObject.distributedFishingSpot.fadeOut),
            Wait(0.40000000000000002),
            Func(self.UICompoments[object].hide),
            Func(self.gameObject.lfgFsm.request, targetState),
            name=self.gameObject.distributedFishingSpot.uniqueName(
                'luiCloseDialogSequence'))
        self.luiCloseDialogSequence.start()

    def updateStruggleTimerText(self, time, percent):
        self.meterFrame['text'] = str(time)
        self.meterFrame['text_fg'] = (1.0 - percent, percent, 0.0, 1.0)
class LegendaryFishingGameGUI:
    
    def __init__(self, gameObject = None):
        base.loadingScreen.beginStep('LegendaryGameGUI', 4, 20)
        self.gameObject = gameObject
        self.guiImage = loader.loadModel('models/minigames/pir_m_gam_fsh_legendaryGui')
        self.UICompoments = { }
        self.uiBaseNode = NodePath('baseNode')
        self.uiBaseNode.reparentTo(aspect2d)
        self.uiBaseNode.show()
        self.leftBaseNode = NodePath('leftBaseNode')
        self.leftBaseNode.reparentTo(base.a2dLeftCenter)
        self.leftBaseNode.show()
        self.fishActor = None
        self.actorAnim = { }
        self.scaleSize = {
            InventoryType.Collection_Set11_Part1: 0.059999999999999998,
            InventoryType.Collection_Set11_Part2: 0.055,
            InventoryType.Collection_Set11_Part3: 0.12,
            InventoryType.Collection_Set11_Part4: 0.086999999999999994,
            InventoryType.Collection_Set11_Part5: 0.080000000000000002 }
        self.meterFrame = DirectFrame(parent = self.leftBaseNode, frameSize = (-0.29999999999999999, 0.29999999999999999, -1.0, 0.0), frameColor = (1.0, 1.0, 1.0, 0.0), relief = None, state = DGG.DISABLED, pos = (1.0, 0.0, -0.45000000000000001), hpr = (0, 0, 0), scale = (1.3, 0.0, 1.3), image = self.guiImage.find('**/pir_t_gui_fsh_meter'), image_scale = (0.20000000000000001, 0.0, 0.80000000000000004), image_pos = (0, 0, 0), text = '', textMayChange = 1, text_scale = PiratesGuiGlobals.TextScaleTitleLarge, text_pos = (-0.55000000000000004, 0.10000000000000001), text_shadow = PiratesGuiGlobals.TextShadow)
        self.UICompoments['meterFrame'] = self.meterFrame
        self.fishingRod = DirectFrame(parent = self.meterFrame, frameSize = (-0.29999999999999999, 0.29999999999999999, -1.0, 0.0), relief = None, state = DGG.DISABLED, pos = FishingGlobals.fishingRodScreenPosition, image = self.guiImage.find('**/pir_t_gui_fsh_fullRod'), image_scale = (1.0, 0.0, 0.125), image_pos = (0.20000000000000001, 0, 0))
        self.fishingRod.setR(FishingGlobals.fishingRodInitSlope)
        self.UICompoments['fishingRod'] = self.fishingRod
        base.loadingScreen.tick()
        self.fishingHandleBaseFrame = DirectFrame(parent = self.uiBaseNode, frameSize = (-0.29999999999999999, 0.29999999999999999, -1.5, 1.5), frameColor = (1.0, 1.0, 1.0, 0.0), relief = None, state = DGG.DISABLED, pos = (0.0, 0.0, 0.0), hpr = (0, 0, 0), scale = (0.71999999999999997, 0.0, 0.71999999999999997), image = self.guiImage.find('**/pir_t_gui_fsh_partialRod'), image_scale = (3.7999999999999998, 0.0, 1.8999999999999999), image_pos = (0, 0, 0), image_hpr = (0.0, 0.0, 0))
        self.fishingHandleBaseFrame.hide()
        self.UICompoments['fishingHandleBaseFrame'] = self.fishingHandleBaseFrame
        self.fishingHandle = DirectFrame(parent = self.fishingHandleBaseFrame, frameSize = (-0.080000000000000002, 0.080000000000000002, -0.20000000000000001, 0.20000000000000001), relief = None, state = DGG.DISABLED, pos = (-0.10000000000000001, 0.0, -0.050000000000000003), hpr = (0, 0, 0), image = self.guiImage.find('**/pir_t_gui_fsh_handleArm'), image_scale = (1.0, 0.0, 1.0), image_pos = (-0.042000000000000003, 0, -0.115), image_hpr = (0.0, 0.0, 0))
        self.UICompoments['fishingHandle'] = self.fishingHandle
        self.arrowImage = DirectFrame(parent = self.fishingHandleBaseFrame, frameSize = (-0.40000000000000002, 0.40000000000000002, -0.40000000000000002, 0.40000000000000002), relief = None, state = DGG.DISABLED, pos = (0.0, 0.0, 0.0), hpr = (0, 0, 0), scale = (1.2, 0.0, 1.2), image = self.guiImage.find('**/pir_t_gui_fsh_arrow'), image_scale = (1.0, 0.0, 1.0), image_pos = (0.0, 0, 0.0), image_hpr = (0.0, 0.0, 0.0))
        self.arrowImage.hide()
        self.UICompoments['arrowImage'] = self.arrowImage
        btnGeom = (self.guiImage.find('**/pir_t_gui_fsh_handle'), self.guiImage.find('**/pir_t_gui_fsh_handle'), self.guiImage.find('**/pir_t_gui_fsh_handleOn'))
        self.fishingHandleButton = GuiButton(pos = (-0.29999999999999999, 0, -0.55000000000000004), hpr = (0, 0, 0), scale = 0.45000000000000001, image = btnGeom, image_pos = (0, 0, 0), image_scale = 1.0, sortOrder = 2)
        self.fishingHandleButton.bind(DGG.B1PRESS, self.handleButtonClicked)
        self.fishingHandleButton.reparentTo(self.fishingHandle)
        self.UICompoments['fishingHandleButton'] = self.fishingHandleButton
        self.fishingHandleBaseFrame.setTransparency(TransparencyAttrib.MAlpha)
        self.meterFrame.setTransparency(TransparencyAttrib.MAlpha)
        self.lineOneTransitTextNode = TextNode('lineOneTransitText')
        self.lineOneTransitTextNode.setFont(PiratesGlobals.getPirateFont())
        self.lineOneTransitTextNode.setText('')
        self.lineOneTransitTextNode.setAlign(TextNode.ACenter)
        self.lineOneTransitTextNode.setTextColor(1.0, 1.0, 1.0, 0.5)
        self.lineOneTransitTextNodePath = NodePath(self.lineOneTransitTextNode)
        self.lineOneTransitTextNodePath.setPos(0.0, 0.0, -0.80000000000000004)
        self.lineOneTransitTextNodePath.setScale(0.34999999999999998, 0.34999999999999998, 0.34999999999999998)
        self.lineOneTransitTextNodePath.reparentTo(self.uiBaseNode)
        self.lineOneTransitTextNodePath.hide()
        self.UICompoments['lineOneTransitText'] = self.lineOneTransitTextNodePath
        self.lineTwoTransitTextNode = TextNode('lineTwoTransitText')
        self.lineTwoTransitTextNode.setFont(PiratesGlobals.getPirateFont())
        self.lineTwoTransitTextNode.setText('')
        self.lineTwoTransitTextNode.setAlign(TextNode.ACenter)
        self.lineTwoTransitTextNode.setTextColor(1.0, 1.0, 1.0, 0.5)
        self.lineTwoTransitTextNodePath = NodePath(self.lineTwoTransitTextNode)
        self.lineTwoTransitTextNodePath.setPos(-0.40000000000000002, 0.0, -0.94999999999999996)
        self.lineTwoTransitTextNodePath.setScale(0.12, 0.12, 0.12)
        self.lineTwoTransitTextNodePath.reparentTo(self.uiBaseNode)
        self.lineTwoTransitTextNodePath.hide()
        self.UICompoments['lineTwoTransitText'] = self.lineTwoTransitTextNodePath
        base.loadingScreen.tick()
        self.test_guiImage = loader.loadModel('models/gui/toplevel_gui')
        self.buttonIcon = (self.test_guiImage.find('**/treasure_chest_closed'), self.test_guiImage.find('**/treasure_chest_closed'), self.test_guiImage.find('**/treasure_chest_closed_over'))
        self.winImagePanel = GuiPanel.GuiPanel('', 2.6000000000000001, 1.8999999999999999, True)
        self.winImagePanel.setPos(-1.3, 0.0, -0.94999999999999996)
        self.winImagePanel.reparentTo(self.uiBaseNode)
        self.winImagePanel.background = OnscreenImage(parent = self.winImagePanel, scale = (2.3999999999999999, 0, 1.8), image = self.guiImage.find('**/pir_t_gui_fsh_posterBackground'), hpr = (0, 0, 0), pos = (1.3, 0, 0.94999999999999996))
        self.winImagePanel.setBin('gui-popup', -4)
        self.winTitleTextNode = TextNode('winTitleTextNode')
        self.winTitleTextNode.setText('Congratulations!')
        self.winTitleTextNode.setAlign(TextNode.ACenter)
        self.winTitleTextNode.setFont(PiratesGlobals.getPirateFont())
        self.winTitleTextNode.setTextColor(0.23000000000000001, 0.089999999999999997, 0.029999999999999999, 1.0)
        self.winTitleTextNodePath = NodePath(self.winTitleTextNode)
        self.winTitleTextNodePath.setPos(1.3500000000000001, 0.0, 1.6699999999999999)
        self.winTitleTextNodePath.setScale(0.17999999999999999)
        self.winTitleTextNodePath.reparentTo(self.winImagePanel)
        self.wholeStoryTextNode = TextNode('storyTextNode')
        self.wholeStoryTextNode.setText('')
        self.wholeStoryTextNode.setWordwrap(19.0)
        self.wholeStoryTextNode.setTextColor(0.23000000000000001, 0.089999999999999997, 0.029999999999999999, 1.0)
        self.wholeStoryTextNodePath = NodePath(self.wholeStoryTextNode)
        self.wholeStoryTextNodePath.setPos(0.33000000000000002, 0.0, 1.6399999999999999)
        self.wholeStoryTextNodePath.setScale(0.050000000000000003)
        self.wholeStoryTextNodePath.reparentTo(self.winImagePanel)
        self.winImagePanel.closeButton['command'] = self.closeDialogGotNextState
        self.winImagePanel.closeButton['extraArgs'] = [
            'winImagePanel',
            'FarewellLegendaryFish',
            False]
        self.UICompoments['winImagePanel'] = self.winImagePanel
        self.winImagePanel.hide()
        self.luiCloseDialogSequence = Sequence()
        self.arrowImageRotationInterval = LerpHprInterval(self.arrowImage, 2.2000000000000002, self.arrowImage.getHpr() + Point3(0.0, 0.0, 280.0), self.arrowImage.getHpr())
        self.luiArrowRotatingSequence = Sequence(Func(self.showGui, [
            'arrowImage']), Parallel(Func(self.arrowImageRotationInterval.start), Wait(2.2000000000000002)), Func(self.hideGui, [
            'arrowImage']), Func(self.arrowImage.setHpr, self.arrowImage.getHpr() + Point3(0.0, 0.0, 5.0)), name = self.gameObject.distributedFishingSpot.uniqueName('luiArrowRotatingSequence'))
        self.lineOneColorChange = LerpColorScaleInterval(self.lineOneTransitTextNodePath, FishingGlobals.legendaryTransitionTextDuration, (1.0, 1.0, 1.0, 0.0), (1.0, 1.0, 1.0, 1.0), blendType = 'easeOut')
        self.lineOnePosChange = LerpPosInterval(self.lineOneTransitTextNodePath, FishingGlobals.legendaryTransitionTextDuration, (0.0, 0.0, -0.20000000000000001), (0.0, 0.0, -0.80000000000000004), blendType = 'easeOut')
        self.lineTwoCholorChange = LerpColorScaleInterval(self.lineTwoTransitTextNodePath, FishingGlobals.legendaryTransitionTextDuration, (1.0, 1.0, 1.0, 1.0), (1.0, 1.0, 1.0, 1.0), blendType = 'easeOut')
        self.lineTwoPosChange = LerpPosInterval(self.lineTwoTransitTextNodePath, FishingGlobals.legendaryTransitionTextDuration, (0.0, 0.0, -0.32000000000000001), (0.0, 0.0, -0.94999999999999996), blendType = 'easeOut')
        self.transitionTextMovingSequence = Sequence(Func(self.lineOneTransitTextNodePath.show), Func(self.lineTwoTransitTextNodePath.show), Parallel(self.lineOnePosChange, self.lineTwoPosChange, self.lineOneColorChange, self.lineTwoCholorChange), Func(self.lineOneTransitTextNodePath.hide), Func(self.lineTwoTransitTextNodePath.hide), name = self.gameObject.distributedFishingSpot.uniqueName('transitionTextMovingSequence'))
        self.meterFadeInInterval = Sequence(Func(self.meterFrame.show), LerpColorScaleInterval(self.meterFrame, FishingGlobals.legendaryTransitionTextDuration, colorScale = (1.0, 1.0, 1.0, 1.0), startColorScale = (1.0, 1.0, 1.0, 0.0), blendType = 'easeOut'), name = 'FadeInLegendaryMeter')
        self.meterFadeOutInterval = Sequence(LerpColorScaleInterval(self.meterFrame, FishingGlobals.legendaryTransitionTextDuration, colorScale = (1.0, 1.0, 1.0, 0.0), startColorScale = (1.0, 1.0, 1.0, 1.0), blendType = 'easeOut'), Func(self.meterFrame.hide), name = 'FadeOutLegendaryMeter')
        self.rodFadeInInterval = Sequence(Func(self.fishingHandleBaseFrame.show), LerpColorScaleInterval(self.fishingHandleBaseFrame, FishingGlobals.legendaryTransitionTextDuration, colorScale = (1.0, 1.0, 1.0, 1.0), startColorScale = (1.0, 1.0, 1.0, 0.0), blendType = 'easeOut'), name = 'FadeInLegendaryRodInterface')
        self.rodFadeOutInterval = Sequence(LerpColorScaleInterval(self.fishingHandleBaseFrame, FishingGlobals.legendaryTransitionTextDuration, colorScale = (1.0, 1.0, 1.0, 0.0), startColorScale = (1.0, 1.0, 1.0, 1.0), blendType = 'easeOut'), Func(self.fishingHandleBaseFrame.hide), name = 'FadeOutLegendaryRodInterface')
        base.loadingScreen.tick()
        smallScale = self.fishingHandleButton['scale']
        bigScale = self.fishingHandleButton['scale'] * 1.2
        self.buttonGrowUpInterval = LerpScaleInterval(self.fishingHandleButton, 1.0, bigScale, smallScale)
        self.luiFightTransitSequence = Sequence(Parallel(Func(self.fishingHandleBaseFrame.show), Func(self.meterFadeOutInterval.start), Func(self.rodFadeInInterval.start), Func(self.buttonGrowUpInterval.start)), Wait(1.0), Func(self.meterFrame.hide), name = self.gameObject.distributedFishingSpot.uniqueName('luiFightTransitSequence'))
        self.luiReelTransitSequence = Sequence(Parallel(Func(self.fishingHandleBaseFrame.show), Func(self.meterFadeOutInterval.start), Func(self.rodFadeInInterval.start)), Wait(1.0), Func(self.meterFrame.hide), name = self.gameObject.distributedFishingSpot.uniqueName('luiReelTransitSequence'))
        self.luiStruggleTransitSequence = Sequence(Parallel(Func(self.meterFrame.show), Func(self.resetFishingRod), self.meterFadeInInterval, self.rodFadeOutInterval), Wait(1.0), Func(self.fishingHandleBaseFrame.hide), name = self.gameObject.distributedFishingSpot.uniqueName('luiStruggleTransitSequence'))
        self.meterFadeOutInterval.start()
        self.rodFadeOutInterval.start()
        self.hideAllGUI()
        base.loadingScreen.endStep('LegendaryGameGUI')

    
    def hideAllGUI(self):
        self.uiBaseNode.reparentTo(hidden)
        self.leftBaseNode.reparentTo(hidden)

    
    def showAllGUI(self):
        self.uiBaseNode.reparentTo(aspect2d)
        self.leftBaseNode.reparentTo(base.a2dLeftCenter)

    
    def hideGui(self, nameList):
        for ui in nameList:
            self.UICompoments[ui].hide()
        

    
    def showGui(self, nameList):
        for ui in nameList:
            self.UICompoments[ui].show()
        

    
    def destroy(self):
        self.arrowImageRotationInterval.pause()
        self.arrowImageRotationInterval.clearToInitial()
        self.luiArrowRotatingSequence.pause()
        self.luiArrowRotatingSequence.clearToInitial()
        self.luiCloseDialogSequence.pause()
        self.luiCloseDialogSequence.clearToInitial()
        totalKey = self.UICompoments.keys()
        for iKey in totalKey:
            del self.UICompoments[iKey]
        
        self.fishingHandle = None
        self.fishingHandleButton = None
        self.fishingRod.removeNode()
        self.leftBaseNode.removeNode()
        self.uiBaseNode.removeNode()
        if self.fishActor:
            self.fishActor.destroy()
            self.fishActor = None
        

    
    def handleButtonClicked(self, mouseKey):
        if self.gameObject.lfgFsm.getCurrentOrNextState() in [
            'CatchIt']:
            self.gameObject.lfgFsm.request('Transition', 'Struggle')
            self.gameObject.sfx['legendaryGreen'].play()
        

    
    def setTransitionText(self, state):
        self.lineOneTransitTextNode.setText(PLocalizer.LegendaryFishingGui[state][0])
        self.lineTwoTransitTextNode.setText(PLocalizer.LegendaryFishingGui[state][1])

    
    def resetInterval(self):
        self.transitionTextMovingSequence.pause()
        self.transitionTextMovingSequence.clearToInitial()
        self.lineOneColorChange.pause()
        self.lineOneColorChange.clearToInitial()
        self.lineOnePosChange.pause()
        self.lineOnePosChange.clearToInitial()
        self.lineTwoCholorChange.pause()
        self.lineTwoCholorChange.clearToInitial()
        self.lineTwoPosChange.pause()
        self.lineTwoPosChange.clearToInitial()
        self.luiReelTransitSequence.pause()
        self.luiReelTransitSequence.clearToInitial()
        self.luiStruggleTransitSequence.pause()
        self.luiStruggleTransitSequence.clearToInitial()
        self.luiFightTransitSequence.pause()
        self.luiFightTransitSequence.clearToInitial()
        self.buttonGrowUpInterval.pause()
        self.buttonGrowUpInterval.clearToInitial()
        self.meterFadeOutInterval.pause()
        self.meterFadeOutInterval.clearToInitial()
        self.rodFadeInInterval.pause()
        self.rodFadeInInterval.clearToInitial()
        self.meterFadeInInterval.pause()
        self.meterFadeInInterval.clearToInitial()
        self.rodFadeOutInterval.pause()
        self.rodFadeOutInterval.clearToInitial()

    
    def fightingTransit(self):
        self.luiFightTransitSequence.start()

    
    def reelTransit(self):
        self.luiReelTransitSequence.start()

    
    def struggleTransit(self):
        self.luiStruggleTransitSequence.start()

    
    def resetFishingRod(self):
        self.fishingRod.setR(FishingGlobals.fishingRodInitSlope)

    
    def showWinImage(self, fish):
        self.hideGui([
            'meterFrame',
            'fishingHandleBaseFrame'])
        result = fish.myData['name'].split(' ')
        fileName = str(result[0]).capitalize()
        imgName = 'pir_t_gui_fsh_render%s' % fileName
        self.actorAnim['swimIdleOpposite'] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (fish.myData['model'], 'swimIdleOpposite')
        self.fishActor = BlendActor('models/char/pir_r_gam_fsh_%s.bam' % fish.myData['model'], self.actorAnim, FishingGlobals.defaultFishBlendTime, FishingGlobals.fishBlendTimeDict)
        self.fishActor.setPlayRate(fish.myData['speed'] * fish.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
        self.fishActor.changeAnimationTo('swimIdleOpposite')
        self.fishActor.reparentTo(self.winImagePanel)
        self.fishActor.setScale(self.scaleSize[fish.myData['id']])
        self.fishActor.setPos(1.7, 0, 1.0)
        self.fishActor.setHpr(0, 0, 35)
        self.fishActor.setDepthWrite(True)
        self.fishActor.setDepthTest(True)
        self.wholeStoryTextNode.setText(PLocalizer.LegendSelectionGui['wholeStory'][fish.myData['id']])
        self.winImagePanel.show()

    
    def closeDialogGotNextState(self, object, targetState, ifFadeInAgain):
        if self.fishActor:
            self.fishActor.destroy()
            self.fishActor = None
        
        self.luiCloseDialogSequence = Sequence(Func(self.gameObject.distributedFishingSpot.fadeOut), Wait(0.40000000000000002), Func(self.UICompoments[object].hide), Func(self.gameObject.lfgFsm.request, targetState), name = self.gameObject.distributedFishingSpot.uniqueName('luiCloseDialogSequence'))
        self.luiCloseDialogSequence.start()

    
    def updateStruggleTimerText(self, time, percent):
        self.meterFrame['text'] = str(time)
        self.meterFrame['text_fg'] = (1.0 - percent, percent, 0.0, 1.0)
Example #7
0
class Fish(NodePath):

    def __init__(self, fishManager, myData, index, trophy=0):
        NodePath.__init__(self, '%s_%d' % (myData['name'], index))
        self.trophy = trophy
        self.myData = myData
        if not self.trophy:
            self.fishManager = fishManager
            self.index = index
            self.fsm = FishFSM(self)
            self.weight = random.randint(self.myData['weightRange'][0], self.myData['weightRange'][1])
        else:
            self.weight = trophy
        self.adjustedScale = (self.myData['scaleRange'][1] - self.myData['scaleRange'][0]) * (self.weight - self.myData['weightRange'][0]) / (self.myData['weightRange'][1] - self.myData['weightRange'][0]) + self.myData['scaleRange'][0]
        self.initActor()
        if not self.trophy:
            self.initVariables()
            self.initFishStatusIcon()
            if FishingGlobals.wantDebugCollisionVisuals:
                self.initCollisions()
        self.avoidingFish = False
        self.biteBubbleEffect = None
        self.idleBubbleEffect = None
        self.fightBubbleEffect = None
        self.behaviorNameToFunction = {'straight': self.performStraightBehavior,'sineStraight': self.performSineStraightBehavior,'erratic': self.performErraticBehavior}
        self.sineDtAccumulator = 0.0
        self.erraticDtAccumulator = 0.0
        self.myZ = 0.0
        if not self.trophy:
            self.setLightOff()
        return

    def initActor(self):
        self.animDict = {}
        for anim in FishingGlobals.fishAnimations:
            self.animDict[anim] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (self.myData['model'], anim)

        self.actor = BlendActor('models/char/pir_r_gam_fsh_%s.bam' % self.myData['model'], self.animDict, FishingGlobals.defaultFishBlendTime, FishingGlobals.fishBlendTimeDict)
        self.actor.reparentTo(self)
        self.actor.setScale(self.adjustedScale)
        self.mouthJoint = self.actor.exposeJoint(None, 'modelRoot', 'hookAttach')
        self.attractionPoint = NodePath('AttractionPoint')
        self.attractionPoint.reparentTo(self.mouthJoint)
        self.attractionPoint.setPos(0.0, 0.0, 0.0)
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdle')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turn')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turnOpposite')
        if not self.trophy:
            self.setBin('fishingGame', 10)
        return

    def codeReload(self):
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdle')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turn')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turnOpposite')

    def initFishStatusIcon(self):
        self.fishStatusIconTextNode = TextNode('fishBitingIcon')
        self.fishStatusIconNodePath = NodePath(self.fishStatusIconTextNode)
        self.fishStatusIconNodePath.setPos(0.0, 0.0, self.myData['indicatorHeightOffset'])
        self.fishStatusIconTextNode.setText('?')
        self.fishStatusIconTextNode.setTextColor(1.0, 0.0, 0.0, 1.0)
        self.fishStatusIconNodePath.reparentTo(self.mouthJoint)
        self.fishStatusIconNodePath.setBillboardPointEye()
        self.fishStatusIconNodePath.hide()
        self.fishStatusIconNodePath.setShaderOff()

    def initVariables(self):
        self.attractionVisual = None
        self.collisionVisual = None
        self.movingRight = True
        self.turnSpeed = 160.0
        self.turnTowardLureInterval = None
        self.velocity = FishingGlobals.baseFishVelocity * self.myData['speed']
        self.accel = FishingGlobals.baseFishAccel * self.myData['speed']
        self.fishMoveSequence = None
        self.bubbleEffect = None
        return

    def initCollisions(self):
        self.collisionVisual = loader.loadModel('models/props/crate')
        self.collisionVisual.setTransparency(1)
        self.collisionVisual.setColor(1.0, 1.0, 1.0, 0.3)
        self.collisionVisual.setScale(*self.myData['collisionBoxSize'])
        self.collisionVisual.setPos(*self.myData['collisionBoxOffset'])
        self.collisionVisual.reparentTo(self)
        self.collisionVisual.hide()
        self.attractionVisual = loader.loadModel('models/ammunition/cannonball')
        self.attractionVisual.setTransparency(1)
        self.attractionVisual.setColor(0.0, 1.0, 0.0, 0.3)
        self.attractionVisual.setScale(self.myData['attractionRadius'])
        self.attractionVisual.reparentTo(self.attractionPoint)
        self.attractionVisual.hide()
        self.collisionVisualVisible = False

    def hide(self):
        NodePath.hide(self)
        if self.idleBubbleEffect:
            self.idleBubbleEffect.hide()

    def show(self):
        NodePath.show(self)
        if self.idleBubbleEffect:
            self.idleBubbleEffect.show()

    def reloadCollisions(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.collisionVisual.removeNode()
            self.attractionVisual.removeNode()
            self.initCollisions()

    def cleanFishData(self):
        pass

    def destroy(self):
        self.closeFish = []
        self.actor.destroy()
        self.stopIdleBubbleEffect()
        self.stopFightBubbleEffect()
        if self.fishMoveSequence:
            self.fishMoveSequence.pause()
            self.fishMoveSequence = None
        if self.fsm:
            del self.fsm
            self.fsm = None
        self.behaviorNameToFunction = {}
        self.removeNode()
        return

    def pickPositionAndSwim(self):
        self.initVariables()
        self.actor.clearControlEffectWeights()
        if self.myData['depth'] == 0:
            depth = random.uniform(FishingGlobals.fishingLevelBoundaries[self.myData['depth']], self.fishManager.gameObject.waterLevel + FishingGlobals.fishSpawnBelowWaterLevelHeight)
        else:
            depth = random.uniform(FishingGlobals.fishingLevelBoundaries[self.myData['depth']], FishingGlobals.fishingLevelBoundaries[self.myData['depth'] - 1])
        startX = random.uniform(FishingGlobals.leftFishBarrier + 5.0, FishingGlobals.rightFishBarrier - 5.0)
        self.setPos(startX, 0.0, depth)
        if random.randint(0, 1):
            self.fsm.request('TurnAround', 'Swimming', False)
        else:
            self.fsm.request('Swimming')

    def turnAround(self, nextState, shouldMoveRight):
        if self.velocity[0] < 0 and shouldMoveRight:
            self.velocity[0] = -self.velocity[0]
        elif self.velocity[0] > 0 and not shouldMoveRight:
            self.velocity[0] = -self.velocity[0]
        self.movingRight = self.velocity[0] > 0
        if self.fishMoveSequence:
            self.fishMoveSequence.pause()
            self.fishMoveSequence.clearToInitial()
        animationToTurn = 'turn'
        if self.movingRight:
            animationToTurn = 'turnOpposite'
        durationOfFishTurn = self.myData['durationOfFishTurn']
        self.fishMoveSequence = Parallel(Sequence(Func(self.actor.changeAnimationTo, animationToTurn, False), Wait(durationOfFishTurn), Func(self.fsm.request, nextState)), Sequence(Wait(durationOfFishTurn * 0.33), Func(self.setXVelocity, 0.0), Wait(durationOfFishTurn * 0.66), Func(self.setXVelocity, self.velocity[0])), name='%s_turnAroundInterval' % self.getName())
        self.velocity[0] = -self.velocity[0]
        self.fishMoveSequence.start()

    def setXVelocity(self, newVel):
        self.velocity[0] = newVel

    def checkForBiting(self):
        if self.fishManager.activeFish is not None:
            return
        if self.fishManager.gameObject.fsm.getCurrentOrNextState() not in ['Fishing', 'Reeling', 'LureStall', 'LegdFishShow']:
            return
        inv = localAvatar.getInventory()
        rodLvl = inv.getItemQuantity(InventoryType.FishingRod)
        if self.myData['depth'] + 1 > rodLvl:
            return
        self.fsm.request('Biting')
        return

    def checkForBoxOverlap(self, otherFish):
        pos = self.getPos(self.fishManager.gameObject.fishingSpot)
        size = self.myData['collisionBoxSize']
        offset = list(self.myData['collisionBoxOffset'])
        otherPos = otherFish.getPos()
        otherSize = otherFish.myData['collisionBoxSize']
        otherOffset = list(otherFish.myData['collisionBoxOffset'])
        if pos[0] + size[0] / 2.0 + offset[0] > otherPos[0] - otherSize[0] / 2.0 + otherOffset[0] and pos[0] - size[0] / 2.0 + offset[0] < otherPos[0] + otherSize[0] / 2.0 + otherOffset[0] and pos[2] + size[2] / 2.0 + offset[2] > otherPos[2] - otherSize[2] / 2.0 + otherOffset[2] and pos[2] - size[2] / 2.0 + offset[2] < otherPos[2] + otherSize[2] / 2.0 + otherOffset[2]:
            return True
        return False

    def checkForCloseFish(self, index):
        if index < len(self.fishManager.uncaughtFish) - 1:
            for i in range(index + 1, len(self.fishManager.uncaughtFish)):
                if self.fishManager.uncaughtFish[i].index != self.index:
                    if self.checkForBoxOverlap(self.fishManager.uncaughtFish[i]):
                        self.closeFish.append(self.fishManager.uncaughtFish[i])
                        if FishingGlobals.wantDebugCollisionVisuals:
                            self.collisionVisual.setColor(1, 0, 0, 0.3)

        if len(self.closeFish) == 0:
            if FishingGlobals.wantDebugCollisionVisuals:
                self.collisionVisual.setColor(1, 1, 1, 0.3)

    def checkForLures(self, currentState, lurePos):
        if self.getX() + FishingGlobals.fishAttractionOffset < lurePos[0] and self.movingRight or self.getX() - FishingGlobals.fishAttractionOffset > lurePos[0] and not self.movingRight:
            if self.attractionPoint.getDistance(self.fishManager.gameObject.lure) < self.myData['attractionRadius'] + self.fishManager.gameObject.lure.lureAttractRadius:
                self.checkForBiting()

    def update(self, dt, index, lurePos):
        currentState = self.fsm.getCurrentOrNextState()
        self.closeFish = []
        if currentState in ['ScareAway', 'Swimming', 'Flee', 'TurnAround']:
            self.checkForCloseFish(index)
            if currentState in ['Swimming']:
                self.checkForLures(currentState, lurePos)
            self.updateBasedOnBehavior(dt, lurePos)
        elif currentState in ['Hooked', 'AboutToFight', 'HookedFighting']:
            self.checkForCloseFish(-1)
            for fish in self.closeFish:
                self.makeFishRunFromMe(fish)

    def makeFishRunFromMe(self, otherFish):
        if otherFish.fsm.getCurrentOrNextState() == 'Flee' or otherFish.fsm.getCurrentOrNextState() == 'TurnAround':
            return
        if otherFish.getX() < self.getX(self.fishManager.gameObject.fishingSpot) and otherFish.movingRight:
            otherFish.fsm.request('TurnAround', 'Flee', False)
        elif otherFish.getX() > self.getX(self.fishManager.gameObject.fishingSpot) and not otherFish.movingRight:
            otherFish.fsm.request('TurnAround', 'Flee', True)
        else:
            otherFish.fsm.request('Flee')

    def updateBasedOnBehavior(self, dt, lurePos):
        currentState = self.fsm.getCurrentOrNextState()
        newX = self.getX()
        newY = self.getY()
        newZ = self.getZ()
        for fish in self.closeFish:
            if self.myData['size'] == 'small' and fish.myData['size'] == 'large':
                if self.checkForEating(fish):
                    return
            self.avoidingFish = True
            if fish.velocity[1] > 0.0 and fish.avoidingFish:
                self.velocity[1] = -FishingGlobals.fishAvoidYVelocity
            else:
                self.velocity[1] = FishingGlobals.fishAvoidYVelocity
            if abs(fish.getY() - self.getY()) > self.myData['collisionBoxSize'][1] + fish.myData['collisionBoxSize'][1]:
                self.velocity[1] = 0.0

        if len(self.closeFish) == 0 and abs(self.getY()) > FishingGlobals.fishYTolerance:
            self.avoidingFish = False
            if self.getY() > 0:
                self.velocity[1] = -FishingGlobals.fishAvoidYVelocity
            else:
                self.velocity[1] = FishingGlobals.fishAvoidYVelocity
        elif len(self.closeFish) == 0 and abs(self.getY()) < FishingGlobals.fishYTolerance:
            self.avoidingFish = False
            self.velocity[1] = 0.0
            self.setY(0.0)
        newY = self.getY() + self.velocity[1] * dt + self.accel[1] * dt * dt
        if currentState in ['Swimming', 'TurnAround', 'Flee', 'ScareAway']:
            if currentState == 'ScareAway':
                newX, newZ = self.performScareAwayBehavior(dt, self.velocity, self.accel)
            else:
                if currentState == 'Flee':
                    newX, newZ = self.performFleeBehavior(dt, self.velocity, self.accel)
                else:
                    newX, newZ = self.behaviorNameToFunction[self.myData['behaviorDict']['name']](dt, self.velocity, self.accel)
                currentState = self.fsm.getCurrentOrNextState()
                if newX < FishingGlobals.leftFishBarrier:
                    if currentState == 'ScareAway':
                        if newX < FishingGlobals.leftFishBarrier - FishingGlobals.fullyOffscreenXOffset:
                            self.fsm.request('Offscreen')
                            return
                    elif currentState != 'TurnAround' and not self.movingRight:
                        self.fsm.request('TurnAround', 'Swimming', True)
                elif newX > FishingGlobals.rightFishBarrier:
                    if currentState != 'TurnAround' and self.movingRight:
                        self.fsm.request('TurnAround', 'Swimming', False)
            newZ = min(max(FishingGlobals.fishingLevelBoundaries[len(FishingGlobals.fishingLevelBoundaries) - 1], newZ), self.fishManager.gameObject.waterLevel + FishingGlobals.fishSpawnBelowWaterLevelHeight)
        self.setPos(newX, newY, newZ)

    def checkForEating(self, fishThatWillEat):
        if (self.getX() < fishThatWillEat.getX() and not fishThatWillEat.movingRight or self.getX() > fishThatWillEat.getX() and fishThatWillEat.movingRight) and self.fsm.getCurrentOrNextState() == 'Swimming' and fishThatWillEat.fsm.getCurrentOrNextState() == 'Swimming' and random.random() < 1.0:
            self.fsm.request('BeingEaten', fishThatWillEat)
            fishThatWillEat.fsm.request('Eating', self.weight)
            return True
        return False

    def startIdleBubbleEffect(self):
        self.idleBubbleEffect = FishIdleBubbleEffect.getEffect(unlimited=True)
        if self.idleBubbleEffect:
            self.idleBubbleEffect.reparentTo(self.mouthJoint)
            self.idleBubbleEffect.setScale(1.0)
            self.idleBubbleEffect.setHpr(0, 0, 0)
            self.idleBubbleEffect.setLifespanBasedOnDepth(self.getPos(render))
            self.idleBubbleEffect.setBubbleSizeBasedOnWeight(self.weight)
            self.idleBubbleEffect.particleDummy.setBin('fishingGame', 5)
            self.idleBubbleEffect.startLoop()

    def stopIdleBubbleEffect(self):
        if self.idleBubbleEffect:
            self.idleBubbleEffect.stopLoop()
        self.idleBubbleEffect = None
        return

    def startBiteBubbleEffect(self):
        self.biteBubbleEffect = FishBitingBubbleEffect.getEffect(unlimited=True)
        if self.biteBubbleEffect:
            self.biteBubbleEffect.reparentTo(self.mouthJoint)
            self.biteBubbleEffect.setScale(1.0)
            self.biteBubbleEffect.setHpr(0, 0, 0)
            self.biteBubbleEffect.setLifespanBasedOnDepth(self.getPos(render))
            self.biteBubbleEffect.setBubbleSizeBasedOnWeight(self.weight)
            self.biteBubbleEffect.particleDummy.setBin('fishingGame', 5)
            self.biteBubbleEffect.play()

    def stopBiteBubbleEffect(self):
        if self.biteBubbleEffect:
            self.biteBubbleEffect.stopLoop()
        self.biteBubbleEffect = None
        return

    def startFightBubbleEffect(self):
        self.fightBubbleEffect = FishFightingHookedBubbleEffect.getEffect(unlimited=True)
        if self.fightBubbleEffect:
            self.fightBubbleEffect.reparentTo(self.mouthJoint)
            self.fightBubbleEffect.setScale(1.0)
            self.fightBubbleEffect.setHpr(0, 0, 0)
            self.fightBubbleEffect.setLifespanBasedOnDepth(self.getPos(render))
            self.fightBubbleEffect.setBubbleSizeBasedOnWeight(self.weight)
            self.fightBubbleEffect.particleDummy.setBin('fishingGame', 5)
            self.fightBubbleEffect.startLoop()

    def stopFightBubbleEffect(self):
        if self.fightBubbleEffect:
            self.fightBubbleEffect.stopLoop()
        self.fightBubbleEffect = None
        return

    def performStraightBehavior(self, dt, velocity, accel):
        newX = self.getX() + velocity[0] * dt + accel[0] * dt * dt
        newZ = self.getZ() + velocity[2] * dt + accel[2] * dt * dt
        return (
         newX, newZ)

    def performSineStraightBehavior(self, dt, velocity, accel):
        self.sineDtAccumulator += dt
        newX = self.getX() + velocity[0] * dt + accel[0] * dt * dt
        newZ = self.myZ + math.sin(self.sineDtAccumulator) * self.myData['behaviorDict']['sineMultiplier']
        return (
         newX, newZ)

    def performScareAwayBehavior(self, dt, velocity, accel):
        newX = self.getX() + velocity[0] * FishingGlobals.scareAwayVelocityMultiplier * dt + accel[0] * dt * dt
        newZ = self.getZ() + velocity[2] * FishingGlobals.scareAwayVelocityMultiplier * dt + accel[2] * dt * dt
        return (
         newX, newZ)

    def performFleeBehavior(self, dt, velocity, accel):
        newX = self.getX() + velocity[0] * FishingGlobals.fleeVelocityMultiplier * dt + accel[0] * dt * dt
        newZ = self.getZ() + velocity[2] * FishingGlobals.fleeVelocityMultiplier * dt + accel[2] * dt * dt
        return (
         newX, newZ)

    def performErraticBehavior(self, dt, velocity, accel):
        self.erraticDtAccumulator += dt
        self.sineDtAccumulator += dt
        newX = self.getX() + velocity[0] * dt + accel[0] * dt * dt
        newZ = self.myZ + math.sin(self.sineDtAccumulator) * self.myData['behaviorDict']['sineMultiplier']
        if self.erraticDtAccumulator > self.myData['behaviorDict']['secondsBetweenChanges']:
            self.erraticDtAccumulator = 0
            if random.random() < self.myData['behaviorDict']['chanceOfTurning']:
                if self.fsm.getCurrentOrNextState() != 'TurnAround':
                    self.fsm.request('TurnAround', 'Swimming', not self.movingRight)
        return (
         newX, newZ)

    def showAttractionCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.attractionVisual.show()

    def hideAttractionCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.attractionVisual.hide()

    def showAvoidanceCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.collisionVisual.show()

    def hideAvoidanceCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.collisionVisual.hide()
class Fish(NodePath):
    
    def __init__(self, fishManager, myData, index, trophy = 0):
        NodePath.__init__(self, '%s_%d' % (myData['name'], index))
        self.trophy = trophy
        self.myData = myData
        if not self.trophy:
            self.fishManager = fishManager
            self.index = index
            self.fsm = FishFSM(self)
            self.weight = random.randint(self.myData['weightRange'][0], self.myData['weightRange'][1])
        else:
            self.weight = trophy
        self.adjustedScale = (self.myData['scaleRange'][1] - self.myData['scaleRange'][0]) * (self.weight - self.myData['weightRange'][0]) / (self.myData['weightRange'][1] - self.myData['weightRange'][0]) + self.myData['scaleRange'][0]
        self.initActor()
        if not self.trophy:
            self.initVariables()
            self.initFishStatusIcon()
            if FishingGlobals.wantDebugCollisionVisuals:
                self.initCollisions()
            
        
        self.avoidingFish = False
        self.biteBubbleEffect = None
        self.idleBubbleEffect = None
        self.fightBubbleEffect = None
        self.behaviorNameToFunction = {
            'straight': self.performStraightBehavior,
            'sineStraight': self.performSineStraightBehavior,
            'erratic': self.performErraticBehavior }
        self.sineDtAccumulator = 0.0
        self.erraticDtAccumulator = 0.0
        self.myZ = 0.0
        if not self.trophy:
            self.setLightOff()
        

    
    def initActor(self):
        self.animDict = { }
        for anim in FishingGlobals.fishAnimations:
            self.animDict[anim] = 'models/char/pir_a_gam_fsh_%s_%s.bam' % (self.myData['model'], anim)
        
        self.actor = BlendActor('models/char/pir_r_gam_fsh_%s.bam' % self.myData['model'], self.animDict, FishingGlobals.defaultFishBlendTime, FishingGlobals.fishBlendTimeDict)
        self.actor.reparentTo(self)
        self.actor.setScale(self.adjustedScale)
        self.mouthJoint = self.actor.exposeJoint(None, 'modelRoot', 'hookAttach')
        self.attractionPoint = NodePath('AttractionPoint')
        self.attractionPoint.reparentTo(self.mouthJoint)
        self.attractionPoint.setPos(0.0, 0.0, 0.0)
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdle')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turn')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turnOpposite')
        if not self.trophy:
            self.setBin('fishingGame', 10)
        

    
    def codeReload(self):
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdle')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['swimAnimationMultiplier'], 'swimIdleOpposite')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turn')
        self.actor.setPlayRate(self.myData['speed'] * self.myData['turnAnimationMultiplier'], 'turnOpposite')

    
    def initFishStatusIcon(self):
        self.fishStatusIconTextNode = TextNode('fishBitingIcon')
        self.fishStatusIconNodePath = NodePath(self.fishStatusIconTextNode)
        self.fishStatusIconNodePath.setPos(0.0, 0.0, self.myData['indicatorHeightOffset'])
        self.fishStatusIconTextNode.setText('?')
        self.fishStatusIconTextNode.setTextColor(1.0, 0.0, 0.0, 1.0)
        self.fishStatusIconNodePath.reparentTo(self.mouthJoint)
        self.fishStatusIconNodePath.setBillboardPointEye()
        self.fishStatusIconNodePath.hide()
        self.fishStatusIconNodePath.setShaderOff()

    
    def initVariables(self):
        self.attractionVisual = None
        self.collisionVisual = None
        self.movingRight = True
        self.turnSpeed = 160.0
        self.turnTowardLureInterval = None
        self.velocity = FishingGlobals.baseFishVelocity * self.myData['speed']
        self.accel = FishingGlobals.baseFishAccel * self.myData['speed']
        self.fishMoveSequence = None
        self.bubbleEffect = None

    
    def initCollisions(self):
        self.collisionVisual = loader.loadModel('models/props/crate')
        self.collisionVisual.setTransparency(1)
        self.collisionVisual.setColor(1.0, 1.0, 1.0, 0.29999999999999999)
        self.collisionVisual.setScale(*self.myData['collisionBoxSize'])
        self.collisionVisual.setPos(*self.myData['collisionBoxOffset'])
        self.collisionVisual.reparentTo(self)
        self.collisionVisual.hide()
        self.attractionVisual = loader.loadModel('models/ammunition/cannonball')
        self.attractionVisual.setTransparency(1)
        self.attractionVisual.setColor(0.0, 1.0, 0.0, 0.29999999999999999)
        self.attractionVisual.setScale(self.myData['attractionRadius'])
        self.attractionVisual.reparentTo(self.attractionPoint)
        self.attractionVisual.hide()
        self.collisionVisualVisible = False

    
    def hide(self):
        NodePath.hide(self)
        if self.idleBubbleEffect:
            self.idleBubbleEffect.hide()
        

    
    def show(self):
        NodePath.show(self)
        if self.idleBubbleEffect:
            self.idleBubbleEffect.show()
        

    
    def reloadCollisions(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.collisionVisual.removeNode()
            self.attractionVisual.removeNode()
            self.initCollisions()
        

    
    def cleanFishData(self):
        pass

    
    def destroy(self):
        self.closeFish = []
        self.actor.destroy()
        self.stopIdleBubbleEffect()
        self.stopFightBubbleEffect()
        if self.fishMoveSequence:
            self.fishMoveSequence.pause()
            self.fishMoveSequence = None
        
        if self.fsm:
            del self.fsm
            self.fsm = None
        
        self.behaviorNameToFunction = { }
        self.removeNode()

    
    def pickPositionAndSwim(self):
        self.initVariables()
        self.actor.clearControlEffectWeights()
        if self.myData['depth'] == 0:
            depth = random.uniform(FishingGlobals.fishingLevelBoundaries[self.myData['depth']], self.fishManager.gameObject.waterLevel + FishingGlobals.fishSpawnBelowWaterLevelHeight)
        else:
            depth = random.uniform(FishingGlobals.fishingLevelBoundaries[self.myData['depth']], FishingGlobals.fishingLevelBoundaries[self.myData['depth'] - 1])
        startX = random.uniform(FishingGlobals.leftFishBarrier + 5.0, FishingGlobals.rightFishBarrier - 5.0)
        self.setPos(startX, 0.0, depth)
        if random.randint(0, 1):
            self.fsm.request('TurnAround', 'Swimming', False)
        else:
            self.fsm.request('Swimming')

    
    def turnAround(self, nextState, shouldMoveRight):
        if self.velocity[0] < 0 and shouldMoveRight:
            self.velocity[0] = -self.velocity[0]
        elif self.velocity[0] > 0 and not shouldMoveRight:
            self.velocity[0] = -self.velocity[0]
        
        self.movingRight = self.velocity[0] > 0
        if self.fishMoveSequence:
            self.fishMoveSequence.pause()
            self.fishMoveSequence.clearToInitial()
        
        animationToTurn = 'turn'
        if self.movingRight:
            animationToTurn = 'turnOpposite'
        
        durationOfFishTurn = self.myData['durationOfFishTurn']
        self.fishMoveSequence = Parallel(Sequence(Func(self.actor.changeAnimationTo, animationToTurn, False), Wait(durationOfFishTurn), Func(self.fsm.request, nextState)), Sequence(Wait(durationOfFishTurn * 0.33000000000000002), Func(self.setXVelocity, 0.0), Wait(durationOfFishTurn * 0.66000000000000003), Func(self.setXVelocity, self.velocity[0])), name = '%s_turnAroundInterval' % self.getName())
        self.velocity[0] = -self.velocity[0]
        self.fishMoveSequence.start()

    
    def setXVelocity(self, newVel):
        self.velocity[0] = newVel

    
    def checkForBiting(self):
        if self.fishManager.activeFish is not None:
            return None
        
        if self.fishManager.gameObject.fsm.getCurrentOrNextState() not in [
            'Fishing',
            'Reeling',
            'LureStall',
            'LegdFishShow']:
            return None
        
        inv = localAvatar.getInventory()
        rodLvl = inv.getItemQuantity(InventoryType.FishingRod)
        if self.myData['depth'] + 1 > rodLvl:
            return None
        
        self.fsm.request('Biting')

    
    def checkForBoxOverlap(self, otherFish):
        pos = self.getPos(self.fishManager.gameObject.fishingSpot)
        size = self.myData['collisionBoxSize']
        offset = list(self.myData['collisionBoxOffset'])
        otherPos = otherFish.getPos()
        otherSize = otherFish.myData['collisionBoxSize']
        otherOffset = list(otherFish.myData['collisionBoxOffset'])
        if pos[0] + size[0] / 2.0 + offset[0] > (otherPos[0] - otherSize[0] / 2.0) + otherOffset[0] and (pos[0] - size[0] / 2.0) + offset[0] < otherPos[0] + otherSize[0] / 2.0 + otherOffset[0] and pos[2] + size[2] / 2.0 + offset[2] > (otherPos[2] - otherSize[2] / 2.0) + otherOffset[2] and (pos[2] - size[2] / 2.0) + offset[2] < otherPos[2] + otherSize[2] / 2.0 + otherOffset[2]:
            return True
        
        return False

    
    def checkForCloseFish(self, index):
        if index < len(self.fishManager.uncaughtFish) - 1:
            for i in range(index + 1, len(self.fishManager.uncaughtFish)):
                if self.fishManager.uncaughtFish[i].index != self.index:
                    if self.checkForBoxOverlap(self.fishManager.uncaughtFish[i]):
                        self.closeFish.append(self.fishManager.uncaughtFish[i])
                        if FishingGlobals.wantDebugCollisionVisuals:
                            self.collisionVisual.setColor(1, 0, 0, 0.29999999999999999)
                        
                    
                self.checkForBoxOverlap(self.fishManager.uncaughtFish[i])
            
        
        if len(self.closeFish) == 0:
            if FishingGlobals.wantDebugCollisionVisuals:
                self.collisionVisual.setColor(1, 1, 1, 0.29999999999999999)
            
        

    
    def checkForLures(self, currentState, lurePos):
        if (self.getX() + FishingGlobals.fishAttractionOffset < lurePos[0] or self.movingRight or self.getX() - FishingGlobals.fishAttractionOffset > lurePos[0]) and not (self.movingRight):
            if self.attractionPoint.getDistance(self.fishManager.gameObject.lure) < self.myData['attractionRadius'] + self.fishManager.gameObject.lure.lureAttractRadius:
                self.checkForBiting()
            
        

    
    def update(self, dt, index, lurePos):
        currentState = self.fsm.getCurrentOrNextState()
        self.closeFish = []
        if currentState in [
            'ScareAway',
            'Swimming',
            'Flee',
            'TurnAround']:
            self.checkForCloseFish(index)
            if currentState in [
                'Swimming']:
                self.checkForLures(currentState, lurePos)
            
            self.updateBasedOnBehavior(dt, lurePos)
        elif currentState in [
            'Hooked',
            'AboutToFight',
            'HookedFighting']:
            self.checkForCloseFish(-1)
            for fish in self.closeFish:
                self.makeFishRunFromMe(fish)
            
        

    
    def makeFishRunFromMe(self, otherFish):
        if otherFish.fsm.getCurrentOrNextState() == 'Flee' or otherFish.fsm.getCurrentOrNextState() == 'TurnAround':
            return None
        
        if otherFish.getX() < self.getX(self.fishManager.gameObject.fishingSpot) and otherFish.movingRight:
            otherFish.fsm.request('TurnAround', 'Flee', False)
        elif otherFish.getX() > self.getX(self.fishManager.gameObject.fishingSpot) and not (otherFish.movingRight):
            otherFish.fsm.request('TurnAround', 'Flee', True)
        else:
            otherFish.fsm.request('Flee')

    
    def updateBasedOnBehavior(self, dt, lurePos):
        currentState = self.fsm.getCurrentOrNextState()
        newX = self.getX()
        newY = self.getY()
        newZ = self.getZ()
        for fish in self.closeFish:
            if self.myData['size'] == 'small' and fish.myData['size'] == 'large':
                if self.checkForEating(fish):
                    return None
                
            
            self.avoidingFish = True
            if fish.velocity[1] > 0.0 and fish.avoidingFish:
                self.velocity[1] = -(FishingGlobals.fishAvoidYVelocity)
            else:
                self.velocity[1] = FishingGlobals.fishAvoidYVelocity
            if abs(fish.getY() - self.getY()) > self.myData['collisionBoxSize'][1] + fish.myData['collisionBoxSize'][1]:
                self.velocity[1] = 0.0
                continue
        
        if len(self.closeFish) == 0 and abs(self.getY()) > FishingGlobals.fishYTolerance:
            self.avoidingFish = False
            if self.getY() > 0:
                self.velocity[1] = -(FishingGlobals.fishAvoidYVelocity)
            else:
                self.velocity[1] = FishingGlobals.fishAvoidYVelocity
        elif len(self.closeFish) == 0 and abs(self.getY()) < FishingGlobals.fishYTolerance:
            self.avoidingFish = False
            self.velocity[1] = 0.0
            self.setY(0.0)
        
        newY = self.getY() + self.velocity[1] * dt + self.accel[1] * dt * dt
        if currentState in [
            'Swimming',
            'TurnAround',
            'Flee',
            'ScareAway']:
            if currentState == 'ScareAway':
                (newX, newZ) = self.performScareAwayBehavior(dt, self.velocity, self.accel)
            elif currentState == 'Flee':
                (newX, newZ) = self.performFleeBehavior(dt, self.velocity, self.accel)
            else:
                (newX, newZ) = self.behaviorNameToFunction[self.myData['behaviorDict']['name']](dt, self.velocity, self.accel)
            currentState = self.fsm.getCurrentOrNextState()
            if newX < FishingGlobals.leftFishBarrier:
                if currentState == 'ScareAway':
                    if newX < FishingGlobals.leftFishBarrier - FishingGlobals.fullyOffscreenXOffset:
                        self.fsm.request('Offscreen')
                        return None
                    
                elif currentState != 'TurnAround' and not (self.movingRight):
                    self.fsm.request('TurnAround', 'Swimming', True)
                
            elif newX > FishingGlobals.rightFishBarrier:
                if currentState != 'TurnAround' and self.movingRight:
                    self.fsm.request('TurnAround', 'Swimming', False)
                
            
            newZ = min(max(FishingGlobals.fishingLevelBoundaries[len(FishingGlobals.fishingLevelBoundaries) - 1], newZ), self.fishManager.gameObject.waterLevel + FishingGlobals.fishSpawnBelowWaterLevelHeight)
        
        self.setPos(newX, newY, newZ)

    
    def checkForEating(self, fishThatWillEat):
        if (self.getX() < fishThatWillEat.getX() or not (fishThatWillEat.movingRight) or self.getX() > fishThatWillEat.getX() or fishThatWillEat.movingRight) and self.fsm.getCurrentOrNextState() == 'Swimming' and fishThatWillEat.fsm.getCurrentOrNextState() == 'Swimming' and random.random() < 1.0:
            self.fsm.request('BeingEaten', fishThatWillEat)
            fishThatWillEat.fsm.request('Eating', self.weight)
            return True
        
        return False

    
    def startIdleBubbleEffect(self):
        self.idleBubbleEffect = FishIdleBubbleEffect.getEffect(unlimited = True)
        if self.idleBubbleEffect:
            self.idleBubbleEffect.reparentTo(self.mouthJoint)
            self.idleBubbleEffect.setScale(1.0)
            self.idleBubbleEffect.setHpr(0, 0, 0)
            self.idleBubbleEffect.setLifespanBasedOnDepth(self.getPos(render))
            self.idleBubbleEffect.setBubbleSizeBasedOnWeight(self.weight)
            self.idleBubbleEffect.particleDummy.setBin('fishingGame', 5)
            self.idleBubbleEffect.startLoop()
        

    
    def stopIdleBubbleEffect(self):
        if self.idleBubbleEffect:
            self.idleBubbleEffect.stopLoop()
        
        self.idleBubbleEffect = None

    
    def startBiteBubbleEffect(self):
        self.biteBubbleEffect = FishBitingBubbleEffect.getEffect(unlimited = True)
        if self.biteBubbleEffect:
            self.biteBubbleEffect.reparentTo(self.mouthJoint)
            self.biteBubbleEffect.setScale(1.0)
            self.biteBubbleEffect.setHpr(0, 0, 0)
            self.biteBubbleEffect.setLifespanBasedOnDepth(self.getPos(render))
            self.biteBubbleEffect.setBubbleSizeBasedOnWeight(self.weight)
            self.biteBubbleEffect.particleDummy.setBin('fishingGame', 5)
            self.biteBubbleEffect.play()
        

    
    def stopBiteBubbleEffect(self):
        if self.biteBubbleEffect:
            self.biteBubbleEffect.stopLoop()
        
        self.biteBubbleEffect = None

    
    def startFightBubbleEffect(self):
        self.fightBubbleEffect = FishFightingHookedBubbleEffect.getEffect(unlimited = True)
        if self.fightBubbleEffect:
            self.fightBubbleEffect.reparentTo(self.mouthJoint)
            self.fightBubbleEffect.setScale(1.0)
            self.fightBubbleEffect.setHpr(0, 0, 0)
            self.fightBubbleEffect.setLifespanBasedOnDepth(self.getPos(render))
            self.fightBubbleEffect.setBubbleSizeBasedOnWeight(self.weight)
            self.fightBubbleEffect.particleDummy.setBin('fishingGame', 5)
            self.fightBubbleEffect.startLoop()
        

    
    def stopFightBubbleEffect(self):
        if self.fightBubbleEffect:
            self.fightBubbleEffect.stopLoop()
        
        self.fightBubbleEffect = None

    
    def performStraightBehavior(self, dt, velocity, accel):
        newX = self.getX() + velocity[0] * dt + accel[0] * dt * dt
        newZ = self.getZ() + velocity[2] * dt + accel[2] * dt * dt
        return (newX, newZ)

    
    def performSineStraightBehavior(self, dt, velocity, accel):
        self.sineDtAccumulator += dt
        newX = self.getX() + velocity[0] * dt + accel[0] * dt * dt
        newZ = self.myZ + math.sin(self.sineDtAccumulator) * self.myData['behaviorDict']['sineMultiplier']
        return (newX, newZ)

    
    def performScareAwayBehavior(self, dt, velocity, accel):
        newX = self.getX() + velocity[0] * FishingGlobals.scareAwayVelocityMultiplier * dt + accel[0] * dt * dt
        newZ = self.getZ() + velocity[2] * FishingGlobals.scareAwayVelocityMultiplier * dt + accel[2] * dt * dt
        return (newX, newZ)

    
    def performFleeBehavior(self, dt, velocity, accel):
        newX = self.getX() + velocity[0] * FishingGlobals.fleeVelocityMultiplier * dt + accel[0] * dt * dt
        newZ = self.getZ() + velocity[2] * FishingGlobals.fleeVelocityMultiplier * dt + accel[2] * dt * dt
        return (newX, newZ)

    
    def performErraticBehavior(self, dt, velocity, accel):
        self.erraticDtAccumulator += dt
        self.sineDtAccumulator += dt
        newX = self.getX() + velocity[0] * dt + accel[0] * dt * dt
        newZ = self.myZ + math.sin(self.sineDtAccumulator) * self.myData['behaviorDict']['sineMultiplier']
        if self.erraticDtAccumulator > self.myData['behaviorDict']['secondsBetweenChanges']:
            self.erraticDtAccumulator = 0
            if random.random() < self.myData['behaviorDict']['chanceOfTurning']:
                if self.fsm.getCurrentOrNextState() != 'TurnAround':
                    self.fsm.request('TurnAround', 'Swimming', not (self.movingRight))
                
            
        
        return (newX, newZ)

    
    def showAttractionCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.attractionVisual.show()
        

    
    def hideAttractionCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.attractionVisual.hide()
        

    
    def showAvoidanceCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.collisionVisual.show()
        

    
    def hideAvoidanceCollisionVisuals(self):
        if FishingGlobals.wantDebugCollisionVisuals:
            self.collisionVisual.hide()