class PlayerRoles(object): """ 玩家配将管理类 """ ROLE_INIT_CMDS = { QUALITY_GREEN: (GREEN_ROLE_INIT_CMD, GREEN_ROLE_INIT_CMD_V), } def __init__(self, player): if 0: from game.player.player import Player self.player = Player() self.player = player self.roles = {} self.rid2roles = {} self.main_role = None #保存武将随机培养值 {rid:attr} self.train_rand_data = None self.cls_init() setting_data = {} _sub_reloaded = False @classmethod def cls_init(cls): if cls._sub_reloaded: return cls._sub_reloaded = True Game.setting_mgr.sub(MSG_RES_RELOAD, cls.handle_setting) cls.handle_setting() @classmethod def handle_setting(cls): """ 处理修改资源表 """ cls.setting_data = {} res_cost = Game.setting_mgr.setdefault(ROLEUP_COST_ITEM, ROLEUP_COST_ITEM_V) cls.setting_data[ROLEUP_COST_ITEM] = common.str2list(res_cost) #银币培养 res_coin1 = Game.setting_mgr.setdefault(ROLETRAIN_COIN1, ROLETRAIN_COIN1_V) cls.setting_data[ROLETRAIN_COIN1] = common.str2dict2(res_coin1) #元宝培养 res_coin2 = Game.setting_mgr.setdefault(ROLETRAIN_COIN2, ROLETRAIN_COIN2_V) cls.setting_data[ROLETRAIN_COIN2] = common.str2dict2(res_coin2) res_locklevel = Game.setting_mgr.setdefault(ROLETRAIN_LOCKLEVEL, ROLETRAIN_LOCKLEVEL_V) cls.setting_data[ROLETRAIN_LOCKLEVEL] = res_locklevel def uninit(self): self.player = None self.roles = {} self.rid2roles = {} self.main_role = None self.train_rand_data = None self.setting_data = {} def gm_add_num(self, num): """ gm改变升段次数 """ for role in self.roles.itervalues(): role.data.n = num role.modify() def load(self, querys=None): if querys is None: querys = dict(pid=self.player.data.id) roles = self.player._game.rpc_store.query_loads(TN_P_ROLE, querys) pass_day = self.player.play_attr.pass_day(FN_P_ATTR_KEY_ROLEUP) for r in roles: role = PlayerRole(self, adict=r) role.handle_roleup_data() if pass_day: role.pass_day() if role.is_main: self.main_role = role self.roles[role.data.id] = role self.rid2roles[role.data.rid] = role def load_used(self): querys = dict(pid=self.player.data.id) querys['status'] = STATUS_COME self.load(querys=querys) def save(self): store = self.player._game.rpc_store for r in self.roles.itervalues(): r.save(store) def clear(self, clear_main=0): store = self.player._game.rpc_store for r in self.roles.itervalues(): if not clear_main and r.is_main: continue r.delete(store) self.roles.clear() self.rid2roles.clear() if not clear_main and self.main_role: self.roles[self.main_role.data.id] = self.main_role self.rid2roles[self.main_role.data.rid] = self.main_role else: self.main_role = None def clear_attr(self): """ 清楚角色佩戴的命格和装备属性 """ for role in self.roles.itervalues(): for key, eid in role.iter_equips(): if not eid: continue setattr(role.data, key, 0) role.modify() for key, fid in role.iter_fates(): if not fid: continue setattr(role.data, key, 0) role.modify() def copy_from(self, roles, bag_items): """ 复制roles前,bag必须先复制好 """ self.clear(clear_main=1) for r in roles.roles.itervalues(): nr = PlayerRole(self, adict=r.data.to_dict()) nr.data.id = None nr.data.pid = self.player.data.id nr.update_items(bag_items) nr.save(self.player._game.rpc_store) self.load() def __contains__(self, item): return item.data.id in self.roles def to_dict(self, used=0): if not used: return [r.to_dict() for r in self.roles.itervalues()] return [r.to_dict() for r in self.iter_come_back_roles()] def roles_to_dict(self, rids): data = [] for r in self.roles.itervalues(): if r.data.rid in rids: data.append(r.to_dict()) return data def roles_bag_to_dict(self, rids): data = dict(equip = [], fate = [], gem = []) for rid in rids: role = self.get_role_by_rid(rid) if role is None: continue for key, fid in role.iter_fates(): if not fid: continue fate = self.player.bag.get_fate(fid) if fate is None: continue data['fate'].append(fate.to_dict()) for key, eid in role.iter_equips(): if not eid: continue equip = self.player.bag.get_equip(eid) if equip is None: continue data['equip'].append(equip.to_dict()) for gid in equip.data.gem.itervalues(): gem = self.player.bag.get_gem(gid) if gem is None: continue data['gem'].append(gem.to_dict()) return data def get_role(self, id): return self.roles.get(id) def iter_roles(self): return self.roles.itervalues() def get_role_by_rid(self, rid): return self.rid2roles.get(rid) def iter_fight_roles(self): """ 根据阵型,遍历角色 """ pos = self.player.positions.get_active() if not pos: return for p, rid in pos.iter_rids(): r = self.get_role_by_rid(rid) if not r or not r.is_come_back: continue yield r # def join_roles(self): # """ 获取参战角色人数 """ # pos = self.player.positions.get_active() # if not pos: # return 1 # num = 0 # for p, rid in pos.iter_rids(): # if not rid: # continue # num += 1 # return num def iter_come_back_roles(self): """ 遍历归队的角色 """ for r in self.roles.itervalues(): if not r.is_come_back: continue yield r def get_role_by_rid(self, rid): return self.rid2roles.get(rid) @property def come_back_count(self): """ 归队人数 """ return len([r for r in self.roles.itervalues() if r.is_come_back]) def can_come_back(self): """ 是否可以执行配将归队 """ return self.come_back_count < Game.setting_mgr.setdefault(ROLE_BACK_MAX, ROLE_BACK_MAX_V) def update_role(self, aRole): """ 角色更新 """ aRole.modify() def del_role(self, rid, send_msg=0): """ 删除角色 """ role = self.rid2roles.get(rid) if role is None: return 0, None if self.main_role == role: self.main_role = None self.roles.pop(role.data.id, None) self.rid2roles.pop(rid, None) eids, fids = role.delete_role(self.player) if send_msg: self.player.pack_msg_data(roles=[role], del_eids=eids, del_fids=fids, send=1) return 1, (role, eids, fids) def can_add(self, rid): if rid in self.rid2roles: return False, errcode.EC_ROLE_MAIN_REP res_role = Game.res_mgr.roles.get(rid) if res_role is None: return False, errcode.EC_ROLE_NOFOUND if res_role.is_main and self.main_role is not None: return False, errcode.EC_ROLE_MAIN_REP return True, res_role def add_role(self, res_role): """ 添加配将,不检查合法性,需要外面调用can_add """ role = PlayerRole(self) role.handle_roleup_data(res_role) role.data.rid = res_role.id role.data.sk = res_role.sk2 if res_role.is_main: self.main_role = role role.come_back() elif self.can_come_back(): role.come_back() role.save(self.player._game.rpc_store) self.roles[role.data.id] = role self.rid2roles[role.data.rid] = role #配将初始化 if res_role.quality in self.ROLE_INIT_CMDS: n, cmd_v = self.ROLE_INIT_CMDS[res_role.quality] cmd = self.player._game.setting_mgr.setdefault(n, cmd_v) gm = self.player._gm_cmd(cmd % res_role.to_dict()) news = gm.locals['equips'] self.player.pack_msg_data(equips=news, send=1) self.player.pub(MSG_ROLE_INVITE, role.data.rid, self.player) return role def invite(self, rid, gm=False, pack_msg=True): """ 招募配将, 失败抛出异常 成功返回: role, uses """ #rid资源必须存在,并且不能多次招募同一个rid rs, err = self.can_add(rid) if not rs: return False, err res_role = err if not res_role.is_main and not gm: #花费 use_id, use_num = res_role.useId, res_role.useNum uses = self.player.bag.cost_item(use_id, use_num, log_type=ITEM_COST_INVITE, pack_msg=pack_msg) if uses is None: return False, errcode.EC_COST_ERR _, _, items = uses else: items = {} self.player.log_normal(PL_ROLE, rid=rid) role = self.add_role(res_role) return role, items def _check_rid_fate(self, rid, fate1, fate2): """ 检测玩家是否穿此命格 """ role = self.roles.get(rid) used = 0 for key, fid in role.iter_fates(): if fid == fate1.data.id or fid == fate2.data.id: used += 1 if used and used == fate1.data.used + fate2.data.used: return True, None log.debug('check-rid-fate rid %s, fate1 %s, fate2 %s', rid, fate1.data.id, fate2.data.id) return False, errcode.EC_ROLE_WEARED def _merge_fate_exp(self, res_fate1, res_fate2, fate1, fate2): """ 经验命格的合并处理 """ if res_fate1.is_exp_fate: update_fate = self._merge_fate_handle(fate1, fate2) return True, update_fate if res_fate2.is_exp_fate: update_fate = self._merge_fate_handle(fate2, fate1) return True, update_fate return False, None def _merge_fate_noexp(self, rid, res_fate1, res_fate2, fate1, fate2): """ 非经验命格的合并处理 """ if rid: if res_fate1.quality > res_fate2.quality: best_id = fate1.data.id else: best_id = fate2.data.id #移动的命格未必使用且它的品质高时 判断是否重叠效果 if fate2.data.used and not fate1.data.used and best_id == fate1.data.id: fate, res_fate = self.player.bag.get_fate_ex(fate1.data.id) tRole = self.roles.get(rid) if tRole._is_fate_repeat(self.player, res_fate): return False, errcode.EC_ROLE_WEAR_REP #品质高的吞噬底的,品质相同时aFtId2吞噬aFtId1 if res_fate1.quality > res_fate2.quality: update_fate = self._merge_fate_handle(fate2, fate1) else: update_fate = self._merge_fate_handle(fate1, fate2) return True, update_fate def merge_fate(self, fid1, fid2, rid=0): """ 命格合并(fid1移动到fid2) """ if fid1 == fid2: return False, errcode.EC_FATE_NOMERGE fate1 = self.player.bag.get_fate(fid1) fate2 = self.player.bag.get_fate(fid2) if not fate1 or not fate2: return False, errcode.EC_FATE_NOFOUND if rid: rs, data = self._check_rid_fate(rid, fate1, fate2) if not rs: return rs, data item_mgr = self.player._game.item_mgr res_fate1 = item_mgr.get_res_fate(fate1.data.fid) res_fate2 = item_mgr.get_res_fate(fate2.data.fid) if res_fate1.is_exp_fate and res_fate2.is_exp_fate: return False, errcode.EC_MERGE_EXPS #经验命格的处理 is_exp_merge, data = self._merge_fate_exp(res_fate1, res_fate2, fate1, fate2) if not is_exp_merge: #非经验命格的处理 rs, data = self._merge_fate_noexp(rid, res_fate1, res_fate2, fate1, fate2) if not rs: return rs, data update_fate = data #合并完成后 对多种操作进行判断 if rid: tRs = self._wear_fate_update(rid, fate1, fate2, update_fate.data.id) if tRs: tRole, data = tRs update_fate.data.used = data self.player.bag.update_fate(update_fate) self.update_role(tRole) del_id = fid2 if update_fate.data.id == fid1 else fid1 return True, self.player.pack_msg_data(fates=[update_fate], del_fids=[del_id]) def _wear_fate_update(self, aRid, aFate1, aFate2, aFtIdBest): """ 处理穿着命格合并的多种情况 然会更新的配将和命格是否使用 """ tRole = self.roles.get(aRid) if not tRole: return None, errcode.EC_ROLE_NOFOUND tRoleWearFates = self._role_wear_fate_data(tRole) #全在身上 if aFate1.data.used and aFate2.data.used: setattr(tRole.data, tRoleWearFates[aFate1.data.id], 0) if aFtIdBest == aFate1.data.id: setattr(tRole.data, tRoleWearFates[aFate2.data.id], aFate1.data.id) return tRole, USED_DO #将身上的移到背包里 elif aFate1.data.used: setattr(tRole.data, tRoleWearFates[aFate1.data.id], 0) return tRole, USED_NOT #将背包里移到身上 elif aFate2.data.used and aFtIdBest == aFate1.data.id: setattr(tRole.data, tRoleWearFates[aFate2.data.id], aFate1.data.id) return tRole, USED_DO return def _role_wear_fate_data(self, aRole): """ 将配将身上的命格存为字典{WearFateId1:FatePlace,...} """ tDict = {} for tFatePlace, tWearFateId in aRole.iter_fates(): if tWearFateId: tDict[tWearFateId] = tFatePlace return tDict def _merge_fate_handle(self, aFate1, aFate2): """ 命格合并:aFate2将aFate1吞噬(固定吞噬方向)""" #写入log self.player.log_merge_fate(ufate=aFate2.to_dict(), dfate=aFate1.to_dict()) tResFateLevels = self.player._game.res_mgr.fate_level_by_fid.get(aFate2.data.fid) tExp = aFate1.data.exp + aFate2.data.exp #获取当前经验所在的等级 tNeedExp = 0 tLevel = 1 max_exp = 0 max_level = 0 for tResFateLevel in tResFateLevels: if tResFateLevel.exp > max_exp: max_exp = tResFateLevel.exp max_level = tResFateLevel.level if tExp < tResFateLevel.exp : tMoreExp = tResFateLevel.exp else: continue if not tNeedExp or tMoreExp<tNeedExp: tNeedExp = tMoreExp tLevel = tResFateLevel.level - 1 #如果无此值则说明合成的等级已经超过上限 if not tNeedExp: tExp = max_exp tLevel = max_level aFate2.data.level = tLevel aFate2.data.exp = tExp if not aFate1.data.isTrade or not aFate2.data.isTrade: aFate2.data.isTrade = CANNOT_TRADE #删除吞噬掉的命格 self.player.bag.del_fate(aFate1.data.id) self.player.bag.update_fate(aFate2) return aFate2 def merge_all_fate(self): """ 命格一键合成 """ #保存数据格式为{效果字段:{品质:tFate...}...} tEffDict = {} tDelFateIds = [] tUpdateFatesDict = {} for tFate in self.player.bag.fates.values(): if tFate.data.used or tFate.data.level == FATE_LEVEL_MAX: continue tResFate = self.player._game.item_mgr.get_res_fate(tFate.data.fid) tKeys = (tFate.data.fid, INIT_LEVEL+1) res_mgr = self.player._game.res_mgr #经验命格不处理 if not res_mgr.fate_level_by_keys.has_key(tKeys): tUpdateFatesDict[tFate.data.id] = tFate.to_dict() continue if tEffDict.has_key(tResFate.effect): if tEffDict[tResFate.effect].has_key(tResFate.quality): #相同影响效果且相同品质进行合并 tFateUp = self._merge_fate_handle(tFate, tEffDict[tResFate.effect][tResFate.quality]) if tFateUp: tDelFateIds.append(tFate.data.id) tUpdateFatesDict[tFateUp.data.id] = tFateUp.to_dict() else: tEffDict[tResFate.effect][tResFate.quality] = tFate else: tEffDict[tResFate.effect] = {tResFate.quality:tFate} if tDelFateIds: return True, {'delFids':tDelFateIds, 'fate':tUpdateFatesDict.values()} return False, errcode.EC_FATE_NOMERGE def role_up_enter(self): """ 进入武将升段 """ pass_day = self.player.play_attr.pass_day(FN_P_ATTR_KEY_ROLEUP) if pass_day: rid2updatens = {} for role in self.roles.itervalues(): rid2updaten = role.pass_day() if rid2updaten: rid2updatens.update(rid2updaten) if rid2updatens: return True, dict(update=rid2updatens) return True, None def role_train_do(self, rid, type): """ 武将培养 产生随机值 """ if self.player.data.level < self.fetch_train_locklevel: return False, errcode.EC_ROLETRAIN_UNLOCK role = self.rid2roles.get(rid) if not role: return False, errcode.EC_VALUE cost = self.train_cost(type) coin1 = coin3 = 0 if type == 0: res_add = self.fetch_train_coin1 coin1 = cost else: res_add = self.fetch_train_coin2 coin3 = cost if not self.player.enough_coin_ex(coin1, aCoin3=coin3): return False, errcode.EC_COST_ERR #产生随机值 rs, data = self._random_train(rid, self.player.data.level, res_add) if not rs: return rs, data if not self.player.cost_coin_ex(coin1, aCoin3=coin3, log_type=COIN_ROLETARIN): return False, errcode.EC_COST_ERR self.train_rand_data = (rid, data) pack = self.player.pack_msg_data(coin=True) return rs, dict(radd=data, update=pack) def _random_train(self, rid, level, res_add): """ 随机产生培养 """ res_role_level = self.player._game.res_mgr.get_role_level(int(rid), level) if not res_role_level: return False, errcode.EC_NORES t_data = {} for attr, (start, end) in res_add.iteritems(): value = getattr(res_role_level, attr) start = value * int(start) * 0.01 end = value * int(end) * 0.01 r_num = random.randint(int(start), int(end)) t_data[attr] = r_num return True, t_data def role_train_ok(self, rid): """ 保存培养 """ if not self.train_rand_data: return False, errcode.EC_ROLETRAIN_NO train_rid, attr = self.train_rand_data if rid != train_rid: return False, errcode.EC_ROLETRAIN_NO role = self.rid2roles.get(rid) if not role: return False, errcode.EC_ROLE_NOFOUND role.train_save(attr) self.train_rand_data = None return True, None def train_cost(self, type): """ 培养消耗 """ res_cost = self.player._game.setting_mgr.setdefault(ROLETRAIN_COST, ROLETRAIN_COST_V) res = common.str2list(res_cost) return res[type] @property def fetch_up_num(self): """ 获取每位武将每天能获得升段次数 """ return self.player._game.setting_mgr.setdefault(ROLEUP_DAY_NUM, ROLEUP_DAY_NUM_V) @property def fetch_up_cost(self): """ 获取武将升段所需要的物品id """ return PlayerRoles.setting_data.get(ROLEUP_COST_ITEM) @property def fetch_train_coin1(self): """ 银币培养 """ return PlayerRoles.setting_data.get(ROLETRAIN_COIN1) @property def fetch_train_coin2(self): """ 元宝培养 """ return PlayerRoles.setting_data.get(ROLETRAIN_COIN2) @property def fetch_train_locklevel(self): """ 培养解锁等级 """ return PlayerRoles.setting_data.get(ROLETRAIN_LOCKLEVEL)
class PlayerVip(object): """ 玩家vip类 """ def __init__(self, player): self.player = player if 0: from .player import Player self.player = Player() def uninit(self): self.player = None def _set_vip(self, value): self.player.data.vip = value self.update() def _get_vip(self): return self.player.data.vip vip = property(_get_vip, _set_vip) def load(self): """ 初始化vip相关数据 """ #背包格子数 self.update() def _send_reward(self, vip_lev): """ 发送vip奖励 """ p = self.player if self.vip > vip_lev: log.info('player(%s) cur vip:%s, upgrade vip:%s', p.data.name, self.vip, vip_lev) return rw_mail = Game.res_mgr.reward_mails.get(RW_MAIL_VIP) pid = p.data.id for vip in xrange(self.vip + 1, vip_lev + 1): try: cont_dict = dict(vip=vip) content = rw_mail.content % cont_dict rid = get_vip_rid(vip) t_rw = p._game.reward_mgr.get(rid) if not t_rw: log.info('vip reward_item is %s, please check data', t_rw) continue items = t_rw.reward(params=p.reward_params()) log.info('player(%s) vip_lv:%s send:%s', p.data.name, vip, items) Game.mail_mgr.send_mails(pid, MAIL_REWARD, rw_mail.title, RW_MAIL_VIP, items, param=content, rid=rid) except: log.log_except("the vip send_mail is error the vip level is:%s", vip) def _init_vip_level(self): """ 根据累计重置元宝数,确定vip等级 只升级,不降级,方便实现送vip等级等人为调整功能 """ lv = self.player._game.vip_mgr.get_vip_level(self.player.data.vipCoin) if lv > self.player.data.vip: self.player.log_normal(PL_VIP_UPGRADE, lv=lv) log.info('player(%s)vip level up:%s', self.player.data.name, lv) self._send_reward(int(lv)) self.vip = lv self.player.pub_vip_level() def update(self): p = self.player game = p._game mgr = game.vip_mgr vip = self.vip def first_charge(self, bag_item): """发送首冲奖励""" rw_mail = Game.res_mgr.reward_mails.get(RW_MAIL_FIRST_CHARGE) content = RW_MAIL_FIRST_CHARGE pid = self.player.data.id log.info("first_charge mailType:%s, pid:%s, items:%s", content, pid, bag_item) if not bag_item: return Game.mail_mgr.send_mails(pid, MAIL_REWARD, rw_mail.title, content, bag_item, param=rw_mail.content) def pay_back(self, bag_items): """ 支付回调,获取奖励 """ #_last = self.player.data.vipCoin #调整vip self.player.data.vipCoin += bag_items.coin2 #log.info("pay_back_vipCoin last:%s, now:%s", _last, self.player.data.vipCoin) self._init_vip_level() #支付奖励,马上保存 self.player.save(full=1) #通知前端 resp_f = 'goodsGive' data = dict(player=self.player.to_dict(), data=bag_items.pack_msg(), vipData=self.player.vip_attr.to_dict()) self.player.send_msg(pack_msg(resp_f, 1, data=data)) def copy_from(self, p_vip): """拷贝玩家数据""" self.vip = p_vip.vip