class SeaMonster(UsesAnimationMixer, Avatar.Avatar, UsesEffectNode): FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0)) SfxNames = { 'death': SoundGlobals.SFX_MONSTER_DEATH } sfx = { } actor = None animInfo = { } class AnimationMixer(AnimationMixer): LOOP = AnimationMixer.LOOP ACTION = dict(AnimationMixer.ACTION) ACTION['MOVIE'] = AnimationMixer.ACTION_INDEX + 1 def __init__(self, animationMixer = None): Avatar.Avatar.__init__(self) UsesEffectNode.__init__(self) self.setPickable(0) self.shadowFileName = 'models/misc/drop_shadow' self.nameText = None self.avatarType = None if not SeaMonster.sfx: for name in SeaMonster.SfxNames: SeaMonster.sfx[name] = loadSfx(SeaMonster.SfxNames[name]) OTPRender.renderReflection(False, self, 'p_creature', None) animationMixer = self.AnimationMixer UsesAnimationMixer.__init__(self, animationMixer) def delete(self): Avatar.Avatar.delete(self) def forceLoadAnimDict(self): for anim in self.animDict: self.getAnimControls(anim) def generateSeaMonster(self): if self.actor: self.copyActor(self.actor) def setAvatarType(self, avatarType): if self.avatarType: self.initializeNametag3d() return None else: self.avatarType = avatarType self.height = EnemyGlobals.getHeight(avatarType) self.initializeDropShadow() self.initializeNametag3d() def initializeNametag3d(self): if self.avatarType.isA(AvatarType(base = AvatarTypes.Animal)): return None Avatar.Avatar.initializeNametag3d(self) self.nametag3d.setH(self.getGeomNode().getH()) self.nametag3d.setFogOff() self.nametag3d.setLightOff() self.nametag3d.setColorScaleOff(100) self.nametag.setFont(PiratesGlobals.getPirateBoldOutlineFont()) self.iconNodePath = self.nametag.getNameIcon() if self.iconNodePath.isEmpty(): self.notify.warning('empty iconNodePath in initializeNametag3d') return 0 if not self.nameText: self.nameText = OnscreenText(fg = Vec4(1, 1, 1, 1), bg = Vec4(0, 0, 0, 0), scale = 1.1000000000000001, align = TextNode.ACenter, mayChange = 1, font = PiratesGlobals.getPirateBoldOutlineFont()) self.nameText.reparentTo(self.iconNodePath) self.nameText.setTransparency(TransparencyAttrib.MDual, 2) self.nameText.setColorScaleOff(100) self.nameText.setLightOff() self.nameText.setFogOff() scale = self.nametag3d.getScale(render) self.nameText.setScale(1.0 / scale[0]) def scaleAnimRate(self, forwardSpeed): rate = 1.0 myMaxSpeed = self.getMaxSpeed() if myMaxSpeed > 0 and forwardSpeed > 0: currTime = globalClockDelta.globalClock.getFrameTime() maxSpeed = myMaxSpeed * (currTime - self.prevSpeedClock) prevTime = self.prevSpeedClock self.prevSpeedClock = currTime rate = min(1.25, forwardSpeed / maxSpeed) return rate def getNametagJoints(self): joints = [] for lodName in self.getLODNames(): bundle = self.getPartBundle('modelRoot', lodName) joint = bundle.findChild('name_tag') if joint: joints.append(joint) continue return joints def getAirborneHeight(self): return 0.0 def getMaxSpeed(self): return 0 def getRadius(self): return self.battleTubeRadius def play(self, *args, **kwArgs): UsesAnimationMixer.play(self, *args, **args) def loop(self, *args, **kwArgs): UsesAnimationMixer.loop(self, *args, **args) def pingpong(self, *args, **kwArgs): UsesAnimationMixer.pingpong(self, *args, **args) def pose(self, *args, **kwArgs): UsesAnimationMixer.pose(self, *args, **args) def stop(self, *args, **kwArgs): UsesAnimationMixer.stop(self, *args, **args) def getDeathAnimName(self, animNum = None): animStrings = [ 'death'] if animNum not in range(len(animStrings)): animNum = random.choice([ 0]) return animStrings[animNum] def getAnimInfo(self, state): return self.animInfo.get(state, self.FailsafeAnims) def setupAnimInfoState(cls, state, info): if len(info) < len(cls.FailsafeAnims): info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):] cls.animInfo[state] = info setupAnimInfoState = classmethod(setupAnimInfoState) def setupAnimInfo(cls): cls.setupAnimInfoState('LandRoam', cls.FailsafeAnims) cls.setupAnimInfoState('WaterRoam', cls.FailsafeAnims) setupAnimInfo = classmethod(setupAnimInfo) def setupAnims(cls): cls.animInfo = copy.copy(SeaMonster.animInfo) cls.setupAnimInfo() filePrefix = cls.ModelInfo[1] animList = cls.AnimList animDict = { } for anim in animList: animDict[anim[0]] = filePrefix + anim[1] cls.animDict = animDict setupAnims = classmethod(setupAnims) def setLODs(self): avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [ 0, 20, 80, 280] elif avatarDetail == 'med': dist = [ 0, 10, 40, 280] elif avatarDetail == 'low': dist = [ 0, 6, 20, 280] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail self.addLOD('low', dist[3], dist[2]) self.addLOD('med', dist[2], dist[1]) self.addLOD('hi', dist[1], dist[0]) def setupAssets(cls): cls.animInfo = copy.copy(SeaMonster.animInfo) cls.setupAnimInfo() filePrefix = cls.ModelInfo[1] animList = cls.AnimList animDict = { } for anim in animList: animDict[anim[0]] = filePrefix + anim[1] cls.animDict = animDict filePrefix = cls.ModelInfo[1] for name in cls.SfxNames: cls.sfx[name] = loadSfx(cls.SfxNames[name]) cls.actor = Actor.Actor() if loader.loadModel(filePrefix + 'med') != None: avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [ 0, 200, 800, 2800] elif avatarDetail == 'med': dist = [ 0, 100, 400, 2800] elif avatarDetail == 'low': dist = [ 0, 60, 200, 2800] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail cls.actor.setLODNode() cls.actor.addLOD('low', dist[3], dist[2]) cls.actor.addLOD('med', dist[2], dist[1]) cls.actor.addLOD('hi', dist[1], dist[0]) cls.actor.loadModel(filePrefix + 'hi', 'modelRoot', 'hi') cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'med') cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'low') cls.actor.loadAnims(cls.animDict, 'modelRoot', 'all') else: cls.actor.loadModel(cls.ModelInfo[0]) cls.actor.loadAnims(cls.animDict) cls.actor.getGeomNode().setH(180) setupAssets = classmethod(setupAssets)
class Creature(UsesAnimationMixer, Avatar.Avatar, UsesEffectNode): __module__ = __name__ FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0)) SfxNames = {'death': SoundGlobals.SFX_MONSTER_DEATH} sfx = {} actor = None animInfo = {} class AnimationMixer(AnimationMixer): __module__ = __name__ LOOP = AnimationMixer.LOOP ACTION = dict(AnimationMixer.ACTION) ACTION['MOVIE'] = AnimationMixer.ACTION_INDEX + 1 def __init__(self, animationMixer=None): Avatar.Avatar.__init__(self) UsesEffectNode.__init__(self) self.setPickable(0) self.shadowFileName = 'models/misc/drop_shadow' self.dimensions = VBase3(0.0, 0.0, 0.0) self.nameText = None self.avatarType = None self.level = None self.nametagOffset = 2.0 self.headNode = self.find('**/def_head') if not Creature.sfx: for name in Creature.SfxNames: Creature.sfx[name] = loadSfx(Creature.SfxNames[name]) self.setupReflection() animationMixer = animationMixer or self.AnimationMixer UsesAnimationMixer.__init__(self, animationMixer) self.deathEffect = None self.shockwaveRingIval = None self.shockwaveRingEffect = None self.spiritIval = None self.spiritEffect = None return def delete(self): if self.deathEffect: self.deathEffect.stop() self.deathEffect = None if self.shockwaveRingIval: self.shockwaveRingIval.pause() self.shockwaveRingIval = None if self.shockwaveRingEffect: self.shockwaveRingEffect.stop() self.shockwaveRingEffect = None if self.spiritIval: self.spiritIval.pause() self.spiritIval = None if self.spiritEffect: self.spiritEffect.stop() self.spiritEffect = None Avatar.Avatar.delete(self) UsesAnimationMixer.delete(self) UsesEffectNode.delete(self) return def setupReflection(self): OTPRender.renderReflection(False, self, 'p_creature', None) return def forceLoadAnimDict(self): for anim in self.animDict: self.getAnimControls(anim) def generateCreature(self): if self.actor: self.copyActor(self.actor) self.headNode = self.find('**/def_head') if base.options.character_detail_level == PiratesGlobals.CD_LOW: self.setLODAnimation(100, 5, 0.1) self.enableMixing() @report(types=['module', 'args'], dConfigParam='nametag') def setAvatarType(self, avatarType): self.avatarType = avatarType self.height = EnemyGlobals.getHeight(avatarType) self.initializeDropShadow() if base.options.terrain_detail_level == PiratesGlobals.CD_LOW: self.shadowPlacer.off() self.initializeNametag3d() def setLevel(self, level): self.level = level def getLevel(self): return self.level @report(types=['module', 'args'], dConfigParam='nametag') def initializeNametag3d(self): Avatar.Avatar.initializeNametag3d(self) self.nametag3d.setFogOff() self.nametag3d.setLightOff() self.nametag3d.setColorScaleOff(100) self.nametag3d.setH(self.getGeomNode().getH()) self.nametag.setFont(PiratesGlobals.getPirateBoldOutlineFont()) self.iconNodePath = self.nametag.getNameIcon() if self.iconNodePath.isEmpty(): self.notify.warning('empty iconNodePath in initializeNametag3d') return 0 if not self.nameText: self.nameText = OnscreenText( fg=Vec4(1, 1, 1, 1), bg=Vec4(0, 0, 0, 0), scale=1.1, align=TextNode.ACenter, mayChange=1, font=PiratesGlobals.getPirateBoldOutlineFont()) self.nameText.reparentTo(self.iconNodePath) self.nameText.setTransparency(TransparencyAttrib.MDual, 2) self.nameText.setColorScaleOff(100) self.nameText.setLightOff() self.nameText.setFogOff() def initializeNametag3dPet(self): pass def getNameText(self): return self.nameText def scaleAnimRate(self, forwardSpeed): rate = 1.0 myMaxSpeed = self.getMaxSpeed() if myMaxSpeed > 0 and forwardSpeed > 0: currTime = globalClockDelta.globalClock.getFrameTime() maxSpeed = myMaxSpeed * (currTime - self.prevSpeedClock) prevTime = self.prevSpeedClock self.prevSpeedClock = currTime rate = min(1.25, forwardSpeed / maxSpeed) return rate @report(types=['module', 'args'], dConfigParam='nametag') def getNametagJoints(self): joints = [] for lodName in self.getLODNames(): bundle = self.getPartBundle('modelRoot', lodName) joint = bundle.findChild('name_tag') if joint: joints.append(joint) return joints def adjustNametag3d(self, parentScale=1.0): self.nametag3d.setZ(self.scale * parentScale * self.nametagOffset - self.nametagOffset) def getAirborneHeight(self): return 0.0 def getMaxSpeed(self): return 0 def getRadius(self): return self.battleTubeRadius def play(self, *args, **kwArgs): UsesAnimationMixer.play(self, *args, **kwArgs) def loop(self, *args, **kwArgs): UsesAnimationMixer.loop(self, *args, **kwArgs) def pingpong(self, *args, **kwArgs): UsesAnimationMixer.pingpong(self, *args, **kwArgs) def pose(self, *args, **kwArgs): UsesAnimationMixer.pose(self, *args, **kwArgs) def stop(self, *args, **kwArgs): UsesAnimationMixer.stop(self, *args, **kwArgs) def getDeathAnimName(self, animNum=None): animStrings = ['death'] if animNum not in range(len(animStrings)): animNum = random.choice([0]) return animStrings[animNum] def getAnimInfo(self, state): return self.animInfo.get(state, self.FailsafeAnims) @classmethod def setupAnimInfoState(cls, state, info): if len(info) < len(cls.FailsafeAnims): info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):] cls.animInfo[state] = info @classmethod def setupAnimInfo(cls): cls.setupAnimInfoState('LandRoam', cls.FailsafeAnims) cls.setupAnimInfoState('WaterRoam', cls.FailsafeAnims) def setLODs(self): avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [0, 20, 80, 280] else: if avatarDetail == 'med': dist = [0, 10, 40, 280] else: if avatarDetail == 'low': dist = [0, 5, 20, 280] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail self.addLOD('hi', dist[1], dist[0]) self.addLOD('med', dist[2], dist[1]) self.addLOD('low', dist[3], dist[2]) @classmethod def setupAssets(cls): cls.animInfo = Creature.animInfo.copy() cls.setupAnimInfo() filePrefix = cls.ModelInfo[1] animList = cls.AnimList animDict = {} for anim in animList: animDict[anim[0]] = filePrefix + anim[1] cls.animDict = animDict filePrefix = cls.ModelInfo[1] for name in cls.SfxNames: cls.sfx[name] = loadSfx(cls.SfxNames[name]) cls.actor = Actor.Actor() if loader.loadModel(filePrefix + 'med') != None: avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [0, 20, 80, 280] else: if avatarDetail == 'med': dist = [0, 10, 40, 280] else: if avatarDetail == 'low': dist = [0, 6, 20, 280] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail cls.actor.setLODNode() cls.actor.addLOD('hi', dist[1], dist[0]) cls.actor.addLOD('med', dist[2], dist[1]) cls.actor.addLOD('low', dist[3], dist[2]) creatureDetail = base.config.GetBool('want-high-creature-detail', 0) if creatureDetail: cls.actor.loadModel(filePrefix + 'hi', 'modelRoot', 'hi') cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'med') cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'low') else: cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'hi') cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'med') cls.actor.loadModel(filePrefix + 'super', 'modelRoot', 'low') cls.actor.loadAnims(cls.animDict, 'modelRoot', 'all') else: cls.actor.loadModel(cls.ModelInfo[0]) cls.actor.loadAnims(cls.animDict) cls.actor.getGeomNode().setH(180) return def getSfx(self, name): return self.sfx.get(name) def shouldNotice(self): return 1 def endShuffle(self): idleAnimInfo = self.animInfo['LandRoam'][PiratesGlobals.STAND_INDEX] try: self.loop(idleAnimInfo[0], blendDelay=0.3, rate=idleAnimInfo[1]) except TypeError, e: self.notify.error('Invalid animation %s for %s' % (idleAnimInfo, self))
class Biped(UsesAnimationMixer, Avatar, UsesEffectNode): SfxNames = { 'death': SoundGlobals.SFX_MONSTER_DEATH } sfx = { } FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0)) animInfo = { } def __init__(self, other = None, animationMixerClass = BipedAnimationMixer): self.wantZombie = base.config.GetBool('want-zombie', 0) Avatar.__init__(self, other) UsesAnimationMixer.__init__(self, animationMixerClass) UsesEffectNode.__init__(self) Biped.initSfx() self.setPickable(0) self.height = 0.0 self.nametagOffset = -5.0 self.rootScale = 1.0 self.nameText = None self.iconNodePath = None self.battleTubeHeight = 0.0 self.battleTubeRadius = 0.0 self.lerpHeadTrack = None self.loadAnimatedHead = None self.rightHandNode = NodePath(ModelNode('rightHand')) self.leftHandNode = NodePath(ModelNode('leftHand')) self.weaponJointInstances = [] self.headFudgeHpr = Vec3(0, 0, 0) self.renderReflection = False self.nametag2dContents = 0 self.nametag2dDist = 0 self.nametag2dNormalContents = 0 self.nametag.getNametag2d().setContents(0) self.nametag3d.setLightOff() self.fader = None def setName(self, val): Avatar.setName(self, val) def deleteWeaponJoints(self): if not self.rightHandNode.isEmpty(): self.rightHandNode.detachNode() if not self.leftHandNode.isEmpty(): self.leftHandNode.detachNode() for node in self.weaponJointInstances: node.detachNode() self.weaponJointInstances = [] def delete(self): self.loadAnimatedHead = None self.deleteWeaponJoints() Avatar.delete(self) UsesAnimationMixer.delete(self) UsesEffectNode.delete(self) def actorInterval(self, *args, **kwargs): if hasattr(self, 'undead') and self.undead: return UsesAnimationMixer.actorInterval(self.skeleton, *args, **kwArgs) else: bodyIval = UsesAnimationMixer.actorInterval(self, *args, **kwArgs) return bodyIval def play(self, *args, **kwArgs): if hasattr(self, 'undead') and self.undead: UsesAnimationMixer.play(self.skeleton, *args, **kwArgs) else: UsesAnimationMixer.play(self, *args, **kwArgs) def loop(self, *args, **kwArgs): if hasattr(self, 'undead') and self.undead: UsesAnimationMixer.loop(self.skeleton, *args, **kwArgs) else: UsesAnimationMixer.loop(self, *args, **kwArgs) def stop(self, *args, **kwArgs): if hasattr(self, 'undead') and self.undead: UsesAnimationMixer.stop(self.skeleton, *args, **kwArgs) else: UsesAnimationMixer.stop(self, *args, **kwArgs) def pose(self, *args, **kwArgs): if hasattr(self, 'undead') and self.undead: UsesAnimationMixer.pose(self.skeleton, *args, **kwArgs) else: UsesAnimationMixer.pose(self, *args, **kwArgs) def pingpong(self, *args, **kwArgs): if hasattr(self, 'undead') and self.undead: UsesAnimationMixer.pingpong(self.skeleton, *args, **kwArgs) else: UsesAnimationMixer.pingpong(self, *args, **kwArgs) def getDuration(self, animName = None, partName = None, fromFrame = None, toFrame = None): return Avatar.getDuration(self, animName, partName, fromFrame, toFrame) def getFrameTime(self, animName, frame, partName = None): return Avatar.getFrameTime(self, animName, frame, partName) def getRadius(self): return self.battleTubeRadius def getWeaponJoints(self): self.deleteWeaponJoints() lods = list(self.getLODNames()) lods.sort() for lodName in lods: handLocator = self.getLOD(lodName).find('**/*weapon_right') if not handLocator.isEmpty(): if lodName == lods[0]: self.rightHandNode.reparentTo(handLocator) else: self.weaponJointInstances.append(self.rightHandNode.instanceTo(handLocator)) handLocator = self.getLOD(lodName).find('**/*weapon_left') if not handLocator.isEmpty(): if lodName == lods[0]: self.leftHandNode.reparentTo(handLocator) else: self.weaponJointInstances.append(self.leftHandNode.instanceTo(handLocator)) self.postAsyncLoadFix() def postAsyncLoadFix(self): pass def startLookAroundTask(self): taskMgr.remove(self.lookAroundTaskName) if self.headNode: delayTime = 1.0 + random.random() * 1.0 taskMgr.doMethodLater(delayTime, self.lookAroundTask, self.lookAroundTaskName) def stopLookAroundTask(self): taskMgr.remove(self.lookAroundTaskName) if self.lerpHeadTrack: self.lerpHeadTrack.pause() self.lerpHeadTrack = None if self.headNode: self.headNode.setHpr(self.headFudgeHpr) def isInFov(self, target): k = 0.66579999999999995 relPos = target.getPos(self) if relPos[1] > 0: tan = relPos[0] / relPos[1] if tan < k and tan > -k: return 1 return 0 def lookAroundTask(self, task): if self.isLocal(): if self.gameFSM.state == 'Battle' and self.currentTarget and not self.currentTarget.isEmpty(): task.delayTime = 5.0 return Task.again if self.getCurrentAnim() in stopLookaroundAnimList: self.headNode.setHpr(self.headFudgeHpr) return Task.again hFov = 90 vFov = 35 if base.cr.targetMgr: allTargets = base.cr.targetMgr.objectDict.values() else: allTargets = [] visibleTargets = [] for target in allTargets: if not target.isEmpty(): if self.isInFov(target): visibleTargets.append(target) self.isInFov(target) if len(visibleTargets) > 0: if random.choice((True, True, False)): dummyNode = self.attachNewNode('dummy') dummyNode.setZ(self.getHeight()) dummyNode.lookAt(random.choice(visibleTargets)) heading = max(-hFov * 0.5, min(hFov * 0.5, dummyNode.getH())) pitch = max(-vFov * 0.5, min(vFov * 0.5, dummyNode.getP())) newHpr = Vec3(0, heading, -pitch) dummyNode.removeNode() else: newHpr = self.headFudgeHpr elif random.choice((True, True, False)): newHpr = Vec3(0, random.random() * hFov - hFov * 0.5, random.random() * vFov - vFov * 0.5) else: newHpr = self.headFudgeHpr if self.lerpHeadTrack: self.lerpHeadTrack.pause() self.lerpHeadTrac3dk = None t = 0.20000000000000001 + random.random() * 0.80000000000000004 self.lerpHeadTrack = LerpHprInterval(self.headNode, t, newHpr, blendType = 'easeInOut') self.lerpHeadTrack.start() task.delayTime = 3.0 + random.random() * 4.0 return Task.again def initializeNametag3d(self): Avatar.initializeNametag3d(self) self.nametag3d.setColorScaleOff(100) self.nametag3d.setLightOff() self.nametag3d.setFogOff() self.nametag3d.setZ(self.scale) self.nametag3d.setH(self.getGeomNode().getH()) self.nametag.setFont(PiratesGlobals.getPirateFont()) return 0 # TODO: fix iconNodePath self.iconNodePath = self.nametag.getNameIcon() if self.iconNodePath.isEmpty(): self.notify.warning('empty iconNodePath in initializeNametag3d') return 0 if not self.nameText: self.nameText = OnscreenText(fg = Vec4(1, 1, 1, 1), bg = Vec4(0, 0, 0, 0), scale = 1.1000000000000001, align = TextNode.ACenter, mayChange = 1, font = PiratesGlobals.getPirateBoldOutlineFont()) self.nameText.reparentTo(self.iconNodePath) self.nameText.setTransparency(TransparencyAttrib.MDual, 2) self.nameText.setColorScaleOff(100) self.nameText.setLightOff() self.nameText.setFogOff() self.nameTag3dInitialized() def nameTag3dInitialized(self): pass def getNameText(self): return self.nameText def getDeathAnimName(self, animNum = None): animStrings = [ 'death', 'death2', 'death3', 'death4'] if animNum not in range(len(animStrings)): animNum = random.choice(range(0, len(animStrings))) return animStrings[animNum] def setChatAbsolute(self, chatString, chatFlags, dialogue = None, interrupt = 1): Avatar.setChatAbsolute(self, chatString, chatFlags, dialogue, interrupt) if chatString: avId = None if hasattr(self, 'doId'): avId = self.doId base.talkAssistant.receiveOpenTalk(avId, self.getName(), 0, None, chatString) def fadeIn(self, time): if self.fader: self.fader.finish() self.fader = None self.setTransparency(1) self.setColorScale(1, 1, 1, 0) self.show() self.fader = self.colorScaleInterval(time, Vec4(1, 1, 1, 1), startColorScale = Vec4(1, 1, 1, 0)) self.fader.start() def fadeOut(self, time): if self.fader: self.fader.finish() self.fader = None self.setTransparency(1) self.setColorScale(1, 1, 1, 1) self.fader = Sequence(self.colorScaleInterval(time, Vec4(1, 1, 1, 0), startColorScale = Vec4(1, 1, 1, 1)), Func(self.hide)) self.fader.start() def setupAnimInfoState(cls, state, info): if len(info) < len(cls.FailsafeAnims): info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):] cls.animInfo[state] = info setupAnimInfoState = classmethod(setupAnimInfoState) def getAnimInfo(self, state): return self.animInfo.get(state, self.FailsafeAnims) def setRenderReflection(self): OTPRender.renderReflection(self.renderReflection, self, 'p_biped', None) def setupAnimInfo(cls): cls.setupAnimInfoState('LandRoam', (('idle', 1.0), ('walk', 1.0), ('run', 1.0), ('walk', -1.0), ('strafe_left', 1), ('strafe_right', 1), ('run_diagonal_left', 1), ('run_diagonal_right', 1), ('walk_back_diagonal_left', 1), ('walk_back_diagonal_right', 1), ('fall_ground', 1), ('fall_ground', 1), ('spin_left', 1), ('spin_right', 1))) cls.setupAnimInfoState('WaterRoam', (('tread_water', 1.0), ('swim', 1.0), ('swim', 1.0), ('swim_back', 1.0), ('swim_left', 1.0), ('swim_right', 1.0), ('swim_left_diagonal', 1.0), ('swim_right_diagonal', 1.0), ('swim_back_diagonal_left', 1.0), ('swim_back_diagonal_right', 1.0), ('fall_ground', 1), ('fall_ground', 1), ('tread_water', 1), ('tread_water', 1))) cls.setupAnimInfoState('LandTreasureRoam', (('chest_idle', 1.0), ('chest_walk', 1.0), ('chest_walk', 1.0), ('chest_walk', -1.0), ('chest_strafe_left', 1.0), ('chest_strafe_right', 1.0), ('chest_strafe_left', 1), ('chest_strafe_right', 1), ('chest_strafe_right', -1), ('chest_strafe_left', -1), ('fall_ground', 1), ('fall_ground', 1), ('chest_walk', 1), ('chest_walk', 1))) cls.setupAnimInfoState('WaterTreasureRoam', (('tread_water', 1.0), ('swim', 1.0), ('swim', 1.0), ('swim_back', 1.0), ('swim_left', 1.0), ('swim_right', 1.0), ('swim_left_diagonal', 1.0), ('swim_right_diagonal', 1.0), ('swim_back_diagonal_left', 1.0), ('swim_back_diagonal_right', 1.0), ('fall_ground', 1), ('fall_ground', 1), ('walk', 1), ('walk', 1))) cls.setupAnimInfoState('BayonetLandRoam', (('bayonet_idle', 1.0), ('bayonet_walk', 1.0), ('bayonet_run', 1.0), ('bayonet_walk', -1.0), ('strafe_left', 1), ('strafe_right', 1), ('run_diagonal_left', 1), ('run_diagonal_right', 1), ('walk_back_diagonal_left', 1), ('walk_back_diagonal_right', 1), ('fall_ground', 1), ('fall_ground', 1), ('spin_left', 1.0), ('spin_right', 1.0))) setupAnimInfo = classmethod(setupAnimInfo) @classmethod def initSfx(cls): for (name, effect) in cls.SfxNames.iteritems(): if name not in cls.sfx: sound = SoundGlobals.loadSfx(effect) if sound and sound.getActive(): cls.sfx[name] = sound
class SeaMonster(UsesAnimationMixer, Avatar.Avatar, UsesEffectNode): FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0)) SfxNames = {'death': SoundGlobals.SFX_MONSTER_DEATH} sfx = {} actor = None animInfo = {} class AnimationMixer(AnimationMixer): LOOP = AnimationMixer.LOOP ACTION = dict(AnimationMixer.ACTION) ACTION['MOVIE'] = AnimationMixer.ACTION_INDEX + 1 def __init__(self, animationMixer=None): Avatar.Avatar.__init__(self) UsesEffectNode.__init__(self) self.setPickable(0) self.shadowFileName = 'models/misc/drop_shadow' self.nameText = None self.avatarType = None if not SeaMonster.sfx: for name in SeaMonster.SfxNames: SeaMonster.sfx[name] = loadSfx(SeaMonster.SfxNames[name]) OTPRender.renderReflection(False, self, 'p_creature', None) animationMixer = self.AnimationMixer UsesAnimationMixer.__init__(self, animationMixer) return def delete(self): Avatar.Avatar.delete(self) def forceLoadAnimDict(self): for anim in self.animDict: self.getAnimControls(anim) def generateSeaMonster(self): if self.actor: self.copyActor(self.actor) def setAvatarType(self, avatarType): if self.avatarType: self.initializeNametag3d() return else: self.avatarType = avatarType self.height = EnemyGlobals.getHeight(avatarType) self.initializeDropShadow() self.initializeNametag3d() def initializeNametag3d(self): if self.avatarType.isA(AvatarType(base=AvatarTypes.Animal)): return Avatar.Avatar.initializeNametag3d(self) self.nametag3d.setH(self.getGeomNode().getH()) self.nametag3d.setFogOff() self.nametag3d.setLightOff() self.nametag3d.setColorScaleOff(100) self.nametag.setFont(PiratesGlobals.getPirateBoldOutlineFont()) self.iconNodePath = self.nametag.getNameIcon() if self.iconNodePath.isEmpty(): self.notify.warning('empty iconNodePath in initializeNametag3d') return 0 if not self.nameText: self.nameText = OnscreenText( fg=Vec4(1, 1, 1, 1), bg=Vec4(0, 0, 0, 0), scale=1.1, align=TextNode.ACenter, mayChange=1, font=PiratesGlobals.getPirateBoldOutlineFont()) self.nameText.reparentTo(self.iconNodePath) self.nameText.setTransparency(TransparencyAttrib.MDual, 2) self.nameText.setColorScaleOff(100) self.nameText.setLightOff() self.nameText.setFogOff() scale = self.nametag3d.getScale(render) self.nameText.setScale(1.0 / scale[0]) def scaleAnimRate(self, forwardSpeed): rate = 1.0 myMaxSpeed = self.getMaxSpeed() if myMaxSpeed > 0 and forwardSpeed > 0: currTime = globalClockDelta.globalClock.getFrameTime() maxSpeed = myMaxSpeed * (currTime - self.prevSpeedClock) prevTime = self.prevSpeedClock self.prevSpeedClock = currTime rate = min(1.25, forwardSpeed / maxSpeed) return rate def getNametagJoints(self): joints = [] for lodName in self.getLODNames(): bundle = self.getPartBundle('modelRoot', lodName) joint = bundle.findChild('name_tag') if joint: joints.append(joint) return joints def getAirborneHeight(self): return 0.0 def getMaxSpeed(self): return 0 def getRadius(self): return self.battleTubeRadius def play(self, *args, **kwArgs): UsesAnimationMixer.play(self, *args, **kwArgs) def loop(self, *args, **kwArgs): UsesAnimationMixer.loop(self, *args, **kwArgs) def pingpong(self, *args, **kwArgs): UsesAnimationMixer.pingpong(self, *args, **kwArgs) def pose(self, *args, **kwArgs): UsesAnimationMixer.pose(self, *args, **kwArgs) def stop(self, *args, **kwArgs): UsesAnimationMixer.stop(self, *args, **kwArgs) def getDeathAnimName(self, animNum=None): animStrings = ['death'] if animNum not in range(len(animStrings)): animNum = random.choice([0]) return animStrings[animNum] def getAnimInfo(self, state): return self.animInfo.get(state, self.FailsafeAnims) @classmethod def setupAnimInfoState(cls, state, info): if len(info) < len(cls.FailsafeAnims): info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):] cls.animInfo[state] = info @classmethod def setupAnimInfo(cls): cls.setupAnimInfoState('LandRoam', cls.FailsafeAnims) cls.setupAnimInfoState('WaterRoam', cls.FailsafeAnims) @classmethod def setupAnims(cls): cls.animInfo = copy.copy(SeaMonster.animInfo) cls.setupAnimInfo() filePrefix = cls.ModelInfo[1] animList = cls.AnimList animDict = {} for anim in animList: animDict[anim[0]] = filePrefix + anim[1] cls.animDict = animDict def setLODs(self): avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [0, 20, 80, 280] elif avatarDetail == 'med': dist = [0, 10, 40, 280] elif avatarDetail == 'low': dist = [0, 6, 20, 280] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail self.addLOD('low', dist[3], dist[2]) self.addLOD('med', dist[2], dist[1]) self.addLOD('hi', dist[1], dist[0]) @classmethod def setupAssets(cls): cls.animInfo = copy.copy(SeaMonster.animInfo) cls.setupAnimInfo() filePrefix = cls.ModelInfo[1] animList = cls.AnimList animDict = {} for anim in animList: animDict[anim[0]] = filePrefix + anim[1] cls.animDict = animDict filePrefix = cls.ModelInfo[1] for name in cls.SfxNames: cls.sfx[name] = loadSfx(cls.SfxNames[name]) cls.actor = Actor.Actor() if loader.loadModel(filePrefix + 'med') != None: avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [0, 200, 800, 2800] elif avatarDetail == 'med': dist = [0, 100, 400, 2800] elif avatarDetail == 'low': dist = [0, 60, 200, 2800] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail cls.actor.setLODNode() cls.actor.addLOD('low', dist[3], dist[2]) cls.actor.addLOD('med', dist[2], dist[1]) cls.actor.addLOD('hi', dist[1], dist[0]) cls.actor.loadModel(filePrefix + 'hi', 'modelRoot', 'hi') cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'med') cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'low') cls.actor.loadAnims(cls.animDict, 'modelRoot', 'all') else: cls.actor.loadModel(cls.ModelInfo[0]) cls.actor.loadAnims(cls.animDict) cls.actor.getGeomNode().setH(180) return
class Creature(UsesAnimationMixer, Avatar.Avatar, UsesEffectNode): FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0)) SfxNames = {'death': SoundGlobals.SFX_MONSTER_DEATH} sfx = {} actor = None animInfo = {} class AnimationMixer(AnimationMixer): LOOP = AnimationMixer.LOOP ACTION = dict(AnimationMixer.ACTION) ACTION['MOVIE'] = AnimationMixer.ACTION_INDEX + 1 def __init__(self, animationMixer = None): Avatar.Avatar.__init__(self) UsesEffectNode.__init__(self) self.setPickable(0) self.shadowFileName = 'models/misc/drop_shadow' self.dimensions = VBase3(0.0, 0.0, 0.0) self.nameText = None self.avatarType = None self.level = None self.nametagOffset = 2.0 self.headNode = self.find('**/def_head') if not Creature.sfx: for name in Creature.SfxNames: Creature.sfx[name] = loadSfx(Creature.SfxNames[name]) self.setupReflection() if not animationMixer: pass animationMixer = self.AnimationMixer UsesAnimationMixer.__init__(self, animationMixer) self.deathEffect = None self.shockwaveRingIval = None self.shockwaveRingEffect = None self.spiritIval = None self.spiritEffect = None def delete(self): if self.deathEffect: self.deathEffect.stop() self.deathEffect = None if self.shockwaveRingIval: self.shockwaveRingIval.pause() self.shockwaveRingIval = None if self.shockwaveRingEffect: self.shockwaveRingEffect.stop() self.shockwaveRingEffect = None if self.spiritIval: self.spiritIval.pause() self.spiritIval = None if self.spiritEffect: self.spiritEffect.stop() self.spiritEffect = None Avatar.Avatar.delete(self) UsesAnimationMixer.delete(self) UsesEffectNode.delete(self) def setupReflection(self): OTPRender.renderReflection(False, self, 'p_creature', None) def forceLoadAnimDict(self): for anim in self.animDict: self.getAnimControls(anim) def generateCreature(self): if self.actor: self.copyActor(self.actor) self.headNode = self.find('**/def_head') if base.options.character_detail_level == PiratesGlobals.CD_LOW: self.setLODAnimation(100, 5, 0.10000000000000001) self.enableMixing() def setAvatarType(self, avatarType): self.avatarType = avatarType self.height = EnemyGlobals.getHeight(avatarType) self.initializeDropShadow() if base.options.terrain_detail_level == PiratesGlobals.CD_LOW: self.shadowPlacer.off() self.initializeNametag3d() setAvatarType = report(types=['module','args'], dConfigParam='nametag')(setAvatarType) def setLevel(self, level): self.level = level def getLevel(self): return self.level def initializeNametag3d(self): Avatar.Avatar.initializeNametag3d(self) self.nametag3d.setFogOff() self.nametag3d.setLightOff() self.nametag3d.setColorScaleOff(100) self.nametag3d.setH(self.getGeomNode().getH()) self.nametag.setFont(PiratesGlobals.getPirateBoldOutlineFont()) self.iconNodePath = self.nametag.getNameIcon() if self.iconNodePath.isEmpty(): self.notify.warning('empty iconNodePath in initializeNametag3d') return False if not self.nameText: self.nameText = OnscreenText(fg = Vec4(1, 1, 1, 1), bg = Vec4(0, 0, 0, 0), scale = 1.1000000000000001, align = TextNode.ACenter, mayChange = 1, font = PiratesGlobals.getPirateBoldOutlineFont()) self.nameText.reparentTo(self.iconNodePath) self.nameText.setTransparency(TransparencyAttrib.MDual, 2) self.nameText.setColorScaleOff(100) self.nameText.setLightOff() self.nameText.setFogOff() initializeNametag3d = report(types=['module','args'], dConfigParam='nametag')(initializeNametag3d) def getNameText(self): return self.nameText def scaleAnimRate(self, forwardSpeed): rate = 1.0 myMaxSpeed = self.getMaxSpeed() if myMaxSpeed > 0 and forwardSpeed > 0: currTime = globalClockDelta.globalClock.getFrameTime() maxSpeed = myMaxSpeed * (currTime - self.prevSpeedClock) prevTime = self.prevSpeedClock self.prevSpeedClock = currTime rate = min(1.25, forwardSpeed / maxSpeed) return rate def getNametagJoints(self): joints = [] for lodName in self.getLODNames(): bundle = self.getPartBundle('modelRoot', lodName) joint = bundle.findChild('name_tag') if joint: joints.append(joint) continue return joints getNametagJoints = report(types=['module','args'], dConfigParam='nametag')(getNametagJoints) def adjustNametag3d(self, parentScale = 1.0): self.nametag3d.setZ(self.scale * parentScale * self.nametagOffset - self.nametagOffset) def getAirborneHeight(self): return 0.0 def getMaxSpeed(self): return 0 def getRadius(self): return self.battleTubeRadius def play(self, *args, **kwArgs): UsesAnimationMixer.play(self, *args, **kwArgs) def loop(self, *args, **kwArgs): UsesAnimationMixer.loop(self, *args, **kwArgs) def pingpong(self, *args, **kwArgs): UsesAnimationMixer.pingpong(self, *args, **kwArgs) def pose(self, *args, **kwArgs): UsesAnimationMixer.pose(self, *args, **kwArgs) def stop(self, *args, **kwArgs): UsesAnimationMixer.stop(self, *args, **kwArgs) def getDeathAnimName(self, animNum = None): animStrings = ['death'] if animNum not in range(len(animStrings)): animNum = random.choice([0]) return animStrings[animNum] def getAnimInfo(self, state): return self.animInfo.get(state, self.FailsafeAnims) def setupAnimInfoState(cls, state, info): if len(info) < len(cls.FailsafeAnims): info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):] cls.animInfo[state] = info setupAnimInfoState = classmethod(setupAnimInfoState) def setupAnimInfo(cls): cls.setupAnimInfoState('LandRoam', cls.FailsafeAnims) cls.setupAnimInfoState('WaterRoam', cls.FailsafeAnims) setupAnimInfo = classmethod(setupAnimInfo) def setLODs(self): avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [ 0, 20, 80, 280] elif avatarDetail == 'med': dist = [ 0, 10, 40, 280] elif avatarDetail == 'low': dist = [ 0, 5, 20, 280] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail self.addLOD('hi', dist[1], dist[0]) self.addLOD('med', dist[2], dist[1]) self.addLOD('low', dist[3], dist[2]) def setupAssets(cls): cls.animInfo = Creature.animInfo.copy() cls.setupAnimInfo() filePrefix = cls.ModelInfo[1] animList = cls.AnimList animDict = { } for anim in animList: animDict[anim[0]] = filePrefix + anim[1] cls.animDict = animDict filePrefix = cls.ModelInfo[1] for name in cls.SfxNames: cls.sfx[name] = loadSfx(cls.SfxNames[name]) cls.actor = Actor.Actor() if loader.loadModel(filePrefix + 'med') != None: avatarDetail = base.config.GetString('avatar-detail', 'high') if avatarDetail == 'high': dist = [ 0, 20, 80, 280] elif avatarDetail == 'med': dist = [ 0, 10, 40, 280] elif avatarDetail == 'low': dist = [ 0, 6, 20, 280] else: raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail cls.actor.setLODNode() cls.actor.addLOD('hi', dist[1], dist[0]) cls.actor.addLOD('med', dist[2], dist[1]) cls.actor.addLOD('low', dist[3], dist[2]) creatureDetail = base.config.GetBool('want-high-creature-detail', 0) if creatureDetail: cls.actor.loadModel(filePrefix + 'hi', 'modelRoot', 'hi') cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'med') cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'low') else: cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'hi') cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'med') cls.actor.loadModel(filePrefix + 'super', 'modelRoot', 'low') cls.actor.loadAnims(cls.animDict, 'modelRoot', 'all') else: cls.actor.loadModel(cls.ModelInfo[0]) cls.actor.loadAnims(cls.animDict) cls.actor.getGeomNode().setH(180) setupAssets = classmethod(setupAssets) def getSfx(self, name): return self.sfx.get(name) def shouldNotice(self): return True def endShuffle(self): idleAnimInfo = self.animInfo['LandRoam'][PiratesGlobals.STAND_INDEX] try: self.loop(idleAnimInfo[0], blendDelay = 0.29999999999999999, rate = idleAnimInfo[1]) except TypeError: e = None self.notify.error('Invalid animation %s for %s' % (idleAnimInfo, self)) def getSplashOverride(self): pass