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) ))
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)))
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)
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)
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)
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]
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 )
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)
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)
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]
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)
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]
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 )
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]