예제 #1
0
    def loadItemDataFromCS(self, dic_item_data):
        #log.debug('[ GSBag::loadItem ] start. cid {0}, dic_item_data {1}, /////////////////////////////////////////'.format( self.__cid, dic_item_data ))
        for k, d in dic_item_data.iteritems():
            gs_att = GSAttribute(self.__cid, self._tbl_name, d['id'], self._item_field_set)
            gs_att.updateGSAttribute(False, d)
            new_item = GSBagItem(gs_att)

            bisect.insort_left(self.__list, new_item)
        log.debug('[ GSBag::loadItem ] end. cid {0}, count {1}'.format( self.__cid, len(self.__list) ))
예제 #2
0
    def loadItemDataFromCS(self, dic_item_data):
        #log.debug('[ GSBag::loadItem ] start. cid {0}, dic_item_data {1}, /////////////////////////////////////////'.format( self.__cid, dic_item_data ))
        for k, d in dic_item_data.iteritems():
            gs_att = GSAttribute(self.__cid, self._tbl_name, d['id'],
                                 self._item_field_set)
            gs_att.updateGSAttribute(False, d)
            new_item = GSBagItem(gs_att)

            bisect.insort_left(self.__list, new_item)
        log.debug('[ GSBag::loadItem ] end. cid {0}, count {1}'.format(
            self.__cid, len(self.__list)))
예제 #3
0
 def createItemViaCS(self, item_type, item_id, add_count):#Return item inst if succeed, else return None
     try:
         res_create = yield cs_call('cs_create_item', (self.__cid, item_type, item_id, add_count))
     except Exception as e:
         log.exception()
         defer.returnValue(None)
         
     err, new_item_data = res_create
     gs_att = GSAttribute(self.__cid, self._tbl_name, new_item_data['id'], self._item_field_set)
     gs_att.updateGSAttribute(False, new_item_data)
     new_item = GSBagItem(gs_att)
     defer.returnValue(new_item)
예제 #4
0
    def createItemViaCS(
            self, item_type, item_id,
            add_count):  #Return item inst if succeed, else return None
        try:
            res_create = yield cs_call(
                'cs_create_item', (self.__cid, item_type, item_id, add_count))
        except Exception as e:
            log.exception()
            defer.returnValue(None)

        err, new_item_data = res_create
        gs_att = GSAttribute(self.__cid, self._tbl_name, new_item_data['id'],
                             self._item_field_set)
        gs_att.updateGSAttribute(False, new_item_data)
        new_item = GSBagItem(gs_att)
        defer.returnValue(new_item)
예제 #5
0
class GSAtlaslistMgr(object):
    _table = 'atlaslist'
    _fields = TABLE_FIELDS['atlaslist'][0]

    def __init__(self, user):
        self.user = user
        self.cid = user.cid

        self.atlaslist = GSAttribute(user.cid, GSAtlaslistMgr._table, user.cid)

        self.load_flag = False

        self.fellow_ids = None
        self.equip_ids = None
        self.treasure_ids = None

    @defer.inlineCallbacks
    def load(self):
        if self.load_flag:
            defer.returnValue(None)

        try:
            table_data = yield gs_load_table_data(self.cid,
                                                  GSAtlaslistMgr._table)
            # 注意在收到返回消息后才能赋值
            self.load_flag = True
            if table_data:
                table_data = dict(zip(GSAtlaslistMgr._fields, table_data))
                self.atlaslist.updateGSAttribute(False, **table_data)
                self.fellow_ids = loads(self.atlaslist.fellow_ids)
                self.equip_ids = loads(self.atlaslist.equip_ids)
                self.treasure_ids = loads(self.atlaslist.treasure_ids)
            else:
                yield self.new()
        except Exception as e:
            log.error('Exception raise. e: {0}.'.format(e))

    @defer.inlineCallbacks
    def new(self):
        self.fellow_ids, self.equip_ids, self.treasure_ids = [], [], []
        # 检查伙伴列表、宝物背包列表、装备背包列表

        init_data = [
            self.cid,
            dumps(self.fellow_ids),
            dumps(self.equip_ids),
            dumps(self.treasure_ids)
        ]
        kwargs = dict(zip(GSAtlaslistMgr._fields[1:], init_data))
        create_data = yield gs_create_table_data(self.cid,
                                                 GSAtlaslistMgr._table,
                                                 **kwargs)
        if create_data:
            create_data = dict(zip(GSAtlaslistMgr._fields, create_data))
            self.atlaslist.updateGSAttribute(False, **create_data)
        else:  # 新增数据失败
            self.load_flag = False

    @defer.inlineCallbacks
    def atlaslist_info(self, category_id, second_type):
        yield self.load()
        _category_conf = get_atlaslist_category_conf(category_id)
        _second_conf = _category_conf.get(second_type, {})
        if not _second_conf:
            defer.returnValue(NOT_FOUND_CONF)

        if category_id == CATEGORY_TYPE_FELLOW:
            _had_get_ids = self.fellow_ids
        elif category_id == CATEGORY_TYPE_EQUIP:
            _had_get_ids = self.equip_ids
        elif category_id == CATEGORY_TYPE_TREASURE:
            _had_get_ids = self.treasure_ids
        else:
            defer.returnValue(CLIENT_DATA_ERROR)

        _second_count = 0
        _quality_data = []
        for _quality, _quality_conf in _second_conf.iteritems():
            _item_ids = []
            _quality_count = 0
            for _item in _quality_conf['Items']:
                if _item['ItemID'] in _had_get_ids:
                    _quality_count += 1
                    _item_ids.append(_item['ItemID'])
            _second_count += _quality_count
            # 星级收齐的奖励
            if _quality_count >= len(_quality_conf['Items']):
                _award_status = 1
                _award_data = yield redis.hget(HASH_ATLASLIST_AWARD, self.cid)
                if _award_data:
                    _award_data = loads(_award_data)
                    if (category_id, second_type, _quality) in _award_data:
                        _award_status = 2
            else:
                _award_status = 0
            _quality_data.append(
                (_quality, _item_ids, _quality_count, _award_status))

        _f_count, _e_count, _t_count = len(self.fellow_ids), len(
            self.equip_ids), len(self.treasure_ids)

        defer.returnValue((_f_count, _e_count, _t_count, category_id,
                           second_type, _second_count, _quality_data))

    @defer.inlineCallbacks
    def new_atlaslist(self, category_id, second_type, quality, item_id):
        yield self.load()
        _category_conf = get_atlaslist_category_conf(category_id)
        _second_conf = _category_conf.get(second_type, {})
        _quality_conf = _second_conf.get(quality, {})
        if not _quality_conf:
            defer.returnValue(None)

        for _item in _quality_conf['Items']:
            if _item['ItemID'] == item_id:
                break
        else:
            defer.returnValue(None)

        if category_id == CATEGORY_TYPE_FELLOW:
            if item_id not in self.fellow_ids:
                self.fellow_ids.append(item_id)
                self.atlaslist.fellow_ids = dumps(self.fellow_ids)
        elif category_id == CATEGORY_TYPE_EQUIP:
            if item_id not in self.equip_ids:
                self.equip_ids.append(item_id)
                self.atlaslist.equip_ids = dumps(self.equip_ids)
        elif category_id == CATEGORY_TYPE_TREASURE:
            if item_id not in self.treasure_ids:
                self.treasure_ids.append(item_id)
                self.atlaslist.treasure_ids = dumps(self.treasure_ids)

        defer.returnValue(None)

    @defer.inlineCallbacks
    def atlaslist_award(self, category_id, second_type, quality):
        _award_data = yield redis.hget(HASH_ATLASLIST_AWARD, self.cid)
        if _award_data:
            _award_data = loads(_award_data)
        else:
            _award_data = []

        _new_award = (category_id, second_type, quality)
        if _new_award in _award_data:
            defer.returnValue(ATLASLIST_AWARD_HAD_ERROR)

        _category_conf = get_atlaslist_category_conf(category_id)
        _second_conf = _category_conf.get(second_type, {})
        _quality_conf = _second_conf.get(quality, {})
        if not _quality_conf or not _quality_conf['Awardlist']:
            defer.returnValue(NOT_FOUND_CONF)

        _award_data.append(_new_award)
        yield redis.hset(HASH_ATLASLIST_AWARD, self.cid, dumps(_award_data))
        items_return = []
        for _type, _id, _num in _quality_conf['Awardlist']:
            model = ITEM_MODELs.get(_type, None)
            if not model:
                log.error(
                    'Unknown item type. cid: {0}, item_type: {1}, item_id: {2}, item_num: {3}.'
                    .format(self.cid, _type, _id, _num))
                continue
            res_err, value = yield model(self.user,
                                         ItemID=_id,
                                         ItemNum=_num,
                                         AddType=WAY_ATLASLIST_AWARD,
                                         CapacityFlag=False)
            if not res_err and value:
                for _v in value:
                    items_return = total_new_items(_v, items_return)

        defer.returnValue(items_return)
예제 #6
0
class GSEliteSceneMgr(object):
    _table = 'elitescene'
    _fields = TABLE_FIELDS['elitescene'][0]

    def __init__(self, user):
        self.user = user
        self.cid = user.cid
        self.load_flag = False

        # 单次战斗中伙伴复活的次数
        self.revive_count = 0
        # 战斗中的精英副本ID
        self.old_elitescene_id = 0
        self.elitescene = GSAttribute(user.cid, GSEliteSceneMgr._table,
                                      user.cid)
        # 已战斗胜利的精英副本ID列表
        self.passed_elitescene_ids = []

    @defer.inlineCallbacks
    def load(self):
        if not self.load_flag:
            try:
                table_data = yield gs_load_table_data(self.cid,
                                                      GSEliteSceneMgr._table)
                # 注意在收到返回消息后才能赋值
                self.load_flag = True

                if table_data:
                    table_data = dict(zip(GSEliteSceneMgr._fields, table_data))
                    self.elitescene.updateGSAttribute(False, **table_data)
                else:
                    yield self.new()
                _data = yield redis.hget(HASH_ELITESCENE_PASSED, self.cid)
                if _data:
                    self.passed_elitescene_ids = loads(_data)
            except Exception as e:
                log.error('Exception raise. e: {0}.'.format(e))

    def sync_to_cs(self):
        if self.elitescene:
            self.elitescene.syncToCS()

    @defer.inlineCallbacks
    def new(self):
        dt_now = datetime.now()
        kwargs = dict(
            zip(GSEliteSceneMgr._fields[1:],
                [self.cid, ELITESCENE_FIGHT_COUNT, 0, 0, dt_now
                 ]))  #datetime2string(dt_now)]))
        create_data = yield gs_create_table_data(self.cid,
                                                 GSEliteSceneMgr._table,
                                                 **kwargs)
        if create_data:
            create_data = dict(zip(GSEliteSceneMgr._fields, create_data))
            self.elitescene.updateGSAttribute(False, **create_data)
        else:  # 新增数据失败
            self.load_flag = False

        defer.returnValue(NO_ERROR)

    def system_daily_reset(self):
        '''
        @summary: 每天24点系统重置精英副本数据, 含免费挑战次数、剩余可够买的次数、更新时间
        '''
        dt_now = datetime.now()
        dt_last = self.elitescene.last_datetime
        if dt_now.date() != dt_last.date():
            self.elitescene.left_buy_fight = 0
            self.elitescene.free_fight = ELITESCENE_FIGHT_COUNT
            self.elitescene.last_datetime = dt_now

    @defer.inlineCallbacks
    def elitescene_data(self):
        '''
        @summary: 获取精英副本的基本信息
        '''
        yield self.load()
        self.system_daily_reset()
        conf = get_vip_conf(self.user.vip_level)
        left_buy_fight = conf['EliteSceneCount'] if conf else 0
        left_buy_fight = left_buy_fight - self.elitescene.left_buy_fight if left_buy_fight > self.elitescene.left_buy_fight else 0

        defer.returnValue(
            (self.elitescene.free_fight + self.elitescene.buyed_fight,
             left_buy_fight, self.passed_elitescene_ids))

    @defer.inlineCallbacks
    def start_battle(self, elitescene_id):
        '''
        @summary: 记录玩家的战斗信息
        '''
        # 检查战斗条件是否满足
        errorno = yield self.check_battle_limit(elitescene_id)
        defer.returnValue(errorno)

    @defer.inlineCallbacks
    def check_battle_limit(self, elitescene_id):
        ''' 检查战斗的条件是否满足 '''
        conf = get_elitescene_conf(elitescene_id)
        if not conf:
            log.error(
                'Unknown elitescene conf. id: {0}.'.format(elitescene_id))
            defer.returnValue(NOT_FOUND_CONF)
        # 检查精英副本是否开启
        _scene_passed = yield self.user.scene_mgr.check_scene_passed(
            conf['SceneID'])
        if 0 == _scene_passed:
            log.error(
                'Scene need passed. cid: {0}, scene_id: {1}, elitescene_id: {2}.'
                .format(self.cid, conf['SceneID'], elitescene_id))
            defer.returnValue(SCENE_NEED_PASSED)
        # 检查精英副本的前置副本是否已通关
        if conf['PrepEliteSceneID'] and conf[
                'PrepEliteSceneID'] not in self.passed_elitescene_ids:
            log.error('PrepEliteSceneID<{0}> need win. cid: {1}.'.format(
                conf['PrepEliteSceneID'], self.cid))
            defer.returnValue(PREP_ELITESCENE_NEED_WIN)
        # 检查玩家的等级限制
        if conf['NeedRoleLevel'] > self.user.base_att.level:
            log.error(
                'User level limit. cid: {0}, need: {1}, cur: {2}.'.format(
                    self.cid, conf['NeedRoleLevel'], self.user.base_att.level))
            defer.returnValue(CHAR_LEVEL_LIMIT)

        self.system_daily_reset()
        # 每日挑战次数限制
        if (self.elitescene.free_fight + self.elitescene.buyed_fight < 1):
            log.error(
                'No fight count. cid: {0}, free_fight: {1}, buyed_fight: {2}.'.
                format(self.cid, self.elitescene.free_fight,
                       self.elitescene.buyed_fight))
            defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)

        self.revive_count = 0
        self.old_elitescene_id = elitescene_id

        defer.returnValue(NO_ERROR)

    @defer.inlineCallbacks
    def dungeon_star_drop(self, dungeon_id, dungeon_star=1):
        '''
        @summary: 精英副本默认难度为1, 无conf则不用计算掉落
        @param  : drop_items-[ [item_type, item_id, item_num], ... ]
        '''
        drop_items = []

        drop_conf = get_drop_conf(dungeon_id, dungeon_star)
        if not drop_conf:
            log.error(
                'No drop conf. dungeon_id: {0}, dungeon_star: {1}.'.format(
                    dungeon_id, dungeon_star))
            defer.returnValue(drop_items)

        # old_rate format: {dungeon_star: {drop_id: rate, ...}, ...}
        old_rate = {}
        data = yield redis.hget(HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid)
        if data:
            old_rate = loads(data)
            if old_rate.has_key(dungeon_star):
                old_star_rate = old_rate[dungeon_star]
            else:
                old_star_rate = {}
                old_rate[dungeon_star] = old_star_rate
                for _id, _drop in drop_conf.iteritems():
                    old_star_rate[_id] = _drop['RateMax']
        else:  # 第一次按照最大概率来计算掉落
            old_star_rate = {}
            old_rate[dungeon_star] = old_star_rate
            for _id, _drop in drop_conf.iteritems():
                old_star_rate[_id] = _drop['RateMax']

        for _drop_id, _drop in drop_conf.iteritems():
            add_rate = old_star_rate.get(_drop_id, 0)
            _drop_rate = _drop['RateStart'] + add_rate
            # 单次增加的封顶概率
            if _drop_rate > _drop['RateMax']:
                _drop_rate = _drop['RateMax']
            # 掉落概率是万分比
            rand_int = random.randint(0, 10000)
            # _drop['QuestID'] 未处理
            # 当前随机值 不大于 配置的掉落概率值时掉落
            if rand_int <= _drop_rate:
                drop_items = add_new_items(
                    [_drop['ItemType'], _drop['ItemID'], _drop['ItemNum']],
                    drop_items)

                old_star_rate[_drop_id] = 0
            else:
                old_star_rate[_drop_id] = old_star_rate.setdefault(
                    _drop_id, 0) + _drop['RateAdd']
        yield redis.hset(HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid,
                         dumps(old_rate))

        defer.returnValue(drop_items)

    @defer.inlineCallbacks
    def get_dungeon_drop(self, drop_items, way_others=''):
        ''' 获取怪物组战斗胜利后 掉落的道具 '''
        dungeon_drop_items = []

        for _item_type, _item_id, _item_num in drop_items:
            # 掉落分魂碎片、普通道具
            _model = ITEM_MODELs.get(_item_type, None)
            if not _model:
                log.error(
                    'Unknown item type. ItemType: {0}.'.format(_item_type))
                continue
            res_err, value = yield _model(self.user,
                                          ItemID=_item_id,
                                          ItemNum=_item_num,
                                          AddType=WAY_ELITESCENE_DROP,
                                          WayOthers=way_others,
                                          CapacityFlag=False)
            if not res_err and value:
                for _v in value:
                    dungeon_drop_items = total_new_items(
                        _v, dungeon_drop_items)

        defer.returnValue(dungeon_drop_items)

    @defer.inlineCallbacks
    def get_battle_reward(self, status, elitescene_id):
        '''
        @param  : 战斗结果 status 0:fail, 1:success
        '''
        self.revive_count = 0
        self.old_elitescene_id = 0
        ## 检查战斗条件是否满足
        #errorno = yield self.check_battle_limit( elitescene_id )
        #if errorno:
        #    defer.returnValue( errorno )
        # 战斗失败
        if not status:
            defer.returnValue(
                (2, status, 0, 0,
                 self.elitescene.free_fight + self.elitescene.buyed_fight, [],
                 0, 0, 0, self.user.base_att.energy))
        # 精英副本奖励金币、仙魂
        golds_reward, soul_reward = 0, 0
        # config
        conf = get_elitescene_conf(elitescene_id)
        if conf:
            golds_reward, soul_reward = conf['Gold'], conf['Soul']
        # 扣挑战次数
        if self.elitescene.buyed_fight > 0:
            self.elitescene.buyed_fight -= 1
        elif self.elitescene.free_fight > 0:
            self.elitescene.free_fight -= 1
        else:
            log.error(
                'No fight count. free_fight: {0}, buyed_fight: {1}.'.format(
                    self.elitescene.free_fight, self.elitescene.buyed_fight))
            defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)

        # 获取怪物组掉落, star默认为1
        drop_items = yield self.dungeon_star_drop(elitescene_id, 1)
        # 新增掉落
        way_others = str((FIGHT_TYPE_ELITE, elitescene_id, 1))
        elitescene_drop_items = yield self.get_dungeon_drop(
            drop_items, way_others)
        # 发放奖励
        if golds_reward > 0:
            #self.user.base_att.golds += golds_reward
            self.user.get_golds(golds_reward, WAY_ELITESCENE_BATTLE)
        if soul_reward > 0:
            self.user.base_att.soul += soul_reward

        # 更新已胜利的精英副本ID列表
        if elitescene_id not in self.passed_elitescene_ids:
            self.passed_elitescene_ids.append(elitescene_id)
            yield redis.hset(HASH_ELITESCENE_PASSED, self.cid,
                             dumps(self.passed_elitescene_ids))
        # 每日任务计数
        yield self.user.daily_quest_mgr.update_daily_quest(DAILY_QUEST_ID_2, 1)
        # 开服七天
        self.passed_elitescene_ids.sort()
        yield self.user.open_server_mgr.update_open_server_activity_quest(
            OPEN_SERVER_QUEST_ID_12, self.passed_elitescene_ids[-1])
        # add syslog
        #成就
        yield self.user.achievement_mgr.update_achievement_status(
            ACHIEVEMENT_QUEST_ID_12, self.passed_elitescene_ids[-1])
        str_drop_items = str(elitescene_drop_items).replace('[', '(')
        str_drop_items = str_drop_items.replace(']', ')')
        syslogger(LOG_SCENE_BATTLE, self.cid, self.user.level,
                  self.user.vip_level, self.user.alliance_id, FIGHT_TYPE_ELITE,
                  status, elitescene_id, 1, 0, soul_reward, golds_reward,
                  str_drop_items)

        defer.returnValue(
            (2, status, 0, 0,
             self.elitescene.free_fight + self.elitescene.buyed_fight,
             elitescene_drop_items, golds_reward, soul_reward, 0,
             self.user.base_att.energy))

    @defer.inlineCallbacks
    def buy_count(self):
        '''
        @summary: 购买挑战次数
               每购买1次额外挑战次数,需要花费10钻石
        '''
        if self.user.base_att.credits < 10:
            log.error('Credits not enough. need: 10, cur: {0}.'.format(
                self.user.base_att.credits))
            defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
        # 还剩余有挑战次数
        if (self.elitescene.free_fight + self.elitescene.buyed_fight > 0):
            log.error(
                'User has more than 1 fight count. free_fight: {0}, buyed_fight: {1}.'
                .format(self.elitescene.free_fight,
                        self.elitescene.buyed_fight))
            defer.returnValue(HAVE_NUM_TO_USE)
        # 判断VIP等级对应的可购买次数限制
        self.system_daily_reset()

        conf = get_vip_conf(self.user.vip_level)
        left_buy_fight = conf['EliteSceneCount'] if conf else 0
        left_buy_fight = left_buy_fight - self.elitescene.left_buy_fight if left_buy_fight > self.elitescene.left_buy_fight else 0
        if left_buy_fight < 1:
            log.error('No fight count could buy today.')
            defer.returnValue(BUY_MAX_NUM_ERROR)
        left_buy_fight -= 1

        yield self.user.consume_credits(10, WAY_ELITESCENE_FIGHT)
        self.elitescene.left_buy_fight += 1
        self.elitescene.buyed_fight += 1

        defer.returnValue(
            ((self.elitescene.free_fight + self.elitescene.buyed_fight),
             left_buy_fight, self.user.base_att.credits))

    def battle_revive(self):
        '''
        @summary: 复活初始价格为200金币, 价格=复活次数*初始价格
             同一场战斗中不同波数复活次数要累计 
        '''
        need_golds = (self.revive_count + 1) * REVIVE_BASIC_GOLDS
        #log.info('For Test. revive_count: {0}, need_golds: {1}, cur_golds: {2}.'.format( self.revive_count, need_golds, self.user.base_att.golds ))
        if (self.user.base_att.golds < need_golds):
            log.error('Golds not enough. need: {0}, cur: {1}.'.format(
                need_golds, self.user.base_att.golds))
            return CHAR_GOLD_NOT_ENOUGH

        #self.user.base_att.golds -= need_golds
        self.user.consume_golds(need_golds, WAY_ELITESCENE_REVIVE)
        self.revive_count += 1

        return [self.user.base_att.golds]
예제 #7
0
class GSClimbingMgr(object):
    '''
    @summary: 天外天
    '''
    _table = 'climbing_tower'
    _fields = TABLE_FIELDS['climbing_tower'][0]

    def __init__(self, user):
        self.user = user
        self.cid  = user.cid
        self.load_flag     = False 

        all_climbing_layers = get_all_climbing_layer()
        self.MAX_LAYER      = max(all_climbing_layers) if all_climbing_layers else 0
        self.climbing       = GSAttribute(user.cid, GSClimbingMgr._table, user.cid)

    @defer.inlineCallbacks
    def load(self):
        if self.load_flag:
            defer.returnValue( None )

        try:
            table_data = yield gs_load_table_data(self.cid, GSClimbingMgr._table)
            # 注意在收到返回消息后才能赋值
            self.load_flag = True

            if table_data:
                table_data = dict(zip(GSClimbingMgr._fields, table_data))
                self.climbing.updateGSAttribute( False, **table_data )
            else:
                yield self.new()
        except Exception as e:
            log.error( 'Exception raise. e: {0}.'.format( e ))

    def sync_to_cs(self):
        if self.climbing:
            self.climbing.syncToCS()

    @defer.inlineCallbacks
    def new(self):
        init_data = [self.cid, 1, 0, 0, 0, 0, 0, 0, 0, int(time())]
        kwargs = dict(zip(GSClimbingMgr._fields[1:], init_data))
        create_data = yield gs_create_table_data(self.cid, GSClimbingMgr._table, **kwargs)
        if create_data:
            create_data = dict(zip(GSClimbingMgr._fields, create_data))
            self.climbing.updateGSAttribute( False, **create_data )
        else: # 新增数据失败
            self.load_flag = False
 
    def system_daily_reset(self):
        '''
        @summary: 每天24点系统重置天外天数据
        '''
        # 不是同一天, 系统重置玩家数据
        dt_now  = datetime.now()
        dt_last = self.climbing.last_datetime
        if dt_now.date() != dt_last.date():
            self.climbing.free_fight     = 0 
            self.climbing.free_reset     = 0
            self.climbing.left_buy_reset = 0
            self.climbing.last_datetime  = dt_now

    def get_vip_conf_of_climbing(self):
        conf = get_vip_conf( self.user.vip_level )
        max_free_fight  = conf['TowerFightCount'] if conf else 0
        left_free_fight = max_free_fight - self.climbing.free_fight if max_free_fight > self.climbing.free_fight else 0
        max_free_reset  = conf['TowerResetCount'] if conf else 0
        left_free_reset = max_free_reset - self.climbing.free_reset if max_free_reset > self.climbing.free_reset else 0
        max_buy_reset   = conf['TowerBuyReset'] if conf else 0
        left_buy_reset  = max_buy_reset - self.climbing.left_buy_reset if max_buy_reset > self.climbing.left_buy_reset else 0

        return [left_free_fight, left_free_reset, left_buy_reset, max_free_fight, max_free_reset, max_buy_reset]

    @defer.inlineCallbacks
    def climbing_data(self):
        '''
        @summary: 天外天的基本信息
        '''
        yield self.load()
        self.system_daily_reset()

        climbing_data = self.get_vip_conf_of_climbing()
        defer.returnValue( (self.climbing.cur_layer, self.climbing.max_layer, climbing_data[0]+self.climbing.buyed_fight, \
                climbing_data[1]+self.climbing.buyed_reset, climbing_data[2], self.climbing.start_datetime, self.user.credits) )

    @defer.inlineCallbacks
    def reset_climbing(self):
        '''
        @summary: 重置天外天数据。当前塔层归1, 挑战次数置满, 更新last_time, 扣重置次数
        '''
        self.system_daily_reset()
        # 正在扫荡, 不能重置
        if self.climbing.start_datetime > 0:
            log.error('In climbing could not reset.')
            defer.returnValue( IN_CLIMBING_ONGOING )
        if self.climbing.cur_layer == 1:
            log.error('Tower layer 1 could not reset.')
            defer.returnValue( IN_CLIMBING_MIN_LAYER )
        climbing_data = self.get_vip_conf_of_climbing()
        if (climbing_data[1] + self.climbing.buyed_reset < 1):
            log.warn('User no reset count. cid: {0}, had_free_reset: {1}, buyed_reset: {2}.'.format( self.cid, self.climbing.free_reset, self.climbing.buyed_reset ))
            res_err = yield self.buy_count(1)
            if isinstance(res_err, int):
                defer.returnValue( res_err )
            climbing_data = self.get_vip_conf_of_climbing()

        self.climbing.cur_layer = 1
        if self.climbing.buyed_reset > 0:
            self.climbing.buyed_reset -= 1
        elif climbing_data[1] > 0:
            self.climbing.free_reset += 1
            climbing_data[1] -= 1

        self.climbing.free_fight    = 0
        self.climbing.last_datetime = datetime.now()
 
        defer.returnValue( (self.climbing.cur_layer, self.climbing.max_layer, climbing_data[3]+self.climbing.buyed_fight, \
                climbing_data[1]+self.climbing.buyed_reset, climbing_data[2], self.climbing.start_datetime, self.user.credits) )

    @defer.inlineCallbacks
    def buy_count(self, count_type):
        '''
        @summary: 购买重置/挑战 次数, 购买前检查上次次数更新时的时间, 重置次数有购买限制, 和VIP level相关。
                count_type: 1:购买重置次数; 2:购买挑战次数
        '''
        res_err = UNKNOWN_ERROR
        self.system_daily_reset()
        climbing_data = self.get_vip_conf_of_climbing()
        if count_type == 1:
            if (climbing_data[1] + self.climbing.buyed_reset > 0):
                log.error('User has reset count. cid: {0}, had_free_reset: {1}, buyed_reset: {2}.'.format( self.cid, self.climbing.free_reset, self.climbing.buyed_reset ))
                defer.returnValue( HAVE_NUM_TO_USE )
            if climbing_data[2] < 1:
                log.error('Daily max buy reset count limit. cid: {0}.'.format( self.cid ))
                defer.returnValue( BUY_MAX_NUM_ERROR )
            if self.climbing.cur_layer < self.climbing.max_layer:
                reset_layer = self.climbing.cur_layer
            else:
                reset_layer = self.climbing.max_layer
            conf = get_climbing_conf( reset_layer )
            if not conf:
                log.error('No conf. cid: {0}, reset_layer: {0}.'.format( cid, reset_layer ))
                defer.returnValue( NOT_FOUND_CONF )
            if conf['ResetCost'] > self.user.base_att.credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format( conf['ResetCost'], self.user.base_att.credits ))
                defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
            yield self.user.consume_credits( conf['ResetCost'], WAY_CLIMBING_RESET )
            self.climbing.left_buy_reset += 1
            self.climbing.buyed_reset    += 1
            res_err = count_type, self.climbing.buyed_reset, self.user.base_att.credits
        elif count_type == 2:
            if (climbing_data[0] + self.climbing.buyed_fight > 0):
                log.error('User has fight count. cid: {0}, had_free_fight: {1}, buyed_fight: {2}.'.format( self.cid, self.climbing.free_fight, self.climbing.buyed_fight ))
                defer.returnValue( HAVE_NUM_TO_USE )
            if CLIMBING_FIGHT_COST > self.user.base_att.credits:
                log.error('Credits not enough. need: 10, cur: {0}.'.format( self.user.base_att.credits ))
                defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
            yield self.user.consume_credits( CLIMBING_FIGHT_COST, WAY_CLIMBING_FIGHT )
            self.climbing.buyed_fight += 1
            res_err = count_type, self.climbing.buyed_fight, self.user.base_att.credits

        defer.returnValue( res_err )
 
    @defer.inlineCallbacks
    def climbing_reward(self, fight_layer, status):
        '''
        @summary: 单次通关失败扣挑战次数, 更新玩家当前所在塔层及最大塔层, 给通关后的奖励
        '''
        self.system_daily_reset()
        # 可挑战的塔层数据不同步
        if fight_layer != self.climbing.cur_layer:
            log.error('User request fight_layer error. cid: {0}, fight_layer: {1}, cur_layer: {2}.'.format( self.cid, fight_layer, self.climbing.cur_layer ))
            defer.returnValue( REQUEST_LIMIT_ERROR )
        # 没有挑战次数不能挑战
        climbing_data = self.get_vip_conf_of_climbing()
        if (climbing_data[0] + self.climbing.buyed_fight < 1):
            log.error('User no fight count. cid: {0}, had_free_fight: {1}, buyed_fight: {2}.'.format( self.cid, self.climbing.free_fight, self.climbing.buyed_fight ))
            defer.returnValue( REQUEST_LIMIT_ERROR )
        # 已经到了最大塔层 不能继续挑战
        if self.climbing.cur_layer >= self.MAX_LAYER:
            log.error('Had been the max layer. cur_layer: {0}, climbing_tower MAX_LAYER: {1}.'.format( self.climbing.cur_layer, self.MAX_LAYER ))
            defer.returnValue( IN_CLIMBING_MAX_LAYER )
        # 每日任务计数
        yield self.user.daily_quest_mgr.update_daily_quest( DAILY_QUEST_ID_9, 1 )
        yield self.user.open_server_mgr.update_open_server_activity_quest( OPEN_SERVER_QUEST_ID_10, self.climbing.cur_layer)
        #成就
        yield self.user.achievement_mgr.update_achievement_status( ACHIEVEMENT_QUEST_ID_10, self.climbing.cur_layer)
        if not status: # 通关失败
            if self.climbing.buyed_fight > 0:
                self.climbing.buyed_fight -= 1
            elif climbing_data[0] > 0:
                climbing_data[0] -= 1
                self.climbing.free_fight += 1
            defer.returnValue( (status, self.climbing.cur_layer, self.climbing.max_layer, climbing_data[0]+self.climbing.buyed_fight, [], 0, 0, 0, self.user.base_att.energy) )
 
        # 获取塔层通过的奖励
        conf = get_climbing_conf( self.climbing.cur_layer )
        if not conf:
            log.error('No conf. cid: {0}, cur_layer: {0}.'.format( cid, self.climbing.cur_layer ))
            defer.returnValue( NOT_FOUND_CONF )

        #self.user.base_att.golds += conf['RewardGold']
        self.user.get_golds( conf['RewardGold'], WAY_CLIMBING_AWARD )
        self.user.base_att.soul  += conf['RewardSoul']
        items_return = []
        #log.info('For Test. cur_layer: {0}, BonusList: {1}.'.format( self.climbing.cur_layer, conf['BonusList'] ))
        for _type, _id, _num in conf['BonusList']:
            model = ITEM_MODELs.get( _type, None )
            if not model:
                log.error('Unknown item type. item: {0}.'.format( (_type, _id, _num) ))
                continue
            res_err, value = yield model(self.user, ItemID=_id, ItemNum=_num, AddType=WAY_CLIMBING_AWARD, CapacityFlag=False)
            if not res_err and value:
                #log.info('For Test. value: {0}.'.format( value ))
                for _v in value:
                    items_return = total_new_items( _v, items_return )
        #log.info('For Test. after BonusList: {0}.'.format( conf['BonusList'] ))

        if self.climbing.cur_layer >= self.MAX_LAYER:
            self.climbing.cur_layer = self.MAX_LAYER
        else:
            self.climbing.cur_layer += 1

        # 挑战更高的塔层
        if (self.climbing.cur_layer <= self.MAX_LAYER) and (self.climbing.cur_layer > self.climbing.max_layer):
            self.climbing.max_layer += 1
        if self.climbing.max_layer > self.MAX_LAYER:
            self.climbing.max_layer = self.MAX_LAYER

        # 更新天外天排行榜
        yield redis.zadd(SET_CLIMBING_CID_LAYER, self.cid, -self.climbing.max_layer)

        defer.returnValue( (status, self.climbing.cur_layer, self.climbing.max_layer, climbing_data[0]+self.climbing.buyed_fight, items_return, conf['RewardGold'], conf['RewardSoul'], 0, self.user.base_att.energy) )

    def start_climbing(self, start_layer):
        '''
        @summary: 记录扫荡的开始时间
        '''
        # 塔层数据不同步
        if start_layer != self.climbing.cur_layer:
            log.error('User request start_layer error. cid: {0}, start_layer: {1}, cur_layer: {2}.'.format( self.cid, start_layer, self.climbing.cur_layer ))
            return REQUEST_LIMIT_ERROR

        if self.climbing.cur_layer > self.climbing.max_layer:
            log.error('Could not climbing. cur_layer: {0}, max_layer: {1}.'.format( self.climbing.cur_layer, self.climbing.max_layer ))
            return IN_CLIMBING_MAX_LAYER
        self.climbing.start_datetime = int(time())
 
        return NO_ERROR

    @defer.inlineCallbacks
    def stop_climbing(self, stop_layer):
        '''
        @summary: 根据结束时间计算可扫荡到的塔层, 奖励进领奖中心。
        '''
        timestamp     = int(time())
        total_sceonds = timestamp - self.climbing.start_datetime
        if (not self.climbing.start_datetime) or (total_sceonds <= 0):
            log.error('Unknown error. start climbing time: {0}, cur_layer: {1}, stop_layer: {2}, total_sceonds: {3}.'.format( self.climbing.start_datetime, self.climbing.cur_layer, stop_layer, total_sceonds ))
            defer.returnValue( IN_CLIMBING_DONE )
        # 重置扫荡的开始时间
        self.climbing.start_datetime = 0

        #log.info('For Test. cur_layer: {0}, stop_layer: {1}, total_sceonds: {2}.'.format( self.climbing.cur_layer, stop_layer, total_sceonds ))
        flag = True
        award_layer = [] # 可获得奖励的塔层列表
        while flag:
            conf = get_climbing_conf( self.climbing.cur_layer )
            if not conf:
                log.error('No conf. tower layer: {0}.'.format( self.climbing.cur_layer ))
                defer.returnValue( NOT_FOUND_CONF )

            if total_sceonds < conf['NeedTime']:
                flag = False
            else:
                total_sceonds -= conf['NeedTime']
                # 奖励进领奖中心
                award_layer.append( self.climbing.cur_layer )
                # 判断是否已经到达了conf的最高层
                if self.climbing.cur_layer >= self.MAX_LAYER:
                    flag = False
                    self.climbing.cur_layer = self.MAX_LAYER
                else:
                    if self.climbing.cur_layer >= self.climbing.max_layer:
                        flag = False
                    self.climbing.cur_layer += 1
                # 每日任务计数
                yield self.user.daily_quest_mgr.update_daily_quest( DAILY_QUEST_ID_9, 1 )
            #log.info('For Test. cur_layer: {0}, stop_layer: {1}, total_sceonds: {2}, flag: {3}.'.format( self.climbing.cur_layer, stop_layer, total_sceonds, flag ))

        if award_layer:
            yield g_AwardCenterMgr.new_award( self.cid, AWARD_TYPE_CLIMBING, [timestamp, award_layer] )
 
        defer.returnValue( (self.climbing.cur_layer, self.climbing.max_layer) )

    @defer.inlineCallbacks
    def finish_climbing(self, start_layer):
        '''
        @summary: 使用钻石购买扫荡到最高塔层的时间, 更新玩家当前所在塔层及最大塔层, 给通关后的奖励
        '''
        if start_layer > self.climbing.max_layer:
            log.error('Could not climbing. cur_layer: {0}, start_layer: {1}, max_layer: {2}.'.format( self.climbing.cur_layer, start_layer, self.climbing.max_layer ))
            defer.returnValue( IN_CLIMBING_MAX_LAYER )
 
        award_layer   = [] # 可获得奖励的塔层列表
        total_credits = 0  # 需要消耗的钻石
        finish_layer  = start_layer # self.climbing.cur_layer
        while finish_layer <= self.climbing.max_layer:
            conf = get_climbing_conf( finish_layer )
            if not conf:
                log.error('No conf. tower layer: {0}.'.format( finish_layer ))
                defer.returnValue( NOT_FOUND_CONF )
            total_credits += conf['NeedTime']
            award_layer.append( finish_layer )
            finish_layer += 1
        if (total_credits % COOLDOWN_TIME_COST):
            total_credits = (total_credits / COOLDOWN_TIME_COST) + 1
        else:
            total_credits = (total_credits / COOLDOWN_TIME_COST)

        if total_credits > self.user.base_att.credits:
            log.error('Credits not enough. need: {0}, cur: {1}.'.format( total_credits, self.user.base_att.credits ))
            defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
        # 重置扫荡的开始时间
        self.climbing.start_datetime = 0

        self.climbing.cur_layer = finish_layer
        yield self.user.consume_credits( total_credits, WAY_CLIMBING_DONE )
        if award_layer:
            g_AwardCenterMgr.new_award( self.cid, AWARD_TYPE_CLIMBING, [int(time()), award_layer] )
            # 每日任务计数
            yield self.user.daily_quest_mgr.update_daily_quest( DAILY_QUEST_ID_9, len(award_layer) )
 
        defer.returnValue( (self.climbing.cur_layer, self.climbing.max_layer, self.user.base_att.credits) )
 
    @defer.inlineCallbacks
    def ranklist(self):
        ''' 获取天外天的排行榜 '''
        yield self.load()
        # get myself rank and layer
        _my_rank  = yield redis.zrank(SET_CLIMBING_CID_LAYER, self.cid)
        _my_rank  = 0 if _my_rank is None else int(_my_rank)+1
        _ranklist = [self.climbing.max_layer, _my_rank, []]

        _cid_layers = yield redis.zrange(SET_CLIMBING_CID_LAYER, 0, 9, withscores=True)
        for _idx, _data in enumerate(_cid_layers):
            #log.error('For Test. _idx: {0}, _cid_layers: {1}.'.format( _idx+1, _data ))
            if int(_data[1]) >= 0:
                continue
            _detail = yield load_climbing_user_data(_data[0])
            if not _detail:
                log.error('Unknown user. cid: {0}.'.format( _data[0] ))
                continue
            _detail.extend( [-int(_data[1]), _idx+1] )
            _ranklist[2].append( _detail )

        defer.returnValue( _ranklist )
예제 #8
0
    def addItem(self,
                add_item_type,
                add_item_id,
                add_count,
                partial_add=False
                ):  #Return item inst if succeed, else return None.

        if add_count > BAG_MAX_PILE:
            log.warn('Exp3404361 Add count > max pile. Add count :', add_count)
            defer.returnValue(None)

        gs_att_find = GSAttribute(self.__cid, self._tbl_name, 0,
                                  self._item_field_set)
        gs_att_find.updateGSAttribute(False, {
            'item_type': add_item_type,
            'item_id': add_item_id,
            'count': add_count
        })
        target_item = GSBagItem(gs_att_find)

        found_pos = bisect.bisect_left(self.__list, target_item)
        found_item = None
        log.debug('Find pos {0}'.format(found_pos))

        find_same = False
        if found_pos < 0 or found_pos >= len(self.__list):
            find_same = False
        else:
            found_item = self.__list[found_pos]
            if target_item.isSame(found_item):
                find_same = True
            else:
                find_same = False

        if find_same:
            leftmost = self.findLeftmostSameOne(found_pos)
            found_item = self.__list[leftmost]
            log.debug('Leftmost pos {0}'.format(leftmost))
            add_count = self.dispatchAddCount(
                leftmost, add_count, BAG_MAX_PILE
            )  #Try to dispath add count on existed (one or several ) items!

            count_sum = found_item.count + add_count
            if count_sum <= BAG_MAX_PILE:
                #Fully pile, just modify existing item's count.
                found_item.setItemCount(count_sum)
                defer.returnValue(found_item)
            else:
                if not partial_add:
                    #Add fail! Not allow partial pile!
                    pass
                else:
                    #Partial pile, ajust their count.
                    found_item.setItemCount(BAG_MAX_PILE)
                    add_count = count_sum - BAG_MAX_PILE

        if len(self.__list) >= self.__capacity:
            log.debug('[ GSBag::addItem ] Bag is full!  Cur capacity:',
                      self.__capacity, ' partial_add:', partial_add)
            defer.returnValue(None)

        log.debug(
            '[ GSBag::addItem ] Need create item via cs. cid {0}, type {1}, id {2}, count {3}'
            .format(self.__cid, add_item_type, add_item_id, add_count))
        try:
            new_item = yield self.createItemViaCS(add_item_type, add_item_id,
                                                  add_count)
        except Exception as e:
            log.exception()
            defer.returnValue(None)

        if not new_item:
            log.error(
                'Exp39303873 create item via cs fail ! cid {0}, item {1}, {2}'.
                format(self.__cid, add_item_type, add_item_id))
            defer.returnValue(None)

        bisect.insort_left(self.__list, new_item)

        defer.returnValue(new_item)
예제 #9
0
    def addItem(self, add_item_type, add_item_id, add_count, partial_add=False):#Return item inst if succeed, else return None.

        if add_count > BAG_MAX_PILE:
            log.warn('Exp3404361 Add count > max pile. Add count :', add_count)
            defer.returnValue(None)

        gs_att_find = GSAttribute(self.__cid, self._tbl_name, 0, self._item_field_set)
        gs_att_find.updateGSAttribute(False, { 'item_type':add_item_type , 'item_id':add_item_id, 'count':add_count })
        target_item = GSBagItem(gs_att_find)

        found_pos = bisect.bisect_left(self.__list, target_item)
        found_item = None
        log.debug('Find pos {0}'.format(found_pos))

        find_same = False
        if found_pos < 0 or found_pos >= len(self.__list):
            find_same = False
        else:
            found_item = self.__list[found_pos]
            if target_item.isSame( found_item ):
                find_same = True
            else:
                find_same = False

        if find_same:
            leftmost = self.findLeftmostSameOne(found_pos)
            found_item = self.__list[leftmost]
            log.debug('Leftmost pos {0}'.format(leftmost))
            add_count = self.dispatchAddCount(leftmost, add_count, BAG_MAX_PILE) #Try to dispath add count on existed (one or several ) items!

            count_sum = found_item.count + add_count
            if count_sum <= BAG_MAX_PILE:
                #Fully pile, just modify existing item's count.
                found_item.setItemCount(count_sum)
                defer.returnValue(found_item)
            else:
                if not partial_add:
                    #Add fail! Not allow partial pile!
                    pass
                else:
                    #Partial pile, ajust their count.
                    found_item.setItemCount(BAG_MAX_PILE)
                    add_count = count_sum - BAG_MAX_PILE

        if len(self.__list) >= self.__capacity:
            log.debug('[ GSBag::addItem ] Bag is full!  Cur capacity:', self.__capacity, ' partial_add:', partial_add)
            defer.returnValue(None)

        log.debug('[ GSBag::addItem ] Need create item via cs. cid {0}, type {1}, id {2}, count {3}'.format( self.__cid, add_item_type, add_item_id, add_count ))
        try:
            new_item = yield self.createItemViaCS(add_item_type, add_item_id, add_count)
        except Exception as e:
            log.exception();
            defer.returnValue(None)

        if not new_item:
            log.error('Exp39303873 create item via cs fail ! cid {0}, item {1}, {2}'.format( self.__cid, add_item_type, add_item_id ))
            defer.returnValue(None)

        bisect.insort_left(self.__list, new_item)

        defer.returnValue(new_item)
예제 #10
0
class GSActiveSceneMgr(object):
    '''
    ( 'id', 'cid', 'panda_free', 'panda_buyed', 'panda_left_buy', 'treasure_free', 'treasure_buyed', 'treasure_left_buy', 'tree_free', 'tree_buyed', 'tree_left_buy', 'last_datetime' )
    '''
    _table = 'activescene'
    _fields = TABLE_FIELDS['activescene'][0]

    def __init__(self, user):
        self.user = user
        self.cid = user.cid
        self.load_flag = False

        # 单次战斗中伙伴复活的次数
        self.revive_count = 0
        # 战斗中的活动副本ID
        self.old_activescene_id = 0
        self.activescene = GSAttribute(user.cid, GSActiveSceneMgr._table,
                                       user.cid)

    @defer.inlineCallbacks
    def load(self):
        if not self.load_flag:
            try:
                table_data = yield gs_load_table_data(self.cid,
                                                      GSActiveSceneMgr._table)
                # 注意在收到返回消息后才能赋值
                self.load_flag = True
                #log.info('For Test. table_data: {0}.'.format( table_data ))
                if table_data:
                    table_data = dict(zip(GSActiveSceneMgr._fields,
                                          table_data))
                    #log.info('For Test. updateGSAttribute. table_data: {0}.'.format( table_data ))
                    self.activescene.updateGSAttribute(False, **table_data)
                else:
                    yield self.new()
            except Exception as e:
                log.error('Exception raise. e: {0}.'.format(e))

    def sync_to_cs(self):
        if self.activescene:
            self.activescene.syncToCS()

    @defer.inlineCallbacks
    def new(self):
        now_weekday = datetime.now().isoweekday()

        conf = get_vip_conf(self.user.base_att.vip_level)
        left_buy = conf['ActiveSceneCount'] if conf else 0

        conf = get_activescene_conf(ACTIVE_PANDA_ID)
        panda_free = self.isOpenCycle(conf, now_weekday)

        conf = get_activescene_conf(ACTIVE_TREASURE_ID)
        treasure_free = self.isOpenCycle(conf, now_weekday)

        conf = get_activescene_conf(ACTIVE_TREE_ID)
        tree_free = self.isOpenCycle(conf, now_weekday)

        dt_now = datetime.now()
        init_data = [
            self.cid, panda_free, 0, left_buy, treasure_free, 0, left_buy,
            tree_free, 0, left_buy, dt_now
        ]
        kwargs = dict(zip(GSActiveSceneMgr._fields[1:], init_data))
        create_data = yield gs_create_table_data(self.cid,
                                                 GSActiveSceneMgr._table,
                                                 **kwargs)
        if create_data:
            create_data = dict(zip(GSActiveSceneMgr._fields, create_data))
            self.activescene.updateGSAttribute(False, **create_data)
        else:  # 新增数据失败
            self.load_flag = False

        defer.returnValue(NO_ERROR)

    @property
    def value(self):
        conf = get_vip_conf(self.user.vip_level)
        total = conf['ActiveSceneCount'] if conf else 0
        panda_left = total - self.activescene.panda_left_buy if total > self.activescene.panda_left_buy else 0
        treasure_left = total - self.activescene.treasure_left_buy if total > self.activescene.treasure_left_buy else 0
        tree_left = total - self.activescene.tree_left_buy if total > self.activescene.tree_left_buy else 0
        return ((ACTIVE_PANDA_ID, self.activescene.panda_free+self.activescene.panda_buyed, panda_left), \
                (ACTIVE_TREASURE_ID, self.activescene.treasure_free+self.activescene.treasure_buyed, treasure_left), \
                (ACTIVE_TREE_ID, self.activescene.tree_free+self.activescene.tree_buyed, tree_left))

    @defer.inlineCallbacks
    def system_daily_reset(self):
        '''
        @summary: 每个活动副本有玩家等级限制 和 固定的开启时间: 星期几及时间段
                每天24点系统重置活动副本数据, 含免费挑战次数、剩余可够买的次数、更新时间
        '''
        yield self.load()
        dt_now = datetime.now()
        dt_last = self.activescene.last_datetime
        if dt_now.date() != dt_last.date():
            now_weekday = dt_now.isoweekday()

            self.activescene.panda_left_buy = 0
            self.activescene.treasure_left_buy = 0
            self.activescene.tree_left_buy = 0

            conf = get_activescene_conf(ACTIVE_PANDA_ID)
            self.activescene.panda_free = self.isOpenCycle(conf, now_weekday)

            conf = get_activescene_conf(ACTIVE_TREASURE_ID)
            self.activescene.treasure_free = self.isOpenCycle(
                conf, now_weekday)

            conf = get_activescene_conf(ACTIVE_TREE_ID)
            self.activescene.tree_free = self.isOpenCycle(conf, now_weekday)

            self.activescene.last_datetime = dt_now

    def isOpenCycle(self, conf, weekday):
        '''
        check OpenCycle return today free count
        '''
        free_num = 0
        if not conf:
            return free_num

        open_cycle = conf['OpenCycle']
        if open_cycle:
            open_cycle = map(int, open_cycle.split(','))
            if weekday in open_cycle:
                free_num = conf['CleanNum']
        else:
            free_num = conf['CleanNum']

        return free_num

    @defer.inlineCallbacks
    def activescene_data(self):
        '''
        @summary: 获取精英副本的基本信息
        '''
        yield self.system_daily_reset()
        defer.returnValue(self.value)

    @defer.inlineCallbacks
    def start_battle(self, activescene_id):
        '''
        @summary: 记录玩家的战斗信息
        '''
        conf = get_activescene_conf(activescene_id)
        if not conf:
            log.error(
                'Unknown activescene conf. id: {0}.'.format(activescene_id))
            defer.returnValue(NOT_FOUND_CONF)

        dt_now = datetime.now()
        # 检查活动副本是否开启
        if conf['OpenCycle']:
            cycle_list = map(int, conf['OpenCycle'].split(','))
            if dt_now.isoweekday() not in cycle_list:
                log.error('Active not opened. OpenCycle: {0}.'.format(
                    conf['OpenCycle']))
                defer.returnValue(ACTIVE_FIGHT_TIME_ERROR)
        if conf['OpenTime']:
            if dt_now.time() < conf['OpenTime'].time():
                log.error('Active not opened. OpenTime: {0}.'.format(
                    conf['OpenTime']))
                defer.returnValue(ACTIVE_FIGHT_TIME_ERROR)
        if conf['CloseTime']:
            if dt_now.time() > conf['CloseTime'].time():
                log.error('Active had closed. CloseTime: {0}.'.format(
                    conf['CloseTime']))
                defer.returnValue(ACTIVE_FIGHT_TIME_ERROR)
        # 玩家等级限制
        if conf['NeedRoleLevel'] > self.user.base_att.level:
            log.error('User level limit. need: {0}, cur: {1}.'.format(
                conf['NeedRoleLevel'], self.user.base_att.level))
            defer.returnValue(CHAR_LEVEL_LIMIT)

        # 每日挑战次数限制
        yield self.system_daily_reset()
        if activescene_id == ACTIVE_PANDA_ID:
            if (self.activescene.panda_free + self.activescene.panda_buyed <
                    1):
                log.error('No fight count. panda_free: {0}, panda_buyed: {1}.'.
                          format(self.activescene.panda_free,
                                 self.activescene.panda_buyed))
                defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)
        elif activescene_id == ACTIVE_TREASURE_ID:
            if (self.activescene.treasure_free +
                    self.activescene.treasure_buyed < 1):
                log.error(
                    'No fight count. treasure_free: {0}, treasure_buyed: {1}.'.
                    format(self.activescene.treasure_free,
                           self.activescene.treasure_buyed))
                defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)
        elif activescene_id == ACTIVE_TREE_ID:
            if (self.activescene.tree_free + self.activescene.tree_buyed < 1):
                log.error(
                    'No fight count. tree_free: {0}, tree_buyed: {1}.'.format(
                        self.activescene.tree_free,
                        self.activescene.tree_buyed))
                defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)
        else:
            log.error('Unknown activescene_id: {0}.'.format(activescene_id))
            defer.returnValue(REQUEST_LIMIT_ERROR)

        self.revive_count = 0
        self.old_activescene_id = activescene_id

        defer.returnValue(NO_ERROR)

    @defer.inlineCallbacks
    def dungeon_star_drop(self, dungeon_id, dungeon_star=1):
        '''
        @summary: 精英副本默认难度为1, 无conf则不用计算掉落
        @param  : drop_items-[ [item_type, item_id, item_num], ... ]
        '''
        drop_items = []

        drop_conf = get_drop_conf(dungeon_id, dungeon_star)
        if not drop_conf:
            log.error(
                'No drop conf. dungeon_id: {0}, dungeon_star: {1}.'.format(
                    dungeon_id, dungeon_star))
            defer.returnValue(drop_items)

        # old_rate format: {dungeon_star: {drop_id: rate, ...}, ...}
        old_rate = {}
        data = yield redis.hget(HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid)
        if data:
            old_rate = loads(data)
            if old_rate.has_key(dungeon_star):
                old_star_rate = old_rate[dungeon_star]
            else:
                old_star_rate = {}
                old_rate[dungeon_star] = old_star_rate
                for _id, _drop in drop_conf.iteritems():
                    old_star_rate[_id] = _drop['RateMax']
        else:  # 第一次按照最大概率来计算掉落
            old_star_rate = {}
            old_rate[dungeon_star] = old_star_rate
            for _id, _drop in drop_conf.iteritems():
                old_star_rate[_id] = _drop['RateMax']

        for _drop_id, _drop in drop_conf.iteritems():
            add_rate = old_star_rate.setdefault(_drop_id, 0)
            _drop_rate = _drop['RateStart'] + add_rate
            # 单次增加的封顶概率
            if _drop_rate > _drop['RateMax']:
                _drop_rate = _drop['RateMax']
            # 掉落概率是万分比
            rand_int = random.randint(0, 10000)
            #log.info('For Test. rand_int: {0}, _drop_rate: {1}, _drop_id: {2}, _drop_num: {3}.'.format( rand_int, _drop_rate, _drop['ItemID'], _drop['ItemNum'] ))
            # _drop['QuestID'] 未处理
            # 当前随机值 不大于 配置的掉落概率值时掉落
            if rand_int <= _drop_rate:
                drop_items = add_new_items(
                    [_drop['ItemType'], _drop['ItemID'], _drop['ItemNum']],
                    drop_items)

                old_star_rate[_drop_id] = 0
            else:
                old_star_rate[_drop_id] += _drop['RateAdd']
        yield redis.hset(HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid,
                         dumps(old_rate))

        defer.returnValue(drop_items)

    @defer.inlineCallbacks
    def get_dungeon_drop(self, drop_items, way_type, way_others=''):
        ''' 获取怪物组战斗胜利后 掉落的道具 '''
        dungeon_drop_items = []

        for _item_type, _item_id, _item_num in drop_items:
            # 掉落分魂碎片、普通道具
            _model = ITEM_MODELs.get(_item_type, None)
            if not _model:
                log.error(
                    'Unknown item type. ItemType: {0}.'.format(_item_type))
                continue
            res_err, value = yield _model(self.user,
                                          ItemID=_item_id,
                                          ItemNum=_item_num,
                                          AddType=way_type,
                                          WayOthers=way_others,
                                          CapacityFlag=False)
            if not res_err and value:
                for _v in value:
                    dungeon_drop_items = total_new_items(
                        _v, dungeon_drop_items)

        defer.returnValue(dungeon_drop_items)

    @defer.inlineCallbacks
    def get_battle_reward(self, battle_type, status, activescene_id):
        '''
        @param : battle_type-3:经验熊猫; 4:经验宝物; 5:打土豪
            当type=5时, status值为对土豪的有效伤害值
        @param : 战斗结果 status 0:fail, 1:success
        '''
        if activescene_id != self.old_activescene_id:
            log.error(
                'Battle data error. old_activescene_id: {0}, activescene_id: {1}.'
                .format(self.old_activescene_id, activescene_id))
            #defer.returnValue( REQUEST_LIMIT_ERROR )

        # 每日挑战次数限制
        yield self.system_daily_reset()

        self.revive_count = 0
        self.old_activescene_id = 0

        # 战斗失败
        if not status:
            if battle_type == FIGHT_TYPE_PANDA:
                fight_count = self.activescene.panda_free + self.activescene.panda_buyed
                defer.returnValue((battle_type, status, 0, 0, fight_count, [],
                                   0, 0, 0, self.user.base_att.energy))
            elif battle_type == FIGHT_TYPE_TREASURE:
                fight_count = self.activescene.treasure_free + self.activescene.treasure_buyed
                defer.returnValue((battle_type, status, 0, 0, fight_count, [],
                                   0, 0, 0, self.user.base_att.energy))
            elif battle_type == FIGHT_TYPE_TREE:
                pass
            else:
                log.error('Unknown battle_type: {0}.'.format(battle_type))
                defer.returnValue(REQUEST_LIMIT_ERROR)

        golds_reward = 0
        activescene_drop_items = []
        # 扣挑战次数
        if battle_type == FIGHT_TYPE_PANDA:
            if self.activescene.panda_buyed > 0:
                self.activescene.panda_buyed -= 1
            elif self.activescene.panda_free > 0:
                self.activescene.panda_free -= 1
            else:
                log.error('No fight count. panda_free: {0}, panda_buyed: {1}.'.
                          format(self.activescene.panda_free,
                                 self.activescene.panda_buyed))
                defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)
            fight_count = self.activescene.panda_free + self.activescene.panda_buyed
            # 获取怪物组掉落, star默认为1
            drop_items = yield self.dungeon_star_drop(activescene_id, 1)
            # 新增掉落
            way_others = str((FIGHT_TYPE_PANDA, activescene_id, 1))
            activescene_drop_items = yield self.get_dungeon_drop(
                drop_items, WAY_ACTIVESCENE_PANDA_FIGHT, way_others)

        elif battle_type == FIGHT_TYPE_TREASURE:
            if self.activescene.treasure_buyed > 0:
                self.activescene.treasure_buyed -= 1
            elif self.activescene.treasure_free > 0:
                self.activescene.treasure_free -= 1
            else:
                log.error(
                    'No fight count. treasure_free: {0}, treasure_buyed: {1}.'.
                    format(self.activescene.treasure_free,
                           self.activescene.treasure_buyed))
                defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)
            fight_count = self.activescene.treasure_free + self.activescene.treasure_buyed
            # 获取怪物组掉落, star默认为1
            drop_items = yield self.dungeon_star_drop(activescene_id, 1)
            # 新增掉落
            way_others = str((FIGHT_TYPE_TREASURE, activescene_id, 1))
            activescene_drop_items = yield self.get_dungeon_drop(
                drop_items, WAY_ACTIVESCENE_TREASURE_FIGHT, way_others)

        elif battle_type == FIGHT_TYPE_TREE:
            if self.activescene.tree_buyed > 0:
                self.activescene.tree_buyed -= 1
            elif self.activescene.tree_free > 0:
                self.activescene.tree_free -= 1
            else:
                log.error(
                    'No fight count. tree_free: {0}, tree_buyed: {1}.'.format(
                        self.activescene.tree_free,
                        self.activescene.tree_buyed))
                defer.returnValue(SCENE_CHALLENGE_COUNT_LIMIT)
            fight_count = self.activescene.tree_free + self.activescene.tree_buyed
            # 计算金币
            golds_reward = int((status + 9) / 10)
            gold_tree_conf = get_gold_tree_conf()
            for _d, _g in gold_tree_conf:
                if status < _d:
                    break
                golds_reward += _g
            self.user.get_golds(golds_reward, WAY_ACTIVESCENE_TREE_FIGHT)
        else:
            log.error('Unknown battle_type: {0}.'.format(battle_type))
            defer.returnValue(REQUEST_LIMIT_ERROR)

        # 每日任务计数
        yield self.user.daily_quest_mgr.update_daily_quest(DAILY_QUEST_ID_4, 1)
        # add syslog
        str_drop_items = str(activescene_drop_items).replace('[', '(')
        str_drop_items = str_drop_items.replace(']', ')')
        syslogger(LOG_SCENE_BATTLE, self.cid, self.user.level,
                  self.user.vip_level, self.user.alliance_id, battle_type,
                  status, activescene_id, 1, 0, 0, golds_reward,
                  str_drop_items)

        defer.returnValue(
            (battle_type, status, 0, 0, fight_count, activescene_drop_items,
             golds_reward, 0, 0, self.user.base_att.energy))

    @defer.inlineCallbacks
    def buy_count(self, battle_type):
        '''
        @summary: 购买挑战次数,价格=基础价格*购买次数
        '''
        vip_conf = get_vip_conf(self.user.base_att.vip_level)
        if not vip_conf:
            log.error('No vip conf. vip_level: {0}.'.format(
                self.user.base_att.vip_level))
            defer.returnValue(NOT_FOUND_CONF)
        yield self.system_daily_reset()
        if battle_type == FIGHT_TYPE_PANDA:
            # 还有剩余挑战次数
            if (self.activescene.panda_free + self.activescene.panda_buyed >
                    0):
                log.error(
                    'User has fight count. panda_free: {0}, panda_buyed: {1}.'.
                    format(self.activescene.panda_free,
                           self.activescene.panda_buyed))
                defer.returnValue(HAVE_NUM_TO_USE)
            # 已购买次数达上限
            if self.activescene.panda_left_buy >= vip_conf['ActiveSceneCount']:
                log.error(
                    'No panda fight count could buy today. cid:{0}, vip_level:{1}.'
                    .format(self.cid, self.user.vip_level))
                defer.returnValue(BUY_MAX_NUM_ERROR)
            # 钻石不足
            conf = get_activescene_conf(ACTIVE_PANDA_ID)
            if not conf:
                log.error('Can not find conf. activescene_id: {0}.'.format(
                    ACTIVE_PANDA_ID))
                defer.returnValue(NOT_FOUND_CONF)
            need_credits = (self.activescene.panda_left_buy +
                            1) * conf['Price']
            if self.user.base_att.credits < need_credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format(
                    need_credits, self.user.base_att.credits))
                defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
            yield self.user.consume_credits(need_credits,
                                            WAY_ACTIVESCENE_PANDA_FIGHT)
            self.activescene.panda_left_buy += 1
            self.activescene.panda_buyed += 1

            defer.returnValue(
                ((self.activescene.panda_free + self.activescene.panda_buyed),
                 self.activescene.panda_left_buy, self.user.base_att.credits))
        elif battle_type == FIGHT_TYPE_TREASURE:
            # 还剩余有挑战次数
            if (self.activescene.treasure_free +
                    self.activescene.treasure_buyed > 0):
                log.error(
                    'User has fight count. treasure_free: {0}, treasure_buyed: {1}.'
                    .format(self.activescene.treasure_free,
                            self.activescene.treasure_buyed))
                defer.returnValue(HAVE_NUM_TO_USE)
            # 剩余购买次数不足
            if self.activescene.treasure_left_buy >= vip_conf[
                    'ActiveSceneCount']:
                log.error(
                    'No treasure fight count could buy today. cid:{0}, vip_level:{1}.'
                    .format(self.cid, self.user.vip_level))
                defer.returnValue(BUY_MAX_NUM_ERROR)
            # 钻石不足
            conf = get_activescene_conf(ACTIVE_TREASURE_ID)
            if not conf:
                log.error(
                    'No conf. activescene_id: {0}.'.format(ACTIVE_TREASURE_ID))
                defer.returnValue(NOT_FOUND_CONF)
            need_credits = (self.activescene.treasure_left_buy +
                            1) * conf['Price']
            if self.user.base_att.credits < need_credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format(
                    need_credits, self.user.base_att.credits))
                defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
            yield self.user.consume_credits(need_credits,
                                            WAY_ACTIVESCENE_TREASURE_FIGHT)
            self.activescene.treasure_left_buy += 1
            self.activescene.treasure_buyed += 1

            defer.returnValue(((self.activescene.treasure_free +
                                self.activescene.treasure_buyed),
                               self.activescene.treasure_left_buy,
                               self.user.base_att.credits))
        elif battle_type == FIGHT_TYPE_TREE:
            # 还剩余有挑战次数
            if (self.activescene.tree_free + self.activescene.tree_buyed > 0):
                log.error(
                    'User has fight count. tree_free: {0}, tree_buyed: {1}.'.
                    format(self.activescene.tree_free,
                           self.activescene.tree_buyed))
                defer.returnValue(HAVE_NUM_TO_USE)
            # 剩余购买次数不足
            if self.activescene.tree_left_buy >= vip_conf['ActiveSceneCount']:
                log.error(
                    'No tree fight count could buy today. cid:{0}, vip_level:{1}.'
                    .format(self.cid, self.user.vip_level))
                defer.returnValue(BUY_MAX_NUM_ERROR)
            # 钻石不足
            conf = get_activescene_conf(ACTIVE_TREE_ID)
            if not conf:
                log.error(
                    'No conf. activescene_id: {0}.'.format(ACTIVE_TREE_ID))
                defer.returnValue(NOT_FOUND_CONF)
            need_credits = (self.activescene.tree_left_buy + 1) * conf['Price']
            if self.user.base_att.credits < need_credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format(
                    need_credits, self.user.base_att.credits))
                defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
            yield self.user.consume_credits(need_credits,
                                            WAY_ACTIVESCENE_TREE_FIGHT)
            self.activescene.tree_left_buy += 1
            self.activescene.tree_buyed += 1

            defer.returnValue(
                ((self.activescene.tree_free + self.activescene.tree_buyed),
                 self.activescene.tree_left_buy, self.user.base_att.credits))
        else:
            log.error('Unknown battle_type: {0}.'.format(battle_type))
            defer.returnValue(REQUEST_LIMIT_ERROR)

    def battle_revive(self, battle_type):
        '''
        @summary: 复活初始价格为200金币, 价格=复活次数*初始价格
             同一场战斗中不同波数复活次数要累计 
        '''
        need_golds = (self.revive_count + 1) * REVIVE_BASIC_GOLDS
        if (self.user.base_att.golds < need_golds):
            log.error('Golds not enough. need: {0}, cur: {1}.'.format(
                need_golds, self.user.base_att.golds))
            return CHAR_GOLD_NOT_ENOUGH

        self.user.base_att.golds -= need_golds
        self.revive_count += 1

        return [self.user.base_att.golds]
예제 #11
0
class GSClimbingMgr(object):
    '''
    @summary: 天外天
    '''
    _table = 'climbing_tower'
    _fields = TABLE_FIELDS['climbing_tower'][0]

    def __init__(self, user):
        self.user = user
        self.cid = user.cid
        self.load_flag = False

        all_climbing_layers = get_all_climbing_layer()
        self.MAX_LAYER = max(all_climbing_layers) if all_climbing_layers else 0
        self.climbing = GSAttribute(user.cid, GSClimbingMgr._table, user.cid)

    @defer.inlineCallbacks
    def load(self):
        if self.load_flag:
            defer.returnValue(None)

        try:
            table_data = yield gs_load_table_data(self.cid,
                                                  GSClimbingMgr._table)
            # 注意在收到返回消息后才能赋值
            self.load_flag = True

            if table_data:
                table_data = dict(zip(GSClimbingMgr._fields, table_data))
                self.climbing.updateGSAttribute(False, **table_data)
            else:
                yield self.new()
        except Exception as e:
            log.error('Exception raise. e: {0}.'.format(e))

    def sync_to_cs(self):
        if self.climbing:
            self.climbing.syncToCS()

    @defer.inlineCallbacks
    def new(self):
        init_data = [self.cid, 1, 0, 0, 0, 0, 0, 0, 0, int(time())]
        kwargs = dict(zip(GSClimbingMgr._fields[1:], init_data))
        create_data = yield gs_create_table_data(self.cid,
                                                 GSClimbingMgr._table,
                                                 **kwargs)
        if create_data:
            create_data = dict(zip(GSClimbingMgr._fields, create_data))
            self.climbing.updateGSAttribute(False, **create_data)
        else:  # 新增数据失败
            self.load_flag = False

    def system_daily_reset(self):
        '''
        @summary: 每天24点系统重置天外天数据
        '''
        # 不是同一天, 系统重置玩家数据
        dt_now = datetime.now()
        dt_last = self.climbing.last_datetime
        if dt_now.date() != dt_last.date():
            self.climbing.free_fight = 0
            self.climbing.free_reset = 0
            self.climbing.left_buy_reset = 0
            self.climbing.last_datetime = dt_now

    def get_vip_conf_of_climbing(self):
        conf = get_vip_conf(self.user.vip_level)
        max_free_fight = conf['TowerFightCount'] if conf else 0
        left_free_fight = max_free_fight - self.climbing.free_fight if max_free_fight > self.climbing.free_fight else 0
        max_free_reset = conf['TowerResetCount'] if conf else 0
        left_free_reset = max_free_reset - self.climbing.free_reset if max_free_reset > self.climbing.free_reset else 0
        max_buy_reset = conf['TowerBuyReset'] if conf else 0
        left_buy_reset = max_buy_reset - self.climbing.left_buy_reset if max_buy_reset > self.climbing.left_buy_reset else 0

        return [
            left_free_fight, left_free_reset, left_buy_reset, max_free_fight,
            max_free_reset, max_buy_reset
        ]

    @defer.inlineCallbacks
    def climbing_data(self):
        '''
        @summary: 天外天的基本信息
        '''
        yield self.load()
        self.system_daily_reset()

        climbing_data = self.get_vip_conf_of_climbing()
        defer.returnValue( (self.climbing.cur_layer, self.climbing.max_layer, climbing_data[0]+self.climbing.buyed_fight, \
                climbing_data[1]+self.climbing.buyed_reset, climbing_data[2], self.climbing.start_datetime, self.user.credits) )

    @defer.inlineCallbacks
    def reset_climbing(self):
        '''
        @summary: 重置天外天数据。当前塔层归1, 挑战次数置满, 更新last_time, 扣重置次数
        '''
        self.system_daily_reset()
        # 正在扫荡, 不能重置
        if self.climbing.start_datetime > 0:
            log.error('In climbing could not reset.')
            defer.returnValue(IN_CLIMBING_ONGOING)
        if self.climbing.cur_layer == 1:
            log.error('Tower layer 1 could not reset.')
            defer.returnValue(IN_CLIMBING_MIN_LAYER)
        climbing_data = self.get_vip_conf_of_climbing()
        if (climbing_data[1] + self.climbing.buyed_reset < 1):
            log.warn(
                'User no reset count. cid: {0}, had_free_reset: {1}, buyed_reset: {2}.'
                .format(self.cid, self.climbing.free_reset,
                        self.climbing.buyed_reset))
            res_err = yield self.buy_count(1)
            if isinstance(res_err, int):
                defer.returnValue(res_err)
            climbing_data = self.get_vip_conf_of_climbing()

        self.climbing.cur_layer = 1
        if self.climbing.buyed_reset > 0:
            self.climbing.buyed_reset -= 1
        elif climbing_data[1] > 0:
            self.climbing.free_reset += 1
            climbing_data[1] -= 1

        self.climbing.free_fight = 0
        self.climbing.last_datetime = datetime.now()

        defer.returnValue( (self.climbing.cur_layer, self.climbing.max_layer, climbing_data[3]+self.climbing.buyed_fight, \
                climbing_data[1]+self.climbing.buyed_reset, climbing_data[2], self.climbing.start_datetime, self.user.credits) )

    @defer.inlineCallbacks
    def buy_count(self, count_type):
        '''
        @summary: 购买重置/挑战 次数, 购买前检查上次次数更新时的时间, 重置次数有购买限制, 和VIP level相关。
                count_type: 1:购买重置次数; 2:购买挑战次数
        '''
        res_err = UNKNOWN_ERROR
        self.system_daily_reset()
        climbing_data = self.get_vip_conf_of_climbing()
        if count_type == 1:
            if (climbing_data[1] + self.climbing.buyed_reset > 0):
                log.error(
                    'User has reset count. cid: {0}, had_free_reset: {1}, buyed_reset: {2}.'
                    .format(self.cid, self.climbing.free_reset,
                            self.climbing.buyed_reset))
                defer.returnValue(HAVE_NUM_TO_USE)
            if climbing_data[2] < 1:
                log.error('Daily max buy reset count limit. cid: {0}.'.format(
                    self.cid))
                defer.returnValue(BUY_MAX_NUM_ERROR)
            if self.climbing.cur_layer < self.climbing.max_layer:
                reset_layer = self.climbing.cur_layer
            else:
                reset_layer = self.climbing.max_layer
            conf = get_climbing_conf(reset_layer)
            if not conf:
                log.error('No conf. cid: {0}, reset_layer: {0}.'.format(
                    cid, reset_layer))
                defer.returnValue(NOT_FOUND_CONF)
            if conf['ResetCost'] > self.user.base_att.credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format(
                    conf['ResetCost'], self.user.base_att.credits))
                defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
            yield self.user.consume_credits(conf['ResetCost'],
                                            WAY_CLIMBING_RESET)
            self.climbing.left_buy_reset += 1
            self.climbing.buyed_reset += 1
            res_err = count_type, self.climbing.buyed_reset, self.user.base_att.credits
        elif count_type == 2:
            if (climbing_data[0] + self.climbing.buyed_fight > 0):
                log.error(
                    'User has fight count. cid: {0}, had_free_fight: {1}, buyed_fight: {2}.'
                    .format(self.cid, self.climbing.free_fight,
                            self.climbing.buyed_fight))
                defer.returnValue(HAVE_NUM_TO_USE)
            if CLIMBING_FIGHT_COST > self.user.base_att.credits:
                log.error('Credits not enough. need: 10, cur: {0}.'.format(
                    self.user.base_att.credits))
                defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
            yield self.user.consume_credits(CLIMBING_FIGHT_COST,
                                            WAY_CLIMBING_FIGHT)
            self.climbing.buyed_fight += 1
            res_err = count_type, self.climbing.buyed_fight, self.user.base_att.credits

        defer.returnValue(res_err)

    @defer.inlineCallbacks
    def climbing_reward(self, fight_layer, status):
        '''
        @summary: 单次通关失败扣挑战次数, 更新玩家当前所在塔层及最大塔层, 给通关后的奖励
        '''
        self.system_daily_reset()
        # 可挑战的塔层数据不同步
        if fight_layer != self.climbing.cur_layer:
            log.error(
                'User request fight_layer error. cid: {0}, fight_layer: {1}, cur_layer: {2}.'
                .format(self.cid, fight_layer, self.climbing.cur_layer))
            defer.returnValue(REQUEST_LIMIT_ERROR)
        # 没有挑战次数不能挑战
        climbing_data = self.get_vip_conf_of_climbing()
        if (climbing_data[0] + self.climbing.buyed_fight < 1):
            log.error(
                'User no fight count. cid: {0}, had_free_fight: {1}, buyed_fight: {2}.'
                .format(self.cid, self.climbing.free_fight,
                        self.climbing.buyed_fight))
            defer.returnValue(REQUEST_LIMIT_ERROR)
        # 已经到了最大塔层 不能继续挑战
        if self.climbing.cur_layer >= self.MAX_LAYER:
            log.error(
                'Had been the max layer. cur_layer: {0}, climbing_tower MAX_LAYER: {1}.'
                .format(self.climbing.cur_layer, self.MAX_LAYER))
            defer.returnValue(IN_CLIMBING_MAX_LAYER)
        # 每日任务计数
        yield self.user.daily_quest_mgr.update_daily_quest(DAILY_QUEST_ID_9, 1)
        yield self.user.open_server_mgr.update_open_server_activity_quest(
            OPEN_SERVER_QUEST_ID_10, self.climbing.cur_layer)
        #成就
        yield self.user.achievement_mgr.update_achievement_status(
            ACHIEVEMENT_QUEST_ID_10, self.climbing.cur_layer)
        if not status:  # 通关失败
            if self.climbing.buyed_fight > 0:
                self.climbing.buyed_fight -= 1
            elif climbing_data[0] > 0:
                climbing_data[0] -= 1
                self.climbing.free_fight += 1
            defer.returnValue(
                (status, self.climbing.cur_layer, self.climbing.max_layer,
                 climbing_data[0] + self.climbing.buyed_fight, [], 0, 0, 0,
                 self.user.base_att.energy))

        # 获取塔层通过的奖励
        conf = get_climbing_conf(self.climbing.cur_layer)
        if not conf:
            log.error('No conf. cid: {0}, cur_layer: {0}.'.format(
                cid, self.climbing.cur_layer))
            defer.returnValue(NOT_FOUND_CONF)

        #self.user.base_att.golds += conf['RewardGold']
        self.user.get_golds(conf['RewardGold'], WAY_CLIMBING_AWARD)
        self.user.base_att.soul += conf['RewardSoul']
        items_return = []
        #log.info('For Test. cur_layer: {0}, BonusList: {1}.'.format( self.climbing.cur_layer, conf['BonusList'] ))
        for _type, _id, _num in conf['BonusList']:
            model = ITEM_MODELs.get(_type, None)
            if not model:
                log.error('Unknown item type. item: {0}.'.format(
                    (_type, _id, _num)))
                continue
            res_err, value = yield model(self.user,
                                         ItemID=_id,
                                         ItemNum=_num,
                                         AddType=WAY_CLIMBING_AWARD,
                                         CapacityFlag=False)
            if not res_err and value:
                #log.info('For Test. value: {0}.'.format( value ))
                for _v in value:
                    items_return = total_new_items(_v, items_return)
        #log.info('For Test. after BonusList: {0}.'.format( conf['BonusList'] ))

        if self.climbing.cur_layer >= self.MAX_LAYER:
            self.climbing.cur_layer = self.MAX_LAYER
        else:
            self.climbing.cur_layer += 1

        # 挑战更高的塔层
        if (self.climbing.cur_layer <= self.MAX_LAYER) and (
                self.climbing.cur_layer > self.climbing.max_layer):
            self.climbing.max_layer += 1
        if self.climbing.max_layer > self.MAX_LAYER:
            self.climbing.max_layer = self.MAX_LAYER

        # 更新天外天排行榜
        yield redis.zadd(SET_CLIMBING_CID_LAYER, self.cid,
                         -self.climbing.max_layer)

        defer.returnValue(
            (status, self.climbing.cur_layer, self.climbing.max_layer,
             climbing_data[0] + self.climbing.buyed_fight, items_return,
             conf['RewardGold'], conf['RewardSoul'], 0,
             self.user.base_att.energy))

    def start_climbing(self, start_layer):
        '''
        @summary: 记录扫荡的开始时间
        '''
        # 塔层数据不同步
        if start_layer != self.climbing.cur_layer:
            log.error(
                'User request start_layer error. cid: {0}, start_layer: {1}, cur_layer: {2}.'
                .format(self.cid, start_layer, self.climbing.cur_layer))
            return REQUEST_LIMIT_ERROR

        if self.climbing.cur_layer > self.climbing.max_layer:
            log.error(
                'Could not climbing. cur_layer: {0}, max_layer: {1}.'.format(
                    self.climbing.cur_layer, self.climbing.max_layer))
            return IN_CLIMBING_MAX_LAYER
        self.climbing.start_datetime = int(time())

        return NO_ERROR

    @defer.inlineCallbacks
    def stop_climbing(self, stop_layer):
        '''
        @summary: 根据结束时间计算可扫荡到的塔层, 奖励进领奖中心。
        '''
        timestamp = int(time())
        total_sceonds = timestamp - self.climbing.start_datetime
        if (not self.climbing.start_datetime) or (total_sceonds <= 0):
            log.error(
                'Unknown error. start climbing time: {0}, cur_layer: {1}, stop_layer: {2}, total_sceonds: {3}.'
                .format(self.climbing.start_datetime, self.climbing.cur_layer,
                        stop_layer, total_sceonds))
            defer.returnValue(IN_CLIMBING_DONE)
        # 重置扫荡的开始时间
        self.climbing.start_datetime = 0

        #log.info('For Test. cur_layer: {0}, stop_layer: {1}, total_sceonds: {2}.'.format( self.climbing.cur_layer, stop_layer, total_sceonds ))
        flag = True
        award_layer = []  # 可获得奖励的塔层列表
        while flag:
            conf = get_climbing_conf(self.climbing.cur_layer)
            if not conf:
                log.error('No conf. tower layer: {0}.'.format(
                    self.climbing.cur_layer))
                defer.returnValue(NOT_FOUND_CONF)

            if total_sceonds < conf['NeedTime']:
                flag = False
            else:
                total_sceonds -= conf['NeedTime']
                # 奖励进领奖中心
                award_layer.append(self.climbing.cur_layer)
                # 判断是否已经到达了conf的最高层
                if self.climbing.cur_layer >= self.MAX_LAYER:
                    flag = False
                    self.climbing.cur_layer = self.MAX_LAYER
                else:
                    if self.climbing.cur_layer >= self.climbing.max_layer:
                        flag = False
                    self.climbing.cur_layer += 1
                # 每日任务计数
                yield self.user.daily_quest_mgr.update_daily_quest(
                    DAILY_QUEST_ID_9, 1)
            #log.info('For Test. cur_layer: {0}, stop_layer: {1}, total_sceonds: {2}, flag: {3}.'.format( self.climbing.cur_layer, stop_layer, total_sceonds, flag ))

        if award_layer:
            yield g_AwardCenterMgr.new_award(self.cid, AWARD_TYPE_CLIMBING,
                                             [timestamp, award_layer])

        defer.returnValue((self.climbing.cur_layer, self.climbing.max_layer))

    @defer.inlineCallbacks
    def finish_climbing(self, start_layer):
        '''
        @summary: 使用钻石购买扫荡到最高塔层的时间, 更新玩家当前所在塔层及最大塔层, 给通关后的奖励
        '''
        if start_layer > self.climbing.max_layer:
            log.error(
                'Could not climbing. cur_layer: {0}, start_layer: {1}, max_layer: {2}.'
                .format(self.climbing.cur_layer, start_layer,
                        self.climbing.max_layer))
            defer.returnValue(IN_CLIMBING_MAX_LAYER)

        award_layer = []  # 可获得奖励的塔层列表
        total_credits = 0  # 需要消耗的钻石
        finish_layer = start_layer  # self.climbing.cur_layer
        while finish_layer <= self.climbing.max_layer:
            conf = get_climbing_conf(finish_layer)
            if not conf:
                log.error('No conf. tower layer: {0}.'.format(finish_layer))
                defer.returnValue(NOT_FOUND_CONF)
            total_credits += conf['NeedTime']
            award_layer.append(finish_layer)
            finish_layer += 1
        if (total_credits % COOLDOWN_TIME_COST):
            total_credits = (total_credits / COOLDOWN_TIME_COST) + 1
        else:
            total_credits = (total_credits / COOLDOWN_TIME_COST)

        if total_credits > self.user.base_att.credits:
            log.error('Credits not enough. need: {0}, cur: {1}.'.format(
                total_credits, self.user.base_att.credits))
            defer.returnValue(CHAR_CREDIT_NOT_ENOUGH)
        # 重置扫荡的开始时间
        self.climbing.start_datetime = 0

        self.climbing.cur_layer = finish_layer
        yield self.user.consume_credits(total_credits, WAY_CLIMBING_DONE)
        if award_layer:
            g_AwardCenterMgr.new_award(self.cid, AWARD_TYPE_CLIMBING,
                                       [int(time()), award_layer])
            # 每日任务计数
            yield self.user.daily_quest_mgr.update_daily_quest(
                DAILY_QUEST_ID_9, len(award_layer))

        defer.returnValue((self.climbing.cur_layer, self.climbing.max_layer,
                           self.user.base_att.credits))

    @defer.inlineCallbacks
    def ranklist(self):
        ''' 获取天外天的排行榜 '''
        yield self.load()
        # get myself rank and layer
        _my_rank = yield redis.zrank(SET_CLIMBING_CID_LAYER, self.cid)
        _my_rank = 0 if _my_rank is None else int(_my_rank) + 1
        _ranklist = [self.climbing.max_layer, _my_rank, []]

        _cid_layers = yield redis.zrange(SET_CLIMBING_CID_LAYER,
                                         0,
                                         9,
                                         withscores=True)
        for _idx, _data in enumerate(_cid_layers):
            #log.error('For Test. _idx: {0}, _cid_layers: {1}.'.format( _idx+1, _data ))
            if int(_data[1]) >= 0:
                continue
            _detail = yield load_climbing_user_data(_data[0])
            if not _detail:
                log.error('Unknown user. cid: {0}.'.format(_data[0]))
                continue
            _detail.extend([-int(_data[1]), _idx + 1])
            _ranklist[2].append(_detail)

        defer.returnValue(_ranklist)
예제 #12
0
class GSActiveSceneMgr(object):
    '''
    ( 'id', 'cid', 'panda_free', 'panda_buyed', 'panda_left_buy', 'treasure_free', 'treasure_buyed', 'treasure_left_buy', 'tree_free', 'tree_buyed', 'tree_left_buy', 'last_datetime' )
    '''
    _table = 'activescene'
    _fields = TABLE_FIELDS['activescene'][0]

    def __init__(self, user):
        self.user = user
        self.cid  = user.cid
        self.load_flag = False

        # 单次战斗中伙伴复活的次数
        self.revive_count = 0
        # 战斗中的活动副本ID
        self.old_activescene_id = 0
        self.activescene = GSAttribute(user.cid, GSActiveSceneMgr._table, user.cid)

    @defer.inlineCallbacks
    def load(self):
        if not self.load_flag:
            try:
                table_data = yield gs_load_table_data(self.cid, GSActiveSceneMgr._table)
                # 注意在收到返回消息后才能赋值
                self.load_flag = True
                #log.info('For Test. table_data: {0}.'.format( table_data ))
                if table_data:
                    table_data = dict(zip(GSActiveSceneMgr._fields, table_data))
                    #log.info('For Test. updateGSAttribute. table_data: {0}.'.format( table_data ))
                    self.activescene.updateGSAttribute( False,  **table_data)
                else:
                    yield self.new()
            except Exception as e:
                log.error( 'Exception raise. e: {0}.'.format( e ))

    def sync_to_cs(self):
        if self.activescene:
            self.activescene.syncToCS()

    @defer.inlineCallbacks
    def new(self):
        now_weekday = datetime.now().isoweekday()

        conf = get_vip_conf( self.user.base_att.vip_level )
        left_buy = conf['ActiveSceneCount'] if conf else 0

        conf = get_activescene_conf( ACTIVE_PANDA_ID )
        panda_free = self.isOpenCycle( conf, now_weekday )

        conf = get_activescene_conf( ACTIVE_TREASURE_ID )
        treasure_free = self.isOpenCycle( conf, now_weekday )

        conf = get_activescene_conf( ACTIVE_TREE_ID )
        tree_free = self.isOpenCycle( conf, now_weekday )

        dt_now = datetime.now()
        init_data = [self.cid, panda_free, 0, left_buy, treasure_free, 0, left_buy, tree_free, 0, left_buy, dt_now]
        kwargs = dict(zip(GSActiveSceneMgr._fields[1:], init_data))
        create_data = yield gs_create_table_data(self.cid, GSActiveSceneMgr._table, **kwargs)
        if create_data:
            create_data = dict(zip(GSActiveSceneMgr._fields, create_data))
            self.activescene.updateGSAttribute( False,  **create_data)
        else: # 新增数据失败
            self.load_flag = False

        defer.returnValue( NO_ERROR )
    
    @property
    def value(self):
        conf  = get_vip_conf( self.user.vip_level )
        total = conf['ActiveSceneCount'] if conf else 0
        panda_left    = total - self.activescene.panda_left_buy if total > self.activescene.panda_left_buy else 0
        treasure_left = total - self.activescene.treasure_left_buy if total > self.activescene.treasure_left_buy else 0
        tree_left     = total - self.activescene.tree_left_buy if total > self.activescene.tree_left_buy else 0
        return ((ACTIVE_PANDA_ID, self.activescene.panda_free+self.activescene.panda_buyed, panda_left), \
                (ACTIVE_TREASURE_ID, self.activescene.treasure_free+self.activescene.treasure_buyed, treasure_left), \
                (ACTIVE_TREE_ID, self.activescene.tree_free+self.activescene.tree_buyed, tree_left))

    @defer.inlineCallbacks
    def system_daily_reset(self):
        '''
        @summary: 每个活动副本有玩家等级限制 和 固定的开启时间: 星期几及时间段
                每天24点系统重置活动副本数据, 含免费挑战次数、剩余可够买的次数、更新时间
        '''
        yield self.load()
        dt_now  = datetime.now()
        dt_last = self.activescene.last_datetime
        if dt_now.date() != dt_last.date():
            now_weekday = dt_now.isoweekday()

            self.activescene.panda_left_buy    = 0
            self.activescene.treasure_left_buy = 0
            self.activescene.tree_left_buy     = 0

            conf = get_activescene_conf( ACTIVE_PANDA_ID )
            self.activescene.panda_free = self.isOpenCycle( conf, now_weekday )

            conf = get_activescene_conf( ACTIVE_TREASURE_ID )
            self.activescene.treasure_free = self.isOpenCycle( conf, now_weekday )

            conf = get_activescene_conf( ACTIVE_TREE_ID )
            self.activescene.tree_free = self.isOpenCycle( conf, now_weekday )

            self.activescene.last_datetime = dt_now

    def isOpenCycle(self, conf, weekday):
        '''
        check OpenCycle return today free count
        '''
        free_num  = 0
        if not conf:
            return free_num

        open_cycle = conf['OpenCycle']
        if open_cycle:
            open_cycle = map( int, open_cycle.split(',') )
            if weekday in open_cycle:
                free_num = conf['CleanNum']
        else:
            free_num = conf['CleanNum']

        return free_num

    @defer.inlineCallbacks
    def activescene_data(self):
        '''
        @summary: 获取精英副本的基本信息
        '''
        yield self.system_daily_reset()
        defer.returnValue( self.value )

    @defer.inlineCallbacks
    def start_battle(self, activescene_id):
        '''
        @summary: 记录玩家的战斗信息
        '''
        conf = get_activescene_conf( activescene_id )
        if not conf:
            log.error('Unknown activescene conf. id: {0}.'.format( activescene_id ))
            defer.returnValue( NOT_FOUND_CONF )

        dt_now  = datetime.now()
        # 检查活动副本是否开启
        if conf['OpenCycle']:
            cycle_list = map(int, conf['OpenCycle'].split(','))
            if dt_now.isoweekday() not in cycle_list:
                log.error('Active not opened. OpenCycle: {0}.'.format( conf['OpenCycle'] ))
                defer.returnValue( ACTIVE_FIGHT_TIME_ERROR )
        if conf['OpenTime']:
            if dt_now.time() < conf['OpenTime'].time():
                log.error('Active not opened. OpenTime: {0}.'.format( conf['OpenTime'] ))
                defer.returnValue( ACTIVE_FIGHT_TIME_ERROR )
        if conf['CloseTime']:
            if dt_now.time() > conf['CloseTime'].time():
                log.error('Active had closed. CloseTime: {0}.'.format( conf['CloseTime'] ))
                defer.returnValue( ACTIVE_FIGHT_TIME_ERROR )
        # 玩家等级限制
        if conf['NeedRoleLevel'] > self.user.base_att.level:
            log.error('User level limit. need: {0}, cur: {1}.'.format( conf['NeedRoleLevel'], self.user.base_att.level ))
            defer.returnValue( CHAR_LEVEL_LIMIT )

        # 每日挑战次数限制
        yield self.system_daily_reset()
        if activescene_id == ACTIVE_PANDA_ID:
            if (self.activescene.panda_free+self.activescene.panda_buyed < 1):
                log.error('No fight count. panda_free: {0}, panda_buyed: {1}.'.format( self.activescene.panda_free, self.activescene.panda_buyed ))
                defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )
        elif activescene_id == ACTIVE_TREASURE_ID:
            if (self.activescene.treasure_free+self.activescene.treasure_buyed < 1):
                log.error('No fight count. treasure_free: {0}, treasure_buyed: {1}.'.format( self.activescene.treasure_free, self.activescene.treasure_buyed ))
                defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )
        elif activescene_id == ACTIVE_TREE_ID:
            if (self.activescene.tree_free+self.activescene.tree_buyed < 1):
                log.error('No fight count. tree_free: {0}, tree_buyed: {1}.'.format( self.activescene.tree_free, self.activescene.tree_buyed ))
                defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )
        else:
            log.error('Unknown activescene_id: {0}.'.format( activescene_id ))
            defer.returnValue( REQUEST_LIMIT_ERROR )

        self.revive_count = 0
        self.old_activescene_id = activescene_id

        defer.returnValue( NO_ERROR )

    @defer.inlineCallbacks
    def dungeon_star_drop(self, dungeon_id, dungeon_star=1):
        '''
        @summary: 精英副本默认难度为1, 无conf则不用计算掉落
        @param  : drop_items-[ [item_type, item_id, item_num], ... ]
        '''
        drop_items=[]

        drop_conf = get_drop_conf( dungeon_id, dungeon_star )
        if not drop_conf:
            log.error('No drop conf. dungeon_id: {0}, dungeon_star: {1}.'.format( dungeon_id, dungeon_star ))
            defer.returnValue( drop_items )

        # old_rate format: {dungeon_star: {drop_id: rate, ...}, ...}
        old_rate  = {}
        data = yield redis.hget( HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid )
        if data:
            old_rate = loads( data )
            if old_rate.has_key( dungeon_star ):
                old_star_rate = old_rate[dungeon_star]
            else:
                old_star_rate = {}
                old_rate[dungeon_star] = old_star_rate
                for _id, _drop in drop_conf.iteritems():
                    old_star_rate[_id] = _drop['RateMax']
        else: # 第一次按照最大概率来计算掉落
            old_star_rate = {}
            old_rate[dungeon_star] = old_star_rate
            for _id, _drop in drop_conf.iteritems():
                old_star_rate[_id] = _drop['RateMax']

        for _drop_id, _drop in drop_conf.iteritems():
            add_rate   = old_star_rate.setdefault(_drop_id, 0)
            _drop_rate = _drop['RateStart'] + add_rate
            # 单次增加的封顶概率
            if _drop_rate > _drop['RateMax']:
                _drop_rate = _drop['RateMax']
            # 掉落概率是万分比
            rand_int = random.randint(0, 10000)
            #log.info('For Test. rand_int: {0}, _drop_rate: {1}, _drop_id: {2}, _drop_num: {3}.'.format( rand_int, _drop_rate, _drop['ItemID'], _drop['ItemNum'] ))
            # _drop['QuestID'] 未处理
            # 当前随机值 不大于 配置的掉落概率值时掉落
            if rand_int <= _drop_rate:
                drop_items = add_new_items( [_drop['ItemType'], _drop['ItemID'], _drop['ItemNum']] , drop_items )

                old_star_rate[_drop_id] = 0
            else:
                old_star_rate[_drop_id] += _drop['RateAdd']
        yield redis.hset( HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid, dumps( old_rate ) )

        defer.returnValue( drop_items )

    @defer.inlineCallbacks
    def get_dungeon_drop(self, drop_items, way_type, way_others=''):
        ''' 获取怪物组战斗胜利后 掉落的道具 '''
        dungeon_drop_items=[]

        for _item_type, _item_id, _item_num in drop_items:
            # 掉落分魂碎片、普通道具
            _model = ITEM_MODELs.get(_item_type, None)
            if not _model:
                log.error('Unknown item type. ItemType: {0}.'.format( _item_type ))
                continue
            res_err, value = yield _model(self.user, ItemID=_item_id, ItemNum=_item_num, AddType=way_type, WayOthers=way_others, CapacityFlag=False)
            if not res_err and value:
                for _v in value:
                    dungeon_drop_items = total_new_items( _v, dungeon_drop_items )

        defer.returnValue( dungeon_drop_items )

    @defer.inlineCallbacks
    def get_battle_reward(self, battle_type, status, activescene_id):
        '''
        @param : battle_type-3:经验熊猫; 4:经验宝物; 5:打土豪
            当type=5时, status值为对土豪的有效伤害值
        @param : 战斗结果 status 0:fail, 1:success
        '''
        if activescene_id != self.old_activescene_id:
            log.error('Battle data error. old_activescene_id: {0}, activescene_id: {1}.'.format( self.old_activescene_id, activescene_id ))
            #defer.returnValue( REQUEST_LIMIT_ERROR )

        # 每日挑战次数限制
        yield self.system_daily_reset()

        self.revive_count       = 0
        self.old_activescene_id = 0

        # 战斗失败
        if not status:
            if battle_type == FIGHT_TYPE_PANDA:
                fight_count = self.activescene.panda_free + self.activescene.panda_buyed
                defer.returnValue( (battle_type, status, 0, 0, fight_count, [], 0, 0, 0, self.user.base_att.energy) )
            elif battle_type == FIGHT_TYPE_TREASURE:
                fight_count = self.activescene.treasure_free + self.activescene.treasure_buyed
                defer.returnValue( (battle_type, status, 0, 0, fight_count, [], 0, 0, 0, self.user.base_att.energy) )
            elif battle_type == FIGHT_TYPE_TREE:
                pass
            else:
                log.error('Unknown battle_type: {0}.'.format( battle_type ))
                defer.returnValue( REQUEST_LIMIT_ERROR )

        golds_reward = 0
        activescene_drop_items = []
        # 扣挑战次数
        if battle_type == FIGHT_TYPE_PANDA:
            if self.activescene.panda_buyed > 0:
                self.activescene.panda_buyed -= 1
            elif self.activescene.panda_free > 0:
                self.activescene.panda_free -= 1
            else:
                log.error('No fight count. panda_free: {0}, panda_buyed: {1}.'.format( self.activescene.panda_free, self.activescene.panda_buyed ))
                defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )
            fight_count = self.activescene.panda_free + self.activescene.panda_buyed
            # 获取怪物组掉落, star默认为1
            drop_items = yield self.dungeon_star_drop( activescene_id, 1 )
            # 新增掉落
            way_others = str((FIGHT_TYPE_PANDA, activescene_id, 1))
            activescene_drop_items = yield self.get_dungeon_drop( drop_items, WAY_ACTIVESCENE_PANDA_FIGHT, way_others )

        elif battle_type == FIGHT_TYPE_TREASURE:
            if self.activescene.treasure_buyed > 0:
                self.activescene.treasure_buyed -= 1
            elif self.activescene.treasure_free > 0:
                self.activescene.treasure_free -= 1
            else:
                log.error('No fight count. treasure_free: {0}, treasure_buyed: {1}.'.format( self.activescene.treasure_free, self.activescene.treasure_buyed ))
                defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )
            fight_count = self.activescene.treasure_free + self.activescene.treasure_buyed
            # 获取怪物组掉落, star默认为1
            drop_items = yield self.dungeon_star_drop( activescene_id, 1 )
            # 新增掉落
            way_others = str((FIGHT_TYPE_TREASURE, activescene_id, 1))
            activescene_drop_items = yield self.get_dungeon_drop( drop_items, WAY_ACTIVESCENE_TREASURE_FIGHT, way_others )

        elif battle_type == FIGHT_TYPE_TREE:
            if self.activescene.tree_buyed > 0:
                self.activescene.tree_buyed -= 1
            elif self.activescene.tree_free > 0:
                self.activescene.tree_free -= 1
            else:
                log.error('No fight count. tree_free: {0}, tree_buyed: {1}.'.format( self.activescene.tree_free, self.activescene.tree_buyed ))
                defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )
            fight_count = self.activescene.tree_free + self.activescene.tree_buyed
            # 计算金币
            golds_reward = int((status+9) / 10)
            gold_tree_conf = get_gold_tree_conf()
            for _d, _g in gold_tree_conf:
                if status < _d:
                    break
                golds_reward += _g
            self.user.get_golds( golds_reward, WAY_ACTIVESCENE_TREE_FIGHT )
        else:
            log.error('Unknown battle_type: {0}.'.format( battle_type ))
            defer.returnValue( REQUEST_LIMIT_ERROR )

        # 每日任务计数
        yield self.user.daily_quest_mgr.update_daily_quest( DAILY_QUEST_ID_4, 1 )
        # add syslog
        str_drop_items = str(activescene_drop_items).replace('[', '(')
        str_drop_items = str_drop_items.replace(']', ')')
        syslogger(LOG_SCENE_BATTLE, self.cid, self.user.level, self.user.vip_level, self.user.alliance_id, battle_type, status, activescene_id, 1, 0, 0, golds_reward, str_drop_items)

        defer.returnValue( (battle_type, status, 0, 0, fight_count, activescene_drop_items, golds_reward, 0, 0, self.user.base_att.energy) )

    @defer.inlineCallbacks
    def buy_count(self, battle_type):
        '''
        @summary: 购买挑战次数,价格=基础价格*购买次数
        '''
        vip_conf = get_vip_conf( self.user.base_att.vip_level )
        if not vip_conf:
            log.error('No vip conf. vip_level: {0}.'.format( self.user.base_att.vip_level ))
            defer.returnValue( NOT_FOUND_CONF )
        yield self.system_daily_reset()
        if battle_type == FIGHT_TYPE_PANDA:
            # 还有剩余挑战次数
            if (self.activescene.panda_free+self.activescene.panda_buyed > 0):
                log.error('User has fight count. panda_free: {0}, panda_buyed: {1}.'.format( self.activescene.panda_free, self.activescene.panda_buyed ))
                defer.returnValue( HAVE_NUM_TO_USE )
            # 已购买次数达上限
            if self.activescene.panda_left_buy >= vip_conf['ActiveSceneCount']:
                log.error('No panda fight count could buy today. cid:{0}, vip_level:{1}.'.format( self.cid, self.user.vip_level ))
                defer.returnValue( BUY_MAX_NUM_ERROR )
            # 钻石不足
            conf = get_activescene_conf( ACTIVE_PANDA_ID )
            if not conf:
                log.error('Can not find conf. activescene_id: {0}.'.format( ACTIVE_PANDA_ID ))
                defer.returnValue( NOT_FOUND_CONF )
            need_credits = (self.activescene.panda_left_buy + 1) * conf['Price']
            if self.user.base_att.credits < need_credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format( need_credits, self.user.base_att.credits ))
                defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
            yield self.user.consume_credits(need_credits, WAY_ACTIVESCENE_PANDA_FIGHT)
            self.activescene.panda_left_buy += 1
            self.activescene.panda_buyed    += 1

            defer.returnValue( ((self.activescene.panda_free + self.activescene.panda_buyed), self.activescene.panda_left_buy, self.user.base_att.credits) )
        elif battle_type == FIGHT_TYPE_TREASURE:
            # 还剩余有挑战次数
            if (self.activescene.treasure_free+self.activescene.treasure_buyed > 0):
                log.error('User has fight count. treasure_free: {0}, treasure_buyed: {1}.'.format( self.activescene.treasure_free, self.activescene.treasure_buyed ))
                defer.returnValue( HAVE_NUM_TO_USE )
            # 剩余购买次数不足
            if self.activescene.treasure_left_buy >= vip_conf['ActiveSceneCount']:
                log.error('No treasure fight count could buy today. cid:{0}, vip_level:{1}.'.format( self.cid, self.user.vip_level ))
                defer.returnValue( BUY_MAX_NUM_ERROR )
            # 钻石不足
            conf = get_activescene_conf( ACTIVE_TREASURE_ID )
            if not conf:
                log.error('No conf. activescene_id: {0}.'.format( ACTIVE_TREASURE_ID ))
                defer.returnValue( NOT_FOUND_CONF )
            need_credits = (self.activescene.treasure_left_buy + 1) * conf['Price']
            if self.user.base_att.credits < need_credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format( need_credits, self.user.base_att.credits ))
                defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
            yield self.user.consume_credits(need_credits, WAY_ACTIVESCENE_TREASURE_FIGHT)
            self.activescene.treasure_left_buy += 1
            self.activescene.treasure_buyed    += 1

            defer.returnValue( ((self.activescene.treasure_free + self.activescene.treasure_buyed), self.activescene.treasure_left_buy, self.user.base_att.credits) )
        elif battle_type == FIGHT_TYPE_TREE:
            # 还剩余有挑战次数
            if (self.activescene.tree_free+self.activescene.tree_buyed > 0):
                log.error('User has fight count. tree_free: {0}, tree_buyed: {1}.'.format( self.activescene.tree_free, self.activescene.tree_buyed ))
                defer.returnValue( HAVE_NUM_TO_USE )
            # 剩余购买次数不足
            if self.activescene.tree_left_buy >= vip_conf['ActiveSceneCount']:
                log.error('No tree fight count could buy today. cid:{0}, vip_level:{1}.'.format( self.cid, self.user.vip_level ))
                defer.returnValue( BUY_MAX_NUM_ERROR )
            # 钻石不足
            conf = get_activescene_conf( ACTIVE_TREE_ID )
            if not conf:
                log.error('No conf. activescene_id: {0}.'.format( ACTIVE_TREE_ID ))
                defer.returnValue( NOT_FOUND_CONF )
            need_credits = (self.activescene.tree_left_buy + 1) * conf['Price']
            if self.user.base_att.credits < need_credits:
                log.error('Credits not enough. need: {0}, cur: {1}.'.format( need_credits, self.user.base_att.credits ))
                defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
            yield self.user.consume_credits(need_credits, WAY_ACTIVESCENE_TREE_FIGHT)
            self.activescene.tree_left_buy += 1
            self.activescene.tree_buyed    += 1

            defer.returnValue( ((self.activescene.tree_free + self.activescene.tree_buyed), self.activescene.tree_left_buy, self.user.base_att.credits) )
        else:
            log.error('Unknown battle_type: {0}.'.format( battle_type ))
            defer.returnValue( REQUEST_LIMIT_ERROR )

    def battle_revive(self, battle_type):
        '''
        @summary: 复活初始价格为200金币, 价格=复活次数*初始价格
             同一场战斗中不同波数复活次数要累计 
        '''
        need_golds = (self.revive_count + 1)*REVIVE_BASIC_GOLDS
        if (self.user.base_att.golds < need_golds):
            log.error('Golds not enough. need: {0}, cur: {1}.'.format( need_golds, self.user.base_att.golds ))
            return CHAR_GOLD_NOT_ENOUGH

        self.user.base_att.golds -= need_golds
        self.revive_count += 1

        return [self.user.base_att.golds]
예제 #13
0
class GSAtlaslistMgr(object):
    _table = 'atlaslist'
    _fields = TABLE_FIELDS['atlaslist'][0]

    def __init__(self, user):
        self.user = user
        self.cid  = user.cid

        self.atlaslist = GSAttribute(user.cid, GSAtlaslistMgr._table, user.cid)

        self.load_flag = False

        self.fellow_ids   = None
        self.equip_ids    = None
        self.treasure_ids = None

    @defer.inlineCallbacks
    def load(self):
        if self.load_flag:
            defer.returnValue( None )

        try:
            table_data = yield gs_load_table_data(self.cid, GSAtlaslistMgr._table)
            # 注意在收到返回消息后才能赋值
            self.load_flag = True
            if table_data:
                table_data = dict(zip(GSAtlaslistMgr._fields, table_data))
                self.atlaslist.updateGSAttribute( False, **table_data )
                self.fellow_ids   = loads(self.atlaslist.fellow_ids)
                self.equip_ids    = loads(self.atlaslist.equip_ids)
                self.treasure_ids = loads(self.atlaslist.treasure_ids)
            else:
                yield self.new()
        except Exception as e:
            log.error( 'Exception raise. e: {0}.'.format( e ))

    @defer.inlineCallbacks
    def new(self):
        self.fellow_ids, self.equip_ids, self.treasure_ids = [], [], []
        # 检查伙伴列表、宝物背包列表、装备背包列表

        init_data = [self.cid, dumps(self.fellow_ids), dumps(self.equip_ids), dumps(self.treasure_ids)]
        kwargs = dict(zip(GSAtlaslistMgr._fields[1:], init_data))
        create_data = yield gs_create_table_data(self.cid, GSAtlaslistMgr._table, **kwargs)
        if create_data:
            create_data = dict(zip(GSAtlaslistMgr._fields, create_data))
            self.atlaslist.updateGSAttribute( False, **create_data )
        else: # 新增数据失败
            self.load_flag = False
 
    @defer.inlineCallbacks
    def atlaslist_info(self, category_id, second_type):
        yield self.load()
        _category_conf = get_atlaslist_category_conf( category_id )
        _second_conf   = _category_conf.get(second_type, {})
        if not _second_conf:
            defer.returnValue( NOT_FOUND_CONF )

        if category_id == CATEGORY_TYPE_FELLOW:
            _had_get_ids = self.fellow_ids
        elif category_id == CATEGORY_TYPE_EQUIP:
            _had_get_ids = self.equip_ids
        elif category_id == CATEGORY_TYPE_TREASURE:
            _had_get_ids = self.treasure_ids
        else:
            defer.returnValue( CLIENT_DATA_ERROR )

        _second_count = 0
        _quality_data = []
        for _quality, _quality_conf in _second_conf.iteritems():
            _item_ids = []
            _quality_count = 0
            for _item in _quality_conf['Items']:
                if _item['ItemID'] in _had_get_ids:
                    _quality_count += 1
                    _item_ids.append( _item['ItemID'] )
            _second_count += _quality_count
            # 星级收齐的奖励
            if _quality_count >= len(_quality_conf['Items']):
                _award_status = 1
                _award_data = yield redis.hget(HASH_ATLASLIST_AWARD, self.cid)
                if _award_data:
                    _award_data = loads(_award_data)
                    if (category_id, second_type, _quality) in _award_data:
                        _award_status = 2
            else:
                _award_status = 0
            _quality_data.append( (_quality, _item_ids, _quality_count, _award_status) )

        _f_count, _e_count, _t_count = len(self.fellow_ids), len(self.equip_ids), len(self.treasure_ids)

        defer.returnValue( (_f_count, _e_count, _t_count, category_id, second_type, _second_count, _quality_data) )

    @defer.inlineCallbacks
    def new_atlaslist(self, category_id, second_type, quality, item_id):
        yield self.load()
        _category_conf = get_atlaslist_category_conf(category_id)
        _second_conf   = _category_conf.get(second_type, {})
        _quality_conf  = _second_conf.get(quality, {})
        if not _quality_conf:
            defer.returnValue( None )

        for _item in _quality_conf['Items']:
            if _item['ItemID'] == item_id:
                break
        else:
            defer.returnValue( None )

        if category_id == CATEGORY_TYPE_FELLOW:
            if item_id not in self.fellow_ids:
                self.fellow_ids.append( item_id )
                self.atlaslist.fellow_ids = dumps( self.fellow_ids )
        elif category_id == CATEGORY_TYPE_EQUIP:
            if item_id not in self.equip_ids:
                self.equip_ids.append( item_id )
                self.atlaslist.equip_ids = dumps( self.equip_ids )
        elif category_id == CATEGORY_TYPE_TREASURE:
            if item_id not in self.treasure_ids:
                self.treasure_ids.append( item_id )
                self.atlaslist.treasure_ids = dumps( self.treasure_ids )

        defer.returnValue( None )

    @defer.inlineCallbacks
    def atlaslist_award(self, category_id, second_type, quality):
        _award_data = yield redis.hget(HASH_ATLASLIST_AWARD, self.cid)
        if _award_data:
            _award_data = loads(_award_data)
        else:
            _award_data = []

        _new_award = (category_id, second_type, quality)
        if _new_award in _award_data:
            defer.returnValue( ATLASLIST_AWARD_HAD_ERROR )

        _category_conf = get_atlaslist_category_conf(category_id)
        _second_conf   = _category_conf.get(second_type, {})
        _quality_conf  = _second_conf.get(quality, {})
        if not _quality_conf or not _quality_conf['Awardlist']:
            defer.returnValue( NOT_FOUND_CONF )
 
        _award_data.append( _new_award )
        yield redis.hset(HASH_ATLASLIST_AWARD, self.cid, dumps( _award_data ))
        items_return = []
        for _type, _id, _num in _quality_conf['Awardlist']:
            model = ITEM_MODELs.get( _type, None )
            if not model:
                log.error('Unknown item type. cid: {0}, item_type: {1}, item_id: {2}, item_num: {3}.'.format( self.cid, _type, _id, _num ))
                continue
            res_err, value = yield model(self.user, ItemID=_id, ItemNum=_num, AddType=WAY_ATLASLIST_AWARD, CapacityFlag=False)
            if not res_err and value:
                for _v in value:
                    items_return = total_new_items( _v, items_return )

        defer.returnValue( items_return )
예제 #14
0
class GSEliteSceneMgr(object):
    _table = 'elitescene'
    _fields = TABLE_FIELDS['elitescene'][0]

    def __init__(self, user):
        self.user = user
        self.cid  = user.cid
        self.load_flag = False

        # 单次战斗中伙伴复活的次数
        self.revive_count = 0
        # 战斗中的精英副本ID
        self.old_elitescene_id = 0
        self.elitescene = GSAttribute(user.cid, GSEliteSceneMgr._table, user.cid)
        # 已战斗胜利的精英副本ID列表
        self.passed_elitescene_ids = []

    @defer.inlineCallbacks
    def load(self):
        if not self.load_flag:
            try:
                table_data = yield gs_load_table_data(self.cid, GSEliteSceneMgr._table)
                # 注意在收到返回消息后才能赋值
                self.load_flag = True

                if table_data:
                    table_data = dict(zip(GSEliteSceneMgr._fields, table_data))
                    self.elitescene.updateGSAttribute( False,  **table_data)
                else:
                    yield self.new()
                _data = yield redis.hget(HASH_ELITESCENE_PASSED, self.cid)
                if _data:
                    self.passed_elitescene_ids = loads(_data)
            except Exception as e:
                log.error( 'Exception raise. e: {0}.'.format( e ))

    def sync_to_cs(self):
        if self.elitescene:
            self.elitescene.syncToCS()

    @defer.inlineCallbacks
    def new(self):
        dt_now = datetime.now()
        kwargs = dict(zip(GSEliteSceneMgr._fields[1:], [self.cid, ELITESCENE_FIGHT_COUNT, 0, 0, dt_now]))#datetime2string(dt_now)]))
        create_data = yield gs_create_table_data(self.cid, GSEliteSceneMgr._table, **kwargs)
        if create_data:
            create_data = dict(zip(GSEliteSceneMgr._fields, create_data))
            self.elitescene.updateGSAttribute( False,  **create_data)
        else: # 新增数据失败
            self.load_flag = False

        defer.returnValue( NO_ERROR )

    def system_daily_reset(self):
        '''
        @summary: 每天24点系统重置精英副本数据, 含免费挑战次数、剩余可够买的次数、更新时间
        '''
        dt_now  = datetime.now()
        dt_last = self.elitescene.last_datetime
        if dt_now.date() != dt_last.date():
            self.elitescene.left_buy_fight = 0
            self.elitescene.free_fight    = ELITESCENE_FIGHT_COUNT
            self.elitescene.last_datetime = dt_now

    @defer.inlineCallbacks
    def elitescene_data(self):
        '''
        @summary: 获取精英副本的基本信息
        '''
        yield self.load()
        self.system_daily_reset()
        conf = get_vip_conf( self.user.vip_level )
        left_buy_fight = conf['EliteSceneCount'] if conf else 0
        left_buy_fight = left_buy_fight - self.elitescene.left_buy_fight if left_buy_fight > self.elitescene.left_buy_fight else 0

        defer.returnValue( (self.elitescene.free_fight + self.elitescene.buyed_fight, left_buy_fight, self.passed_elitescene_ids) )

    @defer.inlineCallbacks
    def start_battle(self, elitescene_id):
        '''
        @summary: 记录玩家的战斗信息
        '''
        # 检查战斗条件是否满足
        errorno = yield self.check_battle_limit( elitescene_id )
        defer.returnValue( errorno )

    @defer.inlineCallbacks
    def check_battle_limit(self, elitescene_id):
        ''' 检查战斗的条件是否满足 '''
        conf = get_elitescene_conf( elitescene_id )
        if not conf:
            log.error('Unknown elitescene conf. id: {0}.'.format( elitescene_id ))
            defer.returnValue( NOT_FOUND_CONF )
        # 检查精英副本是否开启
        _scene_passed = yield self.user.scene_mgr.check_scene_passed( conf['SceneID'] )
        if 0 == _scene_passed:
            log.error('Scene need passed. cid: {0}, scene_id: {1}, elitescene_id: {2}.'.format( self.cid, conf['SceneID'], elitescene_id ))
            defer.returnValue( SCENE_NEED_PASSED )
        # 检查精英副本的前置副本是否已通关
        if conf['PrepEliteSceneID'] and conf['PrepEliteSceneID'] not in self.passed_elitescene_ids:
            log.error('PrepEliteSceneID<{0}> need win. cid: {1}.'.format( conf['PrepEliteSceneID'], self.cid ))
            defer.returnValue( PREP_ELITESCENE_NEED_WIN )
        # 检查玩家的等级限制
        if conf['NeedRoleLevel'] > self.user.base_att.level:
            log.error('User level limit. cid: {0}, need: {1}, cur: {2}.'.format( self.cid, conf['NeedRoleLevel'], self.user.base_att.level ))
            defer.returnValue( CHAR_LEVEL_LIMIT )

        self.system_daily_reset()
        # 每日挑战次数限制
        if (self.elitescene.free_fight + self.elitescene.buyed_fight < 1):
            log.error('No fight count. cid: {0}, free_fight: {1}, buyed_fight: {2}.'.format( self.cid, self.elitescene.free_fight, self.elitescene.buyed_fight ))
            defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )

        self.revive_count = 0
        self.old_elitescene_id = elitescene_id

        defer.returnValue( NO_ERROR )
 
    @defer.inlineCallbacks
    def dungeon_star_drop(self, dungeon_id, dungeon_star=1):
        '''
        @summary: 精英副本默认难度为1, 无conf则不用计算掉落
        @param  : drop_items-[ [item_type, item_id, item_num], ... ]
        '''
        drop_items=[]

        drop_conf = get_drop_conf( dungeon_id, dungeon_star )
        if not drop_conf:
            log.error('No drop conf. dungeon_id: {0}, dungeon_star: {1}.'.format( dungeon_id, dungeon_star ))
            defer.returnValue( drop_items )

        # old_rate format: {dungeon_star: {drop_id: rate, ...}, ...}
        old_rate  = {}
        data = yield redis.hget( HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid )
        if data:
            old_rate = loads( data )
            if old_rate.has_key( dungeon_star ):
                old_star_rate = old_rate[dungeon_star]
            else:
                old_star_rate = {}
                old_rate[dungeon_star] = old_star_rate
                for _id, _drop in drop_conf.iteritems():
                    old_star_rate[_id] = _drop['RateMax']
        else: # 第一次按照最大概率来计算掉落
            old_star_rate = {}
            old_rate[dungeon_star] = old_star_rate
            for _id, _drop in drop_conf.iteritems():
                old_star_rate[_id] = _drop['RateMax']

        for _drop_id, _drop in drop_conf.iteritems():
            add_rate   = old_star_rate.get(_drop_id, 0)
            _drop_rate = _drop['RateStart'] + add_rate
            # 单次增加的封顶概率
            if _drop_rate > _drop['RateMax']:
                _drop_rate = _drop['RateMax']
            # 掉落概率是万分比
            rand_int = random.randint(0, 10000)
            # _drop['QuestID'] 未处理
            # 当前随机值 不大于 配置的掉落概率值时掉落
            if rand_int <= _drop_rate:
                drop_items = add_new_items( [_drop['ItemType'], _drop['ItemID'], _drop['ItemNum']] , drop_items )

                old_star_rate[_drop_id] = 0
            else:
                old_star_rate[_drop_id] = old_star_rate.setdefault(_drop_id, 0) + _drop['RateAdd']
        yield redis.hset( HASH_DUNGEON_DROP_RATE % dungeon_id, self.cid, dumps( old_rate ) )

        defer.returnValue( drop_items )

    @defer.inlineCallbacks
    def get_dungeon_drop(self, drop_items, way_others=''):
        ''' 获取怪物组战斗胜利后 掉落的道具 '''
        dungeon_drop_items=[]

        for _item_type, _item_id, _item_num in drop_items:
            # 掉落分魂碎片、普通道具
            _model = ITEM_MODELs.get(_item_type, None)
            if not _model:
                log.error('Unknown item type. ItemType: {0}.'.format( _item_type ))
                continue
            res_err, value = yield _model(self.user, ItemID=_item_id, ItemNum=_item_num, AddType=WAY_ELITESCENE_DROP, WayOthers=way_others, CapacityFlag=False)
            if not res_err and value:
                for _v in value:
                    dungeon_drop_items = total_new_items( _v, dungeon_drop_items )

        defer.returnValue( dungeon_drop_items )

    @defer.inlineCallbacks
    def get_battle_reward(self, status, elitescene_id):
        '''
        @param  : 战斗结果 status 0:fail, 1:success
        '''
        self.revive_count      = 0
        self.old_elitescene_id = 0
        ## 检查战斗条件是否满足
        #errorno = yield self.check_battle_limit( elitescene_id )
        #if errorno:
        #    defer.returnValue( errorno )
        # 战斗失败
        if not status:
            defer.returnValue( (2, status, 0, 0, self.elitescene.free_fight + self.elitescene.buyed_fight, [], 0, 0, 0, self.user.base_att.energy) )
        # 精英副本奖励金币、仙魂
        golds_reward, soul_reward = 0, 0
        # config
        conf = get_elitescene_conf( elitescene_id )
        if conf:
            golds_reward, soul_reward = conf['Gold'], conf['Soul']
        # 扣挑战次数
        if self.elitescene.buyed_fight > 0:
            self.elitescene.buyed_fight -= 1
        elif self.elitescene.free_fight > 0:
            self.elitescene.free_fight -= 1
        else:
            log.error('No fight count. free_fight: {0}, buyed_fight: {1}.'.format( self.elitescene.free_fight, self.elitescene.buyed_fight ))
            defer.returnValue( SCENE_CHALLENGE_COUNT_LIMIT )

        # 获取怪物组掉落, star默认为1
        drop_items = yield self.dungeon_star_drop( elitescene_id, 1 )
        # 新增掉落
        way_others = str((FIGHT_TYPE_ELITE, elitescene_id, 1))
        elitescene_drop_items = yield self.get_dungeon_drop( drop_items, way_others )
        # 发放奖励
        if golds_reward > 0:
            #self.user.base_att.golds += golds_reward
            self.user.get_golds( golds_reward, WAY_ELITESCENE_BATTLE )
        if soul_reward > 0:
            self.user.base_att.soul  += soul_reward

        # 更新已胜利的精英副本ID列表
        if elitescene_id not in self.passed_elitescene_ids:
            self.passed_elitescene_ids.append( elitescene_id )
            yield redis.hset( HASH_ELITESCENE_PASSED, self.cid, dumps(self.passed_elitescene_ids) )
        # 每日任务计数
        yield self.user.daily_quest_mgr.update_daily_quest( DAILY_QUEST_ID_2, 1 )
        # 开服七天
        self.passed_elitescene_ids.sort()
        yield self.user.open_server_mgr.update_open_server_activity_quest( OPEN_SERVER_QUEST_ID_12, self.passed_elitescene_ids[-1])
        # add syslog
        #成就
        yield self.user.achievement_mgr.update_achievement_status(ACHIEVEMENT_QUEST_ID_12, self.passed_elitescene_ids[-1])
        str_drop_items = str(elitescene_drop_items).replace('[', '(')
        str_drop_items = str_drop_items.replace(']', ')')
        syslogger(LOG_SCENE_BATTLE, self.cid, self.user.level, self.user.vip_level, self.user.alliance_id, FIGHT_TYPE_ELITE, status, elitescene_id, 1, 0, soul_reward, golds_reward, str_drop_items)

        defer.returnValue( (2, status, 0, 0, self.elitescene.free_fight + self.elitescene.buyed_fight, elitescene_drop_items, golds_reward, soul_reward, 0, self.user.base_att.energy) )

    @defer.inlineCallbacks
    def buy_count(self):
        '''
        @summary: 购买挑战次数
               每购买1次额外挑战次数,需要花费10钻石
        '''
        if self.user.base_att.credits < 10:
            log.error('Credits not enough. need: 10, cur: {0}.'.format( self.user.base_att.credits ))
            defer.returnValue( CHAR_CREDIT_NOT_ENOUGH )
        # 还剩余有挑战次数
        if (self.elitescene.free_fight + self.elitescene.buyed_fight > 0):
            log.error('User has more than 1 fight count. free_fight: {0}, buyed_fight: {1}.'.format( self.elitescene.free_fight, self.elitescene.buyed_fight ))
            defer.returnValue( HAVE_NUM_TO_USE )
        # 判断VIP等级对应的可购买次数限制
        self.system_daily_reset()

        conf = get_vip_conf( self.user.vip_level )
        left_buy_fight = conf['EliteSceneCount'] if conf else 0
        left_buy_fight = left_buy_fight - self.elitescene.left_buy_fight if left_buy_fight > self.elitescene.left_buy_fight else 0
        if left_buy_fight < 1:
            log.error('No fight count could buy today.')
            defer.returnValue( BUY_MAX_NUM_ERROR )
        left_buy_fight -= 1
 
        yield self.user.consume_credits(10, WAY_ELITESCENE_FIGHT)
        self.elitescene.left_buy_fight += 1
        self.elitescene.buyed_fight += 1

        defer.returnValue( ((self.elitescene.free_fight + self.elitescene.buyed_fight), left_buy_fight, self.user.base_att.credits) )


    def battle_revive(self):
        '''
        @summary: 复活初始价格为200金币, 价格=复活次数*初始价格
             同一场战斗中不同波数复活次数要累计 
        '''
        need_golds = (self.revive_count + 1)*REVIVE_BASIC_GOLDS
        #log.info('For Test. revive_count: {0}, need_golds: {1}, cur_golds: {2}.'.format( self.revive_count, need_golds, self.user.base_att.golds ))
        if (self.user.base_att.golds < need_golds):
            log.error('Golds not enough. need: {0}, cur: {1}.'.format( need_golds, self.user.base_att.golds ))
            return CHAR_GOLD_NOT_ENOUGH

        #self.user.base_att.golds -= need_golds
        self.user.consume_golds( need_golds, WAY_ELITESCENE_REVIVE )
        self.revive_count += 1

        return [self.user.base_att.golds]