class GameObject(): def __init__(self, pos, modelName, modelAnims, maxHealth, maxSpeed, colliderName): self.actor = Actor(modelName, modelAnims) self.actor.reparentTo(render) self.actor.setPos(pos) self.maxHealth = maxHealth self.health = maxHealth self.maxSpeed = maxSpeed self.velocity = Vec3(0, 0, 0) self.acceleration = 300.0 self.walking = False colliderNode = CollisionNode(colliderName) colliderNode.addSolid(CollisionSphere(0, 0, 0, 0.3)) self.collider = self.actor.attachNewNode(colliderNode) self.collider.setPythonTag("owner", self) def update(self, dt): speed = self.velocity.length() if speed > self.maxSpeed: self.velocity.normalize() self.velocity *= self.maxSpeed speed = self.maxSpeed if not self.walking: frictionVal = FRICTION * dt if frictionVal > speed: self.velocity.set(0, 0, 0) else: frictionVec = -self.velocity frictionVec.normalize() frictionVec *= frictionVal self.velocity += frictionVec self.actor.setPos(self.actor.getPos() + self.velocity * dt) def alterHealth(self, dHealth): self.health += dHealth if self.health > self.maxHealth: self.health = self.maxHealth def cleanup(self): if self.collider is not None and not self.collider.isEmpty(): self.collider.clearPythonTag("owner") base.cTrav.removeCollider(self.collider) base.pusher.removeCollider(self.collider) if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None self.collider = None
class HealthGoblet(): healthGivenFactor = 8 minHealthGiven = 5 def __init__(self, mainRef, enemyRef): print 'HealthGoblet instantiated' self._enemyRef = enemyRef self._playerRef = mainRef.player self.healthGobletNode = mainRef.mainNode.attachNewNode( 'healthGobletNode') self.initAttributes() self.initModel() taskMgr.doMethodLater(1.5, self.updateHealthGoblet, 'updateHealthGobletTask') def initAttributes(self): self.healthGiven = utils.getDXY( self.minHealthGiven, self._enemyRef.level * self.healthGivenFactor) self.perceptionRange = 0.5 self.healthGobletNode.setPos(self._enemyRef.enemyNode.getPos()) def initModel(self): self.healthGobletModel = Actor('models/HealthGoblet', {'float': 'models/HealthGoblet-anim'}) self.healthGobletModel.reparentTo(self.healthGobletNode) self.healthGobletModel.setCollideMask(BitMask32.allOff()) self.healthGobletModel.setScale(0.5) self.healthGobletModel.loop('float') def updateHealthGoblet(self, task): playerNode = self._playerRef.playerNode if utils.getIsInRange(playerNode.getPos(), self.healthGobletNode.getPos(), self.perceptionRange): print 'healed player for:', self.healthGiven self._playerRef.heal(self.healthGiven) self.healthGobletModel.stop() self.suicide() return task.done return task.again def suicide(self): # Cleanup the healthGobletModel self.healthGobletModel.cleanup() self.healthGobletModel.delete() self.healthGobletNode.removeNode() self._enemyRef = None self._playerRef = None
class Splat(DirectObject): def __init__(self, pos, color, scale): self.pos = pos self.color = color self.scale = scale def generate(self): self.splat = Actor('phase_3.5/models/props/splat-mod.bam', {'chan' : 'phase_3.5/models/props/splat-chan.bam'}) self.splat.setBillboardPointEye() self.splat.setColor(self.color) self.splat.setScale(self.scale) self.splat.setPos(self.pos) self.splat.play('chan') self.splat.reparentTo(render) Sequence( Wait(0.5), Func(self.destroy) ).start() def destroy(self): self.splat.cleanup() self.splat.removeNode() del self.splat del self
class GameObject: def __init__(self, modelName, model_anims, max_health, speed, collider_name, base, pos, hpr=Vec3(0, 0, 0), scale=1.0): self.actor = Actor(modelName, model_anims) self.actor.reparentTo(base.render) self.actor.setPos(pos) self.actor.setHpr(hpr) self.actor.setScale(Vec3(scale, scale, scale)) self.base = base self.max_health = max_health self.health = max_health self.speed = speed colliderNode = CollisionNode(collider_name) colliderNode.addSolid( CollisionCapsule( Vec3(0, 0, 2) * 1 / scale, Vec3(0, 0, 9) * 1 / scale, 6 * 1 / scale)) # colliderNode.addSolid(CollisionSphere(0, 0, 0, 0.3)) self.collider = self.actor.attachNewNode(colliderNode) self.collider.setPythonTag("owner", self) # self.collider.show() def get_position(self): return self.actor.getPos() def rotate(self, angle): self.actor.setHpr(self.actor, angle) def change_health(self, dHealth): self.health += dHealth if self.health > self.max_health: self.health = self.max_health elif self.health < 0: self.health = 0 print(self.health) def cleanup(self): # Remove various nodes, and clear the Python-tag--see below! if self.collider is not None and not self.collider.isEmpty(): # self.collider.clearPythonTag("owner") self.base.cTrav.removeCollider(self.collider) self.base.pusher.removeCollider(self.collider) if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None self.collider = None
def disable(self): try: self.Avatar_disabled except: self.Avatar_disabled = 1 if self.ragdoll: self.ragdoll.cleanup() self.ragdoll = None self.clearFadeTrack() if self in base.avatars: base.avatars.remove(self) if self.dmgFadeIval: self.dmgFadeIval.finish() self.stopActivity() self.dmgFadeIval = None self.stopMovingHealthLabel() if self.healthLabel: self.healthLabel.removeNode() self.healthLabel = None self.healthLabelTrack = None if self.floorTask: self.floorTask.remove() self.floorTask = None self.disableRay() self.deleteNametag3d() self.nametag.destroy() del self.nametag self.nametag3d.removeNode() self.nametag3d = None self.deleteShadow() self.removeLoopTask() self.mat = None self.tag = None self.chat = None self.avatarType = None self.charName = None self.nameTag = None self.cleanupPhysics() self.moveAnimProperties = None self.chatSoundTable = None self.lastWakeTime = None self.prevPos = None if self.wake: self.wake.destroy() self.wake = None if self.splashEffect: self.splashEffect.destroy() self.splashEffect = None self.splashSound = None self.avatarFloorToggle = None self.shadowFloorToggle = None Actor.cleanup(self)
class DistributedTNT(DistributedPhysicsEntity): def __init__(self, cr): DistributedPhysicsEntity.__init__(self, cr) self.tnt = None self.tntSound = None self.particle = None def explode(self): self.tntSound.stop() self.hide() self.particle.softStop() self.cleanupPhysics() CIGlobals.makeExplosion(self.getPos(render) + (0, 0, 5.0), 0.7, True) def doSetupPhysics(self): self.setupPhysics(self.getPhysBody(), True) def getPhysBody(self): shape = BulletCylinderShape(0.3925, 1.4, ZUp) body = BulletRigidBodyNode('tntBody') body.addShape(shape) body.setKinematic(True) body.setCcdMotionThreshold(1e-7) body.setCcdSweptSphereRadius(0.3925) return body def announceGenerate(self): self.tnt = Actor('phase_14/models/props/tnt.bam', {'chan': 'phase_5/models/props/tnt-chan.bam'}) self.tnt.reparentTo(self) self.tnt.play('chan') self.tnt.setP(97.492) self.tnt.setY(0.38) self.tntSound = base.audio3d.loadSfx( "phase_14/audio/sfx/dynamite_loop.ogg") self.tntSound.setLoop(True) base.audio3d.attachSoundToObject(self.tntSound, self.tnt) self.particle = ParticleLoader.loadParticleEffect( "phase_14/etc/tnt_spark.ptf") self.particle.start(self.tnt.find('**/joint_attachEmitter'), CIGlobals.getParticleRender()) DistributedPhysicsEntity.announceGenerate(self) self.tntSound.play() def disable(self): if self.tnt: self.tnt.cleanup() self.tnt.removeNode() self.tnt = None if self.tntSound: self.tntSound.stop() self.tntSound = None if self.particle: self.particle.softStop() self.particle = None DistributedPhysicsEntity.disable(self)
def delete(self): try: self.Avatar_deleted except: Actor.cleanup(self) self.Avatar_deleted = 1 del self.__font del self.style Actor.delete(self)
class HealthGoblet(): healthGivenFactor = 8 minHealthGiven = 5 def __init__(self, mainRef, enemyRef): print 'HealthGoblet instantiated' self._enemyRef = enemyRef self._playerRef = mainRef.player self.healthGobletNode = mainRef.mainNode.attachNewNode('healthGobletNode') self.initAttributes() self.initModel() taskMgr.doMethodLater(1.5, self.updateHealthGoblet, 'updateHealthGobletTask') def initAttributes(self): self.healthGiven = utils.getDXY(self.minHealthGiven, self._enemyRef.level * self.healthGivenFactor) self.perceptionRange = 0.5 self.healthGobletNode.setPos(self._enemyRef.enemyNode.getPos()) def initModel(self): self.healthGobletModel = Actor('models/HealthGoblet', {'float':'models/HealthGoblet-anim'}) self.healthGobletModel.reparentTo(self.healthGobletNode) self.healthGobletModel.setCollideMask(BitMask32.allOff()) self.healthGobletModel.setScale(0.5) self.healthGobletModel.loop('float') def updateHealthGoblet(self, task): playerNode = self._playerRef.playerNode if utils.getIsInRange(playerNode.getPos(), self.healthGobletNode.getPos(), self.perceptionRange): print 'healed player for:', self.healthGiven self._playerRef.heal(self.healthGiven) self.healthGobletModel.stop() self.suicide() return task.done return task.again def suicide(self): # Cleanup the healthGobletModel self.healthGobletModel.cleanup() self.healthGobletModel.delete() self.healthGobletNode.removeNode() self._enemyRef = None self._playerRef = None
def cleanup(self): if self.flyTrack is not None: self.flyTrack.finish() self.flyTrack = None if self.television is not None: self.television.delete() self.television = None Actor.cleanup(self)
def delete(self): try: self.Avatar_deleted except: Actor.cleanup(self) self.Avatar_deleted = 1 self.style = None self.collTube = None self.hpText = None self.hpTextGenerator = None ShadowCaster.delete(self) Actor.delete(self)
def precacheToons(): """ Precaches all Toon models and animations! """ from src.coginvasion.base.Precache import precacheActor, precacheModel from direct.actor.Actor import Actor for legType in LegHeightDict.keys(): toon = Actor() generateBodyPart(toon, 'legs', legType, 3, 'shorts') precacheActor(toon) toon.cleanup() toon.removeNode() for torsoType in TorsoHeightDict.keys(): toon = Actor() generateBodyPart(toon, 'torso', torsoType, 3, '') precacheActor(toon) toon.cleanup() toon.removeNode() for animal in HeadScales.keys(): if animal != "dog": precacheModel("phase_3/models/char/%s-heads-1000.bam" % animal) else: for headType in DogHeads: # precache all dog head models and animations mdl = "phase_3/models/char/tt_a_chr_%s_head_1000.bam" % headType partAnimations = {} # Load the body part animations. for animName in ANIMATIONS: animationData = list(ANIMATIONS[animName]) animPath = None if len(animationData) == 2: animPhase = animationData[0] animFile = animationData[1] # Let's create the path for the animation. animPath = BASE_MODEL % (animPhase, headType, '', 'head', animFile) if '_-' in animPath: animPath = animPath.replace('_-', '-') if '__' in animPath: animPath = animPath.replace('__', '_') partAnimations[animName] = animPath precacheActor([mdl, partAnimations])
def stopPlayer(self): logging.debug("stop player...") logging.debug("...stop control...") self.stopControl() self.walk_sound.stop() logging.debug("...stop camera...") self.stopCamera() logging.debug("...stop base...") self.freeCursor() # remove the actor Actor.cleanup(self) self.removeNode() logging.debug("...player stop")
def delete(self): try: self.Avatar_deleted except: self.deleteNametag3d() Actor.cleanup(self) self.Avatar_deleted = 1 del self.__font del self.style del self.soundChatBubble self.nametag.destroy() del self.nametag self.nametag3d.removeNode() ShadowCaster.delete(self) Actor.delete(self)
def delete(self): try: self.Avatar_deleted except: self.deleteNametag3d() Actor.cleanup(self) if self.ManagesNametagAmbientLightChanged: self.ignoreNametagAmbientLightChange() self.Avatar_deleted = 1 del self.__font del self.style del self.soundChatBubble del self.nametag self.nametag3d.removeNode() ShadowCaster.delete(self) Actor.delete(self)
def disable(self): try: self.Avatar_disabled except: self.Avatar_disabled = 1 self.deleteShadow() self.deleteNameTag() self.removeLoopTask() self.mat = None self.tag = None self.chat = None self.height = None self.avatarType = None self.charName = None self.nameTag = None self.name = None Actor.cleanup(self) return
def delete(self): try: self.Avatar_deleted return except: self.Avatar_deleted = 1 self.setBlend(frameBlend=False) self.deleteNametag3d() Actor.cleanup(self) if self.ManagesNametagAmbientLightChanged: self.ignoreNametagAmbientLightChange() del self.__font del self.style del self.soundChatBubble self.nametag.destroy() del self.nametag self.nametag3d.removeNode() ShadowCaster.delete(self) Actor.delete(self)
class BonusGfx(GfxColleague): def __init__(self, mediator, pos, model_path, anim_suff): self.model = None self.pos = pos self.model_path = model_path self.anim_suff = anim_suff GfxColleague.__init__(self, mediator) path = self.model_path self.model = Actor(path, {'anim': path + '-' + self.anim_suff}) self.model.reparent_to(render) self.model.set_pos(self.pos) self.model.loop('anim') self.model.setPlayRate(.5, 'anim') self.model.set_depth_offset(1) def destroy(self): self.model.cleanup() self.model = self.model.remove_node() GfxColleague.destroy(self)
def disable(self): try: self.Avatar_disabled except: self.Avatar_disabled = 1 self.deleteNametag3d() self.nametag.destroy() del self.nametag self.nametag3d.removeNode() self.deleteShadow() self.removeLoopTask() self.mat = None self.tag = None self.chat = None self.height = None self.avatarType = None self.charName = None self.nameTag = None self._name = None Actor.cleanup(self)
class Splat(DirectObject): def __init__(self, pos, color, scale): self.pos = pos self.color = color self.scale = scale def generate(self): self.splat = Actor('phase_3.5/models/props/splat-mod.bam', {'chan': 'phase_3.5/models/props/splat-chan.bam'}) self.splat.setBillboardPointEye() self.splat.setColor(self.color) self.splat.setScale(self.scale) self.splat.setPos(self.pos) self.splat.play('chan') self.splat.reparentTo(render) Sequence(Wait(0.5), Func(self.destroy)).start() def destroy(self): self.splat.cleanup() self.splat.removeNode() del self.splat del self
class EquippedObject(MapObject): def __init__(self, npc, modelPath, texturePath=None): self.npc = npc self.modelPath = modelPath self.texturePath = texturePath self.model = Actor(self.modelPath, self.npc.animDic) #self.model.setTransparency(True) self.model.reparentTo(self.npc.model) if texturePath is not None: self.tex = loader.loadTexture(texturePath) self.model.clearTexture(TextureStage.getDefault()) self.model.clearTexture() self.model.setTexture(TextureStage.getDefault(), self.tex) #print "Adding object with texture : %s" % texturePath def loop(self, animName): self.model.loop(animName) def destroy(self): self.model.cleanup() self.model.remove()
class ToonFPS(DirectObject): notify = directNotify.newCategory('ToonFPS') WeaponName2DamageData = {'pistol': (36.0, 10.0, 150.0, 0.25), 'shotgun': (40.0, 15.0, 155.0, 0.5)} def __init__(self, mg, weaponName = 'pistol'): self.mg = mg self.weaponName = weaponName self.v_model_root = None self.v_model = None self.weapon = None self.track = None self.draw = None self.shoot = None self.reload = None self.empty = None self.cockBack = None self.cockFwd = None self.player_node = None self.shooterTrav = None self.shooterRay = None self.shooterRayNode = None self.shooterHandler = None self.gui = ToonFPSGui(self) self.fsm = ClassicFSM('ToonFPS', [State('off', self.enterOff, self.exitOff), State('alive', self.enterAlive, self.exitAlive), State('dead', self.enterDead, self.exitDead)], 'off', 'off') self.aliveFSM = ClassicFSM('alive', [State('off', self.enterOff, self.exitOff), State('draw', self.enterDraw, self.exitDraw, ['idle']), State('idle', self.enterIdle, self.exitIdle, ['shoot', 'reload']), State('shoot', self.enterShoot, self.exitShoot, ['idle']), State('reload', self.enterReload, self.exitReload, ['idle'])], 'off', 'off') self.fsm.getStateNamed('alive').addChild(self.aliveFSM) self.fsm.enterInitialState() self.aliveFSM.enterInitialState() if self.weaponName == 'pistol': self.ammo = 14 elif self.weaponName == 'shotgun': self.ammo = 7 self.hp = 125 self.max_hp = 125 self.firstPerson = FirstPerson() return def movementTask(self, task): if not inputState.isSet('jump') and not base.localAvatar.walkControls.isAirborne and inputState.isSet('forward') or inputState.isSet('reverse') or inputState.isSet('slideLeft') or inputState.isSet('slideRight'): if base.localAvatar.getAnimState() != 'run': base.localAvatar.setAnimState('run') base.localAvatar.playMovementSfx('run') self.mg.sendUpdate('runningAvatar', [base.localAvatar.doId]) elif inputState.isSet('jump') or base.localAvatar.walkControls.isAirborne: if base.localAvatar.getAnimState() != 'jump': base.localAvatar.setAnimState('jump') base.localAvatar.playMovementSfx(None) self.mg.sendUpdate('jumpingAvatar', [base.localAvatar.doId]) elif base.localAvatar.getAnimState() != 'neutral': base.localAvatar.setAnimState('neutral') base.localAvatar.playMovementSfx(None) self.mg.sendUpdate('standingAvatar', [base.localAvatar.doId]) return Task.cont def enterAlive(self): if self.mg.fsm.getCurrentState().getName() not in ('gameOver', 'announceGameOver', 'finalScores'): base.localAvatar.disableChatInput() self.start() self.resetHp() self.resetAmmo() if self.mg.fsm.getCurrentState().getName() == 'play': self.reallyStart() def exitAlive(self): self.end() self.v_model.reparentTo(hidden) if self.mg.fsm.getCurrentState().getName() != 'play': self.reallyEnd() base.localAvatar.createChatInput() def updatePoints(self): self.points = self.kills - self.deaths def enterDead(self, killer): base.localAvatar.getGeomNode().show() self.gui.end() base.localAvatar.attachCamera() self.freezeCamSfx = base.loadSfx('phase_4/audio/sfx/freeze_cam.wav') self.freezeCamImage = None self.freezeCamImageFile = None base.camera.setZ(base.camera.getZ() + 2.0) taskMgr.add(self.cameraLookAtKillerTask, 'lookAtKiller', extraArgs=[killer], appendTask=True) taskMgr.doMethodLater(2.0, self.startZoomOnKiller, 'startFreezeCam', extraArgs=[killer], appendTask=True) return def startZoomOnKiller(self, killer, task): taskMgr.add(self.__zoomOnKillerTask, 'zoomOnKiller', extraArgs=[killer], appendTask=True) return task.done def __zoomOnKillerTask(self, killer, task): if base.camera.getDistance(killer) <= 10.0 and self.freezeCamSfx.status() == self.freezeCamSfx.READY: base.playSfx(self.freezeCamSfx) if base.camera.getDistance(killer) < 7.0: self.doFreezeCam() return task.done base.camera.setY(base.camera, 60 * globalClock.getDt()) return task.again def doFreezeCam(self): taskMgr.remove('lookAtKiller') self.frameBuffer = PNMImage() base.win.getScreenshot(self.frameBuffer) self.freezeCamTex = Texture() self.freezeCamTex.load(self.frameBuffer) self.freezeCamImage = OnscreenImage(image=self.freezeCamTex, parent=render2d) def cameraLookAtKillerTask(self, killer, task): base.camera.lookAt(killer, 0, 0, 3) return task.cont def exitDead(self): taskMgr.remove('zoomOnKiller') taskMgr.remove('lookAtKiller') taskMgr.remove('startFreezeCam') del self.freezeCamSfx if self.freezeCamImage: self.freezeCamImage.destroy() del self.freezeCamImage self.frameBuffer.clear() self.freezeCamTex.clear() del self.frameBuffer del self.freezeCamTex base.localAvatar.detachCamera() base.localAvatar.getGeomNode().hide() self.gui.start() def load(self): if self.weaponName == 'pistol': self.draw = base.loadSfx('phase_4/audio/sfx/draw_secondary.wav') self.shoot = base.loadSfx('phase_4/audio/sfx/pistol_shoot.wav') self.reload = base.loadSfx('phase_4/audio/sfx/pistol_worldreload.wav') elif self.weaponName == 'shotgun': self.draw = base.loadSfx('phase_4/audio/sfx/draw_primary.wav') self.shoot = base.loadSfx('phase_4/audio/sfx/shotgun_shoot.wav') self.cockBack = base.loadSfx('phase_4/audio/sfx/shotgun_cock_back.wav') self.cockFwd = base.loadSfx('phase_4/audio/sfx/shotgun_cock_forward.wav') self.empty = base.loadSfx('phase_4/audio/sfx/shotgun_empty.wav') self.v_model_root = base.camera.attachNewNode('v_model_root') self.v_model = Actor('phase_4/models/minigames/v_dgm.egg', {'pidle': 'phase_4/models/minigames/v_dgm-pistol-idle.egg', 'pshoot': 'phase_4/models/minigames/v_dgm-pistol-shoot.egg', 'preload': 'phase_4/models/minigames/v_dgm-pistol-reload.egg', 'pdraw': 'phase_4/models/minigames/v_dgm-pistol-draw.egg', 'sidle': 'phase_4/models/minigames/v_dgm-shotgun-idle.egg', 'sshoot': 'phase_4/models/minigames/v_dgm-shotgun-shoot.egg'}) if self.weaponName == 'pistol': self.weapon = loader.loadModel('phase_4/models/props/water-gun.bam') self.weapon.reparentTo(self.v_model.exposeJoint(None, 'modelRoot', 'Bone.011')) self.weapon.setX(-0.125) self.weapon.setY(0.5) self.weapon.setScale(0.65) elif self.weaponName == 'shotgun': self.weapon = loader.loadModel('phase_4/models/props/shotgun.egg') self.weapon.reparentTo(self.v_model.exposeJoint(None, 'modelRoot', 'Bone.029')) self.weapon.setScale(0.75) self.weapon.setPos(0.45, -1.03, -1.17) self.weapon.setHpr(9.46, 308.19, 75.78) color = random.choice([VBase4(1, 0.25, 0.25, 1), VBase4(0.25, 1, 0.25, 1), VBase4(0.25, 0.25, 1, 1)]) self.weapon.setColorScale(color) self.gui.load() return def start(self): base.camLens.setNear(0.1) self.shooterTrav = CollisionTraverser('ToonFPS.shooterTrav') ray = CollisionRay() rayNode = CollisionNode('ToonFPS.rayNode') rayNode.addSolid(ray) rayNode.setCollideMask(BitMask32(0)) rayNode.setFromCollideMask(CIGlobals.WallBitmask | CIGlobals.FloorBitmask) self.shooterRay = ray self.shooterRayNode = base.camera.attachNewNode(rayNode) self.shooterHandler = CollisionHandlerQueue() self.shooterTrav.addCollider(self.shooterRayNode, self.shooterHandler) self.firstPerson.start() self.v_model_root.reparentTo(base.camera) self.v_model.reparentTo(self.v_model_root) if self.weaponName == 'pistol': self.v_model_root.setZ(-1.8) self.v_model_root.setY(0.3) self.v_model_root.setX(-0.1) self.v_model_root.setH(2) elif self.weaponName == 'shotgun': self.v_model_root.setPos(-0.42, -0.81, -1.7) self.v_model_root.setHpr(359, 352.87, 0.0) self.gui.start() self.firstPerson.disableMouse() self.aliveFSM.request('draw') def reallyStart(self): self.firstPerson.reallyStart() taskMgr.add(self.movementTask, 'toonBattleMovement') def end(self): self.aliveFSM.request('off') if self.firstPerson: self.firstPerson.enableMouse() self.firstPerson.end() taskMgr.remove('toonBattleMovement') if self.mg.fsm.getCurrentState().getName() != 'play': self.fsm.request('off') def reallyEnd(self): if self.shooterRayNode: self.shooterRayNode.removeNode() self.shooterRayNode = None self.shooterRay = None self.shooterTrav = None self.shooterHandler = None if self.firstPerson: self.firstPerson.reallyEnd() if self.v_model_root: self.v_model_root.reparentTo(hidden) if self.v_model: self.v_model.reparentTo(hidden) self.v_model.setPosHpr(0, 0, 0, 0, 0, 0) if self.gui: self.gui.end() base.camLens.setNear(1.0) return def cleanup(self): taskMgr.remove('lookAtKiller') taskMgr.remove('toonBattleMovement') if self.firstPerson: self.firstPerson.cleanup() self.firstPerson = None self.draw = None self.shoot = None self.reload = None self.empty = None self.ammo = None self.fsm = None self.aliveFSM = None self.player_node = None self.min_camerap = None self.max_camerap = None self.hp = None self.max_hp = None if self.v_model: self.v_model.cleanup() self.v_model = None if self.weapon: self.weapon.removeNode() self.weapon = None if self.weapon: self.v_model_root.removeNode() self.v_model_root = None if self.gui: self.gui.cleanup() return def damageTaken(self, amount, avId): if self.hp <= 0.0: killer = self.mg.cr.doId2do.get(avId, None) self.fsm.request('dead', [killer]) self.gui.adjustHpMeter() return def enterDraw(self): self.draw.play() if self.weaponName == 'pistol': self.track = ActorInterval(self.v_model, 'pdraw', playRate=1.6, name='drawTrack') elif self.weaponName == 'shotgun': self.v_model.pose('sidle', 15) self.track = LerpQuatInterval(self.v_model, duration=0.5, quat=(0, 0, 0), startHpr=(70, -50, 0), blendType='easeOut', name='drawTrack') self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() def exitDraw(self): if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None return def enterIdle(self): if self.weaponName == 'pistol': self.v_model.loop('pidle') elif self.weaponName == 'shotgun': self.track = Sequence(LerpQuatInterval(self.v_model, duration=2.0, quat=(0, 1, 0), startHpr=(0, 0, 0), blendType='easeInOut'), LerpQuatInterval(self.v_model, duration=2.0, quat=(0, 0, 0), startHpr=(0, 1, 0), blendType='easeInOut')) self.track.loop() self.accept('mouse1', self.requestShoot) if self.ammo <= 0: self.gui.notifyNoAmmo() if self.ammo < 14: self.accept('r', self.aliveFSM.request, ['reload']) def requestShoot(self): if self.mg.fsm.getCurrentState().getName() != 'play': return if self.ammo > 0: self.aliveFSM.request('shoot') else: self.empty.play() def exitIdle(self): self.v_model.stop() if self.track: self.track.finish() self.track = None self.ignore('mouse1') self.ignore('r') return def enterShoot(self): self.shoot.play() if self.weaponName == 'pistol': self.track = ActorInterval(self.v_model, 'pshoot', playRate=2, name='shootTrack') elif self.weaponName == 'shotgun': self.track = Parallel(Sequence(LerpQuatInterval(self.v_model, duration=0.05, quat=(0, 3, 0), startHpr=(0, 0, 0)), LerpQuatInterval(self.v_model, duration=0.1, quat=(0, 0, 0), startHpr=(0, 3, 0))), Sequence(LerpPosInterval(self.v_model, duration=0.05, pos=(0, -0.3, 0), startPos=(0, 0, 0)), LerpPosInterval(self.v_model, duration=0.1, pos=(0, 0, 0), startPos=(0, -0.3, 0)), Wait(0.1))) self.track.setDoneEvent('shootTrack') self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() self.ammo -= 1 self.gui.adjustAmmoGui() self.mg.makeSmokeEffect(self.weapon.find('**/joint_nozzle').getPos(render)) self.traverse() def traverse(self): mpos = base.mouseWatcherNode.getMouse() self.shooterRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.shooterTrav.traverse(render) def calcDamage(self, avatar): dmgData = self.WeaponName2DamageData[self.weaponName] maxDamage = dmgData[0] minDistance = dmgData[1] maxDistance = dmgData[2] factor = dmgData[3] distance = base.localAvatar.getDistance(avatar) if distance < minDistance: distance = minDistance elif distance > maxDistance: distance = maxDistance damage = maxDamage - (distance - minDistance) * factor return damage def exitShoot(self): self.ignore('shootTrack') if self.track: self.track.finish() self.track = None return def enterReload(self): self.gui.deleteNoAmmoLabel() if self.weaponName == 'pistol': self.track = Parallel(Sequence(Wait(0.3), Func(self.reload.play), Func(self.resetAmmo)), ActorInterval(self.v_model, 'preload', playRate=1.5), name='reloadTrack') elif self.weaponName == 'shotgun': self.track = Sequence(Func(self.draw.play), LerpQuatInterval(self.v_model, duration=0.5, quat=(70, -50, 0), startHpr=(0, 0, 0), blendType='easeIn'), SoundInterval(self.cockBack), SoundInterval(self.cockFwd), Func(self.resetAmmo), Func(self.draw.play), LerpQuatInterval(self.v_model, duration=0.5, quat=(0, 0, 0), startHpr=(70, -50, 0), blendType='easeOut'), name='reloadTrack') self.track.setDoneEvent('reloadTrack') self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() def exitReload(self): self.ignore('reloadTrack') if self.track: self.track.finish() self.track = None return def resetAmmo(self): if self.weaponName == 'pistol': self.ammo = 14 elif self.weaponName == 'shotgun': self.ammo = 7 self.gui.resetAmmo() def resetHp(self): self.hp = self.max_hp self.gui.adjustHpMeter() def enterOff(self): pass def exitOff(self): pass
class FountainPenAttack(Attack): notify = directNotify.newCategory('FountainPenAttack') attack = 'fountainpen' def __init__(self, attacksClass, suit): Attack.__init__(self, attacksClass, suit) self.pen = None self.spray = None self.splat = None self.spraySfx = None self.sprayParticle = None self.sprayScaleIval = None self.wsnp = None return def loadAttack(self): self.pen = loader.loadModel('phase_5/models/props/pen.bam') self.pen.reparentTo(self.suit.find('**/joint_Rhold')) self.sprayParticle = ParticleLoader.loadParticleEffect('phase_5/etc/penSpill.ptf') self.spray = loader.loadModel('phase_3.5/models/props/spray.bam') self.spray.setColor(VBase4(0, 0, 0, 1)) self.splat = Actor('phase_3.5/models/props/splat-mod.bam', {'chan': 'phase_3.5/models/props/splat-chan.bam'}) self.splat.setColor(VBase4(0, 0, 0, 1)) self.sprayScaleIval = LerpScaleInterval(self.spray, duration=0.3, scale=(1, 20, 1), startScale=(1, 1, 1)) sphere = CollisionSphere(0, 0, 0, 0.5) sphere.setTangible(0) if hasattr(self.suit, 'uniqueName'): collName = self.suit.uniqueName('fountainPenCollNode') else: collName = 'fountainPenCollNode' collNode = CollisionNode(collName) collNode.addSolid(sphere) collNode.setCollideMask(CIGlobals.WallBitmask) self.wsnp = self.spray.attachNewNode(collNode) self.wsnp.setY(1) def doAttack(self, ts = 0): self.loadAttack() if hasattr(self.suit, 'uniqueName'): name = self.suit.uniqueName('doFountainPenAttack') else: name = 'doFountainPenAttack' self.suitTrack = Parallel(name=name) self.suitTrack.append(ActorInterval(self.suit, 'fountainpen')) self.suitTrack.append(Sequence(Wait(1.2), Func(self.acceptOnce, 'enter' + self.wsnp.node().getName(), self.handleSprayCollision), Func(self.playWeaponSound), Func(self.attachSpray), Func(self.sprayParticle.start, self.pen.find('**/joint_toSpray'), self.pen.find('**/joint_toSpray')), self.sprayScaleIval, Wait(0.5), Func(self.sprayParticle.cleanup), Func(self.spray.setScale, 1), Func(self.spray.reparentTo, hidden), Func(self.ignore, 'enter' + self.wsnp.node().getName()))) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getDoneEvent(), self.finishedAttack) self.suitTrack.delayDelete = DelayDelete.DelayDelete(self.suit, name) self.suitTrack.start(ts) def attachSpray(self): self.spray.reparentTo(self.pen.find('**/joint_toSpray')) pos = self.spray.getPos(render) hpr = self.spray.getHpr(render) self.spray.reparentTo(render) self.spray.setPos(pos) self.spray.setHpr(hpr) self.spray.setP(0) if self.suit.type == 'C': self.spray.setH(self.spray.getH() + 7.5) self.spray.setTwoSided(True) def handleSprayCollision(self, entry): if self.suit: self.suit.sendUpdate('toonHitByWeapon', [self.getAttackId(self.attack), base.localAvatar.doId]) base.localAvatar.b_handleSuitAttack(self.getAttackId(self.attack), self.suit.doId) self.sprayScaleIval.pause() def playWeaponSound(self): self.spraySfx = base.audio3d.loadSfx('phase_5/audio/sfx/SA_fountain_pen.mp3') base.audio3d.attachSoundToObject(self.spraySfx, self.pen) self.spraySfx.play() def cleanup(self): Attack.cleanup(self) if self.wsnp: self.wsnp.node().clearSolids() self.wsnp.removeNode() self.wsnp = None if self.pen: self.pen.removeNode() self.pen = None if self.sprayParticle: self.sprayParticle.cleanup() self.sprayParticle = None if self.spray: self.spray.removeNode() self.spray = None if self.splat: self.splat.cleanup() self.splat = None if self.sprayScaleIval: self.sprayScaleIval.pause() self.sprayScaleIval = None self.spraySfx = None return
class CogAI(DirectObject): cancelStep = False def __init__(self, cog, spawn, support = False): self.cog = cog self.spawn = spawn self.attack = True self.support = support self.flyIn() def setAI(self): collisions = render.getPythonTag('WorldCollisions') collisions.addCogGroundCollision(self.cog) self.AIWorld = AIWorld(render) self.AIChar = AICharacter('Cog', self.cog.getCog(), -125, 90, -14) self.AIWorld.addAiChar(self.AIChar) self.AIBehaviors = self.AIChar.getAiBehaviors() if self.support == False: self.AIBehaviors.pathFollow(8) self.AIBehaviors.addToPath(VBase3(110.60, -0.32, 4.57)) checkpoints = self.spawn.getPath().getCheckpoints() for checkpoint in xrange(len(checkpoints)): self.AIBehaviors.addToPath(checkpoints[checkpoint].getPos()) self.AIBehaviors.startFollow() else: self.AIBehaviors.pursue(render.find('**/Toon')) self.cog.getCog().loop('walk') base.taskMgr.add(self.AIUpdate, "AIUpdate") def calcChance(self, percent): if(random.randint(0, 100) < percent): return True else: return False def toggleAttack(self): if(self.attack): self.attack = False else: self.attack = True def AIUpdate(self, task): if(self.AIBehaviors.behaviorStatus('pathfollow') == 'done'): self.cog.getCog().loop('neutral') self.AIBehaviors.removeAi('pathfollow') toonHall = render.getPythonTag("ToonHall") toonHall.startCogEnter(self.cog) return Task.done else: if(self.cog.getHealth() > 0): if(self.calcChance(40) and self.attack): def resumeAI(task): self.AIBehaviors.resumeAi('pathfollow') self.cog.getCog().loop('walk') return Task.done def enableAttacks(task): return Task.done avatar = render.find('**/Toon') if(self.cog.getCog().getDistance(avatar) <= 20): self.AIBehaviors.pauseAi('pathfollow') self.cog.getCog().stop() self.attack = False self.cog.getCog().lookAt(avatar) self.cog.getCog().play('throw-object') attack = CogAttacks().getRandomAttack(self.cog.getLevel() * 2) attack.execute(self.cog) base.taskMgr.doMethodLater(10, enableAttacks, 'Toggle Attack') base.taskMgr.doMethodLater(3, resumeAI, 'Resume AI') self.AIWorld.update() return Task.cont else: self.AIBehaviors.removeAi('pathfollow') return Task.done def flyIn(self): phase_4 = "phase_4/models/props" cog = self.cog.getCog() collisions = render.getPythonTag('WorldCollisions') collisions.addCogCollision(self.cog) self.propeller = Actor(loader.loadModel(phase_4 + "/propeller-mod.bam"), {'chan' : loader.loadModel(phase_4 + "/propeller-chan.bam")}) self.propeller.reparentTo(cog.find('**/joint_head')) propSound = SoundBank.getSound('propeller') propSound.setLoop(True) propSound.setVolume(0.8) propSound.play() pos = cog.getPos() cog.setPos(pos.getX(), pos.getY(), pos.getZ() + 20) cog.pose('landing', 1) cog.colorScaleInterval(4.8, Vec4(1, 1, 1, 1), startColorScale=Vec4(0.2509803921568627, 0.2509803921568627, 0.2509803921568627, 0.25), blendType='easeInOut').start() path = cog.posInterval(5, pos, startPos = cog.getPos()) path.start() self.propeller.loop('chan', fromFrame=0, toFrame=3) base.taskMgr.add(self.handleCogDead, 'Handle Cog Death') base.taskMgr.doMethodLater(4, self.playInSound, 'Play In Sound', extraArgs = [propSound], appendTask = True) base.taskMgr.doMethodLater(5, self.landCog, 'Land Cog') def handleCogDead(self, task): if(self.cog.isDefeated): self.cancelStep = True collisions = render.getPythonTag('WorldCollisions') collisions.addCogGroundCollision(cog = self.cog) return Task.done else: return Task.cont def landCog(self, task): if not self.cancelStep: base.taskMgr.remove('Handle Cog Death') self.propeller.play('chan', fromFrame=35, toFrame=87) self.cog.getCog().play('landing') base.taskMgr.doMethodLater(3, self.removePropeller, 'Remove Propeller') return Task.done def removePropeller(self, task): self.propeller.cleanup() self.propeller.removeNode() self.setAI() return Task.done def playInSound(self, sound, task): if not self.cancelStep: sound.stop() SoundBank.getSound('propeller_in').play() return Task.done
class Monster(): def __init__(self, id, parent, type, pos): self.id = id self.parent = parent self.hp = 100 self.speed = 1 self.can_move = True if type == 'baby': self.node = Actor('models/baby', {'walk':'models/baby-walk', 'stand':'models/baby-stand', 'idle':'models/baby-idle', 'jump':'models/baby-jump', 'bite1':'models/baby-bite1', 'bite2':'models/baby-bite2', 'head_attack':'models/baby-head_attack', 'hit1':'models/baby-hit1', 'hit2':'models/baby-hit2', 'die':'models/baby-die'}) self.head_node = self.node.exposeJoint(None,"modelRoot","Bip01_Head") self.body_node = self.node.exposeJoint(None,"modelRoot","Bip01_Pelvis") self.node.setH(180) self.node.setScale(0.03) self.node.flattenLight() self.zpos = 0 self.node.setPos(pos[0]*TILE_SIZE,pos[1]*TILE_SIZE,self.zpos) self.node.setTexture(loader.loadTexture('models/Zomby_D.png')) self.ts_normal = TextureStage('ts_normal') self.tex_normal = loader.loadTexture('models/Zomby_N.png') self.ts_normal.setMode(TextureStage.MNormal) self.node.setTexture(self.ts_normal, self.tex_normal) self.ts_gloss = TextureStage('ts_gloss') self.tex_gloss = loader.loadTexture('models/Zomby_S1.png') self.ts_gloss.setMode(TextureStage.MGloss) self.node.setTexture(self.ts_gloss, self.tex_gloss) self.ts_glow = TextureStage('ts_glow') self.tex_glow = loader.loadTexture('models/Zomby_I.png') self.ts_glow.setMode(TextureStage.MGlow) self.node.setTexture(self.ts_glow, self.tex_glow) self.node.reparentTo(render) self.node.loop('walk') elif type == 'nos': self.node = loader.loadModel('models/nos') self.zpos = 5 self.node.setPos(pos[0]*TILE_SIZE,pos[1]*TILE_SIZE,self.zpos) self.node.setScale(2) if self.id == 1: self.node.setColor(1,0,0) elif self.id == 2: self.node.setColor(0,1,0) elif self.id == 3: self.node.setColor(0,0,1) else: self.node.setColor(1,1,1) self.node.reparentTo(render) #self.patrol_points = [(1,1), (4,11), (12,20), (18,4), (19,17)] #initialize 3d sound self.audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], base.camera) self.shot_head = self.audio3d.loadSfx('audio/Zombie In Pain-SoundBible.com-134322253.wav') self.shot_body = self.audio3d.loadSfx('audio/Zombie Moan-SoundBible.com-565291980.wav') self.moan1 = self.audio3d.loadSfx('audio/Mindless Zombie Awakening-SoundBible.com-255444348.wav') self.moan2 = self.audio3d.loadSfx('audio/Zombie Brain Eater-SoundBible.com-1076387080.wav') self.aggro_sound = self.audio3d.loadSfx('audio/Mummy Zombie-SoundBible.com-1966938763.wav') self.attack_sound = self.audio3d.loadSfx('audio/Chopping Off Limb-SoundBible.com-884800545.wav') self.audio3d.attachSoundToObject(self.moan1, self.node) self.audio3d.attachSoundToObject(self.moan2, self.node) self.audio3d.attachSoundToObject(self.shot_head, self.node) self.audio3d.attachSoundToObject(self.shot_body, self.node) self.audio3d.attachSoundToObject(self.aggro_sound, self.node) self.audio3d.attachSoundToObject(self.attack_sound, self.node) delay0 = Wait(d(35)) delay1 = Wait(25+d(35)) delay2 = Wait(25+d(35)) self.moan_sequence = Sequence(delay0, SoundInterval(self.moan1), delay1, SoundInterval(self.moan2), delay2) self.moan_sequence.loop() self.parent.collision_manager.createMonsterCollision(self) self.aggro_sound_last_played = 0 #--------------------------brain------------------------- self.node.setH( 160 ) self.pause = False self.action = ACTION_IDLE if percent(20): self.orders = ORDERS_PATROL else: self.orders = ORDERS_IDLE self.last_melee = 0 self.player_last_seen_abs = None self.idle_timer = time.time() self.idle_value = 1 self.current_waypoint = None #self.wait_until = None self.herding_timer = None self.path = None taskMgr.doMethodLater(1, self.behaviourTask, 'MonsterBehaviourTask'+str(self.id) ) taskMgr.doMethodLater(1, self.debugMoveTask, 'MonsterMoveTask'+str(self.id)) def getLOS(self): return self.parent.collision_manager.checkMonsterPlayerLos(self) def sensePlayer(self): """Return True if player sensed, and his last known coordinates are stored in self.player_last_seen_abs""" # if the player is dead, do not sense him if self.parent.player.health <= 0: return False #get player's position p_pos_abs = self.parent.player.node.getPos() my_pos_abs = self.node.getPos() #--------------------------------SENSE--------------------------------- #if player is within SENSING_RANGE we know he is there if self.distanceToPlayer() < SENSING_RANGE: #print "TOO CLOSE LOOSER!" self.player_last_seen_abs = p_pos_abs return True #---------------------------------HEAR---------------------------------- #if player is within HEARING_RANGE we know he is there effective_hearing_range = HEARING_RANGE if self.parent.player.gunshot_at: effective_hearing_range *= 3 else: if self.parent.player.sprint: effective_hearing_range *= 2 if not self.parent.player.moving: effective_hearing_range = 0 if self.distanceToPlayer() < effective_hearing_range: print "I HEAR U!" self.parent.player.adrenaline() #if we can see go chase him if self.getLOS(): self.player_last_seen_abs = p_pos_abs return True #we cannot see him, build new path to that tile else: dest = getTile( p_pos_abs ) path = pathFind(self.parent.level, getTile( self.node.getPos()), dest) if path: self.path = path self.orders = ORDERS_PATROL self.action = ACTION_FOLLOW_PATH return False #-------------------------------SEE--------------------------------- #if player is in front of us if self.angleToPlayerAbs() <= 45: #if he is close enough to see and we can see him if self.distanceToPlayer() <= VIEW_RANGE and self.getLOS(): self.player_last_seen_abs = p_pos_abs #print "vidim!" return True #if player has a flashlight lit, and we can see him go after him if self.parent.player.flashlight and self.getLOS(): self.player_last_seen_abs = p_pos_abs #print "vidim flashlight" return True #---------------------SEE MY OWN SHADOW--------------------------- #if player is behind us and has a lit up flashlight and we have LOS to him if self.angleToPlayerAbs() > 135 and self.angleToPlayerAbs() < 225: if self.parent.player.flashlight and self.getLOS(): #if he is looking at us my_pos_rel = self.node.getPos( self.parent.player.node ) forward = Vec2( 0, 1 ) if math.fabs( forward.signedAngleDeg( Vec2( my_pos_rel[0], my_pos_rel[1] ) ) ) <= 30: #go after my own shadow print "herding" self.orders = ORDERS_HERDING self.node.setH( self.parent.player.node.getH() ) self.herding_timer = time.time() return False def distanceToPlayer(self): p_pos_abs = self.parent.player.node.getPos() my_pos_abs = self.node.getPos() return math.sqrt( math.pow( p_pos_abs[0] - my_pos_abs[0], 2) + math.pow( p_pos_abs[1] - my_pos_abs[1], 2) ) def angleToPlayer(self): p_pos_rel = self.parent.player.node.getPos( self.node ) forward = Vec2( 0, 1 ) return forward.signedAngleDeg( Vec2( p_pos_rel[0], p_pos_rel[1] ) ) def angleToPlayerAbs(self): return math.fabs( self.angleToPlayer() ) def behaviourTask(self, task): if self.pause: return task.again #top priority, if we sense a player, go after him! if self.sensePlayer(): if time.time() - self.aggro_sound_last_played > 5: self.aggro_sound.play() self.aggro_sound_last_played = time.time() self.action = ACTION_CHASE return task.again elif self.orders == ORDERS_IDLE: #percent chance to go on patrol if percent( 10 ): self.orders = ORDERS_PATROL return task.again self.action = ACTION_IDLE elif self.orders == ORDERS_PATROL: #percent chance to get idle if percent( 5 ): self.orders = ORDERS_IDLE return task.again #if we are already patroling, dont change anything if self.action == ACTION_FOLLOW_PATH: return task.again #build a new path for patrol dest = self.getNewPatrolPoint() self.path = pathFind(self.parent.level, getTile(self.node.getPos()), dest) self.action = ACTION_FOLLOW_PATH elif self.orders == ORDERS_HERDING: self.action = ACTION_MOVE if time.time() - self.herding_timer > HERDING_TIMEOUT: self.orders = ORDERS_IDLE return task.again def debugMoveTask(self, task): if self.pause: return task.cont #print "orders:", self.orders if self.action == ACTION_CHASE: self.parent.player.adrenaline() look_pos = Point3(self.player_last_seen_abs.getX(), self.player_last_seen_abs.getY(), self.zpos) self.node.lookAt( look_pos ) self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0) if self.distanceToPlayer() <= MELEE_RANGE and self.angleToPlayerAbs() <= 45 and self.getLOS(): if time.time() - self.last_melee >= MELEE_TIME: self.attack_sound.play() att = random.randint(0,2) if att == 0: animname = 'bite1' elif att == 1: animname = 'bite2' else: animname = 'head_attack' self.node.play(animname) duration = self.node.getNumFrames(animname) / 24 # animation play rate taskMgr.doMethodLater(duration, self.finishedAnim, 'FinishedAnim', extraArgs = []) self.parent.player.getDamage() self.last_melee = time.time() elif self.action == ACTION_IDLE: if time.time() - self.idle_timer > IDLE_TIME: #we are standing still and rotating, see on whic side we will rotate now self.idle_timer = time.time() if percent(20): self.idle_value *= -1 self.rotateBy( self.idle_value * IDLE_ROTATE_SPEED ) elif self.action == ACTION_FOLLOW_PATH: #if we dont have a waypoint, calculate one if not self.current_waypoint: try: #get next tile from path tile = self.path[0] self.path = self.path[1:] #calculate waypoint varx= 5 - (d(4) + d(4)) vary= 5 - (d(4) + d(4)) self.current_waypoint = (Point3( tile[0] * TILE_SIZE + varx, tile[1] * TILE_SIZE + vary, self.zpos ), time.time() ) #print "waypoint:", self.current_waypoint self.node.lookAt( self.current_waypoint[0] ) except (IndexError, TypeError): #we have reached the end of path self.orders = ORDERS_IDLE self.current_waypoint = None #if we have a waypoint move forward towards it, and check if we arrived at it else: self.node.setFluidPos(self.node, 0, NORMAL_SPEED*globalClock.getDt(), 0) my_pos = self.node.getPos() #if we are close enough to the waypoint or if we didnt get to waypoint in time, delete it so we know we need a new one if math.fabs( my_pos[0] - self.current_waypoint[0][0] ) < 1 and math.fabs( my_pos[1] - self.current_waypoint[0][1] ) < 2 \ or time.time() - self.current_waypoint[1] > WAYPOINT_TIMER: self.current_waypoint = None elif self.action == ACTION_MOVE: self.node.setFluidPos(self.node, 0, NORMAL_SPEED*globalClock.getDt(), 0) return task.cont def finishedAnim(self): if not self.pause: self.node.loop('walk') def rotateBy(self, value): self.node.setH( (self.node.getH() + value) % 360 ) def getNewPatrolPoint(self): lvl = self.parent.level allTiles = lvl.getFloorTiles() while True: t = ( d(lvl.getMaxX()), d(lvl.getMaxY()) ) if t in allTiles: return t def hitWall(self): if self.action == ACTION_CHASE: return #print "lupio!" """self.moan1.play() self.rotateBy( 180 ) self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0) #self.action = IDLE """ """ old = self.node.getH() rnd = 80 + random.randint( 0, 20 ) forward = Vec2( 0, 1 ) impact = Vec2( pos[0], pos[1] ) angle = forward.signedAngleDeg( impact ) #print "angle:", angle if angle < 0: #+ cause angle is negative rnd = 91 + angle self.node.setH( (self.node.getH() + rnd)%360 ) elif angle > 0: rnd = -91 + angle self.node.setH( (self.node.getH() + rnd)%360 ) #print "stari:", old, " novi:", self.node.getH() """ pass def pauze(self): if self.moan_sequence: self.moan_sequence.pause() self.pause = True def resume(self): if self.moan_sequence: self.moan_sequence.resume() self.pause = False def destroy(self): self.audio3d.detachSound(self.moan1) self.audio3d.detachSound(self.moan2) self.audio3d.detachSound(self.shot_head) self.audio3d.detachSound(self.shot_body) self.audio3d.detachSound(self.aggro_sound) self.audio3d.detachSound(self.attack_sound) if self.moan_sequence != None: self.moan_sequence.pause() self.moan_sequence = None taskMgr.remove('MonsterBehaviourTask'+str(self.id)) taskMgr.remove('MonsterMoveTask'+str(self.id)) self.cn_head.node().clearPythonTag('node') self.cn_body.node().clearPythonTag('node') self.cn_pusher.node().clearPythonTag('node') self.cn_ray.node().clearPythonTag('node') self.node.delete() self.node.cleanup() self.node.removeNode() """
class Monster(): def __init__(self, setup_data, common, level=1.0, start_pos=(0,0,0)): common['monsterList'].append(self) id=len(common['monsterList'])-1 self.monsterList=common['monsterList'] self.waypoints_data=common['waypoints_data'] self.waypoints=common['waypoints'] self.audio3d=common['audio3d'] self.common=common #root node self.node=render.attachNewNode("monster") self.sound_node=None self.soundset=None self.actor=Actor(setup_data["model"],setup_data["anim"] ) self.actor.setBlend(frameBlend = True) self.actor.reparentTo(self.node) self.actor.setScale(setup_data["scale"]*random.uniform(0.9, 1.1)) self.actor.setH(setup_data["heading"]) self.actor.setBin("opaque", 10) self.rootBone=self.actor.exposeJoint(None, 'modelRoot', setup_data["root_bone"]) #sounds self.soundID=self.common['soundPool'].get_id() self.common['soundPool'].set_target(self.soundID, self.node) self.sound_names={"hit":setup_data["hit_sfx"], "arrow_hit":setup_data["arrowhit_sfx"], "attack":setup_data["attack_sfx"], "die":setup_data["die_sfx"]} self.vfx=setup_data["hit_vfx"] self.stats={"speed":setup_data["speed"], "hp":setup_data["hp"]*level, "armor":setup_data["armor"]*level, "dmg":setup_data["dmg"]*level } if self.stats['hp']>300: self.stats['hp']=300 self.maxHP=self.stats['hp'] self.HPring=Actor("models/ring_morph", {'anim' : 'models/ring_anim'}) self.HPring.setScale(0.07) self.HPring.setZ(0.4) self.HPring.setLightOff() self.HPring.reparentTo(self.node) self.HPvis=self.HPring.controlJoint(None, 'modelRoot', 'morph01') self.HPvis.setX(self.stats['hp']/300) self.HPring.hide(BitMask32.bit(1)) self.HPring.hide() #self.HPring.setColorScale(0.0, 1.0, 0.0, 1.0) #gamestate variables self.attack_pattern=setup_data["attack_pattern"] self.damage=setup_data["dmg"] #self.HP=setup_data["hp"] self.state="STOP" self.id=id self.nextWaypoint=None self.canSeePC=False self.PCisInRange=False self.PC=common['PC'] self.speed_mode=random.randrange(0+int(level),42+int(level), 7)/100.0 self.totalSpeed=self.stats['speed']+self.speed_mode self.sparkSum=0 self.lastMagmaDmg=0 self.DOT=0 self.arrows=set() self.traverser=CollisionTraverser("Trav"+str(self.id)) #self.traverser.showCollisions(render) self.queue = CollisionHandlerQueue() #bit masks: # 1 visibility polygons & coll-rays # 2 walls & radar-ray # 3 spheres #collision ray for testing visibility polygons coll=self.node.attachNewNode(CollisionNode('collRay')) coll.node().addSolid(CollisionRay(0, 0, 2, 0,0,-180)) coll.setTag("id", str(id)) coll.node().setIntoCollideMask(BitMask32.allOff()) coll.node().setFromCollideMask(BitMask32.bit(1)) self.traverser.addCollider(coll, self.queue) #radar collision ray self.radar=self.node.attachNewNode(CollisionNode('radarRay')) self.radar.node().addSolid(CollisionRay(0, 0, 1, 0,90,0)) self.radar.node().setIntoCollideMask(BitMask32.allOff()) self.radar.node().setFromCollideMask(BitMask32.bit(2)) self.radar.setTag("radar", str(id)) #self.radar.show() self.traverser.addCollider(self.radar, self.queue) #collision sphere self.coll_sphere=self.node.attachNewNode(CollisionNode('monsterSphere')) self.coll_sphere.node().addSolid(CollisionSphere(0, 0, 0.8, 0.8)) self.coll_sphere.setTag("id", str(id)) self.coll_sphere.node().setIntoCollideMask(BitMask32.bit(3)) #coll_sphere.show() #other monster blocking self.coll_quad=loader.loadModel("models/plane") self.coll_quad.reparentTo(self.node) #coll_quad=render.attachNewNode(CollisionNode('monsterSphere')) #coll_quad.node().addSolid(CollisionPolygon(Point3(-.5, -.5, 2), Point3(-.5, .5, 0), Point3(.5, .5, 0), Point3(.5, .5, 2))) #coll_quad.setTag("id", str(id)) #coll_quad.node().setIntoCollideMask(BitMask32.bit(2)) #coll_quad.reparentTo(self.node) #coll_quad.show() Sequence(Wait(random.uniform(.6, .8)), Func(self.restart)).start() self.node.setPos(render,start_pos) taskMgr.add(self.runAI, "AIfor"+str(self.id)) taskMgr.doMethodLater(.6, self.runCollisions,'collFor'+str(self.id)) taskMgr.doMethodLater(1.0, self.damageOverTime,'DOTfor'+str(self.id)) def damageOverTime(self, task): if self.state=="DIE": return task.done if self.DOT>0: self.doDamage(self.DOT) self.DOT=int((self.DOT*0.9)-1.0) if self.stats['hp']<1: self.actor.play("die") #self.common['soundPool'].play(self.soundID, self.sound_names["hit"]) self.common['soundPool'].play(self.soundID, self.sound_names["die"]) self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016, 24) return task.again def restart(self): self.state="SEEK" def check_stacking(self): for monster in self.monsterList: if monster and monster.id!=self.id : if self.node.getDistance(monster.node)< .8: if monster.state!="STOP" and self.state=="SEEK": if self.totalSpeed <= monster.totalSpeed: self.state="STOP" self.actor.stop() Sequence(Wait(1.5), Func(self.restart)).start() return True def doDamage(self, damage, igoreArmor=False): if self.state=="DIE": return if not igoreArmor: damage-=self.stats['armor'] if damage<1: damage=1 #print damage self.stats['hp']-=damage scale=self.stats['hp']/self.maxHP self.HPvis.setX(self.stats['hp']/300.0) #self.HPring.setColor(0.8*(1.0-scale), 0.8*scale, 0.0, 1.0) self.HPring.show() self.HPring.setColorScale((1.0-scale), scale, 0.0, 1.0) if self.stats['hp']<1: self.HPring.hide() def attack(self, pattern): if self.state=="DIE": return if not self.PC.node: return if pattern: next=pattern.pop() else: self.state="SEEK" self.PCisInRange=False return if self.PC.node and self.node: range= self.node.getDistance(self.PC.node) else: return #print range if range<1.8: self.PC.hit(self.damage) Sequence(Wait(next), Func(self.attack, pattern)).start() def onMagmaHit(self): if self.state=="DIE": return damage=self.lastMagmaDmg self.doDamage(damage) self.common['soundPool'].play(self.soundID, "onFire") vfx(self.node, texture="vfx/small_flame.png",scale=.6, Z=.7, depthTest=False, depthWrite=False).start(0.016, stopAtFrame=24) if self.stats['hp']<1: self.actor.play("die") self.common['soundPool'].play(self.soundID, "die3") self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) def onPlasmaHit(self, damage): if self.state=="DIE": return self.doDamage(damage*1.5, True) #self.soundset["spark"].play() #self.common['soundPool'].play(self.soundID, "spark") if self.stats['hp']<1: self.actor.play("die") #self.soundset["die3"].play() self.common['soundPool'].play(self.soundID, "die3") self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) #else: # short_vfx(self.node, texture="vfx/short_spark.png",scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.03) def onSparkHit(self, damage): if self.state=="DIE": return #print damage self.doDamage(damage) #self.soundset["spark"].play() self.common['soundPool'].play(self.soundID, "spark") if self.stats['hp']<1: self.actor.play("die") #self.soundset["die3"].play() self.common['soundPool'].play(self.soundID, "die3") self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) else: short_vfx(self.node, texture="vfx/short_spark.png",scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.03) def onHit(self, damage, sound="hit"): if self.state=="DIE": return self.doDamage(damage) #print damage vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) if self.stats['hp']<1: self.actor.play("die") #self.sounds["die"].play() if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) self.common['soundPool'].play(self.soundID, self.sound_names["die"]) self.state="DIE" else: #self.sounds["hit"].play() if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) def findFirstWaypoint(self): min=100000 nearest=None for waypoint in self.waypoints: dist=self.node.getDistance(waypoint) if dist<min: min=dist nearest=waypoint return nearest def runCollisions(self, task): if self.state=="DIE": return task.done if self.node.getDistance(self.PC.node) >50.0: self.nextWaypoint=None return task.again if self.check_stacking(): return task.again self.radar.lookAt(self.PC.node) valid_waypoints=[] isFirstTest=True self.canSeePC=False self.traverser.traverse(render) self.queue.sortEntries() for entry in self.queue.getEntries(): if entry.getFromNodePath().hasTag("id"): #it's the monsters collRay valid_waypoints.append(int(entry.getIntoNodePath().getTag("index"))) #visibility polygons elif entry.getFromNodePath().hasTag("radar"): #it's the radar-ray #print "radar hit", entry.getIntoNodePath() if isFirstTest: isFirstTest=False #print "first hit!" #print "radar hit", entry.getIntoNodePath() if entry.getIntoNodePath().hasTag("player"): self.canSeePC=True '''distance={} for target in self.PC.myWaypoints: for waypoint in valid_waypoints: distance[target]=self.waypoints_data[target][waypoint] print(target, distance[target]) if distance: self.nextWaypoint=self.waypoints[min(distance, key=distance.get)] #print self.canSeePC''' if not valid_waypoints: #self.nextWaypoint=self.findFirstWaypoint() print(self.id, ": I'm lost!") valid_waypoints=[self.findFirstWaypoint()] #return task.again if self.state=="STOP": self.nextWaypoint=self.waypoints[random.choice(valid_waypoints)] return task.again best_distance=9000000 target_node=None for target in self.PC.myWaypoints: for valid in valid_waypoints: distance=self.waypoints_data[target][valid] #print "target->valid=",target, valid, distance if distance<best_distance: best_distance=distance target_node=valid if target_node: self.nextWaypoint=self.waypoints[target_node] else: #print "no target", valid_waypoints self.nextWaypoint=self.findFirstWaypoint() #self.waypoints[random.choice(valid_waypoints)] #print self.nextWaypoint return task.again def runAI(self, task): #print self.state if self.state=="DIE": self.coll_sphere.node().setIntoCollideMask(BitMask32.allOff()) self.coll_quad.removeNode() self.actor.play("die") self.common["kills"]-=1 if self.common["kills"]==0: Interactive(self.common, data.items['key'], self.node.getPos(render)) elif random.randrange(10)==0: Interactive(self.common, data.items['potion'], self.node.getPos(render)) Sequence(Wait(2.0),LerpPosInterval(self.node, 2.0, VBase3(self.node.getX(),self.node.getY(),self.node.getZ()-5)),Func(self.destroy)).start() return task.done elif self.state=="STOP": target=self.nextWaypoint if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target)>0.3: self.node.setY(self.node, self.totalSpeed*globalClock.getDt()) if(self.actor.getCurrentAnim()!="walk"): self.actor.loop("walk") return task.again elif self.state=="ATTACK": self.node.headsUp(self.PC.node) if(self.actor.getCurrentAnim()!="attack"): self.actor.play("attack") #Sequence(Wait(self.attack_pattern[-1]+self.speed_mode), Func(self.attack, list(self.attack_pattern))).start() Sequence(Wait(self.attack_pattern[-1]), Func(self.attack, list(self.attack_pattern))).start() return task.again elif self.state=="SEEK": if self.PCisInRange: self.state="ATTACK" return task.again target=self.nextWaypoint if self.canSeePC and self.PC.HP>0: target=self.PC.node #print "target pc!" if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target)>0.3: self.node.setY(self.node, self.totalSpeed*globalClock.getDt()) if(self.actor.getCurrentAnim()!="walk"): self.actor.loop("walk") return task.again else: #print "I'm stuck?" #print target #print self.canSeePC self.nextWaypoint=self.PC.node return task.again def destroy(self): #for sound in self.soundset: # self.soundset[sound].stop() #print "destroy:", #self.sound_node.reparentTo(render) #self.common['soundPool'].append([self.sound_node,self.soundset]) self.common['soundPool'].set_free(self.soundID) #self.sounds=None #print " sounds", self.arrows=None if self.actor: self.actor.cleanup() self.actor.removeNode() #print " actor", if taskMgr.hasTaskNamed("AIfor"+str(self.id)): taskMgr.remove("AIfor"+str(self.id)) #print " AI", if taskMgr.hasTaskNamed('collFor'+str(self.id)): taskMgr.remove('collFor'+str(self.id)) #print " collision", if taskMgr.hasTaskNamed('DOTfor'+str(self.id)): taskMgr.remove('DOTfor'+str(self.id)) if self.node: self.node.removeNode() #print " node", self.monsterList[self.id]=None self.traverser=None self.queue=None
class Digger(enemy.Enemy): def __init__(self, mainRef): enemy.Enemy.__init__(self, mainRef, enemy.koboldSkirmisher) # Change to correct kobold self.holeModel = None def initAttributes(self, attributes): super(Digger, self).initAttributes(attributes) rangeMultiplier = 1.5 self.combatRange *= rangeMultiplier self.perceptionRange *= rangeMultiplier def loadEnemyModel(self, modelName): modelPrefix = 'models/digger-' self.enemyModel = Actor(modelPrefix + 'model', { 'attack1':modelPrefix+'attack1', 'attack2':modelPrefix+'attack2', 'attack3':modelPrefix+'attack3', 'attack4':modelPrefix+'attack4', 'special-attack':modelPrefix+'special-attack', 'pursue':modelPrefix+'pursue', 'pursue-to-idle':modelPrefix+'pursue-stop', 'idle-walk':modelPrefix+'idle-walk', 'idle-walk-to-pursue':modelPrefix+'idle-walk-to-pursue', 'idle-walk-to-dig':modelPrefix+'idle-walk-to-dig', 'idle-walk-to-dig-to-sleep':modelPrefix+'idle-walk-to-dig-to-sleep', 'hit1':modelPrefix+'hit1', 'hit2':modelPrefix+'hit2', 'death1':modelPrefix+'death1', 'death2':modelPrefix+'death2', 'death3':modelPrefix+'death3' }) self.enemyModel.reparentTo(self.enemyNode) self.enemyNode.setPos(Point3.zero()) self.enemyNode.setDepthOffset(-1) def enterIdle(self): #print 'enemy enterIdle' #idleTime = 60.0 * 3.0 stopEnemy = self.enemyModel.actorInterval('pursue-to-idle', startFrame=0, endFrame=12) idleEnemy = self.enemyModel.actorInterval('idle-walk-to-dig', startFrame=0, endFrame=60) digHole = Parallel(Func(self.createHole), self.enemyModel.actorInterval('idle-walk-to-dig-to-sleep', startFrame=0, endFrame=120)) #hideEnemy = Func(self.enemyNode.hide) #suicide = Func(self.suicide) self.stopSequence = Sequence(stopEnemy, idleEnemy, digHole) self.stopSequence.start() self.isSleeping = True #taskMgr.doMethodLater(3, self.showEnemy, 'showEnemyTask') def showEnemy(self, task): if self.state == 'Idle': self.enemyNode.show() return task.done def enterPursue(self): #print('enemy enterPursue') loopWalkEnemy = Func(self.enemyModel.loop, 'pursue', fromFrame=0, toFrame=24) # Only awake enemy if it comes from idle if self.isSleeping: self.isSleeping = False awakeEnemy = self.enemyModel.actorInterval('idle-walk-to-pursue', startFrame=0, endFrame=24) self.awakeSequence = Sequence(awakeEnemy, loopWalkEnemy, Func(self.pursuePlayer)) else: self.awakeSequence = Sequence(loopWalkEnemy, Func(self.pursuePlayer)) self.awakeSequence.start() def enterDeath(self): #print('enemy enterDeath') self.enemyAIBehaviors.removeAi('all') randomDeathAnim = 'death' + str(utils.getDX(3)) self.enemyModel.play(randomDeathAnim, fromFrame=0, toFrame=12) def playAttackAnimation(self): randomAttackAnim = 'attack' + str(utils.getD4()) self.enemyModel.play(randomAttackAnim, fromFrame=0, toFrame=12) def playHitAnimation(self): randomHitAnim = 'hit' + str(utils.getDX(2)) self.enemyModel.play(randomHitAnim, fromFrame=0, toFrame=12) def createHole(self): if self.holeModel == None: self.holeModel = Actor('models/hole-model', {'anim':'models/hole-anim'}) self.holeModel.reparentTo(self._mainRef.mainNode) self.holeModel.setPos(self.enemyNode, 0, -.1, 0) self.holeModel.play('anim', fromFrame=0, toFrame=120) removeHoleDelay = 12 taskMgr.doMethodLater(removeHoleDelay, self.removeHole, 'removeHoleTask') def removeHole(self, task): if self.holeModel != None: self.holeModel.cleanup() self.holeModel.delete() self.holeModel = None return task.done
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 PartyCog(FSM): notify = directNotify.newCategory("PartyCog") HpTextGenerator = TextNode("HpTextGenerator") hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed=3, bounceHeight=1, rotateSpeed=1, heightShift=1, xMoveSpeed=0, xMoveDistance=0, bounceOffset=0): self.id = id FSM.__init__(self, "PartyCogFSM-%d" % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request("Down") def load(self): self.root = NodePath("PartyCog-%d" % self.id) self.root.reparentTo(self.parentNode) path = "phase_13/models/parties/cogPinata_" self.actor = Actor( path + "actor", { "idle": path + "idle_anim", "down": path + "down_anim", "up": path + "up_anim", "bodyHitBack": path + "bodyHitBack_anim", "bodyHitFront": path + "bodyHitFront_anim", "headHitBack": path + "headHitBack_anim", "headHitFront": path + "headHitFront_anim", }) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode("temphead") self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode("PartyCog-%d-Body-Collision" % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode("PartyCog-%d-Head-Collision" % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) # Cog's Left Arm self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode("PartyCog-%d-Arm1-Collision" % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) # Cog's Right Arm self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode("PartyCog-%d-Arm2-Collision" % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.mp3') self.hole = loader.loadModel("phase_13/models/parties/cogPinataHole") self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin("ground", 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request("Off") self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound #=============================================================================== # FSM States #=============================================================================== def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, "PartyCog.update-%d" % self.id) def exitActive(self): taskMgr.remove("PartyCog.update-%d" % self.id) taskMgr.remove("PartyCog.bounceTask-%d" % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3( self.root.getH(), 0.0, 0.0), blendType="easeInOut") self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == "Off": self.actor.pose("down", self.actor.getNumFrames("down") - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType="easeIn"), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, "down", loop=0), ), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType="easeOut"), ) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType="easeIn"), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, "up", loop=0), ), Func(self.actor.loop, "idle"), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType="easeOut"), ) self.hitInterval.start() def filterDown(self, request, args): if request == "Down": return None else: return self.defaultFilter(request, args) #------------------------------------------------------------------------------ def setEndPoints(self, start, end, amplitude=1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) # if self.id == 0: # print angle return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin( t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, "PartyCog.bounceTask-%d" % self.id) def bounce(self, task): #self.root.setH(self.root.getH() - self.rotateSpeed) self.root.setZ((math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight) + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot=False, direction=1.0): """The toon hit us, react appropriately.""" assert (self.notify.debugStateCall(self)) if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: #self.notify.debug('localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() def __showSplat(self, position, direction, hot=False): """Show the splat graphic and sound.""" if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: #self.splat.setColorScale(Vec4(0.0, 0.0, 50.0, 1.0)) self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = "HitFront" else: facing = "HitBack" else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) #self.splat.setColorScale(Vec4(1.0, 0.6, 0.08, 1.0)) if self.currentFacing > 0.0: facing = "HitBack" else: facing = "HitFront" if hot: targetscale = 0.75 part = "head" else: targetscale = 0.5 part = "body" def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence( ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, "idle"), ) self.hitInterval.start() self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence( Func(self.splat.showThrough), Parallel( Sequence( LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType="easeOut"), Wait(0.175), ), Sequence( Wait(0.1), LerpFunc( setSplatAlpha, duration=1.0, #0.4, fromData=1.0, toData=0.0, blendType="easeOut"))), Func(self.splat.cleanup), Func(self.splat.removeNode), )) self.kaboomTrack.start() def showHitScore(self, number, scale=1): """ Shows the hit score. Borrowed from otp.avatar.DistributedAvatar.showHpText """ if number <= 0: return # Get rid of the number if it is already there. if self.hpText: self.hideHitScore() # Set the font self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) # Show both negative and positive signs if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText("+" + str(number)) # No shadow self.HpTextGenerator.clearShadow() # Center the number self.HpTextGenerator.setAlign(TextNode.ACenter) # Red, always #if number < 0: r = 1 #0.9 g = 1 #0 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() # Put the hpText over the head of the avatar self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) # Make sure it is a billboard self.hpText.setBillboardPointEye() # Render it after other things in the scene. self.hpText.setBin('fixed', 100) # Initial position ... Center of the body... the "tan tien" self.hpText.setPos(self.root, 0, 0, self.height / 2) # Black magic from the early days of Panda3D, later replaced by a Sequence seq = Task.sequence( # Fly the number out of the character self.hpText.lerpPos(Point3( self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), 0.25, blendType='easeOut'), Task.pause(0.25), # Fade the number self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), # Get rid of the number Task.Task(self.__hideHitScoreTask)) taskMgr.add(seq, "PartyCogHpText" + str(self.id)) def __hideHitScoreTask(self, task): self.hideHitScore() return Task.done def hideHitScore(self): if self.hpText: taskMgr.remove("PartyCogHpText" + str(self.id)) self.hpText.removeNode() self.hpText = None def getHeadLocation(self): (self.actor.getJoints(jointName="head")[0]).getNetTransform( self.temp_transform) self.head_locator.setMat(self.temp_transform) #print self.head_locator.getZ() return self.head_locator.getZ(self.root)
class Weapon(DirectObject): def __init__(self, x, y, z, angle, bullets, id, projZ): self.keyMap = {"firing":0} self.prevtime = 0 #id will be 0 for player, 1 - whatever for ai's self.playerid = id #print(players.players[1]) if str(self.playerid) == "0": self.accept("space", self.setKey, ["firing", 1] ) self.accept("space-up", self.setKey, ["firing", 0] ) #note - projectiles should be an empty list the first time you create the weapon self.bullets = bullets #set weapon cooldown and how long it slows a player down for self.cooldown = 1.0 self.penalty = 0.5 self.ammo = 1000 self.range = 30 self.idLim = 1000 self.projId = 0 self.angle = angle self.xpos = x self.ypos = y self.zpos = z self.projZ = projZ self.pistolSound = loader.loadSfx("Sound/FX/pistol.wav") #for debugging purposes only #taskMgr.add(self.testing, "TESTING_WEAPON") self.prevtime = 0 self.LoadModel() #DEBUGGING PURPOSES ONLY #def testing(self, task): #camera.lookAt(self.form) # self.update(0, 0, 3, 0, task.time - self.prevtime) # self.prevtime = task.time # return Task.cont def LoadModel(self): #self.form = loader.loadModel("models/weapons/revolverProxy") #self.form.setScale(.9) self.form = Actor("animations/gentlemanPistol_idle", {"idle":"animations/gentlemanPistol_idle", "shoot":"animations/gentlemanPistol_idle"}) self.form.setPos(self.xpos, self.ypos, self.zpos) self.form.loop('idle') #self.form.setScale(5) #self.form.setPos(self.xpos,self.ypos,self.zpos+3) #self.form.setH(self.angle) #self.form.reparentTo(render) def setKey(self, key, value): self.keyMap[key] = value #note: angle is the angle that the player is facing #x, y, is the horizontal plane def update(self, x, y, z, angle, elapsed): """you need to call update on the weapon every time you update player""" self.angle = angle self.xpos = x self.ypos = y self.zpos = z self.cooldown = self.cooldown - elapsed if self.cooldown < 0.0: self.cooldown = 0.0 if self.keyMap["firing"] and self.cooldown == 0 and self.ammo > 0 and not players.players[self.playerid].invincible: self.fire() else: if self.form.getCurrentAnim() == "shoot": self.form.stop() self.form.loop('idle') for i, projectile in enumerate(self.bullets): #update all projectiles belonging to this weapon, if not projectile.update(elapsed): #if the projectile was destroyed, get rid of it self.bullets.pop(i) # if the player runs out of ammo (this will only happen on inherited classes, # kill the thing and revert back to the pistol if self.ammo <= 0: self.kill() return False #note, when update returns false, you need to pass the weapon's projecitles #to the new pistol before destroying it return True def fire(self): """pulls the trigger""" #print(len(players.players)) #self.pistolSound.play() if(self.projId >= self.idLim): self.projId = 0 new_projectile = Projectile(100, self.xpos, self.ypos, self.projZ, self.angle, 100, self.playerid, self.projId, len(self.bullets), players) self.bullets.append(new_projectile) self.projId = self.projId + 1 #if self.playerid != 0: # self.accept("projectile:" + str(self.playerid) + ":" + str(len(self.bullets)-1) + "-collision-player", self.address_bullet) #for i in range(1, 4): # if str(i) != self.playerid: # self.accept("projectile:" + str(self.playerid) + ":" + str(len(self.bullets)-1) + "-collision-ai"+str(i), self.address_bullet) if self.form.getCurrentAnim() == "idle": self.form.loop('shoot') self.cooldown = 1.0 #occurs when there is a bullet collision def address_bullet(self, cEntry): """called when a projectile collides with a player or ai""" print "bullet collision detected" #have the injured party incur a penalty handle = cEntry.getIntoNodePath().getName() #will be either ai<num> or player if handle == "player": players[0].take_damage(1) else: players[int(handle[2])].take_damage(1) #remove the bullet object cEntry.getFromNodePath().getParent().remove() def kill(self): """removes the weapon from the scene""" self.form.cleanup() self.form.removeNode()
class KlobWorld(ShowBase): def __init__(self): ShowBase.__init__(self) ## wp = WindowProperties(base.win.getProperties()) ## wp.setSize(1280,720) ## base.win.requestProperties(wp) base.setBackgroundColor(255,250,250) self.listAudio3d = [] self.allSounds() self.energyTime = 0 self.collHandQue = CollisionHandlerQueue() self.collHandQueEne = CollisionHandlerQueue() self.SPEED = .5 self.speedv = 4 base.cTrav = CollisionTraverser() self.bossLvl = False self.bossDead = False self.isMoving = False self.pause = True self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) self.currentLevel = "start" self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "cam-right":0, "cam-up":0, "cam-down":0, "fire-down":0, "p":0} ###Disable the default camera controls### base.disableMouse() self.pusher = CollisionHandlerPusher() base.cTrav.setRespectPrevTransform(True) #Uncomment to show collisions with environment #base.cTrav.showCollisions(render) self.setAcceptKeys() self.MainMenu() ## List to keep track of all actors added in each level ## to make it easier to cleanup level when destroyed self.crAct = [] self.extraElements = [] self.laserAmo = [] self.beamC = [] self.laserAmoCount = 0 self.enemyTimer = 0 self.gunAmmoCount = 0 self.loaded = [] self.bulletC = [] def allSounds(self): self.audio = Audio3DManager(self.sfxManagerList[0]) self.audio.attachListener(base.camera) self.heartBeat = base.loadMusic("sounds/heartbeat.wav") self.cheer = base.loadMusic("sounds/cheer.wav") self.intro = base.loadMusic("sounds/Mario.wav") self.bulletSound = base.loadMusic("sounds/gun_shot.wav") self.laserSound = base.loadMusic("sounds/gun_shot.wav") self.deadSound = base.loadMusic("sounds/pacman_death.wav") self.sound = self.audio.loadSfx("sounds/forest.wav") self.gust = base.loadMusic("sounds/gust.wav") self.siren = base.loadMusic("sounds/siren_2.wav") self.waterfallSound = self.audio.loadSfx("sounds/waterfall.wav") self.etSound = base.loadMusic("sounds/et-sound.wav") self.walking = base.loadMusic("sounds/running.wav") self.mainMenuMusic = base.loadMusic("sounds/intro.wav") self.rainforestMusic = self.loader.loadSfx("sounds/rainforest.wav") self.egyptMusic = self.loader.loadSfx("sounds/egypt.wav") self.asiaMusic = self.loader.loadSfx("sounds/asia.wav") self.newyorkMusic = self.loader.loadSfx("sounds/newyork.wav") self.mainMenuMusic.setLoop(True) self.rainforestMusic.setLoop(True) self.egyptMusic.setLoop(True) self.asiaMusic.setLoop(True) self.newyorkMusic.setLoop(True) self.gust.setLoop(True) self.sound.setLoop(True) self.siren.setLoop(True) self.walking.setVolume(5) self.heartBeat.setVolume(5) self.deadSound.setVolume(.5) self.laserSound.setVolume(.2) self.bulletSound.setVolume(.2) self.sound.setVolume(2) self.rainforestMusic.setVolume(.6) self.egyptMusic.setVolume(2) self.siren.setVolume(.3) def stopAllSounds(self): self.audio.detachSound(self.waterfallSound) self.audio.detachSound(self.sound) self.audio.detachSound(self.rainforestMusic) self.audio.detachSound(self.egyptMusic) self.audio.detachSound(self.newyorkMusic) self.intro.stop() self.bulletSound.stop() self.laserSound.stop() self.deadSound.stop() self.sound.stop() self.gust.stop() self.siren.stop() self.waterfallSound.stop() self.etSound.stop() self.walking.stop() self.mainMenuMusic.stop() self.rainforestMusic.stop() self.egyptMusic.stop() self.asiaMusic.stop() self.newyorkMusic.stop() def MainMenuLevels(self): if(self.currentLevel != "start"): self.destroyLevel() self.stopAllSounds() self.level1Btn = DirectButton( scale = (0.27,0.1,0.1), command = self.loadRainforestLevel, pos = Vec3(0, 0, 0.4), image = 'GUI/southamericabutton.png', relief = None) self.level2Btn = DirectButton( scale = (0.27,0.1,0.1), command = self.loadAfricaLevel, pos = Vec3(0, 0, 0.15), image = 'GUI/africabutton.png', relief = None) self.level3Btn = DirectButton( scale = (0.27,0.1,0.1), command = self.loadAsiaLevel, pos = Vec3(0, 0, -0.1), image = 'GUI/asiabutton.png', relief = None) self.level4Btn = DirectButton( scale = (0.27,0.1,0.1), command = self.loadNewYorkLevel, pos = Vec3(0, 0, -0.35), image = 'GUI/americabutton.png', relief = None) self.level2Btn.setTransparency(TransparencyAttrib.MAlpha) self.level3Btn.setTransparency(TransparencyAttrib.MAlpha) self.level4Btn.setTransparency(TransparencyAttrib.MAlpha) self.level1Btn.setTransparency(TransparencyAttrib.MAlpha) def destroyMainMenuLevels(self): self.level1Btn.destroy() self.level2Btn.destroy() self.level3Btn.destroy() self.level4Btn.destroy() self.mainMenuBtn = DirectButton( text="Main Menu", scale = (0.1,0.1,0.1), command = self.MainMenuLevels, pos = Vec3(0.8, 0, -0.9)) def MainMenu(self): if(self.currentLevel == "help"): self.destroyHelpMenu() elif(self.currentLevel != "start"): self.destroyLevel() self.mainMenuBtn.destroy() self.stopAllSounds() self.currentLevel="start" self.mainMenuImage = OnscreenImage("GUI/mainmenu.png",pos = Vec3(0, 0.0,-0.8), scale=(1.8, 0, 1.8)) self.mainMenuImage.reparentTo(aspect2d) self.mainMenuImage.setTransparency(1) self.mainMenuMusic.play() mapStart = loader.loadModel('GUI/button_maps.egg') self.startBtn = DirectButton(geom = (mapStart.find('**/start_but'), mapStart.find('**/start_but_click'), mapStart.find('**/start_but_roll'), mapStart.find('**/start_but_disabled')), relief = None, command = self.introScreen, scale = (0.7,0.7,0.7), pos = Vec3(0.6, 0, -0.35)) self.startBtn.setTransparency(TransparencyAttrib.MAlpha) mapHelp = loader.loadModel('GUI/helpbutton_maps.egg') self.helpBtn = DirectButton(geom = (mapHelp.find('**/help_but'), mapHelp.find('**/help_but_click'), mapHelp.find('**/help_but_roll'), mapHelp.find('**/help_but_disabled')), relief = None, command = self.HelpMenu, scale = (0.8,0.65,0.65), pos = Vec3(0.6, 0,-0.65)) self.helpBtn.setTransparency(TransparencyAttrib.MAlpha) def destroyMainMenu(self): self.startBtn.destroy() self.helpBtn.destroy() self.mainMenuImage.destroy() self.stopAllSounds() def HelpMenu(self): self.destroyMainMenu() self.currentLevel="help" self.helpMenuImage = OnscreenImage("GUI/helpmenu.png",pos = Vec3(0, 0.0,-0.8), scale=(1.8, 0, 1.8)) self.helpMenuImage.reparentTo(aspect2d) self.helpMenuImage.setTransparency(1) mapHelp = loader.loadModel('GUI/backbutton_maps.egg') self.backBtn = DirectButton(geom = (mapHelp.find('**/backBtn'), mapHelp.find('**/backBtn_click'), mapHelp.find('**/backBtn_roll'), mapHelp.find('**/backBtn_disabled')), relief = None, command = self.MainMenu, scale = (0.7,0.7,0.7), pos = Vec3(-1.4, 0, 0.8)) self.backBtn.setTransparency(TransparencyAttrib.MAlpha) ###...... #code missing. ### .... ##Records the state of the arrow keys### def setKey(self, key, value): if(self.pause is False): self.keyMap[key] = value if(self.keyMap["fire-down"] != 0 ): if( self.energy['value'] != 0 ): if(self.bossDead is False): self.beamC.append( self.loadLaser() ) self.laserAmo.append( self.laser() ) if(self.laserAmo): self.laserAmo[self.laserAmoCount].start() self.energy['value'] -= 3 self.laserAmoCount = self.laserAmoCount + 1 def loadEnviron(self, filename, scale): self.environ = self.loader.loadModel(filename) self.environ.setScale(scale) self.environ.reparentTo(self.render) self.environ.setPos(0, 0, 0) self.environ.setTag('wall','1') self.environ.setCollideMask(BitMask32(0x01)) alight = AmbientLight('alight') alight.setColor(VBase4(0.8, 0.8, 0.8, 1)) alnp = render.attachNewNode(alight) render.setLight(alnp) def loadAlien(self, point): ###Load alien actor### self.alien = Actor("models/alien/slugrocket-model", {"walk":"models/alien/slugrocket-anim"}) self.alien.reparentTo(render) self.alien.setScale(3) self.alien.setPos(point) self.alien.setPlayRate(1.2, "walk") self.alien.setBlend(frameBlend = True) self.dlight = DirectionalLight('my dlight') self.dlnp = render.attachNewNode(self.dlight) self.dlnp.reparentTo(base.camera) self.dlnp.lookAt(self.alien) self.dlight.setColor(VBase4(0.8, 0.8, 0.5, 1)) render.setLight(self.dlnp) base.camera.setPos(0,-10,2) base.camera.reparentTo(self.alien) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(2)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) csAlien = CollisionSphere(0,0,0.6,0.6) cnodeAlienPath = self.alien.attachNewNode(CollisionNode('csAlien')) cnodeAlienPath.node().addSolid(csAlien) self.pusher.addCollider(cnodeAlienPath, self.alien) base.cTrav.addCollider(cnodeAlienPath, self.pusher) ### Uncomment the following comment to show ### the Collision Sphere on the alien ## cnodeAlienPath.show() self.health = DirectWaitBar(scale = 0.5, range = 100, value = 100, barColor = (0,1,0,1), pos = Vec3(0.75, 0, 0.9)) self.energy = DirectWaitBar(scale = 0.5, range = 100, value = 100, barColor = (1,1,0,1), pos = Vec3(-0.75, 0, 0.9)) self.energy.reparentTo(aspect2d) self.health.reparentTo(aspect2d) self.hud = OnscreenImage("GUI/hud.png",scale = Vec3(1.43, 1.0, 1.03),pos = Vec3(0, 0.0,0.045)) self.hud.reparentTo(aspect2d) self.hud.setTransparency(1) self.extraElements.append(self.energy) self.extraElements.append(self.health) self.extraElements.append(self.hud) def alienDie(self, currLvl): self.alien.stop() self.pause=True temp = NodePath(PandaNode("temp")) base.camera.reparentTo(self.floater) base.camera.setZ(base.camera.getZ()+1) base.camera.setY(base.camera.getY()-25) self.deadSound.play() fall = LerpHprInterval(nodePath=self.alien, duration=1.5, hpr=(self.alien.getH(),self.alien.getP(), self.alien.getR()-80)) fall.start() taskMgr.remove("moveTask") taskMgr.remove("laterFc") transition = Transitions(loader) transition.setFadeColor(0, 0, 0) self.dieImage = OnscreenImage("GUI/died.png",scale = Vec3(0.7, 0, 0.2),pos = Vec3(0, 0,-0.5)) self.dieImage.reparentTo(aspect2d) self.dieImage.setTransparency(1) if(self.currentLevel == "rainforest"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(2.0),Func(self.destroyLevel),Func(self.loadRainforestLevel),Func(self.dieImage.destroy),Func(transition.fadeIn)).start() elif(self.currentLevel == "africa"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(2.0),Func(self.destroyLevel),Func(self.loadAfricaLevel),Func(self.dieImage.destroy),Func(transition.fadeIn)).start() elif(self.currentLevel == "asia"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(2.0),Func(self.destroyLevel),Func(self.loadAsiaLevel),Func(self.dieImage.destroy),Func(transition.fadeIn)).start() elif(self.currentLevel == "newyork"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(2.0),Func(self.destroyLevel),Func(self.loadNewYorkLevel),Func(self.dieImage.destroy),Func(transition.fadeIn)).start() def collide(self, collEntry): collEntry.getFromNodePath().getParent().removeNode() def setAcceptKeys(self): ###Accept the control keys for movement and rotation### self.accept("escape", sys.exit) self.accept("p", self.setKey, ["p",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("arrow_down", self.setKey, ["backward", 1]) self.accept("arrow_down-up", self.setKey, ["backward", 0]) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("a", self.setKey, ["cam-left",1]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("s-up", self.setKey, ["cam-right",0]) self.accept("z", self.setKey, ["cam-up",1]) self.accept("z-up", self.setKey, ["cam-up",0]) self.accept("x", self.setKey, ["cam-down", 1]) self.accept("x-up", self.setKey, ["cam-down", 0]) # Accept f to fire self.accept("f", self.setKey, ["fire-down",1]) self.accept("f-up", self.setKey, ["fire-down",0]) self.cTrav.traverse(render) #gun / laser code ommitted def getDistance(self, actor): self.vecAlien = Vec3(self.alien.getPos()) self.vecObj = Vec3(actor.getPos()) disVec = self.vecObj - self.vecAlien return disVec.length() def myFunction(self,task): self.walking.play() if(self.pause is False): for r in range(0, len(self.crAct)): self.crAct[r].setTarget(self.alien) self.bulletC.append( self.createBullet(self.crAct[r]) ) self.loaded.append( self.loadBullet( self.crAct[r]) ) self.loaded[self.gunAmmoCount].start() self.gunAmmoCount += 1 self.bulletSound.play() return task.again def bossLvlTask(self, dec, task): self.crAct[0].setAiPursue(self.alien) if(self.pause is False): self.deleteProjectiles() self.charcMoveKeys() startpos = self.alien.getPos() self.floater.setPos(self.alien.getPos()) self.floater.setZ(self.alien.getZ() + 2.0) base.camera.lookAt(self.floater) self.collHandQueEne.sortEntries() if(self.collHandQueEne.getNumEntries() > 0): entryb = self.collHandQueEne.getEntry(0) if( entryb.getIntoNodePath().getName() == "csAlien"): self.health['value'] -=5 if(self.bulletC): self.bulletC[self.gunAmmoCount-1].remove() self.bulletC.pop(self.gunAmmoCount-1) self.loaded.pop(self.gunAmmoCount-1) self.gunAmmoCount -= 1 if( self.health['value'] < 20 ): self.heartBeat.play() if(self.health['value'] == 0): self.alienDie(self.currentLevel) else: self.bulletC[self.gunAmmoCount-1].remove() self.bulletC.pop(self.gunAmmoCount-1) self.loaded.pop(self.gunAmmoCount-1) self.gunAmmoCount -= 1 self.collHandQue.sortEntries() if( self.collHandQue.getNumEntries() > 0 ): entry = self.collHandQue.getEntry(0) if( entry.getIntoNodePath().getName() == self.crAct[0].getCNP()): self.crAct[0].runAround(self.alien) self.crAct[0].setHitCount(1) self.crAct[0].decreaseHealth(dec) if( self.beamC): self.beamC[self.laserAmoCount-1].remove() self.beamC.pop(self.laserAmoCount-1) if(self.laserAmo): self.laserAmo.pop(self.laserAmoCount-1) self.laserAmoCount -= 1 if( self.crAct[0].getHealth()%4 == 0): self.crAct[0].jumpAway(self.alien) if( self.crAct[0].getHealth() == 0 ): ## print x.getDeaths() ## if( x.canRespawn() ): ## x.setDeaths(1) ## x.resetHitCount(0) ## x.setX(random.randint(0, 50)) ## x.setY(self.alien.getY()+15) ## else: self.crAct[0].cleanup() self.crAct[0].remove() self.crAct.pop(0) self.cutScene() if( self.crAct ): self.crAct[0].AIworld.update() if( self.keyMap["p"]!= 0): self.cutScene() return task.cont def move(self, task): ##ommmitted return task.cont def deleteProjectiles(self): ## if(self.pause is False): if(self.laserAmo): for i, x in enumerate(self.laserAmo): if( not x.isPlaying() ): self.beamC[i].remove() self.beamC.pop(i) self.laserAmo.pop(i) self.laserAmoCount = self.laserAmoCount -1 if(self.loaded): for i, x in enumerate(self.loaded): if(not x.isPlaying()): #self.crAct[i].setTarget(self.alien) self.bulletC[i].remove() self.bulletC.pop(i) self.loaded.pop(i) self.gunAmmoCount = self.gunAmmoCount -1 self.energyTime = self.energyTime + globalClock.getDt() if(self.energyTime > 2 ): if(self.energy['value'] != 100): self.energy['value'] +=5 self.energyTime = 0 def charcMoveKeys(self): if (self.keyMap["cam-left"]!=0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"]!=0): base.camera.setX(base.camera, +20 * globalClock.getDt()) if (self.keyMap["cam-up"]!=0): base.camera.setY(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-down"]!=0): base.camera.setY(base.camera, +20 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.alien.setY(self.alien, 10 * globalClock.getDt()) if (self.keyMap["backward"]!=0): self.alien.setY(self.alien, -10 * globalClock.getDt()) if (self.keyMap["left"]!=0): self.alien.setH(self.alien.getH() + 40 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.alien.setH(self.alien.getH() - 40 * globalClock.getDt()) if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"] != 0): if self.isMoving is False: self.alien.loop("walk") self.isMoving = True else: if self.isMoving: self.alien.stop() self.alien.pose("walk",5) self.isMoving = False def loadingScreen(self): self.intro.play() transition = Transitions(loader) transition.setFadeColor(0, 0, 0) text = TextNode('node name') dummy = NodePath(PandaNode("dummy")) black = OnscreenImage(image="GUI/black.png",pos=(0,0,0), scale=100) black.reparentTo(dummy) textNodePath = aspect2d.attachNewNode(text) textNodePath.reparentTo(aspect2d, 2) textNodePath.setScale(0.07) text.setTextColor(1, 1, 1, 1) if(self.currentLevel=="newyork"): Sequence(Func(transition.fadeOut),Func(black.reparentTo, aspect2d),Func(transition.fadeIn),Func(textNodePath.reparentTo,aspect2d, 10),Func(text.setText, "loading"),Wait(1.0),Func(text.setText, "loading."), Wait(1.0),Func(text.setText, "loading.."), Wait(1.0), Func(text.setText, "loading..."), Func(self.loadNextLevel),Wait(3.0),Func(transition.fadeIn),Func(textNodePath.remove), Func(black.destroy)).start() elif(self.currentLevel=="asia"): Sequence(Func(transition.fadeOut),Func(black.reparentTo, aspect2d),Func(transition.fadeIn),Func(textNodePath.reparentTo,aspect2d, 10),Func(text.setText, "loading"),Wait(1.0),Func(text.setText, "loading."), Wait(1.0),Func(text.setText, "loading.."), Wait(1.0), Func(text.setText, "loading..."), Func(self.loadNextLevel),Wait(3.0),Func(transition.fadeIn),Func(textNodePath.remove), Func(black.destroy)).start() else: Sequence(Func(transition.fadeOut),Func(black.reparentTo, aspect2d),Func(transition.fadeIn),Func(textNodePath.reparentTo,aspect2d, 10),Func(text.setText, "loading"),Wait(0.5),Func(text.setText, "loading."), Wait(0.5),Func(text.setText, "loading.."), Wait(0.5), Func(text.setText, "loading..."), Func(self.loadNextLevel),Wait(1.5),Func(transition.fadeIn),Func(textNodePath.remove), Func(black.destroy)).start() def cutScene(self): self.destroyLevel() self.stopAllSounds() self.cut = OnscreenImage("GUI/bossKilled.png",scale = Vec3(1.6, 0, 1.0),pos = Vec3(0, 0,0)) self.cut.reparentTo(aspect2d) self.cut.setTransparency(1) transition = Transitions(loader) transition.setFadeColor(0, 0, 0) self.cheer.play() if(self.currentLevel=="rainforest"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(1.0),Func(transition.fadeIn),Func(self.cut.setImage,"GUI/map_11.png"), Wait(1.5),Func(self.cut.setImage, "GUI/map_12.png"),Wait(0.5),Func(self.cut.setImage,"GUI/map_13.png"), Wait(0.5),Func(self.cut.setImage,"GUI/map_14.png"),Wait(0.5),Func(self.cut.setImage,"GUI/map_15.png"), Wait(0.5),Func(self.cut.setImage,"GUI/map_16.png"),Wait(3.5),Func(self.cut.destroy), Func(transition.fadeOut), Func(self.loadingScreen), Wait(1.0),Func(transition.fadeIn)).start() elif(self.currentLevel=="africa"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(1.0),Func(transition.fadeIn),Func(self.cut.setImage,"GUI/map_21.png"), Wait(1.5),Func(self.cut.setImage, "GUI/map_22.png"),Wait(0.5),Func(self.cut.setImage,"GUI/map_23.png"), Wait(0.5),Func(self.cut.setImage,"GUI/map_24.png"),Wait(0.5),Func(self.cut.setImage,"GUI/map_25.png"), Wait(0.5),Func(self.cut.setImage,"GUI/map_26.png"), Wait(3.5),Func(self.cut.destroy), Func(transition.fadeOut),Func(self.loadingScreen), Wait(1.0),Func(transition.fadeIn)).start() elif(self.currentLevel=="asia"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(1.0),Func(transition.fadeIn),Func(self.cut.setImage,"GUI/map_31.png"), Wait(1.5),Func(self.cut.setImage, "GUI/map_32.png"),Wait(0.5),Func(self.cut.setImage,"GUI/map_33.png"), Wait(0.5),Func(self.cut.setImage,"GUI/map_34.png"),Wait(0.5),Func(self.cut.setImage,"GUI/map_35.png"), Wait(0.5),Func(self.cut.setImage,"GUI/map_36.png"),Wait(3.5),Func(self.cut.destroy), Func(transition.fadeOut),Func(self.loadingScreen), Wait(1.0),Func(transition.fadeIn)).start() elif(self.currentLevel=="newyork"): Sequence(Wait(2.0),Func(transition.fadeOut),Wait(1.0),Func(transition.fadeIn),Func(self.cut.setImage,"GUI/win.png"), Wait(6.5),Func(self.cut.destroy), Func(transition.fadeOut),Func(self.loadingScreen), Wait(1.0),Func(transition.fadeIn)).start() def loadNextLevel(self): if(self.currentLevel=="start"): self.loadRainforestLevel() elif(self.currentLevel=="rainforest"): self.loadAfricaLevel() elif(self.currentLevel=="africa"): self.loadAsiaLevel() elif(self.currentLevel=="asia"): self.loadNewYorkLevel() else: self.MainMenu() def destroyLevel(self): self.mainMenuBtn.destroy() taskMgr.remove("moveTask") taskMgr.remove("bossTask") taskMgr.remove("myFunction") self.alien.cleanup() for enemy in self.crAct: enemy.cleanup() enemy.remove() self.alien.cleanup() self.alien.remove() for element in self.extraElements: element.removeNode() for beam in self.beamC: beam.removeNode() self.render.clearFog self.laserBeam2.removeNode() self.environ.removeNode() self.crAct[:] = [] self.extraElements[:] = [] self.laserAmo[:] =[] self.laserAmoCount = 0 def loadBossActor(self): self.bossLvl = True ###Load Ralph Boss actor### difficult = 10 taskMgr.remove("moveTask") taskMgr.remove("myFunction") self.health['value'] = 100 self.energy['value'] = 100 if(self.bossDead is False): self.bossImage = OnscreenImage("GUI/bossLoad.png",scale = Vec3(1.6, 0, 1.0),pos = Vec3(0, 0,0)) self.bossImage.reparentTo(aspect2d) self.bossImage.setTransparency(1) self.ralphBoss = EnemyActor(1,difficult,True) self.ralphBoss.enemy.setScale(2.0) self.crAct.append(self.ralphBoss) Sequence(Wait(3.0), Func(self.bossImage.destroy), Func(self.crAct[0].showHealthBar)).start() self.extraElements.append(self.crAct[0].bossHud) self.extraElements.append(self.crAct[0].health) self.crAct[0].setAiPursue(self.alien) self.pusher.addCollider(self.crAct[0].getFromObj(), self.crAct[0].enemy) base.cTrav.addCollider(self.crAct[0].getFromObj(), self.pusher) gunTex = loader.loadTexture('models/gun_tex.png') if(self.currentLevel == "rainforest"): dec = 5 self.ralphBoss.enemy.setPos(0,90,0) ralphTex = loader.loadTexture('models/ralph2rainforest.png') self.ralphBoss.enemy.setTexture(ralphTex, 1) self.ralphBoss.gunPos.setTexture(gunTex, 1) elif(self.currentLevel == "africa"): dec = 4 self.ralphBoss.enemy.setPos(-100,-90,0) ralphTex = loader.loadTexture('models/ralph2egypt.png') self.ralphBoss.enemy.setTexture(ralphTex, 1) self.ralphBoss.gunPos.setTexture(gunTex, 1) elif(self.currentLevel == "asia"): dec = 3 self.ralphBoss.enemy.setPos(0,0,0) ralphTex = loader.loadTexture('models/ralph2asia.png') self.ralphBoss.enemy.setTexture(ralphTex, 1) self.ralphBoss.gunPos.setTexture(gunTex, 1) elif(self.currentLevel == "newyork"): dec = 2 self.ralphBoss.enemy.setPos(120,10,0) taskMgr.add(self.bossLvlTask,"bossTask", extraArgs = [dec], appendTask=True) taskMgr.doMethodLater(1,self.myFunction,"myFunction") def loadRainforestLevel(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "cam-right":0, "cam-up":0, "cam-down":0, "fire-down":0, "p":0} self.pause = False self.currentLevel = "rainforest" self.destroyIntro() difficulty = 2 self.bossLvl = False self.bossDead = False ###Load alien### startPos = Point3(0,0,0) self.loadAlien(startPos) self.rainforestMusic.play() ###Load the enemies### ralphTex = loader.loadTexture('models/ralph2rainforest.png') gunTex = loader.loadTexture('models/gun_tex.png') for i in range(0,2): enemy = EnemyActor(i, difficulty, False) enemy.enemy.setTexture(ralphTex, 1) enemy.gunPos.setTexture(gunTex, 1) enemy.setX(random.randint(-50,50)) enemy.setY(random.randint(-50,50)) enemy.setZ(0) self.crAct.append(enemy) self.crAct[i].setAiPursue(self.alien) self.pusher.addCollider(self.crAct[i].getFromObj(), self.crAct[i].enemy) base.cTrav.addCollider(self.crAct[i].getFromObj(), self.pusher) taskMgr.add(self.move,"moveTask") taskMgr.doMethodLater(3,self.myFunction,"myFunction") self.loadLaser2() self.loadLaser() ###Load the environment### self.loadEnviron("models/south_america/rainforest", 5) self.plants = self.loader.loadModel("models/south_america/rainforest-nocollision") self.plants.reparentTo(self.render) self.plants.setScale(4) self.plants.setTwoSided(True) self.extraElements.append(self.plants) self.myFog = Fog("FOG") self.myFog.setColor(0.5,0.6,0.5) self.myFog.setExpDensity(0.005) render.setFog(self.myFog) self.audio.attachSoundToObject(self.sound, self.environ) self.audio.setSoundVelocityAuto(self.sound) self.audio.setListenerVelocityAuto() self.sound.play() def loadAfricaLevel(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "cam-right":0, "cam-up":0, "cam-down":0, "fire-down":0, "p":0} self.pause = False self.currentLevel="africa" difficulty = 3 self.bossLvl = False self.bossDead = False ###Load alien### startPos = Point3(-130,-130,0) self.loadAlien(startPos) self.alien.setH(-40) ###Load the enemies### ralphTex = loader.loadTexture('models/ralph2egypt.png') gunTex = loader.loadTexture('models/gun_tex.png') for i in range(0,3): enemy = EnemyActor(i, difficulty, False) enemy.enemy.setTexture(ralphTex, 1) enemy.gunPos.setTexture(gunTex, 1) enemy.setX(random.randint(-170,-50)) enemy.setY(random.randint(-170,-50)) enemy.setZ(0) self.crAct.append(enemy) self.crAct[i].setAiPursue(self.alien) self.pusher.addCollider(self.crAct[i].getFromObj(), self.crAct[i].enemy) base.cTrav.addCollider(self.crAct[i].getFromObj(), self.pusher) taskMgr.add(self.move,"moveTask") taskMgr.doMethodLater(3,self.myFunction,"myFunction") self.loadLaser2() self.loadLaser() ###Load environment### self.loadEnviron("models/africa/egypt", 7) self.egypt_nc = self.loader.loadModel("models/africa/egypt-nocollision") self.egypt_nc.reparentTo(self.render) self.egypt_nc.setPos(0,0,0) self.egypt_nc.setScale(7) self.extraElements.append(self.egypt_nc) self.sphinx = self.loader.loadModel("models/africa/sphinx") self.sphinx.setPos(0,80,0) self.sphinx.setH(180) self.sphinx.setScale(0.12) self.sphinx.reparentTo(self.render) self.extraElements.append(self.sphinx) cs = CollisionSphere(0,0,0,200) nodePath = self.sphinx.attachNewNode(CollisionNode('nodePath')) nodePath.node().addSolid(cs) self.gust.play() self.audio.attachSoundToObject(self.egyptMusic, self.environ) self.audio.setSoundVelocityAuto(self.egyptMusic) self.audio.setListenerVelocityAuto() self.egyptMusic.play() def loadAsiaLevel(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "cam-right":0, "cam-up":0, "cam-down":0, "fire-down":0, "p":0} self.pause = False self.currentLevel = "asia" difficulty = 4 self.bossLvl = False self.bossDead = False ###Load alien### startPos = Point3(190,-140,0) self.loadAlien(startPos) ###Load the enemies### ralphTex = loader.loadTexture('models/ralph2asia.png') gunTex = loader.loadTexture('models/gun_tex.png') for i in range(0,4): enemy = EnemyActor(i, difficulty, False) enemy.enemy.setTexture(ralphTex, 1) enemy.gunPos.setTexture(gunTex, 1) enemy.setX(random.randint(0,100)) enemy.setY(random.randint(-150,-50)) enemy.setZ(0) self.crAct.append(enemy) self.crAct[i].setAiPursue(self.alien) self.pusher.addCollider(self.crAct[i].getFromObj(), self.crAct[i].enemy) base.cTrav.addCollider(self.crAct[i].getFromObj(), self.pusher) taskMgr.add(self.move,"moveTask") taskMgr.doMethodLater(3,self.myFunction,"myFunction") self.loadLaser2() self.loadLaser() ###Load the environment### self.loadEnviron("models/asia/asia2", 5) self.asia_nc = self.loader.loadModel("models/asia/asia-nocollision") self.asia_nc.reparentTo(self.render) self.asia_nc.setPos(0,0,0) self.asia_nc.setScale(5) self.extraElements.append(self.asia_nc) self.myFog = Fog("FOG") self.myFog.setColor(0.8,0.8,0.8) self.myFog.setExpDensity(0.002) render.setFog(self.myFog) self.bonzai = self.loader.loadModel("models/asia/bonzai") self.bonzai.reparentTo(self.render) self.bonzai.setPos(170,20,0) self.bonzai.setScale(0.015) self.bonzai.setH(90) self.extraElements.append(self.bonzai) cs = CollisionSphere(0,0,200,200) nodePath = self.bonzai.attachNewNode(CollisionNode('nodePath')) nodePath.node().addSolid(cs) self.pusher.addCollider(nodePath, self.bonzai) self.waterfall = self.loader.loadModel("models/asia/waterFall") self.waterfall.reparentTo(self.render) self.waterfall.setPos(200,80,-.5) self.waterfall.setScale(0.25) self.waterfall.setH(180) self.extraElements.append(self.waterfall) cs = CollisionSphere(0,15,-5,130) nodePath = self.waterfall.attachNewNode(CollisionNode('nodePath')) nodePath.node().addSolid(cs) self.pusher.addCollider(nodePath, self.waterfall) self.waterfallSound.setLoop(True) self.audio.attachSoundToObject(self.waterfallSound,self.waterfall) self.audio.setSoundVelocityAuto(self.waterfallSound) self.audio.setListenerVelocityAuto() self.audio.setDistanceFactor(1.5) self.waterfallSound.play() self.tree1 = self.loader.loadModel("models/asia/bamboo") self.tree1.reparentTo(self.render) self.tree1.setPos(-50,-50,0) self.tree1.setScale(0.6,0.6,0.6) self.tree1.setBillboardAxis() self.extraElements.append(self.tree1) #Child bamboos scattered around placeholder = render.attachNewNode("Bamboo-Placeholder") placeholder.setPos(180,-40,0) placeholder.setScale(0.8) self.tree1.instanceTo(placeholder) self.extraElements.append(placeholder) placeholder = render.attachNewNode("Babmboo-Placeholder") placeholder.setPos(-20,-120,0) placeholder.setScale(1.0) self.tree1.instanceTo(placeholder) self.extraElements.append(placeholder) placeholder = render.attachNewNode("Bamboo-Placeholder") placeholder.setPos(-50,180,0) placeholder.setScale(1.0) self.tree1.instanceTo(placeholder) self.extraElements.append(placeholder) placeholder = render.attachNewNode("Bamboo-Placeholder") placeholder.setPos(-60,165,0) placeholder.setScale(0.6) self.tree1.instanceTo(placeholder) self.extraElements.append(placeholder) placeholder = render.attachNewNode("Bamboo-Placeholder") placeholder.setPos(-110,70,0) placeholder.setScale(1.0) self.tree1.instanceTo(placeholder) self.extraElements.append(placeholder) placeholder = render.attachNewNode("Bamboo-Placeholder") placeholder.setPos(-100,-50,0) placeholder.setScale(1.6) self.tree1.instanceTo(placeholder) self.extraElements.append(placeholder) self.asiaMusic.play() def loadNewYorkLevel(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "cam-right":0, "cam-up":0, "cam-down":0, "fire-down":0,"p":0} self.pause = False self.currentLevel = "newyork" #self.destroyMainMenuLevels() difficulty = 5 ###Load alien### startPos = Point3(20,10,0) self.loadAlien(startPos) self.alien.setH(90) base.camera.setH(90) self.bossLvl = False self.bossDead = False ###Load the enemies### for i in range(0,5): enemy = EnemyActor(i, difficulty, False) enemy.setX(random.randint(-100,100)) enemy.setY(random.randint(8,12)) enemy.setZ(0) self.crAct.append(enemy) self.crAct[i].setAiPursue(self.alien) self.pusher.addCollider(self.crAct[i].getFromObj(), self.crAct[i].enemy) base.cTrav.addCollider(self.crAct[i].getFromObj(), self.pusher) taskMgr.add(self.move,"moveTask") taskMgr.doMethodLater(2,self.myFunction, "myFunction") self.loadLaser2() self.loadLaser() ###Load the environment### self.loadEnviron("models/america/newyork", 4) self.ny_nc = self.loader.loadModel("models/america/newyork-nocollision") self.ny_nc.reparentTo(self.render) self.ny_nc.setScale(4) self.extraElements.append(self.ny_nc) self.statue = self.loader.loadModel("models/america/statue") self.statue.reparentTo(self.render) self.statue.setPos(270,-100,13) self.statue.setScale(1) self.statue.setBillboardAxis() self.statue.setTwoSided(True) self.extraElements.append(self.statue) self.myFog = Fog("FOG") self.myFog.setColor(0.3,0.3,0.3) self.myFog.setExpDensity(0.005) render.setFog(self.myFog) self.siren.play() self.newyorkMusic.play()
class GameObject(): def __init__(self, pos, modelName, modelAnims, maxHealth, maxSpeed, colliderName, height, weaponIntoMask): self.root = render.attachNewNode(PandaNode("obj")) self.colliderName = colliderName self.modelName = modelName if modelName is None: self.actor = NodePath(PandaNode("actor")) elif modelAnims is None: self.actor = loader.loadModel(modelName) else: self.actor = Actor(modelName, modelAnims) self.actor.reparentTo(self.root) if pos is not None: self.root.setPos(pos) self.height = height self.maxHealth = maxHealth self.health = maxHealth self.maxSpeed = maxSpeed self.terminalVelocity = 15 self.flinchCounter = 0 self.velocity = Vec3(0, 0, 0) self.acceleration = 300.0 self.inControl = True self.walking = False self.noZVelocity = True if colliderName is not None: colliderNode = CollisionNode(colliderName) colliderNode.addSolid(CollisionCapsule(0, 0, 0, 0, 0, height, 0.3)) self.weaponCollider = self.root.attachNewNode(colliderNode) self.weaponCollider.setPythonTag(TAG_OWNER, self) colliderNode.setFromCollideMask(0) colliderNode.setIntoCollideMask(weaponIntoMask) #self.weaponCollider.show() else: self.weaponCollider = self.root.attachNewNode( PandaNode("stand-in")) self.deathSound = None self.currentWeapon = None def update(self, dt, fluid=False): speed = self.velocity.length() if self.noZVelocity: self.velocity.setZ(0) if self.inControl: if self.walking and speed > self.maxSpeed: self.velocity.normalize() self.velocity *= self.maxSpeed speed = self.maxSpeed else: if speed > self.terminalVelocity: self.velocity.normalize() self.velocity *= self.terminalVelocity speed = self.terminalVelocity if not self.walking: perc = speed / self.maxSpeed frictionVal = FRICTION * dt / (max(1, perc * perc)) if not self.inControl: frictionVal *= 0.8 if frictionVal > speed: self.velocity.set(0, 0, 0) else: frictionVec = -self.velocity frictionVec.normalize() frictionVec *= frictionVal self.velocity += frictionVec if not self.inControl and speed < 0.1: self.inControl = True if fluid: self.root.setFluidPos(self.root.getPos() + self.velocity * dt) else: self.root.setPos(self.root.getPos() + self.velocity * dt) def alterHealth(self, dHealth, incomingImpulse, flinchValue, overcharge=False): previousHealth = self.health self.health += dHealth if incomingImpulse is not None and incomingImpulse.lengthSquared( ) > 0.1: self.velocity += incomingImpulse self.inControl = False self.walking = False if flinchValue > 0: self.flinchCounter -= flinchValue if dHealth > 0 and self.health > self.maxHealth and not overcharge: self.health = self.maxHealth if previousHealth > 0 and self.health <= 0 and self.deathSound is not None: self.deathSound.play() def turnTowards(self, target, turnRate, dt): if isinstance(target, NodePath): target = target.getPos(render) elif isinstance(target, GameObject): target = target.root.getPos(render) diff = target - self.root.getPos(render) angle = self.getAngleWithVec(diff) if abs(angle) < 1: return angle maxTurn = turnRate * dt if angle < 0: maxTurn = -maxTurn if angle > maxTurn: self.root.setH(self.root, angle) return 0 else: self.root.setH(self.root, maxTurn) return angle - maxTurn else: if angle < maxTurn: self.root.setH(self.root, angle) return 0 else: self.root.setH(self.root, maxTurn) return angle - maxTurn def getAngleWithVec(self, vec): forward = self.actor.getQuat(render).getForward() forward2D = Vec2(forward.x, forward.y) vec = Vec2(vec.x, vec.y) vec.normalize() angle = forward2D.signedAngleDeg(vec) return angle def cleanup(self): if self.weaponCollider is not None and not self.weaponCollider.isEmpty( ): self.weaponCollider.clearPythonTag(TAG_OWNER) self.weaponCollider.removeNode() self.weaponCollider = None if self.actor is not None: if isinstance(self.actor, Actor): self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None
class Golem(FSM, DirectObject): def __init__(self): FSM.__init__(self, "FSM-Golem") random.seed() self.golem = loader.loadModel("Golem") self.golem = Actor("Golem", { "Idle":"Golem-Idle", "Walk":"Golem-Walk", "Attack":"Golem-Attack", "Destroyed":"Golem-Destroyed"}) self.golem.setBlend(frameBlend = True) golemViewSphere = CollisionSphere(0, 0, 0.5, 6) golemViewSphere.setTangible(False) golemViewColNP = self.golem.attachNewNode(CollisionNode('golemViewField')) golemViewColNP.node().addSolid(golemViewSphere) golemHitSphere = CollisionSphere(0, 0, 0.5, 1) golemHitColNP = self.golem.attachNewNode(CollisionNode('golemHitField')) golemHitColNP.node().addSolid(golemHitSphere) # a collision segment to check attacks self.attackCheckSegment = CollisionSegment(0, 0, 1, 0, -1.3, 1) self.golemAttackRay = self.golem.attachNewNode(CollisionNode("golemAttackCollision")) self.golemAttackRay.node().addSolid(self.attackCheckSegment) self.golemAttackRay.node().setIntoCollideMask(0) self.attackqueue = CollisionHandlerQueue() base.cTrav.addCollider(self.golemAttackRay, self.attackqueue) attackAnim = self.golem.actorInterval("Attack", playRate = 2) self.AttackSeq = Parallel( attackAnim, Sequence( Wait(0.5), Func(self.ceckAttack) )) self.lookatFloater = NodePath(PandaNode("golemTracker")) self.lookatFloater.setPos(self.golem, 0, 0, 3.4) self.lookatFloater.hide() self.lookatFloater.reparentTo(render) self.trackerObject = loader.loadModel("misc/Pointlight") self.trackerObject.setColor(0, 1, 0) self.trackerObject.setScale(0.25) self.trackerObject.reparentTo(self.lookatFloater) def start(self, startPos): self.golem.setPos(startPos.getPos()) self.golem.setHpr(startPos.getHpr()) self.golem.reparentTo(render) self.trackedEnemy = None self.health = 5 self.accept("playerCollision-in-golemViewField", lambda extraArgs: base.messenger.send("golemSeesPlayer", [self.golem])) def stop(self): self.trackedEnemy = None taskMgr.remove("GolemAI_task") self.golem.hide() self.ignoreAll() def cleanup(self): self.stop() self.lookatFloater.removeNode() self.golem.cleanup() self.golem.removeNode() def activate(self, trackedEnemy): self.trackedEnemy = trackedEnemy taskMgr.add(self.aiTask, "GolemAI_task") self.lookatFloater.show() def aiTask(self, task): dt = globalClock.getDt() if self.AttackSeq.isPlaying(): return task.cont self.lookatFloater.setPos(self.golem, 0, 0, 3.4) self.lookatFloater.lookAt(self.trackedEnemy) self.lookatFloater.setH(self.lookatFloater.getH() + 180) self.lookatFloater.setP(0) self.lookatFloater.setR(0) self.golem.lookAt(self.trackedEnemy) self.golem.setH(self.golem.getH() + 180) distanceVec = self.golem.getPos() - self.trackedEnemy.getPos() enemyDist = distanceVec.length() if enemyDist < 2.0: # close enough for combat action = random.choice(["Attack", "Idle"]) if action == "Attack": self.request("Attack") else: if self.state != "Idle": self.request("Idle") else: self.golem.setY(self.golem, -0.5 * dt) if self.state != "Walk": self.request("Walk") return task.cont def hit(self): hitInterval = Sequence( Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15)) self.health -= 1 if self.health == 4: self.trackerObject.setColor(0, 1, 0) hitInterval.start() elif self.health == 3: self.trackerObject.setColor(0.25, 0.75, 0) hitInterval.start() elif self.health == 2: self.trackerObject.setColor(0.5, .5, 0) hitInterval.start() elif self.health == 1: self.trackerObject.setColor(0.75, 0.25, 0) hitInterval.start() elif self.health == 0: self.trackerObject.setColor(0, 0, 0) self.request("Destroyed") def ceckAttack(self): for i in range(self.attackqueue.getNumEntries()): entry = self.attackqueue.getEntry(i) into = entry.getIntoNode() if "playerCollision" in into.getName(): if random.random() > .5: base.messenger.send("HitPlayer") def enterIdle(self): self.golem.loop("Idle") def enterWalk(self): self.golem.setPlayRate(2, "Walk") self.golem.loop("Walk") def enterAttack(self): self.AttackSeq.start() def enterDestroyed(self): self.ignoreAll() taskMgr.remove("GolemAI_task") self.AttackSeq.finish() self.golem.play("Destroyed") self.lookatFloater.hide() base.messenger.send("GolemDestroyed")
class Player(FSM, DirectObject): def __init__(self, charId, charNr, controls): FSM.__init__(self, "FSM-Player{}".format(charNr)) self.charId = charId charPath = "characters/character{}/".format(charNr) self.character = Actor( charPath + "char", { "Idle": charPath + "idle", "Walk": charPath + "walk", "Walk_back": charPath + "walk_back", "Punch_l": charPath + "punch_l", "Punch_r": charPath + "punch_r", "Kick_l": charPath + "kick_l", "Kick_r": charPath + "kick_r", "Defend": charPath + "defend", "Hit": charPath + "hit", "Defeated": charPath + "defeated", }, ) self.character.reparentTo(render) self.character.hide() self.walkSpeed = 2.0 # units per second if controls == "p1": self.character.setH(90) self.leftButton = KeyboardButton.asciiKey("d") self.rightButton = KeyboardButton.asciiKey("f") self.punchLButton = KeyboardButton.asciiKey("q") self.punchRButton = KeyboardButton.asciiKey("w") self.kickLButton = KeyboardButton.asciiKey("a") self.kickRButton = KeyboardButton.asciiKey("s") self.defendButton = KeyboardButton.asciiKey("e") elif controls == "p2": self.character.setH(-90) self.leftButton = KeyboardButton.right() self.rightButton = KeyboardButton.left() self.punchLButton = KeyboardButton.asciiKey("i") self.punchRButton = KeyboardButton.asciiKey("o") self.kickLButton = KeyboardButton.asciiKey("k") self.kickRButton = KeyboardButton.asciiKey("l") self.defendButton = KeyboardButton.asciiKey("p") self.getPos = self.character.getPos self.getX = self.character.getX characterSphere = CollisionSphere(0, 0, 1.0, 0.5) self.collisionNodeName = "character{}Collision".format(charId) characterColNode = CollisionNode(self.collisionNodeName) characterColNode.addSolid(characterSphere) self.characterCollision = self.character.attachNewNode(characterColNode) # Uncomment this line to show collision solids # self.characterCollision.show() base.pusher.addCollider(self.characterCollision, self.character) base.cTrav.addCollider(self.characterCollision, base.pusher) characterHitRay = CollisionSegment(0, -0.5, 1.0, 0, -0.8, 1.0) characterColNode.addSolid(characterHitRay) self.audioStep = base.audio3d.loadSfx("assets/audio/step.ogg") self.audioStep.setLoop(True) base.audio3d.attachSoundToObject(self.audioStep, self.character) self.audioHit = base.audio3d.loadSfx("assets/audio/hit.ogg") self.audioHit.setLoop(False) base.audio3d.attachSoundToObject(self.audioStep, self.character) def setEnemy(self, enemyColName): self.enemyColName = enemyColName inEvent = "{}-into-{}".format(enemyColName, self.collisionNodeName) base.pusher.addInPattern(inEvent) self.accept(inEvent, self.setCanBeHit, [True]) outEvent = "{}-out-{}".format(enemyColName, self.collisionNodeName) base.pusher.addOutPattern(outEvent) self.accept(outEvent, self.setCanBeHit, [False]) def setCanBeHit(self, yes, collission): eventName = "hitEnemy{}".format(self.collisionNodeName) if yes: self.accept(eventName, self.gotHit) else: self.ignore(eventName) self.canBeHit = yes def gotHit(self): if not self.canBeHit or self.isDefending: return self.bloodsplat = ParticleEffect() self.bloodsplat.loadConfig("assets/fx/BloodSplat.ptf") floater = self.character.attachNewNode("particleFloater") if self.character.getH() == 90: floater.setPos(-1, 0, 1) if self.character.getH() == -90: floater.setPos(1, 0, 1) self.bloodsplat.start(parent=floater, renderParent=render) taskMgr.doMethodLater(0.5, self.bloodsplat.cleanup, "stop Particle", extraArgs=[]) self.health -= 10 base.messenger.send("lifeChanged", [self.charId, self.health]) if self.health <= 0: self.gotDefeated = True self.request("Defeated") base.messenger.send("gameOver", [self.charId]) else: self.request("Hit") def attackAnimationPlaying(self): actionAnimations = ["Punch_l", "Punch_r", "Kick_l", "Kick_r", "Hit"] if self.character.getCurrentAnim() in actionAnimations: return True def start(self, startPos): self.character.setPos(startPos) self.character.show() self.request("Idle") self.canBeHit = False self.isDefending = False self.gotDefeated = False self.health = 100 taskMgr.add(self.moveTask, "move task {}".format(self.charId)) def stop(self): taskMgr.remove("move task {}".format(self.charId)) self.ignoreAll() base.audio3d.detachSound(self.audioStep) base.audio3d.detachSound(self.audioHit) self.character.cleanup() self.character.removeNode() def moveTask(self, task): if self.gotDefeated: base.messenger.send("GameOver") return task.done if self.attackAnimationPlaying(): return task.cont speed = 0.0 isDown = base.mouseWatcherNode.isButtonDown if isDown(self.defendButton): if self.state != "Defend": self.isDefending = True self.request("Defend") return task.cont self.isDefending = False # Check for attack keys isAction = False if isDown(self.punchLButton): isAction = True self.request("Punch_l") elif isDown(self.punchRButton): isAction = True self.request("Punch_r") elif isDown(self.kickLButton): isAction = True self.request("Kick_l") elif isDown(self.kickRButton): isAction = True self.request("Kick_r") if isAction: base.messenger.send("hitEnemy{}".format(self.enemyColName)) return task.cont if isDown(self.leftButton): speed += self.walkSpeed if isDown(self.rightButton): speed -= self.walkSpeed yDelta = speed * globalClock.getDt() self.character.setY(self.character, yDelta) if speed != 0.0 and self.state != "Walk" and self.state != "Walk_back": if speed < 0: self.request("Walk") else: self.request("Walk_back") elif speed == 0.0 and self.state != "Idle": self.request("Idle") return task.cont def enterIdle(self): self.character.loop("Idle") def exitIdle(self): self.character.stop() def enterWalk(self): self.character.loop("Walk") if self.audioStep.status() != AudioSound.PLAYING: self.audioStep.play() def exitWalk(self): self.character.stop() if self.audioStep.status() == AudioSound.PLAYING: self.audioStep.stop() def enterWalk_back(self): self.character.loop("Walk_back") if self.audioStep.status() != AudioSound.PLAYING: self.audioStep.play() def exitWalk_back(self): self.character.stop() if self.audioStep.status() == AudioSound.PLAYING: self.audioStep.stop() def enterPunch_l(self): self.character.play("Punch_l") def exitPunch_l(self): self.character.stop() def enterPunch_r(self): self.character.play("Punch_r") def exitPunch_r(self): self.character.stop() def enterKick_l(self): self.character.play("Kick_l") def exitKick_l(self): self.character.stop() def enterKick_r(self): self.character.play("Kick_r") def exitKick_r(self): self.character.stop() def enterDefend(self): self.character.play("Defend") def exitDefend(self): self.character.stop() def enterHit(self): self.character.play("Hit") self.audioHit.play() def exitHit(self): self.character.stop() def enterDefeated(self): self.character.play("Defeated") def exitDefeated(self): self.character.stop()
class Boss2(): def __init__(self, common, pos=(0,0,0)): self.common = common common['monsterList'].append(self) id=len(common['monsterList'])-1 self.id=id self.stats={"speed":9, "hp":400, "armor":0 } self.totalSpeed=1 self.sparkSum=0 self.lastMagmaDmg=0 self.DOT=0 self.arrows=set() self.isSolid=True #self.bullet.hide() self.node=render.attachNewNode("monster") self.boss=Actor("models/boss2/boss2.bam", {"die":"models/boss2/boss2_die.bam", "attack1":"models/boss2/boss2_attack1.bam", "hit":"models/boss2/boss2_hit.bam", "idle":"models/boss2/boss2_idle.bam", "attack2":"models/boss2/boss2_attack2.bam", "fly":"models/boss2/boss2_flyforward.bam"}) self.boss.setBlend(frameBlend = True) self.boss.setPlayRate(2, "attack1") self.boss.reparentTo(self.node) self.boss.setScale(0.01,0.01,0.01) self.boss.setP(10) self.boss.setH(180) self.boss.setBin("opaque", 10) #tex = loader.loadTexture('models/boss1-monster/creature1Normal.png') #boss1.setTexture(tex, 1) #self.boss.setColor(0.2, 0.0, 0.9, 0.5) self.node.setPos(render,pos) self.rootBone=self.boss.exposeJoint(None, 'modelRoot', 'Hips') self.ambientLight=AmbientLight('ambientLight') self.ambientLight.setColor(VBase4(.7, .7, .7, 1)) self.ambientLightNode = render.attachNewNode(self.ambientLight) self.boss.setLight(self.ambientLightNode) self.maxHP=self.stats['hp'] self.healthBar=DirectFrame(frameSize=(37, 0, 0, 6), frameColor=(0, 0, 1, 1), frameTexture='icon/glass4.png', parent=pixel2d) self.healthBar.setTransparency(TransparencyAttrib.MDual) self.healthBar.setScale(10,1, 1) #self.healthBar.reparentTo(self.node) wp = base.win.getProperties() winX = wp.getXSize() winY = wp.getYSize() self.healthBar.setPos(71-256+winX/2,0,34-winY) self.healthBar.hide() self.waitfor = 0 # time to wait before to pursue the player self.soundID=self.common['soundPool'].get_id() self.common['soundPool'].set_target(self.soundID, self.node) self.traverser=CollisionTraverser("BossTrav"+str(id)) #self.traverser.showCollisions(render) self.queue = CollisionHandlerQueue() #radar collision ray # self.radar=self.node.attachNewNode(CollisionNode('radarRay')) # self.radar.node().addSolid(CollisionRay(0, 0, 1, 0, 90, 0)) # self.radar.node().setIntoCollideMask(BitMask32.allOff()) # self.radar.node().setFromCollideMask(BitMask32.bit(2)) # self.radar.setTag("radar", str(id)) # self.radar.show() # self.traverser.addCollider(self.radar, self.queue) self.coll_body=self.node.attachNewNode(CollisionNode('bossmonsterCollisionNode')) self.coll_body.node().addSolid(CollisionCapsule(0, 0, 0.3, 0, 0.2, 1.5, 0.3)) self.coll_body.setTag("id", str(id)) self.coll_body.node().setIntoCollideMask(BitMask32.bit(3)) #self.coll_body.show() #self.right_foot = self.boss.exposeJoint(None, "modelRoot", "R_foot") #self.coll_attack2=self.node.attachNewNode(CollisionNode('bossattack2CollisionNode')) #self.coll_attack2.node().addSolid(CollisionSphere(0, 0, 0, 0.2)) ##self.coll_attack2.setTag("id", str(id)) #self.coll_attack2.node().setIntoCollideMask(BitMask32.bit(3)) #self.coll_attack2.show() #other monster blocking self.coll_quad=loader.loadModel("models/plane") self.coll_quad.reparentTo(self.node) self.state="IDLE" self.previous_state=self.state #self.PC = self.common['PC'] #taskMgr.doMethodLater(.6, self.runCollisions,'collFor'+str(self.id)) #taskMgr.doMethodLater(1.0, self.damageOverTime,'DOTfor'+str(self.id)) self.boss.setTransparency(True) self.visible = True self.bullet=loader.loadModel("models/ball.egg") self.bullet.setScale(0.5) self.bullet.reparentTo(render) self.bullet.setPos(0,0,-5) mat = Material() mat.setShininess(0) mat.setAmbient((0.7, 0.1, 0, 0.8)) self.ambientLightBullet=AmbientLight('ambientLight') self.ambientLightBullet.setColor(VBase4(.5, .5, .5, 1)) self.ambientLightBulletNode = render.attachNewNode(self.ambientLightBullet) self.bullet.setLight(self.ambientLightBulletNode) self.bullet.setMaterial(mat) self.bullet.setBin("opaque", 10) self.bullet.hide() self.bullet_radius = 0 # Our model is rotated of 180°, thus we need to move the collision sphere to the opposite directions #self.bullet.setPos(-1*x, -1*y, z) self.fog = Fog("Fog") self.fog.setColor(0.5, 0.5, 0.5) self.fog.setExpDensity(0.1) # self.node.setColorScale(1,1,1,1) # self.node.clearFog() #Sequence(Wait(2),LerpColorScaleInterval(self.node, 2.0, VBase4(1,1,1,0.1))).start() #Sequence(Wait(6),LerpColorScaleInterval(self.node, 2.0, VBase4(1,1,1,1))).start() #Sequence(Wait(10),LerpColorScaleInterval(self.node, 2.0, VBase4(1,1,1,0.1))).start() taskMgr.add(self.runAI, "BossAIfor"+str(id)) def toggleVisibility(self): if (self.visible): #Sequence(Wait(0),LerpColorScaleInterval(self.node, 2.0, VBase4(1,1,1,0.1))).start() self.node.setFog(self.fog) self.node.setColorScale(1,1,1,0.1) else: #Sequence(Wait(0),LerpColorScaleInterval(self.node, 2.0, VBase4(1,1,1,1))).start() self.node.setColorScale(1,1,1,1) self.node.clearFog() self.visible = not self.visible def runAI(self, task): #print(self.stats['hp']) #(x,y,z) = self.right_foot.getPos() ## Our model is rotated of 180°, thus we need to move the collision sphere to the opposite directions #self.coll_attack2.setPos(-1*x, -1*y, z) target = self.common['PC'].node if self.state=="DIE": if(self.boss.getCurrentAnim()!="die"): self.common['soundPool'].attachAndPlay(self.boss, "argh-woman.ogg") self.boss.play("die") Sequence(Wait(0),LerpPosInterval(self.node, 0.4, VBase3(self.node.getX(),self.node.getY(),self.node.getZ()-1))).start() #Check if we have finished the animation if (self.boss.getCurrentFrame() < self.boss.getNumFrames()-1): return task.again else: id = len(self.common["random-objects"]) object = RandomObject(id, self.common, self.node, render, moneyamount=5) self.common["random-objects"].append(object) self.coll_body.node().setIntoCollideMask(BitMask32.allOff()) self.coll_quad.removeNode() Interactive(self.common, data.items['key'], self.node.getPos(render)) Sequence(Wait(1.0),LerpPosInterval(self.node, 2.0, VBase3(self.node.getX(),self.node.getY(),self.node.getZ()-5)),Func(self.destroy)).start() return task.done if (self.state == "HIT") and (self.previous_state == "IDLE"): if(self.boss.getCurrentAnim()!="hit"): self.boss.play("hit") self.common['soundPool'].attachAndPlay(self.boss, "argh-woman.ogg") if (self.boss.getCurrentFrame() == self.boss.getNumFrames()-1): self.state = self.previous_state return task.again #Check if the player is colliding with the bullet if (self.bullet_radius > 0) and (self.bullet.getDistance(target)<1): self.boss.attackdamage = 10 * self.bullet_radius self.common['PC'].hit(self.boss.attackdamage) self.bullet_radius = 0 if self.state == "IDLE": if(self.boss.getCurrentAnim()!="idle"): self.boss.play("idle") if (self.waitfor > 0): self.waitfor -= 1 return task.again if self.common['PC'].HP <= 0 or self.node.getDistance(target)>25: self.state="IDLE" self.common['spawner'].monster_limit = 4 else: self.common['spawner'].monster_limit = 2 if (random.random() < 0.003) and (self.state == "PURSUING"): self.state="IDLE" self.waitfor = random.randrange(200) return task.again if (random.random() < 0.008) or (self.state == "ATTACKING"): self.state="ATTACKING" if(self.boss.getCurrentAnim()!="attack2") and (self.boss.getCurrentAnim()!="attack1"): if (random.random() < 0.5): self.boss.play("attack2") self.common['soundPool'].attachAndPlay(self.boss, "beam-sound.wav", volume=3) self.boss.attackdamage = 0 else: self.boss.play("attack1") self.boss.attackdamage = 0 (x,y,z)=self.node.getPos() self.bullet.setPos(x,y,z+0.75) self.bullet.show() self.bullet_radius = random.randrange(2, 4) Sequence(Wait(0),LerpScaleInterval(self.bullet, 1.0, VBase3(self.bullet_radius,self.bullet_radius,self.bullet_radius), VBase3(0.5,0.5,0.5))).start() Sequence(Wait(0),LerpPosInterval(self.bullet, 4.0, VBase3(self.common['PC'].node.getPos()))).start() #The sound must be played only when the boss hit the floor (it's in the mid of the animation) self.common['soundPool'].attachAndPlay(self.boss, "energy1.wav", volume=3) # Get position of the joint respect to render (i.e. absolute position) #(x,y,_) = self.left_thumb.getPos(render) #vfx(None, texture='vfx/dust.png',scale=1, Z=0, depthTest=True, depthWrite=True,pos=(x,y,0)).start(0.016) # Inflict damage only when we played half of the animation (it should be the moment when the attack hits the player) # This function could be called multiple times even if we are at the same frame (probably depends on the frame rate of the animation) # Thus, we should also check if we are seeing the same previous hit (based on the last frame, it must not be the same) elif (self.boss.getCurrentFrame() == int(self.boss.getNumFrames()/2)) and (self.boss.getCurrentFrame() != self.boss.lastFrame): if (self.boss.getCurrentAnim() == "attack2"): self.toggleVisibility() if (self.visible == False): self.stats['hp'] += 10 self.healthBar.setScale(10*self.stats['hp']/self.maxHP,1, 1) elif (self.boss.getCurrentFrame() == self.boss.getNumFrames()-1): #When the animation is finished return to pursuing the player self.state = "PURSUING" self.boss.lastFrame = self.boss.getCurrentFrame() return task.again self.state = "PURSUING" self.node.headsUp(target) #Look at the player if(self.boss.getCurrentAnim()!="fly"): self.boss.loop("fly") if self.node.getDistance(target)>5: self.node.setY(self.node, self.totalSpeed*globalClock.getDt()) else: self.node.setX(self.node, self.totalSpeed*globalClock.getDt()) self.previous_state = self.state return task.again def doDamage(self, damage, igoreArmor=False): if self.state=="DIE": return if not igoreArmor: damage-=self.stats['armor'] if damage<1: damage=1 #print damage self.stats['hp']-=damage self.healthBar.show() self.healthBar.setScale(10*self.stats['hp']/self.maxHP,1, 1) if self.stats['hp']<1: self.healthBar.hide() def die(self, soundname): #self.common['soundPool'].play(self.soundID, self.sound_names["hit"]) #self.common['soundPool'].play(self.soundID, soundname) self.state="DIE" def onHit(self, damage, sound="hit", weapon=None): if self.state=="DIE" or self.visible == False: return self.state="HIT" self.doDamage(damage) if self.stats['hp']<1: self.die("die") def damageOverTime(self, task): if self.state=="DIE": return task.done if self.DOT>0: self.doDamage(self.DOT) self.DOT=int((self.DOT*0.9)-1.0) vfx(self.node, texture='vfx/blood_dark.png',scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) return task.again def destroy(self): self.arrows=None if self.boss: self.boss.cleanup() self.boss.removeNode() if taskMgr.hasTaskNamed("BossAIfor"+str(self.id)): taskMgr.remove("BossAIfor"+str(self.id)) # if taskMgr.hasTaskNamed('collFor'+str(self.id)): # taskMgr.remove('collFor'+str(self.id)) if taskMgr.hasTaskNamed('DOTfor'+str(self.id)): taskMgr.remove('DOTfor'+str(self.id)) if taskMgr.hasTaskNamed('AIUpdate'): taskMgr.remove('AIUpdate') if self.node: self.node.removeNode() self.common['monsterList'][self.id]=None self.traverser=None self.queue=None #self.common['traverser'].removeCollider(self.coll_sphere) self.coll_body.removeNode() self.coll_quad.removeNode() self.healthBar.removeNode() self.ambientLightNode.removeNode() self.ambientLightBulletNode.removeNode() self.ambientLightBulletNode.removeNode()
class PartyCog(FSM): notify = directNotify.newCategory('PartyCog') HpTextGenerator = TextNode('HpTextGenerator') hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed = 3, bounceHeight = 1, rotateSpeed = 1, heightShift = 1, xMoveSpeed = 0, xMoveDistance = 0, bounceOffset = 0): self.id = id FSM.__init__(self, 'PartyCogFSM-%d' % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request('Down') return def load(self): self.root = NodePath('PartyCog-%d' % self.id) self.root.reparentTo(self.parentNode) path = 'phase_13/models/parties/cogPinata_' self.actor = Actor(path + 'actor', {'idle': path + 'idle_anim', 'down': path + 'down_anim', 'up': path + 'up_anim', 'bodyHitBack': path + 'bodyHitBack_anim', 'bodyHitFront': path + 'bodyHitFront_anim', 'headHitBack': path + 'headHitBack_anim', 'headHitFront': path + 'headHitFront_anim'}) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode('temphead') self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound('AA_wholepie_only.ogg') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg') self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole') self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin('ground', 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request('Off') self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound return def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id) def exitActive(self): taskMgr.remove('PartyCog.update-%d' % self.id) taskMgr.remove('PartyCog.bounceTask-%d' % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3(self.root.getH(), 0.0, 0.0), blendType='easeInOut') self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == 'Off': downAnimControl = self.actor.getAnimControl('down') self.actor.pose('down', downAnimControl.getNumFrames() - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence(LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel(SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'down', loop=0)), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence(LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel(SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'up', loop=0)), Func(self.actor.loop, 'idle'), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def filterDown(self, request, args): if request == 'Down': return None else: return self.defaultFilter(request, args) return None def setEndPoints(self, start, end, amplitude = 1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin(t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id) def bounce(self, task): self.root.setZ(math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot = False, direction = 1.0): if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug('respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() return def __showSplat(self, position, direction, hot = False): if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = 'HitFront' else: facing = 'HitBack' else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) if self.currentFacing > 0.0: facing = 'HitBack' else: facing = 'HitFront' if hot: targetscale = 0.75 part = 'head' else: targetscale = 0.5 part = 'body' def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence(ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, 'idle')) self.hitInterval.start() self.kaboomTrack = Parallel(SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence(Func(self.splat.showThrough), Parallel(Sequence(LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Wait(0.175)), Sequence(Wait(0.1), LerpFunc(setSplatAlpha, duration=1.0, fromData=1.0, toData=0.0, blendType='easeOut'))), Func(self.splat.cleanup), Func(self.splat.removeNode))) self.kaboomTrack.start() return def showHitScore(self, number, scale = 1): if number <= 0: return if self.hpText: self.hideHitScore() self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText('+' + str(number)) self.HpTextGenerator.clearShadow() self.HpTextGenerator.setAlign(TextNode.ACenter) r = 1 g = 1 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) self.hpText.setBillboardPointEye() self.hpText.setBin('fixed', 100) self.hpText.setPos(self.root, 0, 0, self.height / 2) seq = Sequence(self.hpText.posInterval(0.25, Point3(self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), blendType='easeOut'), Wait(0.25), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.__hideHitScore)) seq.start() def hideHitScore(self): if self.hpText: taskMgr.remove('PartyCogHpText' + str(self.id)) self.hpText.removeNode() self.hpText = None return def getHeadLocation(self): self.actor.getJoints(jointName='head')[0].getNetTransform(self.temp_transform) self.head_locator.setMat(self.temp_transform) return self.head_locator.getZ(self.root)
class Toon(Avatar.Avatar, ToonHead, ToonDNA.ToonDNA): def __init__(self, cr, mat = 0): self.cr = cr try: self.Toon_initialized return except: self.Toon_initialized = 1 Avatar.Avatar.__init__(self, mat) ToonDNA.ToonDNA.__init__(self) ToonHead.__init__(self, cr) self.forwardSpeed = 0.0 self.rotateSpeed = 0.0 self.avatarType = CIGlobals.Toon self.track = None self.standWalkRunReverse = None self.playingAnim = None self.tag = None self.money = 0 self.lookAtTrack = None self.portal1 = None self.portal2 = None self.gunAttached = False self.gun = None self.tokenIcon = None self.tokenIconIval = None self.backpack = None self.forcedTorsoAnim = None self.fallSfx = base.audio3d.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.mp3') base.audio3d.attachSoundToObject(self.fallSfx, self) self.eyes = loader.loadTexture('phase_3/maps/eyes.jpg', 'phase_3/maps/eyes_a.rgb') self.myTaskId = random.uniform(0, 1231231232132131231232L) self.closedEyes = loader.loadTexture('phase_3/maps/eyesClosed.jpg', 'phase_3/maps/eyesClosed_a.rgb') self.soundChatBubble = loader.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.mp3') self.shadowCaster = None self.chatSoundDict = {} self.animFSM = ClassicFSM('Toon', [State('off', self.enterOff, self.exitOff), State('neutral', self.enterNeutral, self.exitNeutral), State('swim', self.enterSwim, self.exitSwim), State('walk', self.enterWalk, self.exitWalk), State('run', self.enterRun, self.exitRun), State('openBook', self.enterOpenBook, self.exitOpenBook), State('readBook', self.enterReadBook, self.exitReadBook), State('closeBook', self.enterCloseBook, self.exitCloseBook), State('teleportOut', self.enterTeleportOut, self.exitTeleportOut), State('teleportIn', self.enterTeleportIn, self.exitTeleportIn), State('died', self.enterDied, self.exitDied), State('fallFWD', self.enterFallFWD, self.exitFallFWD), State('fallBCK', self.enterFallBCK, self.exitFallBCK), State('jump', self.enterJump, self.exitJump), State('leap', self.enterLeap, self.exitLeap), State('laugh', self.enterLaugh, self.exitLaugh), State('happy', self.enterHappyJump, self.exitHappyJump), State('shrug', self.enterShrug, self.exitShrug), State('hdance', self.enterHDance, self.exitHDance), State('wave', self.enterWave, self.exitWave), State('scientistEmcee', self.enterScientistEmcee, self.exitScientistEmcee), State('scientistWork', self.enterScientistWork, self.exitScientistWork), State('scientistGame', self.enterScientistGame, self.exitScientistGame), State('scientistJealous', self.enterScientistJealous, self.exitScientistJealous), State('cringe', self.enterCringe, self.exitCringe), State('conked', self.enterConked, self.exitConked), State('win', self.enterWin, self.exitWin), State('walkBack', self.enterWalkBack, self.exitWalkBack), State('deadNeutral', self.enterDeadNeutral, self.exitDeadNeutral), State('deadWalk', self.enterDeadWalk, self.exitDeadWalk), State('squish', self.enterSquish, self.exitSquish), State('Happy', self.enterHappy, self.exitHappy), State('Sad', self.enterSad, self.exitSad)], 'off', 'off') animStateList = self.animFSM.getStates() self.animFSM.enterInitialState() if not hasattr(base, 'localAvatar') or not base.localAvatar == self: Avatar.Avatar.initializeBodyCollisions(self, self.avatarType, 3, 1) return def enterHappy(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = None self.standWalkRunReverse = (('neutral', 1.0), ('walk', 1.0), ('run', 1.0), ('walk', -1.0)) self.setSpeed(self.forwardSpeed, self.rotateSpeed) return def exitHappy(self): self.standWalkRunReverse = None self.stop() return def enterSad(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'sad' self.standWalkRunReverse = (('dneutral', 1.0), ('dwalk', 1.2), ('dwalk', 1.2), ('dwalk', -1.0)) self.setSpeed(0, 0) def exitSad(self): self.standWalkRunReverse = None self.stop() return def setSpeed(self, forwardSpeed, rotateSpeed): self.forwardSpeed = forwardSpeed self.rotateSpeed = rotateSpeed action = None if self.standWalkRunReverse != None: if forwardSpeed >= CIGlobals.RunCutOff: action = CIGlobals.RUN_INDEX elif forwardSpeed > CIGlobals.WalkCutOff: action = CIGlobals.WALK_INDEX elif forwardSpeed < -CIGlobals.WalkCutOff: action = CIGlobals.REVERSE_INDEX elif rotateSpeed != 0.0: action = CIGlobals.WALK_INDEX else: action = CIGlobals.STAND_INDEX anim, rate = self.standWalkRunReverse[action] if anim != self.playingAnim: self.playingAnim = anim self.stop() self.loop(anim) self.setPlayRate(rate, anim) return action def enterSquish(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'squish' sound = loader.loadSfx('phase_9/audio/sfx/toon_decompress.mp3') lerpTime = 0.1 node = self.getGeomNode().getChild(0) origScale = node.getScale() if hasattr(self, 'uniqueName'): name = self.uniqueName('getSquished') else: name = 'getSquished' self.track = Sequence(LerpScaleInterval(node, lerpTime, VBase3(2, 2, 0.025), blendType='easeInOut'), Wait(1.0), Parallel(Sequence(Wait(0.4), LerpScaleInterval(node, lerpTime, VBase3(1.4, 1.4, 1.4), blendType='easeInOut'), LerpScaleInterval(node, lerpTime / 2.0, VBase3(0.8, 0.8, 0.8), blendType='easeInOut'), LerpScaleInterval(node, lerpTime / 3.0, origScale, blendType='easeInOut')), ActorInterval(self, 'happy', startTime=0.2), SoundInterval(sound)), name=name) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.squishDone, [callback, extraArgs]) self.track.delayDelete = DelayDelete.DelayDelete(self, name) self.track.start(ts) def squishDone(self, callback = None, extraArgs = []): self.__doCallback(callback, extraArgs) def exitSquish(self): if self.track: self.ignore(self.track.getName()) DelayDelete.cleanupDelayDeletes(self.track) self.track.finish() self.track = None self.playingAnim = 'neutral' return def enterDeadNeutral(self, ts = 0, callback = None, extraArgs = []): self.loop('dneutral') def exitDeadNeutral(self): self.stop() def enterDeadWalk(self, ts = 0, callback = None, extraArgs = []): self.loop('dwalk') def exitDeadWalk(self): self.stop() def setBackpack(self, pack): self.backpack = pack def getGhost(self): return 0 def updateChatSoundDict(self): self.chatSoundDict['exclaim'] = base.audio3d.loadSfx(self.getToonAnimalNoise('exclaim')) self.chatSoundDict['question'] = base.audio3d.loadSfx(self.getToonAnimalNoise('question')) self.chatSoundDict['short'] = base.audio3d.loadSfx(self.getToonAnimalNoise('short')) self.chatSoundDict['medium'] = base.audio3d.loadSfx(self.getToonAnimalNoise('med')) self.chatSoundDict['long'] = base.audio3d.loadSfx(self.getToonAnimalNoise('long')) self.chatSoundDict['howl'] = base.audio3d.loadSfx(self.getToonAnimalNoise('howl')) base.audio3d.attachSoundToObject(self.chatSoundDict['exclaim'], self.getPart('head')) base.audio3d.attachSoundToObject(self.chatSoundDict['question'], self.getPart('head')) base.audio3d.attachSoundToObject(self.chatSoundDict['short'], self.getPart('head')) base.audio3d.attachSoundToObject(self.chatSoundDict['medium'], self.getPart('head')) base.audio3d.attachSoundToObject(self.chatSoundDict['long'], self.getPart('head')) base.audio3d.attachSoundToObject(self.chatSoundDict['howl'], self.getPart('head')) def ghostOn(self): self.getGeomNode().hide() self.getNameTag().hide() self.getShadow().hide() if self.tokenIcon: self.tokenIcon.hide() self.stashBodyCollisions() def ghostOff(self): self.unstashBodyCollisions() if self.tokenIcon: self.tokenIcon.show() self.getShadow().show() self.getNameTag().show() self.getGeomNode().show() def attachGun(self, gunName): self.detachGun() if gunName == 'pistol': self.gun = loader.loadModel('phase_4/models/props/water-gun.bam') self.gun.reparentTo(self.find('**/def_joint_right_hold')) self.gun.setPos(Point3(0.28, 0.1, 0.08)) self.gun.setHpr(VBase3(85.6, -4.44, 94.43)) self.gunAttached = True elif gunName == 'shotgun': self.gun = loader.loadModel('phase_4/models/props/shotgun.egg') self.gun.setScale(0.75) self.gun.reparentTo(self.find('**/def_joint_right_hold')) self.gun.setPos(Point3(-0.5, -0.2, 0.19)) self.gun.setHpr(Vec3(350, 272.05, 0)) color = random.choice([VBase4(1, 0.25, 0.25, 1), VBase4(0.25, 1, 0.25, 1), VBase4(0.25, 0.25, 1, 1)]) self.gun.setColorScale(color) self.gunAttached = True def detachGun(self): if self.gun and self.gunAttached: self.gun.removeNode() self.gun = None self.gunAttached = False return def stopAnimations(self): if hasattr(self, 'animFSM'): if not self.animFSM.isInternalStateInFlux(): self.animFSM.request('off') else: notify.warning('animFSM in flux, state=%s, not requesting off' % self.animFSM.getCurrentState().getName()) else: notify.warning('animFSM has been deleted') if self.track != None: self.track.finish() DelayDelete.cleanupDelayDeletes(self.track) self.track = None return def disable(self): try: self.Toon_disabled except: self.Toon_disabled = 1 self.backpack = None self.stopAnimations() self.removeAdminToken() ToonHead.delete(self) self.deleteCurrentToon() self.chatSoundDict = {} return def delete(self): try: self.Toon_deleted except: self.Toon_deleted = 1 del self.animFSM self.forwardSpeed = None self.chatSoundDict = None self.rotateSpeed = None self.avatarType = None self.track = None self.standWalkRunReverse = None self.currentAnim = None self.toon_head = None self.forcedTorsoAnim = None self.toon_torso = None self.toon_legs = None self.gender = None self.headtype = None self.head = None self.legtype = None self.torsotype = None self.hr = None self.hg = None self.hb = None self.tr = None self.tg = None self.tb = None self.lr = None self.lg = None self.lb = None self.shir = None self.shig = None self.shib = None self.shor = None self.shog = None self.shob = None self.shirt = None self.sleeve = None self.short = None self.tag = None self.money = None self.lookAtTrack = None self.portal1 = None self.portal2 = None self.backpack = None self.fallSfx = None self.eyes = None self.myTaskId = None self.closedEyes = None self.soundChatBubble = None self.lastAction = None self.lastState = None self.playingAnim = None Avatar.Avatar.delete(self) return def initCollisions(self): self.collNodePath.setCollideMask(BitMask32(0)) self.collNodePath.node().setFromCollideMask(CIGlobals.WallBitmask) pusher = CollisionHandlerPusher() pusher.setInPattern('%in') pusher.addCollider(self.collNodePath, self) base.cTrav.addCollider(self.collNodePath, pusher) def deleteCurrentToon(self): if self.shadowCaster: self.shadowCaster.clear() self.shadowCaster = None try: self.stopLookAround() self.stopBlink() except: pass self.pupils = [] if 'head' in self._Actor__commonBundleHandles: del self._Actor__commonBundleHandles['head'] if 'torso' in self._Actor__commonBundleHandles: del self._Actor__commonBundleHandles['torso'] if 'legs' in self._Actor__commonBundleHandles: del self._Actor__commonBundleHandles['legs'] self.deleteShadow() self.removePart('head') self.removePart('torso') self.removePart('legs') self.detachGun() return def enterGagShop(self): DirectLabel(text='ENTERED GAG SHOP', relief=None, text_scale=0.08) return def setAdminToken(self, tokenId): tokens = {0: 500} if tokenId in tokens.keys(): icons = loader.loadModel('phase_3/models/props/gm_icons.bam') self.tokenIcon = icons.find('**/access_level_%s' % tokens[tokenId]) self.tokenIcon.reparentTo(self) x = self.getNameTag().getX() y = self.getNameTag().getY() z = self.getNameTag().getZ() self.tokenIcon.setPos(Vec3(x, y, z) + (0, 0, 0.5)) self.tokenIcon.setScale(0.4) self.tokenIconIval = Sequence(LerpHprInterval(self.tokenIcon, duration=3.0, hpr=Vec3(360, 0, 0), startHpr=Vec3(0, 0, 0))) self.tokenIconIval.loop() icons.removeNode() def removeAdminToken(self): if self.tokenIcon != None and self.tokenIconIval != None: self.tokenIconIval.finish() self.tokenIcon.removeNode() self.tokenIconIval = None self.tokenIcon = None return def setChat(self, chatString): if not self.isThought(chatString): if not self.getGhost() or self.doId == base.localAvatar.doId: if 'ooo' in chatString.lower(): sfx = self.chatSoundDict['howl'] elif '!' in chatString.lower(): sfx = self.chatSoundDict['exclaim'] elif '?' in chatString.lower(): sfx = self.chatSoundDict['question'] elif len(chatString) <= 9: sfx = self.chatSoundDict['short'] elif 10 <= len(chatString) <= 19: sfx = self.chatSoundDict['medium'] elif len(chatString) >= 20: sfx = self.chatSoundDict['long'] sfx.play() Avatar.Avatar.setChat(self, chatString) def setName(self, nameString): Avatar.Avatar.setName(self, nameString, avatarType=self.avatarType) def setDNAStrand(self, dnaStrand, makeTag = 1): ToonDNA.ToonDNA.setDNAStrand(self, dnaStrand) self.deleteCurrentToon() self.generateToon(makeTag) def generateToon(self, makeTag = 1): self.generateLegs() self.generateTorso() self.generateHead() self.setToonColor() self.setClothes() self.setGloves() self.parentToonParts() self.rescaleToon() if makeTag: self.setupNameTag() Avatar.Avatar.initShadow(self) if self.cr.isShowingPlayerIds: self.showAvId() self.updateChatSoundDict() def attachTNT(self): self.pies.attachTNT() self.holdTNTAnim() def detachTNT(self): self.pies.detachTNT() self.animFSM.request(self.animFSM.getCurrentState().getName()) def holdTNTAnim(self): self.pose('toss', 22, partName='torso') def parentToonParts(self): self.attach('head', 'torso', 'def_head') self.attach('torso', 'legs', 'joint_hips') def unparentToonParts(self): self.getPart('head').reparentTo(self.getGeomNode()) self.getPart('torso').reparentTo(self.getGeomNode()) self.getPart('legs').reparentTo(self.getGeomNode()) def rescaleToon(self): animal = self.getAnimal() bodyScale = CIGlobals.toonBodyScales[animal] headScale = CIGlobals.toonHeadScales[animal][2] shoulderHeight = CIGlobals.legHeightDict[self.legs] * bodyScale + CIGlobals.torsoHeightDict[self.torso] * bodyScale height = shoulderHeight + CIGlobals.headHeightDict[self.head] * headScale bodyScale = CIGlobals.toonBodyScales[animal] self.setAvatarScale(bodyScale) self.setHeight(height) def setGloves(self): color = self.getGloveColor() gloves = self.find('**/hands') gloves.setColor(color) def setClothes(self): shirt, shirtcolor = self.getShirtStyle() short, shortcolor = self.getShortStyle() sleeve, sleevecolor = self.getSleeveStyle() torsot = self.findAllMatches('**/torso-top') torsob = self.findAllMatches('**/torso-bot') sleeves = self.findAllMatches('**/sleeves') torsot.setTexture(loader.loadTexture(shirt), 1) torsob.setTexture(loader.loadTexture(short), 1) sleeves.setTexture(loader.loadTexture(sleeve), 1) torsot.setColor(shirtcolor) sleeves.setColor(sleevecolor) torsob.setColor(shortcolor) def generateLegs(self): legtype = self.getLegs() self.loadModel('phase_3/models/char/tt_a_chr_' + legtype + '_shorts_legs_' + str(CIGlobals.getModelDetail(self.avatarType)) + '.bam', 'legs') self.loadAnims({'neutral': 'phase_3/models/char/tt_a_chr_' + legtype + '_shorts_legs_neutral.bam', 'run': 'phase_3/models/char/tt_a_chr_' + legtype + '_shorts_legs_run.bam', 'walk': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_walk.bam', 'pie': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_pie-throw.bam', 'fallb': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_slip-backward.bam', 'fallf': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_slip-forward.bam', 'lose': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_lose.bam', 'win': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_victory-dance.bam', 'squirt': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_water-gun.bam', 'zend': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_jump-zend.bam', 'tele': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_teleport.bam', 'book': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_book.bam', 'leap': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_leap_zhang.bam', 'jump': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_jump-zhang.bam', 'happy': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_jump.bam', 'shrug': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_shrug.bam', 'hdance': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_happy-dance.bam', 'wave': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_wave.bam', 'scemcee': 'phase_4/models/char/tt_a_chr_dgm_shorts_legs_scientistEmcee.bam', 'scwork': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_scientistWork.bam', 'scgame': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_scientistGame.bam', 'scjealous': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_scientistJealous.bam', 'swim': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_swim.bam', 'toss': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_toss.bam', 'cringe': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_cringe.bam', 'conked': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_conked.bam', 'catchneutral': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_gameneutral.bam', 'catchrun': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_gamerun.bam', 'hold-bottle': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_hold-bottle.bam', 'push-button': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_press-button.bam', 'happy-dance': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_happy-dance.bam', 'juggle': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_juggle.bam', 'shout': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_shout.bam', 'dneutral': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_sad-neutral.bam', 'dwalk': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_losewalk.bam', 'smooch': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_smooch.bam', 'conked': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_conked.bam', 'sound': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_shout.bam', 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_sprinkle-dust.bam', 'start-sit': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_intoSit.bam', 'sit': 'phase_4/models/char/char/tt_a_chr_' + legtype + '_shorts_legs_sit.bam'}, 'legs') self.findAllMatches('**/boots_long').stash() self.findAllMatches('**/boots_short').stash() self.findAllMatches('**/shoes').stash() def generateTorso(self): torsotype = self.getTorso() self.loadModel('phase_3/models/char/tt_a_chr_' + torsotype + '_torso_' + str(CIGlobals.getModelDetail(self.avatarType)) + '.bam', 'torso') self.loadAnims({'neutral': 'phase_3/models/char/tt_a_chr_' + torsotype + '_torso_neutral.bam', 'run': 'phase_3/models/char/tt_a_chr_' + torsotype + '_torso_run.bam', 'walk': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_walk.bam', 'pie': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_pie-throw.bam', 'fallb': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_slip-backward.bam', 'fallf': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_slip-forward.bam', 'lose': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_lose.bam', 'win': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_victory-dance.bam', 'squirt': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_water-gun.bam', 'zend': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_jump-zend.bam', 'tele': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_teleport.bam', 'book': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_book.bam', 'leap': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_leap_zhang.bam', 'jump': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_jump-zhang.bam', 'happy': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_jump.bam', 'shrug': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_shrug.bam', 'hdance': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_happy-dance.bam', 'wave': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_wave.bam', 'scemcee': 'phase_4/models/char/tt_a_chr_dgm_shorts_torso_scientistEmcee.bam', 'scwork': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_scientistWork.bam', 'scgame': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_scientistGame.bam', 'scjealous': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_scientistJealous.bam', 'swim': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_swim.bam', 'toss': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_toss.bam', 'cringe': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_cringe.bam', 'conked': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_conked.bam', 'catchneutral': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_gameneutral.bam', 'catchrun': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_gamerun.bam', 'hold-bottle': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_hold-bottle.bam', 'push-button': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_press-button.bam', 'happy-dance': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_happy-dance.bam', 'juggle': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_juggle.bam', 'shout': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_shout.bam', 'dneutral': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_sad-neutral.bam', 'dwalk': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_losewalk.bam', 'smooch': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_smooch.bam', 'conked': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_conked.bam', 'sound': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_shout.bam', 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_sprinkle-dust.bam', 'start-sit': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_intoSit.bam', 'sit': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_sit.bam'}, 'torso') def generateHead(self, pat = 0): gender = self.getGender() head = self.getAnimal() headtype = self.getHead() ToonHead.generateHead(self, gender, head, headtype) def setToonColor(self): self.setHeadColor() self.setTorsoColor() self.setLegColor() def setLegColor(self): legcolor = self.getLegColor() self.findAllMatches('**/legs').setColor(legcolor) self.findAllMatches('**/feet').setColor(legcolor) def setTorsoColor(self): torsocolor = self.getTorsoColor() self.findAllMatches('**/arms').setColor(torsocolor) self.findAllMatches('**/neck').setColor(torsocolor) self.findAllMatches('**/hands').setColor(1, 1, 1, 1) def setForcedTorsoAnim(self, string): self.forcedTorsoAnim = string self.loop(string, partName='torso') def clearForcedTorsoAnim(self): self.forcedTorsoAnim = None self.animFSM.request(self.animFSM.getCurrentState().getName()) return def enterOff(self, ts = 0, callback = None, extraArgs = []): self.currentAnim = None return def exitOff(self): pass def enterWin(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'win' self.sfx = base.audio3d.loadSfx('phase_3.5/audio/sfx/ENC_Win.mp3') self.sfx.setLoop(True) base.audio3d.attachSoundToObject(self.sfx, self) base.playSfx(self.sfx) self.loop('win') def exitWin(self): self.stop() self.sfx.stop() del self.sfx self.playingAnim = 'neutral' def enterShrug(self, ts = 0, callback = None, extraArgs = []): self.play('shrug') def exitShrug(self): self.exitGeneral() def enterHDance(self, ts = 0, callback = None, extraArgs = []): self.play('hdance') def exitHDance(self): self.exitGeneral() def enterScientistWork(self, ts = 0, callback = None, extraArgs = []): self.loop('scwork') def exitScientistWork(self): self.exitGeneral() def enterScientistEmcee(self, ts = 0, callback = None, extraArgs = []): self.loop('scemcee') def exitScientistEmcee(self): self.exitGeneral() def enterScientistGame(self, ts = 0, callback = None, extraArgs = []): self.loop('scgame') def exitScientistGame(self): self.exitGeneral() def enterScientistJealous(self, ts = 0, callback = None, extraArgs = []): self.loop('scjealous') def exitScientistJealous(self): self.exitGeneral() def enterWave(self, ts = 0, callback = None, extraArgs = []): self.play('wave') def exitWave(self): self.exitGeneral() def enterLaugh(self, ts = 0, callback = None, extraArgs = []): self.setPlayRate(5.0, 'neutral') self.loop('neutral') def exitLaugh(self): self.setPlayRate(1.0, 'neutral') self.stop() def enterNeutral(self, ts = 0, callback = None, extraArgs = []): if self.backpack: if self.backpack.getCurrentGag(): if self.backpack.getCurrentGag().getState() != GagState.LOADED: self.loop('neutral', partName='legs') if self.animal == 'dog': self.loop('neutral', partName='head') return if self.forcedTorsoAnim != None: self.loop(self.forcedTorsoAnim, partName='torso') self.loop('neutral', partName='legs') return else: self.loop('neutral') self.playingAnim = 'neutral' return def exitNeutral(self): self.exitGeneral() self.playingAnim = 'neutral' def exitGeneral(self): if self.backpack: if self.backpack.getCurrentGag(): if self.backpack.getCurrentGag().getState() != GagState.LOADED: self.stop(partName='legs') else: self.stop() else: self.stop() else: self.stop() def enterRun(self, ts = 0, callback = None, extraArgs = []): if self.backpack: if self.backpack.getCurrentGag(): if self.backpack.getCurrentGag().getState() != GagState.LOADED: self.loop('run', partName='legs') if self.animal == 'dog': self.loop('run', partName='head') return if self.forcedTorsoAnim != None: self.loop(self.forcedTorsoAnim, partName='torso') self.loop('run', partName='legs') return else: self.loop('run') return def exitRun(self): self.exitGeneral() def enterWalk(self, ts = 0, callback = None, extraArgs = []): if self.backpack: if self.backpack.getCurrentGag(): if self.backpack.getCurrentGag().getState() != GagState.LOADED: self.loop('walk', partName='legs') if self.animal == 'dog': self.loop('walk', partName='head') return if self.forcedTorsoAnim != None: self.loop(self.forcedTorsoAnim, partName='torso') self.loop('walk', partName='legs') return else: self.loop('walk') return def exitWalk(self): self.exitGeneral() def enterWalkBack(self, ts = 0, callback = None, extraArgs = []): self.setPlayRate(-1.0, 'walk') self.enterWalk() def exitWalkBack(self): self.exitWalk() self.setPlayRate(1.0, 'walk') def enterOpenBook(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'book' self.book1 = Actor('phase_3.5/models/props/book-mod.bam', {'chan': 'phase_3.5/models/props/book-chan.bam'}) self.book1.reparentTo(self.getPart('torso').find('**/def_joint_right_hold')) self.track = ActorInterval(self, 'book', startFrame=CIGlobals.OpenBookFromFrame, endFrame=CIGlobals.OpenBookToFrame, name=self.uniqueName('enterOpenBook')) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.__doCallback, [callback, extraArgs]) self.track.start(ts) self.book1.play('chan', fromFrame=CIGlobals.OpenBookFromFrame, toFrame=CIGlobals.OpenBookToFrame) def exitOpenBook(self): if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None if self.book1: self.book1.cleanup() self.book1 = None self.playingAnim = 'neutral' return def enterReadBook(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'book' self.book2 = Actor('phase_3.5/models/props/book-mod.bam', {'chan': 'phase_3.5/models/props/book-chan.bam'}) self.book2.reparentTo(self.getPart('torso').find('**/def_joint_right_hold')) self.pingpong('book', fromFrame=CIGlobals.ReadBookFromFrame, toFrame=CIGlobals.ReadBookToFrame) self.book2.pingpong('chan', fromFrame=CIGlobals.ReadBookFromFrame, toFrame=CIGlobals.ReadBookToFrame) def exitReadBook(self): if self.book2: self.book2.cleanup() self.book2 = None self.playingAnim = 'neutral' return def enterCloseBook(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'book' self.book3 = Actor('phase_3.5/models/props/book-mod.bam', {'chan': 'phase_3.5/models/props/book-chan.bam'}) self.book3.reparentTo(self.getPart('torso').find('**/def_joint_right_hold')) self.track = ActorInterval(self, 'book', startFrame=CIGlobals.CloseBookFromFrame, endFrame=CIGlobals.CloseBookToFrame, name=self.uniqueName('enterCloseBook')) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.__doCallback, [callback, extraArgs]) self.track.start(ts) self.book3.play('chan', fromFrame=CIGlobals.CloseBookFromFrame, toFrame=CIGlobals.CloseBookToFrame) def exitCloseBook(self): if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None if self.book3: self.book3.cleanup() self.book3 = None self.playingAnim = 'neutral' return def enterTeleportOut(self, ts = 0, callback = None, extraArgs = []): self.notify.info(str(self.doId) + '-' + str(self.zoneId) + ': enterTeleportOut') self.playingAnim = 'tele' self.portal1 = Actor('phase_3.5/models/props/portal-mod.bam', {'chan': 'phase_3.5/models/props/portal-chan.bam'}) self.portal1.play('chan') self.portal1.reparentTo(self.getPart('legs').find('**/def_joint_right_hold')) self.play('tele') if hasattr(self, 'uniqueName'): name = self.uniqueName('enterTeleportOut') else: name = 'enterTeleportOut' self.track = Sequence(Wait(0.4), Func(self.teleportOutSfx), Wait(1.3), Func(self.throwPortal), Wait(3.4), name=name) self.track.delayDelete = DelayDelete.DelayDelete(self, name) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getName(), self.teleportOutDone, [callback, extraArgs]) self.track.start(ts) def doPortalBins(self, portal): portal.setBin('shadow', 0) portal.setDepthWrite(0) portal.setDepthTest(0) def teleportOutDone(self, callback, requestStatus): self.notify.info(str(self.doId) + '-' + str(self.zoneId) + ': teleportOutDone') self.__doCallback(callback, requestStatus) self.exitTeleportOut() def teleportOutSfx(self): self.outSfx = base.audio3d.loadSfx('phase_3.5/audio/sfx/AV_teleport.mp3') base.audio3d.attachSoundToObject(self.outSfx, self.portal1) self.outSfx.play() def throwPortal(self): self.doPortalBins(self.portal1) self.portal1.reparentTo(self.getPart('legs').find('**/joint_nameTag')) self.portal1.setScale(CIGlobals.PortalScale) self.portal1.setY(6.5) self.portal1.setH(180) def exitTeleportOut(self): self.notify.info(str(self.doId) + '-' + str(self.zoneId) + ': exitTeleportOut') if self.track != None: self.ignore(self.track.getName()) self.track.finish() DelayDelete.cleanupDelayDeletes(self.track) self.track = None if self.portal1: self.portal1.cleanup() self.portal1 = None self.playingAnim = 'neutral' return def getTeleportInTrack(self, portal): self.doPortalBins(portal) holeTrack = Sequence() holeTrack.append(Func(portal.reparentTo, self)) pos = Point3(0, -2.4, 0) holeTrack.append(Func(portal.setPos, pos)) holeTrack.append(ActorInterval(portal, 'chan', startTime=3.4, endTime=3.1)) holeTrack.append(Wait(0.6)) holeTrack.append(ActorInterval(portal, 'chan', startTime=3.1, endTime=3.4)) def restorePortal(portal): portal.setPos(0, 0, 0) portal.detachNode() portal.clearBin() portal.clearDepthTest() portal.clearDepthWrite() holeTrack.append(Func(restorePortal, portal)) toonTrack = Sequence(Wait(0.3), Func(self.getGeomNode().show), Func(self.getNameTag().show), ActorInterval(self, 'happy', startTime=0.45)) if hasattr(self, 'uniqueName'): trackName = self.uniqueName('teleportIn') else: trackName = 'teleportIn' return Parallel(toonTrack, holeTrack, name=trackName) def enterTeleportIn(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'happy' self.portal2 = Actor('phase_3.5/models/props/portal-mod.bam', {'chan': 'phase_3.5/models/props/portal-chan.bam'}) self.show() self.getGeomNode().hide() self.getNameTag().hide() self.track = self.getTeleportInTrack(self.portal2) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getName(), self.teleportInDone, [callback, extraArgs]) self.track.delayDelete = DelayDelete.DelayDelete(self, self.track.getName()) self.track.start(ts) def teleportInDone(self, callback, extraArgs): self.__doCallback(callback, extraArgs) self.exitTeleportIn() def exitTeleportIn(self): if self.track != None: self.ignore(self.track.getName()) self.track.finish() DelayDelete.cleanupDelayDeletes(self.track) self.track = None if self.portal2: self.portal2.cleanup() self.portal2 = None if self.getGeomNode(): self.getGeomNode().show() if self.getNameTag(): self.getNameTag().show() self.playingAnim = 'neutral' return def enterFallFWD(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'fallf' self.play('fallf') Sequence(Wait(0.5), Func(self.fallSfx.play)).start() def exitFallFWD(self): self.exitGeneral() self.playingAnim = 'neutral' def enterFallBCK(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'fallb' self.play('fallb') Sequence(Wait(0.5), Func(self.fallSfx.play)).start() def exitFallBCK(self): self.playingAnim = 'neutral' self.exitGeneral() def enterHappyJump(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'happy' self.play('happy') def exitHappyJump(self): self.exitGeneral() self.playingAnim = 'neutral' def enterSwim(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'swim' self.loop('swim') self.getGeomNode().setP(-89.0) self.getGeomNode().setZ(4.0) nt = self.getNameTag() nt.setX(0) nt.setY(-2) nt.setZ(5.0) def exitSwim(self): self.exitGeneral() self.getGeomNode().setP(0.0) self.getGeomNode().setZ(0.0) nt = self.getNameTag() nt.setX(0) nt.setY(0) nt.setZ(self.getHeight() + 0.3) self.playingAnim = 'neutral' def enterDied(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'lose' self.isdying = True self.play('lose') self.track = Sequence(Wait(2.2), Func(self.dieSfx), Wait(2.8), self.getGeomNode().scaleInterval(2, Point3(0.01), startScale=self.getGeomNode().getScale()), Func(self.delToon), name=self.uniqueName('enterDied')) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.diedDone, [callback, extraArgs]) self.track.delayDelete = DelayDelete.DelayDelete(self, 'enterTeleportOut') self.track.start(ts) def diedDone(self, callback, extraArgs): self.__doCallback(callback, extraArgs) self.exitDied() def __doCallback(self, callback, extraArgs): if callback: if extraArgs: callback(*extraArgs) else: callback() def dieSfx(self): self.Losesfx = base.audio3d.loadSfx('phase_5/audio/sfx/ENC_Lose.mp3') base.audio3d.attachSoundToObject(self.Losesfx, self) self.Losesfx.play() def delToon(self): self.isdead = True def exitDied(self): if self.track != None: self.ignore(self.track.getDoneEvent()) self.track.finish() DelayDelete.cleanupDelayDeletes(self.track) self.track = None self.rescaleToon() self.playingAnim = 'neutral' return def enterJump(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'jump' self.loop('jump') def exitJump(self): self.exitGeneral() self.playingAnim = 'neutral' def enterLeap(self, ts = 0, callback = None, extraArgs = []): self.playingAnim = 'leap' self.loop('leap') def exitLeap(self): self.exitGeneral() self.playingAnim = 'neutral' def enterCringe(self, ts = 0, callback = None, extraArgs = []): self.play('cringe') def exitCringe(self): self.exitGeneral() def enterConked(self, ts = 0, callback = None, extraArgs = []): self.play('conked') def exitConked(self): self.exitGeneral()
class Player(FSM, DirectObject): NormalMode = "Normal" FightMode = "Fight" GAMEPADMODE = "Gamepad" MOUSEANDKEYBOARD = "MouseAndKeyboard" def __init__(self): FSM.__init__(self, "FSM-Player") random.seed() # # PLAYER CONTROLS AND CAMERA # self.player = Actor( "Character", { "Idle": "Character-Idle", "Run": "Character-Run", "Activate": "Character-Activate", "Death": "Character-Death", "Jump": "Character-Jump", "Hit": "Character-Hit", "Fight_Attack": "Character-FightAttack", "Fight_Idle": "Character-FightIdle", "Fight_Left": "Character-FightLeft", "Fight_Right": "Character-FightRight", }, ) self.player.setBlend(frameBlend=True) # the initial cam distance self.fightCamDistance = 3.0 # the next two vars will set the min and max distance the cam can have # to the node it is attached to self.maxCamDistance = 4.0 self.minCamDistance = 1.2 # the initial cam distance self.camDistance = (self.maxCamDistance - self.minCamDistance) / 2.0 + self.minCamDistance # the next two vars set the min and max distance on the Z-Axis to the # node the cam is attached to self.maxCamHeightDist = 3.0 self.minCamHeightDist = 1.5 # the average camera height self.camHeightAvg = (self.maxCamHeightDist - self.minCamHeightDist) / 2.0 + self.minCamHeightDist # an invisible object which will fly above the player and will be used to # track the camera on it self.camFloater = NodePath(PandaNode("playerCamFloater")) self.camFloater.setPos(0, 0, 1.5) self.camFloater.reparentTo(self.player) # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 # Interval for the jump animation self.jumpInterval = None self.jumpstartFloater = NodePath(PandaNode("jumpstartFloater")) self.jumpstartFloater.reparentTo(render) self.deathComplete = None # Joystick/Gamepad support self.hasJoystick = False if gamepadSupport: # initialize controls joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())] if len(joysticks) > 0: self.mainJoystick = joysticks[0] self.mainJoystick.init() self.hasJoystick = True # # WEAPONS AND ACCESSORIES # self.RightHandAttach = self.player.exposeJoint(None, "modelRoot", "HandAttach_R") self.spear = loader.loadModel("Spear") self.spear.setP(90) self.spear.setR(180) self.spear.reparentTo(self.RightHandAttach) self.LeftHandAttach = self.player.exposeJoint(None, "modelRoot", "HandAttach_L") self.shield = loader.loadModel("Shield") self.shield.setZ(0.05) self.shield.setH(-90) self.shield.reparentTo(self.LeftHandAttach) # # PLAYER COLLISION DETECTION AND PHYSICS # self.playerSphere = CollisionSphere(0, 0, 0.8, 0.7) self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision")) self.playerCollision.node().addSolid(self.playerSphere) base.pusher.addCollider(self.playerCollision, self.player) base.cTrav.addCollider(self.playerCollision, base.pusher) # The foot collision checks self.footRay = CollisionRay(0, 0, 0, 0, 0, -1) self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision")) self.playerFootRay.node().addSolid(self.footRay) self.playerFootRay.node().setIntoCollideMask(0) self.lifter = CollisionHandlerFloor() self.lifter.addCollider(self.playerFootRay, self.player) self.lifter.setMaxVelocity(5) base.cTrav.addCollider(self.playerFootRay, self.lifter) # a collision segment slightly in front of the player to check for jump ledges self.jumpCheckSegment = CollisionSegment(0, -0.2, 0.5, 0, -0.2, -2) self.playerJumpRay = self.player.attachNewNode(CollisionNode("playerJumpCollision")) self.playerJumpRay.node().addSolid(self.jumpCheckSegment) self.playerJumpRay.node().setIntoCollideMask(0) self.jumper = CollisionHandlerEvent() self.jumper.addOutPattern("%fn-out") base.cTrav.addCollider(self.playerJumpRay, self.jumper) # a collision segment to check attacks self.attackCheckSegment = CollisionSegment(0, 0, 1, 0, -1.3, 1) self.playerAttackRay = self.player.attachNewNode(CollisionNode("playerAttackCollision")) self.playerAttackRay.node().addSolid(self.attackCheckSegment) self.playerAttackRay.node().setIntoCollideMask(0) self.attackqueue = CollisionHandlerQueue() base.cTrav.addCollider(self.playerAttackRay, self.attackqueue) # # SOUNDEFFECTS # self.footstep = loader.loadSfx("Footstep.ogg") self.footstep.setLoop(True) self.footstep.setPlayRate(1.5) self.footstep.setVolume(0.5) self.spearAttackSfx = loader.loadSfx("SpearAttack.ogg") self.spearAttackSfx.setVolume(0.5) # # START/STOP # def start(self, startPoint): self.player.setPos(startPoint.getPos()) self.player.setHpr(startPoint.getHpr()) self.player.reparentTo(render) self.jumpstartFloater.setPos(self.player.getPos()) self.keyMap = {"horizontal": 0, "vertical": 0} self.health = 3 self.trackedEnemy = None # this mode will be used to determine in which move mode the player currently is self.mode = Player.NormalMode # the initial cam height self.camHeight = self.camHeightAvg # a time to keep the cam zoom at a specific speed independent of # current framerate self.camElapsed = 0.0 self.mouseSpeedX = 15.0 * base.mouseSensitivity self.mouseSpeedY = 0.2 * base.mouseSensitivity self.speed = 1.0 self.camCenterEvents = ["centerCam", "home", "q"] self.camZoomInEvents = ["zoomIn", "+", "wheel_up"] self.camZoomOutEvents = ["zoomOut", "-", "wheel_down"] self.actionEvents = ["doAction", "enter", "e"] self.accept("arrow_left", self.setKey, ["horizontal", 1]) self.accept("arrow_right", self.setKey, ["horizontal", -1]) self.accept("arrow_up", self.setKey, ["vertical", -1]) self.accept("arrow_down", self.setKey, ["vertical", 1]) self.accept("arrow_left-up", self.setKey, ["horizontal", 0]) self.accept("arrow_right-up", self.setKey, ["horizontal", 0]) self.accept("arrow_up-up", self.setKey, ["vertical", 0]) self.accept("arrow_down-up", self.setKey, ["vertical", 0]) self.accept("a", self.setKey, ["horizontal", 1]) self.accept("d", self.setKey, ["horizontal", -1]) self.accept("w", self.setKey, ["vertical", -1]) self.accept("s", self.setKey, ["vertical", 1]) self.accept("a-up", self.setKey, ["horizontal", 0]) self.accept("d-up", self.setKey, ["horizontal", 0]) self.accept("w-up", self.setKey, ["vertical", 0]) self.accept("s-up", self.setKey, ["vertical", 0]) for event in self.camCenterEvents: self.acceptOnce(event, self.center) for event in self.camZoomInEvents: self.acceptOnce(event, self.zoom, [True]) for event in self.camZoomOutEvents: self.acceptOnce(event, self.zoom, [False]) for event in self.actionEvents: self.acceptOnce(event, self.request, ["Action"]) self.accept("ActionDone", self.request, ["Idle"]) self.accept("playerJumpCollision-out", self.jump) taskMgr.add(self.move, "task_movement", priority=-10) taskMgr.add(self.updateCam, "task_camActualisation", priority=-4) if self.hasJoystick: taskMgr.add(self.gamepadLoop, "task_gamepad_loop", priority=-5) camera.setPos(self.player, 0, self.camDistance, self.camHeightAvg) self.hasJumped = False self.isActionmove = False self.request("Idle") def stop(self): taskMgr.remove("task_movement") taskMgr.remove("task_camActualisation") taskMgr.remove("task_gamepad_loop") self.ignoreAll() self.player.hide() def cleanup(self): self.stop() if self.deathComplete is not None: self.deathComplete.finish() if self.jumpInterval is not None: self.jumpInterval.finish() self.spear.removeNode() self.shield.removeNode() self.player.cleanup() self.player.removeNode() self.jumpstartFloater.removeNode() self.camFloater.removeNode() # # BASIC FUNCTIONS # def die(self): self.health -= 1 base.messenger.send("setHealth", [self.health]) self.request("Death") def heal(self): if self.health >= 3: return self.health += 1 base.messenger.send("setHealth", [self.health]) def hit(self): self.health -= 1 base.messenger.send("setHealth", [self.health]) if self.health == 0: self.request("Death") else: self.request("Hit") def resetPlayerPos(self): self.player.setPos(self.jumpstartFloater.getPos()) self.jumper.clear() self.request("Idle") def gameOver(self): base.messenger.send("GameOver", ["loose"]) def enterFightMode(self, trackedEnemy): self.trackedEnemy = trackedEnemy self.mode = Player.FightMode base.messenger.send("EnterFightMode") def exitFightMode(self): self.trackedEnemy = None self.mode = Player.NormalMode base.messenger.send("ExitFightMode") def gamepadLoop(self, task): joymap = {0: "doAction", 5: "centerCam", 6: "zoomIn", 4: "zoomOut", 9: "escape"} for event in pygame.event.get(): for button in range(self.mainJoystick.get_numbuttons()): if button in joymap and self.mainJoystick.get_button(button): base.messenger.send(joymap[button]) if event.type == pygame.JOYAXISMOTION: for axis in range(self.mainJoystick.get_numaxes()): axisChange = 0.0 axisChange = self.mainJoystick.get_axis(axis) if axis == 0: self.setKey("horizontal", -axisChange) if axis == 1: self.setKey("vertical", axisChange) return task.cont def setAnimationSpeed(self, requestedState): if requestedState == "Run": self.player.setPlayRate(3 * self.speed, "Run") elif requestedState == "RunReverse": self.player.setPlayRate(-3 * self.speed, "Run") elif requestedState == "FightLeft": self.player.setPlayRate(2 * self.speed, "Fight_Left") elif requestedState == "FightRight": self.player.setPlayRate(2 * self.speed, "Fight_Right") # # MOVE FUNCTIONS # def setKey(self, key, value): self.keyMap[key] = value def move(self, task): dt = globalClock.getDt() resetMouse = False def resetMouse(): if base.controlType == Player.MOUSEANDKEYBOARD: base.win.movePointer(0, self.winXhalf, self.winYhalf) if self.player.getAnimControl("Hit").isPlaying() or self.player.getAnimControl("Death").isPlaying(): resetMouse() return task.cont if self.deathComplete is not None: if self.deathComplete.isPlaying(): resetMouse() return task.cont if self.jumpInterval is not None: if self.jumpInterval.isPlaying(): resetMouse() return task.cont if self.isActionmove: resetMouse() return task.cont if self.mode == Player.NormalMode: self.__normalMove(dt) else: self.__fightMove(dt) return task.cont def __normalMove(self, dt): requestState = "Idle" move = False if self.keyMap["horizontal"] != 0: requestState = "Run" move = True if self.keyMap["vertical"] != 0: requestState = "Run" move = True if move and base.controlType == Player.GAMEPADMODE: movementVec = Vec3(self.keyMap["horizontal"], self.keyMap["vertical"], 0) self.speed = max(abs(self.keyMap["horizontal"]), abs(self.keyMap["vertical"])) angle = math.atan2(-movementVec.getX(), movementVec.getY()) rotation = angle * (180.0 / math.pi) self.player.setH(camera, rotation) self.player.setP(0) self.player.setR(0) self.player.setPos(self.player, (0, -2 * self.speed * dt, 0)) elif base.controlType == Player.MOUSEANDKEYBOARD: if not base.mouseWatcherNode.hasMouse(): return self.pointer = base.win.getPointer(0) mouseX = self.pointer.getX() mouseY = self.pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): z = camera.getZ() + (mouseY - self.winYhalf) * self.mouseSpeedY * dt camera.setZ(z) h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX * dt if h < -360: h = 360 elif h > 360: h = -360 self.player.setH(h) if move: self.player.setPos( self.player, (2 * dt * self.keyMap["horizontal"], 2 * dt * self.keyMap["vertical"], 0) ) self.center() if self.state != requestState: self.request(requestState) self.setAnimationSpeed(requestState) def __fightMove(self, dt): if self.trackedEnemy == None: return requestState = "Idle" self.player.lookAt(self.trackedEnemy) self.player.setH(self.player, 180) if self.keyMap["horizontal"] > 0: self.player.setX(self.player, 2 * self.speed * dt) requestState = "FightLeft" elif self.keyMap["horizontal"] < 0: self.player.setX(self.player, -2 * self.speed * dt) requestState = "FightRight" elif self.keyMap["vertical"] < 0: self.player.setY(self.player, -2 * self.speed * dt) requestState = "Run" elif self.keyMap["vertical"] > 0: self.player.setY(self.player, 2 * self.speed * dt) requestState = "RunReverse" if self.state != requestState: self.request(requestState) self.setAnimationSpeed(requestState) def jump(self, extraArg): intoName = extraArg.getIntoNode().getName().lower() if not "floor" in intoName and not "plate" in intoName: return # setup the projectile interval startPos = self.player.getPos() self.jumpstartFloater.setPos(self.player, 0, 0.5, 0) tempFloater = NodePath(PandaNode("tempJumpFloater")) tempFloater.setPos(self.player, 0, -3.2, 0.1) endPos = tempFloater.getPos() tempFloater.removeNode() self.jumpInterval = ProjectileInterval( self.player, startPos=startPos, endPos=endPos, duration=1.5, gravityMult=0.25 ) self.request("Jump") self.jumpInterval.start() # # CAMERA FUNCTIONS # def updateCam(self, task): if self.mode == Player.NormalMode: self.__normalCam() else: self.__fightCam() return task.cont def zoom(self, zoomIn): # Camera Movement Updates camvec = self.player.getPos() - camera.getPos() camvec.setZ(0) camdist = camvec.length() zoom = 0 if zoomIn: if camdist > self.minCamDistance + 0.5: zoom = 0.5 for event in self.camZoomInEvents: self.acceptOnce(event, self.zoom, [True]) else: if camdist < self.maxCamDistance - 0.5: zoom = -0.5 for event in self.camZoomOutEvents: self.acceptOnce(event, self.zoom, [False]) camera.setPos(camera, 0, zoom, 0) def center(self): # Camera Movement Updates camvec = self.player.getPos() - camera.getPos() camvec.setZ(0) camdist = camvec.length() # get the cameras current offset to the player model on the z-axis offsetZ = camera.getZ() - self.player.getZ() camera.setPos(self.player, 0, camdist, offsetZ) for event in self.camCenterEvents: self.acceptOnce(event, self.center) def __normalCam(self): """This function will check the min and max distance of the camera to the defined model and will correct the position if the cam is to close or to far away""" # Camera Movement Updates camvec = self.player.getPos() - camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() # If far from player start following if camdist > self.maxCamDistance: camera.setPos(camera.getPos() + camvec * (camdist - self.maxCamDistance)) camdist = self.maxCamDistance # If player to close move cam backwards if camdist < self.minCamDistance: camera.setPos(camera.getPos() - camvec * (self.minCamDistance - camdist)) camdist = self.minCamDistance # get the cameras current offset to the player model on the z-axis offsetZ = camera.getZ() - self.player.getZ() # check if the camera is within the min and max z-axis offset if offsetZ < self.minCamHeightDist: camera.setZ(self.player.getZ() + self.minCamHeightDist) offsetZ = self.minCamHeightDist elif offsetZ > self.maxCamHeightDist: camera.setZ(self.player.getZ() + self.maxCamHeightDist) offsetZ = self.maxCamHeightDist if offsetZ != self.camHeightAvg and not base.controlType == Player.MOUSEANDKEYBOARD: # if we are not moving up or down, set the cam to an average position if offsetZ != self.camHeightAvg: if offsetZ > self.camHeightAvg: # the cam is higher then the average cam height above the player # so move it slowly down camera.setZ(camera.getZ() - 5 * globalClock.getDt()) newOffsetZ = camera.getZ() - self.player.getZ() # check if the cam has reached the desired offset if newOffsetZ < self.camHeightAvg: # set the cam z position to exactly the desired offset camera.setZ(self.player.getZ() + self.camHeightAvg) else: # the cam is lower then the average cam height above the player # so move it slowly up camera.setZ(camera.getZ() + 5 * globalClock.getDt()) newOffsetZ = camera.getZ() - self.player.getZ() # check if the cam has reached the desired offset if newOffsetZ > self.camHeightAvg: # set the cam z position to exactly the desired offset camera.setZ(self.player.getZ() + self.camHeightAvg) camera.lookAt(self.camFloater) def __fightCam(self): """This function will check the min and max distance of the camera to the defined model and will correct the position if the cam is to close or to far away""" camera.setX(self.player, 0) camera.setY(self.player, self.fightCamDistance) camera.setZ(0.5) camera.lookAt(self.camFloater) # # FSM FUNCTIONS # def enterIdle(self): if self.mode == Player.NormalMode: self.player.loop("Idle") self.footstep.stop() elif self.mode == Player.FightMode: self.player.loop("Fight_Idle") self.footstep.stop() def enterRun(self): self.player.loop("Run") self.footstep.play() def enterRunReverse(self): self.player.loop("Run") self.footstep.play() def enterAction(self): if self.player.getAnimControl("Hit").isPlaying() or self.player.getAnimControl("Death").isPlaying(): self.__exitAction() return self.isActionmove = True if self.mode == Player.NormalMode: self.__enterActivate() elif self.mode == Player.FightMode: self.__enterFightAttack() self.accept("ActionDone", self.__exitAction) def __exitAction(self): self.isActionmove = False for event in self.actionEvents: self.acceptOnce(event, self.request, ["Action"]) def __enterActivate(self): activateAnim = self.player.actorInterval("Activate", playRate=3) activateAnim.setDoneEvent("ActionDone") activateAnim.start() base.messenger.send("Player_Activate") self.footstep.stop() def enterDeath(self): self.footstep.stop() deathAnim = self.player.actorInterval("Death") deathComplete = None if self.health == 0: self.deathComplete = Sequence(deathAnim, Wait(2), Func(self.gameOver)) else: self.deathComplete = Sequence(deathAnim, Wait(2), Func(self.resetPlayerPos)) self.deathComplete.start() def enterJump(self): self.player.play("Jump") self.footstep.stop() def enterHit(self): self.player.setPlayRate(4, "Hit") self.player.play("Hit") self.footstep.stop() def __enterFightAttack(self): attackAnim = self.player.actorInterval("Fight_Attack", playRate=3) attackAnim.setDoneEvent("ActionDone") attackAnim.start() self.spearAttackSfx.play() for i in range(self.attackqueue.getNumEntries()): entry = self.attackqueue.getEntry(i) into = entry.getIntoNode() if "golemHitField" in into.getName(): if random.random() > 0.15: base.messenger.send("HitEnemy") self.footstep.stop() def enterFightLeft(self): self.player.loop("Fight_Left") self.footstep.play() def enterFightRight(self): self.player.loop("Fight_Right") self.footstep.play()
class HL2Pistol(BaseHitscan, HL2PistolShared): #ModelPath = "phase_14/hl2/w_pistol/w_pistol.bam" ModelOrigin = (-0.03, 1.19, -0.14) ModelAngles = (2.29, 347.01, 45) ModelScale = 2 Name = GagGlobals.HL2Pistol ID = ATTACK_HL2PISTOL Hold = ATTACK_HOLD_RIGHT sgDir = 'phase_14/hl2/v_pistol/' sgActorDef = [ sgDir + 'v_pistol.bam', { 'draw': sgDir + 'v_pistol-draw.egg', 'idle': sgDir + 'v_pistol-idle01.egg', 'fire': sgDir + 'v_pistol-fire.egg', 'reload': sgDir + 'v_pistol-reload.egg' } ] sgFirePath = 'phase_14/hl2/v_pistol/pistol_fire2.wav' sgEmptyPath = 'phase_14/hl2/v_pistol/pistol_empty.wav' sgReloadPath = 'phase_14/hl2/v_pistol/pistol_reload1.wav' SpecialVM = True def __init__(self): BaseHitscan.__init__(self) self.sgViewModel = None self.fireSound = None self.emptySound = None self.reloadSound = None self.fpMuzzleAttach = None @classmethod def doPrecache(cls): super(HL2Pistol, cls).doPrecache() precacheActor(cls.sgActorDef) precacheSound(cls.sgFirePath) precacheSound(cls.sgEmptyPath) precacheSound(cls.sgReloadPath) def load(self): self.fireSound = base.audio3d.loadSfx(self.sgFirePath) self.emptySound = base.audio3d.loadSfx(self.sgEmptyPath) self.reloadSound = base.audio3d.loadSfx(self.sgReloadPath) base.audio3d.attachSoundToObject(self.fireSound, self.avatar) base.audio3d.attachSoundToObject(self.emptySound, self.avatar) base.audio3d.attachSoundToObject(self.reloadSound, self.avatar) if self.isLocal(): self.sgViewModel = Actor(self.sgActorDef[0], self.sgActorDef[1]) self.sgViewModel.setPlayRate(self.Speed, "idle") self.sgViewModel.node().setBounds(OmniBoundingVolume()) self.sgViewModel.node().setFinal(1) self.sgViewModel.setBlend( frameBlend=base.config.GetBool('interpolate-frames', False)) self.sgViewModel.setH(180) self.fpMuzzleAttach = self.sgViewModel.exposeJoint( None, "modelRoot", "ValveBiped.muzzle") def cleanup(self): if self.sgViewModel: self.sgViewModel.cleanup() self.sgViewModel.removeNode() self.sgViewModel = None self.fpMuzzleAttach = None if self.fireSound: base.audio3d.detachSound(self.fireSound) self.fireSound = None if self.emptySound: base.audio3d.detachSound(self.emptySound) self.emptySound = None if self.reloadSound: base.audio3d.detachSound(self.reloadSound) self.reloadSound = None BaseHitscan.cleanup(self) def equip(self): if not BaseHitscan.equip(self): return False if self.isFirstPerson(): fpsCam = self.getFPSCam() fpsCam.swapViewModel(self.sgViewModel, 54.0) self.getViewModel().show() self.doDrawAndHold('squirt', 0, 43, 1.0, 43, 43) return True def unEquip(self): if not BaseHitscan.unEquip(self): return False if self.isFirstPerson(): self.getFPSCam().restoreViewModel() self.getViewModel().hide() return True def onSetAction(self, action): if action == self.StateReload: self.reloadSound.play() elif action == self.StateFire: self.fireSound.play() def onSetAction_firstPerson(self, action): track = Sequence() vm = self.getViewModel() fpsCam = self.getFPSCam() if action == self.StateIdle: track.append(Func(vm.loop, "idle")) elif action == self.StateDraw: track.append(ActorInterval(vm, "draw", playRate=self.Speed)) elif action == self.StateReload: track.append(Func(self.reloadSound.play)) track.append(ActorInterval(vm, "reload", playRate=self.Speed)) elif action == self.StateFire: CIGlobals.makeMuzzleFlash(self.fpMuzzleAttach, (0, 0, 0), (-90, 0, 0), 7) fpsCam.resetViewPunch() fpsCam.addViewPunch( Vec3(random.uniform(-0.6, 0.6), random.uniform(-0.25, -0.5), 0.0)) track.append(Func(self.fireSound.play)) track.append(ActorInterval(vm, "fire", playRate=self.Speed)) fpsCam.setVMAnimTrack(track)
class Gag(object): def __init__(self, name, model, damage, gagType, hitSfx, playRate = 1.0, anim = None, scale = 1, autoRelease = False): __metaclass__ = ABCMeta self.name = name self.model = model self.anim = anim self.scale = scale self.damage = damage self.gagType = gagType self.playRate = playRate self.avatar = None self.gag = None self.splat = None self.splatPos = None self.state = GagState.LOADED self.woosh = None self.handJoint = None self.equipped = False self.autoRelease = autoRelease self.index = None self.target = None self.health = 0 self.id = GagGlobals.getIDByName(name) self.image = None if game.process == 'client': if gagType == GagType.THROW: self.woosh = base.audio3d.loadSfx(GagGlobals.PIE_WOOSH_SFX) self.hitSfx = base.audio3d.loadSfx(hitSfx) return @abc.abstractmethod def start(self): if not self.avatar: return backpack = self.avatar.getBackpack() if not backpack: return if self not in backpack.getGags(): return if backpack.getSupply(self.getName()) == 0: return try: base.audio3d.detachSound(self.woosh) self.track.pause() self.cleanupGag() except: pass self.state = GagState.START self.avatar.getBackpack().setActiveGag(self.getName()) @abc.abstractmethod def reset(self): self.state = GagState.LOADED self.target = None if self.avatar: backpack = self.avatar.getBackpack() if backpack.getActiveGag(): if backpack.getActiveGag() == self: backpack.setActiveGag(None) return @abc.abstractmethod def throw(self): pass @abc.abstractmethod def release(self): self.state = GagState.RELEASED @abc.abstractmethod def buildCollisions(self): pass @abc.abstractmethod def onCollision(self): pass def setAvatar(self, avatar): self.avatar = avatar def getAvatar(self): return self.avatar def setState(self, paramState): self.state = paramState def getState(self): return self.state def setTarget(self, target): self.target = target def getTarget(self): return self.target def getType(self): return self.gagType def build(self): if self.anim: self.gag = Actor(self.model, {'chan': self.anim}) else: self.gag = loader.loadModel(self.model) self.setHandJoint() self.gag.setScale(self.scale) self.gag.setName(self.getName()) def setHandJoint(self): if self.avatar: self.handJoint = self.avatar.find('**/def_joint_right_hold') def equip(self): if not self.avatar or not self.avatar.getBackpack() or self.avatar.getBackpack() and self.avatar.getBackpack().getSupply(self.getName()) == 0: return self.setHandJoint() if not self.gag: self.build() self.gag.reparentTo(self.handJoint) self.equipped = True @abc.abstractmethod def unEquip(self): if game.process != 'client': return if self.equipped and self.handJoint: inHand = self.handJoint.getChildren() for item in inHand: if item.getName() == self.getName(): item.removeNode() self.equipped = False self.reset() base.localAvatar.enablePieKeys() def setHealth(self, health): self.health = health def getHealth(self): return self.health def setImage(self, image): self.image = image def getImage(self): return self.image def getDamage(self): return self.damage def getName(self): return self.name def delete(self): self.unEquip() self.handJoint = None self.avatar = None self.state = None self.cleanupGag() self.cleanupSplat() if self.woosh: self.woosh.stop() self.woosh = None if self.hitSfx: self.hitSfx.stop() self.hitSfx = None return def cleanupGag(self): try: self.track.pause() except: pass if self.gag and self.state == GagState.LOADED: name = self.gag.getName() if self.anim: self.gag.cleanup() if self.avatar: copies = self.avatar.findAllMatches('**/%s' % name) for copy in copies: copy.removeNode() if self.gag and not self.gag.isEmpty(): self.gag.removeNode() self.gag = None return def getGag(self): return self.gag def placeProp(self, handJoint, prop, pos = None, hpr = None, scale = None): prop.reparentTo(handJoint) if pos: prop.setPos(pos) if hpr: prop.setHpr(hpr) if scale: prop.setScale(scale) def getScaleTrack(self, props, duration, startScale, endScale): track = Parallel() if not isinstance(props, list): props = [props] for prop in props: track.append(LerpScaleInterval(prop, duration, endScale, startScale=startScale)) return track def getSoundTrack(self, delay, node, duration = None): soundTrack = Sequence() soundTrack.append(Wait(delay)) if duration: soundTrack.append(SoundInterval(self.hitSfx, duration=duration, node=node)) else: soundTrack.append(SoundInterval(self.hitSfx, node=node)) return soundTrack def getScaleIntervals(self, props, duration, startScale, endScale): tracks = Parallel() if not isinstance(props, list): props = [props] for prop in props: tracks.append(LerpScaleInterval(prop, duration, endScale, startScale=startScale)) return tracks def getScaleBlendIntervals(self, props, duration, startScale, endScale, blendType): tracks = Parallel() if not isinstance(props, list): props = [props] for prop in props: tracks.append(LerpScaleInterval(prop, duration, endScale, startScale=startScale, blendType=blendType)) return tracks def buildSplat(self, scale, color): self.cleanupSplat() self.splat = Actor(GagGlobals.SPLAT_MDL, {'chan': GagGlobals.SPLAT_CHAN}) self.splat.setScale(scale) self.splat.setColor(color) self.splat.setBillboardPointEye() self.splat.play('chan') return self.splat def setSplatPos(self, x, y, z): self.cleanupGag() self.splatPos = Point3(x, y, z) self.handleSplat() def cleanupSplat(self): if self.splat: self.splat.cleanup() self.splat def setEndPos(self, x, y, z): pass def handleSplat(self): pass def delSplat(self, task): self.cleanupSplat() return Task.done def getAudio3D(self): return base.audio3d def doesAutoRelease(self): return self.autoRelease def isLocal(self): if not self.avatar: return False return self.avatar.doId == base.localAvatar.doId def getID(self): return self.id
class Item(DirectObject, object): ''' 道具类的虚基类 ''' num = 0 # use to identify item collition node def __init__(self, itemName): super(Item, self).__init__() self.number = Item.num self.itemName = itemName Item.num += 1 def initModel(self, pos, scale, player, buffState, parent=None): ''' 初始化道具模型和设置碰撞检测 #pos 道具模型的放置位置 (世界坐标系) #scale 模型缩放比例 #player 英雄实例 ''' # 加载并设置模型 try: modelName = ModelPath + "model_" + self.itemName self.item = Actor(modelName, {'revolve': modelName}) self.item.loop('revolve') except Exception: self.item = Actor() self.item.setScale(0.3) self.item.setPos(pos) self.item.setScale(scale) if parent == None: self.item.reparentTo(base.render) else: self.item.reparentTo(parent) # 设置碰撞检测 collisionSphere = CollisionSphere(0, 0, 0, 1) self.collisionNodeName = "{}CollisionNode{}".format( self.itemName, self.number) itemColNode = CollisionNode(self.collisionNodeName) itemColNode.addSolid(collisionSphere) itemColNode.setIntoCollideMask(CollideMask.bit(DefaultHeroMaskVal)) itemColNode.setFromCollideMask(CollideMask.allOff()) self.itemCollision = self.item.attachNewNode(itemColNode) self.itemCollision.setPythonTag("Item", self) ##显示包围体 用于粗略模拟道具盒 # self.itemCollision.show() base.cTrav.addCollider(self.itemCollision, base.cHandler) inEvent = "{}-into-{}".format(player.colliderName, self.collisionNodeName) self.accept(inEvent, self.action) buffState.accept(inEvent, buffState.addBuff) @print_func_time def action(self, entry): ''' 碰撞处理事件 将道具效果应用到英雄对象 不同类型道具有不同实现方式 ''' #print self.itemName,self.collisionNodeName player = entry.getFromNodePath().getPythonTag("Hero") player.sounds["GetItem"].play() @print_func_time def _destroy(self): ''' 道具使用后立即销毁 ''' self.ignoreAll() if not self.item.isEmpty(): self.item.cleanup() self.item.removeNode()
class Enemy(FSM, Unit): # Declare private variables _enemyActive = False _removeCorpseDelay = 2 # seconds before corpse is cleaned def __init__(self, mainRef, attributes): print("Enemy instantiated") Unit.__init__(self) FSM.__init__(self, 'playerFSM') self._mainRef = mainRef self._playerRef = mainRef.player self._AIworldRef = mainRef.AIworld self._enemyListRef = mainRef.enemyList self._ddaHandlerRef = mainRef.DDAHandler self._stateHandlerRef = mainRef.stateHandler self._scenarioHandlerRef = mainRef.scenarioHandler #self.topEnemyNode = mainRef.mainNode.attachNewNode('topEnemyNode') self.initEnemyNode(mainRef.mainNode) utils.enemyDictionary[self.enemyNode.getName()] = self self.loadEnemyModel(attributes.modelName) self.initAttributes(attributes) self.initEnemyAi() self.initEnemyDDA() self.initEnemyCollisionHandlers() self.initEnemyCollisionSolids() #self.request('Idle') self.request('Disabled') # Start enemy updater task self.enemyUpdaterTask = taskMgr.add(self.enemyUpdater, 'enemyUpdaterTask') def initEnemyNode(self, parentNode): enemyName = 'enemy' + str(len(self._enemyListRef)) self.enemyNode = parentNode.attachNewNode(enemyName) self._enemyListRef.append(self) def loadEnemyModel(self, modelName): modelPrefix = 'models/' + modelName self.enemyModel = Actor(modelPrefix + '-model', { 'walk':modelPrefix+'-walk', 'attack':modelPrefix+'-attack', 'idle':modelPrefix+'-idle', 'awake':modelPrefix+'-awake', 'stop':modelPrefix+'-stop', 'hit':modelPrefix+'-hit', 'death1':modelPrefix+'-death1', 'death2':modelPrefix+'-death2' }) self.enemyModel.reparentTo(self.enemyNode) self.enemyNode.setPos(Point3.zero()) self.enemyNode.setDepthOffset(-1) def initAttributes(self, attributes): perceptionRangeMultiplier = 1.2 combatRangeMultiplier = .3 speedMultiplier = .1 self.strength = attributes.strength self.constitution = attributes.constitution self.dexterity = attributes.dexterity self.mass = attributes.mass self.movementSpeed = speedMultiplier * attributes.movementSpeed self.perceptionRange = perceptionRangeMultiplier * attributes.perceptionRange self.combatRange = combatRangeMultiplier * attributes.combatRange self.attackBonus = attributes.attackBonus self.damageBonus = attributes.damageBonus self.damageRange = attributes.damageRange self.initiativeBonus = attributes.initiativeBonus self.fixedHealthPoints = attributes.fixedHealthPoints self.armorClass = attributes.armorClass if attributes.startLevel > 1: for i in range(attributes.startLevel-1): self.increaseLevel() self.expAward = attributes.expAward self.initHealth() def initEnemyDDA(self): if self._scenarioHandlerRef.getHasDDA(): maxLevelDifference = self._ddaHandlerRef.maxLevelDifference # Level enemy up to player's level minus maxLevelDifference levelDifference = self._playerRef.level - self.level if levelDifference >= maxLevelDifference: for i in range (levelDifference-maxLevelDifference): self.increaseLevel() def getAttackBonus(self): modifier = self.getStrengthModifier() if self.getStrengthModifier() > self.getDexterityModifier() else self.getDexterityModifier() ab = self.attackBonus + (self.level / 2) + modifier# + utils.getD20() if self._scenarioHandlerRef.getHasDDA(): attackBonusModifier = self._ddaHandlerRef.attackBonusModifier if attackBonusModifier < 0: ab -= attackBonusModifier if ab < 1: ab = 1 return ab + utils.getD20() def initEnemyAi(self): self.enemyAI = AICharacter('enemy', self.enemyNode, self.mass, # Mass 0.1, # Movt force self.movementSpeed) # Max force self._AIworldRef.addAiChar(self.enemyAI) self.enemyAIBehaviors = self.enemyAI.getAiBehaviors() #self.enemyAIBehaviors.obstacleAvoidance(1.0) def initEnemyCollisionHandlers(self): self.groundHandler = CollisionHandlerQueue() self.collPusher = CollisionHandlerPusher() def initEnemyCollisionSolids(self): # Enemy ground ray groundRay = CollisionRay(0, 0, 2, 0, 0, -1) groundColl = CollisionNode('enemyGroundRay') groundColl.addSolid(groundRay) groundColl.setIntoCollideMask(BitMask32.allOff()) groundColl.setFromCollideMask(BitMask32.bit(1)) self.groundRayNode = self.enemyNode.attachNewNode(groundColl) #self.groundRayNode.show() base.cTrav.addCollider(self.groundRayNode, self.groundHandler) # Enemy collision sphere collSphereNode = CollisionNode('enemyCollSphere') collSphere = CollisionSphere(0, 0, 0.1, 0.2) collSphereNode.addSolid(collSphere) collSphereNode.setIntoCollideMask(BitMask32.allOff()) collSphereNode.setFromCollideMask(BitMask32.bit(2)) self.sphereNode = self.enemyNode.attachNewNode(collSphereNode) #sphereNode.show() base.cTrav.addCollider(self.sphereNode, self.collPusher) self.collPusher.addCollider(self.sphereNode, self.enemyNode) # Enemy picker collision sphere pickerSphereCollNode = CollisionNode(self.enemyNode.getName()) pickerCollSphere = CollisionSphere(0, 0, 0, 0.5) pickerSphereCollNode.addSolid(pickerCollSphere) pickerSphereCollNode.setFromCollideMask(BitMask32.allOff()) pickerSphereCollNode.setIntoCollideMask(BitMask32.bit(1)) self.pickerNode = self.enemyNode.attachNewNode(pickerSphereCollNode) #sphereNodePath.show() # Enemy attack collision sphere attackCollSphereNode = CollisionNode(self.enemyNode.getName()+'atkSph') attackCollSphere = CollisionSphere(0, 0, 0.1, 0.15) attackCollSphereNode.addSolid(attackCollSphere) attackCollSphereNode.setIntoCollideMask(BitMask32.bit(3)) attackCollSphereNode.setFromCollideMask(BitMask32.allOff()) attackSphereNode = self.enemyNode.attachNewNode(attackCollSphereNode) #attackSphereNode.show() def slowMovementByPercentage(self, percentage=30, slowDuration=20): #print self.enemyNode.getName(), ' slowed by ', percentage, ' %' oldSpeed = self.movementSpeed newSpeed = ((100.0 - percentage) / 100.0) * oldSpeed if newSpeed < 1.0: newSpeed = 1.0 self.movementSpeed = newSpeed taskMgr.doMethodLater(slowDuration, self.removeSlowMovement, 'removeSlowMovementTask', extraArgs=[oldSpeed], appendTask=True) def removeSlowMovement(self, oldSpeed, task): self.movementSpeed = oldSpeed return task.done def checkGroundCollisions(self): if self.groundHandler.getNumEntries() > 0: self.groundHandler.sortEntries() entries = [] for i in range(self.groundHandler.getNumEntries()): entry = self.groundHandler.getEntry(i) #print('entry:', entry) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) for i in range(len(entries)): if entries[i].getIntoNode().getName()[:6] == 'ground': #print('entryFound:', entries[0]) newZ = entries[i].getSurfacePoint(base.render).getZ() self.enemyNode.setZ(newZ) #print('enemyZ:', newZ) break; def enemyUpdater(self, task): if self._stateHandlerRef.state != self._stateHandlerRef.PLAY or not self._enemyActive: self.enemyModel.stop() # Do not do anything when paused return task.cont self.checkGroundCollisions() if self.getIsDead(): self.onDeath() return task.done if self._playerRef.getIsDead(): return task.cont playerPos = self._playerRef.playerNode.getPos() enemyPos = self.enemyNode.getPos() # If player is within enemy perception range if utils.getIsInRange(playerPos, enemyPos, self.perceptionRange): # If enemy is not doing anything if self.state == 'Idle': # Start pursuing if self.state != 'Pursue': self.request('Pursue') # If enemy is already pursueing elif self.state == 'Pursue': # If player is within combat range if utils.getIsInRange(playerPos, enemyPos, self.combatRange): #print 'enemy go to combat' # Go to combat if self.state != 'Combat': self.request('Combat') # If enemy is already in combat elif self.state == 'Combat': # If player has moved out of combat range if not utils.getIsInRange(playerPos, enemyPos, self.combatRange): # Start pursuing if self.state != 'Pursue': self.request('Pursue') # If enemy is disabled elif self.state == 'Disabled': if self.enemyAI.getMaxForce() != self.movementSpeed: self.enemyAI.setMaxForce(self.movementSpeed) # If player is not within perception range else: if self.state != 'Idle': self.request('Idle') return task.cont def pursuePlayer(self): taskMgr.add(self.pursue, 'pursueTask') def pursue(self, task): if self.state == 'Pursue' and not self.getIsDead(): pitchRoll = self.enemyNode.getP(), self.enemyNode.getR() self.enemyNode.headsUp(self._playerRef.playerNode) self.enemyNode.setHpr(self.enemyNode.getH()-180, *pitchRoll) speed = -self.movementSpeed * globalClock.getDt() self.enemyNode.setFluidPos(self.enemyNode, 0, speed, 0) return task.cont else: task.done def enterIdle(self): #print 'enemy enterIdle' stopEnemy = self.enemyModel.actorInterval('stop', loop=0) idleEnemy = self.enemyModel.actorInterval('idle', startFrame=0, endFrame=1, loop=0) self.stopSequence = Sequence(stopEnemy, idleEnemy) self.stopSequence.start() self.isSleeping = True def exitIdle(self): #print('enemy exitIdle') self.stopSequence.finish() def enterPursue(self): #print('enemy enterPursue') loopWalkEnemy = Func(self.enemyModel.loop, 'walk', fromFrame=0, toFrame=12) # Only awake enemy if it comes from idle if self.isSleeping: self.isSleeping = False awakeEnemy = self.enemyModel.actorInterval('awake', loop=0) self.awakeSequence = Sequence(awakeEnemy, loopWalkEnemy, Func(self.pursuePlayer)) else: self.awakeSequence = Sequence(loopWalkEnemy, Func(self.pursuePlayer)) self.awakeSequence.start() def exitPursue(self): #print('enemy exitPursue') self.awakeSequence.finish() def enterCombat(self): #print('enemy enterCombat') self.enemyModel.stop() attackDelay = self.getInitiativeRoll() self.attackTask = taskMgr.doMethodLater(attackDelay, self.attackPlayer, 'attackPlayerTask') def enterDisabled(self): #print 'enterDisable' pass def exitDisabled(self): #print 'exitDisable' pass def exitCombat(self): #print('enemy exitCombat') taskMgr.remove(self.attackTask) def enterDeath(self): #print('enemy enterDeath') self.enemyAIBehaviors.removeAi('all') randomDeathAnim = 'death' + str(utils.getD2()) self.enemyModel.play(randomDeathAnim) def attack(self, other): if not self.getIsDead() and not other.getIsDead(): if self.getAttackBonus() >= other.getArmorClass(): dmg = self.getDamageBonus() #print(self.getName(), ' damaged ', other.getName(), ' for ', dmg, ' damage') other.receiveDamage(dmg) return 2 # Returns 2 when self damages other return 1 # Returns 1 when self attacks other, but misses return 0 # Returns 0 when either self or other is dead def attackPlayer(self, task): if self._stateHandlerRef.state != self._stateHandlerRef.PLAY or not self._enemyActive: # Do not do anything when paused return task.again if self._playerRef.getIsDead(): print('player is already dead') self.request('Idle') return task.done elif self.getIsDead(): return task.done else: #print('Attack player!') # Make sure enemy is facing player when attacking pitchRoll = self.enemyNode.getP(), self.enemyNode.getR() self.enemyNode.headsUp(self._playerRef.playerNode) self.enemyNode.setHpr(self.enemyNode.getH()-180, *pitchRoll) attacked = self.attack(self._playerRef) if attacked != 0: self.playAttackAnimation() if attacked == 2: self._playerRef.playerModel.play('hit') return task.again def playAttackAnimation(self): self.enemyModel.play('attack', fromFrame=0, toFrame=12) def playHitAnimation(self): self.enemyModel.play('hit') def moveEnemy(self, x, y): self.enemyNode.setPos(x, y, .01) def handleHealthGlobe(self): global dropChanceFactor global dropChance global maxDropChance # if we drop, create health goblet chance = dropChanceFactor + dropChance if self._scenarioHandlerRef.getHasDDA(): chance *= self._ddaHandlerRef.healthGobletModifier if utils.getD100() <= chance: HealthGoblet(self._mainRef, self) print 'dropping health goblet' # Otherwise, increase dropChance else: if dropChance+dropChanceFactor <= maxDropChance: dropChance += dropChanceFactor def suicide(self): print('suicide: ', self) # Remove AI behavior self.enemyAIBehaviors.removeAi('all') # Remove enemy picker sphere (handlerQueue) self.pickerNode.removeNode() taskMgr.add(self.removeCorpse, 'removeCorpseTask') def onDeath(self): if self.getIsDead(): # Remove AI behavior self.enemyAIBehaviors.removeAi('all') # Award the player exp self._playerRef.receiveEXP(self.expAward) # Remove enemy picker sphere (handlerQueue) self.pickerNode.removeNode() # Change state self.request('Death') # Increase DDA death count if self._scenarioHandlerRef.getHasDDA(): self._ddaHandlerRef.enemyDeathCount += 1 # Handle health globe self.handleHealthGlobe() # Remove enemy corpse and clean up taskMgr.doMethodLater(self._removeCorpseDelay, self.removeCorpse, 'removeCorpseTask') def removeCorpse(self, task): # Remove enemy collision sphere (pusher) self.sphereNode.removeNode() # Stop the collision pusher self.collPusher = None # Remove enemy from enemyList self._enemyListRef.remove(self) # Cleanup the enemy model self.enemyModel.cleanup() self.enemyModel.delete() # Cleanup FSM self.cleanup() # Remove the enemy node self.enemyNode.removeNode() #self.topEnemyNode.removeNode() # Remove enemy updater tasks taskMgr.remove(self.enemyUpdaterTask) # Remove the passive regeneration task (from Unit class) self.removePassiveRegeneration() # Remove references self._mainRef = None self._playerRef = None self._AIworldRef = None self._enemyListRef = None self._stateHandlerRef = None return task.done
class DynObject(): def __init__(self, render, objid, start_pos, gameclient): self.client = gameclient self.id = objid self.motion_controller = None self.is_player = False # state management self.isAnimating = False self.state = state.IDLE self.render = render # scene graph root # create the panda3d actor: just load a default model for now self.actor = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.actor.reparentTo(render) self.actor.setScale(.2) self.actor.setPos(start_pos) # prepare collision handling self.cTrav = CollisionTraverser() self.GroundRay = CollisionRay() self.GroundRay.setOrigin(0,0,1000) self.GroundRay.setDirection(0,0,-1) self.GroundCol = CollisionNode('actorRay') self.GroundCol.addSolid(self.GroundRay) self.GroundCol.setFromCollideMask(BitMask32.bit(0)) self.GroundCol.setIntoCollideMask(BitMask32.allOff()) self.GroundColNp = self.actor.attachNewNode(self.GroundCol) self.GroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.GroundColNp, self.GroundHandler) def destroy(self): if self.actor != None: self.actor.cleanup() self.actor.removeNode() self.actor = None # called reqularly from a Panda3 task # move the object according to its current state def move(self): actor = self.actor # save our initial position so that we can restore it, # in case we fall off the map or run into something. startpos = actor.getPos() # let the motion_controller determine our new state self.motion_controller.processMove() # evaluate state and move/rotate the actor accordingly if (self.state & state.LEFT): actor.setH(actor.getH() + 300 * globalClock.getDt()) if (self.state & state.RIGHT): actor.setH(actor.getH() - 300 * globalClock.getDt()) if (self.state & state.FORWARD): actor.setY(actor, -25 * globalClock.getDt()) # Simplistic animation control: # If we are moving, loop the run animation. # If we are standing still, stop the animation. if (self.state != state.IDLE): if self.isAnimating is False: actor.loop("run") self.isAnimating = True else: if self.isAnimating: actor.stop() actor.pose("walk", 5) self.isAnimating = False # Now check for collisions. self.cTrav.traverse(render) # Adjust Z coordinate. If the ray hit terrain, # update Z. If it hit anything else, or didn't hit anything, put # us back where we were last frame. entries = [] for i in range(self.GroundHandler.getNumEntries()): entry = self.GroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.actor.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.actor.setPos(startpos) # if this is the player avatar: make the camera follow us if self.is_player is True: self.client.world.moveCamera() # convenience getter/setters def setPos(self, pos): self.actor.setPos(pos) def getPos(self): return self.actor.getPos() def getH(self): return self.actor.getH() def getX(self): return self.actor.getX() def getY(self): return self.actor.getY() def getZ(self): return self.actor.getZ()
class DistributedScienceFair(DistributedObject): def announceGenerate(self): DistributedObject.announceGenerate(self) self.tent = loader.loadModel('phase_4/models/events/event_tent.bam') self.tent.reparentTo(render) self.tent.setPosHpr(0, 0, 0, 270, 0, 0) self.redFlag = Actor(loader.loadModel('phase_4/models/events/event-flag-mod.bam')) self.redFlag.loadAnims({'waving': 'phase_4/models/events/event-flag-anim.bam'}) self.redFlag.reparentTo(self.tent.find('**/flag1_jnt')) self.redFlag.loop('waving') self.blueFlag = Actor(loader.loadModel('phase_4/models/events/event-flag-mod.bam')) self.blueFlag.loadAnims({'waving': 'phase_4/models/events/event-flag-anim.bam'}) self.blueFlag.reparentTo(self.tent.find('**/flag2_jnt')) self.blueFlag.loop('waving') self.tent2 = loader.loadModel('phase_4/models/events/event_tent.bam') self.tent2.reparentTo(render) self.tent2.setPosHpr(85.91, 149.76, 2.61, 327.99, 0, 0) self.balloonArchway = loader.loadModel('phase_4/models/events/balloon_archway_spiraled.bam') self.balloonArchway.reparentTo(render) self.balloonArchway.setPosHpr(-24.25, 17.24, 0, 0, 0, 0) self.balloonArchway.flattenStrong() self.balloonArchway2 = loader.loadModel('phase_4/models/events/balloon_archway_spiraled.bam') self.balloonArchway2.reparentTo(render) self.balloonArchway2.setPosHpr(-24.25, -31.03, 0, 0, 0, 0) self.balloonArchway2.flattenStrong() self.balloonArchway3 = loader.loadModel('phase_4/models/events/balloon_archway_spiraled.bam') self.balloonArchway3.reparentTo(render) self.balloonArchway3.setPosHpr(99.6, 0.65, 4, 272.39, 0, 0) self.balloonArchway3.setScale(1.21) self.balloonArchway3.flattenStrong() self.balloontowerCake = loader.loadModel('phase_4/models/events/balloon_set_cake.bam') self.balloontowerCake.reparentTo(render) self.balloontowerCake.setPosHpr(95.65, 6.75, 4, 270, 0, 0) self.balloontowerCake.flattenStrong() self.balloontowerStar = loader.loadModel('phase_4/models/events/balloon_set_star.bam') self.balloontowerStar.reparentTo(render) self.balloontowerStar.setPosHpr(95.70, -5.56, 4, 270, 0, 0) self.balloontowerStar.flattenStrong() self.barrierCircle = loader.loadModel('phase_4/models/events/barrier_circle_sf.bam') self.barrierCircle.reparentTo(render) self.barrierCircle.setPosHpr(-14.67, 51.93, 0.025, 287.10, 0, 0) self.barrierCircle.flattenStrong() #self.tent3 = Actor(loader.loadModel('phase_4/models/events/tele_anim02_repaired.bam')) #self.tent3.reparentTo(render) #self.tent3.setPosHpr(0, 0, 0, 0, 0, 0) #CHAN TRY AND FIGURE THIS BULL SHIT OUT! IT'S A SINGLE BAM FILE WITH AN ANIMATION AND A MODEL. IT DOESN'T LOAD THE ANIMATION IN GAME! ;-; def delete(self): if self.tent2 is not None: self.tent2.removeNode() self.tent2 = None if self.blueFlag is not None: self.blueFlag.cleanup() self.blueFlag = None if self.redFlag is not None: self.redFlag.cleanup() self.redFlag = None if self.balloonArchway is not None: self.balloonArchway.removeNode() self.balloonArchway = None if self.balloonArchway2 is not None: self.balloonArchway2.removeNode() self.balloonArchway2 = None if self.balloonArchway3 is not None: self.balloonArchway3.removeNode() self.balloonArchway3 = None if self.barrierCircle is not None: self.barrierCircle.removeNode() self.barrierCircle = None if self.balloontowerCake is not None: self.balloontowerCake.removeNode() self.balloontowerCake = None if self.balloontowerStar is not None: self.balloontowerStar.removeNode() self.balloontowerStar = None if self.tent is not None: self.tent.removeNode() self.tent = None DistributedObject.delete(self)
class BaseAttack(Precacheable, BaseAttackShared): notify = directNotify.newCategory("BaseAttack") ModelPath = None ModelAnimPath = None ModelScale = 1 ModelAngles = Vec3(0, 0, 0) ModelOrigin = Point3(0, 0, 0) AttackType = ATTACKTYPE_NONE Hold = ATTACK_HOLD_NONE ModelVMOrigin = Point3(0, 0, 0) ModelVMAngles = Point3(0, 0, 0) ModelVMScale = 1 ModelVMAnimate = True SpecialVM = False SpecialVMCull = True SpecialVMActor = None SpecialVMFov = 54.0 SpecialVMOrigin = Point3(0) SpecialVMAngles = Vec3(0) SpecialVMScale = 1 def __init__(self, sharedMetadata=None): BaseAttackShared.__init__(self, sharedMetadata) self.model = None self.specialViewModel = None self.crosshair = CrosshairData() self.animTrack = None def hasSpecialViewModel(self): return self.SpecialVM and (self.specialViewModel is not None) and self.isFirstPerson() def unloadViewModel(self): if self.specialViewModel: self.specialViewModel.cleanup() self.specialViewModel = None def loadViewModel(self): self.unloadViewModel() if self.SpecialVM and self.SpecialVMActor: modelName, anims = self.SpecialVMActor self.specialViewModel = Actor(modelName, anims) self.specialViewModel.setPos(self.SpecialVMOrigin) self.specialViewModel.setHpr(self.SpecialVMAngles) self.specialViewModel.setScale(self.SpecialVMScale) self.specialViewModel.setBlend( frameBlend=base.config.GetBool('interpolate-frames', False)) if not self.SpecialVMCull: self.specialViewModel.node().setBounds(OmniBoundingVolume()) self.specialViewModel.node().setFinal(1) def doDrawNoHold(self, drawAnim, drawAnimStart=None, drawAnimEnd=None, drawAnimSpeed=1.0): self.setAnimTrack(Sequence( Func(self.avatar.setForcedTorsoAnim, drawAnim), self.getAnimationTrack(drawAnim, drawAnimStart, drawAnimEnd, drawAnimSpeed)), startNow=True) def doHold(self, anim, bobStart, bobEnd, bobSpeed): self.setAnimTrack(self.getBobSequence(anim, bobStart, bobEnd, bobSpeed), startNow=True, looping=True) def doDrawAndHold(self, drawAnim, drawAnimStart=None, drawAnimEnd=None, drawAnimSpeed=1.0, bobStart=None, bobEnd=None, bobSpeed=1.0, holdCallback=None): def __doHold(): if holdCallback: holdCallback() self.doHold(drawAnim, bobStart, bobEnd, bobSpeed) self.setAnimTrack(Sequence( Func(self.avatar.setForcedTorsoAnim, drawAnim), self.getAnimationTrack(drawAnim, drawAnimStart, drawAnimEnd, drawAnimSpeed), Func(__doHold)), startNow=True) # This should be called to change the 'animTrack' variable. def setAnimTrack(self, track, startNow=False, looping=False): """ Sets the animation track for this gag. """ if track is None: # If we try to set the animation track to None, we should # just call clearAnimTrack. self.clearAnimTrack() return # Stop the one that was playing before. self.clearAnimTrack() self.animTrack = track if startNow: if looping: self.animTrack.loop() else: self.animTrack.start() # This should be called whenever we want to clear the 'animTrack' variable. def clearAnimTrack(self): if self.animTrack is not None: self.animTrack.pause() self.animTrack = None def playAnimThatShouldBePlaying(self): if self.avatar and hasattr(self.avatar, 'playingAnim'): self.avatar.loop(self.avatar.playingAnim) def getAnimationTrack(self, animName, startFrame=None, endFrame=None, playRate=1.0, startTime=None, endTime=None, fullBody=False): seq = Parallel() def __animTrack(partName): return ActorInterval(self.avatar, animName, startFrame=startFrame, endFrame=endFrame, partName=partName, playRate=playRate, startTime=startTime, endTime=endTime) if not fullBody: uppers = self.avatar.getUpperBodySubpart() for part in uppers: seq.append(__animTrack(part)) else: seq.append(__animTrack(None)) return seq def getBobSequence(self, animName, startFrame, endFrame, playRate): def __animTrack_bobUp(partName): return ActorInterval(self.avatar, animName, startFrame=startFrame, endFrame=endFrame, partName=partName, playRate=playRate) def __animTrack_bobDown(partName): return ActorInterval(self.avatar, animName, startFrame=endFrame, endFrame=startFrame, partName=partName, playRate=playRate) uppers = self.avatar.getUpperBodySubpart() seq = Sequence() bobUp = Parallel() for part in uppers: bobUp.append(__animTrack_bobUp(part)) bobDown = Parallel() for part in uppers: bobDown.append(__animTrack_bobDown(part)) seq.append(bobUp) seq.append(bobDown) return seq def getCrosshair(self): return self.crosshair # =========================================== # These functions are to be overridden by child classes # to add any arbitrary data when we send these fire # events to the server. def addPrimaryPressData(self, dg): pass def addPrimaryReleaseData(self, dg): pass def addSecondaryPressData(self, dg): pass def addSecondaryReleaseData(self, dg): pass def addReloadPressData(self, dg): pass def addReloadReleaseData(self, dg): pass # =========================================== def primaryFirePress(self, data=None): dg = PyDatagram() self.addPrimaryPressData(dg) self.avatar.sendUpdate('primaryFirePress', [dg.getMessage()]) def primaryFireRelease(self, data=None): dg = PyDatagram() self.addPrimaryReleaseData(dg) self.avatar.sendUpdate('primaryFireRelease', [dg.getMessage()]) def secondaryFirePress(self, data=None): dg = PyDatagram() self.addSecondaryPressData(dg) self.avatar.sendUpdate('secondaryFirePress', [dg.getMessage()]) def secondaryFireRelease(self, data=None): dg = PyDatagram() self.addSecondaryReleaseData(dg) self.avatar.sendUpdate('secondaryFireRelease', [dg.getMessage()]) def reloadPress(self, data=None): dg = PyDatagram() self.addReloadPressData(dg) self.avatar.sendUpdate('reloadPress', [dg.getMessage()]) def reloadRelease(self, data=None): dg = PyDatagram() self.addReloadReleaseData(dg) self.avatar.sendUpdate('reloadRelease', [dg.getMessage()]) @classmethod def doPrecache(cls): print("BaseAttack(%s).doPrecache()" % cls.ModelPath) if cls.ModelAnimPath: precacheActor([ cls.ModelPath, { 'chan': cls.ModelAnimPath, 'zero': cls.ModelPath } ]) elif cls.ModelPath: precacheModel(cls.ModelPath) if cls.SpecialVM and cls.SpecialVMActor: precacheActor(cls.SpecialVMActor) def getName(self): return self.Name def isLocal(self): return self.avatar == base.localAvatar def isFirstPerson(self): return self.isLocal() and base.localAvatar.isFirstPerson() def getViewModel(self): return base.localAvatar.getViewModel() def getFPSCam(self): return base.localAvatar.getFPSCam() def getVMGag(self): return base.localAvatar.getFPSCam().vmGag def getViewPunch(self): """ Return the angles of the view "punch" that is applied to the camera when this attack is used by the local avatar. """ return Vec3.zero() def load(self): BaseAttackShared.load(self) if self.isLocal(): self.loadViewModel() def __loadAttackModel(self): if self.model: self.model.removeNode() self.model = None if self.ModelPath: if self.ModelAnimPath: self.model = Actor(self.ModelPath, { 'chan': self.ModelAnimPath, 'zero': self.ModelPath }) else: self.model = loader.loadModel(self.ModelPath) self.model.setPos(self.ModelOrigin) self.model.setHpr(self.ModelAngles) self.model.setScale(self.ModelScale) self.model.setName(self.Name + "-model") # copy the attack model to first person if self.isFirstPerson(): if self.hasSpecialViewModel(): self.getFPSCam().swapViewModel(self.specialViewModel, self.SpecialVMFov) elif self.model: self.getFPSCam().setVMGag( self.model, self.ModelVMOrigin, self.ModelVMAngles, self.ModelVMScale, self.Hold, self.ModelAnimPath is not None and self.ModelVMAnimate) if not self.getViewModel().isEmpty( ) and self.action != self.StateOff: self.getViewModel().show() def __holdAttackModel(self): if not self.hasAvatar(): self.notify.warning( "Tried to hold attack model, but no valid avatar.") return if not CIGlobals.isNodePathOk(self.model): return if self.Hold == ATTACK_HOLD_LEFT: self.model.reparentTo(self.avatar.getLeftHandNode()) elif self.Hold == ATTACK_HOLD_RIGHT: self.model.reparentTo(self.avatar.getRightHandNode()) else: self.model.reparentTo(NodePath()) def equip(self): if not BaseAttackShared.equip(self): return False if not self.hasAvatar(): self.notify.warning("Tried to equip attack, but no valid avatar.") return False self.__loadAttackModel() self.__holdAttackModel() return True def unEquip(self): if not BaseAttackShared.unEquip(self): return False if self.model: if isinstance(self.model, Actor): self.model.cleanup() self.model.removeNode() self.model = None self.clearAnimTrack() if self.hasAvatar(): self.avatar.clearForcedTorsoAnim() if self.isFirstPerson(): self.getFPSCam().clearVMGag() self.getFPSCam().clearVMAnimTrack() self.getFPSCam().restoreViewModelFOV() if self.hasSpecialViewModel(): self.getFPSCam().restoreViewModel() if not self.getViewModel().isEmpty(): self.getViewModel().hide() return True def cleanup(self): BaseAttackShared.cleanup(self) self.unloadViewModel() self.crosshair.cleanup() del self.crosshair del self.model
class Bot(object): def __init__(self, team, position, direction): self._orders = Actions.DoNothing self._hp = 5 self._death_played = False self._interval = None self.kills = 0 self.team = team self._model = NodePath('bot') self._model.reparentTo(render) self._model.setPos(position) self._model.setHpr(direction, 0, 0) self._model.setColorScale(*self.team) self._model.setScale(.2, .2, .2) # Load the animations self._actor = Actor("models/RockGolem", { 'idle': 'models/RockGolem-idle', 'walk': 'models/RockGolem-walk', 'reverse-walk': 'models/RockGolem-walk', 'punch': 'models/RockGolem-punch', 'death': 'models/RockGolem-death', 'throw': 'models/RockGolem-throw', }) self._actor.setPlayRate(2.65, 'walk') self._actor.setPlayRate(-2.65, 'reverse-walk') self._actor.setPlayRate(4, 'punch') self._actor.setPlayRate(5.25, 'throw') self._actor.setBlend(frameBlend=True) self._actor.reparentTo(self._model) self._actor.loop('idle') self._actor.setH(180) # Floating Label text = TextNode('node name') text.setText(self.__class__.__name__) text.setAlign(TextNode.ACenter) self._name_label = self._model.attachNewNode(text) self._name_label.setBillboardPointEye() self._name_label.setPos(Vec3(0, 0, 6)) self._name_label.setScale(3, 3, 3) # Debug Field of View Cones # fov = make_fov() # fov.reparentTo(self._model) def update(self, tick_number, visible_objects): return Actions.DoNothing def get_position(self): """Return a rounded version of the position vector.""" p = self._model.getPos() return Vec3(round(p.x, 0), round(p.y, 0), round(p.z, 0)) def get_direction(self): """Return a rounded version of the direction vector.""" v = render.getRelativeVector(self._model, Vec3(0, 1, 0)) v.normalize() return Vec3(round(v.x, 0), round(v.y, 0), round(v.z, 0)) def get_name(self): return self.__class__.__name__ def _get_orders(self, tick_number, visible_objects): # If the health is too low, die. if self._hp <= 0: self._orders = Actions.Suicide return # noinspection PyBroadException try: self._orders = self.update(tick_number, visible_objects) except Exception as e: print(type(self), e) self._orders = None def _execute_orders(self, tick_length, battle): # Pre-calculate some useful things new_pos = self.get_position() new_dir = self._model.getHpr() # TODO: Getting rounding errors here velocity = self.get_direction() # If we're outside of the arena, take damage ARENA_SIZE = 13 if new_pos.length() > ARENA_SIZE: battle.announce("{} fled the battle!".format(self.get_name())) self.take_damage(999) # Execute the order if self._orders == Actions.MoveForward: new_pos += velocity self.safe_loop('walk') elif self._orders == Actions.MoveBackward: new_pos -= velocity self.safe_loop('reverse-walk') elif self._orders == Actions.StrafeLeft: v = render.getRelativeVector(self._model, Vec3(-1, 0, 0)) v.normalize() v = Vec3(round(v.x, 0), round(v.y, 0), round(v.z, 0)) new_pos += v self.safe_loop('walk') elif self._orders == Actions.StrafeRight: v = render.getRelativeVector(self._model, Vec3(1, 0, 0)) v.normalize() v = Vec3(round(v.x, 0), round(v.y, 0), round(v.z, 0)) new_pos += v self.safe_loop('walk') elif self._orders == Actions.TurnLeft: new_dir.x += 90 self.safe_loop('walk') elif self._orders == Actions.TurnAround: new_dir.x += 180 self.safe_loop('walk') elif self._orders == Actions.TurnRight: new_dir.x -= 90 self.safe_loop('walk') elif self._orders == Actions.Punch: self.punch(battle) elif self._orders == Actions.DoNothing: self.safe_loop('idle') elif self._orders == Actions.Suicide: self._hp = 0 battle.announce("{} killed itself.".format(self.get_name())) self.take_damage(999) else: # Bad orders detected! Kill this bot. self._hp = 0 battle.announce("{} made an illegal move and died.".format(self.get_name())) self.take_damage(999) # Animate the motion if self._hp <= 0: return self._interval = LerpPosHprInterval( self._model, tick_length-0.05, new_pos, new_dir) self._interval.start() def safe_loop(self, animation): if self._death_played: return if self._actor.getCurrentAnim() != animation: self._actor.loop(animation) def punch(self, battle): if not self._death_played: self._actor.play('punch') hazard = self.get_direction() + self.get_position() bot = battle.get_object_at_position(hazard) if isinstance(bot, Bot): bot.take_damage(5) # TODO: This is fun as 1 if bot._hp > 0: return if bot.team == self.team: message = "{self} killed its teammate {target}!" self.kills -= 1 else: message = "{self} just pwned {target}!" self.kills += 1 battle.announce(message.format(self=self.get_name(), target=bot.get_name()), color=self.team, sfx="Ownage" if self.kills == 1 else None) if self.kills == 2: battle.announce("{} is ON FIRE!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="DoubleKill") elif self.kills == 3: battle.announce("{} is UNSTOPPABLE!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="TripleKill") elif self.kills == 4: battle.announce("{} is DOMINATING!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="Dominating") elif self.kills > 4: battle.announce("{} is GODLIKE!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="Godlike") def take_damage(self, amount): self._hp -= amount if self._hp <= 0: self._name_label.hide() if self._interval: self._interval.pause() if not self._death_played: self._actor.play('death') self._death_played = True def delete(self): self._model.removeNode() self._actor.cleanup() self._name_label.removeNode()
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 Monster(): def __init__(self, setup_data, common, start_pos=(0, 0, 0)): level = common[ 'max_level'] + 1 # max_level is the current level starting from 0 common['monsterList'].append(self) id = len(common['monsterList']) - 1 self.monsterList = common['monsterList'] self.waypoints_data = common['waypoints_data'] self.waypoints = common['waypoints'] self.audio3d = common['audio3d'] self.common = common #root node self.node = render.attachNewNode("monster") self.sound_node = None self.soundset = None self.actor = Actor(setup_data["model"], setup_data["anim"]) self.actor.setBlend(frameBlend=True) self.actor.reparentTo(self.node) self.actor.setScale(setup_data["scale"] * random.uniform(0.9, 1.1)) self.actor.setH(setup_data["heading"]) self.actor.setBin("opaque", 10) self.rootBone = self.actor.exposeJoint(None, 'modelRoot', setup_data["root_bone"]) #sounds self.soundID = self.common['soundPool'].get_id() self.common['soundPool'].set_target(self.soundID, self.node) self.sound_names = { "hit": setup_data["hit_sfx"], "arrow_hit": setup_data["arrowhit_sfx"], "attack": setup_data["attack_sfx"], "die": setup_data["die_sfx"] } self.vfx = setup_data["hit_vfx"] self.stats = { "speed": setup_data["speed"], "hp": setup_data["hp"] * (level**0.15), "armor": setup_data["armor"] * (level**0.2), "dmg": setup_data["dmg"] * (level**0.8) } if self.stats['hp'] > 500: self.stats['hp'] = 500 self.maxHP = self.stats['hp'] self.healthBar = DirectFrame(frameSize=(-0.05, 0.05, 0, 0.05), frameColor=(1, 0, 0, 1), frameTexture='icon/glass4.png', parent=self.node) self.healthBar.setTransparency(TransparencyAttrib.MDual) self.healthBar.setScale(10, 1, 1) self.healthBar.setZ(2) self.healthBar.setBillboardPointEye( ) #Make it flat in front of the camera self.ambientLight = AmbientLight('ambientLight') self.ambientLight.setColor(VBase4(.3, .3, .3, 1)) self.ambientLightNode = render.attachNewNode(self.ambientLight) self.healthBar.setLight(self.ambientLightNode) self.healthBar.hide() wp = base.win.getProperties() winX = wp.getXSize() winY = wp.getYSize() #self.HPring.setColorScale(0.0, 1.0, 0.0, 1.0) #gamestate variables self.attack_pattern = setup_data["attack_pattern"] self.damage = setup_data["dmg"] #self.HP=setup_data["hp"] self.state = "STOP" self.id = id self.nextWaypoint = None self.canSeePC = False self.PCisInRange = False self.PC = common['PC'] self.speed_mode = random.randrange(0 + int(level), 42 + int(level), 7) / 100.0 self.totalSpeed = self.stats['speed'] + self.speed_mode self.sparkSum = 0 self.lastMagmaDmg = 0 self.DOT = 0 self.arrows = set() self.isSolid = True self.traverser = CollisionTraverser("Trav" + str(self.id)) #self.traverser.showCollisions(render) self.queue = CollisionHandlerQueue() #bit masks: # 1 visibility polygons & coll-rays # 2 walls & radar-ray # 3 spheres #collision ray for testing visibility polygons coll = self.node.attachNewNode(CollisionNode('collRay')) coll.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -180)) coll.setTag("id", str(id)) coll.node().setIntoCollideMask(BitMask32.allOff()) coll.node().setFromCollideMask(BitMask32.bit(1)) self.traverser.addCollider(coll, self.queue) #radar collision ray self.radar = self.node.attachNewNode(CollisionNode('radarRay')) self.radar.node().addSolid(CollisionRay(0, 0, 1, 0, 90, 0)) self.radar.node().setIntoCollideMask(BitMask32.allOff()) self.radar.node().setFromCollideMask(BitMask32.bit(2)) self.radar.setTag("radar", str(id)) #self.radar.show() self.traverser.addCollider(self.radar, self.queue) #collision sphere self.coll_sphere = self.node.attachNewNode( CollisionNode('monsterSphere')) self.coll_sphere.node().addSolid(CollisionSphere(0, 0, 0.8, 0.6)) self.coll_sphere.setTag("id", str(id)) self.coll_sphere.node().setIntoCollideMask(BitMask32.bit(3)) #self.coll_sphere.show() #other monster blocking self.coll_quad = loader.loadModel("models/plane") self.coll_quad.reparentTo(self.node) #self.coll_quad=render.attachNewNode(CollisionNode('monsterSphere')) #self.coll_quad.node().addSolid(CollisionPolygon(Point3(-.5, -.5, 2), Point3(-.5, .5, 0), Point3(.5, .5, 0), Point3(.5, .5, 2))) #self.coll_quad.setTag("id", str(id)) #self.coll_quad.node().setIntoCollideMask(BitMask32.bit(2)) #self.coll_quad.reparentTo(self.node) #self.coll_quad.show() Sequence(Wait(random.uniform(.6, .8)), Func(self.restart)).start() self.node.setPos(render, start_pos) taskMgr.add(self.runAI, "AIfor" + str(self.id)) taskMgr.doMethodLater(.6, self.runCollisions, 'collFor' + str(self.id)) taskMgr.doMethodLater(1.0, self.damageOverTime, 'DOTfor' + str(self.id)) def die(self, soundname): n = random.random() if n < self.common["random-objects-freq"]: id = len(self.common["random-objects"]) object = RandomObject(id, self.common, self.node, render) self.common["random-objects"].append(object) self.actor.play("die") #self.common['soundPool'].play(self.soundID, self.sound_names["hit"]) self.common['soundPool'].play(self.soundID, soundname) self.state = "DIE" def damageOverTime(self, task): if self.state == "DIE": return task.done if self.DOT > 0: self.doDamage(self.DOT) self.DOT = int((self.DOT * 0.9) - 1.0) if self.stats['hp'] < 1: self.die(self.sound_names["die"]) vfx(self.node, texture=self.vfx, scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016, 24) return task.again def restart(self): self.state = "SEEK" def check_stacking(self): for monster in self.monsterList: if monster and monster.id != self.id: if self.node.getDistance(monster.node) < .8: if monster.state != "STOP" and self.state == "SEEK": if self.totalSpeed <= monster.totalSpeed: self.state = "STOP" self.actor.stop() Sequence(Wait(1.5), Func(self.restart)).start() return True def hideHealthbarTask(self, task): self.healthBar.hide() def doDamage(self, damage, ignoreArmor=False): if self.state == "DIE": return if not ignoreArmor: damage -= self.stats['armor'] if damage < 1: damage = 1 #print damage self.stats['hp'] -= damage self.healthBar.show() self.healthBar.setScale(10 * self.stats['hp'] / self.maxHP, 1, 1) taskMgr.doMethodLater(7.0, self.hideHealthbarTask, 'hideHealthbar') if self.stats['hp'] < 1: self.healthBar.hide() def attack(self, pattern): if self.state == "DIE": return if not self.PC.node: return if pattern: next = pattern.pop() else: self.state = "SEEK" self.PCisInRange = False return if self.PC.node and self.node: range = self.node.getDistance(self.PC.node) else: return #print range if range < 1.8: self.PC.hit(self.damage) Sequence(Wait(next), Func(self.attack, pattern)).start() def onHit(self, damage, sound="hit", weapon=None): if self.state == "DIE": return if weapon == "magma": damage = self.lastMagmaDmg self.common['soundPool'].play(self.soundID, "onFire") vfx(self.node, texture="vfx/small_flame.png", scale=.6, Z=.7, depthTest=False, depthWrite=False).start(0.016, stopAtFrame=24) elif weapon == "spark": self.common['soundPool'].play(self.soundID, "spark") short_vfx(self.node, texture="vfx/short_spark.png", scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.03) else: vfx(self.node, texture=self.vfx, scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) self.doDamage(damage) if self.stats['hp'] < 1: if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) self.die(self.sound_names["die"]) else: if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) def findFirstWaypoint(self): min = 100000 nearest = None for waypoint in self.waypoints: dist = self.node.getDistance(waypoint) if dist < min: min = dist nearest = waypoint return nearest def runCollisions(self, task): if self.state == "DIE": return task.done if self.node.getDistance(self.PC.node) > 50.0: self.nextWaypoint = None return task.again if self.check_stacking(): return task.again self.radar.lookAt(self.PC.node) valid_waypoints = [] isFirstTest = True self.canSeePC = False self.traverser.traverse(render) self.queue.sortEntries() for entry in self.queue.getEntries(): if entry.getFromNodePath().hasTag( "id"): #it's the monsters collRay valid_waypoints.append( int(entry.getIntoNodePath().getTag( "index"))) #visibility polygons elif entry.getFromNodePath().hasTag("radar"): #it's the radar-ray #print "radar hit", entry.getIntoNodePath() if isFirstTest: isFirstTest = False #print "first hit!" #print "radar hit", entry.getIntoNodePath() if entry.getIntoNodePath().hasTag("player"): self.canSeePC = True '''distance={} for target in self.PC.myWaypoints: for waypoint in valid_waypoints: distance[target]=self.waypoints_data[target][waypoint] print(target, distance[target]) if distance: self.nextWaypoint=self.waypoints[min(distance, key=distance.get)] #print self.canSeePC''' if not valid_waypoints: #self.nextWaypoint=self.findFirstWaypoint() print(self.id, ": I'm lost!") valid_waypoints = [self.findFirstWaypoint()] #return task.again if self.state == "STOP": self.nextWaypoint = self.waypoints[random.choice(valid_waypoints)] return task.again best_distance = 9000000 target_node = None for target in self.PC.myWaypoints: for valid in valid_waypoints: distance = self.waypoints_data[target][valid] #print "target->valid=",target, valid, distance if distance < best_distance: best_distance = distance target_node = valid if target_node: self.nextWaypoint = self.waypoints[target_node] else: #print "no target", valid_waypoints self.nextWaypoint = self.findFirstWaypoint() #self.waypoints[random.choice(valid_waypoints)] #print self.nextWaypoint return task.again def runAI(self, task): #print self.state if self.state == "DIE": self.coll_sphere.node().setIntoCollideMask(BitMask32.allOff()) self.coll_quad.removeNode() #self.actor.play("die") self.common["kills"] -= 1 if self.common["kills"] == 0: Interactive(self.common, data.items['key'], self.node.getPos(render)) Sequence( Wait(2.0), LerpPosInterval( self.node, 2.0, VBase3(self.node.getX(), self.node.getY(), self.node.getZ() - 5)), Func(self.destroy)).start() return task.done elif self.state == "STOP": target = self.nextWaypoint if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target) > 0.3: self.node.setY(self.node, self.totalSpeed * globalClock.getDt()) if (self.actor.getCurrentAnim() != "walk"): self.actor.loop("walk") return task.again elif self.state == "ATTACK": self.node.headsUp(self.PC.node) if (self.actor.getCurrentAnim() != "attack"): self.actor.play("attack") #Sequence(Wait(self.attack_pattern[-1]+self.speed_mode), Func(self.attack, list(self.attack_pattern))).start() Sequence(Wait(self.attack_pattern[-1]), Func(self.attack, list(self.attack_pattern))).start() return task.again elif self.state == "SEEK": if self.PCisInRange: self.state = "ATTACK" return task.again target = self.nextWaypoint if self.canSeePC and self.PC.HP > 0: target = self.PC.node #print "target pc!" if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target) > 0.3: self.node.setY(self.node, self.totalSpeed * globalClock.getDt()) if (self.actor.getCurrentAnim() != "walk"): self.actor.loop("walk") return task.again else: #print "I'm stuck?" #print target #print self.canSeePC self.nextWaypoint = self.PC.node return task.again def destroy(self): #for sound in self.soundset: # self.soundset[sound].stop() #print "destroy:", #self.sound_node.reparentTo(render) #self.common['soundPool'].append([self.sound_node,self.soundset]) self.common['soundPool'].set_free(self.soundID) #self.sounds=None #print " sounds", self.arrows = None if self.actor: self.actor.cleanup() self.actor.removeNode() #print " actor", if taskMgr.hasTaskNamed("hideHealthbar"): taskMgr.remove("hideHealthbar") if taskMgr.hasTaskNamed("AIfor" + str(self.id)): taskMgr.remove("AIfor" + str(self.id)) #print " AI", if taskMgr.hasTaskNamed('collFor' + str(self.id)): taskMgr.remove('collFor' + str(self.id)) #print " collision", if taskMgr.hasTaskNamed('DOTfor' + str(self.id)): taskMgr.remove('DOTfor' + str(self.id)) if self.node: self.node.removeNode() #print " node", self.monsterList[self.id] = None self.traverser = None self.queue = None self.healthBar.removeNode() self.ambientLightNode.removeNode()
class Toon: notify = DirectNotifyGlobal.directNotify.newCategory("Toon") def __init__(self): self.name = "Flippy" legsAnimDict = {'right-hand-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-hand-start.bam', 'firehose': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_firehose.bam', 'rotateL-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_rotateL-putt.bam', 'slip-forward': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_slip-forward.bam', 'catch-eatnrun': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_eatnrun.bam', 'tickle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_tickle.bam', 'water-gun': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_water-gun.bam', 'leverNeutral': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverNeutral.bam', 'swim': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_swim.bam', 'catch-run': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gamerun.bam', 'sad-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_sad-neutral.bam', 'pet-loop': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petloop.bam', 'jump-squat': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zstart.bam', 'wave': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_wave.bam', 'reel-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reelneutral.bam', 'pole-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_poleneutral.bam', 'bank': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_jellybeanJar.bam', 'scientistGame': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistGame.bam', 'right-hand': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-hand.bam', 'lookloop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_lookloop-putt.bam', 'victory': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_victory-dance.bam', 'lose': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_lose.bam', 'cringe': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_cringe.bam', 'right': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_right.bam', 'headdown-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_headdown-putt.bam', 'conked': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_conked.bam', 'jump': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump.bam', 'into-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_into-putt.bam', 'fish-end': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishEND.bam', 'running-jump-land': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zend.bam', 'shrug': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_shrug.bam', 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_sprinkle-dust.bam', 'hold-bottle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hold-bottle.bam', 'takePhone': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_takePhone.bam', 'melt': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_melt.bam', 'pet-start': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petin.bam', 'look-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_look-putt.bam', 'loop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_loop-putt.bam', 'good-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_good-putt.bam', 'juggle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_juggle.bam', 'run': 'phase_3/models/char/tt_a_chr_dgs_shorts_legs_run.bam', 'pushbutton': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_press-button.bam', 'sidestep-right': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-back-right.bam', 'water': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_water.bam', 'right-point-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-point-start.bam', 'bad-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_bad-putt.bam', 'struggle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_struggle.bam', 'running-jump': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_running-jump.bam', 'callPet': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_callPet.bam', 'throw': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_pie-throw.bam', 'catch-eatneutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_eat_neutral.bam', 'tug-o-war': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_tug-o-war.bam', 'bow': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_bow.bam', 'swing': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_swing.bam', 'climb': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_climb.bam', 'scientistWork': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistWork.bam', 'think': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_think.bam', 'catch-intro-throw': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gameThrow.bam', 'walk': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_walk.bam', 'down': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_down.bam', 'pole': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_pole.bam', 'periscope': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_periscope.bam', 'duck': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_duck.bam', 'curtsy': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_curtsy.bam', 'jump-land': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zend.bam', 'loop-dig': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_loop_dig.bam', 'angry': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_angry.bam', 'bored': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_bored.bam', 'swing-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_swing-putt.bam', 'pet-end': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petend.bam', 'spit': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_spit.bam', 'right-point': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-point.bam', 'start-dig': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_into_dig.bam', 'castlong': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_castlong.bam', 'confused': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_confused.bam', 'neutral': 'phase_3/models/char/tt_a_chr_dgs_shorts_legs_neutral.bam', 'jump-idle': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zhang.bam', 'reel': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reel.bam', 'slip-backward': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_slip-backward.bam', 'sound': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_shout.bam', 'sidestep-left': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_sidestep-left.bam', 'up': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_up.bam', 'fish-again': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishAGAIN.bam', 'cast': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_cast.bam', 'phoneBack': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_phoneBack.bam', 'phoneNeutral': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_phoneNeutral.bam', 'scientistJealous': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistJealous.bam', 'battlecast': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fish.bam', 'sit-start': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_intoSit.bam', 'toss': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_toss.bam', 'happy-dance': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_happy-dance.bam', 'running-jump-squat': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zstart.bam', 'teleport': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_teleport.bam', 'sit': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_sit.bam', 'sad-walk': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_losewalk.bam', 'give-props-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_give-props-start.bam', 'book': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_book.bam', 'running-jump-idle': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zhang.bam', 'scientistEmcee': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistEmcee.bam', 'leverPull': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverPull.bam', 'tutorial-neutral': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_tutorial-neutral.bam', 'badloop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_badloop-putt.bam', 'give-props': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_give-props.bam', 'hold-magnet': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hold-magnet.bam', 'hypnotize': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hypnotize.bam', 'left-point': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_left-point.bam', 'leverReach': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverReach.bam', 'feedPet': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_feedPet.bam', 'reel-H': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reelH.bam', 'applause': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_applause.bam', 'smooch': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_smooch.bam', 'rotateR-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_rotateR-putt.bam', 'fish-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishneutral.bam', 'push': 'phase_9/models/char/tt_a_chr_dgs_shorts_legs_push.bam', 'catch-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gameneutral.bam', 'left': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_left.bam'} torsoAnimDict = {'right-hand-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-hand-start.bam', 'firehose': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_firehose.bam', 'rotateL-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_rotateL-putt.bam', 'slip-forward': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_slip-forward.bam', 'catch-eatnrun': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_eatnrun.bam', 'tickle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_tickle.bam', 'water-gun': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_water-gun.bam', 'leverNeutral': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverNeutral.bam', 'swim': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_swim.bam', 'catch-run': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gamerun.bam', 'sad-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_sad-neutral.bam', 'pet-loop': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petloop.bam', 'jump-squat': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zstart.bam', 'wave': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_wave.bam', 'reel-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reelneutral.bam', 'pole-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_poleneutral.bam', 'bank': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_jellybeanJar.bam', 'scientistGame': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistGame.bam', 'right-hand': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-hand.bam', 'lookloop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_lookloop-putt.bam', 'victory': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_victory-dance.bam', 'lose': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_lose.bam', 'cringe': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_cringe.bam', 'right': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_right.bam', 'headdown-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_headdown-putt.bam', 'conked': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_conked.bam', 'jump': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump.bam', 'into-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_into-putt.bam', 'fish-end': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishEND.bam', 'running-jump-land': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zend.bam', 'shrug': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_shrug.bam', 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_sprinkle-dust.bam', 'hold-bottle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hold-bottle.bam', 'takePhone': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_takePhone.bam', 'melt': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_melt.bam', 'pet-start': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petin.bam', 'look-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_look-putt.bam', 'loop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_loop-putt.bam', 'good-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_good-putt.bam', 'juggle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_juggle.bam', 'run': 'phase_3/models/char/tt_a_chr_dgl_shorts_torso_run.bam', 'pushbutton': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_press-button.bam', 'sidestep-right': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-back-right.bam', 'water': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_water.bam', 'right-point-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-point-start.bam', 'bad-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_bad-putt.bam', 'struggle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_struggle.bam', 'running-jump': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_running-jump.bam', 'callPet': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_callPet.bam', 'throw': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_pie-throw.bam', 'catch-eatneutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_eat_neutral.bam', 'tug-o-war': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_tug-o-war.bam', 'bow': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_bow.bam', 'swing': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_swing.bam', 'climb': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_climb.bam', 'scientistWork': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistWork.bam', 'think': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_think.bam', 'catch-intro-throw': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gameThrow.bam', 'walk': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_walk.bam', 'down': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_down.bam', 'pole': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_pole.bam', 'periscope': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_periscope.bam', 'duck': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_duck.bam', 'curtsy': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_curtsy.bam', 'jump-land': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zend.bam', 'loop-dig': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_loop_dig.bam', 'angry': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_angry.bam', 'bored': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_bored.bam', 'swing-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_swing-putt.bam', 'pet-end': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petend.bam', 'spit': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_spit.bam', 'right-point': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-point.bam', 'start-dig': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_into_dig.bam', 'castlong': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_castlong.bam', 'confused': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_confused.bam', 'neutral': 'phase_3/models/char/tt_a_chr_dgl_shorts_torso_neutral.bam', 'jump-idle': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zhang.bam', 'reel': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reel.bam', 'slip-backward': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_slip-backward.bam', 'sound': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_shout.bam', 'sidestep-left': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_sidestep-left.bam', 'up': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_up.bam', 'fish-again': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishAGAIN.bam', 'cast': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_cast.bam', 'phoneBack': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_phoneBack.bam', 'phoneNeutral': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_phoneNeutral.bam', 'scientistJealous': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistJealous.bam', 'battlecast': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fish.bam', 'sit-start': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_intoSit.bam', 'toss': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_toss.bam', 'happy-dance': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_happy-dance.bam', 'running-jump-squat': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zstart.bam', 'teleport': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_teleport.bam', 'sit': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_sit.bam', 'sad-walk': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_losewalk.bam', 'give-props-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_give-props-start.bam', 'book': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_book.bam', 'running-jump-idle': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zhang.bam', 'scientistEmcee': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistEmcee.bam', 'leverPull': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverPull.bam', 'tutorial-neutral': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_tutorial-neutral.bam', 'badloop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_badloop-putt.bam', 'give-props': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_give-props.bam', 'hold-magnet': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hold-magnet.bam', 'hypnotize': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hypnotize.bam', 'left-point': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_left-point.bam', 'leverReach': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverReach.bam', 'feedPet': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_feedPet.bam', 'reel-H': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reelH.bam', 'applause': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_applause.bam', 'smooch': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_smooch.bam', 'rotateR-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_rotateR-putt.bam', 'fish-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishneutral.bam', 'push': 'phase_9/models/char/tt_a_chr_dgl_shorts_torso_push.bam', 'catch-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gameneutral.bam', 'left': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_left.bam'} self.toonHead = loader.loadModel('phase_3/models/char/horse-heads-1000.bam') otherParts = self.toonHead.findAllMatches('**/*long*') for partNum in range(0, otherParts.getNumPaths()): if not 'muzzle' in str(otherParts.getPath(partNum)): otherParts.getPath(partNum).removeNode() ntrlMuzzle = self.toonHead.find('**/*muzzle*neutral') otherParts = self.toonHead.findAllMatches('**/*muzzle*') for partNum in range(0, otherParts.getNumPaths()): part = otherParts.getPath(partNum) if part != ntrlMuzzle: otherParts.getPath(partNum).removeNode() self.toonTorso = loader.loadModel('phase_3/models/char/tt_a_chr_dgl_shorts_torso_1000.bam') self.toonLegs = loader.loadModel('phase_3/models/char/tt_a_chr_dgs_shorts_legs_1000.bam') otherParts = self.toonLegs.findAllMatches('**/boots*')+self.toonLegs.findAllMatches('**/shoes') for partNum in range(0, otherParts.getNumPaths()): otherParts.getPath(partNum).removeNode() self.toonActor = Actor({'head':self.toonHead, 'torso':self.toonTorso, 'legs':self.toonLegs}, {'torso':torsoAnimDict, 'legs':legsAnimDict}) self.toonActor.setBlend(frameBlend = True) self.toonActor.attach('head', 'torso', 'def_head') self.toonActor.attach('torso', 'legs', 'joint_hips') gloves = self.toonActor.findAllMatches('**/hands') ears = self.toonActor.findAllMatches('**/*ears*') head = self.toonActor.findAllMatches('**/head-*') sleeves = self.toonActor.findAllMatches('**/sleeves') shirt = self.toonActor.findAllMatches('**/torso-top') shorts = self.toonActor.findAllMatches('**/torso-bot') neck = self.toonActor.findAllMatches('**/neck') arms = self.toonActor.findAllMatches('**/arms') legs = self.toonActor.findAllMatches('**/legs') feet = self.toonActor.findAllMatches('**/feet') self.bodyNodes = [] self.bodyNodes += [gloves] self.bodyNodes += [head, ears] self.bodyNodes += [sleeves, shirt, shorts] self.bodyNodes += [neck, arms, legs, feet] self.bodyNodes[0].setColor(1, 1, 1, 1) self.bodyNodes[1].setColor(0.18, 0.54, 0.34, 1) self.bodyNodes[2].setColor(0.18, 0.54, 0.34, 1) self.bodyNodes[3].setColor(1, 1, 1, 1) self.bodyNodes[4].setColor(1, 1, 1, 1) self.bodyNodes[5].setColor(1, 1, 1, 1) self.bodyNodes[6].setColor(0.18, 0.54, 0.34, 1) self.bodyNodes[7].setColor(0.18, 0.54, 0.34, 1) self.bodyNodes[8].setColor(0.18, 0.54, 0.34, 1) self.bodyNodes[9].setColor(0.18, 0.54, 0.34, 1) topTex = loader.loadTexture('phase_4/maps/ContestfishingVestShirt2.jpg') botTex = loader.loadTexture('phase_4/maps/CowboyShorts1.jpg') sleeveTex = loader.loadTexture('phase_4/maps/ContestfishingVestSleeve1.jpg') self.bodyNodes[3].setTexture(sleeveTex, 1) self.bodyNodes[4].setTexture(topTex, 1) self.bodyNodes[5].setTexture(botTex, 1) self.height = 3.2375 self.runNoise = loader.loadSfx('phase_3.5/audio/sfx/AV_footstep_runloop' + base.sfxExt2) self.runNoise.setLoop(True) self.walkNoise = loader.loadSfx('phase_3.5/audio/sfx/AV_footstep_walkloop' + base.sfxExt2) self.walkNoise.setLoop(True) self.loop('neutral') self.toonActor.reparentTo(render) def loop(self, anim): self.runNoise.stop() self.walkNoise.stop() self.toonActor.loop(anim) if anim == 'run': self.runNoise.play() elif anim == 'walk': self.walkNoise.play() def remove(self): self.toonActor.cleanup() self.toonActor.removeNode() del self
class Hobot: max_speed = 0.25 acceleration = 0.5 deceleration = 0.5 def __init__(self, anim_root): self.move_root = base.render.attach_new_node('hobot') self.anim_root = anim_root self.model = Actor('hobot/hobot.bam') self.hand = self.model.expose_joint(None, 'modelRoot', 'hand') head = self.model.expose_joint(None, 'modelRoot', 'head') self.model.reparent_to(self.anim_root) self.model.set_two_sided(True) self.model.find("**/+GeomNode").set_transform( self.model.get_joint_transform_state('modelRoot', 'hobot root').get_inverse()) self.model.set_z(0.1) self.facing = 1.0 self.move_control = self.model.get_anim_control('move_forward') self.speed = 0.0 self.locked = True self.model.wrt_reparent_to(self.move_root) self.model.hide() light_texture = loader.load_texture('hobot/light_on.png') light_texture.set_wrap_u(core.SamplerState.WM_clamp) light_texture.set_wrap_v(core.SamplerState.WM_clamp) cm = core.CardMaker('card') cm.set_frame(-0.15, 0.15, 0.15, 0.45) self.lightbulb = head.attach_new_node(cm.generate()) self.lightbulb.set_texture(light_texture) self.lightbulb.set_attrib( core.ColorBlendAttrib.make(core.ColorBlendAttrib.M_add, core.ColorBlendAttrib.O_incoming_alpha, core.ColorBlendAttrib.O_one)) self.lightbulb.set_depth_test(False) self.lightbulb.set_bin('fixed', 0) self.lightbulb.set_p(-90) self.lightbulb.set_billboard_point_eye() self.lightbulb.set_two_sided(True) self.lightbulb.hide() shadow_texture = loader.load_texture('hobot/drop_shadow.png') shadow_texture.set_wrap_u(core.SamplerState.WM_clamp) shadow_texture.set_wrap_v(core.SamplerState.WM_clamp) cm = core.CardMaker('card') cm.set_frame(-0.35, 0.35, -0.45, -0.1) self.shadow = self.model.attach_new_node(cm.generate()) self.shadow.set_texture(shadow_texture) self.shadow.set_attrib( core.ColorBlendAttrib.make( core.ColorBlendAttrib.M_add, core.ColorBlendAttrib.O_zero, core.ColorBlendAttrib.O_one_minus_incoming_alpha)) self.shadow.set_p(-90) self.shadow.set_depth_write(False) self.shadow.set_x(0.2) self.shadow.set_billboard_point_eye() self.shadow.set_two_sided(True) self.shadow.set_bin('transparent', 0) self.shadow.set_alpha_scale(0) self.shadow_fade = None self.ding_sfx = loader.load_sfx('hobot/sfx/ding.wav') self.ding_sfx.set_volume(0.5) self.move_sfx = loader.load_sfx('hobot/sfx/move.wav') self.move_sfx.set_loop(True) self.action_callback = None def destroy(self): if self.move_control.playing: self.move_control.stop() self.move_sfx.stop() # RIP hobot :-( self.model.cleanup() def set_action(self, callback): self.action_callback = callback if self.lightbulb.is_hidden(): self.ding_sfx.play() self.lightbulb.show() def clear_action(self): self.action_callback = None self.lightbulb.hide() def do_action(self): if self.action_callback: self.action_callback() def lock(self): #self.model.wrt_reparent_to(self.anim_root) self.locked = True self.speed = 0.0 def unlock(self): self.model.set_pos(self.anim_root.get_pos()) self.locked = False self.model.set_hpr(0, 0, -90) self.model.show() def face(self, dir): if dir: self.facing = 1 if dir > 0 else -1 self.model.set_sz(self.facing * -self.model.get_sx()) def process_input(self, input, dt, level): if self.locked: return if input.get_action('interact'): self.do_action() move_x = input.get_axis('move-horizontal') move_y = input.get_axis('move-vertical') if move_x: self.speed += move_x * self.acceleration * dt self.face(move_x) elif self.speed > 0: self.speed = max(0, self.speed - self.deceleration * dt) elif self.speed < 0: self.speed = min(0, self.speed + self.deceleration * dt) delta = core.Vec2(0, 0) if move_y: delta.y = move_y * dt * MOVE_Y_SPEED if self.speed != 0: if self.speed > self.max_speed: self.speed = self.max_speed elif self.speed < -self.max_speed: self.speed = -self.max_speed delta.x = self.speed * dt pos_changed = True self.move_control.set_play_rate(self.speed * self.facing * 4.0) if not self.move_control.playing: self.move_control.loop(False) self.move_sfx.play() elif self.move_control.playing: self.move_control.stop() self.move_sfx.stop() if delta.length_squared() > 0: old_pos = self.model.get_pos() new_pos = level.adjust_move(old_pos.xy, delta) self.model.set_pos(core.LPoint3(new_pos, old_pos.z))
class Boss1(): def __init__(self, common, pos=(0,0,0)): self.common = common common['monsterList'].append(self) id=len(common['monsterList'])-1 self.id=id self.stats={"speed":9, "hp":500, "armor":5 } self.totalSpeed=10 self.sparkSum=0 self.lastMagmaDmg=0 self.DOT=0 self.arrows=set() self.isSolid=True self.node=render.attachNewNode("monster") self.boss=Actor("models/boss1-monster/monster", {"die":"models/boss1-monster/monster-die", "attack1":"models/boss1-monster/monster-doublepunch", "hit":"models/boss1-monster/monster-hit", "idle":"models/boss1-monster/monster-idle", "attack2":"models/boss1-monster/monster-kick", "run":"models/boss1-monster/monster-run", "scream":"models/boss1-monster/monster-scream", "walk":"models/boss1-monster/monster-walk", "rwalk":"models/boss1-monster/monster-walk-right", "lwalk":"models/boss1-monster/monster-walk-left"}) self.boss.setBlend(frameBlend = True) self.boss.setPlayRate(0.8, "walk") self.boss.reparentTo(self.node) self.boss.setScale(1) #self.boss.setH(180.0) #self.boss.setBin("opaque", 10) #tex = loader.loadTexture('models/boss1-monster/creature1Normal.png') #boss1.setTexture(tex, 1) #self.boss.setColor(0.2, 0.0, 0.9, 0.5) self.node.setPos(render,pos) self.rootBone=self.boss.exposeJoint(None, 'modelRoot', 'hips') self.maxHP=self.stats['hp'] self.healthBar=DirectFrame(frameSize=(37, 0, 0, 6), frameColor=(0, 0, 1, 1), frameTexture='icon/glass4.png', parent=pixel2d) self.healthBar.setTransparency(TransparencyAttrib.MDual) self.healthBar.setScale(10,1, 1) #self.healthBar.reparentTo(self.node) wp = base.win.getProperties() winX = wp.getXSize() winY = wp.getYSize() self.healthBar.setPos(71-256+winX/2,0,34-winY) self.healthBar.hide() self.soundID=self.common['soundPool'].get_id() self.common['soundPool'].set_target(self.soundID, self.node) self.traverser=CollisionTraverser("BossTrav"+str(id)) #self.traverser.showCollisions(render) self.queue = CollisionHandlerQueue() #radar collision ray # self.radar=self.node.attachNewNode(CollisionNode('radarRay')) # self.radar.node().addSolid(CollisionRay(0, 0, 1, 0, 90, 0)) # self.radar.node().setIntoCollideMask(BitMask32.allOff()) # self.radar.node().setFromCollideMask(BitMask32.bit(2)) # self.radar.setTag("radar", str(id)) # self.radar.show() # self.traverser.addCollider(self.radar, self.queue) self.coll_body=self.node.attachNewNode(CollisionNode('bossmonsterCollisionNode')) self.coll_body.node().addSolid(CollisionCapsule(0, 0, 0.3, 0, 0, 2, 0.6)) self.coll_body.setTag("id", str(id)) self.coll_body.node().setIntoCollideMask(BitMask32.bit(3)) #self.coll_body.show() self.left_thumb=self.boss.exposeJoint(None, 'modelRoot', 'L_thumb1') #self.right_foot = self.boss.exposeJoint(None, "modelRoot", "R_foot") #self.coll_attack2=self.node.attachNewNode(CollisionNode('bossattack2CollisionNode')) #self.coll_attack2.node().addSolid(CollisionSphere(0, 0, 0, 0.2)) ##self.coll_attack2.setTag("id", str(id)) #self.coll_attack2.node().setIntoCollideMask(BitMask32.bit(3)) #self.coll_attack2.show() #other monster blocking self.coll_quad=loader.loadModel("models/plane") self.coll_quad.reparentTo(self.node) self.state="IDLE" self.previous_state=self.state #self.PC = self.common['PC'] #taskMgr.doMethodLater(.6, self.runCollisions,'collFor'+str(self.id)) taskMgr.doMethodLater(1.0, self.setAI, 'setAITask') taskMgr.doMethodLater(1.0, self.damageOverTime,'DOTfor'+str(self.id)) #taskMgr.add(self.runAI, "BossAIfor"+str(id)) def setAI(self, task): #Creating AI World self.AIworld = AIWorld(render) self.AIchar = AICharacter("pursuer",self.node, 140, 0.05, 7) self.AIworld.addAiChar(self.AIchar) self.AIbehaviors = self.AIchar.getAiBehaviors() self.AIbehaviors.pursue(self.common['PC'].node) # Obstacle avoidance (FIXME) #self.AIbehaviors.obstacleAvoidance(0.0001) #self.AIworld.addObstacle(self.common['map_walls']) #self.AIworld.addObstacle(self.common['map_black']) #AI World update taskMgr.add(self.runAI,"AIUpdate") return task.done def runAI(self, task): #print(self.stats['hp']) #(x,y,z) = self.right_foot.getPos() ## Our model is rotated of 180°, thus we need to move the collision sphere to the opposite directions #self.coll_attack2.setPos(-1*x, -1*y, z) target = self.common['PC'].node if self.state=="DIE": if(self.boss.getCurrentAnim()!="die"): self.common['soundPool'].attachAndPlay(self.boss, "creature_roar_01.ogg") self.boss.play("die") #Check if we have finished the animation if (self.boss.getCurrentFrame() < self.boss.getNumFrames()-1): return task.again else: id = len(self.common["random-objects"]) object = RandomObject(id, self.common, self.node, render, moneyamount=5) self.common["random-objects"].append(object) Interactive(self.common, data.items['key'], self.node.getPos(render)) self.coll_body.node().setIntoCollideMask(BitMask32.allOff()) self.coll_quad.removeNode() Sequence(Wait(2.0),LerpPosInterval(self.node, 2.0, VBase3(self.node.getX(),self.node.getY(),self.node.getZ()-5)),Func(self.destroy)).start() return task.done if self.stats['hp'] < 50: self.AIchar.setMass(self.AIchar.getMass()-20) if (self.state == "HIT"): rn = 0.005 if (type(self.common['PC']).__name__ == "Knight"): rn = 0.4 if (random.random() < rn): if(self.boss.getCurrentAnim()!="hit"): self.boss.play("hit") self.common['soundPool'].attachAndPlay(self.boss, "creature_roar_01.ogg") self.state = "PLAYINGHIT" if (self.state == "PLAYINGHIT"): if (self.boss.getCurrentFrame() == None) or (self.boss.getCurrentFrame() == self.boss.getNumFrames()-1): self.state = self.previous_state return task.again if self.state == "IDLE": if(self.boss.getCurrentAnim()!="idle"): self.boss.play("idle") if self.common['PC'].HP <= 0 or self.node.getDistance(target)>14: self.state="IDLE" self.common['spawner'].monster_limit = 4 else: self.common['spawner'].monster_limit = 2 if self.boss.getAnimControl('scream').isPlaying(): #we must wait until the animation is finished return task.again if (random.random() < 0.001): self.state="SCREAMING" if(self.boss.getCurrentAnim()!="scream"): self.boss.play("scream") self.common['soundPool'].attachAndPlay(self.boss, "awake-the-beast.wav") else: if self.node.getDistance(target)>2: #If the boss is idle or has finished to play an animation (e.g. an attack) he must pursue the player if self.state == "HIT" or self.state == "IDLE" or self.boss.getCurrentAnim() == None: self.state="PURSUING" if self.state == "PURSUING": self.AIworld.update() #self.node.setY(self.node, 1*globalClock.getDt()) if(self.boss.getCurrentAnim()!="walk"): self.common['soundPool'].attachAndPlay(self.boss, "creature_slime_01-2.ogg", 0.7) self.boss.play("walk") else: self.state="ATTACKING" if(self.boss.getCurrentAnim()!="attack2") and (self.boss.getCurrentAnim()!="attack1"): if (type(self.common['PC']).__name__ == "Knight") and (random.random() > 0.1): self.state="IDLE" self.previous_state = self.state return task.again if (random.random() < 0.5): self.boss.play("attack2") self.common['soundPool'].attachAndPlay(self.boss, "Whoosh4.ogg") self.boss.attackdamage = 20 else: self.common['soundPool'].attachAndPlay(self.boss, "explodemini.wav", delay=1) self.boss.play("attack1") self.boss.attackdamage = 30 # Inflict damage only when we played half of the animation (it should be the moment when the attack hits the player) # This function could be called multiple times even if we are at the same frame (probably depends on the frame rate of the animation) # Thus, we should also check if we are seeing the same previous hit (based on the last frame, it must not be the same) elif (self.boss.getCurrentFrame() == int(self.boss.getNumFrames()/2)) and (self.boss.getCurrentFrame() != self.boss.lastFrame): if (self.boss.getCurrentAnim() == "attack1"): #The sound must be played only when the boss hit the floor (it's in the mid of the animation) # Get position of the joint respect to render (i.e. absolute position) (x,y,_) = self.left_thumb.getPos(render) vfx(None, texture='vfx/dust.png',scale=1, Z=0, depthTest=True, depthWrite=True,pos=(x,y,0)).start(0.016) self.common['PC'].hit(self.boss.attackdamage) self.boss.lastFrame = self.boss.getCurrentFrame() self.previous_state = self.state return task.again def doDamage(self, damage, igoreArmor=False): if self.state=="DIE": return if not igoreArmor: damage-=self.stats['armor'] if damage<1: damage=1 #print damage self.stats['hp']-=damage self.healthBar.show() self.healthBar.setScale(10*self.stats['hp']/self.maxHP,1, 1) if self.stats['hp']<1: self.healthBar.hide() def die(self, soundname): #self.common['soundPool'].play(self.soundID, self.sound_names["hit"]) #self.common['soundPool'].play(self.soundID, soundname) self.state="DIE" def onHit(self, damage, sound="hit", weapon=None): if self.state=="DIE": return self.state="HIT" self.doDamage(damage) if self.stats['hp']<1: self.die("die") def damageOverTime(self, task): if self.state=="DIE": return task.done if self.DOT>0: self.doDamage(self.DOT) self.DOT=int((self.DOT*0.9)-1.0) vfx(self.node, texture='vfx/blood_dark.png',scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) return task.again def destroy(self): self.arrows=None if self.boss: self.boss.cleanup() self.boss.removeNode() if taskMgr.hasTaskNamed("BossAIfor"+str(self.id)): taskMgr.remove("BossAIfor"+str(self.id)) # if taskMgr.hasTaskNamed('collFor'+str(self.id)): # taskMgr.remove('collFor'+str(self.id)) if taskMgr.hasTaskNamed('DOTfor'+str(self.id)): taskMgr.remove('DOTfor'+str(self.id)) if taskMgr.hasTaskNamed('AIUpdate'): taskMgr.remove('AIUpdate') if self.node: self.node.removeNode() self.common['monsterList'][self.id]=None self.traverser=None self.queue=None #self.common['traverser'].removeCollider(self.coll_sphere) self.coll_body.removeNode() self.coll_quad.removeNode() self.healthBar.removeNode()
class Suit(Avatar.Avatar): healthColors = (Vec4(0, 1, 0, 1), Vec4(1, 1, 0, 1), Vec4(1, 0.5, 0, 1), Vec4(1, 0, 0, 1), Vec4(0.3, 0.3, 0.3, 1)) healthGlowColors = (Vec4(0.25, 1, 0.25, 0.5), Vec4(1, 1, 0.25, 0.5), Vec4(1, 0.5, 0.25, 0.5), Vec4(1, 0.25, 0.25, 0.5), Vec4(0.3, 0.3, 0.3, 0)) medallionColors = {'c': Vec4(0.863, 0.776, 0.769, 1.0), 's': Vec4(0.843, 0.745, 0.745, 1.0), 'l': Vec4(0.749, 0.776, 0.824, 1.0), 'm': Vec4(0.749, 0.769, 0.749, 1.0)} health2DmgMultiplier = 2.5 def __init__(self): try: self.Suit_initialized return except: self.Suit_initialized = 1 Avatar.Avatar.__init__(self) self.avatarType = CIGlobals.Suit self.name = '' self.chat = '' self.suit = None self.suitHeads = None self.suitHead = None self.loserSuit = None self.healthMeterGlow = None self.healthMeter = None self.weapon = None self.weapon_sfx = None self.anim = None self.suit_dial = None self.shadow = None self.balloon_sfx = None self.add_sfx = None self.explosion = None self.largeExp = None self.smallExp = None self.death_sfx = None self.attack = None self.wtrajectory = None self.throwObjectId = None self.hasSpawned = False self.condition = 0 self.type = "" self.head = "" self.team = "" self.isSkele = 0 self.animFSM = ClassicFSM('Suit', [State('off', self.enterOff, self.exitOff), State('neutral', self.enterNeutral, self.exitNeutral), State('walk', self.enterWalk, self.exitWalk), State('die', self.enterDie, self.exitDie), State('attack', self.enterAttack, self.exitAttack), State('flydown', self.enterFlyDown, self.exitFlyDown), State('pie', self.enterPie, self.exitPie), State('win', self.enterWin, self.exitWin), State('flyaway', self.enterFlyAway, self.exitFlyAway), State('rollodex', self.enterRollodex, self.exitRollodex)], 'off', 'off') animStateList = self.animFSM.getStates() self.animFSM.enterInitialState() self.initializeBodyCollisions() def delete(self): try: self.Suit_deleted except: self.Suit_deleted = 1 if self.suit: self.cleanupSuit() if self.loserSuit: self.cleanupLoserSuit() if self.suitHeads: self.suitHeads.remove() self.suitHeads = None if self.suitHead: self.suitHead.remove() self.suitHead = None if self.healthMeterGlow: self.healthMeterGlow.remove() self.healthMeterGlow = None if self.healthMeter: self.healthMeter.remove() self.healthMeter = None if self.shadow: self.shadow.remove() self.shadow = None self.weapon = None self.weapon_sfx = None self.suit_dial = None del self.shadowPlacer def generateSuit(self, suitType, suitHead, suitTeam, suitHealth, skeleton): self.health = suitHealth self.maxHealth = suitHealth self.generateBody(suitType, suitTeam, suitHead, skeleton) self.generateHealthMeter() self.generateHead(suitType, suitHead) self.setupNameTag() Avatar.Avatar.initShadow(self) def generateBody(self, suitType, suitTeam, suitHead, skeleton): if self.suit: self.cleanupSuit() self.team = suitTeam self.type = suitType self.head = suitHead self.isSkele = skeleton if suitType == "A": if skeleton: self.suit = Actor("phase_5/models/char/cogA_robot-zero.bam") else: self.suit = Actor("phase_3.5/models/char/suitA-mod.bam") self.suit.loadAnims({"neutral": "phase_4/models/char/suitA-neutral.bam", "walk": "phase_4/models/char/suitA-walk.bam", "pie": "phase_4/models/char/suitA-pie-small.bam", "land": "phase_5/models/char/suitA-landing.bam", "throw-object": "phase_5/models/char/suitA-throw-object.bam", "throw-paper": "phase_5/models/char/suitA-throw-paper.bam", "glower": "phase_5/models/char/suitA-glower.bam", "win": "phase_4/models/char/suitA-victory.bam", "rollodex": "phase_5/models/char/suitA-roll-o-dex.bam"}) if suitType == "B": if skeleton: self.suit = Actor("phase_5/models/char/cogB_robot-zero.bam") else: self.suit = Actor("phase_3.5/models/char/suitB-mod.bam") self.suit.loadAnims({"neutral": "phase_4/models/char/suitB-neutral.bam", "walk": "phase_4/models/char/suitB-walk.bam", "pie": "phase_4/models/char/suitB-pie-small.bam", "land": "phase_5/models/char/suitB-landing.bam", "throw-object": "phase_5/models/char/suitB-throw-object.bam", "throw-paper": "phase_5/models/char/suitB-throw-paper.bam", "glower": "phase_5/models/char/suitB-magic1.bam", "win": "phase_4/models/char/suitB-victory.bam", "rollodex": "phase_5/models/char/suitB-roll-o-dex.bam"}) if suitType == "C": if skeleton: self.suit = Actor("phase_5/models/char/cogC_robot-zero.bam") else: self.suit = Actor("phase_3.5/models/char/suitC-mod.bam") self.suit.loadAnims({"neutral": "phase_3.5/models/char/suitC-neutral.bam", "walk": "phase_3.5/models/char/suitC-walk.bam", "pie": "phase_3.5/models/char/suitC-pie-small.bam", "land": "phase_5/models/char/suitC-landing.bam", "throw-object": "phase_3.5/models/char/suitC-throw-paper.bam", "throw-paper": "phase_3.5/models/char/suitC-throw-paper.bam", "glower": "phase_5/models/char/suitC-glower.bam", "win": "phase_4/models/char/suitC-victory.bam"}) if skeleton: self.suit.setTwoSided(1) self.suit.getGeomNode().setScale(CIGlobals.SuitScales[suitHead] / CIGlobals.SuitScaleFactors[suitType]) if skeleton: if suitTeam == "s": self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_sales.jpg") elif suitTeam == "m": self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_money.jpg") elif suitTeam == "l": self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_legal.jpg") elif suitTeam == "c": self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_boss.jpg") self.suit.find('**/tie').setTexture(self.suit_tie, 1) else: self.suit_blazer = loader.loadTexture("phase_3.5/maps/" + suitTeam + "_blazer.jpg") self.suit_leg = loader.loadTexture("phase_3.5/maps/" + suitTeam + "_leg.jpg") self.suit_sleeve = loader.loadTexture("phase_3.5/maps/" + suitTeam + "_sleeve.jpg") self.suit.find('**/legs').setTexture(self.suit_leg, 1) self.suit.find('**/arms').setTexture(self.suit_sleeve, 1) self.suit.find('**/torso').setTexture(self.suit_blazer, 1) if suitHead == "coldcaller": self.suit.find('**/hands').setColor(0.55, 0.65, 1.0, 1.0) elif suitHead == "corporateraider": self.suit.find('**/hands').setColor(0.85, 0.55, 0.55, 1.0) elif suitHead == "bigcheese": self.suit.find('**/hands').setColor(0.75, 0.95, 0.75, 1.0) elif suitHead == "bloodsucker": self.suit.find('**/hands').setColor(0.95, 0.95, 1.0, 1.0) elif suitHead == "spindoctor": self.suit.find('**/hands').setColor(0.5, 0.8, 0.75, 1.0) elif suitHead == "legaleagle": self.suit.find('**/hands').setColor(0.25, 0.25, 0.5, 1.0) elif suitHead == "pennypincher": self.suit.find('**/hands').setColor(1.0, 0.5, 0.6, 1.0) elif suitHead == "loanshark": self.suit.find('**/hands').setColor(0.5, 0.85, 0.75, 1.0) else: self.suit.find('**/hands').setColor(CIGlobals.SuitHandColors[suitTeam]) self.suit.reparentTo(self) def generateHead(self, suitType, suitHead): if self.suitHead: self.cleanupSuitHead() self.type = suitType self.head = suitHead if suitHead == "vp": self.suitHead = Actor("phase_9/models/char/sellbotBoss-head-zero.bam", {"neutral": "phase_9/models/char/bossCog-head-Ff_neutral.bam"}) self.suitHead.setTwoSided(True) self.suitHead.loop("neutral") self.suitHead.setScale(0.35) self.suitHead.setHpr(270, 0, 270) self.suitHead.setZ(-0.10) else: if suitType == "A" or suitType == "B": self.suitHeads = loader.loadModel("phase_4/models/char/suit" + suitType + "-heads.bam") else: self.suitHeads = loader.loadModel("phase_3.5/models/char/suit" + suitType + "-heads.bam") self.suitHead = self.suitHeads.find('**/' + CIGlobals.SuitHeads[suitHead]) if suitHead == "flunky": glasses = self.suitHeads.find('**/glasses') glasses.reparentTo(self.suitHead) glasses.setTwoSided(True) if suitHead in CIGlobals.SuitSharedHeads: if suitHead == "coldcaller": self.suitHead.setColor(0.25, 0.35, 1.0, 1.0) else: headTexture = loader.loadTexture("phase_3.5/maps/" + suitHead + ".jpg") self.suitHead.setTexture(headTexture, 1) if not self.isSkele: self.suitHead.reparentTo(self.suit.find('**/joint_head')) def cleanupSuit(self): if self.shadow: self.shadow.remove() self.shadow = None self.removeHealthBar() self.suit.cleanup() self.suit = None def cleanupSuitHead(self): if self.suitHeads: self.suitHeads.remove() self.suitHeads = None if self.suitHead: self.suitHead.remove() self.suitHead = None def cleanupLoserSuit(self): if self.explosion: self.explosion.remove() self.explosion = None if self.smallExp: self.smallExp = None if self.largeExp: self.largeExp.cleanup() self.largeExp = None if self.loserSuit: self.loserSuit.cleanup() self.loserSuit = None def setName(self, nameString, charName): Avatar.Avatar.setName(self, nameString, avatarType=self.avatarType, charName=charName) def setChat(self, chatString): self.chat = chatString if self.isSkele: if "?" in chatString: self.suit_dial = audio3d.loadSfx("phase_5/audio/sfx/Skel_COG_VO_question.ogg") elif "!" in chatString: self.suit_dial = audio3d.loadSfx("phase_5/audio/sfx/Skel_COG_VO_grunt.ogg") else: self.suit_dial = audio3d.loadSfx("phase_5/audio/sfx/Skel_COG_VO_statement.ogg") elif self.head == "vp": if "?" in chatString: self.suit_dial = audio3d.loadSfx("phase_9/audio/sfx/Boss_COG_VO_question.ogg") elif "!" in chatString: self.suit_dial = audio3d.loadSfx("phase_9/audio/sfx/Boss_COG_VO_grunt.ogg") else: self.suit_dial = audio3d.loadSfx("phase_9/audio/sfx/Boss_COG_VO_statement.ogg") else: if "?" in chatString: self.suit_dial = audio3d.loadSfx("phase_3.5/audio/dial/COG_VO_question.ogg") elif "!" in chatString: self.suit_dial = audio3d.loadSfx("phase_3.5/audio/dial/COG_VO_grunt.ogg") else: self.suit_dial = audio3d.loadSfx("phase_3.5/audio/dial/COG_VO_statement.ogg") if self.isSkele: audio3d.attachSoundToObject(self.suit_dial, self.suit) else: audio3d.attachSoundToObject(self.suit_dial, self.suitHead) self.suit_dial.play() Avatar.Avatar.setChat(self, chatString) def generateHealthMeter(self): self.removeHealthBar() model = loader.loadModel("phase_3.5/models/gui/matching_game_gui.bam") button = model.find('**/minnieCircle') button.setScale(3.0) button.setH(180) button.setColor(self.healthColors[0]) chestNull = self.suit.find('**/def_joint_attachMeter') if chestNull.isEmpty(): chestNull = self.suit.find('**/joint_attachMeter') button.reparentTo(chestNull) self.healthBar = button glow = loader.loadModel("phase_3.5/models/props/glow.bam") glow.reparentTo(self.healthBar) glow.setScale(0.28) glow.setPos(-0.005, 0.01, 0.015) glow.setColor(self.healthGlowColors[0]) button.flattenLight() self.healthBarGlow = glow self.condition = 0 def updateHealthBar(self, hp): if hp > self.hp: self.hp = hp self.hp -= hp health = float(self.health) / float(self.maxHP) if health > 0.95: condition = 0 elif health > 0.7: condition = 1 elif health > 0.3: condition = 2 elif health > 0.05: condition = 3 elif health > 0.0: condition = 4 else: condition = 5 if self.condition != condition: if condition == 4: blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.75), Task(self.__blinkGray), Task.pause(0.1)) taskMgr.add(blinkTask, self.taskName('blink-task')) elif condition == 5: if self.condition == 4: taskMgr.remove(self.taskName('blink-task')) blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.25), Task(self.__blinkGray), Task.pause(0.1)) taskMgr.add(blinkTask, self.taskName('blink-task')) else: self.healthBar.setColor(self.healthColors[condition], 1) self.healthBarGlow.setColor(self.healthGlowColors[condition], 1) self.condition = condition def __blinkRed(self, task): self.healthBar.setColor(self.healthColors[3], 1) self.healthBarGlow.setColor(self.healthGlowColors[3], 1) if self.condition == 5: self.healthBar.setScale(1.17) return Task.done def __blinkGray(self, task): if not self.healthBar: return self.healthBar.setColor(self.healthColors[4], 1) self.healthBarGlow.setColor(self.healthGlowColors[4], 1) if self.condition == 5: self.healthBar.setScale(1.0) return Task.done def removeHealthBar(self): if self.healthMeter: self.healthBar.removeNode() self.healthBar = None if self.condition == 4 or self.condition == 5: taskMgr.remove(self.taskName('blink-task')) self.healthCondition = 0 return def enterOff(self): self.anim = None return def exitOff(self): pass def exitGeneral(self): self.suit.stop() def enterNeutral(self): self.suit.loop("neutral") def exitNeutral(self): self.exitGeneral() def enterRollodex(self): self.suit.play("rollodex") def exitRollodex(self): self.exitGeneral() def enterWalk(self): self.suit.loop("walk") def exitWalk(self): self.exitGeneral() def generateLoserSuit(self): self.cleanupLoserSuit() if self.type == "A": if self.isSkele: self.loserSuit = Actor("phase_5/models/char/cogA_robot-lose-mod.bam") else: self.loserSuit = Actor("phase_4/models/char/suitA-lose-mod.bam") self.loserSuit.loadAnims({"lose": "phase_4/models/char/suitA-lose.bam"}) if self.type == "B": if self.isSkele: self.loserSuit = Actor("phase_5/models/char/cogB_robot-lose-mod.bam") else: self.loserSuit = Actor("phase_4/models/char/suitB-lose-mod.bam") self.loserSuit.loadAnims({"lose": "phase_4/models/char/suitB-lose.bam"}) if self.type == "C": if self.isSkele: self.loserSuit = Actor("phase_5/models/char/cogC_robot-lose-mod.bam") else: self.loserSuit = Actor("phase_3.5/models/char/suitC-lose-mod.bam") self.loserSuit.loadAnims({"lose": "phase_3.5/models/char/suitC-lose.bam"}) if self.isSkele: self.loserSuit.find('**/tie').setTexture(self.suit_tie, 1) self.loserSuit.setTwoSided(1) else: self.loserSuit.find('**/hands').setColor(self.suit.find('**/hands').getColor()) self.loserSuit.find('**/legs').setTexture(self.suit_leg, 1) self.loserSuit.find('**/arms').setTexture(self.suit_sleeve, 1) self.loserSuit.find('**/torso').setTexture(self.suit_blazer, 1) self.loserSuit.getGeomNode().setScale(self.suit.getScale()) self.loserSuit.reparentTo(self) if not self.isSkele: self.suitHead.reparentTo(self.loserSuit.find('**/joint_head')) self.loserSuit.setPos(self.suit.getPos(render)) self.loserSuit.setHpr(self.suit.getHpr(render)) self.cleanupSuit() Avatar.Avatar.initShadow(self, self.avatarType) self.loserSuit.reparentTo(render) def enterDie(self): self.generateLoserSuit() self.state = "dead" self.loserSuit.play("lose") spinningSound = base.loadSfx("phase_3.5/audio/sfx/Cog_Death.ogg") deathSound = base.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg") #audio3d.attachSoundToObject(spinningSound, self.loserSuit) #audio3d.attachSoundToObject(deathSound, self.loserSuit) Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.4, node=self.loserSuit), SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=2.0, node=self.loserSuit), SoundInterval(deathSound, volume=0.32, node=self.loserSuit)).start() Sequence(Wait(0.8), Func(self.smallDeathParticles), Wait(4.2), Func(self.suitExplode), Wait(1.0), Func(self.delSuit)).start() def smallDeathParticles(self): self.smallExp = ParticleLoader.loadParticleEffect("phase_3.5/etc/gearExplosionSmall.ptf") self.smallExp.start(self.loserSuit) def suitExplode(self): self.smallExp.cleanup() self.largeExp = ParticleLoader.loadParticleEffect("phase_3.5/etc/gearExplosion.ptf") self.largeExp.start(self.loserSuit) self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam") self.explosion.setScale(0.5) self.explosion.reparentTo(render) self.explosion.setBillboardPointEye() if self.isSkele: self.explosion.setPos(self.loserSuit.find('**/joint_head').getPos(render) + (0, 0, 2)) else: self.explosion.setPos(self.suitHead.getPos(render) + (0,0,2)) def delSuit(self): self.cleanupLoserSuit() self.disableBodyCollisions() def exitDie(self): pass def enterFlyDown(self): self.fd_sfx = audio3d.loadSfx("phase_5/audio/sfx/ENC_propeller_in.ogg") self.prop = Actor("phase_4/models/props/propeller-mod.bam", {"chan": "phase_4/models/props/propeller-chan.bam"}) audio3d.attachSoundToObject(self.fd_sfx, self.prop) self.fd_sfx.play() self.prop.reparentTo(self.suit.find('**/joint_head')) propTrack = Sequence(Func(self.prop.loop, 'chan', fromFrame=0, toFrame=3), Wait(1.75), Func(self.prop.play, 'chan', fromFrame=3)) propTrack.start() if not self.hasSpawned: showSuit = Task.sequence(Task(self.hideSuit), Task.pause(0.3), Task(self.showSuit)) taskMgr.add(showSuit, "showsuit") self.hasSpawned = True dur = self.suit.getDuration('land') suitTrack = Sequence(Func(self.suit.pose, 'land', 0), Wait(1.9), ActorInterval(self.suit, 'land', duration=dur)) suitTrack.start() def hideSuit(self, task): self.hide() return Task.done def showSuit(self, task): self.show() fadeIn = Sequence(Func(self.setTransparency, 1), self.colorScaleInterval(0.6, colorScale=Vec4(1,1,1,1), startColorScale=Vec4(1,1,1,0)), Func(self.clearColorScale), Func(self.clearTransparency), Func(self.reparentTo, render)) fadeIn.start() return Task.done def initializeLocalCollisions(self, name): Avatar.Avatar.initializeLocalCollisions(self, 1, 3, name) def initializeBodyCollisions(self): Avatar.Avatar.initializeBodyCollisions(self, self.avatarType, 2.25, 1, 4, 2) self.initializeRay(self.avatarType) self.collTube.setTangible(0) def deleteBean(self): if self.bean: self.bean.remove_node() self.bean = None def createJellyBean(self): self.deleteBean() money = int(self.maxHP / CIGlobals.SuitAttackDamageFactors['clipontie']) if money == 1: self.bean = loader.loadModel("phase_5.5/models/estate/jellyBean.bam") self.bean.set_two_sided(True) random_r = random.uniform(0, 1) random_g = random.uniform(0, 1) random_b = random.uniform(0, 1) self.bean.set_color(random_r, random_g, random_b, 1) else: self.bean = loader.loadModel("phase_5.5/models/estate/jellybeanJar.bam") self.bean.reparent_to(render) self.bean.set_pos(self.get_pos(render) + (0, 0, 1)) bean_int = self.bean.hprInterval(1, Point3(360, 0, 0), startHpr=(0, 0, 0)) bean_int.loop() def exitFlyDown(self): audio3d.detachSound(self.fd_sfx) self.prop.cleanup() self.prop = None def enterFlyAway(self): self.fa_sfx = audio3d.loadSfx("phase_5/audio/sfx/ENC_propeller_out.ogg") self.prop = Actor("phase_4/models/props/propeller-mod.bam", {"chan": "phase_4/models/props/propeller-chan.bam"}) audio3d.attachSoundToObject(self.fa_sfx, self.prop) self.fa_sfx.play() self.prop.reparentTo(self.suit.find('**/joint_head')) self.prop.setPlayRate(-1.0, "chan") propTrack = Sequence(Func(self.prop.play, 'chan', fromFrame=3), Wait(1.75), Func(self.prop.play, 'chan', fromFrame=0, toFrame=3)) propTrack.start() self.suit.setPlayRate(-1.0, 'land') self.suit.play('land') def exitFlyAway(self): audio3d.detachSound(self.fa_sfx) self.prop.cleanup() self.prop = None def enterAttack(self, attack): self.attack = attack self.weapon_state = 'start' if attack == "canned": self.weapon = loader.loadModel("phase_5/models/props/can.bam") self.weapon.setScale(15) self.weapon.setR(180) self.wss = CollisionSphere(0,0,0,0.05) elif attack == "clipontie": self.weapon = loader.loadModel("phase_5/models/props/power-tie.bam") self.weapon.setScale(4) self.weapon.setR(180) self.wss = CollisionSphere(0,0,0,0.2) elif attack == "sacked": self.weapon = loader.loadModel("phase_5/models/props/sandbag-mod.bam") self.weapon.setScale(2) self.weapon.setR(180) self.weapon.setP(90) self.weapon.setY(-2.8) self.weapon.setZ(-0.3) self.wss = CollisionSphere(0,0,0,1) elif attack == "playhardball": self.weapon = loader.loadModel("phase_5/models/props/baseball.bam") self.weapon.setScale(10) self.wss = CollisionSphere(0,0,0,0.1) self.weapon.setZ(-0.5) elif attack == "marketcrash": self.weapon = loader.loadModel("phase_5/models/props/newspaper.bam") self.weapon.setScale(3) self.weapon.setPos(0.41, -0.06, -0.06) self.weapon.setHpr(90, 0, 270) self.wss = CollisionSphere(0,0,0,0.35) elif attack == "glowerpower": self.weapon = loader.loadModel("phase_5/models/props/dagger.bam") self.wss = CollisionSphere(0,0,0,1) else: notify.warning("unknown attack!") self.throwObjectId = random.uniform(0, 101010101010) if attack == "canned" or attack == "playhardball": self.weapon.reparentTo(self.suit.find('**/joint_Rhold')) if self.type == "C": taskMgr.doMethodLater(2.2, self.throwObject, "throwObject" + str(self.throwObjectId)) else: taskMgr.doMethodLater(3, self.throwObject, "throwObject" + str(self.throwObjectId)) self.suit.play("throw-object") elif attack == "clipontie" or attack == "marketcrash" or attack == "sacked": self.weapon.reparentTo(self.suit.find('**/joint_Rhold')) if self.type == "C": taskMgr.doMethodLater(2.2, self.throwObject, "throwObject" + str(self.throwObjectId)) else: taskMgr.doMethodLater(3, self.throwObject, "throwObject" + str(self.throwObjectId)) self.suit.play("throw-paper") elif attack == "glowerpower": taskMgr.doMethodLater(1, self.throwObject, "throwObject" + str(self.throwObjectId)) self.suit.play("glower") self.weaponSensorId = random.uniform(0, 1010101010101001) wsnode = CollisionNode('weaponSensor' + str(self.weaponSensorId)) wsnode.addSolid(self.wss) self.wsnp = self.weapon.attachNewNode(wsnode) if attack == "sacked": self.wsnp.setZ(1) elif attack == "marketcrash": self.wsnp.setPos(-0.25, 0.3, 0) def delWeapon(self, task): if self.weapon: self.weapon.removeNode() self.weapon = None return task.done def interruptAttack(self): if self.wtrajectory: if self.wtrajectory.isStopped(): if self.weapon: self.weapon.removeNode() self.weapon = None if self.throwObjectId: taskMgr.remove("throwObject" + str(self.throwObjectId)) def handleWeaponTouch(self): if not self.attack == "glowerpower" or not self.attack == "clipontie": if self.weapon_sfx: self.weapon_sfx.stop() try: self.wtrajectory.pause() except: pass if self.weapon: self.weapon.removeNode() self.weapon = None def weaponCollisions(self): self.wsnp.setCollideMask(BitMask32(0)) self.wsnp.node().setFromCollideMask(CIGlobals.EventBitmask) event = CollisionHandlerEvent() event.setInPattern("%fn-into") event.setOutPattern("%fn-out") base.cTrav.addCollider(self.wsnp, event) def throwObject(self, task): self.playWeaponSound() self.weaponNP = NodePath("weaponNP") self.weaponNP.setScale(render, 1) try: self.weaponNP.reparentTo(self.find('**/joint_nameTag')) except: return task.done self.weaponNP.setPos(0, 50, 0) self.weaponNP.setHpr(0, 0, 0) if self.weapon: self.weapon.setScale(self.weapon.getScale(render)) try: self.weapon.reparentTo(render) except: return task.done self.weapon.setPos(0,0,0) self.weapon.setHpr(0,0,0) if self.attack == "glowerpower": self.weapon.setH(self.weaponNP.getH(render)) self.wtrajectory = self.weapon.posInterval(0.5, Point3(self.weaponNP.getPos(render)), startPos=(self.getX(render), self.getY(render) + 3, self.find('**/joint_head').getZ(render))) self.wtrajectory.start() else: self.wtrajectory = ProjectileInterval(self.weapon, startPos = (self.suit.find('**/joint_Rhold').getPos(render)), endPos = self.weaponNP.getPos(render), gravityMult = 0.7, duration = 1) self.wtrajectory.start() if self.attack == "glowerpower": taskMgr.doMethodLater(0.5, self.delWeapon, "delWeapon") else: taskMgr.doMethodLater(1, self.delWeapon, "delWeapon") self.weapon_state = 'released' def playWeaponSound(self): if self.attack == "glowerpower": self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_glower_power.ogg") elif self.attack == "canned": self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg") elif self.attack == "clipontie": self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_powertie_throw.ogg") elif self.attack == "sacked": self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg") elif self.attack == "playhardball": self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg") elif self.attack == "marketcrash": self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg") if self.weapon: audio3d.attachSoundToObject(self.weapon_sfx, self.weapon) self.weapon_sfx.play() def exitAttack(self): pass def enterPie(self): self.suit.play("pie") def exitPie(self): self.exitGeneral() def enterWin(self): self.suit.play("win") def exitWin(self): self.exitGeneral()
class PartyCog(FSM): notify = directNotify.newCategory('PartyCog') HpTextGenerator = TextNode('HpTextGenerator') hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed=3, bounceHeight=1, rotateSpeed=1, heightShift=1, xMoveSpeed=0, xMoveDistance=0, bounceOffset=0): self.id = id FSM.__init__(self, 'PartyCogFSM-%d' % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request('Down') return def load(self): self.root = NodePath('PartyCog-%d' % self.id) self.root.reparentTo(self.parentNode) path = 'phase_13/models/parties/cogPinata_' self.actor = Actor( path + 'actor', { 'idle': path + 'idle_anim', 'down': path + 'down_anim', 'up': path + 'up_anim', 'bodyHitBack': path + 'bodyHitBack_anim', 'bodyHitFront': path + 'bodyHitFront_anim', 'headHitBack': path + 'headHitBack_anim', 'headHitFront': path + 'headHitFront_anim' }) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode('temphead') self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.ogg') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg') self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole') self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin('ground', 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request('Off') self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound return def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id) def exitActive(self): taskMgr.remove('PartyCog.update-%d' % self.id) taskMgr.remove('PartyCog.bounceTask-%d' % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3( self.root.getH(), 0.0, 0.0), blendType='easeInOut') self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == 'Off': downAnimControl = self.actor.getAnimControl('down') self.actor.pose('down', downAnimControl.getNumFrames() - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'down', loop=0)), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'up', loop=0)), Func(self.actor.loop, 'idle'), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def filterDown(self, request, args): if request == 'Down': return None else: return self.defaultFilter(request, args) return None def setEndPoints(self, start, end, amplitude=1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin( t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id) def bounce(self, task): self.root.setZ( math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot=False, direction=1.0): if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() return def __showSplat(self, position, direction, hot=False): if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = 'HitFront' else: facing = 'HitBack' else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) if self.currentFacing > 0.0: facing = 'HitBack' else: facing = 'HitFront' if hot: targetscale = 0.75 part = 'head' else: targetscale = 0.5 part = 'body' def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence( ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, 'idle')) self.hitInterval.start() self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence( Func(self.splat.showThrough), Parallel( Sequence( LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Wait(0.175)), Sequence( Wait(0.1), LerpFunc(setSplatAlpha, duration=1.0, fromData=1.0, toData=0.0, blendType='easeOut'))), Func(self.splat.cleanup), Func(self.splat.removeNode))) self.kaboomTrack.start() return def showHitScore(self, number, scale=1): if number <= 0: return if self.hpText: self.hideHitScore() self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText('+' + str(number)) self.HpTextGenerator.clearShadow() self.HpTextGenerator.setAlign(TextNode.ACenter) r = 1 g = 1 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) self.hpText.setBillboardPointEye() self.hpText.setBin('fixed', 100) self.hpText.setPos(self.root, 0, 0, self.height / 2) seq = Task.sequence( self.hpText.lerpPos(Point3( self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), 0.25, blendType='easeOut'), Task.pause(0.25), self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), Task.Task(self.__hideHitScoreTask)) taskMgr.add(seq, 'PartyCogHpText' + str(self.id)) def __hideHitScoreTask(self, task): self.hideHitScore() return Task.done def hideHitScore(self): if self.hpText: taskMgr.remove('PartyCogHpText' + str(self.id)) self.hpText.removeNode() self.hpText = None return def getHeadLocation(self): self.actor.getJoints(jointName='head')[0].getNetTransform( self.temp_transform) self.head_locator.setMat(self.temp_transform) return self.head_locator.getZ(self.root)
class Enemy3(object): def __init__(self,game,spawnloc = (0,0,0),name = "Enemy-0-0"): self.health = 20 self.value = 2000 self.maxspeed = 10 self.name = name # Load the enemy model and set the initial position of it self.loadModel() self.actor.setPos(spawnloc) self.enemy_start_pos = spawnloc self.safepos = (0,0,0) #Set the clock stuff self.dt = game.player.dt self.cTrav = CollisionTraverser() # Enemy Rays self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,100) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.actor.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) #self.ralphGroundColNp.show() self.pursue_start = False self.evade_start = False self.timer = 300 self.fire_rate = 60 # Collision stuff for bullets #self.cTrav = CollisionTraverser() self.cHandler = CollisionHandlerQueue() self.cSphere = CollisionSphere(0,0,4, 8) self.cNode = CollisionNode("Enemy") self.cNodePath = self.actor.attachNewNode(self.cNode) self.cNodePath.node().addSolid(self.cSphere) #self.cNodePath.show() self.cTrav.addCollider(self.cNodePath, self.cHandler) #self.heightTask = taskMgr.add(self.updateHeight,'EnemyHeight',extraArgs=[game]) def take_damage(self, damage): """ Cause an enemy to take damage. Negative health means object is immortal (negative damage kills anything instantly) """ if damage < 0: self.health = 0 return self.value if self.health > 0: self.health -= damage if self.health <= 0: self.health = 0 return self.value return 0 def loadModel(self): self.actor = Actor("models/hummer",{'tread':'models/hummer'}) self.actor.setPlayRate(2.0,'tread') self.actor.setH(self.actor.getH() - 90) self.actor.reparentTo(render) self.actor.setScale(0.25) def distanceToTarget(self): return math.sqrt((self.actor.getX() - self.target.getX())**2 + (self.actor.getY() - self.target.getY())**2 )#+ (self.actor.getZ() - self.target.getZ())) def setupAI(self, target): """ Start the enemy's AI """ self.target = target self.AIchar = AICharacter(self.name,self.actor,100,0.5,self.maxspeed) self.AIbehaviors = self.AIchar.getAiBehaviors() self.AIbehaviors.evade(self.target,2,10,1.0) self.AIbehaviors.pursue(self.target,1.0) self.AIbehaviors.wander(4,3,100,0.5) self.pause_e() self.resume_e() self.actor.loop("tread") return self.AIchar def updateAI(self,game): self.pause_e() if self.distanceToTarget() > 40 or self.pursue_start: self.pursue_start = True self.evade_start = False self.AIbehaviors.pursue(game.player.actor,1.0) else: self.pursue_start = False self.evade_start = True self.AIbehaviors.flee(game.player.actor,30,10,0.5) if self.distanceToTarget() <= 14: self.pursue_start = False if self.distanceToTarget() > 100: self.evade_start = False self.resume_e() def updateHeight(self,game): startpos = self.actor.getPos() self.updateAI(game) self.fire(game) self.cTrav.traverse(render) entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) if entry.getIntoNode().getName() != "Enemy": entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.actor.setZ(entries[0].getSurfacePoint(render).getZ()+0) self.safepos = self.actor.getPos() else: self.actor.setPos(self.safepos) self.actor.setHpr(self.actor.getH(),0,0) self.actor.setH(self.actor.getH() - 90) # Check boundaries and bullets for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) if entry.getIntoNode().getName() == "fence_c" or entry.getIntoNode().getName() == "debris": self.actor.setPos(self.safepos) self.pause_e() self.resume_e() if entry.getIntoNode().getName() == "ball": #print "hit: ball" self.health -= 10 if entry.getIntoNode().getName() == "shotgun_bullet": #print "hit: shotgun" self.health -= 12 if entry.getIntoNode().getName() == "mortar": #print "hit: mortar" self.health -= 20 # Keep enemy within bounds (HACK) edge = 43 if self.actor.getX() > edge: self.actor.setPos(edge,self.actor.getY(),self.actor.getZ()) if self.actor.getX() < -edge: self.actor.setPos(-edge,self.actor.getY(),self.actor.getZ()) if self.actor.getY() < -edge: self.actor.setPos(self.actor.getX(),-edge,self.actor.getZ()) if self.actor.getY() > edge: self.actor.setPos(self.actor.getX(),edge,self.actor.getZ()) if self.health <= 0: game.score += self.value game.explosions_handler.Small_Explosion(self.actor.getPos()) #self.die() #AI Controls def pause_e(self): self.AIbehaviors.pauseAi("pursue") self.AIbehaviors.pauseAi("evade") self.AIbehaviors.pauseAi("flee") self.AIbehaviors.pauseAi("wander") def resume_e(self): self.AIbehaviors.resumeAi("wander") def fire(self,game): # Get the angle between current heading and that looking directly at the player h1 = self.actor.getH() self.actor.lookAt(game.player.actor) h2 = self.actor.getH() h = math.fabs(h1 - h2) - 180 # Firing angle and fire rate code if math.fabs(h) < 20 and self.timer <= 0: ## Put firing code here b1 = bullets.Bullet(self,game,True,manoffset=(5,11,2)) b2 = bullets.Bullet(self,game,True,manoffset=(5,11,2)) b3 = bullets.Bullet(self,game,True,manoffset=(5,11,2)) b4 = bullets.Bullet(self,game,True,manoffset=(5,11,2)) b5 = bullets.Bullet(self,game,True,manoffset=(5,11,2)) b1.bulletNP.setH(b1.bulletNP.getH() + 90) b2.bulletNP.setH(b2.bulletNP.getH() + 90) b3.bulletNP.setH(b3.bulletNP.getH() + 90) b4.bulletNP.setH(b4.bulletNP.getH() + 90) b5.bulletNP.setH(b5.bulletNP.getH() + 90) self.timer = self.fire_rate else: self.timer -= 1 self.actor.setH(h1) hpr = self.actor.getHpr() def die(self,game): game.AIworld.removeAiChar(self.name) self.actor.cleanup() self.actor.removeNode()
class GameObject(): def __init__(self, pos, modelName, modelAnims, maxHealth, maxSpeed, colliderName): self.actor = Actor(modelName, modelAnims) self.actor.reparentTo(render) self.actor.setPos(pos) self.maxHealth = maxHealth self.health = maxHealth self.maxSpeed = maxSpeed self.velocity = Vec3(0, 0, 0) self.acceleration = 300.0 self.walking = False colliderNode = CollisionNode(colliderName) colliderNode.addSolid(CollisionSphere(0, 0, 0, 0.3)) self.collider = self.actor.attachNewNode(colliderNode) self.collider.setPythonTag("owner", self) def update(self, dt): # If we're going faster than our maximum speed, # set the velocity-vector's length to that maximum speed = self.velocity.length() if speed > self.maxSpeed: self.velocity.normalize() self.velocity *= self.maxSpeed speed = self.maxSpeed # If we're walking, don't worry about friction. # Otherwise, use friction to slow us down. if not self.walking: frictionVal = FRICTION*dt if frictionVal > speed: self.velocity.set(0, 0, 0) else: frictionVec = -self.velocity frictionVec.normalize() frictionVec *= frictionVal self.velocity += frictionVec # Move the character, using our velocity and # the time since the last update. self.actor.setPos(self.actor.getPos() + self.velocity*dt) def alterHealth(self, dHealth): self.health += dHealth if self.health > self.maxHealth: self.health = self.maxHealth # Remove various nodes, and clear the Python-tag--see below! def cleanup(self): if self.collider is not None and not self.collider.isEmpty(): self.collider.clearPythonTag("owner") base.cTrav.removeCollider(self.collider) base.pusher.removeCollider(self.collider) if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None self.collider = None
class Enemy(Creature): def __init__(self, mainReference, name, position, regionID): super(Enemy, self).__init__(mainReference) # unique enemy name self.name = name # If enemy is alive self.alive = True # enemy's pursue speed P-units/s self.speed = 2.9 # enemy's rotation speed angles/s self.rotSpeed = 10 # enemy's current convex region; for pursue purposes self.currentRegionID = regionID # Hit Points of each part of zombie self.hitPoints = {'leg_lr':2, 'leg_ll':2, 'arm_lr':2, 'arm_ll':2} self.lifePoints = 100 # enemy NodePath self.enemyNP = self.mainRef.render.attachNewNode(self.name) self.enemyNP.setPos(position) # the name of the task the zombie is currently performing self.enemyActiveState = "" self.isEnemyAttacking = False # the cross point of the portal that the zombie is trying to cross self.currentCrossPointGoal = None # the time that the enemy will spend confused self.lostTargetTotalTime = 1.0 self.lostTargetTimer = self.lostTargetTotalTime # load our zombie self.enemyModel = Actor("../../models/model_zombie/zombie",{ 'walk':'../../models/model_zombie/zombie-walk', 'attack':'../../models/model_zombie/zombie-attack', }) # ****SCALE**** self.enemyModel.setScale(0.55) # ****SCALE**** #enemy's character controller self.enemyBody = CharacterBody(self.mainRef, self.enemyNP.getPos(), 0.38, 0.5 ) self.enemyBody.charBodyNP.reparentTo(self.enemyNP) # load the zombie's bounding boxes self.enemyBB = loader.loadModel("../../models/model_zombie/zombieBB") global bodyParts bodyParts = ['head', 'leg_ur', 'leg_ul', 'leg_lr', 'leg_ll', 'torso', 'arm_ur', 'arm_ul', 'arm_lr', 'arm_ll'] # List of the bullet nodes for this enemy, to be removed later self.bulletNodes = {} self.partNodes = {} # Get Joints self.joints = {} #for bodyPart in ['leg_lr', 'leg_ll', 'arm_lr', 'arm_ll']: # # Get joint control structure # self.joints[bodyPart] = self.enemyModel.controlJoint(None, 'modelRoot', bodyPart) # getting 1 by 1 and attaching them to their corresponding bones for bodyPart in bodyParts: self.bodyPartShape = BulletConvexHullShape() self.bodyPartShape.addGeom(self.enemyBB.getChild(0).find(bodyPart).node().getGeom(0)) self.bulletbodyPartNode = BulletRigidBodyNode(bodyPart+"_"+name) self.bulletbodyPartNode.addShape(self.bodyPartShape) self.bodyPartNode = self.mainRef.render.attachNewNode(self.bulletbodyPartNode) # ****SCALE**** self.bodyPartNode.setScale(0.55) # ****SCALE**** self.mainRef.world.attachRigidBody(self.bulletbodyPartNode) self.bodyPartNode.setCollideMask( BitMask32.bit( 2 ) ) self.bodyPartNode.wrtReparentTo(self.enemyModel.exposeJoint(None,"modelRoot",bodyPart)) self.bulletNodes[bodyPart] = self.bulletbodyPartNode self.partNodes[bodyPart] = self.bodyPartNode # uncomment to use triangleMesh instead of convexHull # mesh = BulletTriangleMesh() # mesh.addGeom(self.enemyBB.getChild(0).find(bodyPart).node().getGeom(0)) # self.bodyPartShape = BulletTriangleMeshShape(mesh, dynamic=True) # # self.bulletbodyPartNode = BulletRigidBodyNode(bodyPart) # self.bulletbodyPartNode.addShape(self.bodyPartShape) # # self.bodyPartNode = self.mainRef.render.attachNewNode(self.bulletbodyPartNode) # self.mainRef.world.attachRigidBody(self.bulletbodyPartNode) # # self.bodyPartNode.wrtReparentTo(self.enemyModel.exposeJoint(None,"modelRoot",bodyPart)) # initial path must be calculated self.updatePath() # adding a task to check if the enemy is leaving their region self.checkIfChangedRegionName = self.name + "cicr" self.oldPosition = self.enemyNP.getPos() taskMgr.add(self.checkIfChangedRegion, self.checkIfChangedRegionName) # walk loop # self.enemyModel.loop("walk") self.enemyModel.loop("walk") # attaching to render self.enemyModel.reparentTo(self.enemyNP) self.enemyModel.setPos(0,0,-0.51) # loading enemy roar sound zombieRoar = [None,None,None,None] for i in range( len(zombieRoar) ): zombieRoar[i] = self.mainRef.audio3d.loadSfx('../../sounds/zombie_roar_' + str(i+1) + '.mp3') # initialize first zombie roar self.zombieRoarFX = zombieRoar[0] self.mainRef.audio3d.attachSoundToObject(self.zombieRoarFX, self.enemyNP) self.zombieRoarFX.play() # random zombie roar def roarSort(task): if(self.zombieRoarFX.status() != self.zombieRoarFX.PLAYING): random.seed() value = random.choice(range(3)) self.zombieRoarFX = zombieRoar[value] self.mainRef.audio3d.attachSoundToObject(self.zombieRoarFX, self.enemyNP) self.zombieRoarFX.play() return task.again self.mainRef.taskMgr.doMethodLater(2, roarSort,self.name+'roar sort') def hide(self): self.enemyModel.hide() def show(self): self.mainRef.world.attachRigidBody(self.enemyBulletNode) self.enemyModel.show() self.enemyModel.loop("walk") def setNewCourse(self): # Simply follow the player if (len(self.portalsPathList) == 0): taskMgr.remove( self.enemyActiveState ) self.enemyActiveState = self.name + "pt" taskMgr.add(self.pursueTargetStep, self.enemyActiveState) # Go to the cross point that makes you closer to your target elif (self.portalsPathList[0].connectedRegionsIDs[0] == self.mainRef.player.currentRegionID or self.portalsPathList[0].connectedRegionsIDs[1] == self.mainRef.player.currentRegionID): self.setOptimalCrossPoint() taskMgr.remove( self.enemyActiveState ) self.enemyActiveState = self.name + "htp" taskMgr.add(self.headToPortalStep, self.enemyActiveState) # Go to the middle cross point else: self.currentCrossPointGoal = self.portalsPathList[0].middleCrossPoint taskMgr.remove( self.enemyActiveState ) self.enemyActiveState = self.name + "htp" taskMgr.add(self.headToPortalStep, self.enemyActiveState) # ======================================================================== # ======================== STATE MACHINE METHODS ========================== def pursueTargetStep(self, task): if (self.mainRef.player.currentRegionID == self.currentRegionID): if ( self.mainRef.player.playerNP.getPos(self.enemyNP).length() < 4.0): if (not self.isEnemyAttacking): self.speed += 1.0 self.isEnemyAttacking = True self.enemyModel.loop("attack") elif (self.isEnemyAttacking): self.speed -= 1.0 self.isEnemyAttacking = False self.enemyModel.loop("walk") targetDirection = Vec2( self.mainRef.player.playerNP.getPos(self.enemyNP).getXy() ) targetDirectionAngle = Vec2(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())) ).signedAngleDeg(targetDirection) rotationAngle = targetDirectionAngle * self.rotSpeed * globalClock.getDt() self.enemyModel.setH(self.enemyModel.getH() + rotationAngle) targetDirection.normalize() playerMoveSpeedVec = targetDirection * self.speed * globalClock.getDt() self.enemyNP.setPos( self.enemyBody.move(Vec3(playerMoveSpeedVec.getX(), playerMoveSpeedVec.getY(), 0) ) ) if (abs(rotationAngle) > 120 * globalClock.getDt()): self.lostTargetTimer = self.lostTargetTotalTime self.enemyActiveState = self.name + "lt" taskMgr.add(self.lostTargetStep, self.enemyActiveState) return task.done return task.cont def lostTargetStep(self, task): self.enemyNP.setPos( self.enemyBody.move(Vec3(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())), 0) * self.speed * globalClock.getDt() ) ) self.lostTargetTimer -= globalClock.getDt() if (self.lostTargetTimer < 0): self.enemyActiveState = self.name + "rt" taskMgr.add(self.recoverTargetStep, self.enemyActiveState) return task.done return task.cont def recoverTargetStep(self, task): targetDirection = Vec2( self.mainRef.player.playerNP.getPos(self.enemyNP).getXy() ) targetDirectionAngle = Vec2(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())) ).signedAngleDeg(targetDirection) rotationAngle = targetDirectionAngle * self.rotSpeed * globalClock.getDt() self.enemyModel.setH(self.enemyModel.getH() + rotationAngle) if (abs(targetDirectionAngle) < 5): self.enemyActiveState = self.name + "pt" taskMgr.add(self.pursueTargetStep, self.enemyActiveState) return task.done return task.cont def headToPortalStep(self, task): directionVec = Vec3(self.currentCrossPointGoal.getX() - self.enemyNP.getX(), self.currentCrossPointGoal.getY() - self.enemyNP.getY(), 0) directionVec.normalize() targetDirection = Vec2( self.currentCrossPointGoal - self.enemyNP.getPos().getXy() ) targetDirectionAngle = Vec2(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())) ).signedAngleDeg(targetDirection) rotationAngle = targetDirectionAngle * self.rotSpeed * globalClock.getDt() self.enemyModel.setH(self.enemyModel.getH() + rotationAngle) self.enemyNP.setPos( self.enemyBody.move( directionVec * self.speed * globalClock.getDt() ) ) return task.cont # ====================== END OF STATE MACHINE METHODS ======================== # ============================================================================ def destroy(self): self.alive = False taskMgr.remove(self.name+'roar sort') # removing sound for node in self.bulletNodes.keys(): self.mainRef.world.removeRigidBody(self.bulletNodes[node]) self.partNodes[node].removeNode() taskMgr.remove( self.enemyActiveState ) # removing state machine task self.enemyModel.cleanup() self.enemyBB.removeNode() self.enemyBody.destroy() def detachLimb(self,limb): # Detaches a limb from the enemy and makes it drop on the floor print "[Detach] Detach %s" % limb # self.partNodes[limb].wrtReparentTo(self.mainRef.render) # # shape = BulletSphereShape(10.0) # node = BulletRigidBodyNode('Sphere') # node.setMass(1.0) # node.addShape(shape) # playerNP = self.mainRef.render.attachNewNode(node) # playerNP.setPos(self.enemyModel.exposeJoint(None,"modelRoot",limb).getPos()) # playerNP.setPos(playerNP.getRelativePoint(self.partNodes[limb],self.partNodes[limb].getPos())) # playerNP.setPos(60,0,-60) # print playerNP.getRelativePoint(self.partNodes[limb],self.partNodes[limb].getPos()) # print self.partNodes[limb].getPos() # self.mainRef.world.attachRigidBody(node) # # self.bulletNodes[limb].applyCentralForce(Vec3(0, 0, -5)) # self.mainRef.world.removeRigidBody(self.bulletNodes[limb]) def updatePath(self): convexRegionsList = self.mainRef.map.convexRegions self.portalsPathList = [] # this is what we want for enemy's correct pursue path discoveredRegionsList = [] # part of the BFS algorithm visitedRegionsList = [False for item in range( len(convexRegionsList))] regionFatherList = [None for item in range( len(convexRegionsList))] # this list keeps track of a region's father AND the portalEntrance connecting them # from now, we'll execute a BFS to find each region that enemy will cross to reach player's position discoveredRegionsList.append( convexRegionsList[self.currentRegionID] ) visitedRegionsList[self.currentRegionID] = True regionFatherList[self.currentRegionID] = [-1, None] while(discoveredRegionsList): analisedRegion = discoveredRegionsList.pop(0) for portalEntrance in analisedRegion.portalEntrancesList: neighbourRegionID = portalEntrance.connectedRegionID if (not visitedRegionsList[neighbourRegionID]): regionFatherList[neighbourRegionID] = [analisedRegion.regionID, portalEntrance.portal] if (neighbourRegionID == self.mainRef.player.currentRegionID): discoveredRegionsList = [] # break while statement trick break visitedRegionsList[neighbourRegionID] = True discoveredRegionsList.append( convexRegionsList[neighbourRegionID] ) # now that we have all regions necessary , we'll just put all portals on the correct order lastRegionFatherID = self.mainRef.player.currentRegionID while (lastRegionFatherID != -1): lastRegionFather = regionFatherList[lastRegionFatherID] lastRegionFatherID = lastRegionFather[0] self.portalsPathList.append(lastRegionFather[1]) # putting portals path on the right order for enemy pursuing algorithm self.portalsPathList.pop() self.portalsPathList.reverse() # Debug # print "lista de portais:" # for portal in self.portalsPathList: # print portal.connectedRegionsIDs self.setNewCourse() def checkIfChangedRegion(self, task, lastRegion=0): for portalEntrance in self.mainRef.map.convexRegions[self.currentRegionID].portalEntrancesList: if ( self.intersect( self.oldPosition, self.enemyNP.getPos(), portalEntrance.portal.frontiers[0], portalEntrance.portal.frontiers[1] ) and portalEntrance.portal.connectedRegionsIDs[0] != lastRegion and portalEntrance.portal.connectedRegionsIDs[1] != lastRegion ): oldRegion = self.mainRef.player.currentRegionID self.currentRegionID = portalEntrance.connectedRegionID # Debug # print self.name + " region changed: ", oldRegion, ">", self.currentRegionID # erase last item of portalsPathList (if it isn't empty) if (len(self.portalsPathList) != 0): self.portalsPathList.pop(0) # new course must be calculated if the enemy changed it's region self.setNewCourse() self.oldPosition = self.enemyNP.getPos() return task.cont def ccw(self, A,B,C): return (C.getY()-A.getY())*(B.getX()-A.getX()) > (B.getY()-A.getY())*(C.getX()-A.getX()) def intersect(self, A,B,C,D): return self.ccw(A,C,D) != self.ccw(B,C,D) and self.ccw(A,B,C) != self.ccw(A,B,D) def setOptimalCrossPoint(self): deltaPositionVec = self.mainRef.player.playerNP.getPos() - self.enemyNP.getPos() positionPoint = self.enemyNP.getPos() deltaFrontiersVec = self.portalsPathList[0].frontiersVec frontierPoint = self.portalsPathList[0].frontiers[0] if (deltaPositionVec.getX() == 0): tang2 = deltaFrontiersVec.getY() / deltaFrontiersVec.getX() b2 = frontierPoint.getY() - tang2 * frontierPoint.getX() xRes = positionPoint.getX() yRes = tang2 * xRes + b2 if (deltaFrontiersVec.getX() == 0): tang1 = deltaPositionVec.getY() / deltaPositionVec.getX() b1 = positionPoint.getY() - tang1 * positionPoint.getX() xRes = frontierPoint.getX() yRes = tang1 * xRes + b1 else: tang1 = deltaPositionVec.getY() / deltaPositionVec.getX() tang2 = deltaFrontiersVec.getY() / deltaFrontiersVec.getX() b1 = positionPoint.getY() - tang1 * positionPoint.getX() b2 = frontierPoint.getY() - tang2 * frontierPoint.getX() xRes = (b1 - b2) / (tang1 - tang2) yRes = tang1 * xRes + b1 if (deltaFrontiersVec.getX() == 0): if ( ( yRes > self.portalsPathList[0].crossPoints[0].getY() and yRes < self.portalsPathList[0].crossPoints[1].getY() ) or ( yRes < self.portalsPathList[0].crossPoints[0].getY() and yRes > self.portalsPathList[0].crossPoints[1].getY() ) ) : self.currentCrossPointGoal = Vec2(xRes, yRes) elif (yRes > self.portalsPathList[0].crossPoints[0].getY() and yRes > self.portalsPathList[0].crossPoints[1].getY() ): if ( self.portalsPathList[0].crossPoints[0].getY() > self.portalsPathList[0].crossPoints[1].getY()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1] else: if ( self.portalsPathList[0].crossPoints[0].getY() < self.portalsPathList[0].crossPoints[1].getY()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1] else: if ( ( xRes > self.portalsPathList[0].crossPoints[0].getX() and xRes < self.portalsPathList[0].crossPoints[1].getX() ) or ( xRes < self.portalsPathList[0].crossPoints[0].getX() and xRes > self.portalsPathList[0].crossPoints[1].getX() ) ) : self.currentCrossPointGoal = Vec2(xRes, yRes) elif (xRes > self.portalsPathList[0].crossPoints[0].getX() and xRes > self.portalsPathList[0].crossPoints[1].getX()): if ( self.portalsPathList[0].crossPoints[0].getX() > self.portalsPathList[0].crossPoints[1].getX()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1] else: if ( self.portalsPathList[0].crossPoints[0].getX() < self.portalsPathList[0].crossPoints[1].getX()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1]