class Ship(DirectObject.DirectObject): notify = directNotify.newCategory('Ship') WantWake = config.GetBool('want-wake', 1) breakSfx1 = None breakSfx3 = None sinkingSfx1 = None sinkingSfx2 = None def __init__(self, shipClass, root, breakAnims, hitAnims, metaAnims, collisions, locators): self.modelRoot = root self.transRoot = NodePath('transRoot') self.modelRoot.reparentTo(self.transRoot) self.shipRoot = None self.shipClass = shipClass self.sailing = False self.sfxAlternativeStyle = False self.landedGrapples = [] self.landedGrappleNodes = [] self.breakAnims = breakAnims self.hitAnims = hitAnims self.metaAnims = metaAnims self.char = self.modelRoot.find('**/+Character') self.riggingControls = {} numBundles = self.char.node().getNumBundles() masts = self.breakAnims.keys() masts.sort() self.sinkTimeScale = 1.0 if self.breakSfx1 is None: Ship.breakSfx1 = loadSfx(SoundGlobals.SFX_SHIP_MAST_BREAK_01) if self.breakSfx3 == None: Ship.breakSfx3 = loadSfx( SoundGlobals.SFX_MINIGAME_CANNON_MAST_BREAK) for (i, j) in enumerate(masts): bundle = self.char.node().getBundle(i + 1) ladderJoint = bundle.findChild('def_ladder_base') if ladderJoint: self.riggingControls[j] = ladderJoint continue self._Ship__breakIvals = {} for i in self.breakAnims: self._Ship__breakIvals[i] = Sequence( AnimControlInterval(self.breakAnims[i][0]), AnimControlInterval(self.breakAnims[i][1])) self._Ship__hitSailingIvals = {} for i in self.breakAnims: self._Ship__hitSailingIvals[i] = Sequence( AnimControlInterval(self.hitAnims[i][1]), Func(self.metaAnims['idle'].playAll)) self.lod = self.modelRoot.find('**/+LODNode') self.modelCollisions = collisions self.mastStates = [1, 1, 1, 1, 1] self.mastsHidden = False self._Ship__targetableCollisions = [] self.locators = locators self.center = None self.stern = None self.bow = None self.starboard = None self.port = None if self.sinkingSfx1 is None: Ship.sinkingSfx1 = loadSfx(SoundGlobals.SFX_SHIP_SINKING) Ship.sinkingSfx2 = loadSfx( SoundGlobals.SFX_MINIGAME_CANNON_SHIP_SINK) self.sinkEffectsRoot = None self.sinkEffects = [] self.sinkTrack = None self.isSplit = False self.owner = None self.mastCollisions = [ self.modelCollisions.findAllMatches('**/collision_masts') ] self.sailCollisions = self.modelCollisions.findAllMatches( '**/collision_sails') self.disableSails() if self.metaAnims['rolldown'].getNumAnims(): self._Ship__rollDownIval = AnimControlInterval( self.metaAnims['rolldown']) self.metaAnims['rolldown'].poseAll(0) else: self._Ship__rollDownIval = Interval('dummy', 0, 0) if self.metaAnims['rollup'].getNumAnims(): self._Ship__rollUpIval = AnimControlInterval( self.metaAnims['rollup']) else: self._Ship__rollUpIval = Interval('dummy', 0, 0) self.sailStartIval = Sequence(Func(self.stopIvals), Func(self.enableSails), self._Ship__rollDownIval, Func(self.metaAnims['idle'].loopAll, 1)) self.sailStopIval = Sequence(Func(self.stopIvals), self._Ship__rollUpIval, Func(self.disableSails), Func(self.metaAnims['tiedup'].playAll)) self.windTunnelEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stormEffect = None self.wake = None self.fogEffect = None self.leftSideFire = None self.leftSideSmoke = None self.leftSideFire2 = None self.leftSideSmoke2 = None self.rightSideFire = None self.rightSideSmoke = None self.rightSideFire2 = None self.rightSideSmoke2 = None self.rearSideFire = None self.rearSideSmoke = None self.fader = None self.idleBounds = self.modelRoot.getTightBounds() self.setupCollisions() def setOwner(self, owner, ownerIsModelRoot=False): self.owner = owner if self.owner: if ownerIsModelRoot: self.shipRoot = self.owner.getParent() self.owner.reparentTo(self.shipRoot) self.transRoot.reparentTo(self.owner) else: self.shipRoot = self.owner.attachNewNode('ShipRoot') self.transRoot.reparentTo(self.shipRoot) self.modelRoot.setPythonTag('ship', owner) def setupCollisions(self): self.modelCollisions.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) self.floors = self.modelCollisions.find('**/collision_floors') self.deck = self.modelCollisions.find('**/collision_deck') self.planeBarriers = self.modelCollisions.find('**/collision_planes') self.planeBarriers.stash() self.walls = self.modelCollisions.find('**/collision_walls') self.shipCollWall = self.modelCollisions.find( '**/collision_shiptoship') self.shipCollWall.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) if self.owner: self.shipCollWall.setTag('shipId', str(self.owner.doId)) self.panels = self.modelCollisions.find('**/collision_panels') self.stashPlaneCollisions() def stashPlaneCollisions(self): self.planeBarriers.stash() def unstashPlaneCollisions(self): self.planeBarriers.unstash() def computeDimensions(self): if not self.center: self.center = self.modelRoot.attachNewNode('center') tb = self.idleBounds self.center.setPos((tb[0] + tb[1]) / 2.0) self.dimensions = tb[1] - tb[0] self.hullDimensions = tb[1] - tb[0] if not self.bow: self.bow = self.modelRoot.attachNewNode('bowPos') if not self.port: self.port = self.modelRoot.attachNewNode('portPos') if not self.starboard: self.starboard = self.modelRoot.attachNewNode('starboardPos') if not self.stern: self.stern = self.modelRoot.attachNewNode('sternPos') self.stern.setPos(Point3(0, tb[1][1], 0)) self.bow.setPos(Point3(0, tb[0][1], 0)) self.starboard.setPos(Point3(tb[1][0], 0, 0)) self.port.setPos(Point3(tb[0][0], 0, 0)) def getBoardingLocators(self): return self.locators.findAllMatches('**/boarding_spot_*;+s') def getPartNodes(self): if not self.center: self.computeDimensions() return (self.bow, self.port, self.starboard, self.stern) def disableOnDeckInteractions(self): pass def uniqueName(self, name): return name + '-%s' % id(self) def isInCrew(self, avId): if self.owner: return self.owner.isInCrew(avId) return False def dropMast(self, index): if index in self.breakAnims: self.breakAnims[index][1].playAll() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def dropRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze( TransformState.makeScale((0, 0, 0))) self.char.node().forceUpdate() def restoreRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze( TransformState.makeMat( self.riggingControls[index].getDefaultValue())) self.char.node().forceUpdate() def hideMasts(self): self.mastsHidden = True for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][1].playAll() self.dropRigging(i) self.mastStates[i] def showMasts(self): self.mastsHidden = False for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][0].poseAll(0) self.restoreRigging(i) self.mastStates[i] def breakMast(self, index): breakSfx = self.breakSfx1 if self.sfxAlternativeStyle: breakSfx = self.breakSfx3 base.playSfx(breakSfx, node=self.modelRoot, cutoff=3000) if index in self.breakAnims: self._Ship__hitSailingIvals[index].pause() self._Ship__breakIvals[index].pause() self._Ship__breakIvals[index].start() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def restoreMast(self, index): if index in self.breakAnims: self._Ship__breakIvals[index].pause() self.breakAnims[index][0].poseAll(0) self.restoreRigging(index) self.mastCollisions[index].unstash() self.mastStates[index] = 1 def mastHit(self, index): if index in self.hitAnims: if self.mastStates[index] and not (self.mastsHidden): if not self.sailing: self.hitAnims[index][0].playAll() else: self._Ship__hitSailingIvals[index].start() def stopIvals(self): self._Ship__rollDownIval.pause() self._Ship__rollUpIval.pause() for ival in self._Ship__hitSailingIvals.values(): ival.pause() def playIdle(self): self.stopIvals() self.metaAnims['idle'].loopAll(1) def instantSailing(self): self.sailing = True self.enableSails() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['idle'].loopAll(1) def startSailing(self): self.stopIvals() if not self.sailing: self.sailing = True self.sailStopIval.pause() self.sailStartIval.pause() self.sailStartIval.start() def instantDocked(self): self.sailing = False self.disableSails() self.stopIvals() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['tiedup'].playAll() def stopSailing(self): if self.sailing: self.sailing = False self.sailStartIval.pause() self.sailStopIval.pause() self.sailStopIval.start() def playFullSailEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: if not self.windTunnelEffect1: self.windTunnelEffect1 = Wind.getEffect() if self.windTunnelEffect1: self.windTunnelEffect1.reparentTo(self.center) self.windTunnelEffect1.fadeColor = Vec4( 0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windTunnelEffect1.setScale(self.dimensions / 6.0) self.windTunnelEffect1.fadeTime = 2.0 self.windTunnelEffect1.setH(180) self.windTunnelEffect1.play() def playComeAboutEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: if not self.windTunnelEffect2: self.windTunnelEffect2 = Wind.getEffect() if self.windTunnelEffect2: self.windTunnelEffect2.reparentTo(self.center) self.windTunnelEffect2.fadeColor = Vec4( 0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.40000000000000002) self.windTunnelEffect2.setScale(self.dimensions / 10.0) self.windTunnelEffect2.fadeTime = 2.0 self.windTunnelEffect2.setH(0) self.windTunnelEffect2.play() def playRamEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: if not self.windConeEffect: self.windConeEffect = WindBlurCone.getEffect() if self.windConeEffect: self.windConeEffect.reparentTo(self.bow) self.windConeEffect.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windConeEffect.setScale(self.dimensions / 3.0) self.windConeEffect.setPos(0, self.dimensions[1] / 18.0, self.dimensions[2] / 4.0) self.windConeEffect.fadeTime = 2.0 self.windConeEffect.startLoop() def playRechargeEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: if not self.powerRechargeEffect: self.powerRechargeEffect = ShipPowerRecharge.getEffect() if self.powerRechargeEffect: self.powerRechargeEffect.reparentTo(self.char) self.powerRechargeEffect.setEffectColor(Vec4(0.5, 0.5, 1, 1)) self.powerRechargeEffect.setScale(self.dimensions / 4.0) self.powerRechargeEffect.startLoop() def playSpawnEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: self.protectionEffect = ProtectionDome.getEffect() if self.protectionEffect: self.protectionEffect.reparentTo(self.shipRoot) self.protectionEffect.setScale(self.dimensions[1] / 15.0) self.protectionEffect.startLoop() def playTakeCoverEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: self.takeCoverEffect = FadingCard(loader.loadModel( 'models/textureCards/skillIcons').find('**/sail_take_cover'), color=Vec4(1, 1, 1, 1), fadeTime=0.01, waitTime=2.5, startScale=0.94999999999999996, endScale=1.0) if self.takeCoverEffect: self.takeCoverEffect.reparentTo(self.shipRoot) self.takeCoverEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.takeCoverEffect.setScale(self.dimensions[1] / 4.0) self.takeCoverEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffTakeCoverString) def playOpenFireEffect(self): if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: self.openFireEffect = FadingCard(loader.loadModel( 'models/textureCards/skillIcons').find('**/sail_openfire2'), color=Vec4(1, 1, 1, 1), fadeTime=0.01, waitTime=2.5, startScale=0.94999999999999996, endScale=1.0) if self.openFireEffect: self.openFireEffect.reparentTo(self.shipRoot) self.openFireEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.openFireEffect.setScale(self.dimensions[1] / 4.0) self.openFireEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffOpenFireString) def stopRamEffect(self): if self.windConeEffect: self.windConeEffect.stopLoop() def stopRechargeEffect(self): if self.powerRechargeEffect: self.powerRechargeEffect.stopLoop() def stopSpawnEffect(self): if self.protectionEffect: self.protectionEffect.stopLoop() def stopTakeCoverEffect(self): if self.takeCoverEffect: self.takeCoverEffect.stop() def stopOpenFireEffect(self): if self.openFireEffect: self.openFireEffect.stop() def playStormEffect(self): if not self.stormEffect: self.stormEffect = DarkMaelstrom(self.shipRoot) self.stormEffect.setZ(50) self.stormEffect.loop() compassFX = CompassEffect.make(render) self.stormEffect.setEffect(compassFX) def stopStormEffect(self): if self.stormEffect: self.stormEffect.destroy() self.stormEffect = None def createWake(self): if self.owner: ownerId = self.owner.doId else: ownerId = None if not base.cr.activeWorld: self.notify.warning( 'Ship %s is trying to create a wake without an active world.' % (ownerId, )) return None if not base.cr.activeWorld.getWater(): self.notify.warning( 'Ship %s is trying to create a wake without an ocean. (world: %s)' % (ownerId, base.cr.activeWorld)) return None if self.WantWake and base.cr.wantSpecialEffects and self.owner: self.removeWake() if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsMedium: if not hasattr(base.cr.activeWorld.getWater(), 'patch'): self.notify.error( "Ship %s is in location %s,%s (%s[%s]).\nThis causes Attribute Error: 'NoneType' object has no attribute 'patch'\n" % (ownerId, self.getLocation()[0], self.getLocation()[1], type(self.getParentObj()), safeRepr(self.getParentObj()))) self.wake = Wake.getEffect() if self.wake: self.wake.attachToShip(self.owner) compassFX = CompassEffect.make(render) self.wake.setEffect(compassFX) self.wake.startAnimate(self.owner) def removeWake(self): if self.wake: self.wake.cleanUpEffect() self.wake = None def hasWake(self): return self.wake != None def cleanup(self): self.sinkingEnd() self.modelRoot.clearPythonTag('ship') self.breakAnims = {} self.metaAnims = {} self.lod = None self.modelRoot.detachNode() self.modelRoot = None self.locators = None self.center = None self.stern = None self.bow = None self.starboard = None self.port = None self.removeLandedGrapples() self.cleanupCollisions() self.char = None loader.unloadSfx(self.sinkingSfx1) loader.unloadSfx(self.sinkingSfx2) self.sinkingSfx1 = None self.sinkingSfx2 = None self.sinkEffectsRoot = None self.sinkEffects = [] self.owner = None self._Ship__rollDownIval.pause() self._Ship__rollDownIval = None self._Ship__rollUpIval.pause() self._Ship__rollUpIval = None self.sailStartIval.pause() self.sailStartIval = None self.sailStopIval.pause() self.sailStopIval = None for ival in self._Ship__breakIvals.values(): ival.pause() self._Ship__breakIvals = {} self.windTunneldEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stopStormEffect() self.removeWake() self.cleanupDarkFog() if self.fader: self.fader.pause() self.fader = None def cleanupCollisions(self): self.mastCollisions = None self._Ship__targetableCollisions = [] self.modelCollisions = None self.floors = None self.deck = None self.planeBarriers = None self.walls = None self.shipCollWall = None self.panels = None def demandMastStates(self, mastStates, maxHealth): for i in range(5): if maxHealth[i]: if mastStates[i]: self.restoreMast(i) else: self.dropMast(i) mastStates[i] def sinkingBegin(self): self.computeDimensions() self.disableOnDeckInteractions() self.removeWake() soundTrack = Sequence() sinkingSfx = self.sinkingSfx1 if self.sfxAlternativeStyle: sinkingSfx = self.sinkingSfx2 if sinkingSfx: soundTrack = Sequence( Func(base.playSfx, sinkingSfx, node=self.modelRoot, cutoff=1000)) self.sinkTrack = Sequence() sinkParallel = Parallel() if self.isInCrew(localAvatar.doId): sinkParallel.append( Func(base.localAvatar.b_setGameState, 'Cutscene', localArgs=[self.owner])) sinkParallel.append(self.getSinkCamIval()) sinkParallel.append( Sequence(Func(self.startSinkEffects), soundTrack, self.getSinkShipIval())) self.sinkTrack.append(sinkParallel) self.sinkTrack.append(Func(self.endSinkEffects)) if self.owner.isInCrew(localAvatar.doId): self.sinkTrack.append(Func(self.cleanupLocalSinking)) self.sinkTrack.start() def sinkingEnd(self): if self.sinkTrack: self.sinkTrack.finish() self.sinkTrack = None self.endSinkEffects() def getSinkShipIval(self): return Parallel( LerpPosInterval(self.modelRoot, 18.0 * self.sinkTimeScale, Vec3(0, 0, -1.5 * self.dimensions[2])), LerpHprInterval( self.modelRoot, 12.0 * self.sinkTimeScale, VBase3(self.modelRoot.getH(), self.modelRoot.getP() + 75, self.modelRoot.getR()))) def getSinkCamIval(self): camStartPos = Vec3(-4.0 * self.dimensions[0], -1.25 * self.dimensions[1], 40) camEndPos = Vec3(-4.0 * self.dimensions[0], self.dimensions[1], self.dimensions[2] / 2.0) if self.owner: self.owner.lookAtDummy.setPos(0, 0, self.center.getZ()) def camLookAtDummy(t): camera.lookAt(self.owner.lookAtDummy) return Parallel( Func(camera.reparentTo, self.owner.attachNewNode('cameraDummy')), LerpPosInterval(camera, 16.0 * self.sinkTimeScale, camEndPos, startPos=camStartPos, blendType='easeInOut'), LerpPosInterval(self.owner.lookAtDummy, 18.0 * self.sinkTimeScale, Vec3(0, 80, 0)), LerpFunc(camLookAtDummy, 18.0 * self.sinkTimeScale)) def startSinkEffects(self): if not self.sinkEffectsRoot: self.sinkEffectsRoot = self.shipRoot.attachNewNode( 'sinkEffectsRoot') self.sinkEffectsRoot.setY(self.center.getY()) if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsMedium: ripples = WaterWakes.getEffect() if ripples: scale = self.hullDimensions ripples.duration = ripples.duration * self.sinkTimeScale ripples.reparentTo(self.sinkEffectsRoot) ripples.setScale(scale[0] / 6, scale[1] / 10, scale[2] / 5) ripples.play() self.sinkEffects.append(ripples) if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsHigh: mist = WaterMist.getEffect() if mist: mist.sinkTimeScale = self.sinkTimeScale mist.reparentTo(self.sinkEffectsRoot) mist.setScale(self.hullDimensions / 50.0) mist.setEffectScale(1.0) mist.setZ(-5.0) mist.play() self.sinkEffects.append(mist) taskMgr.add(self.updateSinkEffects, self.uniqueName('updateSinkEffects')) def endSinkEffects(self): taskMgr.remove(self.uniqueName('updateSinkEffects')) for effect in self.sinkEffects: effect.stopLoop() self.sinkEffects = [] def updateSinkEffects(self, task): pos = self.modelRoot.getPos(render) if base.cr.activeWorld and base.cr.activeWorld.getWater(): waterHeight = base.cr.activeWorld.getWater().calcHeight( pos[0], pos[1], 0, render) self.sinkEffectsRoot.setZ(render, waterHeight) self.sinkEffectsRoot.setY(self.sinkEffectsRoot.getY() - 0.14999999999999999) return task.cont def cleanupLocalSinking(self): base.transitions.fadeOut() base.transitions.letterboxOff() base.cr.interactionMgr.unlock() base.cr.interactionMgr.start() base.musicMgr.requestCurMusicFadeOut() def undoSinking(self): self.modelRoot.setPosHpr(0, 0, 0, 0, 0, 0) if self.isSplit: self.clipParent1.setPosHpr(0, 0, 0, 0, 0, 0) self.clipParent2.setPosHpr(0, 0, 0, 0, 0, 0) def splitShip(self): if not self.isSplit: self.isSplit = True self.modelGeom.instanceTo(self.clipParent2) planeNode1 = NodePath( PlaneNode('planeNode1', Plane(Vec4(0, 1, 0, 0)))) planeNode1.reparentTo(self.clipParent1) planeNode1.setY(ShipGlobals.getShipSplitOffset(self.shipClass)) self.clipParent1.setClipPlane(planeNode1) planeNode2 = NodePath( PlaneNode('planeNode2', Plane(Vec4(0, -1, 0, 0)))) planeNode2.reparentTo(self.clipParent2) planeNode2.setY(ShipGlobals.getShipSplitOffset(self.shipClass)) self.clipParent2.setClipPlane(planeNode2) def destroy(self): self.cleanup() def manufactureCannons(self, detailLevel=2): stats = ShipGlobals.getShipConfig(self.shipClass) cannonConfig = stats['cannons'] leftConfig = stats['leftBroadsides'] rightConfig = stats['rightBroadsides'] cannons = {} for i in range(len(cannonConfig)): cannonType = cannonConfig[i] cannon = Cannon.Cannon(None) cannon.loadModel(None, cannonType) cannons[i] = [cannon, 0] broadsides = [[[], []], None] for i in range(len(leftConfig)): if leftConfig[i] > 0: cannon = CannonPort.CannonPort(leftConfig[i], 0, i) broadsides[0][0].append(cannon) continue broadsides[0][0].append(None) for i in range(len(rightConfig)): if rightConfig[i] > 0: cannon = CannonPort.CannonPort(rightConfig[i], 1, i) broadsides[0][1].append(cannon) continue broadsides[0][1].append(None) self.setupCannons(cannons, broadsides, detailLevel) def setupCannons(self, cannons, broadsides, detailLevel=2): self.cannons = {} if detailLevel in (1, 2): self.cannonsHigh = self.lod.getChild(0).attachNewNode( ModelNode('cannons')) self.cannonsMed = self.lod.getChild(1).attachNewNode( ModelNode('cannons')) self.cannonsLow = self.lod.getChild(2).attachNewNode( ModelNode('cannons')) else: self.cannonsHigh = self.lod.getChild(0).attachNewNode( ModelNode('cannons')) self.cannonsMed = self.lod.getChild(1).attachNewNode( ModelNode('cannons')) self.cannonColl = self.modelCollisions.attachNewNode('cannons') for i in cannons: transform = self.locators.find('**/cannon_%s;+s' % i).getTransform( self.locators) cannon = cannons[i][0] cannon.root.setTransform(transform) cannon.root.flattenLight() char = cannon.root.node() bundle = char.getBundle(0) if detailLevel in (1, 2): high = cannon.lod.getChild(0) med = cannon.lod.getChild(1) low = cannon.lod.getChild(2) self.char.node().combineWith(char) high.reparentTo(self.cannonsHigh) med.reparentTo(self.cannonsMed) low.reparentTo(self.cannonsLow) else: low = cannon.lod.getChild(2) superlow = cannon.lod.getChild(3) self.char.node().combineWith(char) low.reparentTo(self.cannonsHigh) superlow.reparentTo(self.cannonsMed) cannon.propCollisions.setTransform(transform) cannon.propCollisions.reparentTo(self.cannonColl) cannon.hNode.reparentTo(self.locators.find('**/cannon_%s;+s' % i)) self.cannons[i] = cannon if broadsides: broadsideLeft = broadsides[0][0] broadsideRight = broadsides[0][1] self.broadsides = [broadsideLeft, broadsideRight] leftRoot = self.locators.find('**/broadsides_left') rightRoot = self.locators.find('**/broadsides_right') for (broadsideSet, side) in zip(broadsides[0], ((leftRoot, 'left'), (rightRoot, 'right'))): for i in range(len(broadsideSet)): port = broadsideSet[i] if not port: continue locator = side[0].find('broadside_%s_%s;+s' % (side[1], i)) transform = locator.getTransform(self.locators) port.locator = locator port.root.setTransform(transform) port.root.flattenLight() char = port.root.node() bundle = char.getBundle(0) if detailLevel in (1, 2): high = port.lod.getChild(0) med = port.lod.getChild(1) low = port.lod.getChild(2) self.char.node().combineWith(char) high.reparentTo(self.cannonsHigh) med.reparentTo(self.cannonsMed) low.reparentTo(self.cannonsLow) continue geom = port.lod.getChild(2) self.char.node().combineWith(char) geom.copyTo(self.cannonsHigh) geom.copyTo(self.cannonsMed) else: self.broadsides = [] self.cannonsHigh.flattenStrong() self.cannonsMed.flattenStrong() if detailLevel != 0: self.cannonsLow.flattenStrong() for cannon in self.cannons.values(): cannon.finalize() for side in self.broadsides: for port in side: if port: port.finalize() continue def updateDamageEffects(self, health, rear, left, right): effectSettings = base.options.getSpecialEffectsSetting() if left <= 30.0: locator = self.locators.find('**/location_fire_1') scale = locator.getScale()[0] / 1.75 + ( locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if not self.leftSideFire: self.leftSideFire = ShipFire.getEffect() if self.leftSideFire: self.leftSideFire.reparentTo(self.modelRoot) self.leftSideFire.setPos(locator.getPos()) self.leftSideFire.setHpr(80, -15, 0) self.leftSideFire.startLoop() if self.leftSideFire: self.leftSideFire.setEffectScale(scale) if not (self.leftSideSmoke ) and effectSettings >= base.options.SpecialEffectsMedium: self.leftSideSmoke = ShipSmoke.getEffect() if self.leftSideSmoke: self.leftSideSmoke.reparentTo(self.modelRoot) self.leftSideSmoke.setPos(locator.getPos()) self.leftSideSmoke.setHpr(90, -15, 0) self.leftSideSmoke.startLoop() if self.leftSideSmoke: self.leftSideSmoke.setEffectScale(scale) elif self.leftSideFire: self.leftSideFire.stopLoop() self.leftSideFire = None if self.leftSideSmoke: self.leftSideSmoke.stopLoop() self.leftSideSmoke = None if left <= 0.0 and effectSettings >= base.options.SpecialEffectsMedium: locator = self.locators.find('**/location_fire_3') if locator: scale = locator.getScale()[0] / 1.75 + ( locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if locator and not (self.leftSideFire2): self.leftSideFire2 = ShipFire.getEffect() if self.leftSideFire2: self.leftSideFire2.reparentTo(self.modelRoot) self.leftSideFire2.setPos(locator.getPos()) self.leftSideFire2.setHpr(90, -10, 10) self.leftSideFire2.startLoop() if self.leftSideFire2: self.leftSideFire2.setEffectScale(scale) if locator and not (self.leftSideSmoke2): self.leftSideSmoke2 = ShipSmoke.getEffect() if self.leftSideSmoke2: self.leftSideSmoke2.reparentTo(self.modelRoot) self.leftSideSmoke2.setPos(locator.getPos()) self.leftSideSmoke2.setHpr(90, -15, 0) self.leftSideSmoke2.startLoop() if self.leftSideSmoke2: self.leftSideSmoke2.setEffectScale(scale) elif self.leftSideFire2: self.leftSideFire2.stopLoop() self.leftSideFire2 = None if self.leftSideSmoke2: self.leftSideSmoke2.stopLoop() self.leftSideSmoke2 = None if right <= 30.0: locator = self.locators.find('**/location_fire_2') scale = locator.getScale()[0] / 1.75 + ( locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if not self.rightSideFire: self.rightSideFire = ShipFire.getEffect() if self.rightSideFire: self.rightSideFire.reparentTo(self.modelRoot) self.rightSideFire.setPos(locator.getPos()) self.rightSideFire.setHpr(100, 15, 0) self.rightSideFire.startLoop() if self.rightSideFire: self.rightSideFire.setEffectScale(scale) if not (self.rightSideSmoke ) and effectSettings >= base.options.SpecialEffectsMedium: self.rightSideSmoke = ShipSmoke.getEffect() if self.rightSideSmoke: self.rightSideSmoke.reparentTo(self.modelRoot) self.rightSideSmoke.setPos(locator.getPos()) self.rightSideSmoke.setHpr(90, 15, 0) self.rightSideSmoke.startLoop() if self.rightSideSmoke: self.rightSideSmoke.setEffectScale(scale) elif self.rightSideFire: self.rightSideFire.stopLoop() self.rightSideFire = None if self.rightSideSmoke: self.rightSideSmoke.stopLoop() self.rightSideSmoke = None if right <= 0.0 and effectSettings >= base.options.SpecialEffectsMedium: locator = self.locators.find('**/location_fire_4') if locator: scale = locator.getScale()[0] / 1.75 + ( locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if locator and not (self.rightSideFire2): self.rightSideFire2 = ShipFire.getEffect() if self.rightSideFire2: self.rightSideFire2.reparentTo(self.modelRoot) self.rightSideFire2.setPos(locator.getPos()) self.rightSideFire2.setHpr(90, 10, 10) self.rightSideFire2.startLoop() if self.rightSideFire2: self.rightSideFire2.setEffectScale(scale) if locator and not (self.rightSideSmoke2): self.rightSideSmoke2 = ShipSmoke.getEffect() if self.rightSideSmoke2: self.rightSideSmoke2.reparentTo(self.modelRoot) self.rightSideSmoke2.setPos(locator.getPos()) self.rightSideSmoke2.setHpr(90, 15, 0) self.rightSideSmoke2.startLoop() if self.rightSideSmoke2: self.rightSideSmoke2.setEffectScale(scale) elif self.rightSideFire2: self.rightSideFire2.stopLoop() self.rightSideFire2 = None if self.rightSideSmoke2: self.rightSideSmoke2.stopLoop() self.rightSideSmoke2 = None if rear <= 30.0: locator = self.locators.findAllMatches('**/location_fire_0')[0] scale = locator.getScale()[0] / 1.75 + ( locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if not self.rearSideFire: self.rearSideFire = ShipFire.getEffect() if self.rearSideFire: self.rearSideFire.reparentTo(self.modelRoot) self.rearSideFire.setPos(locator.getPos()) self.rearSideFire.setHpr(0, 20, 0) self.rearSideFire.startLoop() if self.rearSideFire: self.rearSideFire.setEffectScale(scale) if not (self.rearSideSmoke ) and effectSettings >= base.options.SpecialEffectsMedium: self.rearSideSmoke = ShipSmoke.getEffect() if self.rearSideSmoke: self.rearSideSmoke.reparentTo(self.modelRoot) self.rearSideSmoke.setPos(locator.getPos()) self.rearSideSmoke.setHpr(0, 20, 0) self.rearSideSmoke.startLoop() if self.rearSideSmoke: self.rearSideSmoke.setEffectScale(scale) elif self.rearSideFire: self.rearSideFire.stopLoop() self.rearSideFire = None if self.rearSideSmoke: self.rearSideSmoke.stopLoop() self.rearSideSmoke = None def cleanUpDamageEffects(self): if self.leftSideFire: self.leftSideFire.cleanUpEffect() self.leftSideFire = None if self.leftSideSmoke: self.leftSideSmoke.cleanUpEffect() self.leftSideSmoke = None if self.leftSideFire2: self.leftSideFire2.cleanUpEffect() self.leftSideFire2 = None if self.leftSideSmoke2: self.leftSideSmoke2.cleanUpEffect() self.leftSideSmoke2 = None if self.rightSideFire: self.rightSideFire.cleanUpEffect() self.rightSideFire = None if self.rightSideSmoke: self.rightSideSmoke.cleanUpEffect() self.rightSideSmoke = None if self.rightSideFire2: self.rightSideFire2.cleanUpEffect() self.rightSideFire2 = None if self.rightSideSmoke2: self.rightSideSmoke2.cleanUpEffect() self.rightSideSmoke2 = None if self.rearSideFire: self.rearSideFire.cleanUpEffect() self.rearSideFire = None if self.rearSideSmoke: self.rearSideSmoke.cleanUpEffect() self.rearSideSmoke = None def startDarkFog(self, offset=None): self.fogEffect = DarkShipFog.getEffect() if self.fogEffect: self.fogEffect.reparentTo(self.shipRoot) if offset: self.fogEffect.setY(self.fogEffect, offset) self.fogEffect.setZ(self.fogEffect, 50) self.fogEffect.startLoop() def stopDarkFog(self): if self.fogEffect: self.fogEffect.stopLoop() self.fogEffect = None def cleanupDarkFog(self): if self.fogEffect: self.fogEffect.destroy() self.fogEffect = None def fadeIn(self, duration=2.0): if self.fader: self.fader.finish() self.fader = None self.modelRoot.setTransparency(1) self.fader = Sequence( self.modelRoot.colorScaleInterval(duration, Vec4(1, 1, 1, 1), startColorScale=Vec4(0, 0, 0, 0)), Func(self.modelRoot.clearTransparency)) self.fader.start() def fadeOut(self, duration=2.0): if self.fader: self.fader.finish() self.fader = None self.modelRoot.setTransparency(1) self.fader = Sequence( self.modelRoot.colorScaleInterval(duration / 2.0, Vec4(0, 0, 0, 0), startColorScale=Vec4(1, 1, 1, 1)), Func(self.modelRoot.clearTransparency)) self.fader.start() def enableSails(self): self.sailCollisions.unstash() def disableSails(self): self.sailCollisions.stash() def forceLOD(self, index): self.lod.node().forceSwitch(index) def clearForceLOD(self): self.lod.node().clearForceSwitch() def getRope(self, thickness=0.14999999999999999): rope = Rope() rope.ropeNode.setRenderMode(RopeNode.RMTube) rope.ropeNode.setNumSlices(10) rope.ropeNode.setUvMode(RopeNode.UVDistance) rope.ropeNode.setUvDirection(1) rope.ropeNode.setUvScale(0.25) rope.ropeNode.setThickness(thickness) ropePile = loader.loadModel('models/char/rope_high') ropeTex = ropePile.findTexture('rope_single_omit') ropePile.removeNode() rope.setTexture(ropeTex) rope.setLightOff() rope.setColorScale(0.5, 0.5, 0.5, 1) return rope getRope = report(types=['frameCount', 'deltaStamp'], dConfigParam='shipboard')(getRope) def setLandedGrapples(self, ship, landedGrapples): for grapple in landedGrapples: if grapple not in self.landedGrapples: self.createLandedGrapple(ship, grapple[1]) continue self.landedGrapples = landedGrapples self.startAnimateLandedGrappleTask() def createLandedGrapple(self, otherShip, targetId): self.accept(otherShip.getDisableEvent(), self.removeLandedGrapples) otherShipRelX = otherShip.model.modelRoot.getX(self.modelRoot) grappleStr = '**/grapple_right*' anchorOffset = Vec3(0, 0, -1) if otherShipRelX < 0: grappleStr = '**/grapple_left*' anchorNode = random.choice(self.locators.findAllMatches(grappleStr)) anchorPos = anchorNode.getPos(self.modelRoot) + anchorOffset side = 'right' if self.modelRoot.getX(otherShip.model.modelRoot) < 0: side = 'left' targetStr = '**/grapple_%s_%s' % (side, targetId) if targetId >= 0: grappleLocator = otherShip.findLocator(targetStr) else: grappleLocator = random.choice( otherShip.findLocators('**/grapple_%s_*' % (side, ))) rope = self.getRope(thickness=0.5) grapplePos = grappleLocator.getPos(self.modelRoot) sagNode = self.modelRoot.attachNewNode('sagNode') sagNode.setPos((grapplePos + anchorPos) * 0.5) grapple = loader.loadModel('models/ammunition/GrapplingHook') grapple.reparentTo(otherShip.model.modelRoot) posHpr = (grappleLocator, 2, 0, -2.5, -270, -350, 80) if targetStr.find('right') > 0: posHpr = (grappleLocator, 1, 0, -1.5, 90, -40, -180) grapple.setPosHpr(*posHpr) rope.reparentTo(grapple) rope.setup(3, ((None, Point3(0)), (sagNode, Point3(0)), (self.modelRoot, anchorPos))) self.landedGrappleNodes.append( [otherShip, grapple, anchorNode, sagNode, grappleLocator, rope]) def removeLandedGrapples(self): self.stopAnimateLandedGrappleTask() for (ship, grapple, anchorNode, sagNode, grappleLocator, rope) in self.landedGrappleNodes: self.ignore(ship.getDisableEvent()) grapple.removeNode() sagNode.removeNode() rope.removeNode() self.landedGrappleNodes = [] self.landedGrapples = [] def startAnimateLandedGrappleTask(self): self.stopAnimateLandedGrappleTask() taskMgr.add(self.animateLandedGrappleTask, self.uniqueName('animateGrapple')) def animateLandedGrappleTask(self, task): ship = None for (ship, grapple, anchorNode, sagNode, grappleLocator, rope) in self.landedGrappleNodes: grapplePos = grappleLocator.getPos(self.modelRoot) anchorPos = anchorNode.getPos(self.modelRoot) sagPos = (grapplePos + anchorPos) * 0.5 sagNode.setPos(sagPos) return task.cont def stopAnimateLandedGrappleTask(self): taskMgr.remove(self.uniqueName('animateGrapple'))
class Ship(DirectObject.DirectObject): notify = directNotify.newCategory('Ship') WantWake = config.GetBool('want-wake', 1) breakSfx1 = None breakSfx3 = None sinkingSfx1 = None sinkingSfx2 = None def __init__(self, shipClass, root, breakAnims, hitAnims, metaAnims, collisions, locators): self.modelRoot = root self.transRoot = NodePath('transRoot') self.modelRoot.reparentTo(self.transRoot) self.shipRoot = None self.shipClass = shipClass self.sailing = False self.sfxAlternativeStyle = False self.landedGrapples = [] self.landedGrappleNodes = [] self.breakAnims = breakAnims self.hitAnims = hitAnims self.metaAnims = metaAnims self.char = self.modelRoot.find('**/+Character') self.riggingControls = { } numBundles = self.char.node().getNumBundles() masts = self.breakAnims.keys() masts.sort() self.sinkTimeScale = 1.0 if self.breakSfx1 is None: Ship.breakSfx1 = loadSfx(SoundGlobals.SFX_SHIP_MAST_BREAK_01) if self.breakSfx3 == None: Ship.breakSfx3 = loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_MAST_BREAK) for (i, j) in enumerate(masts): bundle = self.char.node().getBundle(i + 1) ladderJoint = bundle.findChild('def_ladder_base') if ladderJoint: self.riggingControls[j] = ladderJoint continue self._Ship__breakIvals = { } for i in self.breakAnims: self._Ship__breakIvals[i] = Sequence(AnimControlInterval(self.breakAnims[i][0]), AnimControlInterval(self.breakAnims[i][1])) self._Ship__hitSailingIvals = { } for i in self.breakAnims: self._Ship__hitSailingIvals[i] = Sequence(AnimControlInterval(self.hitAnims[i][1]), Func(self.metaAnims['idle'].playAll)) self.lod = self.modelRoot.find('**/+LODNode') self.modelCollisions = collisions self.mastStates = [ 1, 1, 1, 1, 1] self.mastsHidden = False self._Ship__targetableCollisions = [] self.locators = locators self.center = None self.stern = None self.bow = None self.starboard = None self.port = None if self.sinkingSfx1 is None: Ship.sinkingSfx1 = loadSfx(SoundGlobals.SFX_SHIP_SINKING) Ship.sinkingSfx2 = loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_SHIP_SINK) self.sinkEffectsRoot = None self.sinkEffects = [] self.sinkTrack = None self.isSplit = False self.owner = None continue self.mastCollisions = _[1]([ (int(x.getTag('Mast Code')), x) for x in self.modelCollisions.findAllMatches('**/collision_masts') ]) self.sailCollisions = self.modelCollisions.findAllMatches('**/collision_sails') self.disableSails() if self.metaAnims['rolldown'].getNumAnims(): self._Ship__rollDownIval = AnimControlInterval(self.metaAnims['rolldown']) self.metaAnims['rolldown'].poseAll(0) else: self._Ship__rollDownIval = Interval('dummy', 0, 0) if self.metaAnims['rollup'].getNumAnims(): self._Ship__rollUpIval = AnimControlInterval(self.metaAnims['rollup']) else: self._Ship__rollUpIval = Interval('dummy', 0, 0) self.sailStartIval = Sequence(Func(self.stopIvals), Func(self.enableSails), self._Ship__rollDownIval, Func(self.metaAnims['idle'].loopAll, 1)) self.sailStopIval = Sequence(Func(self.stopIvals), self._Ship__rollUpIval, Func(self.disableSails), Func(self.metaAnims['tiedup'].playAll)) self.windTunnelEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stormEffect = None self.wake = None self.fogEffect = None self.leftSideFire = None self.leftSideSmoke = None self.leftSideFire2 = None self.leftSideSmoke2 = None self.rightSideFire = None self.rightSideSmoke = None self.rightSideFire2 = None self.rightSideSmoke2 = None self.rearSideFire = None self.rearSideSmoke = None self.fader = None self.idleBounds = self.modelRoot.getTightBounds() self.setupCollisions() def setOwner(self, owner, ownerIsModelRoot = False): self.owner = owner if self.owner: if ownerIsModelRoot: self.shipRoot = self.owner.getParent() self.owner.reparentTo(self.shipRoot) self.transRoot.reparentTo(self.owner) else: self.shipRoot = self.owner.attachNewNode('ShipRoot') self.transRoot.reparentTo(self.shipRoot) self.modelRoot.setPythonTag('ship', owner) def setupCollisions(self): self.modelCollisions.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) self.floors = self.modelCollisions.find('**/collision_floors') self.deck = self.modelCollisions.find('**/collision_deck') self.planeBarriers = self.modelCollisions.find('**/collision_planes') self.planeBarriers.stash() self.walls = self.modelCollisions.find('**/collision_walls') self.shipCollWall = self.modelCollisions.find('**/collision_shiptoship') self.shipCollWall.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) if self.owner: self.shipCollWall.setTag('shipId', str(self.owner.doId)) self.panels = self.modelCollisions.find('**/collision_panels') self.stashPlaneCollisions() def stashPlaneCollisions(self): self.planeBarriers.stash() def unstashPlaneCollisions(self): self.planeBarriers.unstash() def computeDimensions(self): if not self.center: self.center = self.modelRoot.attachNewNode('center') tb = self.idleBounds self.center.setPos((tb[0] + tb[1]) / 2.0) self.dimensions = tb[1] - tb[0] self.hullDimensions = tb[1] - tb[0] if not self.bow: self.bow = self.modelRoot.attachNewNode('bowPos') if not self.port: self.port = self.modelRoot.attachNewNode('portPos') if not self.starboard: self.starboard = self.modelRoot.attachNewNode('starboardPos') if not self.stern: self.stern = self.modelRoot.attachNewNode('sternPos') self.stern.setPos(Point3(0, tb[1][1], 0)) self.bow.setPos(Point3(0, tb[0][1], 0)) self.starboard.setPos(Point3(tb[1][0], 0, 0)) self.port.setPos(Point3(tb[0][0], 0, 0)) def getBoardingLocators(self): return self.locators.findAllMatches('**/boarding_spot_*;+s') def getPartNodes(self): if not self.center: self.computeDimensions() return (self.bow, self.port, self.starboard, self.stern) def disableOnDeckInteractions(self): pass def uniqueName(self, name): return name + '-%s' % id(self) def isInCrew(self, avId): if self.owner: return self.owner.isInCrew(avId) return False def dropMast(self, index): if index in self.breakAnims: self.breakAnims[index][1].playAll() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def dropRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze(TransformState.makeScale((0, 0, 0))) self.char.node().forceUpdate() def restoreRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze(TransformState.makeMat(self.riggingControls[index].getDefaultValue())) self.char.node().forceUpdate() def hideMasts(self): self.mastsHidden = True for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][1].playAll() self.dropRigging(i) self.mastStates[i] def showMasts(self): self.mastsHidden = False for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][0].poseAll(0) self.restoreRigging(i) self.mastStates[i] def breakMast(self, index): breakSfx = self.breakSfx1 if self.sfxAlternativeStyle: breakSfx = self.breakSfx3 base.playSfx(breakSfx, node = self.modelRoot, cutoff = 3000) if index in self.breakAnims: self._Ship__hitSailingIvals[index].pause() self._Ship__breakIvals[index].pause() self._Ship__breakIvals[index].start() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def restoreMast(self, index): if index in self.breakAnims: self._Ship__breakIvals[index].pause() self.breakAnims[index][0].poseAll(0) self.restoreRigging(index) self.mastCollisions[index].unstash() self.mastStates[index] = 1 def mastHit(self, index): if index in self.hitAnims: if self.mastStates[index] and not (self.mastsHidden): if not self.sailing: self.hitAnims[index][0].playAll() else: self._Ship__hitSailingIvals[index].start() def stopIvals(self): self._Ship__rollDownIval.pause() self._Ship__rollUpIval.pause() for ival in self._Ship__hitSailingIvals.values(): ival.pause() def playIdle(self): self.stopIvals() self.metaAnims['idle'].loopAll(1) def instantSailing(self): self.sailing = True self.enableSails() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['idle'].loopAll(1) def startSailing(self): self.stopIvals() if not self.sailing: self.sailing = True self.sailStopIval.pause() self.sailStartIval.pause() self.sailStartIval.start() def instantDocked(self): self.sailing = False self.disableSails() self.stopIvals() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['tiedup'].playAll() def stopSailing(self): if self.sailing: self.sailing = False self.sailStartIval.pause() self.sailStopIval.pause() self.sailStopIval.start() def playFullSailEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windTunnelEffect1: self.windTunnelEffect1 = Wind.getEffect() if self.windTunnelEffect1: self.windTunnelEffect1.reparentTo(self.center) self.windTunnelEffect1.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windTunnelEffect1.setScale(self.dimensions / 6.0) self.windTunnelEffect1.fadeTime = 2.0 self.windTunnelEffect1.setH(180) self.windTunnelEffect1.play() def playComeAboutEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windTunnelEffect2: self.windTunnelEffect2 = Wind.getEffect() if self.windTunnelEffect2: self.windTunnelEffect2.reparentTo(self.center) self.windTunnelEffect2.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.40000000000000002) self.windTunnelEffect2.setScale(self.dimensions / 10.0) self.windTunnelEffect2.fadeTime = 2.0 self.windTunnelEffect2.setH(0) self.windTunnelEffect2.play() def playRamEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windConeEffect: self.windConeEffect = WindBlurCone.getEffect() if self.windConeEffect: self.windConeEffect.reparentTo(self.bow) self.windConeEffect.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windConeEffect.setScale(self.dimensions / 3.0) self.windConeEffect.setPos(0, self.dimensions[1] / 18.0, self.dimensions[2] / 4.0) self.windConeEffect.fadeTime = 2.0 self.windConeEffect.startLoop() def playRechargeEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.powerRechargeEffect: self.powerRechargeEffect = ShipPowerRecharge.getEffect() if self.powerRechargeEffect: self.powerRechargeEffect.reparentTo(self.char) self.powerRechargeEffect.setEffectColor(Vec4(0.5, 0.5, 1, 1)) self.powerRechargeEffect.setScale(self.dimensions / 4.0) self.powerRechargeEffect.startLoop() def playSpawnEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.protectionEffect = ProtectionDome.getEffect() if self.protectionEffect: self.protectionEffect.reparentTo(self.shipRoot) self.protectionEffect.setScale(self.dimensions[1] / 15.0) self.protectionEffect.startLoop() def playTakeCoverEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.takeCoverEffect = FadingCard(loader.loadModel('models/textureCards/skillIcons').find('**/sail_take_cover'), color = Vec4(1, 1, 1, 1), fadeTime = 0.01, waitTime = 2.5, startScale = 0.94999999999999996, endScale = 1.0) if self.takeCoverEffect: self.takeCoverEffect.reparentTo(self.shipRoot) self.takeCoverEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.takeCoverEffect.setScale(self.dimensions[1] / 4.0) self.takeCoverEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffTakeCoverString) def playOpenFireEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.openFireEffect = FadingCard(loader.loadModel('models/textureCards/skillIcons').find('**/sail_openfire2'), color = Vec4(1, 1, 1, 1), fadeTime = 0.01, waitTime = 2.5, startScale = 0.94999999999999996, endScale = 1.0) if self.openFireEffect: self.openFireEffect.reparentTo(self.shipRoot) self.openFireEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.openFireEffect.setScale(self.dimensions[1] / 4.0) self.openFireEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffOpenFireString) def stopRamEffect(self): if self.windConeEffect: self.windConeEffect.stopLoop() def stopRechargeEffect(self): if self.powerRechargeEffect: self.powerRechargeEffect.stopLoop() def stopSpawnEffect(self): if self.protectionEffect: self.protectionEffect.stopLoop() def stopTakeCoverEffect(self): if self.takeCoverEffect: self.takeCoverEffect.stop() def stopOpenFireEffect(self): if self.openFireEffect: self.openFireEffect.stop() def playStormEffect(self): if not self.stormEffect: self.stormEffect = DarkMaelstrom(self.shipRoot) self.stormEffect.setZ(50) self.stormEffect.loop() compassFX = CompassEffect.make(render) self.stormEffect.setEffect(compassFX) def stopStormEffect(self): if self.stormEffect: self.stormEffect.destroy() self.stormEffect = None def createWake(self): if self.owner: ownerId = self.owner.doId else: ownerId = None if not base.cr.activeWorld: self.notify.warning('Ship %s is trying to create a wake without an active world.' % (ownerId,)) return None if not base.cr.activeWorld.getWater(): self.notify.warning('Ship %s is trying to create a wake without an ocean. (world: %s)' % (ownerId, base.cr.activeWorld)) return None if self.WantWake and base.cr.wantSpecialEffects and self.owner: self.removeWake() if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsMedium: if not hasattr(base.cr.activeWorld.getWater(), 'patch'): self.notify.error("Ship %s is in location %s,%s (%s[%s]).\nThis causes Attribute Error: 'NoneType' object has no attribute 'patch'\n" % (ownerId, self.getLocation()[0], self.getLocation()[1], type(self.getParentObj()), safeRepr(self.getParentObj()))) self.wake = Wake.getEffect() if self.wake: self.wake.attachToShip(self.owner) compassFX = CompassEffect.make(render) self.wake.setEffect(compassFX) self.wake.startAnimate(self.owner) def removeWake(self): if self.wake: self.wake.cleanUpEffect() self.wake = None def hasWake(self): return self.wake != None def cleanup(self): self.sinkingEnd() self.modelRoot.clearPythonTag('ship') self.breakAnims = { } self.metaAnims = { } self.lod = None self.modelRoot.detachNode() self.modelRoot = None self.locators = None self.center = None self.stern = None self.bow = None self.starboard = None self.port = None self.removeLandedGrapples() self.cleanupCollisions() self.char = None loader.unloadSfx(self.sinkingSfx1) loader.unloadSfx(self.sinkingSfx2) self.sinkingSfx1 = None self.sinkingSfx2 = None self.sinkEffectsRoot = None self.sinkEffects = [] self.owner = None self._Ship__rollDownIval.pause() self._Ship__rollDownIval = None self._Ship__rollUpIval.pause() self._Ship__rollUpIval = None self.sailStartIval.pause() self.sailStartIval = None self.sailStopIval.pause() self.sailStopIval = None for ival in self._Ship__breakIvals.values(): ival.pause() self._Ship__breakIvals = { } self.windTunneldEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stopStormEffect() self.removeWake() self.cleanupDarkFog() if self.fader: self.fader.pause() self.fader = None def cleanupCollisions(self): self.mastCollisions = None self._Ship__targetableCollisions = [] self.modelCollisions = None self.floors = None self.deck = None self.planeBarriers = None self.walls = None self.shipCollWall = None self.panels = None def demandMastStates(self, mastStates, maxHealth): for i in range(5): if maxHealth[i]: if mastStates[i]: self.restoreMast(i) else: self.dropMast(i) mastStates[i] def sinkingBegin(self): self.computeDimensions() self.disableOnDeckInteractions() self.removeWake() soundTrack = Sequence() sinkingSfx = self.sinkingSfx1 if self.sfxAlternativeStyle: sinkingSfx = self.sinkingSfx2 if sinkingSfx: soundTrack = Sequence(Func(base.playSfx, sinkingSfx, node = self.modelRoot, cutoff = 1000)) self.sinkTrack = Sequence() sinkParallel = Parallel() if self.isInCrew(localAvatar.doId): sinkParallel.append(Func(base.localAvatar.b_setGameState, 'Cutscene', localArgs = [ self.owner])) sinkParallel.append(self.getSinkCamIval()) sinkParallel.append(Sequence(Func(self.startSinkEffects), soundTrack, self.getSinkShipIval())) self.sinkTrack.append(sinkParallel) self.sinkTrack.append(Func(self.endSinkEffects)) if self.owner.isInCrew(localAvatar.doId): self.sinkTrack.append(Func(self.cleanupLocalSinking)) self.sinkTrack.start() def sinkingEnd(self): if self.sinkTrack: self.sinkTrack.finish() self.sinkTrack = None self.endSinkEffects() def getSinkShipIval(self): return Parallel(LerpPosInterval(self.modelRoot, 18.0 * self.sinkTimeScale, Vec3(0, 0, -1.5 * self.dimensions[2])), LerpHprInterval(self.modelRoot, 12.0 * self.sinkTimeScale, VBase3(self.modelRoot.getH(), self.modelRoot.getP() + 75, self.modelRoot.getR()))) def getSinkCamIval(self): camStartPos = Vec3(-4.0 * self.dimensions[0], -1.25 * self.dimensions[1], 40) camEndPos = Vec3(-4.0 * self.dimensions[0], self.dimensions[1], self.dimensions[2] / 2.0) if self.owner: self.owner.lookAtDummy.setPos(0, 0, self.center.getZ()) def camLookAtDummy(t): camera.lookAt(self.owner.lookAtDummy) return Parallel(Func(camera.reparentTo, self.owner.attachNewNode('cameraDummy')), LerpPosInterval(camera, 16.0 * self.sinkTimeScale, camEndPos, startPos = camStartPos, blendType = 'easeInOut'), LerpPosInterval(self.owner.lookAtDummy, 18.0 * self.sinkTimeScale, Vec3(0, 80, 0)), LerpF
class Ship(DirectObject.DirectObject): notify = directNotify.newCategory('Ship') WantWake = config.GetBool('want-wake', 1) breakSfx1 = None breakSfx3 = None sinkingSfx1 = None sinkingSfx2 = None def __init__(self, shipClass, root, breakAnims, hitAnims, metaAnims, collisions, locators): self.modelRoot = root self.transRoot = NodePath('transRoot') self.modelRoot.reparentTo(self.transRoot) self.shipRoot = None self.shipClass = shipClass self.sailing = False self.sfxAlternativeStyle = False self.breakAnims = breakAnims self.hitAnims = hitAnims self.metaAnims = metaAnims self.char = self.modelRoot.find('**/+Character') self.riggingControls = { } numBundles = self.char.node().getNumBundles() masts = self.breakAnims.keys() masts.sort() self.sinkTimeScale = 1.0 if self.breakSfx1 is None: Ship.breakSfx1 = loadSfx(SoundGlobals.SFX_SHIP_MAST_BREAK_01) if self.breakSfx3 == None: Ship.breakSfx3 = loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_MAST_BREAK) for (i, j) in enumerate(masts): bundle = self.char.node().getBundle(i + 1) ladderJoint = bundle.findChild('def_ladder_base') if ladderJoint: self.riggingControls[j] = ladderJoint continue self.__breakIvals = { } for i in self.breakAnims: self.__breakIvals[i] = Sequence(AnimControlInterval(self.breakAnims[i][0]), AnimControlInterval(self.breakAnims[i][1])) self.__hitSailingIvals = { } for i in self.breakAnims: self.__hitSailingIvals[i] = Sequence(AnimControlInterval(self.hitAnims[i][1]), Func(self.metaAnims['idle'].playAll)) self.lod = self.modelRoot.find('**/+LODNode') self.modelCollisions = collisions self.mastStates = [ 1, 1, 1, 1, 1] self.mastsHidden = False self.__targetableCollisions = [] self.locators = locators self.center = None self.stern = None self.bow = None self.starboard = None self.port = None if self.sinkingSfx1 is None: Ship.sinkingSfx1 = loadSfx(SoundGlobals.SFX_SHIP_SINKING) Ship.sinkingSfx2 = loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_SHIP_SINK) self.sinkEffectsRoot = None self.sinkEffects = [] self.sinkTrack = None self.isSplit = False self.owner = None self.mastCollisions = [(int(x.getTag('Mast Code')), x) for x in self.modelCollisions.findAllMatches('**/collision_masts')] self.sailCollisions = self.modelCollisions.findAllMatches('**/collision_sails') self.disableSails() if self.metaAnims['rolldown'].getNumAnims(): self.__rollDownIval = AnimControlInterval(self.metaAnims['rolldown']) self.metaAnims['rolldown'].poseAll(0) else: self.__rollDownIval = Interval('dummy', 0, 0) if self.metaAnims['rollup'].getNumAnims(): self.__rollUpIval = AnimControlInterval(self.metaAnims['rollup']) else: self.__rollUpIval = Interval('dummy', 0, 0) self.sailStartIval = Sequence(Func(self.stopIvals), Func(self.enableSails), self.__rollDownIval, Func(self.metaAnims['idle'].loopAll, 1)) self.sailStopIval = Sequence(Func(self.stopIvals), self.__rollUpIval, Func(self.disableSails), Func(self.metaAnims['tiedup'].playAll)) self.windTunnelEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stormEffect = None self.wake = None self.fogEffect = None self.leftSideFire = None self.leftSideSmoke = None self.leftSideFire2 = None self.leftSideSmoke2 = None self.rightSideFire = None self.rightSideSmoke = None self.rightSideFire2 = None self.rightSideSmoke2 = None self.rearSideFire = None self.rearSideSmoke = None self.fader = None self.idleBounds = self.modelRoot.getTightBounds() self.setupCollisions() def setOwner(self, owner, ownerIsModelRoot = False): self.owner = owner if self.owner: if ownerIsModelRoot: self.shipRoot = self.owner.getParent() self.owner.reparentTo(self.shipRoot) self.transRoot.reparentTo(self.owner) else: self.shipRoot = self.owner.attachNewNode('ShipRoot') self.transRoot.reparentTo(self.shipRoot) self.modelRoot.setPythonTag('ship', owner) def setupCollisions(self): self.modelCollisions.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) self.floors = self.modelCollisions.find('**/collision_floors') self.deck = self.modelCollisions.find('**/collision_deck') self.planeBarriers = self.modelCollisions.find('**/collision_planes') self.planeBarriers.stash() self.walls = self.modelCollisions.find('**/collision_walls') self.shipCollWall = self.modelCollisions.find('**/collision_shiptoship') self.shipCollWall.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) if self.owner: self.shipCollWall.setTag('shipId', str(self.owner.doId)) self.panels = self.modelCollisions.find('**/collision_panels') self.stashPlaneCollisions() def stashPlaneCollisions(self): self.planeBarriers.stash() def unstashPlaneCollisions(self): self.planeBarriers.unstash() def computeDimensions(self): if not self.center: self.center = self.modelRoot.attachNewNode('center') tb = self.idleBounds self.center.setPos((tb[0] + tb[1]) / 2.0) self.dimensions = tb[1] - tb[0] self.hullDimensions = tb[1] - tb[0] if not self.bow: self.bow = self.modelRoot.attachNewNode('bowPos') if not self.port: self.port = self.modelRoot.attachNewNode('portPos') if not self.starboard: self.starboard = self.modelRoot.attachNewNode('starboardPos') if not self.stern: self.stern = self.modelRoot.attachNewNode('sternPos') self.stern.setPos(Point3(0, tb[1][1], 0)) self.bow.setPos(Point3(0, tb[0][1], 0)) self.starboard.setPos(Point3(tb[1][0], 0, 0)) self.port.setPos(Point3(tb[0][0], 0, 0)) def getPartNodes(self): if not self.center: self.computeDimensions() return (self.bow, self.port, self.starboard, self.stern) def disableOnDeckInteractions(self): pass def uniqueName(self, name): return name + '-%s' % id(self) def isInCrew(self, avId): if self.owner: return self.owner.isInCrew(avId) return False def dropMast(self, index): if index in self.breakAnims: self.breakAnims[index][1].playAll() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def dropRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze(TransformState.makeScale((0, 0, 0))) self.char.node().forceUpdate() def restoreRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze(TransformState.makeMat(self.riggingControls[index].getDefaultValue())) self.char.node().forceUpdate() def hideMasts(self): self.mastsHidden = True for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][1].playAll() self.dropRigging(i) self.mastStates[i] def showMasts(self): self.mastsHidden = False for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][0].poseAll(0) self.restoreRigging(i) self.mastStates[i] def breakMast(self, index): breakSfx = self.breakSfx1 if self.sfxAlternativeStyle: breakSfx = self.breakSfx3 base.playSfx(breakSfx, node = self.modelRoot, cutoff = 3000) if index in self.breakAnims: self.__hitSailingIvals[index].pause() self.__breakIvals[index].pause() self.__breakIvals[index].start() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def restoreMast(self, index): if index in self.breakAnims: self.__breakIvals[index].pause() self.breakAnims[index][0].poseAll(0) self.restoreRigging(index) self.mastCollisions[index].unstash() self.mastStates[index] = 1 def mastHit(self, index): if index in self.hitAnims: if self.mastStates[index] and not (self.mastsHidden): if not self.sailing: self.hitAnims[index][0].playAll() else: self.__hitSailingIvals[index].start() def stopIvals(self): self.__rollDownIval.pause() self.__rollUpIval.pause() for ival in self.__hitSailingIvals.values(): ival.pause() def playIdle(self): self.stopIvals() self.metaAnims['idle'].loopAll(1) def instantSailing(self): self.sailing = True self.enableSails() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['idle'].loopAll(1) def startSailing(self): self.stopIvals() if not self.sailing: self.sailing = True self.sailStopIval.pause() self.sailStartIval.pause() self.sailStartIval.start() def instantDocked(self): self.sailing = False self.disableSails() self.stopIvals() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['tiedup'].playAll() def stopSailing(self): if self.sailing: self.sailing = False self.sailStartIval.pause() self.sailStopIval.pause() self.sailStopIval.start() def playFullSailEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windTunnelEffect1: self.windTunnelEffect1 = Wind.getEffect() if self.windTunnelEffect1: self.windTunnelEffect1.reparentTo(self.center) self.windTunnelEffect1.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windTunnelEffect1.setScale(self.dimensions / 6.0) self.windTunnelEffect1.fadeTime = 2.0 self.windTunnelEffect1.setH(180) self.windTunnelEffect1.play() def playComeAboutEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windTunnelEffect2: self.windTunnelEffect2 = Wind.getEffect() if self.windTunnelEffect2: self.windTunnelEffect2.reparentTo(self.center) self.windTunnelEffect2.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.40000000000000002) self.windTunnelEffect2.setScale(self.dimensions / 10.0) self.windTunnelEffect2.fadeTime = 2.0 self.windTunnelEffect2.setH(0) self.windTunnelEffect2.play() def playRamEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windConeEffect: self.windConeEffect = WindBlurCone.getEffect() if self.windConeEffect: self.windConeEffect.reparentTo(self.bow) self.windConeEffect.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windConeEffect.setScale(self.dimensions / 3.0) self.windConeEffect.setPos(0, self.dimensions[1] / 18.0, self.dimensions[2] / 4.0) self.windConeEffect.fadeTime = 2.0 self.windConeEffect.startLoop() def playRechargeEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.powerRechargeEffect: self.powerRechargeEffect = ShipPowerRecharge.getEffect() if self.powerRechargeEffect: self.powerRechargeEffect.reparentTo(self.char) self.powerRechargeEffect.setEffectColor(Vec4(0.5, 0.5, 1, 1)) self.powerRechargeEffect.setScale(self.dimensions / 4.0) self.powerRechargeEffect.startLoop() def playSpawnEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.protectionEffect = ProtectionDome.getEffect() if self.protectionEffect: self.protectionEffect.reparentTo(self.shipRoot) self.protectionEffect.setScale(self.dimensions[1] / 15.0) self.protectionEffect.startLoop() def playTakeCoverEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.takeCoverEffect = FadingCard(loader.loadModel('models/textureCards/skillIcons').find('**/sail_take_cover'), color = Vec4(1, 1, 1, 1), fadeTime = 0.01, waitTime = 2.5, startScale = 0.94999999999999996, endScale = 1.0) if self.takeCoverEffect: self.takeCoverEffect.reparentTo(self.shipRoot) self.takeCoverEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.takeCoverEffect.setScale(self.dimensions[1] / 4.0) self.takeCoverEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffTakeCoverString) def playOpenFireEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.openFireEffect = FadingCard(loader.loadModel('models/textureCards/skillIcons').find('**/sail_openfire2'), color = Vec4(1, 1, 1, 1), fadeTime = 0.01, waitTime = 2.5, startScale = 0.94999999999999996, endScale = 1.0) if self.openFireEffect: self.openFireEffect.reparentTo(self.shipRoot) self.openFireEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.openFireEffect.setScale(self.dimensions[1] / 4.0) self.openFireEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffOpenFireString) def stopRamEffect(self): if self.windConeEffect: self.windConeEffect.stopLoop() def stopRechargeEffect(self): if self.powerRechargeEffect: self.powerRechargeEffect.stopLoop() def stopSpawnEffect(self): if self.protectionEffect: self.protectionEffect.stopLoop() def stopTakeCoverEffect(self): if self.takeCoverEffect: self.takeCoverEffect.stop() def stopOpenFireEffect(self): if self.openFireEffect: self.openFireEffect.stop() def playStormEffect(self): if not self.stormEffect: self.stormEffect = DarkMaelstrom(self.shipRoot) self.stormEffect.setZ(50) self.stormEffect.loop() compassFX = CompassEffect.make(render) self.stormEffect.setEffect(compassFX) def stopStormEffect(self): if self.stormEffect: self.stormEffect.destroy() self.stormEffect = None def createWake(self): if self.owner: ownerId = self.owner.doId else: ownerId = None if not base.cr.activeWorld: self.notify.warning('Ship %s is trying to create a wake without an active world.' % (ownerId,)) return None if not base.cr.activeWorld.getWater(): self.notify.warning('Ship %s is trying to create a wake without an ocean. (world: %s)' % (ownerId, base.cr.activeWorld)) return None if self.WantWake and base.cr.wantSpecialEffects and self.owner: self.removeWake() if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsMedium: if not hasattr(base.cr.activeWorld.getWater(), 'patch'): self.notify.error("Ship %s is in location %s,%s (%s[%s]).\nThis causes Attribute Error: 'NoneType' object has no attribute 'patch'\n" % (ownerId, self.getLocation()[0], self.getLocation()[1], type(self.getParentObj()), safeRepr(self.getParentObj()))) self.wake = Wake.getEffect() if self.wake: self.wake.attachToShip(self.owner) compassFX = CompassEffect.make(render) self.wake.setEffect(compassFX) self.wake.startAnimate(self.owner) def removeWake(self): if self.wake: self.wake.cleanUpEffect() self.wake = None def hasWake(self): return self.wake != None def cleanup(self): self.sinkingEnd() self.modelRoot.clearPythonTag('ship') self.breakAnims = { } self.metaAnims = { } self.lod = None self.modelRoot.detachNode() self.modelRoot = None self.locators = None self.center = None self.stern = None self.bow = None self.starboard = None self.port = None self.cleanupCollisions() self.char = None loader.unloadSfx(self.sinkingSfx1) loader.unloadSfx(self.sinkingSfx2) self.sinkingSfx1 = None self.sinkingSfx2 = None self.sinkEffectsRoot = None self.sinkEffects = [] self.owner = None self.__rollDownIval.pause() self.__rollDownIval = None self.__rollUpIval.pause() self.__rollUpIval = None self.sailStartIval.pause() self.sailStartIval = None self.sailStopIval.pause() self.sailStopIval = None for ival in self.__breakIvals.values(): ival.pause() self.__breakIvals = { } self.windTunneldEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stopStormEffect() self.removeWake() self.cleanupDarkFog() if self.fader: self.fader.pause() self.fader = None def cleanupCollisions(self): self.mastCollisions = None self.__targetableCollisions = [] self.modelCollisions = None self.floors = None self.deck = None self.planeBarriers = None self.walls = None self.shipCollWall = None self.panels = None def demandMastStates(self, mastStates, maxHealth): for i in range(5): if maxHealth[i]: if mastStates[i]: self.restoreMast(i) else: self.dropMast(i) mastStates[i] def sinkingBegin(self): self.computeDimensions() self.disableOnDeckInteractions() self.removeWake() soundTrack = Sequence() sinkingSfx = self.sinkingSfx1 if self.sfxAlternativeStyle: sinkingSfx = self.sinkingSfx2 if sinkingSfx: soundTrack = Sequence(Func(base.playSfx, sinkingSfx, node = self.modelRoot, cutoff = 1000)) self.sinkTrack = Sequence() sinkParallel = Parallel() if self.isInCrew(localAvatar.doId): sinkParallel.append(Func(base.localAvatar.b_setGameState, 'Cutscene', localArgs = [ self.owner])) sinkParallel.append(self.getSinkCamIval()) sinkParallel.append(Sequence(Func(self.startSinkEffects), soundTrack, self.getSinkShipIval())) self.sinkTrack.append(sinkParallel) self.sinkTrack.append(Func(self.endSinkEffects)) if self.owner.isInCrew(localAvatar.doId): self.sinkTrack.append(Func(self.cleanupLocalSinking)) self.sinkTrack.start() def sinkingEnd(self): if self.sinkTrack: self.sinkTrack.finish() self.sinkTrack = None def getSinkShipIval(self): return Parallel(LerpPosInterval(self.modelRoot, 18.0 * self.sinkTimeScale, Vec3(0, 0, -1.5 * self.dimensions[2])), LerpHprInterval(self.modelRoot, 12.0 * self.sinkTimeScale, VBase3(self.modelRoot.getH(), self.modelRoot.getP() + 75, self.modelRoot.getR()))) def getSinkCamIval(self): camStartPos = Vec3(-4.0 * self.dimensions[0], -1.25 * self.dimensions[1], 40) camEndPos = Vec3(-4.0 * self.dimensions[0], self.dimensions[1], self.dimensions[2] / 2.0) if self.owner: self.owner.lookAtDummy.setPos(0, 0, self.center.getZ()) def camLookAtDummy(t): camera.lookAt(self.owner.lookAtDummy) return Parallel(Func(camera.reparentTo, self.owner.attachNewNode('cameraDummy')), LerpPosInterval(camera, 16.0 * self.sinkTimeScale, camEndPos, startPos = camStartPos, blendType = 'easeInOut'), LerpPosInterval(self.owner.lookAtDummy, 18.0 * self.sinkTimeScale, Vec3(0, 80, 0)), LerpFunc(camLookAtDummy, 18.0 * self.sinkTimeScale)) def startSinkEffects(self): if not self.sinkEffectsRoot: self.sinkEffectsRoot = self.shipRoot.attachNewNode('sinkEffectsRoot') self.sinkEffectsRoot.setY(self.center.getY()) if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsMedium: ripples = WaterWakes.getEffect() if ripples: scale = self.hullDimensions ripples.duration = ripples.duration * self.sinkTimeScale ripples.reparentTo(self.sinkEffectsRoot) ripples.setScale(scale[0] / 6, scale[1] / 10, scale[2] / 5) ripples.play() self.sinkEffects.append(ripples) if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsHigh: mist = WaterMist.getEffect() if mist: mist.sinkTimeScale = self.sinkTimeScale mist.reparentTo(self.sinkEffectsRoot) mist.setScale(self.hullDimensions / 50.0) mist.setEffectScale(1.0) mist.setZ(-5.0) mist.play() self.sinkEffects.append(mist) taskMgr.add(self.updateSinkEffects, self.uniqueName('updateSinkEffects')) def endSinkEffects(self): taskMgr.remove(self.uniqueName('updateSinkEffects')) for effect in self.sinkEffects: effect.stopLoop() self.sinkEffects = [] def updateSinkEffects(self, task): pos = self.modelRoot.getPos(render) if base.cr.activeWorld and base.cr.activeWorld.getWater(): waterHeight = base.cr.activeWorld.getWater().calcHeight(pos[0], pos[1], 0, render) self.sinkEffectsRoot.setZ(render, waterHeight) self.sinkEffectsRoot.setY(self.sinkEffectsRoot.getY() - 0.14999999999999999) return task.cont # failed block decompiling. FIXME def cleanupLocalSinking(self): base.transitions.fadeOut() base.transitions.letterboxOff() base.cr.interactionMgr.unlock() base.cr.interactionMgr.start() base.musicMgr.requestCurMusicFadeOut() def undoSinking(self): self.modelRoot.setPosHpr(0, 0, 0, 0, 0, 0) if self.isSplit: self.clipParent1.setPosHpr(0, 0, 0, 0, 0, 0) self.clipParent2.setPosHpr(0, 0, 0, 0, 0, 0) def splitShip(self): if not self.isSplit: self.isSplit = True self.modelGeom.instanceTo(self.clipParent2) planeNode1 = NodePath(PlaneNode('planeNode1', Plane(Vec4(0, 1, 0, 0)))) planeNode1.reparentTo(self.clipParent1) planeNode1.setY(ShipGlobals.getShipSplitOffset(self.shipClass)) self.clipParent1.setClipPlane(planeNode1) planeNode2 = NodePath(PlaneNode('planeNode2', Plane(Vec4(0, -1, 0, 0)))) planeNode2.reparentTo(self.clipParent2) planeNode2.setY(ShipGlobals.getShipSplitOffset(self.shipClass)) self.clipParent2.setClipPlane(planeNode2) def destroy(self): self.cleanup() def manufactureCannons(self, detailLevel = 2): stats = ShipGlobals.getShipConfig(self.shipClass) cannonConfig = stats['cannons'] leftConfig = stats['leftBroadsides'] rightConfig = stats['rightBroadsides'] cannons = { } for i in range(len(cannonConfig)): cannonType = cannonConfig[i] cannon = Cannon.Cannon(None) cannon.loadModel(None, cannonType) cannons[i] = [ cannon, 0] broadsides = [ [ [], []], None] for i in range(len(leftConfig)): if leftConfig[i] > 0: cannon = CannonPort.CannonPort(leftConfig[i], 0, i) broadsides[0][0].append(cannon) continue broadsides[0][0].append(None) for i in range(len(rightConfig)): if rightConfig[i] > 0: cannon = CannonPort.CannonPort(rightConfig[i], 1, i) broadsides[0][1].append(cannon) continue broadsides[0][1].append(None) self.setupCannons(cannons, broadsides, detailLevel) def setupCannons(self, cannons, broadsides, detailLevel = 2): self.cannons = { } if detailLevel in (1, 2): self.cannonsHigh = self.lod.getChild(0).attachNewNode(ModelNode('cannons')) self.cannonsMed = self.lod.getChild(1).attachNewNode(ModelNode('cannons')) self.cannonsLow = self.lod.getChild(2).attachNewNode(ModelNode('cannons')) else: self.cannonsHigh = self.lod.getChild(0).attachNewNode(ModelNode('cannons')) self.cannonsMed = self.lod.getChild(1).attachNewNode(ModelNode('cannons')) self.cannonColl = self.modelCollisions.attachNewNode('cannons') for i in cannons: transform = self.locators.find('**/cannon_%s;+s' % i).getTransform(self.locators) cannon = cannons[i][0] cannon.root.setTransform(transform) cannon.root.flattenLight() char = cannon.root.node() bundle = char.getBundle(0) if detailLevel in (1, 2): high = cannon.lod.getChild(0) med = cannon.lod.getChild(1) low = cannon.lod.getChild(2) self.char.node().combineWith(char) high.reparentTo(self.cannonsHigh) med.reparentTo(self.cannonsMed) low.reparentTo(self.cannonsLow) else: low = cannon.lod.getChild(2) superlow = cannon.lod.getChild(3) self.char.node().combineWith(char) low.reparentTo(self.cannonsHigh) superlow.reparentTo(self.cannonsMed) cannon.propCollisions.setTransform(transform) cannon.propCollisions.reparentTo(self.cannonColl) cannon.hNode.reparentTo(self.locators.find('**/cannon_%s;+s' % i)) self.cannons[i] = cannon if broadsides: broadsideLeft = broadsides[0][0] broadsideRight = broadsides[0][1] self.broadsides = [ broadsideLeft, broadsideRight] leftRoot = self.locators.find('**/broadsides_left') rightRoot = self.locators.find('**/broadsides_right') for (broadsideSet, side) in zip(broadsides[0], ((leftRoot, 'left'), (rightRoot, 'right'))): for i in range(len(broadsideSet)): port = broadsideSet[i] if not port: continue locator = side[0].find('broadside_%s_%s;+s' % (side[1], i)) transform = locator.getTransform(self.locators) port.locator = locator port.root.setTransform(transform) port.root.flattenLight() char = port.root.node() bundle = char.getBundle(0) if detailLevel in (1, 2): high = port.lod.getChild(0) med = port.lod.getChild(1) low = port.lod.getChild(2) self.char.node().combineWith(char) high.reparentTo(self.cannonsHigh) med.reparentTo(self.cannonsMed) low.reparentTo(self.cannonsLow) continue geom = port.lod.getChild(2) self.char.node().combineWith(char) geom.copyTo(self.cannonsHigh) geom.copyTo(self.cannonsMed) else: self.broadsides = [] self.cannonsHigh.flattenStrong() self.cannonsMed.flattenStrong() if detailLevel != 0: self.cannonsLow.flattenStrong() for cannon in self.cannons.values(): cannon.finalize() for side in self.broadsides: for port in side: if port: port.finalize() continue def updateDamageEffects(self, health, rear, left, right): effectSettings = base.options.getSpecialEffectsSetting() if left <= 30.0: locator = self.locators.find('**/location_fire_1') scale = locator.getScale()[0] / 1.75 + (locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if not self.leftSideFire: self.leftSideFire = ShipFire.getEffect() if self.leftSideFire: self.leftSideFire.reparentTo(self.modelRoot) self.leftSideFire.setPos(locator.getPos()) self.leftSideFire.setHpr(80, -15, 0) self.leftSideFire.startLoop() if self.leftSideFire: self.leftSideFire.setEffectScale(scale) if not (self.leftSideSmoke) and effectSettings >= base.options.SpecialEffectsMedium: self.leftSideSmoke = ShipSmoke.getEffect() if self.leftSideSmoke: self.leftSideSmoke.reparentTo(self.modelRoot) self.leftSideSmoke.setPos(locator.getPos()) self.leftSideSmoke.setHpr(90, -15, 0) self.leftSideSmoke.startLoop() if self.leftSideSmoke: self.leftSideSmoke.setEffectScale(scale) elif self.leftSideFire: self.leftSideFire.stopLoop() self.leftSideFire = None if self.leftSideSmoke: self.leftSideSmoke.stopLoop() self.leftSideSmoke = None if left <= 0.0 and effectSettings >= base.options.SpecialEffectsMedium: locator = self.locators.find('**/location_fire_3') if locator: scale = locator.getScale()[0] / 1.75 + (locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if locator and not (self.leftSideFire2): self.leftSideFire2 = ShipFire.getEffect() if self.leftSideFire2: self.leftSideFire2.reparentTo(self.modelRoot) self.leftSideFire2.setPos(locator.getPos()) self.leftSideFire2.setHpr(90, -10, 10) self.leftSideFire2.startLoop() if self.leftSideFire2: self.leftSideFire2.setEffectScale(scale) if locator and not (self.leftSideSmoke2): self.leftSideSmoke2 = ShipSmoke.getEffect() if self.leftSideSmoke2: self.leftSideSmoke2.reparentTo(self.modelRoot) self.leftSideSmoke2.setPos(locator.getPos()) self.leftSideSmoke2.setHpr(90, -15, 0) self.leftSideSmoke2.startLoop() if self.leftSideSmoke2: self.leftSideSmoke2.setEffectScale(scale) elif self.leftSideFire2: self.leftSideFire2.stopLoop() self.leftSideFire2 = None if self.leftSideSmoke2: self.leftSideSmoke2.stopLoop() self.leftSideSmoke2 = None if right <= 30.0: locator = self.locators.find('**/location_fire_2') scale = locator.getScale()[0] / 1.75 + (locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if not self.rightSideFire: self.rightSideFire = ShipFire.getEffect() if self.rightSideFire: self.rightSideFire.reparentTo(self.modelRoot) self.rightSideFire.setPos(locator.getPos()) self.rightSideFire.setHpr(100, 15, 0) self.rightSideFire.startLoop() if self.rightSideFire: self.rightSideFire.setEffectScale(scale) if not (self.rightSideSmoke) and effectSettings >= base.options.SpecialEffectsMedium: self.rightSideSmoke = ShipSmoke.getEffect() if self.rightSideSmoke: self.rightSideSmoke.reparentTo(self.modelRoot) self.rightSideSmoke.setPos(locator.getPos()) self.rightSideSmoke.setHpr(90, 15, 0) self.rightSideSmoke.startLoop() if self.rightSideSmoke: self.rightSideSmoke.setEffectScale(scale) elif self.rightSideFire: self.rightSideFire.stopLoop() self.rightSideFire = None if self.rightSideSmoke: self.rightSideSmoke.stopLoop() self.rightSideSmoke = None if right <= 0.0 and effectSettings >= base.options.SpecialEffectsMedium: locator = self.locators.find('**/location_fire_4') if locator: scale = locator.getScale()[0] / 1.75 + (locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if locator and not (self.rightSideFire2): self.rightSideFire2 = ShipFire.getEffect() if self.rightSideFire2: self.rightSideFire2.reparentTo(self.modelRoot) self.rightSideFire2.setPos(locator.getPos()) self.rightSideFire2.setHpr(90, 10, 10) self.rightSideFire2.startLoop() if self.rightSideFire2: self.rightSideFire2.setEffectScale(scale) if locator and not (self.rightSideSmoke2): self.rightSideSmoke2 = ShipSmoke.getEffect() if self.rightSideSmoke2: self.rightSideSmoke2.reparentTo(self.modelRoot) self.rightSideSmoke2.setPos(locator.getPos()) self.rightSideSmoke2.setHpr(90, 15, 0) self.rightSideSmoke2.startLoop() if self.rightSideSmoke2: self.rightSideSmoke2.setEffectScale(scale) elif self.rightSideFire2: self.rightSideFire2.stopLoop() self.rightSideFire2 = None if self.rightSideSmoke2: self.rightSideSmoke2.stopLoop() self.rightSideSmoke2 = None if rear <= 30.0: locator = self.locators.findAllMatches('**/location_fire_0')[0] scale = locator.getScale()[0] / 1.75 + (locator.getScale()[0] / 2.0) * (1.0 - health / 100.0) if not self.rearSideFire: self.rearSideFire = ShipFire.getEffect() if self.rearSideFire: self.rearSideFire.reparentTo(self.modelRoot) self.rearSideFire.setPos(locator.getPos()) self.rearSideFire.setHpr(0, 20, 0) self.rearSideFire.startLoop() if self.rearSideFire: self.rearSideFire.setEffectScale(scale) if not (self.rearSideSmoke) and effectSettings >= base.options.SpecialEffectsMedium: self.rearSideSmoke = ShipSmoke.getEffect() if self.rearSideSmoke: self.rearSideSmoke.reparentTo(self.modelRoot) self.rearSideSmoke.setPos(locator.getPos()) self.rearSideSmoke.setHpr(0, 20, 0) self.rearSideSmoke.startLoop() if self.rearSideSmoke: self.rearSideSmoke.setEffectScale(scale) elif self.rearSideFire: self.rearSideFire.stopLoop() self.rearSideFire = None if self.rearSideSmoke: self.rearSideSmoke.stopLoop() self.rearSideSmoke = None def cleanUpDamageEffects(self): if self.leftSideFire: self.leftSideFire.cleanUpEffect() self.leftSideFire = None if self.leftSideSmoke: self.leftSideSmoke.cleanUpEffect() self.leftSideSmoke = None if self.leftSideFire2: self.leftSideFire2.cleanUpEffect() self.leftSideFire2 = None if self.leftSideSmoke2: self.leftSideSmoke2.cleanUpEffect() self.leftSideSmoke2 = None if self.rightSideFire: self.rightSideFire.cleanUpEffect() self.rightSideFire = None if self.rightSideSmoke: self.rightSideSmoke.cleanUpEffect() self.rightSideSmoke = None if self.rightSideFire2: self.rightSideFire2.cleanUpEffect() self.rightSideFire2 = None if self.rightSideSmoke2: self.rightSideSmoke2.cleanUpEffect() self.rightSideSmoke2 = None if self.rearSideFire: self.rearSideFire.cleanUpEffect() self.rearSideFire = None if self.rearSideSmoke: self.rearSideSmoke.cleanUpEffect() self.rearSideSmoke = None def startDarkFog(self, offset = None): self.fogEffect = DarkShipFog.getEffect() if self.fogEffect: self.fogEffect.reparentTo(self.shipRoot) if offset: self.fogEffect.setY(self.fogEffect, offset) self.fogEffect.setZ(self.fogEffect, 50) self.fogEffect.startLoop() def stopDarkFog(self): if self.fogEffect: self.fogEffect.stopLoop() self.fogEffect = None def cleanupDarkFog(self): if self.fogEffect: self.fogEffect.destroy() self.fogEffect = None def fadeIn(self, duration = 2.0): if self.fader: self.fader.finish() self.fader = None self.modelRoot.setTransparency(1) self.fader = Sequence(self.modelRoot.colorScaleInterval(duration, Vec4(1, 1, 1, 1), startColorScale = Vec4(0, 0, 0, 0)), Func(self.modelRoot.clearTransparency)) self.fader.start() def fadeOut(self, duration = 2.0): if self.fader: self.fader.finish() self.fader = None self.modelRoot.setTransparency(1) self.fader = Sequence(self.modelRoot.colorScaleInterval(duration / 2.0, Vec4(0, 0, 0, 0), startColorScale = Vec4(1, 1, 1, 1)), Func(self.modelRoot.clearTransparency)) self.fader.start() def enableSails(self): self.sailCollisions.unstash() def disableSails(self): self.sailCollisions.stash() def forceLOD(self, index): self.lod.node().forceSwitch(index) def clearForceLOD(self): self.lod.node().clearForceSwitch() def getRope(self, thickness = 0.14999999999999999): rope = Rope() rope.ropeNode.setRenderMode(RopeNode.RMTube) rope.ropeNode.setNumSlices(10) rope.ropeNode.setUvMode(RopeNode.UVDistance) rope.ropeNode.setUvDirection(1) rope.ropeNode.setUvScale(0.25) rope.ropeNode.setThickness(thickness) ropePile = loader.loadModel('models/char/rope_high') ropeTex = ropePile.findTexture('rope_single_omit') ropePile.removeNode() rope.setTexture(ropeTex) rope.setLightOff() rope.setColorScale(0.5, 0.5, 0.5, 1) return rope getRope = report(types = [ 'frameCount', 'deltaStamp'], dConfigParam = 'shipboard')(getRope) def setLandedGrapples(self, ship, landedGrapples): for grapple in landedGrapples: if grapple not in self.landedGrapples: self.createLandedGrapple(ship, grapple[1]) continue self.landedGrapples = landedGrapples self.startAnimateLandedGrappleTask() def createLandedGrapple(self, otherShip, targetId): self.accept(otherShip.getDisableEvent(), self.removeLandedGrapples) otherShipRelX = otherShip.model.modelRoot.getX(self.modelRoot) grappleStr = '**/grapple_right*' anchorOffset = Vec3(0, 0, -1) if otherShipRelX < 0: grappleStr = '**/grapple_left*' anchorNode = random.choice(self.locators.findAllMatches(grappleStr)) anchorPos = anchorNode.getPos(self.modelRoot) + anchorOffset side = 'right' if self.modelRoot.getX(otherShip.model.modelRoot) < 0: side = 'left' targetStr = '**/grapple_%s_%s' % (side, targetId) if targetId >= 0: grappleLocator = otherShip.findLocator(targetStr) else: grappleLocator = random.choice(otherShip.findLocators('**/grapple_%s_*' % (side,))) rope = self.getRope(thickness = 0.5) grapplePos = grappleLocator.getPos(self.modelRoot) sagNode = self.modelRoot.attachNewNode('sagNode') sagNode.setPos((grapplePos + anchorPos) * 0.5) grapple = loader.loadModel('models/ammunition/GrapplingHook') grapple.reparentTo(otherShip.model.modelRoot) posHpr = (grappleLocator, 2, 0, -2.5, -270, -350, 80) if targetStr.find('right') > 0: posHpr = (grappleLocator, 1, 0, -1.5, 90, -40, -180) grapple.setPosHpr(*posHpr) rope.reparentTo(grapple) rope.setup(3, ((None, Point3(0)), (sagNode, Point3(0)), (self.modelRoot, anchorPos))) self.landedGrappleNodes.append([ otherShip, grapple, anchorNode, sagNode, grappleLocator, rope]) def removeLandedGrapples(self): self.stopAnimateLandedGrappleTask() for (ship, grapple, anchorNode, sagNode, grappleLocator, rope) in self.landedGrappleNodes: self.ignore(ship.getDisableEvent()) grapple.removeNode() sagNode.removeNode() rope.removeNode() self.landedGrappleNodes = [] self.landedGrapples = [] def startAnimateLandedGrappleTask(self): self.stopAnimateLandedGrappleTask() taskMgr.add(self.animateLandedGrappleTask, self.uniqueName('animateGrapple')) def animateLandedGrappleTask(self, task): ship = None for (ship, grapple, anchorNode, sagNode, grappleLocator, rope) in self.landedGrappleNodes: grapplePos = grappleLocator.getPos(self.modelRoot) anchorPos = anchorNode.getPos(self.modelRoot) sagPos = (grapplePos + anchorPos) * 0.5 sagNode.setPos(sagPos) return task.cont def stopAnimateLandedGrappleTask(self): taskMgr.remove(self.uniqueName('animateGrapple'))
class Ship(DirectObject.DirectObject): notify = directNotify.newCategory('Ship') WantWake = config.GetBool('want-wake', 1) breakSfx1 = None breakSfx3 = None sinkingSfx1 = None sinkingSfx2 = None def __init__(self, shipClass, root, breakAnims, hitAnims, metaAnims, collisions, locators): self.modelRoot = root self.transRoot = NodePath('transRoot') self.modelRoot.reparentTo(self.transRoot) self.shipRoot = None self.shipClass = shipClass self.sailing = False self.sfxAlternativeStyle = False self.breakAnims = breakAnims self.hitAnims = hitAnims self.metaAnims = metaAnims self.char = self.modelRoot.find('**/+Character') self.riggingControls = { } numBundles = self.char.node().getNumBundles() masts = self.breakAnims.keys() masts.sort() self.sinkTimeScale = 1.0 if self.breakSfx1 is None: Ship.breakSfx1 = loadSfx(SoundGlobals.SFX_SHIP_MAST_BREAK_01) if self.breakSfx3 == None: Ship.breakSfx3 = loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_MAST_BREAK) for (i, j) in enumerate(masts): bundle = self.char.node().getBundle(i + 1) ladderJoint = bundle.findChild('def_ladder_base') if ladderJoint: self.riggingControls[j] = ladderJoint continue self._Ship__breakIvals = { } for i in self.breakAnims: self._Ship__breakIvals[i] = Sequence(AnimControlInterval(self.breakAnims[i][0]), AnimControlInterval(self.breakAnims[i][1])) self._Ship__hitSailingIvals = { } for i in self.breakAnims: self._Ship__hitSailingIvals[i] = Sequence(AnimControlInterval(self.hitAnims[i][1]), Func(self.metaAnims['idle'].playAll)) self.lod = self.modelRoot.find('**/+LODNode') self.modelCollisions = collisions self.mastStates = [ 1, 1, 1, 1, 1] self.mastsHidden = False self._Ship__targetableCollisions = [] self.locators = locators self.center = None self.stern = None self.bow = None self.starboard = None self.port = None if self.sinkingSfx1 is None: Ship.sinkingSfx1 = loadSfx(SoundGlobals.SFX_SHIP_SINKING) Ship.sinkingSfx2 = loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_SHIP_SINK) self.sinkEffectsRoot = None self.sinkEffects = [] self.sinkTrack = None self.isSplit = False self.owner = None continue self.mastCollisions = _[1]([ (int(x.getTag('Mast Code')), x) for x in self.modelCollisions.findAllMatches('**/collision_masts') ]) self.sailCollisions = self.modelCollisions.findAllMatches('**/collision_sails') self.disableSails() if self.metaAnims['rolldown'].getNumAnims(): self._Ship__rollDownIval = AnimControlInterval(self.metaAnims['rolldown']) self.metaAnims['rolldown'].poseAll(0) else: self._Ship__rollDownIval = Interval('dummy', 0, 0) if self.metaAnims['rollup'].getNumAnims(): self._Ship__rollUpIval = AnimControlInterval(self.metaAnims['rollup']) else: self._Ship__rollUpIval = Interval('dummy', 0, 0) self.sailStartIval = Sequence(Func(self.stopIvals), Func(self.enableSails), self._Ship__rollDownIval, Func(self.metaAnims['idle'].loopAll, 1)) self.sailStopIval = Sequence(Func(self.stopIvals), self._Ship__rollUpIval, Func(self.disableSails), Func(self.metaAnims['tiedup'].playAll)) self.windTunnelEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stormEffect = None self.wake = None self.fogEffect = None self.leftSideFire = None self.leftSideSmoke = None self.leftSideFire2 = None self.leftSideSmoke2 = None self.rightSideFire = None self.rightSideSmoke = None self.rightSideFire2 = None self.rightSideSmoke2 = None self.rearSideFire = None self.rearSideSmoke = None self.fader = None self.idleBounds = self.modelRoot.getTightBounds() self.setupCollisions() def setOwner(self, owner, ownerIsModelRoot = False): self.owner = owner if self.owner: if ownerIsModelRoot: self.shipRoot = self.owner.getParent() self.owner.reparentTo(self.shipRoot) self.transRoot.reparentTo(self.owner) else: self.shipRoot = self.owner.attachNewNode('ShipRoot') self.transRoot.reparentTo(self.shipRoot) self.modelRoot.setPythonTag('ship', owner) def setupCollisions(self): self.modelCollisions.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) self.floors = self.modelCollisions.find('**/collision_floors') self.deck = self.modelCollisions.find('**/collision_deck') self.planeBarriers = self.modelCollisions.find('**/collision_planes') self.planeBarriers.stash() self.walls = self.modelCollisions.find('**/collision_walls') self.shipCollWall = self.modelCollisions.find('**/collision_shiptoship') self.shipCollWall.setTag('objType', str(PiratesGlobals.COLL_NEWSHIP)) if self.owner: self.shipCollWall.setTag('shipId', str(self.owner.doId)) self.panels = self.modelCollisions.find('**/collision_panels') self.stashPlaneCollisions() def stashPlaneCollisions(self): self.planeBarriers.stash() def unstashPlaneCollisions(self): self.planeBarriers.unstash() def computeDimensions(self): if not self.center: self.center = self.modelRoot.attachNewNode('center') tb = self.idleBounds self.center.setPos((tb[0] + tb[1]) / 2.0) self.dimensions = tb[1] - tb[0] self.hullDimensions = tb[1] - tb[0] if not self.bow: self.bow = self.modelRoot.attachNewNode('bowPos') if not self.port: self.port = self.modelRoot.attachNewNode('portPos') if not self.starboard: self.starboard = self.modelRoot.attachNewNode('starboardPos') if not self.stern: self.stern = self.modelRoot.attachNewNode('sternPos') self.stern.setPos(Point3(0, tb[1][1], 0)) self.bow.setPos(Point3(0, tb[0][1], 0)) self.starboard.setPos(Point3(tb[1][0], 0, 0)) self.port.setPos(Point3(tb[0][0], 0, 0)) def getPartNodes(self): if not self.center: self.computeDimensions() return (self.bow, self.port, self.starboard, self.stern) def disableOnDeckInteractions(self): pass def uniqueName(self, name): return name + '-%s' % id(self) def isInCrew(self, avId): if self.owner: return self.owner.isInCrew(avId) return False def dropMast(self, index): if index in self.breakAnims: self.breakAnims[index][1].playAll() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def dropRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze(TransformState.makeScale((0, 0, 0))) self.char.node().forceUpdate() def restoreRigging(self, index): if index in self.riggingControls: self.riggingControls[index].applyFreeze(TransformState.makeMat(self.riggingControls[index].getDefaultValue())) self.char.node().forceUpdate() def hideMasts(self): self.mastsHidden = True for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][1].playAll() self.dropRigging(i) self.mastStates[i] def showMasts(self): self.mastsHidden = False for i in range(5): if i in self.breakAnims: if self.mastStates[i]: self.breakAnims[i][0].poseAll(0) self.restoreRigging(i) self.mastStates[i] def breakMast(self, index): breakSfx = self.breakSfx1 if self.sfxAlternativeStyle: breakSfx = self.breakSfx3 base.playSfx(breakSfx, node = self.modelRoot, cutoff = 3000) if index in self.breakAnims: self._Ship__hitSailingIvals[index].pause() self._Ship__breakIvals[index].pause() self._Ship__breakIvals[index].start() self.dropRigging(index) self.mastCollisions[index].stash() self.mastStates[index] = 0 def restoreMast(self, index): if index in self.breakAnims: self._Ship__breakIvals[index].pause() self.breakAnims[index][0].poseAll(0) self.restoreRigging(index) self.mastCollisions[index].unstash() self.mastStates[index] = 1 def mastHit(self, index): if index in self.hitAnims: if self.mastStates[index] and not (self.mastsHidden): if not self.sailing: self.hitAnims[index][0].playAll() else: self._Ship__hitSailingIvals[index].start() def stopIvals(self): self._Ship__rollDownIval.pause() self._Ship__rollUpIval.pause() for ival in self._Ship__hitSailingIvals.values(): ival.pause() def playIdle(self): self.stopIvals() self.metaAnims['idle'].loopAll(1) def instantSailing(self): self.sailing = True self.enableSails() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['idle'].loopAll(1) def startSailing(self): self.stopIvals() if not self.sailing: self.sailing = True self.sailStopIval.pause() self.sailStartIval.pause() self.sailStartIval.start() def instantDocked(self): self.sailing = False self.disableSails() self.stopIvals() self.sailStopIval.pause() self.sailStartIval.pause() self.metaAnims['tiedup'].playAll() def stopSailing(self): if self.sailing: self.sailing = False self.sailStartIval.pause() self.sailStopIval.pause() self.sailStopIval.start() def playFullSailEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windTunnelEffect1: self.windTunnelEffect1 = Wind.getEffect() if self.windTunnelEffect1: self.windTunnelEffect1.reparentTo(self.center) self.windTunnelEffect1.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windTunnelEffect1.setScale(self.dimensions / 6.0) self.windTunnelEffect1.fadeTime = 2.0 self.windTunnelEffect1.setH(180) self.windTunnelEffect1.play() def playComeAboutEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windTunnelEffect2: self.windTunnelEffect2 = Wind.getEffect() if self.windTunnelEffect2: self.windTunnelEffect2.reparentTo(self.center) self.windTunnelEffect2.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.40000000000000002) self.windTunnelEffect2.setScale(self.dimensions / 10.0) self.windTunnelEffect2.fadeTime = 2.0 self.windTunnelEffect2.setH(0) self.windTunnelEffect2.play() def playRamEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.windConeEffect: self.windConeEffect = WindBlurCone.getEffect() if self.windConeEffect: self.windConeEffect.reparentTo(self.bow) self.windConeEffect.fadeColor = Vec4(0.80000000000000004, 0.80000000000000004, 0.80000000000000004, 0.5) self.windConeEffect.setScale(self.dimensions / 3.0) self.windConeEffect.setPos(0, self.dimensions[1] / 18.0, self.dimensions[2] / 4.0) self.windConeEffect.fadeTime = 2.0 self.windConeEffect.startLoop() def playRechargeEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: if not self.powerRechargeEffect: self.powerRechargeEffect = ShipPowerRecharge.getEffect() if self.powerRechargeEffect: self.powerRechargeEffect.reparentTo(self.char) self.powerRechargeEffect.setEffectColor(Vec4(0.5, 0.5, 1, 1)) self.powerRechargeEffect.setScale(self.dimensions / 4.0) self.powerRechargeEffect.startLoop() def playSpawnEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.protectionEffect = ProtectionDome.getEffect() if self.protectionEffect: self.protectionEffect.reparentTo(self.shipRoot) self.protectionEffect.setScale(self.dimensions[1] / 15.0) self.protectionEffect.startLoop() def playTakeCoverEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.takeCoverEffect = FadingCard(loader.loadModel('models/textureCards/skillIcons').find('**/sail_take_cover'), color = Vec4(1, 1, 1, 1), fadeTime = 0.01, waitTime = 2.5, startScale = 0.94999999999999996, endScale = 1.0) if self.takeCoverEffect: self.takeCoverEffect.reparentTo(self.shipRoot) self.takeCoverEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.takeCoverEffect.setScale(self.dimensions[1] / 4.0) self.takeCoverEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffTakeCoverString) def playOpenFireEffect(self): if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsLow: self.openFireEffect = FadingCard(loader.loadModel('models/textureCards/skillIcons').find('**/sail_openfire2'), color = Vec4(1, 1, 1, 1), fadeTime = 0.01, waitTime = 2.5, startScale = 0.94999999999999996, endScale = 1.0) if self.openFireEffect: self.openFireEffect.reparentTo(self.shipRoot) self.openFireEffect.setPos(0, 0, self.dimensions[2] * 1.25) self.openFireEffect.setScale(self.dimensions[1] / 4.0) self.openFireEffect.play() self.owner.playTextEffect(PLocalizer.CrewBuffOpenFireString) def stopRamEffect(self): if self.windConeEffect: self.windConeEffect.stopLoop() def stopRechargeEffect(self): if self.powerRechargeEffect: self.powerRechargeEffect.stopLoop() def stopSpawnEffect(self): if self.protectionEffect: self.protectionEffect.stopLoop() def stopTakeCoverEffect(self): if self.takeCoverEffect: self.takeCoverEffect.stop() def stopOpenFireEffect(self): if self.openFireEffect: self.openFireEffect.stop() def playStormEffect(self): if not self.stormEffect: self.stormEffect = DarkMaelstrom(self.shipRoot) self.stormEffect.setZ(50) self.stormEffect.loop() compassFX = CompassEffect.make(render) self.stormEffect.setEffect(compassFX) def stopStormEffect(self): if self.stormEffect: self.stormEffect.destroy() self.stormEffect = None def createWake(self): if self.owner: ownerId = self.owner.doId else: ownerId = None if not base.cr.activeWorld: self.notify.warning('Ship %s is trying to create a wake without an active world.' % (ownerId,)) return None if not base.cr.activeWorld.getWater(): self.notify.warning('Ship %s is trying to create a wake without an ocean. (world: %s)' % (ownerId, base.cr.activeWorld)) return None if self.WantWake and base.cr.wantSpecialEffects and self.owner: self.removeWake() if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsMedium: if not hasattr(base.cr.activeWorld.getWater(), 'patch'): self.notify.error("Ship %s is in location %s,%s (%s[%s]).\nThis causes Attribute Error: 'NoneType' object has no attribute 'patch'\n" % (ownerId, self.getLocation()[0], self.getLocation()[1], type(self.getParentObj()), safeRepr(self.getParentObj()))) self.wake = Wake.getEffect() if self.wake: self.wake.attachToShip(self.owner) compassFX = CompassEffect.make(render) self.wake.setEffect(compassFX) self.wake.startAnimate(self.owner) def removeWake(self): if self.wake: self.wake.cleanUpEffect() self.wake = None def hasWake(self): return self.wake != None def cleanup(self): self.sinkingEnd() self.modelRoot.clearPythonTag('ship') self.breakAnims = { } self.metaAnims = { } self.lod = None self.modelRoot.detachNode() self.modelRoot = None self.locators = None self.center = None self.stern = None self.bow = None self.starboard = None self.port = None self.cleanupCollisions() self.char = None loader.unloadSfx(self.sinkingSfx1) loader.unloadSfx(self.sinkingSfx2) self.sinkingSfx1 = None self.sinkingSfx2 = None self.sinkEffectsRoot = None self.sinkEffects = [] self.owner = None self._Ship__rollDownIval.pause() self._Ship__rollDownIval = None self._Ship__rollUpIval.pause() self._Ship__rollUpIval = None self.sailStartIval.pause() self.sailStartIval = None self.sailStopIval.pause() self.sailStopIval = None for ival in self._Ship__breakIvals.values(): ival.pause() self._Ship__breakIvals = { } self.windTunneldEffect1 = None self.windTunnelEffect2 = None self.windConeEffect = None self.powerRechargeEffect = None self.protectionEffect = None self.takeCoverEffect = None self.openFireEffect = None self.stopStormEffect() self.removeWake() self.cleanupDarkFog() if self.fader: self.fader.pause() self.fader = None def cleanupCollisions(self): self.mastCollisions = None self._Ship__targetableCollisions = [] self.modelCollisions = None self.floors = None self.deck = None self.planeBarriers = None self.walls = None self.shipCollWall = None self.panels = None def demandMastStates(self, mastStates, maxHealth): for i in range(5): if maxHealth[i]: if mastStates[i]: self.restoreMast(i) else: self.dropMast(i) mastStates[i] def sinkingBegin(self): self.computeDimensions() self.disableOnDeckInteractions() self.removeWake() soundTrack = Sequence() sinkingSfx = self.sinkingSfx1 if self.sfxAlternativeStyle: sinkingSfx = self.sinkingSfx2 if sinkingSfx: soundTrack = Sequence(Func(base.playSfx, sinkingSfx, node = self.modelRoot, cutoff = 1000)) self.sinkTrack = Sequence() sinkParallel = Parallel() if self.isInCrew(localAvatar.doId): sinkParallel.append(Func(base.localAvatar.b_setGameState, 'Cutscene', localArgs = [ self.owner])) sinkParallel.append(self.getSinkCamIval()) sinkParallel.append(Sequence(Func(self.startSinkEffects), soundTrack, self.getSinkShipIval())) self.sinkTrack.append(sinkParallel) self.sinkTrack.append(Func(self.endSinkEffects)) if self.owner.isInCrew(localAvatar.doId): self.sinkTrack.append(Func(self.cleanupLocalSinking)) self.sinkTrack.start() def sinkingEnd(self): if self.sinkTrack: self.sinkTrack.finish() self.sinkTrack = None def getSinkShipIval(self): return Parallel(LerpPosInterval(self.modelRoot, 18.0 * self.sinkTimeScale, Vec3(0, 0, -1.5 * self.dimensions[2])), LerpHprInterval(self.modelRoot, 12.0 * self.sinkTimeScale, VBase3(self.modelRoot.getH(), self.modelRoot.getP() + 75, self.modelRoot.getR()))) def getSinkCamIval(self): camStartPos = Vec3(-4.0 * self.dimensions[0], -1.25 * self.dimensions[1], 40) camEndPos = Vec3(-4.0 * self.dimensions[0], self.dimensions[1], self.dimensions[2] / 2.0) if self.owner: self.owner.lookAtDummy.setPos(0, 0, self.center.getZ()) def camLookAtDummy(t): camera.lookAt(self.owner.lookAtDummy) return Parallel(Func(camera.reparentTo, self.owner.attachNewNode('cameraDummy')), LerpPosInterval(camera, 16.0 * self.sinkTimeScale, camEndPos, startPos = camStartPos, blendType = 'easeInOut'), LerpPosInterval(self.owner.lookAtDummy, 18.0 * self.sinkTimeScale, Vec3(0, 80, 0)), LerpFunc(camLookAtDummy, 18.0 * self.sinkTimeScale)) def startSinkEffects(self): if not self.sinkEffectsRoot: self.sinkEffectsRoot = self.shipRoot.attachNewNode('sinkEffectsRoot') self.sinkEffectsRoot.setY(self.center.getY()) if base.options.getSpecialEffectsSetting() >= base.options.SpecialEffectsMediu