def _getSpawnPoint(self, player): # in solo-mode, if there's an existing live player on the map, spawn at whichever # spot is farthest from them (keeps the action spread out) if self._soloMode: livingPlayer = None for team in self.teams: for player in team.players: if player.isAlive(): p = player.actor.node.position livingPlayer = player livingPlayerPos = p break if livingPlayer: playerPos = bs.Vector(*livingPlayerPos) points = [] for team in self.teams: startPos = bs.Vector( *self.getMap().getStartPosition(team.getID())) points.append([(startPos - playerPos).length(), startPos]) points.sort() return points[-1][1] else: return None else: return None
def zUpdate(self): # update one of our bot lists each time through.. # first off, remove dead bots from the list # (we check exists() here instead of dead.. we want to keep them around even if they're just a corpse) #####This is overloaded from bsSpaz to prevent zombies from attacking player Zombies. try: botList = self._botLists[self._botUpdateList] = [ b for b in self._botLists[self._botUpdateList] if b.exists() ] except Exception: bs.printException("error updating bot list: " + str(self._botLists[self._botUpdateList])) self._botUpdateList = (self._botUpdateList + 1) % self._botListCount # update our list of player points for the bots to use playerPts = [] for player in bs.getActivity().players: try: if player.isAlive(): if player.gameData[ 'lives'] > 0: #If the player has lives, add to attack points playerPts.append( (bs.Vector(*player.actor.node.position), bs.Vector(*player.actor.node.velocity))) except Exception: bs.printException('error on bot-set _update') for b in botList: b._setPlayerPts(playerPts) b._updateAI()
def zUpdate(self): # update one of our bot lists each time through.. # first off, remove dead bots from the list # (we check exists() here instead of dead.. we want to keep them around even if they're just a corpse) #####This is overloaded from bsSpaz to walk over other players' mines, but not source player. try: botList = self._botLists[self._botUpdateList] = [b for b in self._botLists[self._botUpdateList] if b.exists()] except Exception: bs.printException("error updating bot list: "+str(self._botLists[self._botUpdateList])) self._botUpdateList = (self._botUpdateList+1)%self._botListCount # update our list of player points for the bots to use playerPts = [] for player in bs.getActivity().players: try: if player.exists(): if not player is self.sourcePlayer: #If the player has lives, add to attack points for m in player.gameData['mines']: if not m.isHome and m.exists(): playerPts.append((bs.Vector(*m.node.position), bs.Vector(0,0,0))) except Exception: bs.printException('error on bot-set _update') for b in botList: b._setPlayerPts(playerPts) b._updateAI()
def _updatePlayerOrder(self): # calc all player distances for player in self.players: try: pos = bs.Vector(*player.actor.node.position) except Exception: pos = None if pos is not None: rIndex = player.gameData['lastRegion'] r1 = self._regions[rIndex] r1Pt = bs.Vector(*r1._pt[:3]) r2 = self._regions[0] if rIndex == len( self._regions) - 1 else self._regions[rIndex + 1] r2Pt = bs.Vector(*r2._pt[:3]) r1Dist = (pos - r1Pt).length() r2Dist = (pos - r2Pt).length() amt = 1.0 - (r2Dist / (r2Pt - r1Pt).length()) amt = player.gameData['lap'] + (rIndex + amt) * ( 1.0 / len(self._regions)) player.gameData['distance'] = amt # sort players by distance and update their ranks pList = [[player.gameData['distance'], player] for player in self.players] pList.sort(reverse=True) for i, p in enumerate(pList): try: p[1].gameData['rank'] = i if p[1].actor is not None: n = p[1].actor.distanceTxt if n.exists(): n.text = str(i + 1) if p[1].isAlive() else '' except Exception: bs.printException('error updating player orders')
def _getPlayerSpawnPosition(self,player): # iterate until we find a spawn owned by this team.. spawnCount = len(self.getMap().spawnByFlagPoints) # get all spawns owned by this team spawns = [i for i in range(spawnCount) if self._flags[i].getTeam() is player.getTeam()] closestSpawn = 0 closestDistance = 9999 # now find the spawn thats closest to a spawn not owned by us.. we'll use that one for s in spawns: p = self.getMap().spawnByFlagPoints[s] ourPt = bs.Vector(p[0],p[1],p[2]) for os in [i for i in range(spawnCount) if self._flags[i].getTeam() is not player.getTeam()]: p = self.getMap().spawnByFlagPoints[os] theirPt = bs.Vector(p[0],p[1],p[2]) dist = (theirPt-ourPt).length() if dist < closestDistance: closestDistance = dist closestSpawn = s pt = self.getMap().spawnByFlagPoints[closestSpawn] xRange = (-0.5,0.5) if pt[3] == 0 else (-pt[3],pt[3]) zRange = (-0.5,0.5) if pt[5] == 0 else (-pt[5],pt[5]) pt = (pt[0]+random.uniform(*xRange),pt[1],pt[2]+random.uniform(*zRange)) return pt
def _updateBots(self): bots = self._bots.getLivingBots() for bot in bots: bot.targetFlag = None # if we're waiting on a continue, stop here so they don't keep scoring if self.isWaitingForContinue(): self._bots.stopMoving() return # if we've got a flag and no player are holding it, find the closest bot to it, and make them the designated flag-bearer if self._flag.node.exists(): for p in self.players: try: if p.actor.isAlive( ) and p.actor.node.holdNode == self._flag.node: return except Exception: bs.printException("exception checking hold node") pass fp = bs.Vector(*self._flag.node.position) closestBot = None for bot in bots: if bot.heldCount > 0: continue # if a bot is picked up he should forget about the flag bp = bs.Vector(*bot.node.position) l = (bp - fp).length() if (closestBot is None or l < closestLen): closestLen = l closestBot = bot if closestBot is not None: closestBot.targetFlag = self._flag
def mineUpdate(self): #print self.mineCount #purge dead mines, update their animantion, check if players died for m in self.mines: if not m.exists(): self.mines.remove(m) else: #First, check if any player is within the current death zone for player in self.players: if not player.actor is None: if player.actor.isAlive(): p1 = player.actor.node.position p2 = m.node.position diff = (bs.Vector(p1[0] - p2[0], 0.0, p1[2] - p2[2])) dist = (diff.length()) if dist < m.rad: player.actor.handleMessage(bs.DieMessage()) #Now tell the circle to grow to the new size if m.rad < self.maxSize: bs.animateArray( m.zone, 'size', 1, { 0: [m.rad * 2], self.updateRate: [(m.rad + self.growthRate) * 2] }) #Tell the circle to be the new size. This will be the new check radius next time. m.rad += self.growthRate #make a new mine if needed. if self.mineCount < self.maxMines: pos = self.getRandomPowerupPoint() self.mineCount += 1 self._flashMine(pos) bs.gameTimer(950, bs.Call(self._makeMine, pos))
def _update(self): try: botList = self._botLists[self._botUpdateList] = [b for b in self._botLists[self._botUpdateList] if b.exists()] except Exception: bs.printException("error updating bot list: "+str(self._botLists[self._botUpdateList])) self._botUpdateList = (self._botUpdateList+1)%self._botListCount playerPts = [] for player in bs.getActivity().teams[(self.team+1)%2].players: try: if player.isAlive(): playerPts.append((bs.Vector(*player.actor.node.position), bs.Vector(*player.actor.node.velocity))) except Exception: bs.printException('error on bot-set _update') for b in botList: b._setPlayerPts(playerPts) b._updateAI()
def activateArea(self): mineOK = False if self.exists(): r = self.defRad fudge = self.getActivity().minOverlap #This is the minimum overlap to join owner's territory (not used to check enemy overlap) p1 = self.node.position self.node.maxSpeed = 0.0 #We don't want mines moving around. They could leave their zone. self.damping = 100 #First, confirm that this mine "touches" owner's mines if self.sourcePlayer.exists(): for m in self.sourcePlayer.gameData['mines']: if m.exists() and not m.died: if m.rad != 0: #Don't check un-activated mines p2 = m.node.position diff = (bs.Vector(p1[0]-p2[0],0.0,p1[2]-p2[2])) dist = (diff.length()) if dist < (m.rad + r)-fudge: #We check m.rad just in case it's somehow different. However, this probably shouldn't happen. Unless I change gameplay later. mineOK = True #mine adjoins owner's territory. Will set to false if it also adjoin's enemy though. break #Get out of the loop takeovers = [] if mineOK: for p in self.getActivity().players: if not p is self.sourcePlayer: if p.exists(): for m in p.gameData['mines']: if m.rad != 0.0: #Don't check un-activated mines p2 = m.node.position diff = (bs.Vector(p1[0]-p2[0],0.0,p1[2]-p2[2])) dist = (diff.length()) if dist < m.rad + r: #We check m.rad just in case it's somehowdifferent. However, this probably shouldn't happen. Unless I change gameplay later. mineOK = False takeovers = [] break #If we made it to here and mineOK is true, we can activate. Otherwise, we'll flash red and die. self.zone = bs.newNode('locator',attrs={'shape':'circle','position':self.node.position,'color':self.sourcePlayer.color,'opacity':0.5,'drawBeauty':False,'additive':True}) bs.animateArray(self.zone,'size',1,{0:[0.0],150:[2*r]}) #Make circle at the default radius to show players where it would go if OK if mineOK or self.isHome: self.activated = True self.rad = r #Immediately set this mine's radius else: #mine was not OK keys = {0:(1,0,0),49:(1,0,0),50:(1,1,1),100:(0,1,0)} bs.animateArray(self.zone,'color',3,keys,loop=True) bs.gameTimer(800, bs.WeakCall(self.handleMessage, bs.DieMessage()), repeat=False)
def calcBust(self, oVel): #Original speed (magnitude of velocity) oSpd = bs.Vector(*oVel).length() #Now get the dot product of the original velocity and current velocity. dot = sum(x*y for x,y in zip(oVel,self.node.velocity)) if oSpd*oSpd - dot > 50.0: #Basically, the more different the dot product from the square of the original #velocity vector, the more the ball trajectory changed when it it something. #This is the best way I could figure out how "hard" the ball hit. #A difference value was a pretty arbitrary choice. #Add a very short timer to allow just a couple of hits. bs.gameTimer(50, bs.WeakCall(self.doBust))
def doCirle(): if self.isAlive(): p = self.node.position p2 = self.lastPos diff = (bs.Vector(p[0]-p2[0],0.0,p[2]-p2[2])) dist = (diff.length()) if dist > 0.2: c = bs.getConfig()["effectsMod"]["color"] r = bs.newNode('locator',attrs={'shape':'circle','position':p,'color':self.node.color if c else (5,5,5),'opacity':1,'drawBeauty':False,'additive':False,'size':[0.2]}) bsUtils.animateArray(r,'size',1,{0:[0.2],2500:[0.2],3000:[0]}) bs.gameTimer(3000,r.delete) self.lastPos = self.node.position
def check4Players(self): if self._timeRemaining <= 0: self.stopTimer() bs.gameTimer(1500, self.deleteZone) for player in self.players: if not player.actor is None: if player.actor.isAlive(): p1 = player.actor.node.position p2 = self.zone.position diff = (bs.Vector(p1[0] - p2[0], 0.0, p1[2] - p2[2])) dist = (diff.length()) if dist > (self.getPlayersCount() * 0.7): player.actor.handleMessage(bs.DieMessage())
def __init__(self, position=(0, 5, -8), color=(1, 1, 1)): self._r1 = 0.7 self._rFudge = 0.15 bs.Actor.__init__(self) self._position = bs.Vector(*position) self.color = color p1 = position p2 = (position[0] + 1, position[1], position[2]) p3 = (position[0] - 1, position[1], position[2]) showInSpace = False self._hit = False n1 = bs.newNode('locator', attrs={ 'shape': 'circle', 'position': p1, 'color': self.color, 'opacity': 0.5, 'drawBeauty': showInSpace, 'additive': True }) n2 = bs.newNode('locator', attrs={ 'shape': 'circle', 'position': p2, 'color': self.color, 'opacity': 0.5, 'drawBeauty': showInSpace, 'additive': True }) n3 = bs.newNode('locator', attrs={ 'shape': 'circle', 'position': p3, 'color': self.color, 'opacity': 0.5, 'drawBeauty': showInSpace, 'additive': True }) n4 = bs.newNode('light', attrs={ 'color': self.color, 'position': p1, 'intensity': .5 }) bs.animateArray(n1, 'size', 1, {0: [0.0], 200: [self._r1 * 2.0]}) bs.animateArray(n2, 'size', 1, {0: [0.0], 200: [self._r1 * 2.0]}) bs.animateArray(n3, 'size', 1, {0: [0.0], 200: [self._r1 * 2.0]}) self._nodes = [n1, n2, n3, n4]
def __init__(self,position): self._r1 = 0.45 self._r2 = 1.1 self._r3 = 2.0 self._rFudge = 0.15 bs.Actor.__init__(self) self._position = bs.Vector(*position) self._hit = False showInSpace = False # it can be handy to test with this on to make sure the projection isn't too far off from the actual object.. n1 = bs.newNode('locator',attrs={'shape':'circle','position':position,'color':(0,1,0),'opacity':0.5,'drawBeauty':showInSpace,'additive':True}) n2 = bs.newNode('locator',attrs={'shape':'circleOutline','position':position,'color':(0,1,0),'opacity':0.3,'drawBeauty':False,'additive':True}) n3 = bs.newNode('locator',attrs={'shape':'circleOutline','position':position,'color':(0,1,0),'opacity':0.1,'drawBeauty':False,'additive':True}) self._nodes = [n1,n2,n3] bs.animateArray(n1,'size',1,{0:[0.0],200:[self._r1*2.0]}) bs.animateArray(n2,'size',1,{50:[0.0],250:[self._r2*2.0]}) bs.animateArray(n3,'size',1,{100:[0.0],300:[self._r3*2.0]}) bs.playSound(bs.getSound('laserReverse'))
def _bUpdate(self): # update one of our bot lists each time through.. # first off, remove dead bots from the list # (we check exists() here instead of dead.. we want to keep them around even if they're just a corpse) try: botList = self._botLists[self._botUpdateList] = \ [b for b in self._botLists[self._botUpdateList] if b.exists()] except Exception: bs.printException('error updating bot list: ' + str(self._botLists[self._botUpdateList])) self._botUpdateList = (self._botUpdateList + 1) % self._botListCount # update our list of player points for the bots to use playerPts = [] try: #if player.isAlive() and not (player is self.sourcePlayer): # playerPts.append((bs.Vector(*player.actor.node.position), # bs.Vector(*player.actor.node.velocity))) for n in bs.getNodes(): if n.getNodeType() == 'spaz': s = n.getDelegate() if isinstance(s, bsSpaz.SpazBot): if not s in self.getLivingBots(): if hasattr(s, 'sourcePlayer'): if not s.sourcePlayer is self.sourcePlayer: playerPts.append((bs.Vector(*n.position), bs.Vector(*n.velocity))) else: playerPts.append((bs.Vector(*n.position), bs.Vector(*n.velocity))) elif isinstance(s, bsSpaz.PlayerSpaz): try: if not (s.getPlayer().getTeam() is self.sourcePlayer.getTeam()): playerPts.append((bs.Vector(*n.position), bs.Vector(*n.velocity))) except: pass except Exception: bs.printException('error on bot-set _update') for b in botList: b._setPlayerPts(playerPts) b._updateAI()
def mineUpdate(self): for player in self.players: #Need to purge mines, whether or not player is living for m in player.gameData['mines']: if not m.exists(): player.gameData['mines'].remove(m) if not player.actor is None: if player.actor.isAlive(): pSafe = False p1 = player.actor.node.position for teamP in player.getTeam().players: for m in teamP.gameData['mines']: if m.exists(): if not m._exploded: p2 = m.node.position diff = (bs.Vector(p1[0]-p2[0],0.0,p1[2]-p2[2])) dist = (diff.length()) if dist < m.rad: pSafe = True break if not pSafe: #print player.getName(), "died with mines:", len(player.gameData['mines']) player.actor.handleMessage(bs.DieMessage())
def handleMessage(self,m): super(self.__class__, self).handleMessage(m) if isinstance(m, otherHitMessage): if self._exploded: return #Don't bother with calcs if we've done blowed up or busted. if self.shouldBust: myVel = self.node.velocity #Get the velocity at the instant of impact. We'll check it after 20ms (after bounce). If it has changed a lot, bust. bs.gameTimer(10, bs.WeakCall(self.calcBust,myVel)) else: return if isinstance(m,bs.DieMessage): self.node.delete() bs.gameTimer(100, self.nodeLight.delete) elif isinstance(m,bs.OutOfBoundsMessage): self.handleMessage(bs.DieMessage()) elif isinstance(m,bs.HitMessage): self.node.handleMessage("impulse",m.pos[0],m.pos[1],m.pos[2], m.velocity[0],m.velocity[1],m.velocity[2], 1.0*m.magnitude,1.0*m.velocityMagnitude,m.radius,0, m.forceDirection[0],m.forceDirection[1],m.forceDirection[2]) elif isinstance(m, bs.ImpactDamageMessage): print [dir(m), m.intensity] elif isinstance(m,snoMessage): #We should get a snoMessage any time a snowball hits a spaz. #We'll either explode (if we're exploding) or calculate like a punch. #We have to do this the hard way because the ImpactMessage won't do it for us (no source) #Below is modified pretty much from bsSpaz handling of a _punchHitMessage #print bsVector.Vector(*self.node.velocity).length() if self._exploded: return #Don't do anything if we've already done our damage, or if we've busted already if self.shouldExplode: """ Blows up the ball if it has not yet done so. """ if self._exploded: return self._exploded = True activity = self.getActivity() if activity is not None and self.node.exists(): blast = bsBomb.Blast(position=self.node.position,velocity=self.node.velocity, blastRadius=0.7,blastType='impact',sourcePlayer=self.sourcePlayer,hitType='snoBall',hitSubType='explode').autoRetain() # we blew up so we need to go away bs.gameTimer(1,bs.WeakCall(self.handleMessage,bs.DieMessage())) else: v = self.node.velocity #Only try to damage if the ball is moving at some reasonable rate of speed if bs.Vector(*v).length() > 5.0: node = bs.getCollisionInfo("opposingNode") # only allow one hit per node per ball if node is not None and node.exists() and not node in self._hitNodes: t = self.node.position #was punchPosition hitDir = self.node.velocity self._hitNodes.add(node) node.handleMessage(bs.HitMessage(pos=t, velocity=v, magnitude=bsVector.Vector(*v).length()*0.1, velocityMagnitude=bsVector.Vector(*v).length()*0.1, radius=0, srcNode=self.node, sourcePlayer=self.sourcePlayer, forceDirection = hitDir, hitType='snoBall', hitSubType='default')) if self.shouldBust: #Since we hit someone, let's bust: #Add a very short timer to allow one ball to hit more than one spaz if almost simultaneous. bs.gameTimer(50, bs.WeakCall(self.doBust)) else: bs.Actor.handleMessage(self,m)
def doHitAtPosition(self, pos, player): activity = self.getActivity() # ignore hits if the game is over or if we've already been hit if activity.hasEnded() or self._hit or not self._nodes: return 0 diff = (bs.Vector(*pos) - self._position) diff[ 1] = 0.0 # disregard y difference (our target point probably isnt exactly on the ground anyway) dist = diff.length() bullsEye = False points = 0 if dist <= self._r3 + self._rFudge: # inform our activity that we were hit self._hit = True self.getActivity().handleMessage(self.TargetHitMessage()) keys = {0: (1, 0, 0), 49: (1, 0, 0), 50: (1, 1, 1), 100: (0, 1, 0)} cDull = (0.3, 0.3, 0.3) if dist <= self._r1 + self._rFudge: bullsEye = True self._nodes[1].color = cDull self._nodes[2].color = cDull bs.animateArray(self._nodes[0], 'color', 3, keys, loop=True) popupScale = 1.8 popupColor = (1, 1, 0, 1) streak = player.gameData['streak'] points = 10 + min(20, streak * 2) bs.playSound(bs.getSound('bellHigh')) if streak > 0: bs.playSound( bs.getSound( 'orchestraHit4' if streak > 3 else 'orchestraHit3' if streak > 2 else 'orchestraHit2' if streak > 1 else 'orchestraHit')) elif dist <= self._r2 + self._rFudge: self._nodes[0].color = cDull self._nodes[2].color = cDull bs.animateArray(self._nodes[1], 'color', 3, keys, loop=True) popupScale = 1.25 popupColor = (1, 0.5, 0.2, 1) points = 4 bs.playSound(bs.getSound('bellMed')) else: self._nodes[0].color = cDull self._nodes[1].color = cDull bs.animateArray(self._nodes[2], 'color', 3, keys, loop=True) popupScale = 1.0 popupColor = (0.8, 0.3, 0.3, 1) points = 2 bs.playSound(bs.getSound('bellLow')) # award points/etc.. (technically should probably leave this up to the activity) popupStr = "+" + str(points) # if there's more than 1 player in the game, include their names and colors # so they know who got the hit if len(activity.players) > 1: popupColor = bs.getSafeColor(player.color, targetIntensity=0.75) popupStr += ' ' + player.getName() bs.PopupText(popupStr, position=self._position, color=popupColor, scale=popupScale).autoRetain() # give this player's team points and update the score-board player.getTeam().gameData['score'].add(points) activity._updateScoreBoard() # also give this individual player points (only applies in teams mode) activity.scoreSet.playerScored(player, points, showPoints=False, screenMessage=False) bs.animateArray(self._nodes[0], 'size', 1, { 800: self._nodes[0].size, 1000: [0.0] }) bs.animateArray(self._nodes[1], 'size', 1, { 850: self._nodes[1].size, 1050: [0.0] }) bs.animateArray(self._nodes[2], 'size', 1, { 900: self._nodes[2].size, 1100: [0.0] }) bs.gameTimer(1100, bs.Call(self.handleMessage, bs.DieMessage())) return bullsEye
def getDistFromPoint(self, pos): 'Given a point, returns distance squared from it' return (bs.Vector(*pos) - self._position).length()
def _onBotSpawn(self, spaz): # we want to move to the left by default spaz.targetPointDefault = bs.Vector(0, 0, 0)
def _on_spawn(self, bot): bot.targetPointDefault = bs.Vector(0,0,0)