def get_all_desc(amount=None): if amount is None: docs = MongoArena._get_collection().find({}, {'score': 1}).sort('score', -1) else: docs = MongoArena._get_collection().find({}, {'score': 1}).sort('score', -1).limit(amount) return [(doc['_id'], doc['score']) for doc in docs]
def initialize(self): if not func_opened(self.char_id, Arena.FUNC_ID): self.mongo_arena = None return try: self.mongo_arena = MongoArena.objects.get(id=self.char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=self.char_id) self.mongo_arena.score = ArenaScoreManager.get_init_score() self.mongo_arena.save()
def __init__(self, char_id): self.char_id = char_id try: self.mongo_arena = MongoArena.objects.get(id=char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=char_id) self.mongo_arena.score = ARENA_DEFAULT_SCORE self.mongo_arena.save() if not self.score: redis_client.zadd(REDIS_ARENA_KEY, self.char_id, self.mongo_arena.score)
def get_all(): docs = MongoArena._get_collection().find( {}, {'score': 1} ).sort('score', 1) return [(doc['_id'], doc['score']) for doc in docs]
def get_init_score(): # 获得初始积分 lowest_doc = MongoArena._get_collection().find({}, {'score':1}).sort('score', 1).limit(1) if lowest_doc.count() == 0: return ARENA_INITIAL_SCORE doc = lowest_doc[0] score = int(doc['score']) if score < ARENA_LOWEST_SCORE: score = ARENA_LOWEST_SCORE return score
def __init__(self, char_id): self.char_id = char_id try: self.mongo_arena = MongoArena.objects.get(id=char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=char_id) self.mongo_arena.save() try: self.mongo_day = MongoArenaDay.objects.get(id=char_id) except DoesNotExist: self.mongo_day = MongoArenaDay(id=char_id) self.mongo_day.score = 0 self.mongo_day.save() try: self.mongo_week = MongoArenaWeek.objects.get(id=char_id) except DoesNotExist: self.mongo_week = MongoArenaWeek(id=char_id) self.mongo_week.score = 0 self.mongo_week.rank = 0 self.mongo_week.save()
def get_chars_by_score(low_score=None, high_score=None): conditions = [] if low_score: conditions.append( {'score': {'$gte': low_score}} ) if high_score: conditions.append( {'score': {'$lte': high_score}} ) if len(conditions) == 1: conditions = conditions[0] elif len(conditions) == 2: conditions = {'$and': conditions} docs = MongoArena._get_collection().find(conditions, {'_id': 1}) return [doc['_id'] for doc in docs]
class Arena(object): FUNC_ID = 8 def __init__(self, char_id): self.char_id = char_id self.initialize() def initialize(self): if not func_opened(self.char_id, Arena.FUNC_ID): self.mongo_arena = None return try: self.mongo_arena = MongoArena.objects.get(id=self.char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=self.char_id) self.mongo_arena.score = ArenaScoreManager.get_init_score() self.mongo_arena.save() @property def score(self): return self.mongo_arena.score if self.mongo_arena else 0 @property def rank(self): if self.score < ARENA_RANK_LINE: return 5000 return ArenaScoreManager.get_char_rank(self.score) @property def remained_free_times(self): c = Counter(self.char_id, 'arena') return c.remained_value @property def remained_buy_times(self): c = Counter(self.char_id, 'arena_buy') return c.remained_value def set_score(self, score): self.mongo_arena.score = score self.mongo_arena.save() @classmethod def get_top_ranks(cls, amount=10): return ArenaScoreManager.get_top_ranks(amount=amount) def send_notify(self): if self.mongo_arena is None: return msg = protomsg.ArenaNotify() msg.score = self.score msg.rank = self.rank msg.remained_free_times = self.remained_free_times msg.remained_sycee_times = self.remained_buy_times msg.arena_cost = ARENA_COST_SYCEE publish_to_char(self.char_id, pack_msg(msg)) def make_panel_response(self): if self.mongo_arena is None: return None msg = protomsg.ArenaPanelResponse() msg.ret = 0 top_ranks = self.get_top_ranks() for index, data in enumerate(top_ranks): rank = index + 1 _cid, _score = data if _score < ARENA_RANK_LINE: break board = msg.boards.add() board.char.MergeFrom(create_character_infomation_message(_cid)) board.score = _score board.rank = rank return msg def choose_rival(self): my_score = self.score def _find(low_score, high_score): choosing = ArenaScoreManager.get_chars_by_score(low_score=low_score, high_score=high_score) if not choosing: return None if self.char_id in choosing: choosing.remove(self.char_id) while choosing: got = random.choice(choosing) # check cd if redis_client.ttl(REDIS_ARENA_BATTLE_CD_KEY(got)) > 0: choosing.remove(got) continue return got return None got = _find(int(my_score * 0.95), int(my_score * 1.05)) if got: return got got = _find(int(my_score * 0.8), int(my_score * 1.2)) if got: return got choosing = ArenaScoreManager.get_chars_by_score(low_score=int(my_score * 1.2), high_score=None) if choosing: if self.char_id in choosing: choosing.remove(self.char_id) return choosing[0] return None def battle(self): need_sycee = 0 counter = Counter(self.char_id, 'arena') if counter.remained_value <= 0: counter = Counter(self.char_id, 'arena_buy') if counter.remained_value <= 0: char = Char(self.char_id).mc if char.vip < VIP_MAX_LEVEL: raise SanguoException( errormsg.ARENA_NO_TIMES, self.char_id, "Arena Battle", "arena no times. vip current: {0}, max {1}".format(char.vip, VIP_MAX_LEVEL) ) raise SanguoException( errormsg.ARENA_NO_TIMES_FINAL, self.char_id, "Arena Battle", "arena no times. vip reach max level {0}".format(VIP_MAX_LEVEL) ) else: need_sycee = ARENA_COST_SYCEE rival_id = self.choose_rival() if not rival_id: raise SanguoException( errormsg.ARENA_NO_RIVAL, self.char_id, "Arena Battle", "no rival." ) if need_sycee: resource = Resource(self.char_id, "Arena Battle", "battle for no free times") resource.check_and_remove(sycee=-need_sycee) counter.incr() # set battle cd redis_client.setex(REDIS_ARENA_BATTLE_CD_KEY(rival_id), 1, ARENA_CD) msg = protomsg.Battle() b = PVP(self.char_id, rival_id, msg) b.start() t = Task(self.char_id) t.trig(2) drop = make_standard_drop_from_template() adding_score = 0 if msg.self_win: achievement = Achievement(self.char_id) achievement.trig(11, 1) # 只有打赢才设置积分 self_score = self.score rival_arena = Arena(rival_id) rival_score = rival_arena.score new_score = calculate_score(self_score, rival_score, msg.self_win) self.set_score(new_score) adding_score = new_score - self_score rival_arena.be_beaten(rival_score, self_score, not msg.self_win, self.char_id) TimesLogArenaWin(self.char_id).inc() ae = ActivityEntry(self.char_id, 50004) if ae and ae.is_valid(): drop = ae.get_additional_drop() Resource(self.char_id, "Arena Win").add(**drop) TimesLogArena(self.char_id).inc() ae = ActivityEntry(self.char_id, 40006) if ae: ae.trig() self.send_notify() drop['stuffs'].append((1001, adding_score)) return msg, drop def be_beaten(self, self_score, rival_score, win, rival_id): score = calculate_score(self_score, rival_score, win) self.set_score(score) rival_name = get_char_property(rival_id, 'name') record = MongoEmbeddedArenaBeatenRecord() record.name = rival_name record.old_score = self_score record.new_score = score self.mongo_arena.beaten_record.append(record) self.mongo_arena.save() def login_process(self): from core.mail import Mail if not self.mongo_arena or not self.mongo_arena.beaten_record: return def _make_content(record): if record.old_score > record.new_score: template = MAIl_ARENA_BEATEN_LOST_TEMPLATE # des = '-{0}'.format(abs(record.old_score - record.new_score)) else: template = MAIl_ARENA_BEATEN_WIN_TEMPLATE # des = '+{0}'.format(abs(record.old_score - record.new_score)) # return template.format(record.name, record.old_score, record.new_score, des) return template.format(record.name) contents = [_make_content(record) for record in self.mongo_arena.beaten_record[-1:-5:-1]] content_header = u'共受到{0}次挑战,积分从{1}变成{2}\n'.format( len(self.mongo_arena.beaten_record), self.mongo_arena.beaten_record[0].old_score, self.mongo_arena.beaten_record[-1].new_score, ) content_body = u'\n'.join(contents) content = content_header + content_body if len(self.mongo_arena.beaten_record) > 4: content += u'\n...' Mail(self.char_id).add(MAIL_ARENA_BEATEN_TITLE, content, send_notify=False) self.mongo_arena.beaten_record = [] self.mongo_arena.save()
def get_top_ranks(amount=10): docs = MongoArena._get_collection().find({}, {'score': 1}).sort('score', -1).limit(amount) return [(doc['_id'], doc['score']) for doc in docs]
class Arena(object): def __init__(self, char_id): self.char_id = char_id try: self.mongo_arena = MongoArena.objects.get(id=char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=char_id) self.mongo_arena.save() try: self.mongo_day = MongoArenaDay.objects.get(id=char_id) except DoesNotExist: self.mongo_day = MongoArenaDay(id=char_id) self.mongo_day.score = 0 self.mongo_day.save() try: self.mongo_week = MongoArenaWeek.objects.get(id=char_id) except DoesNotExist: self.mongo_week = MongoArenaWeek(id=char_id) self.mongo_week.score = 0 self.mongo_week.rank = 0 self.mongo_week.save() @property def day_score(self): return self.mongo_day.score @property def week_rank(self): return self.mongo_week.rank @property def week_score(self): return self.mongo_week.score @property def remained_free_times(self): c = Counter(self.char_id, 'arena') return c.remained_value @property def remained_buy_times(self): c = Counter(self.char_id, 'arena_buy') return c.remained_value def _fill_up_panel_msg(self, msg): msg.week_rank = self.week_rank msg.day_rank = 0 msg.week_score = self.week_score msg.day_score = self.day_score msg.remained_free_times = self.remained_free_times msg.remained_sycee_times = self.remained_buy_times msg.arena_cost = ARENA_COST_SYCEE top_ranks = MongoArenaTopRanks.objects.all() for t in top_ranks: char = msg.chars.add() char.rank = t.id char.name = t.name def send_notify(self): msg = protomsg.ArenaNotify() self._fill_up_panel_msg(msg) publish_to_char(self.char_id, pack_msg(msg)) def choose_rival(self): my_score = self.day_score choosing = [] score_diff = 2 while True: if score_diff >= DAY_MAX_SCORE: break choosing = MongoArenaDay.objects.filter( Q(score__gte=my_score) & Q(score__lte=my_score + score_diff) & Q(id__ne=self.char_id)) if choosing: break score_diff += 2 choosing = [c.id for c in choosing if c.id != self.char_id] if not choosing: char_count = MongoCharacter.objects.count() id_list = random.sample(range(1, char_count + 1), min(char_count, 100)) choosing = MongoCharacter.objects.filter(id__in=id_list) choosing = [c.id for c in choosing] if self.char_id in choosing: choosing.remove(self.char_id) if not choosing: choosing = MongoCharacter.objects.all() choosing = [c.id for c in choosing] choosing.remove(self.char_id) return random.choice(choosing) def battle(self): counter = Counter(self.char_id, 'arena') try: # 免费次数 counter.incr() except CounterOverFlow: counter = Counter(self.char_id, 'arena_buy') try: # 花费元宝次数 counter.incr() except CounterOverFlow: char = Char(self.char_id).mc if char.vip < VIP_MAX_LEVEL: raise SanguoException( errormsg.ARENA_NO_TIMES, self.char_id, "Arena Battle", "arena no times. vip current: {0}, max {1}".format( char.vip, VIP_MAX_LEVEL)) raise SanguoException( errormsg.ARENA_NO_TIMES_FINAL, self.char_id, "Arena Battle", "arena no times. vip reach max level {0}".format( VIP_MAX_LEVEL)) else: resource = Resource(self.char_id, "Arena Battle", "battle for no free times") resource.check_and_remove(sycee=-ARENA_COST_SYCEE) rival_id = self.choose_rival() msg = protomsg.Battle() b = PVP(self.char_id, rival_id, msg) b.start() achievement = Achievement(self.char_id) if msg.self_win: score = ARENA_GET_SCORE_WHEN_WIN achievement.trig(11, 1) self.mongo_arena.continues_win += 1 else: score = ARENA_GET_SCORE_WHEN_LOST self.mongo_arena.continues_win = 0 self.mongo_arena.save() if score: self.mongo_day.score += score self.mongo_day.save() t = Task(self.char_id) t.trig(2) self.send_notify() return msg
class Arena(object): FUNC_ID = 8 def __init__(self, char_id): self.char_id = char_id try: self.mongo_arena = MongoArena.objects.get(id=char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=char_id) self.mongo_arena.score = ARENA_DEFAULT_SCORE self.mongo_arena.save() if not self.score: redis_client.zadd(REDIS_ARENA_KEY, self.char_id, self.mongo_arena.score) @property def score(self): score = redis_client.zscore(REDIS_ARENA_KEY, self.char_id) return int(score) if score else 0 @property def rank(self): rank = redis_client.zrevrank(REDIS_ARENA_KEY, self.char_id) return rank+1 if rank is not None else 0 @property def remained_free_times(self): c = Counter(self.char_id, 'arena') return c.remained_value @property def remained_buy_times(self): c = Counter(self.char_id, 'arena_buy') return c.remained_value def set_score(self, score): redis_client.zadd(REDIS_ARENA_KEY, self.char_id, score) self.mongo_arena.score = score self.mongo_arena.save() @cache_it('_redis_arena_top_cache', ARENA_TOP_RANKS_CACHE) def get_top_ranks(self): # return [(char_id, score, power, name, leader), ...] top_data = redis_client.zrevrange(REDIS_ARENA_KEY, 0, 2, withscores=True) tops = [] for _id, _score in top_data: char = Char(int(_id)) tops.append( (int(_id), _score, char.power, char.mc.name, char.leader_oid) ) tops.sort(key=lambda item: (-item[1], -item[2])) return tops def fill_up_panel_msg(self, msg, score=None): msg.score = score or self.score msg.rank = self.rank msg.remained_free_times = self.remained_free_times msg.remained_sycee_times = self.remained_buy_times msg.arena_cost = ARENA_COST_SYCEE top_ranks = self.get_top_ranks() for index, top in enumerate(top_ranks): char = msg.chars.add() char.rank = index + 1 char.name = top[3] char.leader = top[4] char.power = top[2] def send_notify(self, score=None): msg = protomsg.ArenaNotify() self.fill_up_panel_msg(msg, score=score) publish_to_char(self.char_id, pack_msg(msg)) def choose_rival(self): my_score = self.score def _find(low_score, high_score): choosing = redis_client.zrangebyscore(REDIS_ARENA_KEY, low_score, high_score) if not choosing: return None if str(self.char_id) in choosing: choosing.remove(str(self.char_id)) while choosing: got = random.choice(choosing) # check cd if redis_client.ttl(REDIS_ARENA_BATTLE_CD_KEY(got)) > 0: choosing.remove(got) continue return int(got) return None got = _find(int(my_score * 0.95), int(my_score * 1.05)) if got: return got got = _find(int(my_score * 0.8), int(my_score * 1.2)) if got: return got choosing = redis_client.zrangebyscore(REDIS_ARENA_KEY, int(my_score * 1.2), '+inf') if choosing: if str(self.char_id) in choosing: choosing.remove(str(self.char_id)) return int(choosing[0]) return None def battle(self): need_sycee = 0 counter = Counter(self.char_id, 'arena') if counter.remained_value <= 0: counter = Counter(self.char_id, 'arena_buy') if counter.remained_value <= 0: char = Char(self.char_id).mc if char.vip < VIP_MAX_LEVEL: raise SanguoException( errormsg.ARENA_NO_TIMES, self.char_id, "Arena Battle", "arena no times. vip current: {0}, max {1}".format(char.vip, VIP_MAX_LEVEL) ) raise SanguoException( errormsg.ARENA_NO_TIMES_FINAL, self.char_id, "Arena Battle", "arena no times. vip reach max level {0}".format(VIP_MAX_LEVEL) ) else: need_sycee = ARENA_COST_SYCEE rival_id = self.choose_rival() if not rival_id: raise SanguoException( errormsg.ARENA_NO_RIVAL, self.char_id, "Arena Battle", "no rival." ) if need_sycee: resource = Resource(self.char_id, "Arena Battle", "battle for no free times") resource.check_and_remove(sycee=-need_sycee) counter.incr() # set battle cd redis_client.setex(REDIS_ARENA_BATTLE_CD_KEY(rival_id), 1, ARENA_CD) msg = protomsg.Battle() b = PVP(self.char_id, rival_id, msg) b.start() if msg.self_win: achievement = Achievement(self.char_id) achievement.trig(11, 1) self_score = self.score rival_arena = Arena(rival_id) rival_score = rival_arena.score new_score = calculate_score(self_score, rival_score, msg.self_win) self.set_score(new_score) t = Task(self.char_id) t.trig(2) self.send_notify(score=new_score) rival_arena.be_beaten(rival_score, self_score, not msg.self_win, self.char_id) return msg def be_beaten(self, self_score, rival_score, win, rival_id): score = calculate_score(self_score, rival_score, win) self.set_score(score) rival_name = Char(rival_id).mc.name record = MongoEmbeddedArenaBeatenRecord() record.name = rival_name record.old_score = self_score record.new_score = score self.mongo_arena.beaten_record.append(record) self.mongo_arena.save() def login_process(self): from core.mail import Mail if not self.mongo_arena.beaten_record: return def _make_content(record): if record.old_score > record.new_score: template = MAIl_ARENA_BEATEN_LOST_TEMPLATE des = '-{0}'.format(abs(record.old_score - record.new_score)) else: template = MAIl_ARENA_BEATEN_WIN_TEMPLATE des = '+{0}'.format(abs(record.old_score - record.new_score)) return template.format(record.name, record.old_score, record.new_score, des) contents = [_make_content(record) for record in self.mongo_arena.beaten_record[-1:-5:-1]] content_header = u'共受到{0}次挑战,积分从{1}变成{2}\n'.format( len(self.mongo_arena.beaten_record), self.mongo_arena.beaten_record[0].old_score, self.mongo_arena.beaten_record[-1].new_score, ) content_body = u'\n'.join(contents) content = content_header + content_body if len(self.mongo_arena.beaten_record) > 4: content += u'\n...' Mail(self.char_id).add(MAIL_ARENA_BEATEN_TITLE, content, send_notify=False) self.mongo_arena.beaten_record = [] self.mongo_arena.save()
class Arena(object): def __init__(self, char_id): self.char_id = char_id try: self.mongo_arena = MongoArena.objects.get(id=char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=char_id) self.mongo_arena.save() try: self.mongo_day = MongoArenaDay.objects.get(id=char_id) except DoesNotExist: self.mongo_day = MongoArenaDay(id=char_id) self.mongo_day.score = 0 self.mongo_day.save() try: self.mongo_week = MongoArenaWeek.objects.get(id=char_id) except DoesNotExist: self.mongo_week = MongoArenaWeek(id=char_id) self.mongo_week.score = 0 self.mongo_week.rank = 0 self.mongo_week.save() @property def day_score(self): return self.mongo_day.score @property def week_rank(self): return self.mongo_week.rank @property def week_score(self): return self.mongo_week.score @property def remained_free_times(self): c = Counter(self.char_id, 'arena') return c.remained_value @property def remained_buy_times(self): c = Counter(self.char_id, 'arena_buy') return c.remained_value def _fill_up_panel_msg(self, msg): msg.week_rank = self.week_rank msg.day_rank = 0 msg.week_score = self.week_score msg.day_score = self.day_score msg.remained_free_times = self.remained_free_times msg.remained_sycee_times = self.remained_buy_times msg.arena_cost = ARENA_COST_SYCEE top_ranks = MongoArenaTopRanks.objects.all() for t in top_ranks: char = msg.chars.add() char.rank = t.id char.name = t.name def send_notify(self): msg = protomsg.ArenaNotify() self._fill_up_panel_msg(msg) publish_to_char(self.char_id, pack_msg(msg)) def choose_rival(self): my_score = self.day_score choosing = [] score_diff = 2 while True: if score_diff >= DAY_MAX_SCORE: break choosing = MongoArenaDay.objects.filter(Q(score__gte=my_score) & Q(score__lte=my_score+score_diff) & Q(id__ne=self.char_id)) if choosing: break score_diff += 2 choosing = [c.id for c in choosing if c.id != self.char_id] if not choosing: char_count = MongoCharacter.objects.count() id_list = random.sample(range(1, char_count+1), min(char_count, 100)) choosing = MongoCharacter.objects.filter(id__in=id_list) choosing = [c.id for c in choosing] if self.char_id in choosing: choosing.remove(self.char_id) if not choosing: choosing = MongoCharacter.objects.all() choosing = [c.id for c in choosing] choosing.remove(self.char_id) return random.choice(choosing) def battle(self): counter = Counter(self.char_id, 'arena') try: # 免费次数 counter.incr() except CounterOverFlow: counter = Counter(self.char_id, 'arena_buy') try: # 花费元宝次数 counter.incr() except CounterOverFlow: char = Char(self.char_id).mc if char.vip < VIP_MAX_LEVEL: raise SanguoException( errormsg.ARENA_NO_TIMES, self.char_id, "Arena Battle", "arena no times. vip current: {0}, max {1}".format(char.vip, VIP_MAX_LEVEL) ) raise SanguoException( errormsg.ARENA_NO_TIMES_FINAL, self.char_id, "Arena Battle", "arena no times. vip reach max level {0}".format(VIP_MAX_LEVEL) ) else: resource = Resource(self.char_id, "Arena Battle", "battle for no free times") resource.check_and_remove(sycee=-ARENA_COST_SYCEE) rival_id = self.choose_rival() msg = protomsg.Battle() b = PVP(self.char_id, rival_id, msg) b.start() achievement = Achievement(self.char_id) if msg.self_win: score = ARENA_GET_SCORE_WHEN_WIN achievement.trig(11, 1) self.mongo_arena.continues_win += 1 else: score = ARENA_GET_SCORE_WHEN_LOST self.mongo_arena.continues_win = 0 self.mongo_arena.save() if score: self.mongo_day.score += score self.mongo_day.save() t = Task(self.char_id) t.trig(2) self.send_notify() return msg
def get_char_rank(char_score): docs = MongoArena._get_collection().find({'score': {'$gt': char_score}}, {'_id': 1}) rank = docs.count() return rank + 1
def get_char_score(char_id): doc = MongoArena._get_collection().find_one( {'_id': char_id}, {'score': 1} ) return doc['score']
class Arena(object): FUNC_ID = 8 def __init__(self, char_id): self.char_id = char_id try: self.mongo_arena = MongoArena.objects.get(id=char_id) except DoesNotExist: self.mongo_arena = MongoArena(id=char_id) self.mongo_arena.score = ARENA_DEFAULT_SCORE self.mongo_arena.save() if not self.score: redis_client.zadd(REDIS_ARENA_KEY, self.char_id, self.mongo_arena.score) @property def score(self): score = redis_client.zscore(REDIS_ARENA_KEY, self.char_id) return int(score) if score else 0 @property def rank(self): rank = redis_client.zrevrank(REDIS_ARENA_KEY, self.char_id) return rank + 1 if rank is not None else 0 @property def remained_free_times(self): c = Counter(self.char_id, 'arena') return c.remained_value @property def remained_buy_times(self): c = Counter(self.char_id, 'arena_buy') return c.remained_value def set_score(self, score): redis_client.zadd(REDIS_ARENA_KEY, self.char_id, score) self.mongo_arena.score = score self.mongo_arena.save() @cache_it('_redis_arena_top_cache', ARENA_TOP_RANKS_CACHE) def get_top_ranks(self): # return [(char_id, score, power, name, leader), ...] top_data = redis_client.zrevrange(REDIS_ARENA_KEY, 0, 2, withscores=True) tops = [] for _id, _score in top_data: char = Char(int(_id)) tops.append( (int(_id), _score, char.power, char.mc.name, char.leader_oid)) tops.sort(key=lambda item: (-item[1], -item[2])) return tops def fill_up_panel_msg(self, msg, score=None): msg.score = score or self.score msg.rank = self.rank msg.remained_free_times = self.remained_free_times msg.remained_sycee_times = self.remained_buy_times msg.arena_cost = ARENA_COST_SYCEE top_ranks = self.get_top_ranks() for index, top in enumerate(top_ranks): char = msg.chars.add() char.rank = index + 1 char.name = top[3] char.leader = top[4] char.power = top[2] def send_notify(self, score=None): msg = protomsg.ArenaNotify() self.fill_up_panel_msg(msg, score=score) publish_to_char(self.char_id, pack_msg(msg)) def choose_rival(self): my_score = self.score def _find(low_score, high_score): choosing = redis_client.zrangebyscore(REDIS_ARENA_KEY, low_score, high_score) if not choosing: return None if str(self.char_id) in choosing: choosing.remove(str(self.char_id)) while choosing: got = random.choice(choosing) # check cd if redis_client.ttl(REDIS_ARENA_BATTLE_CD_KEY(got)) > 0: choosing.remove(got) continue return int(got) return None got = _find(int(my_score * 0.95), int(my_score * 1.05)) if got: return got got = _find(int(my_score * 0.8), int(my_score * 1.2)) if got: return got choosing = redis_client.zrangebyscore(REDIS_ARENA_KEY, int(my_score * 1.2), '+inf') if choosing: if str(self.char_id) in choosing: choosing.remove(str(self.char_id)) return int(choosing[0]) return None def battle(self): need_sycee = 0 counter = Counter(self.char_id, 'arena') if counter.remained_value <= 0: counter = Counter(self.char_id, 'arena_buy') if counter.remained_value <= 0: char = Char(self.char_id).mc if char.vip < VIP_MAX_LEVEL: raise SanguoException( errormsg.ARENA_NO_TIMES, self.char_id, "Arena Battle", "arena no times. vip current: {0}, max {1}".format( char.vip, VIP_MAX_LEVEL)) raise SanguoException( errormsg.ARENA_NO_TIMES_FINAL, self.char_id, "Arena Battle", "arena no times. vip reach max level {0}".format( VIP_MAX_LEVEL)) else: need_sycee = ARENA_COST_SYCEE rival_id = self.choose_rival() if not rival_id: raise SanguoException(errormsg.ARENA_NO_RIVAL, self.char_id, "Arena Battle", "no rival.") if need_sycee: resource = Resource(self.char_id, "Arena Battle", "battle for no free times") resource.check_and_remove(sycee=-need_sycee) counter.incr() # set battle cd redis_client.setex(REDIS_ARENA_BATTLE_CD_KEY(rival_id), 1, ARENA_CD) msg = protomsg.Battle() b = PVP(self.char_id, rival_id, msg) b.start() if msg.self_win: achievement = Achievement(self.char_id) achievement.trig(11, 1) self_score = self.score rival_arena = Arena(rival_id) rival_score = rival_arena.score new_score = calculate_score(self_score, rival_score, msg.self_win) self.set_score(new_score) t = Task(self.char_id) t.trig(2) self.send_notify(score=new_score) rival_arena.be_beaten(rival_score, self_score, not msg.self_win, self.char_id) return msg def be_beaten(self, self_score, rival_score, win, rival_id): score = calculate_score(self_score, rival_score, win) self.set_score(score) rival_name = Char(rival_id).mc.name record = MongoEmbeddedArenaBeatenRecord() record.name = rival_name record.old_score = self_score record.new_score = score self.mongo_arena.beaten_record.append(record) self.mongo_arena.save() def login_process(self): from core.mail import Mail if not self.mongo_arena.beaten_record: return def _make_content(record): if record.old_score > record.new_score: template = MAIl_ARENA_BEATEN_LOST_TEMPLATE des = '-{0}'.format(abs(record.old_score - record.new_score)) else: template = MAIl_ARENA_BEATEN_WIN_TEMPLATE des = '+{0}'.format(abs(record.old_score - record.new_score)) return template.format(record.name, record.old_score, record.new_score, des) contents = [ _make_content(record) for record in self.mongo_arena.beaten_record[-1:-5:-1] ] content_header = u'共受到{0}次挑战,积分从{1}变成{2}\n'.format( len(self.mongo_arena.beaten_record), self.mongo_arena.beaten_record[0].old_score, self.mongo_arena.beaten_record[-1].new_score, ) content_body = u'\n'.join(contents) content = content_header + content_body if len(self.mongo_arena.beaten_record) > 4: content += u'\n...' Mail(self.char_id).add(MAIL_ARENA_BEATEN_TITLE, content, send_notify=False) self.mongo_arena.beaten_record = [] self.mongo_arena.save()