class DistributedEagleSuit(DistributedSuit): notify = directNotify.newCategory('DistributedEagleSuit') def __init__(self, cr): DistributedSuit.__init__(self, cr) self.eagleCry = base.audio3d.loadSfx( 'phase_5/audio/sfx/tt_s_ara_cfg_eagleCry.ogg') base.audio3d.attachSoundToObject(self.eagleCry, self) self.fallWhistle = base.audio3d.loadSfx( 'phase_5/audio/sfx/incoming_whistleALT.ogg') base.audio3d.attachSoundToObject(self.fallWhistle, self) self.explode = base.audio3d.loadSfx( 'phase_3.5/audio/sfx/ENC_cogfall_apart.ogg') base.audio3d.attachSoundToObject(self.explode, self) self.eventSphereNodePath = None self.fallingPropeller = None self.fallingPropProjectile = None self.mg = None self.flySpeed = 0.0 return def enterNeutral(self, ts=0): self.show() self.timestampAnimTrack = Sequence(Wait(ts), Func(self.loop, 'flyNeutral')) self.timestampAnimTrack.start() def makeStateDict(self): self.suitFSM.addState( State('eagleFly', self.enterEagleFly, self.exitEagleFly)) self.suitFSM.addState( State('eagleFall', self.enterEagleFall, self.exitEagleFall)) self.stateIndex2suitState = { 0: self.suitFSM.getStateNamed('off'), 1: self.suitFSM.getStateNamed('walking'), 2: self.suitFSM.getStateNamed('flyingDown'), 3: self.suitFSM.getStateNamed('flyingUp'), 4: self.suitFSM.getStateNamed('lured'), 5: self.suitFSM.getStateNamed('eagleFly'), 6: self.suitFSM.getStateNamed('eagleFall') } self.suitState2stateIndex = {} for stateId, state in self.stateIndex2suitState.items(): self.suitState2stateIndex[state.getName()] = stateId def setFlySpeed(self, value): self.flySpeed = value def getFlySpeed(self): return self.flySpeed def enterEagleFly(self, startIndex, endIndex, ts=0.0): durationFactor = self.getFlySpeed() if startIndex > -1: startPos = EGG.EAGLE_FLY_POINTS[startIndex] else: startPos = self.getPos(render) endPos = EGG.EAGLE_FLY_POINTS[endIndex] if self.moveIval: self.moveIval.pause() self.moveIval = None self.moveIval = NPCWalkInterval(self, endPos, durationFactor=durationFactor, startPos=startPos, fluid=1) self.moveIval.start(ts) return def exitEagleFly(self): if self.moveIval: self.moveIval.pause() self.moveIval = None return def enterEagleFall(self, startIndex, endIndex, ts=0.0): self.moveIval = LerpPosInterval(self, duration=4.0, pos=self.getPos(render) - (0, 0, 75), startPos=self.getPos(render), blendType='easeIn') self.moveIval.start(ts) def exitEagleFall(self): if self.moveIval: self.moveIval.finish() self.moveIval = None return def fallAndExplode(self): self.cleanupPropeller() self.fallingPropeller = Actor( 'phase_4/models/props/propeller-mod.bam', {'chan': 'phase_4/models/props/propeller-chan.bam'}) self.fallingPropeller.reparentTo(render) self.fallingPropeller.loop('chan', fromFrame=0, toFrame=3) parentNode = self.attachNewNode('fallingPropParentNode') h = random.randint(0, 359) parentNode.setH(h) dummyNode = parentNode.attachNewNode('dummyNode') dummyNode.setPos(0, 10, -50) self.fallingPropProjectile = FlightProjectileInterval( self.fallingPropeller, startPos=self.find('**/joint_head').getPos(render), endPos=dummyNode.getPos(render), duration=5.0, gravityMult=0.25) self.fallingPropProjectile.start() dummyNode.removeNode() del dummyNode parentNode.removeNode() del parentNode self.updateHealthBar(0) self.ignoreHit() base.playSfx(self.fallWhistle, node=self) taskMgr.doMethodLater(4.0, self.doExplodeSound, self.uniqueName('DEagleSuit-doExplodeSound')) def doExplodeSound(self, task): base.playSfx(self.explode, node=self) return Task.done def __initializeEventSphere(self): sphere = CollisionSphere(0, 0, 0, 2) sphere.setTangible(0) node = CollisionNode(self.uniqueName('DEagleSuit-eventSphere')) node.addSolid(sphere) node.setCollideMask(CIGlobals.WallBitmask) np = self.attachNewNode(node) np.setSz(2.5) np.setZ(5.5) self.eventSphereNodePath = np def removeEventSphere(self): if self.eventSphereNodePath: self.eventSphereNodePath.removeNode() self.eventSphereNodePath = None return def acceptHit(self): self.acceptOnce('enter' + self.eventSphereNodePath.node().getName(), self.__handleHit) def ignoreHit(self): self.ignore('enter' + self.eventSphereNodePath.node().getName()) def __handleHit(self, entry): messenger.send(EGG.EAGLE_HIT_EVENT, [self.doId]) def setSuit(self, arg, variant): DistributedSuit.setSuit(self, arg, 3) self.deleteShadow() self.disableBodyCollisions() self.disableRay() self.__initializeEventSphere() self.show() self.setAnimState('flyNeutral') def __doEagleCry(self, task): base.playSfx(self.eagleCry, node=self) task.delayTime = random.uniform(3, 30) return Task.again def announceGenerate(self): DistributedSuit.announceGenerate(self) taskMgr.doMethodLater(random.uniform(5, 25), self.__doEagleCry, self.uniqueName('DEagleSuit-doEagleCry')) self.acceptHit() def disable(self): self.ignoreHit() self.removeEventSphere() taskMgr.remove(self.uniqueName('DEagleSuit-doExplodeSound')) taskMgr.remove(self.uniqueName('DEagleSuit-doEagleCry')) if self.fallingPropProjectile: self.fallingPropProjectile.finish() self.fallingPropProjectile = None if self.fallingPropeller: self.fallingPropeller.cleanup() self.fallingPropeller = None base.audio3d.detachSound(self.fallWhistle) del self.fallWhistle base.audio3d.detachSound(self.explode) del self.explode base.audio3d.detachSound(self.eagleCry) del self.eagleCry self.mg = None DistributedSuit.disable(self) return
class DistributedSuit(Suit, DistributedAvatar, DistributedSmoothNode, DelayDeletable): notify = directNotify.newCategory('DistributedSuit') def __init__(self, cr): Suit.__init__(self) DistributedAvatar.__init__(self, cr) DistributedSmoothNode.__init__(self, cr) self.anim = None self._state = SuitState.ALIVE self.dept = None self.variant = None self.suitPlan = None self.level = None self.moveIval = None self.hpFlash = None # For PythonCTMusicManager: # Are we in range of the localAvatar? self.isInRange = False self.chaseTarget = 0 self.suitFSM = ClassicFSM('DistributedSuit', [ State('off', self.enterSuitOff, self.exitSuitOff), State('walking', self.enterWalking, self.exitWalking), State('flyingDown', self.enterFlyingDown, self.exitFlyingDown), State('flyingUp', self.enterFlyingUp, self.exitFlyingUp), State('lured', self.enterLured, self.exitLured) ], 'off', 'off') self.stateIndex2suitState = {} self.suitFSM.enterInitialState() self.makeStateDict() def setChaseTarget(self, avId): if avId != base.localAvatar.doId: if self.chaseTarget == base.localAvatar.doId: messenger.send(PCTMM.getCogLostTargetEvent()) else: messenger.send(PCTMM.getCogChasingEvent()) self.chaseTarget = avId def setWalkPath(self, path, timestamp): elapsedT = globalClockDelta.localElapsedTime(timestamp) self.suitFSM.request('walking', [path, elapsedT]) def showAvId(self): self.setDisplayName(self.getName() + "\n" + str(self.doId)) def showName(self): self.setDisplayName(self.getName()) def setDisplayName(self, name): self.setupNameTag(tempName=name) def enterWalking(self, path, elapsedT): # path: A list of point2s. # # We will make a sequence of NPCWalkIntervals for each point2 in the path. self.clearMoveTrack() self.moveIval = getMoveIvalFromPath(self, path, elapsedT, True, 'suitMoveIval') self.moveIval.start(elapsedT) def clearMoveTrack(self): if self.moveIval: self.ignore(self.moveIval.getDoneEvent()) self.moveIval.pause() self.moveIval = None if not self.isDead(): self.animFSM.request('neutral') def exitWalking(self): self.clearMoveTrack() if not self.isDead(): self.animFSM.request('neutral') def enterFlyingDown(self, startIndex, endIndex, ts=0.0): if self.getHood() != '' and startIndex != -1 and endIndex != -1: duration = 3.5 startPoint = CIGlobals.SuitSpawnPoints[ self.getHood()].keys()[startIndex] startPos = CIGlobals.SuitSpawnPoints[ self.getHood()][startPoint] + (0, 0, 6.5 * 4.8) endPoint = CIGlobals.SuitSpawnPoints[ self.getHood()].keys()[endIndex] endPos = CIGlobals.SuitSpawnPoints[self.getHood()][endPoint] self.stopMoving(finish=1) groundF = 28 dur = self.getDuration('land') fr = self.getFrameRate('land') if fr: animTimeInAir = groundF / fr else: animTimeInAir = groundF impactLength = dur - animTimeInAir timeTillLanding = 6.5 - impactLength self.moveIval = LerpPosInterval(self, duration=timeTillLanding, pos=endPos, startPos=startPos, fluid=1) self.moveIval.start(ts) self.animFSM.request('flyDown', [ts]) def exitFlyingDown(self): self.stopMoving(finish=1) self.animFSM.request('neutral') def enterFlyingUp(self, startIndex, endIndex, ts=0.0): if self.getHood() != '': duration = 3 if startIndex > -1: startPoint = CIGlobals.SuitSpawnPoints[ self.getHood()].keys()[startIndex] startPos = CIGlobals.SuitSpawnPoints[ self.getHood()][startPoint] else: startPos = self.getPos(render) if endIndex > -1: endPoint = CIGlobals.SuitSpawnPoints[ self.getHood()].keys()[endIndex] endPos = CIGlobals.SuitSpawnPoints[ self.getHood()][endPoint] + (0, 0, 6.5 * 4.8) else: endPos = self.getPos(render) + (0, 0, 6.5 * 4.8) self.stopMoving(finish=1) groundF = 28 dur = self.getDuration('land') fr = self.getFrameRate('land') if fr: animTimeInAir = groundF / fr else: animTimeInAir = groundF impactLength = dur - animTimeInAir timeTillLanding = 6.5 - impactLength self.moveIval = Sequence( Wait(impactLength), LerpPosInterval(self, duration=timeTillLanding, pos=endPos, startPos=startPos, fluid=1)) self.moveIval.start(ts) self.animFSM.request('flyAway', [ts, 1]) def exitFlyingUp(self): if self.moveIval: self.moveIval.finish() self.moveIval = None self.animFSM.request('neutral') def enterLured(self, _, __, ___): self.loop('lured') def exitLured(self): self.stop() def enterSuitOff(self, foo1=None, foo2=None, foo3=None): pass def exitSuitOff(self): pass def setName(self, name): Suit.setName(self, name, self.suitPlan.getName()) def setLevel(self, level): self.level = level if self.level == 12: self.maxHealth = 200 elif self.level > 0: self.maxHealth = (self.level + 1) * (self.level + 2) else: self.maxHealth = 1 self.health = self.maxHealth self.updateHealthBar(self.health) def getLevel(self): return self.level def startMoveInterval(self, startX, startY, startZ, endX, endY, endZ, duration): self.stopMoving() endPos = Point3(endX, endY, endZ) self.moveIval = NPCWalkInterval(self, endPos, durationFactor=duration, fluid=1) self.moveIval.start() def stopMoveInterval(self, andTurnAround=0): if self.moveIval: self.moveIval.pause() self.moveIval = None if andTurnAround == 1: if self.health > 0: self.animFSM.request('neutral') self.setH(self.getH() - 180) def toggleRay(self, ray=1): if ray: Suit.initializeRay(self, self.avatarType, 2) else: Suit.disableRay(self) def startProjInterval(self, startX, startY, startZ, endX, endY, endZ, duration, gravityMult, ts=0): if isinstance(ts, int) and ts != 0: ts = globalClockDelta.localElapsedTime(ts) self.disableRay() self.stopMoveInterval() startPos = Point3(startX, startY, startZ) endPos = Point3(endX, endY, endZ) oldHpr = self.getHpr(render) self.headsUp(endPos) newHpr = self.getHpr(render) self.setHpr(oldHpr) self.moveIval = Parallel( LerpHprInterval(self, duration=0.5, hpr=newHpr, startHpr=oldHpr, blendType='easeInOut'), Sequence(Func(self.animFSM.request, 'flyAway', [ts]), Wait(3.5), Func(self.animFSM.request, 'flyDown', [1.0])), Sequence( Wait(2.0), Func(self.headsUp, endPos), ProjectileInterval(self, startPos=startPos, endPos=endPos, gravityMult=gravityMult, duration=duration))) self.moveIval.start(ts) def startPosInterval(self, startX, startY, startZ, endX, endY, endZ, duration, blendType, ts=0.0): if ts != 0.0: ts = globalClockDelta.localElapsedTime(ts) self.stopMoveInterval() startPos = Point3(startX, startY, startZ) endPos = Point3(endX, endY, endZ) self.moveIval = LerpPosInterval(self, duration=duration, pos=endPos, startPos=startPos, blendType=blendType) self.moveIval.start(ts) def stopMoving(self, finish=0): if self.moveIval: if finish: self.moveIval.finish() else: self.moveIval.pause() self.moveIval = None def d_disableMovement(self, wantRay=False): self.sendUpdate('disableMovement', []) self.interruptAttack() self.stopMoving() if not wantRay: Suit.disableRay(self) def d_enableMovement(self): self.sendUpdate('enableMovement', []) Suit.initializeRay(self, self.avatarType, 2) def startRay(self): Suit.initializeRay(self, self.avatarType, 2) def setHealth(self, health): if health > self.health: # We got an hp boost. Flash green. flashColor = VBase4(0, 1, 0, 1) elif health < self.health: # We got an hp loss. Flash red. flashColor = VBase4(1, 0, 0, 1) DistributedAvatar.setHealth(self, health) def doBossFlash(): if not self.isEmpty(): LerpColorScaleInterval(self, 0.2, flashColor).start() def clearBossFlash(): if not self.isEmpty(): self.clearColorScale() if self.isDead(): self.setChaseTarget(0) base.taskMgr.remove(self.uniqueName('monitorLocalAvDistance')) if self.isInRange: messenger.send(PCTMM.getCogOutOfRangeEvent()) self.isInRange = False self.interruptAttack() if self.getLevel() > 12: if self.hpFlash: self.hpFlash.finish() self.hpFlash = None self.hpFlash = Sequence(Func(doBossFlash), Wait(0.2), Func(clearBossFlash)) self.hpFlash.start() self.updateHealthBar(health) def announceHealth(self, level, hp): DistributedAvatar.announceHealth(self, level, hp) if level == 1: healthSfx = base.audio3d.loadSfx(SuitGlobals.healedSfx) base.audio3d.attachSoundToObject(healthSfx, self) SoundInterval(healthSfx, node=self).start() del healthSfx # # 'setSuit' sets the suit type and generates it. # 'arg' is an id for a SuitPlan as defined in SuitBank or # an instance of SuitPlan. # 'variant' is an optional argument that sets the variant. # It takes an id for the variant or an instance of Variant. # Default is Variant.NORMAL. def setSuit(self, arg, variant=0): if isinstance(arg, SuitPlan): plan = arg else: plan = SuitBank.getSuitById(arg) voice = Voice.NORMAL if variant: if isinstance(variant, (int, long, float, complex)): variant = Variant.getVariantById(variant) if plan.getForcedVoice(): voice = plan.getForcedVoice() Suit.generate(self, plan, variant, voice=voice) self.suitPlan = plan self.variant = Variant.getVariantById(variant) def getSuit(self): return tuple((self.suitPlan, self.variant)) def spawn(self, startIndex, endIndex, spawnMode=SpawnMode.FLYDOWN): if spawnMode == SpawnMode.FLYDOWN: startPoint = CIGlobals.SuitSpawnPoints[ self.getHood()].keys()[startIndex] startPos = CIGlobals.SuitSpawnPoints[ self.getHood()][startPoint] + (0, 0, 50) endPoint = CIGlobals.SuitSpawnPoints[ self.getHood()].keys()[endIndex] endPos = CIGlobals.SuitSpawnPoints[self.getHood()][endPoint] if self.moveIval: self.moveIval.finish() self.moveIval = None self.moveIval = LerpPosInterval(self, duration=3, pos=endPos, startPos=startPos, fluid=1) def makeStateDict(self): self.stateIndex2suitState = { 0: self.suitFSM.getStateNamed('off'), 1: self.suitFSM.getStateNamed('walking'), 2: self.suitFSM.getStateNamed('flyingDown'), 3: self.suitFSM.getStateNamed('flyingUp'), 4: self.suitFSM.getStateNamed('lured') } self.suitState2stateIndex = {} for stateId, state in self.stateIndex2suitState.items(): self.suitState2stateIndex[state.getName()] = stateId def setSuitState(self, index, startPoint, endPoint, timestamp=None): if timestamp != None: ts = globalClockDelta.localElapsedTime(timestamp) else: ts = 0.0 self.suitState = self.stateIndex2suitState[index] self.startPoint = startPoint self.endPoint = endPoint self.suitFSM.request(self.suitState, [startPoint, endPoint, ts]) def getSuitState(self): return self.suitState def setAnimState(self, anim, loop=1, timestamp=None): prevAnim = self.anim self.anim = anim if timestamp == None: ts = 0.0 else: ts = globalClockDelta.localElapsedTime(timestamp) if type(anim) == types.IntType: if anim != 44 and anim != 45: anim = SuitGlobals.getAnimById(anim) animName = anim.getName() elif anim == 44: animName = 'die' elif anim == 45: animName = 'flyNeutral' elif type(anim) == types.StringType: animName = anim if self.animFSM.hasStateNamed(animName): self.animFSM.request(animName, [ts]) else: if loop: self.loop(animName) else: self.play(animName) messenger.send(SuitGlobals.animStateChangeEvent % (self.uniqueName), [anim, prevAnim]) def doAttack(self, attackId, avId, timestamp=None): if timestamp == None: ts = 0.0 else: ts = globalClockDelta.localElapsedTime(timestamp) attackName = SuitAttacks.SuitAttackLengths.keys()[attackId] attackTaunt = CIGlobals.SuitAttackTaunts[attackName][random.randint( 0, len(CIGlobals.SuitAttackTaunts[attackName]) - 1)] avatar = self.cr.doId2do.get(avId) shouldChat = 0 if self.suitPlan in [SuitBank.VicePresident, SuitBank.LucyCrossbill]: shouldChat = random.randint(0, 2) if shouldChat == 0: self.setChat(attackTaunt) self.animFSM.request('attack', [attackName, avatar, 0.0]) def throwObject(self): self.acceptOnce('enter' + self.wsnp.node().getName(), self.__handleWeaponCollision) Suit.throwObject(self) def __handleWeaponCollision(self, entry): self.sendUpdate('toonHitByWeapon', [self.attack, base.localAvatar.doId]) base.localAvatar.handleHitByWeapon(self.attack, self) self.b_handleWeaponTouch() def b_handleWeaponTouch(self): self.sendUpdate('handleWeaponTouch', []) self.handleWeaponTouch() def __monitorLocalAvDistance(self, task): if self.getDistance(base.localAvatar) <= PCTMM.getCogInRangeDistance( ) and not self.isInRange: self.isInRange = True messenger.send(PCTMM.getCogInRangeEvent()) elif self.getDistance(base.localAvatar) > PCTMM.getCogInRangeDistance( ) and self.isInRange: self.isInRange = False messenger.send(PCTMM.getCogOutOfRangeEvent()) return task.cont def announceGenerate(self): DistributedAvatar.announceGenerate(self) self.setAnimState('neutral') base.taskMgr.add(self.__monitorLocalAvDistance, self.uniqueName('monitorLocalAvDistance')) def generate(self): DistributedAvatar.generate(self) DistributedSmoothNode.generate(self) def disable(self): base.taskMgr.remove(self.uniqueName('monitorLocalAvDistance')) self.anim = None self._state = None self.dept = None self.variant = None self.suitPlan = None if self.hpFlash: self.hpFlash.finish() self.hpFlash = None if self.moveIval: self.moveIval.pause() self.moveIval = None Suit.disable(self) DistributedAvatar.disable(self) def delete(self): Suit.delete(self) del self.anim del self._state del self.dept del self.variant del self.suitPlan del self.moveIval DistributedAvatar.delete(self) DistributedSmoothNode.delete(self)
class InventoryGui(DirectObject): directNotify = DirectNotify().newCategory('InventoryGui') HiddenPos = (0.2, 0, 0) VisiblePos = (-0.1725, 0, 0) SwitchTime = 0.3 AutoShowTime = 1.5 DELETED = False def __init__(self): DirectObject.__init__(self) self.backpack = base.localAvatar.backpack if not self.backpack: return self.backpack.loadoutGUI = self self.oneSlotPos = [(0, 0, 0)] self.twoSlotsPos = [(0, 0, 0.3), (0, 0, -0.2)] self.threeSlotsPos = [(0, 0, 0.5), (0, 0, 0), (0, 0, -0.5)] self.fourSlotPos = [(0, 0, 0.5), (0, 0, 0.15), (0, 0, -0.2), (0, 0, -0.55)] self.availableSlot = 0 self.slots = [] self.activeSlot = None self.defaultSlots = 3 self.prevSlot = None self.ammoLabel = None self.inventoryFrame = DirectFrame(parent=base.a2dRightCenter, pos=(-0.1725, 0, 0)) self.visibilityBtn = DirectButton(text='', relief=None, text_bg=(1, 1, 1, 0), parent=base.a2dRightCenter, pos=(-0.1725, 0, 0), frameSize=(-0.2, 0.2, -0.725, 0.7), clickSound=None, rolloverSound=None) self.visibilityBtn.bind(DGG.WITHIN, self.__handleVisEnter) self.visibilityBtn.bind(DGG.WITHOUT, self.__handleVisExit) self.visibilityBtn.setBin('background', 10) self.visibilityBtn = None self.visibilityBtnStatus = 0 self.switchSound = True self.switchSoundSfx = base.loadSfx( 'phase_3/audio/sfx/GUI_balloon_popup.ogg') self.visibilityFSM = ClassicFSM('InventoryGui-VisibilityFSM', [ State('off', self.enterOff, self.exitOff), State('hidden', self.enterHidden, self.exitHidden), State('hidden2visible', self.enterHidden2Visible, self.exitHidden2Visible), State('visible', self.enterVisible, self.exitVisible), State('visible2hidden', self.enterVisible2Hidden, self.exitVisible2Hidden) ], 'off', 'off') self.visibilityFSM.enterInitialState() self.visibilityFSM.request('hidden') return def enterOff(self): pass def exitOff(self): pass def enterHidden(self): self.inventoryFrame.setPos(InventoryGui.HiddenPos) self.inventoryFrame.hide() def exitHidden(self): pass def enterVisible(self, autoShow=False): self.inventoryFrame.setPos(InventoryGui.VisiblePos) self.inventoryFrame.show() if self.visibilityBtnStatus == 0: if autoShow is False: self.visibilityFSM.request('visible2hidden') def exitVisible(self): pass def enterHidden2Visible(self, autoShow=False): self.inventoryFrame.show() self.moveIval = LerpPosInterval(self.inventoryFrame, duration=InventoryGui.SwitchTime, pos=InventoryGui.VisiblePos, startPos=InventoryGui.HiddenPos) self.moveIval.setDoneEvent('hidden2visible') self.acceptOnce('hidden2visible', self.visibilityFSM.request, ['visible', [autoShow]]) self.moveIval.start() def exitHidden2Visible(self): self.ignore('hidden2visible') self.moveIval.finish() del self.moveIval def enterVisible2Hidden(self): self.moveIval = LerpPosInterval(self.inventoryFrame, duration=InventoryGui.SwitchTime, pos=InventoryGui.HiddenPos, startPos=InventoryGui.VisiblePos) self.moveIval.setDoneEvent('visible2hidden') self.acceptOnce('visible2hidden', self.visibilityFSM.request, ['hidden']) self.moveIval.start() def exitVisible2Hidden(self): self.ignore('visible2hidden') self.moveIval.finish() del self.moveIval def click_setWeapon(self, slot, cmd): self.setWeapon(slot, playSound=False) def setWeapon(self, slot, playSound=True, showUpIfHidden=False): if isinstance(slot, str): for iSlot in self.slots: if iSlot.getGag(): if iSlot.getGag().getID() == slot: slot = iSlot if self.activeSlot and slot != self.activeSlot: self.activeSlot.setOutlineImage('idle') self.prevSlot = self.activeSlot if slot.getGag() and self.backpack.getSupply(slot.getGag().getID( )) > 0 and not slot.getGag().getState() == GagState.RECHARGING: if self.activeSlot != slot: gagId = slot.getGag().getID() base.localAvatar.needsToSwitchToGag = gagId if base.localAvatar.gagsTimedOut == False: base.localAvatar.b_equip(gagId) base.localAvatar.enableGagKeys() slot.setOutlineImage('selected') self.activeSlot = slot else: if self.activeSlot == slot and slot.getGag().getState() in [ GagState.LOADED, GagState.RECHARGING ]: base.localAvatar.needsToSwitchToGag = 'unequip' if base.localAvatar.gagsTimedOut == False: base.localAvatar.b_unEquip() base.localAvatar.enableGagKeys() self.activeSlot = None self.update() if self.switchSound and playSound: base.playSfx(self.switchSoundSfx) if showUpIfHidden: base.taskMgr.remove('showUpIfHidden') self.__autoVisEnter() base.taskMgr.doMethodLater(InventoryGui.AutoShowTime, self.__autoVisExitTask, 'showUpIfHidden') return def __autoVisExitTask(self, task): if self.visibilityBtnStatus == 0: self.__handleVisExit(None, updateBtnStatus=False) return task.done def __autoVisEnter(self): self.__handleVisEnter(None, True, False) return def __handleVisEnter(self, foo, autoShow=False, updateBtnStatus=True): if updateBtnStatus: self.visibilityBtnStatus = 1 if self.visibilityFSM.getCurrentState().getName() == 'hidden': self.visibilityFSM.request('hidden2visible', [autoShow]) else: if self.visibilityFSM.getCurrentState().getName( ) == 'visible2hidden': self.visibilityFSM.request('visible') def __handleVisExit(self, foo, updateBtnStatus=True): if updateBtnStatus: self.visibilityBtnStatus = 0 base.taskMgr.remove('showUpIfHidden') if self.visibilityFSM.getCurrentState().getName() == 'visible': self.visibilityFSM.request('visible2hidden') def createGui(self): self.deleteGui() posGroup = self.threeSlotsPos if self.defaultSlots == 4: posGroup = self.fourSlotPos for slot in range(len(posGroup) + 1): if slot == 3: posGroup = self.fourSlotPos slotObj = Slot(self, slot + 1, posGroup[slot], self.inventoryFrame) self.slots.append(slotObj) if slot == 3: slotObj.hide() self.ammoLabel = DirectLabel(text='Ammo: 0', text_fg=(1, 1, 1, 1), relief=None, text_shadow=(0, 0, 0, 1), text_scale=0.08, pos=(0.2, 0, 0.35), parent=base.a2dBottomLeft) self.ammoLabel.hide() self.enableWeaponSwitch() self.resetScroll() self.update() return def deleteGui(self): self.disableWeaponSwitch() for slot in self.slots: slot.destroy() self.slots = [] if self.ammoLabel: self.ammoLabel.destroy() self.ammoLabel = None self.DELETED = True return def resetScroll(self): nextGag = 0 prevGag = -1 curGag = -1 if self.prevSlot: prevGag = self.slots.index(self.prevSlot) if self.activeSlot: curGag = self.slots.index(self.activeSlot) if curGag == len(self.slots) - 1: nextGag = 0 prevGag = curGag - 1 else: if curGag == 0: nextGag = 1 prevGag = len(self.slots) - 1 else: if curGag == -1: prevGag = len(self.slots) - 1 else: nextGag = curGag + 1 prevGag = curGag - 1 self.accept('wheel_down', self.setWeapon, extraArgs=[self.slots[nextGag], True, True]) self.accept('wheel_up', self.setWeapon, extraArgs=[self.slots[prevGag], True, True]) def update(self): if not self.backpack: return for element in [self.ammoLabel, self.inventoryFrame]: if not element: return updateSlots = list(self.slots) for slot in self.slots: gag = slot.getGag() if not gag: updateSlots.remove(slot) slot.hide() continue supply = self.backpack.getSupply(gag.getID()) index = self.slots.index(slot) if not gag and len(self.backpack.getGags()) - 1 >= index: gag = self.backpack.getGagByIndex(index) slot.setGag(gag) if self.backpack.getSupply(gag.getID( )) > 0 and not gag.getState() == GagState.RECHARGING: slot.setOutlineImage('idle') else: slot.setOutlineImage('no_ammo') elif slot == self.activeSlot: self.ammoLabel['text_fg'] = (1, 1, 1, 1) if supply > 0 and not gag.getState() == GagState.RECHARGING: slot.setOutlineImage('selected') else: if supply <= 0: self.ammoLabel['text_fg'] = (0.9, 0, 0, 1) slot.setOutlineImage('no_ammo') self.activeSlot = None self.ammoLabel.show() self.ammoLabel['text'] = 'Ammo: %s' % self.backpack.getSupply( slot.getGag().getID()) elif self.backpack.getSupply(slot.getGag().getID( )) > 0 and not gag.getState() == GagState.RECHARGING: slot.setOutlineImage('idle') else: slot.setOutlineImage('no_ammo') numSlots = len(updateSlots) posGroup = { 1: self.oneSlotPos, 2: self.twoSlotsPos, 3: self.threeSlotsPos, 4: self.fourSlotPos }.get(numSlots) for i in xrange(len(updateSlots)): updateSlots[i].setPos(posGroup[i]) updateSlots[i].show() if self.activeSlot == None: self.ammoLabel.hide() self.ammoLabel['text'] = 'Ammo: 0' self.resetScroll() return def setBackpack(self, backpack): self.backpack = backpack def updateLoadout(self): if self.backpack: loadout = self.backpack.getLoadout() if len(loadout) <= 3: self.reseatSlots() else: if len(loadout) == 4: self.reseatSlots(slots=4) for i in range(len(self.slots)): slot = self.slots[i] if i < len(loadout): slot.setGag(loadout[i]) else: slot.setGag(None) self.update() return def reseatSlots(self, slots=3): for slot in range(len(self.slots) - 1): if slots == 4: self.slots[slot].setPos(self.fourSlotPos[slot]) else: self.slots[slot].setPos(self.threeSlotsPos[slot]) def enableWeaponSwitch(self): for index in range(len(self.slots)): self.accept(str(index + 1), self.setWeapon, extraArgs=[self.slots[index], True, True]) def disableWeaponSwitch(self): for key in ['1', '2', '3', '4', 'wheel_down', 'wheel_up']: self.ignore(key) def getSlots(self): return self.slots def getActiveSlot(self): return self.activeSlot def isDeleted(self): return self.DELETED
class GUnit(GEntity): def __init__(self,conf): GEntity.__init__(self,conf) self.p3dobject.reparentTo(self.gmap.units_node) self.p3dobject.setTransparency(TransparencyAttrib.MAlpha) #to be put under condition for non pickable units (bonuses npc for instance) self.p3dobject.setTag('GUnit-pickable','1') self.p3dobject.setPos(self.gmap.root.find('**/tile_'+str(conf['tileid'])),0,0,0) #supposedly already a float, but will screw up if not, so just making sure. self.move_speed=float(conf['move_speed']) self.path=[] self.popout_when_move_over=False self.pid=conf['pid'] #highlight self.ts_highlighted=TextureStage('ts_highlighted') self.ts_highlighted.setMode(TextureStage.MDecal) self.ts_highlighted.setSort(2) #highlight self.ts_selected=TextureStage('ts_selected') self.ts_selected.setMode(TextureStage.MDecal) self.ts_selected.setSort(3) @staticmethod def load_resources(): GUnit.textures={ 'highlighted':loader.loadTexture('data/models/highlighted.tex.png'), 'selected':loader.loadTexture('data/models/selected.tex.png'), } def dispose(self): '''del method''' GEntity.dispose(self) self.popout_sequence.finish() del self.popout_sequence def add_path(self,data): ''' adds tile to pass by. ''' #check for data completeness if not 'path' in data: out('WARNING in GUnit.add_path: incomplete data:\n'+str(data)) return elif not isinstance(data['path'],list): out('WARNING in GUnit.add_path: invalid data:\n'+str(data)) return #data considered valid self.path.extend([self.instances[eid] for eid in data['path']]) if not self.update_move in update_list: update_list.append(self.update_move) #out('GUnit.add_path:'+str(data)) def finish_move_to(self,data): '''triggered by server side unit, to indicate the need to popout at end of move.''' out('GUnit.finish_move_to()'+str(data)) if self.update_move in update_list: self.popout_when_move_over=True else: self.popout() def popout(self): '''sets up the popout animation at end of unit's mission''' scale=self.p3dobject.scaleInterval(.5,(.1,.1,.1)) finish=Func(lambda:dispose_list.append(self)) self.popout_sequence=Sequence(scale,finish) self.popout_sequence.start() def set_highlighted(self): self.p3dobject.setTexture(self.ts_highlighted,self.textures['highlighted']) def unset_highlighted(self): self.p3dobject.clearTexture(self.ts_highlighted) def set_selected(self): self.p3dobject.setTexture(self.ts_selected,self.textures['selected']) def unset_selected(self): self.p3dobject.clearTexture(self.ts_selected) def update_move(self): '''called every frame during while a move.''' if len(self.path)==0: out('WARNING in GUnit.update_move: path is empty, but method still called. removing it.') update_list.remove(self.update_move) return if not hasattr(self,'move_interval'): #start moving #first 3 args=model,duration,pos, the duration=1/... is relative to server side tile side size self.move_interval=LerpPosInterval(self.p3dobject, (1/(self.move_speed*ConfigVariableDouble('clock-frame-rate').getValue())), self.path[0].p3dobject.getPos(), name='interval_unit_move_'+str(self.eid) ) self.p3dobject.lookAt(self.path[0].p3dobject.getPos()) self.p3dobject.loop('run') self.move_interval.start() else: #is move ~over ? #t=self.move_interval.getT() #d=self.move_interval.getDuration() #d=d-t d=dist3(self.p3dobject,self.path[0].p3dobject) #out('client '+str(t*100./d)+'%') #arrived if d<self.move_speed: #out('client '+str(self.path[0].eid)+'@'+str(self.frame_no)) self.p3dobject.setPos(self.path[0].p3dobject,0,0,0) self.path.pop(0) if len(self.path)==0: self.p3dobject.stop() self.move_interval.finish() del self.move_interval update_list.remove(self.update_move) if self.popout_when_move_over: self.popout() else: #first 3 args=model,duration,pos self.move_interval.finish() self.move_interval=LerpPosInterval(self.p3dobject, (1/(self.move_speed*ConfigVariableDouble('clock-frame-rate').getValue())), self.path[0].p3dobject.getPos(), name='interval_unit_move_'+str(self.eid) ) self.p3dobject.lookAt(self.path[0].p3dobject.getPos()) self.move_interval.start()
class DistributedEagleSuit(DistributedSuit): notify = directNotify.newCategory('DistributedEagleSuit') def __init__(self, cr): DistributedSuit.__init__(self, cr) self.eagleCry = base.audio3d.loadSfx('phase_5/audio/sfx/tt_s_ara_cfg_eagleCry.mp3') base.audio3d.attachSoundToObject(self.eagleCry, self) self.fallWhistle = base.audio3d.loadSfx('phase_5/audio/sfx/incoming_whistleALT.mp3') base.audio3d.attachSoundToObject(self.fallWhistle, self) self.explode = base.audio3d.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart.mp3') base.audio3d.attachSoundToObject(self.explode, self) self.eventSphereNodePath = None self.fallingPropeller = None self.fallingPropProjectile = None self.mg = None self.flySpeed = 0.0 return def enterNeutral(self, ts = 0): self.show() self.timestampAnimTrack = Sequence(Wait(ts), Func(self.loop, 'flyNeutral')) self.timestampAnimTrack.start() def makeStateDict(self): self.suitFSM.addState(State('eagleFly', self.enterEagleFly, self.exitEagleFly)) self.suitFSM.addState(State('eagleFall', self.enterEagleFall, self.exitEagleFall)) self.stateIndex2suitState = {0: self.suitFSM.getStateNamed('off'), 1: self.suitFSM.getStateNamed('walking'), 2: self.suitFSM.getStateNamed('flyingDown'), 3: self.suitFSM.getStateNamed('flyingUp'), 4: self.suitFSM.getStateNamed('lured'), 5: self.suitFSM.getStateNamed('eagleFly'), 6: self.suitFSM.getStateNamed('eagleFall')} self.suitState2stateIndex = {} for stateId, state in self.stateIndex2suitState.items(): self.suitState2stateIndex[state.getName()] = stateId def setFlySpeed(self, value): self.flySpeed = value def getFlySpeed(self): return self.flySpeed def enterEagleFly(self, startIndex, endIndex, ts = 0.0): durationFactor = self.getFlySpeed() if startIndex > -1: startPos = EGG.EAGLE_FLY_POINTS[startIndex] else: startPos = self.getPos(render) endPos = EGG.EAGLE_FLY_POINTS[endIndex] if self.moveIval: self.moveIval.pause() self.moveIval = None self.moveIval = NPCWalkInterval(self, endPos, durationFactor=durationFactor, startPos=startPos, fluid=1) self.moveIval.start(ts) return def exitEagleFly(self): if self.moveIval: self.moveIval.pause() self.moveIval = None return def enterEagleFall(self, startIndex, endIndex, ts = 0.0): self.moveIval = LerpPosInterval(self, duration=4.0, pos=self.getPos(render) - (0, 0, 75), startPos=self.getPos(render), blendType='easeIn') self.moveIval.start(ts) def exitEagleFall(self): if self.moveIval: self.moveIval.finish() self.moveIval = None return def fallAndExplode(self): self.cleanupPropeller() self.fallingPropeller = Actor('phase_4/models/props/propeller-mod.bam', {'chan': 'phase_4/models/props/propeller-chan.bam'}) self.fallingPropeller.reparentTo(render) self.fallingPropeller.loop('chan', fromFrame=0, toFrame=3) parentNode = self.attachNewNode('fallingPropParentNode') h = random.randint(0, 359) parentNode.setH(h) dummyNode = parentNode.attachNewNode('dummyNode') dummyNode.setPos(0, 10, -50) self.fallingPropProjectile = FlightProjectileInterval(self.fallingPropeller, startPos=self.find('**/joint_head').getPos(render), endPos=dummyNode.getPos(render), duration=5.0, gravityMult=0.25) self.fallingPropProjectile.start() dummyNode.removeNode() del dummyNode parentNode.removeNode() del parentNode self.updateHealthBar(0) self.ignoreHit() self.fallWhistle.play() taskMgr.doMethodLater(4.0, self.doExplodeSound, self.uniqueName('DEagleSuit-doExplodeSound')) def doExplodeSound(self, task): self.explode.play() return Task.done def __initializeEventSphere(self): sphere = CollisionSphere(0, 0, 0, 2) sphere.setTangible(0) node = CollisionNode(self.uniqueName('DEagleSuit-eventSphere')) node.addSolid(sphere) node.setCollideMask(CIGlobals.WallBitmask) np = self.attachNewNode(node) np.setSz(2.5) np.setZ(5.5) self.eventSphereNodePath = np def removeEventSphere(self): if self.eventSphereNodePath: self.eventSphereNodePath.removeNode() self.eventSphereNodePath = None return def acceptHit(self): self.acceptOnce('enter' + self.eventSphereNodePath.node().getName(), self.__handleHit) def ignoreHit(self): self.ignore('enter' + self.eventSphereNodePath.node().getName()) def __handleHit(self, entry): messenger.send(EGG.EAGLE_HIT_EVENT, [self.doId]) def setSuit(self, arg, variant): DistributedSuit.setSuit(self, arg, 3) self.deleteShadow() self.disableBodyCollisions() self.disableRay() self.__initializeEventSphere() self.show() self.setAnimState('flyNeutral') def __doEagleCry(self, task): self.eagleCry.play() task.delayTime = random.uniform(3, 30) return Task.again def announceGenerate(self): DistributedSuit.announceGenerate(self) taskMgr.doMethodLater(random.uniform(5, 25), self.__doEagleCry, self.uniqueName('DEagleSuit-doEagleCry')) self.acceptHit() def disable(self): self.ignoreHit() self.removeEventSphere() taskMgr.remove(self.uniqueName('DEagleSuit-doExplodeSound')) taskMgr.remove(self.uniqueName('DEagleSuit-doEagleCry')) if self.fallingPropProjectile: self.fallingPropProjectile.finish() self.fallingPropProjectile = None if self.fallingPropeller: self.fallingPropeller.cleanup() self.fallingPropeller = None base.audio3d.detachSound(self.fallWhistle) del self.fallWhistle base.audio3d.detachSound(self.explode) del self.explode base.audio3d.detachSound(self.eagleCry) del self.eagleCry self.mg = None DistributedSuit.disable(self) return
class EnemyUnit(Unit): """Base class of enemy units. Args: id_ (int): Enemy unit id. class_ (str): Enemy class name. class_data (dict): Enemy class description. model (actor.Actor): Enemy character model. y_positions (list): Free positions along Y. enemy_handler (CollisionHandlerEvent): Enemy collisions handler. """ def __init__(self, id_, class_, class_data, model, y_positions, enemy_handler): Unit.__init__(self, "enemy_" + str(id_), class_, class_data) self.transport_snd = None self._move_int = None self._rb_node = None self._tooltip = "Skinhead - " + self.class_ self._y_positions = y_positions self._y_pos = take_random(self._y_positions) self._x_range = (-0.3, 0.4) if self.class_data["part"] == "side" else (0.6, 1.3) self.node = render.attachNewNode(self.id + "_node") # noqa: F821 self.node.setPos(self._io_dist, -7, 0) self.model = model self.model.pose("ride", 1) self.model.reparentTo(self.node) # organize movement and aiming tasks time_to_overtake = random.randint(33, 50) self._move(time_to_overtake, (self._y_pos, random.uniform(*self._x_range), 0)) taskMgr.doMethodLater( # noqa: F821 time_to_overtake + 2, self._float_move, self.id + "_float_move" ) @abc.abstractmethod def _explode(self): raise NotImplementedError( "Every enemy unit class must implement _explode() method." ) @property def _io_dist(self): """Enemy Y-distance for approach and back off.""" if self._y_pos > 0: return self._y_pos + 0.45 return self._y_pos - 0.45 @property def clear_delay(self): """Delay between this unit death and its clearing. Returns: int: Seconds to hold the unit before delete. """ return 15 @property def shooting_speed(self): """Delay between shots of this unit. Returns: float: Delay between shots in seconds. """ return 1.7 + random.uniform(0.1, 0.9) @property def tooltip(self): """Tooltip to show on mouse pointing to this enemy. Returns: str: This unit fraction and class. """ return self._tooltip def _die(self): """Make this enemy unit die. Play death sequence of movements and sounds, stop all the tasks for this enemy, plan clearing. Returns: bool: True, if the unit dies for the first time. """ if not Unit._die(self): return False self.model.setColorScale(1, 1, 1, 1) self._stop_tasks("_float_move") self._move_int.pause() self.model.play("die") if self.id in base.world.enemy.active_units: # noqa: F821 base.world.enemy.active_units.pop(self.id) # noqa: F821 if self.current_part: self.current_part.enemies.remove(self) self._explode() self.transport_snd.stop() self._y_positions.append(self._y_pos) base.add_head(self.class_data["class"].__name__) # noqa: F821 return True def _float_move(self, task): """Make enemy floatly move along the Train.""" if chance(80): shift = random.choice((-0.05, 0.05)) if self._y_pos + shift in self._y_positions: self._y_positions.append(self._y_pos) self._y_pos = self._y_pos + shift self._y_positions.remove(self._y_pos) self._move( random.randint(3, 6), (self._y_pos, random.uniform(*self._x_range), 0) ) task.delayTime = random.randint(7, 9) return task.again def _move(self, period, new_pos): """Run a new movement interval with the given parameters. Args: period (tuple): Interval duration bounds. new_pos (tuple): New enemy position. """ if self._move_int is not None: self._move_int.pause() self._move_int = LerpPosInterval( self.node, period, new_pos, blendType="easeInOut" ) self._move_int.start() def capture_train(self): """The Train got critical damage - stop near it.""" self._stop_tasks("_float_move") def clear(self, task=None): """Clear all the graphical, physical and sound data of this unit.""" base.sound_mgr.detach_sound(self.transport_snd) # noqa: F821 if getattr(self, "_cry_snd", None): base.sound_mgr.detach_sound(self._cry_snd) # noqa: F821 self._move_int.finish() self.model.cleanup() self.node.removeNode() if self._rb_node is not None: base.world.phys_mgr.removeRigidBody(self._rb_node) # noqa: F821 if task is not None: return task.done def get_damage(self, damage): """Take damage points and change model color. The more damage the unit taken the more red it'll be. Args: damage (int): Damage points to get. """ Unit.get_damage(self, damage) self.model.setColorScale(self.model.getColorScale()[0] + 0.018, 1, 1, 1) def stop(self): """Smoothly stop this unit following the Train.""" self._stop_tasks("_float_move") self._move(random.randint(9, 11), (self._io_dist, -7, 0)) self._y_positions.append(self._y_pos) def stop_ride(self): """Stop riding actions.""" self.transport_snd.stop()