def TakeAction(self,t): if not self.IsPlayer() and len(self.action_list) == 0: path,cost,enemy = self.FindNearestEnemy() if not enemy: return False offset = enemy.pos-self.pos #Check first if we can blast anyone for index,action in utils.r_enumerate(self.blast_action_creator.actions): if action.cost <= self.stats.mana: self.blast_action_creator.SetAction(index) if self.blast_action_creator.Valid(offset): self.action_list.extend( self.blast_action_creator.Create(offset,t,self) ) return self.action_list.pop(0) #If we get here there's nothing to return return super(BlastingMonster,self).TakeAction(t)
def TakeAction(self,t): # +-----------------------------------------------------------------------------------+ # | ..-#.-- . -. | # | -.%--+ . .+..+.. | # | .m##-m. ###+m | # | -m-*%%+. -m+%+-- | # | +%m% . .++++ | # | +-.-. ..++- .. -. | # | . . . . .m--+.-. -- . . . | # | .. +-. .mm-%.-. -..- | # | .. m.#**###-*#%##+.m + | # | -%%.#*#m. -m-+.. +.*#+* -. | # | -.+#-m-+. -..- +.+-+##- | # | +-##m. .-.... . . .-.+*%+. | # | - +-#%. --m.%m-. | # | ...m+m+.. . ..#+-. | # | .m#%-.. ..-#... | # | +.-+m--. .-.- | # | -.. - . | # | .. | # | | # | ____ | # | | _ \ ___ ___ | # | | |_) / _ \ / _ \ | # | | __/ (_) | (_) | | # | |_| \___/ \___/ | # | | # | | # |FIXME: This code is hacked-together rubbish. Implement something sensible | # +-----------------------------------------------------------------------------------+ if len(self.action_list) == 0 and self.IsPlayer(): return None if not self.IsPlayer() and len(self.action_list) == 0: #For a computer player, decide what to do #regular players populate this list themselves self.InvalidatePathCache() #Find the nearest enemy enemies = [] danger_score = 0. away_vector = Point(0,0) for player in self.tiles.wizards: for enemy in player.controlled: if enemy.player is self.player: continue #offset = utils.WrapDistance(enemy.pos,self.pos,self.tiles.width) #distance = offset.length() #path = self.tiles.PathTo(self.pos,enemy.pos) #if path == None: # cost = (enemy.pos-self.pos).length() #else: # cost = path.cost cost = (enemy.pos - self.pos).length() if cost < 6: danger_score += (enemy.stats.attack + enemy.stats.health + enemy.stats.mana)/cost away_vector -= (enemy.pos - self.pos) enemies.append((cost,enemy)) enemies.sort(lambda x,y : cmp(x[0],y[0])) if len(enemies) == 0: #wtf? There are no other wizards? the game should have ended return False cost,enemy = enemies[0] path = self.PathTo(enemy.pos) if path: cost = path.cost danger_score /= float(self.player.personality.confidence + self.stats.health + self.stats.mana) #print self.name,danger_score,away_vector,Point(0 if away_vector.x == 0 else 5.0/away_vector.x,0 if away_vector.y == 0 else 5.0/away_vector.y) target = self.pos + away_vector away_path = None if away_vector != Point(0,0): for adjust in utils.Spiral(15): final_target = target + adjust away_path = self.PathTo(final_target) if away_path: break if danger_score < 1 or self.player.personality.confidence > 5: #We're either not in danger or we're brash, so try wizard blasting the nearest enemy offset = enemy.pos-self.pos for index,action in utils.r_enumerate(self.blast_action_creator.actions): if action.cost < self.stats.mana: self.blast_action_creator.SetAction(index) if self.blast_action_creator.Valid(offset): self.action_list.extend( self.blast_action_creator.Create(offset,t,self) ) return self.action_list.pop(0) if danger_score > 1: #Stop saving, this is serious self.saving_for = None #we want to leave target = self.pos + away_vector if away_path: if self.stats.move > 0: #walk that way if self.move_action_creator.Valid(away_path.steps[0]): self.action_list.extend( self.move_action_creator.Create(away_path.steps[0],t,self) ) elif self.stats.mana > 0: if danger_score > 2 and self.player.personality.confidence < 4: #try a teleport to get away fast if self.stats.mana > self.teleport_action_creator.actions[1].cost*2: target_action = 1 elif self.stats.mana > self.teleport_action_creator.actions[0].cost: target_action = 0 else: #we can't do a teleport target_action = None if target_action != None: self.teleport_action_creator.SetAction(target_action) offset = final_target - self.pos if not self.teleport_action_creator.Valid(offset): #shit, we can't teleport there for some reason, let's try others in the same direction candidates = utils.Brensenham(final_target,self.pos,self.tiles.width) for point in candidates: if self.teleport_action_creator.Valid(point - self.pos): final_target = point offset = final_target - self.pos break else: offset = None if offset != None: #Woop can teleport self.action_list.extend( self.teleport_action_creator.Create(offset,t,self) ) elif self.ReadyToAttack(): #Not too dangerous, so attack! #Teleports are cool for getting in striking distance quickly If we've got enough mana left over to #strike, and we can get in there, lets give it a go offset = enemy.pos - self.pos if not self.saving_for and offset.length() < 10: if self.stats.mana > self.teleport_action_creator.actions[1].cost*2: target_action = 1 elif self.stats.mana > self.teleport_action_creator.actions[0].cost*2: target_action = 0 else: #we we don't want to do a teleport target_action = None if target_action != None: self.teleport_action_creator.SetAction(target_action) #We can't teleport right onto him, try a spiral for adjust in utils.Spiral(16): if self.teleport_action_creator.Valid(offset + adjust): self.action_list.extend( self.teleport_action_creator.Create(offset + adjust,t,self) ) return self.action_list.pop(0) break if len(self.action_list) == 0: #Not teleporting, maybe we want to move if self.stats.move > 0 and path: if self.move_action_creator.Valid(path.steps[0]): self.action_list.extend( self.move_action_creator.Create(path.steps[0],t,self) ) return self.action_list.pop(0) elif self.stats.move > 0: #move away to give us time to build up forces and look busy if away_path: path = away_path else: opposite_point = enemy.pos + Point(self.tiles.width/2,0) if enemy.pos.y < self.tiles.height/2: opposite_point.y = self.tiles.height-1 opposite_point.x %= self.tiles.width path = self.PathTo(opposite_point) if path: if self.move_action_creator.Valid(path.steps[0]): self.action_list.extend( self.move_action_creator.Create(path.steps[0],t,self) ) if len(self.action_list) == 0: if self.saving_for and self.saving_for.cost + self.player.personality.emergency_mana <= self.stats.mana: self.saving_for.creator.SetAction(self.saving_for.index) self.SummonMonster(self.saving_for.creator,t) self.saving_for = None if len(self.action_list) == 0: #We've dealt with the logic of getting away from or towards the enemy, but maybe we've #got mana to burn and we should summon some monsters #Which monster? Ideally we want the number of monsters we have to match our preference ratio #so cast the one which is furthest out if len(self.player.controlled) < self.player.personality.necessary_monsters and danger_score > self.player.personality.confidence/4: #just cast the first one we can afford for monster in self.monsters.monsters: if monster.cost + self.player.personality.emergency_mana <= self.stats.mana: monster.creator.SetAction(monster.index) self.SummonMonster(monster.creator,t) break elif len(self.player.controlled) < self.player.personality.desired_monsters: #We've already got a few (probably shitty) ones, so lets save up for a better one actual_counts = [] for monster in self.monsters.monsters: count = len([m for m in self.player.controlled if type(m) == monster.monster]) actual_counts.append(count) #print self.name,[(monster.monster.name,c) for (monster,c) in zip(self.monsters.monsters,actual_counts)] total = sum(actual_counts) actual_ratios = [0 if total == 0 else float(c)/total for c in actual_counts] required = sorted([(monster,monster.desirability - actual_ratio) for actual_ratio,monster in itertools.izip(actual_ratios,self.monsters.monsters)],lambda x,y:cmp(y[1],x[1])) #print self.name,[(monster.monster.name,needed) for (monster,needed) in required] monster,needed = required[0] if monster.cost + self.player.personality.emergency_mana <= self.stats.mana: monster.creator.SetAction(monster.index) self.SummonMonster(monster.creator,t) else: self.saving_for = monster #Stand-in AI logic until the game rules are fixed. There are two types, # tentative wizards do: # - Move away from the enemy if possible # - Shoot any enemy in range # - Otherwise try to summon a monster if you can, but stay above 6 mana # # gungho wizards do: # - Shoot any enemy in range # - Summon a Goblin if they can (but stay above 2 mana for shooting) # - # if self.player_type == players.PlayerTypes.TENTATIVE: # if self.stats.move > 0: # #Go away from the nearest enemy # opposite_point = enemy.pos + Point(self.tiles.width/2,0) # if enemy.pos.y < self.tiles.height/2: # opposite_point.y = self.tiles.height-1 # opposite_point.x %= self.tiles.width # path = self.tiles.PathTo(self.pos,opposite_point) # if path: # if self.move_action_creator.Valid(path.steps[0]): # self.action_list.extend( self.move_action_creator.Create(path.steps[0],t,self) ) # #We've had a chance, at moving, but maybe we decided not to? # if len(self.action_list) == 0: # offset = enemy.pos-self.pos # if self.blast_action_creator.Valid(offset): # self.action_list.extend( self.blast_action_creator.Create(offset,t,self) ) # elif self.stats.mana - self.summon_goblin_creator.cost >= 6: # #Want to summon a goblin, find the first spot that works # choices = sorted([p for p in self.summon_goblin_creator.valid_vectors],lambda x,y:cmp(x.length(),y.length())) # for point in choices: # if self.summon_goblin_creator.Valid(point): # self.action_list.extend( self.summon_goblin_creator.Create(point,t,self) ) # break # else: # #coun't find a place to put it. pants # pass # elif self.player_type == players.PlayerTypes.GUNGHO: # if self.stats.move > 0 and path: # if self.move_action_creator.Valid(path.steps[0]): # self.action_list.extend( self.move_action_creator.Create(path.steps[0],t,self) ) # #We've had a chance, at moving, but maybe we decided not to? # if len(self.action_list) == 0: # offset = enemy.pos-self.pos # if self.blast_action_creator.Valid(offset): # self.action_list.extend( self.blast_action_creator.Create(offset,t,self) ) # elif self.stats.mana - self.summon_goblin_creator.cost >= 2: # #Want to summon a goblin, find the first spot that works # choices = sorted([p for p in self.summon_goblin_creator.valid_vectors],lambda x,y:cmp(x.length(),y.length())) # for point in choices: # if self.summon_goblin_creator.Valid(point): # self.action_list.extend( self.summon_goblin_creator.Create(point,t,self) ) # break # else: # #coun't find a place to put it. pants # pass if len(self.action_list) == 0: #we failed to think of anything to do, so this guy is done return False return self.action_list.pop(0)