Пример #1
0
class CogdoFlyingPropeller(CogdoFlyingGatherable):

    def __init__(self, serialNum, model):
        CogdoFlyingGatherable.__init__(self, Globals.Level.GatherableTypes.Propeller, serialNum, model, Globals.Gameplay.PropellerCollisionRadius, animate=False)
        self.activePropellers = []
        self.usedPropellers = []
        propellers = self._model.findAllMatches('**/propeller*')
        for prop in propellers:
            self.activePropellers.append(prop)

        self.initIntervals()

    def initIntervals(self):
        self.animatedPropellerIval = Parallel(name='%s.object-%i-animatePropellerIval' % (self.__class__.__name__, self.serialNum))
        for propeller in self.activePropellers:
            self.animatedPropellerIval.append(LerpHprInterval(propeller, duration=Globals.Level.PropellerSpinDuration, startHpr=Vec3(0.0, 0.0, 0.0), hpr=Vec3(360.0, 0.0, 0.0)))

    def show(self):
        self.animatedPropellerIval.loop()
        CogdoFlyingGatherable.show(self)

    def hide(self):
        self.animatedPropellerIval.clearToInitial()
        CogdoFlyingGatherable.hide(self)

    def destroy(self):
        taskMgr.removeTasksMatching('propeller-respawn-*')
        self.animatedPropellerIval.clearToInitial()
        del self.animatedPropellerIval
        CogdoFlyingGatherable.destroy(self)

    def pickUp(self, toon, elapsedSeconds = 0.0):
        prop = self.removePropeller()
        if prop != None:
            respawnTime = Globals.Gameplay.PropellerRespawnTime
            if elapsedSeconds < respawnTime:
                taskMgr.doMethodLater(respawnTime - elapsedSeconds, self.addPropeller, 'propeller-respawn-%i' % self.serialNum, extraArgs=[prop])
            else:
                self.addPropeller(prop)
        else:
            self.disable()
        return

    def addPropeller(self, prop):
        if len(self.usedPropellers) > 0:
            if len(self.activePropellers) == 0:
                self.enable()
            self.usedPropellers.remove(prop)
            prop.show()
            self.activePropellers.append(prop)
            self._wasPickedUp = False

    def removePropeller(self):
        if len(self.activePropellers) > 0:
            prop = self.activePropellers.pop()
            prop.hide()
            self.usedPropellers.append(prop)
            if len(self.activePropellers) == 0:
                self._wasPickedUp = True
            return prop
        else:
            return None

    def isPropeller(self):
        if len(self.activePropellers) > 0:
            return True
        else:
            return False
Пример #2
0
class CogdoFlyingPropeller(CogdoFlyingGatherable):
    def __init__(self, serialNum, model):
        CogdoFlyingGatherable.__init__(
            self,
            Globals.Level.GatherableTypes.Propeller,
            serialNum,
            model,
            Globals.Gameplay.PropellerCollisionRadius,
            animate=False)
        self.activePropellers = []
        self.usedPropellers = []
        propellers = self._model.findAllMatches('**/propeller*')
        for prop in propellers:
            self.activePropellers.append(prop)

        self.initIntervals()

    def initIntervals(self):
        self.animatedPropellerIval = Parallel(
            name='%s.object-%i-animatePropellerIval' %
            (self.__class__.__name__, self.serialNum))
        for propeller in self.activePropellers:
            self.animatedPropellerIval.append(
                LerpHprInterval(propeller,
                                duration=Globals.Level.PropellerSpinDuration,
                                startHpr=Vec3(0.0, 0.0, 0.0),
                                hpr=Vec3(360.0, 0.0, 0.0)))

    def show(self):
        self.animatedPropellerIval.loop()
        CogdoFlyingGatherable.show(self)

    def hide(self):
        self.animatedPropellerIval.clearToInitial()
        CogdoFlyingGatherable.hide(self)

    def destroy(self):
        taskMgr.removeTasksMatching('propeller-respawn-*')
        self.animatedPropellerIval.clearToInitial()
        del self.animatedPropellerIval
        CogdoFlyingGatherable.destroy(self)

    def pickUp(self, toon, elapsedSeconds=0.0):
        prop = self.removePropeller()
        if prop != None:
            respawnTime = Globals.Gameplay.PropellerRespawnTime
            if elapsedSeconds < respawnTime:
                taskMgr.doMethodLater(respawnTime - elapsedSeconds,
                                      self.addPropeller,
                                      'propeller-respawn-%i' % self.serialNum,
                                      extraArgs=[prop])
            else:
                self.addPropeller(prop)
        else:
            self.disable()
        return

    def addPropeller(self, prop):
        if len(self.usedPropellers) > 0:
            if len(self.activePropellers) == 0:
                self.enable()
            self.usedPropellers.remove(prop)
            prop.show()
            self.activePropellers.append(prop)
            self._wasPickedUp = False

    def removePropeller(self):
        if len(self.activePropellers) > 0:
            prop = self.activePropellers.pop()
            prop.hide()
            self.usedPropellers.append(prop)
            if len(self.activePropellers) == 0:
                self._wasPickedUp = True
            return prop
        return

    def isPropeller(self):
        if len(self.activePropellers) > 0:
            return True
        else:
            return False
class DistributedPieTurret(DistributedAvatar, DistributedSmoothNode):
    notify = directNotify.newCategory('DistributedPieTurret')

    def __init__(self, cr):
        DistributedAvatar.__init__(self, cr)
        DistributedSmoothNode.__init__(self, cr)
        self.fsm = ClassicFSM(
            'DistributedPieTurret',
            [
                State('off', self.enterOff, self.exitOff),
                State('scan', self.enterScan, self.exitScan),
                State('shoot', self.enterShoot, self.exitShoot)
             ],
             'off', 'off'
         )
        self.fsm.enterInitialState()
        self.reloadTime = 0.25
        self.cannon = None
        self.track = None
        self.owner = None
        self.gag = None
        self.readyGag = None
        self.hitGag = None
        self.explosion = None
        self.wallCollNode = None
        self.eventCollNode = None
        self.event = None
        self.suit = None
        self.eventId = None
        self.entities = []
        self.upgradeID = None
        self.deathEvent = None

    def setOwner(self, avatar):
        self.owner = avatar

    def getOwner(self):
        return self.owner

    def setGag(self, upgradeId):
        gags = {0 : CIGlobals.WholeCreamPie, 1 : CIGlobals.WholeFruitPie, 2 : CIGlobals.BirthdayCake, 3 : CIGlobals.WeddingCake}
        self.gag = gags.get(upgradeId)
        if not self.readyGag:
            self.loadGagInTurret()

    def b_setGag(self, upgradeId):
        self.sendUpdate('setGag', [upgradeId])
        self.setGag(upgradeId)
        self.upgradeID = upgradeId

    def getGag(self):
        return self.gag

    def getGagID(self):
        return self.upgradeID

    def generate(self):
        DistributedAvatar.generate(self)
        DistributedSmoothNode.generate(self)

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        DistributedSmoothNode.announceGenerate(self)
        self.healthLabel.setScale(1.1)
        self.deathEvent = self.uniqueName('DistributedPieTurret-death')
        self.makeTurret()

    def disable(self):
        self.fsm.requestFinalState()
        del self.fsm

        # This should fix crashes related to Sequences.
        if self.track:
            self.track.pause()
            self.track = None

        # Cleanup entities.
        for ent in self.entities:
            ent.cleanup()
        self.entities = None

        # Get rid of explosions.
        if self.explosion:
            self.explosion.removeNode()
            self.explosion = None

        self.removeTurret()
        DistributedSmoothNode.disable(self)
        DistributedAvatar.disable(self)

    def showAndMoveHealthLabel(self):
        self.unstashHpLabel()
        self.stopMovingHealthLabel()
        moveTrack = LerpPosInterval(self.healthLabel,
                                duration = 0.5,
                                pos = Point3(0, 0, 5),
                                startPos = Point3(0, 0, 0),
                                blendType = 'easeOut')
        self.healthLabelTrack = Sequence(moveTrack, Wait(1.0), Func(self.stashHpLabel))
        self.healthLabelTrack.start()

    # BEGIN STATES

    def enterShoot(self, suitId):
        if self.cannon:
            smoke = loader.loadModel("phase_4/models/props/test_clouds.bam")
            smoke.setBillboardPointEye()
            smoke.reparentTo(self.cannon.find('**/cannon'))
            smoke.setPos(0, 6, -3)
            smoke.setScale(0.5)
            smoke.wrtReparentTo(render)
            self.suit = self.cr.doId2do.get(suitId)
            self.cannon.find('**/cannon').lookAt(self.suit.find('**/joint_head'))
            self.cannon.find('**/square_drop_shadow').headsUp(self.suit.find('**/joint_head'))
            self.track = Sequence(Parallel(LerpScaleInterval(smoke, 0.5, 3), LerpColorScaleInterval(smoke, 0.5, Vec4(2, 2, 2, 0))), Func(smoke.removeNode))
            self.track.start()
            self.createAndShootGag()

    def exitShoot(self):
        if hasattr(self, 'suit'):
            del self.suit

    def shoot(self, suitId):
        self.fsm.request('shoot', [suitId])

    def scan(self, timestamp = None, afterShooting = 0):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)

        self.fsm.request('scan', [ts, afterShooting])
        
    def buildScanTrack(self, ts = None):
        if self.track:
            self.track.pause()
            self.track = None
        self.track = Parallel(
            Sequence(
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0),
                    startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
                    startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
            ),
            Sequence(
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0),
                    startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
                    startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
            )
        )
        if ts:
            self.track.loop(ts)
        else:
            self.track.loop()

    def enterScan(self, ts = 0, afterShooting = 0):
        if afterShooting:
            self.track = Parallel(
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
                    startHpr = self.cannon.find('**/cannon').getHpr(), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
                    startHpr = self.cannon.find('**/square_drop_shadow').getHpr(), blendType = 'easeInOut'),
                name = "afterShootTrack" + str(id(self))
            )
            self.track.setDoneEvent(self.track.getName())
            self.acceptOnce(self.track.getDoneEvent(), self._afterShootTrackDone)
            self.track.start(ts)
        else:
            self.buildScanTrack(ts)

    def exitScan(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    # END STATES

    def _afterShootTrackDone(self):
        self.buildScanTrack()

    def makeTurret(self):
        self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon.bam')
        self.cannon.reparentTo(self)
        self.loadGagInTurret()
        self.setupWallSphere()
        if self.isLocal():
            self.setupEventSphere()

    def removeTurret(self):
        self.removeWallSphere()
        self.removeGagInTurret()
        if self.cannon:
            self.cannon.removeNode()
            self.cannon = None

    def getCannon(self):
        return self.cannon.find('**/cannon')

    def setupWallSphere(self):
        sphere = CollisionSphere(0.0, 0.0, 0.0, 3.0)
        node = CollisionNode('DistributedPieTurret.WallSphere')
        node.addSolid(sphere)
        node.setCollideMask(CIGlobals.WallBitmask)
        self.wallCollNode = self.cannon.attachNewNode(node)
        self.wallCollNode.setZ(2)
        self.wallCollNode.setY(1.0)

    def removeWallSphere(self):
        if self.wallCollNode:
            self.wallCollNode.removeNode()
            self.wallCollNode = None

    def createAndShootGag(self):
        if not self.readyGag:
            self.loadGagInTurret()
        if self.readyGag:
            self.readyGag.shoot(Point3(0, 200, -90))
            self.entities.append(self.readyGag)
            collideEventName = self.readyGag.getCollideEventName()
            self.readyGag = None
            if self.isLocal():
                self.acceptOnce(collideEventName, self.handleGagCollision)
        Sequence(Wait(self.reloadTime), Func(self.loadGagInTurret)).start()

    def loadGagInTurret(self):
        if self.cannon and self.gag:
            self.removeGagInTurret()
            self.eventId = random.uniform(0, 100000000)
            self.readyGag = TurretGag(self, self.uniqueName('pieTurretCollision') + str(self.eventId), self.gag)
            self.readyGag.build()

    def removeGagInTurret(self):
        if self.readyGag:
            self.readyGag.cleanup()
            self.readyGag = None

    def makeSplat(self, index, pos):
        if index >= len(self.entities):
            return
        ent = self.entities[index]
        gagClass = ent.gagClass
        splat = gagClass.buildSplat(gagClass.splatScale, gagClass.splatColor)
        base.audio3d.attachSoundToObject(gagClass.hitSfx, splat)
        splat.reparentTo(render)
        splat.setPos(pos[0], pos[1], pos[2])
        gagClass.hitSfx.play()
        Sequence(Wait(0.5), Func(splat.cleanup)).start()
        self.hitGag = None

    def d_makeSplat(self, index, pos):
        self.sendUpdate('makeSplat', [index, pos])

    def b_makeSplat(self, index, pos):
        self.d_makeSplat(index, pos)
        self.makeSplat(index, pos)

    def handleGagCollision(self, entry, ent):
        x, y, z = ent.getGag().getPos(render)
        self.b_makeSplat(self.entities.index(ent), [x, y, z])
        if self.isLocal():
            intoNP = entry.getIntoNodePath()
            avNP = intoNP.getParent()
            for key in self.cr.doId2do.keys():
                obj = self.cr.doId2do[key]
                if obj.__class__.__name__ == 'DistributedSuit':
                    if obj.getKey() == avNP.getKey():
                        if obj.getHealth() > 0:
                            obj.sendUpdate('hitByGag', [ent.getID()])
        ent.cleanup()

    def setHealth(self, hp):
        DistributedAvatar.setHealth(self, hp)
        if self.isLocal():
            base.localAvatar.getMyBattle().getTurretManager().updateTurretGui()

    def die(self):
        self.fsm.requestFinalState()
        turretPos = self.cannon.getPos(render)
        self.removeTurret()
        self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam")
        self.explosion.setScale(0.5)
        self.explosion.reparentTo(render)
        self.explosion.setBillboardPointEye()
        self.explosion.setPos(turretPos + (0, 0, 5))
        sfx = base.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg")
        base.audio3d.attachSoundToObject(sfx, self)
        base.playSfx(sfx)
        messenger.send(self.deathEvent)

    def isLocal(self):
        return self.getOwner() == base.localAvatar.doId

    def getDeathEvent(self):
        return self.deathEvent
class DistributedPieTurret(DistributedAvatar, DistributedSmoothNode):
	notify = directNotify.newCategory("DistributedPieTurret")

	def __init__(self, cr):
		DistributedAvatar.__init__(self, cr)
		DistributedSmoothNode.__init__(self, cr)
		self.fsm = ClassicFSM(
			'DistributedPieTurret',
			[
				State('off', self.enterOff, self.exitOff),
				State('scan', self.enterScan, self.exitScan),
				#State('lockOn', self.enterLockOn, self.exitLockOn),
				State('shoot', self.enterShoot, self.exitShoot)
			],
			'off', 'off'
		)
		self.fsm.enterInitialState()
		self.cannon = None
		self.track = None
		self.avatar = None
		self.readyPie = None
		self.explosion = None
		self.wallCollNode = None
		self.eventCollNode = None
		self.event = None
		self.piesInFlight = []

	def setHealth(self, hp):
		DistributedAvatar.setHealth(self, hp)
		if self.getAvatar() == base.localAvatar.doId:
			base.localAvatar.getMyBattle().getTurretManager().updateTurretGui()

	def die(self):
		self.fsm.requestFinalState()
		turretPos = self.cannon.getPos(render)
		self.removeTurret()
		self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam")
		self.explosion.setScale(0.5)
		self.explosion.reparentTo(render)
		self.explosion.setBillboardPointEye()
		self.explosion.setPos(turretPos + (0, 0, 1))
		sfx = base.localAvatar.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.mp3")
		base.localAvatar.audio3d.attachSoundToObject(sfx, self)
		base.playSfx(sfx)

	def showAndMoveHealthLabel(self):
		self.unstashHpLabel()
		self.stopMovingHealthLabel()
		moveTrack = LerpPosInterval(self.healthLabel,
								duration = 0.5,
								pos = Point3(0, 0, 5),
								startPos = Point3(0, 0, 0),
								blendType = 'easeOut')
		self.healthLabelTrack = Sequence(moveTrack, Wait(1.0), Func(self.stashHpLabel))
		self.healthLabelTrack.start()

	def enterOff(self):
		pass

	def exitOff(self):
		pass

	def makeSplat(self, pos):
		splat = Actor("phase_3.5/models/props/splat-mod.bam",
			{"chan": "phase_3.5/models/props/splat-chan.bam"})
		splat.setScale(0.5)
		splat.reparentTo(render)
		splat.setBillboardPointEye()
		splat.setColor(VBase4(1, 1, 0, 1))
		x, y, z = pos
		splat.setPos(x, y, z)
		sfx = base.localAvatar.audio3d.loadSfx("phase_4/audio/sfx/AA_wholepie_only.mp3")
		base.localAvatar.audio3d.attachSoundToObject(sfx, splat)
		base.playSfx(sfx)
		track = Sequence(
			ActorInterval(splat, "chan"),
			Func(splat.cleanup),
			Func(splat.removeNode)
		)
		track.start()

	def d_makeSplat(self, pos):
		self.sendUpdate("makeSplat", [pos])

	def b_makeSplat(self, pos):
		self.d_makeSplat(pos)
		self.makeSplat(pos)

	def shoot(self, suitId):
		self.fsm.request('shoot', [suitId])

	def enterShoot(self, suitId):
		if self.cannon:
			smoke = loader.loadModel("phase_4/models/props/test_clouds.bam")
			smoke.setBillboardPointEye()
			smoke.reparentTo(self.cannon.find('**/cannon'))
			smoke.setPos(0, 6, -3)
			smoke.setScale(0.5)
			smoke.wrtReparentTo(render)
			self.suit = self.cr.doId2do.get(suitId)
			self.cannon.find('**/cannon').lookAt(self.suit.find('**/joint_head'))
			self.cannon.find('**/square_drop_shadow').headsUp(self.suit.find('**/joint_head'))
			self.eventId = random.uniform(0, 100000000)
			track = Sequence(Parallel(LerpScaleInterval(smoke, 0.5, 3), LerpColorScaleInterval(smoke, 0.5, Vec4(2, 2, 2, 0))), Func(smoke.removeNode))
			track.start()
			self.createAndShootPie()

	def loadPieInTurret(self):
		if self.cannon:
			if self.readyPie:
				self.readyPie.removeNode()
				self.readyPie = None
			pie = loader.loadModel("phase_3.5/models/props/tart.bam")
			pie.reparentTo(self.cannon.find('**/cannon'))
			pie.setY(5.2)
			pie.setHpr(90, -90, 90)
			self.readyPie = pie

	def removePieInTurret(self):
		if self.readyPie:
			self.readyPie.removeNode()
			self.readyPie = None

	def createAndShootPie(self):
		if not self.readyPie:
			self.loadPieInTurret()
		local = 0
		if base.localAvatar.doId == self.getAvatar():
			local = 1
		proj = ProjectilePie(self.uniqueName('pieTurretCollision') + str(self.eventId), self.cannon.find('**/cannon'), self.readyPie, Point3(0, 200, -90), 0.9, 2.5, local, self)
		self.readyPie = None
		self.piesInFlight.append(proj)
		if local:
			self.acceptOnce(self.uniqueName('pieTurretCollision') + str(self.eventId), self.handlePieCollision)
		Sequence(Wait(0.25), Func(self.loadPieInTurret)).start()

	def handlePieCollision(self, entry, proj):
		x, y, z = proj.pie.getPos(render)
		self.b_makeSplat([x, y, z])
		proj.cleanup()
		if base.localAvatar.doId == self.getAvatar():
			intoNP = entry.getIntoNodePath()
			avNP = intoNP.getParent()
			for key in self.cr.doId2do.keys():
				obj = self.cr.doId2do[key]
				if obj.__class__.__name__ == "DistributedSuit":
					if obj.getKey() == avNP.getKey():
						if obj.getHealth() > 0:
							base.localAvatar.sendUpdate('suitHitByPie', [obj.doId, GagGlobals.getIDByName(CIGlobals.WholeCreamPie)])

	def exitShoot(self):
		del self.suit
		del self.eventId

	def scan(self, timestamp = None, afterShooting = 0):
		if timestamp == None:
			ts = 0.0
		else:
			ts = globalClockDelta.localElapsedTime(timestamp)

		self.fsm.request('scan', [ts, afterShooting])

	def enterScan(self, ts = 0, afterShooting = 0):
		if afterShooting:
			self.track = Parallel(
				LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
					startHpr = self.cannon.find('**/cannon').getHpr(), blendType = 'easeInOut'),
				LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
					startHpr = self.cannon.find('**/square_drop_shadow').getHpr(), blendType = 'easeInOut'),
				name = "afterShootTrack" + str(id(self))
			)
			self.track.setDoneEvent(self.track.getName())
			self.acceptOnce(self.track.getDoneEvent(), self._afterShootTrackDone)
			self.track.start(ts)
		else:
			self.track = Parallel(
				Sequence(
					LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0),
						startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
					LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
						startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
				),
				Sequence(
					LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0),
						startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
					LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
						startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
				)
			)
			self.track.loop(ts)

	def _afterShootTrackDone(self):
		self.track = None
		self.track = Parallel(
			Sequence(
				LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0),
					startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
				LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
					startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
			),
			Sequence(
				LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0),
					startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
				LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
					startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
			)
		)
		self.track.loop()

	def exitScan(self):
		if self.track:
			self.ignore(self.track.getDoneEvent())
			self.track.finish()
			self.track = None

	def setAvatar(self, avId):
		self.avatar = avId

	def getAvatar(self):
		return self.avatar

	def makeTurret(self):
		self.cannon = loader.loadModel("phase_4/models/minigames/toon_cannon.bam")
		self.cannon.reparentTo(self)
		self.loadPieInTurret()
		self.setupWallSphere()
		if self.getAvatar() == base.localAvatar.doId:
			self.setupEventSphere()

	def setupWallSphere(self):
		sphere = CollisionSphere(0.0, 0.0, 0.0, 3.0)
		node = CollisionNode('DistributedPieTurret.WallSphere')
		node.addSolid(sphere)
		node.setCollideMask(CIGlobals.WallBitmask)
		self.wallCollNode = self.cannon.attachNewNode(node)
		self.wallCollNode.setZ(2)
		self.wallCollNode.setY(1.0)

	def removeWallSphere(self):
		if self.wallCollNode:
			self.wallCollNode.removeNode()
			self.wallCollNode = None

	def removeTurret(self):
		self.removeWallSphere()
		self.removePieInTurret()
		if self.cannon:
			self.cannon.removeNode()
			self.cannon = None

	def generate(self):
		DistributedAvatar.generate(self)
		DistributedSmoothNode.generate(self)

	def announceGenerate(self):
		DistributedAvatar.announceGenerate(self)
		DistributedSmoothNode.announceGenerate(self)
		self.healthLabel.setScale(1.1)
		self.makeTurret()

	def disable(self):
		self.fsm.requestFinalState()
		del self.fsm
		for projs in self.piesInFlight:
			projs.cleanup()
		self.piesInFlight = None
		if self.explosion:
			self.explosion.removeNode()
			self.explosion = None
		self.removeTurret()
		DistributedSmoothNode.disable(self)
		DistributedAvatar.disable(self)
Пример #5
0
class DistributedCityCart(DistributedNode):
    notify = directNotify.newCategory('DistributedCityCart')

    def __init__(self, cr):
        DistributedNode.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedCityCart', [State('off', self.enterOff, self.exitOff), State('pathFollow', self.enterPathFollow, self.exitPathFollow), State('collision', self.enterCollision, self.exitCollision)], 'off', 'off')
        self.fsm.enterInitialState()
        self.suitInCar = None
        self.cart = None
        self.honkSfxPath = 'phase_14/audio/sfx/cogtropolis_citycar_driveby_horn.mp3'
        self.cartModelPath = 'phase_12/models/bossbotHQ/Coggolf_cart3.bam'
        self.moPaths = ['phase_14/models/paths/ct-citycar-drivepath-1.egg',
         'phase_14/models/paths/ct-citycar-drivepath-2.egg',
         'phase_14/models/paths/ct-citycar-drivepath-3.egg',
         'phase_14/models/paths/ct-citycar-drivepath-4.egg',
         'phase_14/models/paths/ct-citycar-drivepath-5.egg',
         'phase_14/models/paths/ct-citycar-drivepath-6.egg']
        self.moPath = None
        self.soundEngineLoop = None
        self.soundDriveByHorn = None
        self.ivalTDisplace = None
        self.pathIndex = None
        self.wheelSpinTrack = None
        self.collNodePath = None
        self.soundDriveBy = None
        return

    def setIvalTDisplace(self, displace):
        self.ivalTDisplace = displace

    def setPathIndex(self, index):
        self.pathIndex = index

    def setState(self, state, timestamp):
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        self.fsm.request(state, [ts])

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterPathFollow(self, ts):
        duration = CityCartGlobals.index2Duration[self.pathIndex]
        self.moPath = NURBSMopath.NURBSMopath(self.moPaths[self.pathIndex], name=self.uniqueName('DCityCart_moPath'))
        startT = 0.0
        if ts > 0.0:
            startT = ts % duration * (1.0 / duration)
        self.moPath.play(self, loop=True, duration=duration, startT=startT)
        base.taskMgr.add(self.__drive, self.uniqueName('DCityCart.drive'))
        self.wheelSpinTrack = Parallel()
        for name in ['leftFrontWheel',
         'rightBackWheel',
         'rightFrontWheel',
         'leftBackWheel']:
            wheel = self.find('**/' + name)
            self.wheelSpinTrack.append(LerpHprInterval(wheel, duration=0.1, hpr=(0, 360, 0), startHpr=(0, 0, 0)))

        self.wheelSpinTrack.loop()
        self.accept('enter' + self.collNodePath.node().getName(), self.__handleRanOver)

    def __handleRanOver(self, entry):
        self.suitInCar.setChat(CityCartGlobals.SuitRanOverTaunt)
        self.sendUpdate('hitByCar')
        self.cr.playGame.getPlace().fsm.request('stop')
        base.localAvatar.b_setAnimState('squish', callback=self.cr.playGame.getPlace().fsm.request, extraArgs=['walk'])

    def __drive(self, task):
        if base.localAvatar.getDistance(self) < 10.0:
            if self.soundDriveByHorn.status() == self.soundDriveByHorn.READY:
                wantsToHonk = random.randint(0, 3)
                if wantsToHonk == 3:
                    base.playSfx(self.soundDriveByHorn)
                return task.cont
        elif base.localAvatar.getDistance(self) < 20.0:
            if self.soundDriveBy.status() == self.soundDriveBy.READY:
                base.playSfx(self.soundDriveBy)
                return task.cont
        return task.cont

    def exitPathFollow(self):
        self.ignore('enter' + self.collNodePath.node().getName())
        if self.wheelSpinTrack:
            self.wheelSpinTrack.finish()
            self.wheelSpinTrack = None
        if self.moPath:
            self.moPath.stop()
            self.moPath = None
        return

    def enterCollision(self, ts):
        pass

    def exitCollision(self):
        pass

    def generate(self):
        DistributedNode.generate(self)
        self.cart = loader.loadModel(self.cartModelPath)
        self.cart.reparentTo(self)
        self.cart.setH(180)
        heads = []
        for head in CIGlobals.SuitBodyData.keys():
            if CIGlobals.SuitBodyData[head][0] != 'B':
                heads.append(head)

        head = random.choice(heads)
        suitType = CIGlobals.SuitBodyData[head][0]
        suitDept = CIGlobals.SuitBodyData[head][1]
        self.suitInCar = Suit()
        self.suitInCar.generateSuit(suitType, head, suitDept, 137, 0, False)
        self.suitInCar.loop('sit')
        self.suitInCar.disableRay()
        self.suitInCar.setScale(0.7)
        self.suitInCar.setH(180)
        self.suitInCar.setPos(0, -1, -1.5)
        self.suitInCar.reparentTo(self.cart.find('**/seat1'))
        self.soundEngineLoop = base.audio3d.loadSfx('phase_6/audio/sfx/KART_Engine_loop_0.wav')
        base.audio3d.attachSoundToObject(self.soundEngineLoop, self)
        base.playSfx(self.soundEngineLoop, looping=1)
        self.soundDriveByHorn = base.audio3d.loadSfx(self.honkSfxPath)
        base.audio3d.attachSoundToObject(self.soundDriveByHorn, self)
        self.soundDriveBy = base.audio3d.loadSfx('phase_14/audio/sfx/cogtropolis_citycar_driveby.mp3')
        base.audio3d.attachSoundToObject(self.soundDriveBy, self)
        sphere = CollisionSphere(0, 0, 0, 2.5)
        sphere.setTangible(0)
        node = CollisionNode(self.uniqueName('cartSphere'))
        node.setCollideMask(CIGlobals.WallBitmask)
        node.addSolid(sphere)
        self.collNodePath = self.attachNewNode(node)
        self.collNodePath.setZ(1.5)
        self.collNodePath.setSy(2.0)
        self.collNodePath.setSx(1.75)

    def disable(self):
        self.fsm.requestFinalState()
        if self.moPath:
            self.moPath.stop()
            self.moPath = None
        self.moPaths = None
        self.honkSfxPath = None
        self.cartModelPath = None
        self.soundEngineLoop = None
        self.soundDriveBy = None
        if self.suitInCar:
            self.suitInCar.disable()
            self.suitInCar.delete()
            self.suitInCar = None
        if self.cart:
            self.cart.removeNode()
            self.cart = None
        del self.fsm
        DistributedNode.disable(self)
        return
class DistributedCityCart(DistributedNode):
    notify = directNotify.newCategory('DistributedCityCart')

    def __init__(self, cr):
        DistributedNode.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedCityCart', [State('off', self.enterOff, self.exitOff),
         State('pathFollow', self.enterPathFollow, self.exitPathFollow),
         State('collision', self.enterCollision, self.exitCollision)], 'off', 'off')
        self.fsm.enterInitialState()
        self.suitInCar = None
        self.cart = None
        self.honkSfxPath = 'phase_14/audio/sfx/cogtropolis_citycar_driveby_horn.ogg'
        self.cartModelPath = 'phase_12/models/bossbotHQ/Coggolf_cart3.bam'
        self.moPaths = ['phase_14/models/paths/ct-citycar-drivepath-1.egg',
            'phase_14/models/paths/ct-citycar-drivepath-2.egg',
            'phase_14/models/paths/ct-citycar-drivepath-3.egg',
            'phase_14/models/paths/ct-citycar-drivepath-4.egg',
            'phase_14/models/paths/ct-citycar-drivepath-5.egg',
            'phase_14/models/paths/ct-citycar-drivepath-6.egg']
        self.moPath = None
        self.soundEngineLoop = None
        self.soundDriveByHorn = None
        self.ivalTDisplace = None
        self.pathIndex = None
        self.wheelSpinTrack = None
        self.collNodePath = None
        self.soundDriveBy = None

    def setIvalTDisplace(self, displace):
        self.ivalTDisplace = displace

    def setPathIndex(self, index):
        self.pathIndex = index

    def setState(self, state, timestamp):
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        self.fsm.request(state, [ts])

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterPathFollow(self, ts):
        duration = CityCartGlobals.index2Duration[self.pathIndex]
        self.moPath = NURBSMopath.NURBSMopath(self.moPaths[self.pathIndex], name = self.uniqueName('DCityCart_moPath'))
        startT = 0.0
        if ts > 0.0:
            startT = (ts % duration) * (1.0 / duration)
        self.moPath.play(self, loop = True, duration = duration, startT = startT)
        base.taskMgr.add(self.__drive, self.uniqueName('DCityCart.drive'))
        self.wheelSpinTrack = Parallel()
        for name in ['leftFrontWheel', 'rightBackWheel', 'rightFrontWheel', 'leftBackWheel']:
            wheel = self.find('**/' + name)
            self.wheelSpinTrack.append(LerpHprInterval(wheel, duration = 0.1, hpr = (0, 360, 0), startHpr = (0, 0, 0)))
        self.wheelSpinTrack.loop()
        self.accept('enter' + self.collNodePath.node().getName(), self.__handleRanOver)

    def __handleRanOver(self, entry):
        self.suitInCar.setChat(CityCartGlobals.SuitRanOverTaunt)
        self.sendUpdate('hitByCar')
        self.cr.playGame.getPlace().fsm.request('stop')
        base.localAvatar.b_setAnimState('squish', callback = self.cr.playGame.getPlace().fsm.request, extraArgs = ['walk'])

    def __drive(self, task):
        if base.localAvatar.getDistance(self) < 10.0:
            if self.soundDriveByHorn.status() == self.soundDriveByHorn.READY:
                wantsToHonk = random.randint(0, 3)
                if wantsToHonk == 3:
                    base.playSfx(self.soundDriveByHorn)
                return task.cont
        elif base.localAvatar.getDistance(self) < 20.0:
            if self.soundDriveBy.status() == self.soundDriveBy.READY:
                base.playSfx(self.soundDriveBy)
                return task.cont
        return task.cont

    def exitPathFollow(self):
        self.ignore('enter' + self.collNodePath.node().getName())
        base.taskMgr.remove(self.uniqueName('DCityCart.drive'))
        if self.wheelSpinTrack:
            self.wheelSpinTrack.finish()
            self.wheelSpinTrack = None
        if self.moPath:
            self.moPath.stop()
            self.moPath = None

    def enterCollision(self, ts):
        pass

    def exitCollision(self):
        pass

    def generate(self):
        DistributedNode.generate(self)
        self.cart = loader.loadModel(self.cartModelPath)
        self.cart.reparentTo(self)
        self.cart.setH(180)
        plans = []
        for plan in SuitBank.getSuits():
            if plan.getSuitType() != SuitType.B:
                plans.append(plan)
        plan = random.choice(plans)
        self.suitInCar = Suit()
        self.suitInCar.level = 0
        self.suitInCar.generate(plan, Variant.NORMAL)
        self.suitInCar.loop('sit')
        self.suitInCar.disableRay()
        self.suitInCar.setScale(0.7)
        self.suitInCar.setH(180)
        self.suitInCar.setPos(0, -1, -1.5)
        self.suitInCar.reparentTo(self.cart.find('**/seat1'))
        self.suitInCar.show()
        self.soundEngineLoop = base.audio3d.loadSfx('phase_6/audio/sfx/KART_Engine_loop_0.ogg')
        base.audio3d.attachSoundToObject(self.soundEngineLoop, self)
        base.playSfx(self.soundEngineLoop, looping = 1)
        self.soundDriveByHorn = base.audio3d.loadSfx(self.honkSfxPath)
        base.audio3d.attachSoundToObject(self.soundDriveByHorn, self)
        self.soundDriveBy = base.audio3d.loadSfx('phase_14/audio/sfx/cogtropolis_citycar_driveby.ogg')
        base.audio3d.attachSoundToObject(self.soundDriveBy, self)
        sphere = CollisionSphere(0, 0, 0, 2.5)
        sphere.setTangible(0)
        node = CollisionNode(self.uniqueName('cartSphere'))
        node.setCollideMask(CIGlobals.WallBitmask)
        node.addSolid(sphere)
        self.collNodePath = self.attachNewNode(node)
        self.collNodePath.setZ(1.5)
        self.collNodePath.setSy(2.0)
        self.collNodePath.setSx(1.75)

    def disable(self):
        self.fsm.requestFinalState()
        if self.moPath:
            self.moPath.stop()
            self.moPath = None
        self.moPaths = None
        self.honkSfxPath = None
        self.cartModelPath = None
        self.soundEngineLoop = None
        self.soundDriveBy = None
        if self.suitInCar:
            self.suitInCar.disable()
            self.suitInCar.delete()
            self.suitInCar = None
        if self.cart:
            self.cart.removeNode()
            self.cart = None
        del self.fsm
        DistributedNode.disable(self)
Пример #7
0
class Movement(DirectObject.DirectObject):
    def __init__(self, parent):
        self.parent = parent

        self.hovered_unit_id = None
        self.hovered_tile = None
        self.hovered_compass_tile = None

        self.mouse_node = aspect2d.attachNewNode('mouse_node')
        self.move_node = aspect2d.attachNewNode('move_node')
        self.move_outline_node = NodePath('')
        self.move_np_list = []
        self.target_info_node = None

        self.accept("mouse1", self.mouseLeftClick)
        self.accept("mouse1-up", self.mouseLeftClickUp)

        #taskMgr.add(self.rayupdate, 'rayupdate_task')
        taskMgr.add(self.pickerTask, 'picker_task')
        taskMgr.add(self.positionTask, 'position_task', sort=2)

        self.color_scale_parallel = None

        # Create movement compass nodes
        self.turn_node = NodePath('turn_node')
        self.turn_node.setTag('show', '0')
        self.turn_np_list = []
        for i in xrange(9):
            text = TextNode('node name')
            text.setAlign(TextNode.ACenter)
            if i == 0:
                text.setText('NW')
                key = utils.HEADING_NW
            elif i == 1:
                text.setText('N')
                key = utils.HEADING_N
            elif i == 2:
                text.setText('NE')
                key = utils.HEADING_NE
            elif i == 3:
                text.setText('W')
                key = utils.HEADING_W
            elif i == 4:
                text.setText('E')
                key = utils.HEADING_E
            elif i == 5:
                text.setText('SW')
                key = utils.HEADING_SW
            elif i == 6:
                text.setText('S')
                key = utils.HEADING_S
            elif i == 7:
                text.setText('SE')
                key = utils.HEADING_SE
            elif i == 8:
                text.setText('X')
                key = utils.HEADING_NONE
            textNodePath = self.turn_node.attachNewNode(text)
            textNodePath.setColor(1, 1, 1)
            textNodePath.setScale(0.06)
            textNodePath.setTag('key', str(key))
            self.turn_np_list.append(textNodePath)

    def calcUnitAvailMove(self, unit_id):
        """Displays visual indicator of tiles which are in movement range of the selected unit."""
        # First delete old movement list
        for c in self.move_np_list:
            c.removeNode()
        self.move_np_list = []
        # Start calculation of new list
        unit = self.parent.local_engine.units[unit_id]
        if self.parent.turn_player != self.parent.player_id:
            return
        if unit:
            unit['move_dict'] = getMoveDict(unit,
                                            self.parent.local_engine.level,
                                            self.parent.local_engine.units)
            self.parent.local_engine.units[unit_id]['move_dict'] = unit[
                'move_dict']
            move_dict = unit['move_dict']
            for tile in move_dict:
                text = TextNode('node name')
                text.setText("%s" % move_dict[tile])
                text.setAlign(TextNode.ACenter)
                textNodePath = self.move_node.attachNewNode(text)
                textNodePath.setColor(1, 1, 1)
                textNodePath.setScale(0.06)
                textNodePath.setPythonTag('pos', tile)
                pos2d = utils.pointCoordIn2d(
                    Point3(utils.TILE_SIZE * (tile[0] + 0.5),
                           utils.TILE_SIZE * (tile[1] + 0.5),
                           utils.GROUND_LEVEL))
                textNodePath.setPos(pos2d)
                self.move_np_list.append(textNodePath)

    def showUnitAvailMove(self):
        self.move_node.reparentTo(aspect2d)
        self.hovered_tile = None
        #self.drawMoveOutline(self.calcMoveOutline(move_dict, self.parent.local_engine.units[unit_id]['pos']))

    def hideUnitAvailMove(self):
        self.move_node.detachNode()

    """
    def calcMoveOutline(self, move_dict, pos):
        outline = {}
        for tile in move_dict:
            dir = []
            if not (tile[0]-1, tile[1]) in move_dict and (tile[0]-1, tile[1]) != pos:
                dir.append('W')
            if not (tile[0], tile[1]-1) in move_dict and (tile[0], tile[1]-1) != pos:
                dir.append('S')
            if not (tile[0]+1, tile[1]) in move_dict and (tile[0]+1, tile[1]) != pos:
                dir.append('E')                
            if not (tile[0], tile[1]+1) in move_dict and (tile[0], tile[1]+1) != pos:
                dir.append('N')
            if dir != []:
                outline[tile] = dir
        return outline
    
    def drawMoveOutline(self, outline):
        self.move_outline_node.removeNode()
        zpos = utils.GROUND_LEVEL + 0.01
        off = 0.1
        segs = LineSegs()
        segs.setThickness(3)
        segs.setColor(Vec4(0.686,1,0.992,1))
        for tile in outline:
            for dir in outline[tile]:
                if dir == 'N':
                    d1 = 0
                    d2 = 0
                    if (tile[0]+1, tile[1]) in outline and 'N' in outline[(tile[0]+1, tile[1])]:
                        d2 = off
                    elif (tile[0]+1, tile[1]+1) in outline:
                        d2 = 2*off
                    if (tile[0]-1, tile[1]) in outline and 'N' in outline[(tile[0]-1, tile[1])]:
                        d1 = off
                    elif (tile[0]-1, tile[1]+1) in outline:
                        d1 = 2*off
                    segs.moveTo(tile[0]+off-d1, tile[1]+1-off, zpos)
                    segs.drawTo(tile[0]+1-off+d2, tile[1]+1-off, zpos)
                elif dir == 'S':
                    d1 = 0
                    d2 = 0
                    if (tile[0]+1, tile[1]) in outline and 'S' in outline[(tile[0]+1, tile[1])]:
                        d2 = off
                    elif (tile[0]+1, tile[1]-1) in outline:
                        d2 = 2*off
                    if (tile[0]-1, tile[1]) in outline and 'S' in outline[(tile[0]-1, tile[1])]:
                        d1 = off
                    elif (tile[0]-1, tile[1]-1) in outline:
                        d1 = 2*off                  
                    segs.moveTo(tile[0]+off-d1, tile[1]+off, zpos)
                    segs.drawTo(tile[0]+1-off+d2, tile[1]+off, zpos)
                elif dir == 'W':
                    d1 = 0
                    d2 = 0
                    if (tile[0], tile[1]+1) in outline and 'W' in outline[(tile[0], tile[1]+1)]:
                        d2 = off
                    elif (tile[0]-1, tile[1]+1) in outline:
                        d2 = 2*off
                    if (tile[0], tile[1]-1) in outline and 'W' in outline[(tile[0], tile[1]-1)]:
                        d1 = off                     
                    elif (tile[0]-1, tile[1]-1) in outline:
                        d1 = 2*off
                    segs.moveTo(tile[0]+off, tile[1]+off-d1, zpos)
                    segs.drawTo(tile[0]+off, tile[1]+1-off+d2, zpos)
                elif dir == 'E':
                    d1 = 0
                    d2 = 0
                    if (tile[0], tile[1]+1) in outline and 'E' in outline[(tile[0], tile[1]+1)]:
                        d2 = off
                    elif (tile[0]+1, tile[1]+1) in outline:
                        d2 = 2*off
                    if (tile[0], tile[1]-1) in outline and 'E' in outline[(tile[0], tile[1]-1)]:
                        d1 = off                     
                    elif (tile[0]+1, tile[1]-1) in outline:
                        d1 = 2*off                   
                    segs.moveTo(tile[0]+1-off, tile[1]+off-d1, zpos)
                    segs.drawTo(tile[0]+1-off, tile[1]+1-off+d2, zpos)                                        
        self.move_outline_node = render.attachNewNode(segs.create())
        self.move_outline_node.setBin("fixed", 40)
        #self.move_outline_node.setDepthTest(False)
        #self.move_outline_node.setDepthWrite(False)
        self.move_outline_node.setLightOff()  
    """

    def showMoveCompass(self, dest):
        # Calculate postion of compass nodes based on destination tile
        for i in self.turn_np_list:
            i.setPythonTag('pos', utils.getHeadingTile(i.getTag('key'), dest))
        # Show compass nodes
        self.turn_node.reparentTo(aspect2d)
        self.turn_node.setPythonTag('pos', dest)
        self.turn_node.setTag('show', '1')

        # Hide move nodes
        self.move_node.detachNode()

    def hideMoveCompass(self):
        # Hide compass nodes
        self.turn_node.detachNode()
        self.turn_node.setTag('show', '0')
        if self.hovered_compass_tile != None:
            self.hovered_compass_tile.setColor(1, 1, 1)
            self.hovered_compass_tile.setScale(0.05)
            self.color_scale_parallel.pause()
            self.hovered_compass_tile = None

    def mouseLeftClick(self):
        if self.parent.interface.hovered_gui != None:
            return

        if self.hovered_unit_id != None:
            unit_id = int(self.hovered_unit_id)
            pickedCoord = self.parent.local_engine.getCoordsByUnit(unit_id)
            # Player can only select his own units
            if self.parent.local_engine.isThisMyUnit(unit_id):
                if unit_id != self.parent.sel_unit_id:
                    self.parent.selectUnit(unit_id)
                else:
                    # Remember movement tile so we can send orientation message when mouse is depressed
                    # Do this only if it is our turn
                    if self.parent.player_id == self.parent.turn_player:
                        self.unit_move_destination = pickedCoord
                        self.showMoveCompass(self.unit_move_destination)
            elif self.parent.local_engine.isThisEnemyUnit(unit_id):
                if self.parent.sel_unit_id != None and self.parent.player_id == self.parent.turn_player:
                    self.parent.render_manager.unit_renderer_dict[
                        self.parent.
                        sel_unit_id].target_unit = self.parent.render_manager.unit_renderer_dict[
                            unit_id]
                    if self.parent._anim_in_process == False:
                        ClientMsg.shoot(self.parent.sel_unit_id, unit_id)

        elif self.hovered_tile != None:
            if self.parent.sel_unit_id != None and self.parent.player_id == self.parent.turn_player:
                # Remember movement tile so we can send movement message when mouse is depressed
                # Do this only if it is our turn
                move_coord = self.hovered_tile.getPythonTag('pos')
                if self.parent.local_engine.units[self.parent.sel_unit_id][
                        'move_dict'].has_key(move_coord):
                    self.unit_move_destination = move_coord
                    self.showMoveCompass(self.unit_move_destination)

    def mouseLeftClickUp(self):
        """Handles left mouse click actions when mouse button is depressed.
           Used for unit movement.
        """
        o = None
        if self.hovered_compass_tile != None:
            x = self.turn_node.getPythonTag('pos')[0]
            y = self.turn_node.getPythonTag('pos')[1]
            orientation = int(self.hovered_compass_tile.getTag('key'))
            if orientation == utils.HEADING_NW:
                o = Point2(x - 1, y + 1)
            elif orientation == utils.HEADING_N:
                o = Point2(x, y + 1)
            elif orientation == utils.HEADING_NE:
                o = Point2(x + 1, y + 1)
            elif orientation == utils.HEADING_W:
                o = Point2(x - 1, y)
            elif orientation == utils.HEADING_E:
                o = Point2(x + 1, y)
            elif orientation == utils.HEADING_SW:
                o = Point2(x - 1, y - 1)
            elif orientation == utils.HEADING_S:
                o = Point2(x, y - 1)
            elif orientation == utils.HEADING_SE:
                o = Point2(x + 1, y - 1)
            else:
                o = None

        self.hideMoveCompass()
        if o != None:
            ClientMsg.move(self.parent.sel_unit_id, (x, y), (o.x, o.y))

    def positionTask(self, task):
        # If turn node is displayed, you have to cancel turning or turn to be able to pick another unit or another tile to move to
        if self.turn_node.getTag('show') == '1':
            for tile in self.turn_np_list:
                pos = Point3(
                    utils.TILE_SIZE * (tile.getPythonTag('pos')[0] + 0.5),
                    utils.TILE_SIZE * (tile.getPythonTag('pos')[1]) + 0.5,
                    utils.GROUND_LEVEL)
                pos2d = utils.pointCoordIn2d(pos)
                tile.setPos(pos2d)
        else:
            for unit in self.parent.render_manager.unit_renderer_dict.itervalues(
            ):
                p = utils.nodeCoordIn2d(unit.model)
                unit.node_2d.setPos(p)
            for tile in self.move_np_list:
                pos = Point3(
                    utils.TILE_SIZE * (tile.getPythonTag('pos')[0] + 0.5),
                    utils.TILE_SIZE * (tile.getPythonTag('pos')[1] + 0.5),
                    utils.GROUND_LEVEL)
                pos2d = utils.pointCoordIn2d(pos)
                tile.setPos(pos2d)
        return task.cont

    def pickerTask(self, task):
        if self.parent._anim_in_process:
            self.hovered_unit_id = None
            self.hovered_tile = None
            self.hovered_compass_tile = None
            return task.cont

        if self.parent.interface.hovered_gui != None:
            if self.hovered_unit_id != None:
                self.parent.render_manager.unit_marker_renderer.unmarkHovered(
                    self.hovered_unit_id)
                self.hovered_unit_id = None
            if self.hovered_tile != None and not self.hovered_tile.isEmpty():
                self.hovered_tile.setColor(1, 1, 1)
                self.hovered_tile.setScale(0.05)
                self.color_scale_parallel.pause()
            if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty(
            ):
                self.hovered_compass_tile.setColor(1, 1, 1)
                self.hovered_compass_tile.setScale(0.05)
                self.color_scale_parallel.pause()
            return task.cont

        min_distance = 0.5
        min_unit_id = None
        min_tile = None
        min_compass_tile = None
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            r2d = Point3(mpos.getX(), 0, mpos.getY())
            a2d = aspect2d.getRelativePoint(render2d, r2d)
            self.mouse_node.setPos(a2d)

            # At the end of all this we have:
            # - min_distance to a unit or a movement node, IF this distance is lower than 0.5 which is set at the beginning
            # - min_unit_id - ID of unit which is closest to the mouse, or None if there is a movement tile closer, or if everything is further than 0.5
            # - min_tile - nodepath of the movement tile closest to the mouse, or None if there is a unit closer, or if evertythin is further than 0.5
            if self.turn_node.getTag('show') == '1':
                # Get 2d coordinates for every compass node
                for tile in self.turn_np_list:
                    # We cannot do nodepath.getDistance() because tiles are reparented to self.turn_node and are in different coord space than mouse node
                    # So we do simple vector math to get distance
                    d = Vec3(self.mouse_node.getPos() - tile.getPos()).length()
                    if d < min_distance:
                        min_distance = d
                        min_unit_id = None
                        min_tile = None
                        min_compass_tile = tile
            else:
                # Get 2d coordinates of all units
                for unit_id in self.parent.render_manager.unit_renderer_dict:
                    unit = self.parent.render_manager.unit_renderer_dict[
                        unit_id]
                    if self.parent.local_engine.isThisMyUnit(unit_id):
                        # Calculate distance between every friendly unit and mouse cursor and remember closest unit
                        d = self.mouse_node.getDistance(unit.node_2d)
                        if d < min_distance:
                            min_distance = d
                            min_unit_id = unit_id
                    else:
                        # Calculate distance between every enemy unit and mouse cursor and remember closest unit
                        d = self.mouse_node.getDistance(unit.node_2d)
                        # To target enemy unit, distance has to be even smaller than needed for regular selection/movement
                        if d < min_distance and d < 0.1:
                            min_distance = d
                            min_unit_id = unit_id

                # Get 2d coordinates for every movement node of the selected unit
                for tile in self.move_np_list:
                    # We cannot do nodepath.getDistance() because tiles are reparented to self.move_node and are in different coord space than mouse node
                    # So we do simple vector math to get distance
                    d = Vec3(self.mouse_node.getPos() - tile.getPos()).length()
                    if d < min_distance:
                        min_distance = d
                        min_unit_id = None
                        min_tile = tile

        # If a unit is the closest to the mouse:
        # - hide movement nodes (Incubation style!)
        # - unmark last hovered unit
        # - unmark last hovered tile
        # - mark new hovered unit
        # TODO: ogs: potencijalna optimizacija da se provjeri da li je self.hovered_unit_id = min_unit_id, tada ne treba unmark+mark
        if min_compass_tile != None:
            if self.hovered_tile != None and not self.hovered_tile.isEmpty():
                self.hovered_tile.setColor(1, 1, 1)
                self.hovered_tile.setScale(0.05)
                self.color_scale_parallel.pause()
                self.hovered_tile = None
            if min_compass_tile != self.hovered_compass_tile:
                if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty(
                ):
                    self.hovered_compass_tile.setColor(1, 1, 1)
                    self.hovered_compass_tile.setScale(0.05)
                    self.color_scale_parallel.pause()
                min_compass_tile.setColor(1, 0, 0)
                s1 = Sequence(
                    LerpColorInterval(min_compass_tile, 0.5, (1, 1, 0, 1)),
                    LerpColorInterval(min_compass_tile, 0.5, (1, 0, 0, 1)))
                s2 = Sequence(LerpScaleInterval(min_compass_tile, 0.5, (0.1)),
                              LerpScaleInterval(min_compass_tile, 0.5, (0.05)))
                self.color_scale_parallel = Parallel(s1, s2)
                self.color_scale_parallel.loop()
            self.hovered_compass_tile = min_compass_tile
        elif min_unit_id != None:
            self.move_node.detachNode()
            if min_unit_id != self.hovered_unit_id and self.hovered_unit_id != None:
                if self.parent.render_manager.unit_renderer_dict.has_key(
                        int(self.hovered_unit_id)):
                    self.parent.render_manager.unit_marker_renderer.unmarkHovered(
                        self.hovered_unit_id)
            self.parent.render_manager.unit_marker_renderer.markHovered(
                min_unit_id)
            if self.hovered_tile != None and not self.hovered_tile.isEmpty():
                self.hovered_tile.setColor(1, 1, 1)
                self.hovered_tile.setScale(0.05)
                self.color_scale_parallel.pause()
                self.hovered_tile = None
            self.hovered_unit_id = min_unit_id
        # If a movement tile is closest to the mouse:
        # - unmark last hovered unit
        # - unmark last marked tile
        # - show movement nodes (Incubation style!)
        # - mark new hovered tile
        elif min_tile != None:
            if self.hovered_unit_id != None:
                if self.parent.render_manager.unit_renderer_dict.has_key(
                        int(self.hovered_unit_id)):
                    self.parent.render_manager.unit_marker_renderer.unmarkHovered(
                        self.hovered_unit_id)
                self.hovered_unit_id = None
            if min_tile != self.hovered_tile:
                self.move_node.reparentTo(aspect2d)
                if self.hovered_tile != None and not self.hovered_tile.isEmpty(
                ):
                    self.hovered_tile.setColor(1, 1, 1)
                    self.hovered_tile.setScale(0.05)
                    self.color_scale_parallel.pause()
                min_tile.setColor(1, 0, 0)
                s1 = Sequence(LerpColorInterval(min_tile, 0.5, (1, 1, 0, 1)),
                              LerpColorInterval(min_tile, 0.5, (1, 0, 0, 1)))
                s2 = Sequence(LerpScaleInterval(min_tile, 0.5, (0.1)),
                              LerpScaleInterval(min_tile, 0.5, (0.05)))
                self.color_scale_parallel = Parallel(s1, s2)
                self.color_scale_parallel.loop()
            self.hovered_tile = min_tile
        # If neither any of the units nor any of the movement tiles is closer than 0.5:
        # - unmark last hovered unit
        # - unmark last hovered tile
        else:
            if self.hovered_unit_id != None:
                if self.parent.render_manager.unit_renderer_dict.has_key(
                        int(self.hovered_unit_id)):
                    self.parent.render_manager.unit_marker_renderer.unmarkHovered(
                        self.hovered_unit_id)
                self.hovered_unit_id = None
            if self.hovered_tile != None and not self.hovered_tile.isEmpty():
                self.hovered_tile.setColor(1, 1, 1)
                self.hovered_tile.setScale(0.05)
                self.color_scale_parallel.pause()
                self.hovered_tile = None
            if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty(
            ):
                self.hovered_compass_tile.setColor(1, 1, 1)
                self.hovered_compass_tile.setScale(0.05)
                self.color_scale_parallel.pause()
                self.hovered_compass_tile = None
        return task.cont