コード例 #1
0
ファイル: role.py プロジェクト: hw233/twisted_zdzl
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)
コード例 #2
0
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