技能系统学习

技能的配置

@Resource
public class SkillResource implements IAfterResourceLoad, IResourceCheck {
    private static transient Logger logger = LoggerFactory.getLogger(SkillResource.class);

    @ResourceId
    private int id;

    private String skillName;

    // 职业
    private String job;

    // 技能id,相同等级的技能id相同
    private int skillId;
    // 技能等级
    private int level;
    // 技能伤害类型
    private SkillHarmType skillHarmType;
    // 技能使用方式
    private SkillUseType useType;
    // 施法距离
    private int range;
    // 施法消耗
    private ConsumeResource consumeResource;
    private Consumes<AbstractCreature> consumes;

    // 施法消耗
    private List<ConditionResource> useConditionResources;
    private Conditions<AbstractCreature> useCondition;

    // 特殊效果,与目标查询的编号对应
    private Map<Integer, List<Integer>> effects;
    // 通用效果,对上面所有目标生效
    private List<Integer> generalEffects;

    // 冷却CD
    private int cd;

    // 公共cd
    private int gcd;

    private int[] orbGroups;

    // 是否播放攻击动作
    private boolean action;

    // 是否只对自己播放攻击动作
    private boolean actionSelf;

    // 沉默类型
    private int silence;

    private List<KeyPosition> keyPosition;

    // 死亡以后是否移出,临时技能配置true
    private boolean deadRemove;

    // 战力
    private int fightForce;

    // 升级技能条件
    private List<ConditionResource> upgradeConditionResource;

    // 技能升级消耗
    private List<ConsumeResource> upgradeConsumeResource;

    // 下级
    private int nextId;

    private Consumes<Player> upgradeConsume;
    private Conditions<Player> upgradeCondtion;

    // 可生效的天赋组列表
    private int[] innateGrops;

    // 是否有效
    private boolean useWithAttackSpeed;

    // 分段技能父技能id
    private int parentId;

    // 技能标记
    private int mark;

}


技能伤害类型

```java
public enum SkillHarmType {
    // 单体伤害
    HARMFUL,
    // 群体伤害型
    GROUP_HARMFUL,
    // 远距离伤害
    RANGE_HARMFUL,
    // 缩短距离型
    DASH,
    // 自身增益型
    SELF_USERFUL,
    // 单体增益型
    USEFUL,
    // 群体增益型
    GROUP_USEFUL,
    // 全能型,既能对友方释放,也能对地方释放
    BOTH,
    ;
}

技能使用类型

public enum SkillUseType {
    // b被动
    PSV,
    // 锁定目标
    TARG,
    // 直接释放
    IMME,
    // 自身
    SELF,
    // 选定方向
    DIR,
    // 选定区域,
    AREA,
    // 点击地面
    GROUND
}

技能效果配置表

@Resource
public class EffectResouece implements IAftereResoueLoad,IResourceCheck {
    @ResourceId
    private int id;
    // 效果等级
    private int level;
    // 效果类型
    private EffectType effectType;
    // 目标类型
    private int targetObject;
    // 是否广播给周围的玩家
    private boolean broadcast;
    // 伤害触发是否广播,广播后所有人都能看到该效果造成的伤害值
    private boolean damageBroadcast;
    // 免疫掩码
    private int immune;
    // 叠加组id
    private int groupId;
    // 状态条件组
    private List<ConditionResource> validConditionResource;
    private Conditions<AbstractCreature> validConditions;
    // 冷却时间ms
    private int cd;
    // 组cd
    private int gcd;
    // 效果持续时间打算公式
    private String duration;
    private IFormula durationformula;
    // 效果失效条件
    private List<ConditionResouce> invalidConditionResouce;
    private Conditions<AbstractCreature> invalidConditions;
    // 周期性时间ms
    private int[] period;
    // 玩家下线服务器重启以后是否储存
    private boolean playerSave;
    // 下线时Buffer时间是否继续走动
    private boolean offlineDuration;
    // 死亡是否移出
    private boolean deadRemove;
    // 伤害类型,如果没有配置,则根据攻击方职业决定
    private DamageType damageType;
    // 效果生效概率万分比
    private int effectOdds;
    // 效果上下文
    private EffectContext effctContext;
    // 效果标识标记,不需要识别的效果不用配置
    private int effectMark;
    private traansient Set<EffectMark> effectMarkSet;
    // 可生效的天赋组列表
    private int[] innateGroups;
    // 父效果组id,当前效果依附于主效果,生命周期与主效果一致
    private int parentGroupId;
    // 是否能在技能被移除时结束效果
    private boolean endOnSkillLoss;

    // 是否为指定效果
    public boolean is(EffectMark effectMark) {
        return effectMark.beIncludeIn(this.effectMark);
    }
    // 检测该效果是否包含标记
    public boolean hasMark(int mark) {
        return (this.efffctMark & mark) != 0;
    }
    // 检测该效果是否包含全部标记
    public boolean hasAllMark(Set<EffectMark> effectMarkSet) {
        for(EffectMark effectMark : effectMarkSet) {
            if(!effectMark.beIncludeInt(this.effectMark)) {
                return false;
            }
        }
        return ture;
    }
    public boolean isDamageBroadcast() {
        return damageBroadcast;
    }
    // 获取此效果包含的所有effectMark
    public Set<EffectMark> getAllEffectMark() {
        if(this.effectMarkSet == null) {
            effectMarkSet == EffectMark.getAllEffectMark(this.effectMark);
        }
        return effectMarkSet;
    }
    // 计算持续时间
    public int getDuration(AbstractCreature effected, AbstractCreature effector) {
        return durationformula == null ? 0 : Math.max(1,(int) durationformula.cal(effector,effected))
    }


}

公式接口

public interface IFormula {
    // 计算值
    double cal(AbstractCreature self, AbstractCreature other, double... vars);

    // 合并公式,如果某一个公式是null,返回不为null的那一个,如果都不为null,返回公司A+公式B
    static IFormula merge(IFormula a, IFormula b) {
        return MergeUtil.merge(a,b, (o,o2) -> {
            if(o == null) {
                return o2;
            }
            if(o2 == null) {
                return o;
            }
            return new FormulaExpression(Sign.add, o, o2);
        });
    }
}

效果辨识标记

public enum EffectMark {
    @Desc("毒")
    poison(1),
    @Desc("麻痹")
    palsy(2),
    @Decs("冰冻")
    ice(4),
    @Decs("白虎伤害")
    tiger_hurt(8),
    //@Desc("撕裂")
    //tear(16),
    @Desc("死亡不掉装备")
    dieNoDrop(32),
    @Desc("斩杀")
    KILL(64),
    @Desc("狂暴")
    fury(256),
    @Desc("青龙圣兽伤害")
    DragonPower(512),
    @Desc("白虎圣兽伤害")
    TigerPower(1024),
    @Desc("朱雀圣兽伤害")
    BirdPower(2048),
    @Desc("玄武圣兽伤害")
    TurtlePower(4096),

    ;

    private int id;

    EffectMark(int id) {
        this.id = id;
    }

    // 当前标记是否包含在指定整数中
    public boolean beIncludenIn(int mark) {
        return (mark & id) == id;
    }

    // 整取整数mark中包含的所有EffectMark
    public static Set<EffectMark> getAllEffectMark(int mark) {
        Set<EffectMark> result = new HashSet<>(4);
        for(EffectMark effectMark : values()) {
            if(effectMark.beIncludeIn(mark)) {
                result.add(effectMark);
            }
        }
        return result;
    }

}

技能管理器

public class SkillController {
    // 通过天赋:buff缩头技能的天赋标识
    private static final Logger LOGGER = LoggerFactory.getLogger(SkillController.class);

    private AbstractCreature owner;

    // 当前拥有的技能<技能配置id,技能信息>
    private Map<Integger,CustomSkill> skillMap = new ConcurrentHashMap<>(1);

    // 技能冷却
    private AgingMark<Integer> skillCoolDowns = new AgingMark<>();

    // 公共冷却
    private AgingMark<Integer, CustomSkill> skillMap = new ConcurrentHashMap<>(1);

    // 是否正在刷新天赋,避免天赋重复刷新死循环
    private AtomicBoolean innateRefreshing = new AtomicBoolean(false);

    // 配置型天赋集合<加成类型,加成列表>
    private ConcurrentHashMap<InnateType, CopyOnWriteArrayLsit<Integer>> innateMap = new ConcurentHashMap<>(0);
    // 限制技能id的天赋<天赋id,技能id>
    private Map<Integer, Integer> limitInnateWithSkillMap = new ConcurrentHashMap<>(0);
    // 禁用技能信息
    private ConterMap<Integer> forblddenSkill = new CunterMap<>(0);
    // 测试某个特定技能的剩余次数
    private CounterMap<Integer> skillTestLeftTime;
    {
        if(Start.debug) {
            skillTestLeftTime = new CounterMap<>();
        }
    }
    // 测试特定的味道效果的剩余次数
    private CounterMap<Long> innaeTestLeftTime;

    // 测试特定效果的剩余次数
    private CounterMap<Integer> effectTestLeftTime;

    public SkillController(AbstractCreature owner) {
        this.owner = owner;
        // 监听死亡移除技能
        this.owner.getObserveController().attachForever(ICreatureDead.class, (creature, lastAttacker) -> skillMap.foreach((skillId,resource) -> {
            if(resource.isDeadReove) {
                removeSkill(skillId);
            }
        }));
    }

    //  是否拥有指定技能
    public boolean hasSkill(int id) { 
        return skillMap.containsKey(id);
    }

    // 通过技能的唯一id,批次添加技能
    public void addSkill(Collection<Integer> ids, boolean deadReomve) {

    }

    // 通过金额改得唯一id,批量移出技能
    public void removeSkill(Collection<Integer> ids) {

    }

    // 替换技能,执行继承CD操作
    public void replaceSkill(int oldId, int newId) {

    }

    // 升级技能,如果存在相同的技能,则先移出,再添加新的
    public void updateSkill2New(int newId) {

    }

    // 让被动技能的效果生效
    private void linkPsv(int id) {
        // 各种检验 。。。。

        // 开始效果
        SkillResource skillResource = SkillManager.getInstance().getSkillResource(id);
        if(skillResource.getUseType.PSV) {
            // 添加被动效果
            Target target = Taerget.valueOf(owner,owner);
            Skill skill = Skill.valueOf(0,id,owner, target);
            skill.useSkill();
        }
    }

    // 移出被动技能的效果
    private void unlinkPsv(iny id) {
        CustomSkill customSkill = skillMap.get(id);
        if(customSkill == null) {
            return;
        }
        if(!customSkill.getLink().compareAndSet(true,false)) }{
            // 技能未生效
            return;
        }
        // 移出关联的永久性效果,有时效的效果不需要移出
        owner.getEffectController().remove(effect -> effect.isForever && effect.getSkillId() == id && effecct.getEffector() == owner);
    }

    // 移出一个技能
    public void removeSkill(int id) {
        unlinkPsv(id);
        CustomSkill customSkill = skillMap.remove(id);
        if(customSkill == null) {
            return;
        }
        owner.getObserveController().fire(ICreatureRemoveSkill.class, iCreatureRemoveSkill -> iCreatureRemoveSkill -> iCreatureRemoveSkill.onRemoveSkill(owner, id));
        if(owner.isPlayer()) {
            // 通知移出

            // 抛出事件
        }
    }

    // 单位身上的所有非死亡移出技能id
    public List<CustomSkill> getSkillWithoutDeadRemove() {

    }

    // 单位身上的所有技能
    public List<CustomSkill> getAllSkill() {

    }

    // 获取技能
    private CustomSkill getrSkillWithBaseId(int skillBaseId) {

    }

    // 获取技能,如果单位没有该技能,返回null
    public CustomSkill getSkill(int id) {

    }

    // 技能是否冷却
    public boolean isSkillDisabled(SkillResource skillResource) {
        return skillCoolDowns.hasMark(skillResource.getSkillId() || publicCoolDowns.hasMark(skillResource.getGcdGroup()))
    }

    // 计算技能cd
    public void cdSkill(SkillResource resource,int cd) {

    }

    // 清除所有技能cd
    public List<IntegerAndIntegerPairEntry> clearAllSkillCd() {
        List<IntegerAndIntegerPairEntry> clearList = new ArrayList<>(skillCoolDowns.size());
        skillCoolDowns.walkAll( (skillId, time) -> clearList.add(IntegerAndIntegerPairEntry.valueOf(skillId, -1)));
        skillCoolDowns.clear();
        return clearList;
    }

    // 清除所有公共cd
    public List<IntegerAndIntrgerPairEntry> clearPublicCd() {
       // ....
    }

    // 增加天赋
    public void addInnate(int innateId) {
        addInnate(0,innateId)
    }

    // 移出天赋
    public void removeInnate(int innateId) {

    }

    // 添加只对指定技能生效的天赋
    public void addInnate(int skillId, int innateId) {
        int skillBaseId = 0;
        if(skillId > 0) {
            SkillResource skillResource = SkillManager.getInstance().getSkillResource(skillId);
            skillBaseId = skillResource.getSkillId();
        }
        addInnateWithSkillBaseId(skillBaseId, innateId);
    }

    // 获取天赋的时候,把所有技能都刷新一遍,目前未找到好的方式来根据天赋id刷新对应的技能
    public void refreshPsvSkillInnate(int innateId) {

    }

    // 刷新被动技能的效果
    public void refreshPsvSkill() {
    }

    // 收集天赋加成长数值
    public double cutNumber(int skillId, int resId, InnateType innateType, AbstractCreature target, double... vars) {

    }
    // 收集天赋加成id型
    public List<Integer> cutNewId(int skillId, int resId, InnateType innateType, AbstractCreature target) {

    }
    // 收集天赋加成属性型
    public Map<SateEnum, Integer> cutStatMap(int skillId, int resId, InnateType innateType) {

    }
    // 获取当前所有拥有的所有天赋id
    public List<Integer> getAllInnateIds() {

    }
    // 查找符合条件的技能
    public CustomSkill findSkill(Predicate<CustomSkill> predicate) {

    }
    // 查找符合条件的所有技能
    public List<CustomSkill> findSkills(Predicate<CustomSkill> predicate) {

    }
    // 禁用技能
    public void forbidden(int skillId) {

    }
    // 解除禁用

    // 技能是否已经被禁用

    // 获取一个指定伤害类型且处于CD完成的技能ID
    public int getTypeSkillId(SkillHarmType skillHarmType) {

    }

    // 获取技能释放最短间隔,用于确认NPC的技能释放间隔
    public int getSkillInterval() {

    }
}

技能

public final class Skill{
    // 客户端序号
    private int seq;
    // 施法者,这个可能为空
    private AbstractCrature effector;
    // 配置表id
    private int skillId;
    // 客户端传过来的目标参数
    private Target target;
    // 技能配置信息
    private CustomSkill customSkill;
    // 客户端使用技能时间
    private int clientTime;
    public static Skill valueOf(int seq, int skillId,AbsrtractCreature effect, Target target) {
        Skill skill = new Skill();
        if(seq == 0) {
            // 服务器释放的技能,没有序号,随机一个
            skill.seq = RandomUtis.betweenInt(1000, 20000,true);
        } else {
            skill.seq = seq;
        }
    }


    /**
     *  使用技能
     *
     */

     public Result useSkill() {
         // 各种校验


         // 是否有施法动作
         if(resource.isAction()) {
            // 施法时要停止移动
            effector.getMoveController.stopMoving(target.getClientX(), target.getClientY());

            // 检验位置
            validTarget(effector, target, resource);
         }

         // cd生效
         cdSkill(resource, clientTime);

        // 定义效果<目标选择器id,效果列表>
        Map<Integer, List<Integer>> effectMap = resource.getEffect();
        // 通用效果
        List<Integer> generalEffects = resource.getGeneralEffects();

        List<TargetInfo> effectTargets = resource.getGeneralEffects();

        List<TargetInfo> effectTargets = new ArrayList<(effectMap.size());
        for(Map.Entry<Integer,List<Iteger>> entry : effectMap,.entrySet()) {
            int targetChooserId = entry.getKey();
            // 找出目标,这是目标选择器的配置
            TargetChooserResource chooserResource = getChooserResource(targetChooserId);
            TargetInfo targetInfo = SkillTargetManager.instance().chooseTarget(effector, target, skillId, chooserResource);
            effectTargets.add(targetInfo);

            // 定制效果生效
            List<Integer> effectIds = entry.getValue();
            for (int effectId : effectIds) {
                EffectManager.getInstance().effect(effector, this, effectId,targetInfo);
            }
            // 通用效果
            if(generalEffects != null) {
                for(Integer generalEffect : generalEffects) {
                    EffectManager.getInstance().effect(effector,this,generalEffect, targetInfo);
                }
            }
            // 天赋额外效果
            targetInfo.getFianalTargets().forEach( abstractCreature -> {
                List<Integer> list = skillController.cutNewID(resource.getId(), resource.getId(), InnateType.skill_newGeneralEffect, abstractCreature);
                list.foreach(effectId -> EffectManager.getINstance().effect(effect, this,effectId, abstractCreature));
            });
            // 抛出技能效果作用事件
            targetInfo.getFinalTargets().forEach( target -> target.getObserveController().fire(IcreatureBeUseSkill.class, iCreatureBeUseSkill -> iCreatureBeUseSkill -> iCreatureBEUseSkill.onCreatureBeUseSkill(target,effector, this));
        }
        List<Integer> list = skilController.cutNewId(resource.getId(), resource.getId(), InnateType.skill_effect_link_self,effector);
        list.forEach(effectId -> EffectManager.getInstance().effect(effector, this, effectId,effector));

        // 抛出技能使用事件


        //  
        if(effector.getMasterOrSelef() instanceOf FightPlayer && SkillUtils.skillNeedTest(effector,skiiId)) {
            StringBuilder stringBuilder = new StringBuilder();
            for(TargetInfo targetInfo : effectTargets) {
                Multimap<Integer, AbstractCreature> effectId2AbstractCreatures = targetInfo.getOrCreateEffectId2AbstractCreature();
                for(int key: effectId2AbstractCreatures.ketSet()) {
                    Collection<AbstractCreature> abstractCreatures = effectId2AbstractCreatures.get(key);
                    String creatureInfo = StringUtils.join(abstractCreatures,",");
                    String message = MessageFormatter.arrayFormat("\效果[id={}],附加到以下生物[{}]",new Object[] {key, creatureInfo}).getMessage();
                    stringBuilder.append(message);
                }
            }
            CounterMap<Integer> skillTestLeftTime = effector.getMasterOrSelf().getSkillController().getSkillTestLeftTime();
            skillTestLeftTime.dec(skillId);
            MessagePacketUtil.sendTips((FightPlayer) effetor, MessageCode.SKILL_TEST_INFO, skillId, stringBuilder.toString(),
            skillTestLeftTime.getCount(skillId));
        }
        long useTime = System.nanoTiume - start;
        ProfileType.other.getProfile.getOrCreatureProInfo("useSkill-"+skillId).recordExc(useTime, 0);
        return Result.SUCCESS;
     }
     // 计算冷却
     private void cdSkill() {
        if(!resouce.hasCd()) {
            // 没有cd
            return;
        }
        SkillController skillController = effector.getSkillController();
        int cd = skillController.getSkillCdValue(resource.getId());
        int gcd = skillController.getSkillGcdValue(resource.getId());
        skillController.cdSkill(res);
     }

     // 修正目标信息的合法性
     private void validTarget(AbstractCreature self,Target target, SkillResource resource) {

     }

}


技能效果管理器

@Component
public class EffectManager implements ApplicationContextAware. OnThePlayerEntityUpdateRule {

    // 获取技能效果处理模板
    public <T extends IEffectTempalte> T getEffectTemplate(EffectType effectType) {
        return (T) effectTemplateMap.get(effectType);
    }


    // 对目标生效
    public void effect(AbstractCreature effector, Skill skill, int effectId, AbstractCreature target) {
        TargetInfo targetInfo = new TargetInfo(effector, target);
        effect(effector, skill, effectId, targetInfo);
    }

    // 效果对形状内目标生效
    public void effect(AbstractCreature effector,Skill skill, int effectId, TargetInfo targetInfo) {
        EffectResource effecrResource = skill.getEffectResouece(effectId);
        try{
            IEffectTemplate effectTemplate = EffectManager.getInstance().getEffectTemplate(effectResouece);
            if(SkillUtils.effectNeed) {
                MessagePacketUtil.snedTips((FightPlayer) effector.getMasterOrSelf(), MessageCode.EFFECT_TRY_USE,effectId);
            }
            effectTemplate.applyEffect(effector, skill, targetInfo, effectResource);
            aterApp
        } catch(Exception e) {
            //
        }
    }


    // 效果处理后的后续操作
    public void afterApplyEffect(AbstractCreature efferct, Skill skill, TargetInfo targetInfo, EffectResuece effectResource) {
        if(!targetInfo.getFianlTargets().isEmpty()) {
            // 天赋额外效果只针对生效的效果有效
            // 对最终目标生效
            targetInfo.getFinalTargets().forEach(creature -> {
                List<Integer> list = effector.getSkillController().cutNewId(skill.getSkillId(), effectResource.getId(), InnateType.effect_link_target, creature));
                list.forEeach(linkEffectId -> effect(effector, skill, linkEffectId,creature));
            });
            // 对目标立刻再放一个技能
            targetInfo.getFinalTargets().forEach(targetCreature -> {
                List<Integer> list = effector.getSkillController().cutNewId(skill.getSkillId(), effectResource.getId(), InnateType.skill_link_target, targetCtCreature);
                list.forEach(skillId -> SkillManager.getInstance().npcUseSKill(skillId, effector, Target.valueOf(effector, targetCreature)));
            });
            // 对自己生效
            List<Integer> list = effector.getSkillController().cutNewId(skill.getSkillId(), effectResource.getId(), InnateType.skill_link_self, targetCtCreature);
            list.forEach(linkEffectId -> effect(effector, skill, linkEffectId,effector));
        }
    }

    // 尝试触发天赋额外效果
    public void triggerInnateEffect(AbstractCreature self, AbstractCreature target, int seq, int skillId, int resId) {
        Skill skill = Skill.valueOf(seq, skillId, self);
        // 对最终目标生效
        List<Integer> list = self.getSkillController().cutNewId(skillId, resId, InnateType.effect_link_target, target);
        list.forEach(linkEffectId -> effect(self, skill, linkEffectId, target));

        // 对自己生效
        list = self.getSkillController().cutNewId(skillId, resId, InnateType, effect_link_self, self);
        list.forEach(linkEffectId -> effect(self, skill, linkEffect,self));
    }
}

效果模板

效果模分为主动效果和被动效果,它们都继承于IEffectTemplate的。

被动效果(psv):

  • 控制效果
  • 伤害过滤效果

效果模板接口

public interface IEffectTemplate {
    // 返回处理的效果类型
    EffectType type();

    // 效果处理接口
    void applyEffect(AbstractCreature effector, Skill skill, EffectResource effectResouece, TargetInfo targetInfo);
}

主动效果抽象


// 主动效果
public abstract class BaseInitiativeEffect implements IEffectTemplate {
    // 空
}

直接伤害

@Component
public class DamageEffect extends BaseInitiativeEffect {
    @Override
    public EffectType type() {
        return EffectType.DAMAGE;
    }
    @Override
    public void applyEffect(AbstractCreature effetor, Skill skill, EffectResource effectResource ) {
        EffectUtils.executeDamage(effector, skill, effectResource, targetInfo, null);
    }
}

天赋管理器

// 天赋管理器


public class InnateManager {

    @Static
    private Storage<Integer, InnateResource> innateResoueceStorage;

    private MultiValueMap<Integer, InnateResource> innateResourceMap;

    // 获取天赋配置
    public InnateResource getResource(int innateId) {
        return innateResourceStorage.get(innateId, true);
    }

    public ArrayListVlaueHashMap<Integer, InnateResouece> getInnateResource() {
        return (ArrayListValuedHashMap<Integer, InnateResource>) innateResoueceMap;
    }

}

天赋模块

技能天赋配置

public class InnateResource implement IAfterResourceLoad, IResourceCheck {

    // 检查用
    private static transient Multimap<Integer, InnateResourec> innateGroup2InnateResource;

    @ResourceId
    private int innateId;

    // 天赋组,生效检测使用,被技能、效果、形状引用
    private int innateGroup;

    // 针对施法者的条件
    private Conditions<AbstractCreature> selfCondition;
    private List<ConditionResource> selfConditionResource;

    // 针对目标的条件
    private Conditions<AbStractCreature> targetCondition;
    private List<ConditionResource> targetConditionResource;

    // 天赋的类型
    private InnateType innateType;

    // 天赋参数
    private String param;
    private transient IInnateCut innateCut;

    // 该天赋在使用时触发的概率,如果不慎,表示必然触发
    private int odds;

    // 针对SkillResource的条件
    private Conditions<SkillResource> skillCondition;
    private List<CondtionResource> skillConditionResources;

    // 针对EffectResource的条件
    private Conditions<EffectResouece> effectConditions;
    private List<ConditionResource> effectConditionResource;

    // 针对TargetChooserResouece的条件
    private Conditions<TargetChooserResource> targetChooserCondition;
    private List<ConditionResource> targetChooserConditionResource;

    // 检测天赋组是否存在
    private static void innateGroupExist(Object obj, int id, int groupId) {
        if(!getOrCreateCheckMap().containsKey(groupId)) {
            String message = MessageFormatter.arrayFormat("{} [id = {}使用了不存在的天赋组[{}]",
            new Object[] {obj.getClass().getSimpleName(), id, groupId}).getMessage();
        }
    }
}

结果收集器

@FunctionalInterface
public interface IResultCollect<R> {
    // 添加结果
    void put(R r);
}

天赋类型

public enum InnateType {

    // 技能cd
    skill_cd(CutFormula.class, SkillResource.class),

    // 公cd
    skill_gcd(CutFormul.class, SKillResource.class),

    // 技能新效果
    skill_newGeneralEffect(CutNewId.calss, SkillResouece.class) {
        @Override
        public void check(InnateResource innateResource) {
            InnateType.checkEffectEffectExist();
        }
    }
    // 释放技能时,给自己一个新效果
    skill_effect_link_self(CutNewId.class, SkillResource.class) {
        @Override
        public void check(InnateResource innateResource) {
            InnateType.checkEffectEffectExist(innateResource);
        }
    },

    // 增/减技能产生的所有伤害的伤害的伤害倍率
    skill_damageR(CutFormula.class, SkillResource.class),

    // 伤害加成万分比
    damageCfg_damageR(CutFormual.class, EffectType.DAMAGE, EffectType.DAMAGE_PSV, EffectType.DAMAGE,EffectType.DAMAGE_ONCE_BLEED,
    EffectType.DAMAGE_FORMULA, EffectType.DAMAGE_FORMULA_PSV),

    // 原伤害加成固定值
    damageCfg_damage(CutFormula.class, EffectType.DAMAGE, EffectType.DAMAGE_PSV, EffectType.DAMAGE_ONCE_BLEED),

    // 原等级差
    pushBack_lv(CutFormula.class, EffectType.PUSH_BACK),

    // 原免疫数量
    immune_count(CutFormula.class, EffectType.IMMUNE),

    // 免疫效果免疫成功后,对目标 额外释放一个效果
    immune_suc_tar_effect(CutNewId.class, EffectType.IMMUNE) {
        @Override
        public void check(InnateResource innateResource){
           InnateType.checkEffectExist(innateRsource);
        };
    }

    // 施放者效果触发率
    effect_odds(CutFormala.class),

    // 被施法者效果触发概率
    effect_odds_Defend(CutFormula.class),

    // 施放者持续时间
    effect_duration(CutFormula.class) {
        @Override
        public Class getClassLimit() {
            return BasePassivityEffect.class;
        }
    }
    // 效果释放成功后,对自己继续释放一个效果
    effect_link_self(CutNewId.class) {
        @Override
        public void check(InnateResource innateResource) {
            InnateType.checkEffectExist(innateResource);
        }
    }

    // 效果释放成功后,对目标继续释放一个效果
    effect_link_target(CutNewId,class) {
        @Override
        public void check() {

        }
    }

    // 效果触发时,给自己添加一个效果
    target_link_self(CutNeId.class) {
        @Override
        public void check() {
            @Override
            public void check(InnateResource innateResource) {
                InnateType.checkEffectExist(innateResource);
            }
        }
    }

    // 效果触发时,给目标添加一个效果
    trigger_link_target(CutNewId.class) {
        @Override
        public void check(InnateResource) {

        }
    }

    // 给新召唤的召唤物添加一个效果
    effect_link_summon(CutNewId.class, EffectType.SUMMON) {
        @Override
        public void check(InnateResource innateResource) {
            InnateType.checkEffectExist(innateResource);
        }
    }

    // 选择器数目
    chooser_num(CutFormula.class, TargetChooserResource.class),

    // 召唤物的数目
    summon_num(CutFormula.class, EffectType.SUMMON),

    // 召唤物基础主人属性万分比加成
    summon_masterStat(CutStatMap.class, EffectType.SUMMON),

    // 召唤物额外基础属性
    summon_stat(CutStatMap.class, EffectType.SUMMON),

    // 分身继承属性万分比
    shadow_statRct(CutStatMap.class, EffectType.SHADOW),

    // 偷取技能失败原cd
    stealSkill_failReduceCD(CutFormula.class, EffectType.STEAL_SKILL),

    // 原封禁技能数量
    forbiddenSKill_count(CutFormula.class, EffectType.FORBINDDEN_SKILL),

    // 原偷取效果数量
    stealEffect_count(CutFormula.class, EffectType.TRANSFER_EFFECT),

    // 属性buff效果倍数
    statBuff_multi(CutFormula.class, EffectType.STAT_BUFF),

    // 原魔法盾减伤万分比
    shield_dec_r(CutFormula.class, EffectType.SHIELD),
    ;

    private Class<? extends IInnateCut> cutClass;

    // 此种天赋应该配置在什么资源的可生效天赋组中,默认 EffectResourece
    private Class locationClz;

    // 限制只能配置在特定类型的效果上,用于检测配置是否存在问题,空表示不限制
    private EffectType[] effectTypes;

    InnateType(Class<? extends IInnateCut> cutClass, EffectType... effectTypes) {
        this.cutclass = cutClass;
        this.locationClz = locationClz;
        this.effectTypes = effectTypes;
    }

    // 当其指向技能id或者效果id时需要作相应的检查
    public void check(InnateResource innateResource) {
        if(cutClass == CutNewId.calss) {
            throw new RuntimeException(MessageFormatter.format("切入类型为[{}]的天赋,必须覆盖此方法作相应id是否存在的检查", CutNew));
        }
    }

    private static void checkEffectExist(InnateResource innateReosurce) {
        IInnateCut innateCut = innateResource.getInnateCut();
        int id = (CutNewId) innateCut.getNewId();
        try {
            SKillManager.getInstance().getEeffectResource(id);
        } catch () {
            throw new RuntimeException(String.format("天赋[id=%s]指向的效果[id=%s]不存在", innateResource.getInnateId(),id));
        }
    }

    private static void checkSKillExist(InnateResource innateResource) {
        InnateCut innateCut = innateResource.getInnateCut();
        int id = ((CutNewId) innateCut).getNewIdCut();
        try {
            SKillManager.getInstance().getSkillResource(id);
        } catch () {
            throw new RuntimeException(String.format("天赋[id=%s]指向的技能[id=%s]不存在", innateResource.getInnateId(),id));
        }
    }

    // 检验innateId天赋的天赋组是否包含在resId资源的可生效天赋组中
    public boolean verifyInnateGroup(int resId, int innateId) {

    }

    public Result verifyCondition(int resId, int innateId) {

    }

    public EffectType[] getEffectTypes() {
        retirn effectTypes;
    }

    public Class getLocationClz() {
        return locationClz;
    }

    // 限制在某种效果类上使用
    public Class getClassLimit() {
        return null;
    }

    public IInateCut create(String param) throws Illea {
        IInnateCut cut = cutClass.newInstance();
        cut.init(param);
        return cut;
    }

}

数值改变公式

public class CutFormula implements IInnateCut {
    private IFormula formula;

    @Override
    public void init(String param) {
        formula = FormulaType.create(param);
    }

    public double cal(AbstractCreature self, AbstractCreature other, double... vars) {
        return formula.cal();
    }
}

额外的id参数

public class CutNewId implements IInnateCut {
    private int newId;
    @
}

属性集合

public class CutStatMap implements IInnateCut {
    private Map<StatEnum, Integer> statMap;

    @Override
    public void init(String param) {

    }

    public Map<StatEnum, Integer> getStatMap {

    }
}

公式

伤害和属性变化等数值变化使用公式来描述

公式计算接口

// 公式计算接口
public interface IFormula {

    // 计算值
    double cal(AbstractCreature self, AbstractCreature other, double... vars);

    // 合并公式,如果某一个公式是null,返回不为null的那一个,如果都不为null,返回公式A+公式B
    static IFormula merge(IFormula a, IFormula b) {
        if(o == null) {
            return o2;
        }
        if(o2 == null) {
            return o;
        }
        return new FormulaExpression(Sing.add, o, o2);
    }
}

公式实现类

空公式

public class FormulaEmpty implements IFormula {

}

战斗系统值计算公式

public class FormulaExpression implements IFormula {
    // 符号
    priavte Sign sign;

    private IFormula left;
    private IFormula right;

    publci 
}
// 公式逻辑运算类型
public enum LoginType {

    public abstract IFormula creatureFormula(String... params);

    // 青龙之力分类
    DragonPowerClassify {
        @Override
        public IFormula createFormula(String... params) {
            int classifyVal = Integer.valueOf(params[0]);
            return ((self, other, vars)) -> {
                int curDragonPower = PlayerEquipPowerManager.getInstance().
                getEquipPowerLevel(other, EquipStorageType.DRAGON);
                if(curDragon >= classifyVal) {
                    return 0;
                }
                return 1;
            }
        }
    }

    // 当前环节的伤害值
    CutDamage {
        @Override
        public IFormula createFormula(String... params) {
            return ((selef, other, vars)) -> {
                if(vars == null || vars.length < 1) {
                    return vars[0];
                }
            }
        }
    }

    // 绝学修为过滤
    MartialCultivationFilter {
        @Override
        public IFormula createFormula(String... params) {
            int classifyVal = Integer.valueOf(params[0]);
            return ((self, other, vars)) ->  {
                int martialCultivation = MartialManger.getInstance().getMartialCutivation(other);
                if(martialCultivation >= classifyVal) {
                    return 0;
                }
                return 1;
            }
        }
    }
}
// 公式符号定义

public enum Sign {

    // 加
    add("+") {
        @Override
        public double cal(double a, double b) {
            return a + b;
        }
    }

    // 减
    sub("-") {
        @Override
        public double cal(double a, double b) {
            return a - b;
        }
    }


    // 除
    sub("/") {
        @Override
        public double cal(double a, double b) {
            return a / b;
        }
    }

    // 乘
    sub("*") {
        @Override
        public double cal(double a, double b) {
            return a * b;
        }
    }


}
// 公式类型

public enum FormulaType {

    // 预缓存括号
    parenthesisPre {}

    // 表达式
    expression {
        @Ovveride
        public IFormula tryParse(List<IFormula> parenthesis, String resource) {
            // 表达式
            // 遍历顺序加减乘除,树形结构存储,先计算叶节点,实际计算顺序为乘除减加
            for(Sigin sigin : Sign.values()) {
                int idenx = resource.indexOf(sign,getS());
                if(index != -1) {
                    // 左表达式
                    IFormula left = create0(parenthesis, resource.substring(0, index));
                    // 右表达式
                    IFormula right = creature0(parenthesis, resource.substring(index+1, resource.length()))
                }
            }
            return null;
        }
    }

    // 填入括号内容
    parenthesis {
        @Override
        protected IFormula tryParse(List<IFormula parenthsis, String resource>) {
            if(!resource.contains("parenthesis")) {
                return null;
            }
            int index = Integer.valueOf(resource.replace("parenthesis", ""));
            return parenthesis.get(index);
        }
    }

    // 属性值
    star {}

    // 随机表达式
    random {}

    // 逻辑运算值
    login {}

    // 参数值,这个在不同的使用位置,参数各不相同
    var {}

效果工具

public class EffectUtils {

    // 效果延迟执行,延迟为0时直接执行
    public static void delayEcecute(AbstractCreature effector, String name, int delay, TimeUnit timeUnit, Skill skill, TargetInfo targetInfo, EffectResource effectResource, Runnable runnable) {
        if(delay == 0) {
            runnable.run();
            return;
        }
        IdentityEventExecutorGroup.addScheduleTask(effector.getDispatcherHashCode(), name, delay, timeUnit, () -> {
            runnable.run();
            EffectManager.getInstance().afterApplyEffect(effector, skill, targetInfo, effectResource);
        });
    }

    public static interface DamageTargetHandler {
        // 对每个受到伤害的目标进行一些处理
        void handle(AbstractCreature effector, Skill skill, EffectResource effectRsource, AbstractCreature target, DamageBoard damageBoard);
    }

    // 执行伤害
    public static void executeDamage(AbstractCreature effector, Skill skill, EffectResource effectResource, TargetInfo targetInfo, DamageTargetHandler damageTargetHandler) {
        DamageCfg damageCfg = efectResource.getEffectContext.getDamageCfg;

        targetInfo.walkWithInitiativePassEffect(skill, effectResouece, null, target -> {
            if(target.getLifeStats().isAlreadyDead()) {
                return EffectResult.FAIL;
            }
        DamageBoard damageBoard = FightManager.instance().calDamage(effector, target, skill.getResource(), effectResource, damageCfg);
            if(damageBoard.isMark(DamageShowType.MISS)) {
                // 广播miss
                EffectSendUtility.sendDamage(effect, target, effectResource.getId(), skill.getSeq(), damageBoard.toResp())
            }
             // 扣减伤害
        damageBoard.tryResetDamage(target.getController().attackAndNotityAttackedobserver(effector, damageBoard.damage, skill, effectResource));
        // 反弹
        damageBoard.instance().thorns(damageBoard);
        // 吸血
        if(effectResource.getEffectContext().getDamageCfg().isSuckable()) {
            FightManager.instance().suck(damageBoard);
        }
        // 混沌伤害
        FighrManager.instance().chaos(damageBoard);
        if(damageBoard.damage == 0) {
            // 最终伤害为0,则格挡
            damageBoard.mark(DamageShowType.PARRY);
        }
        // 广播伤害
        EffectSendUtility.sendDamage(effector, target, effectResouece.getId(), skill.getSeq(), damageBoard.toResp());

        if(damageBoard.isMark(DamageShowType.)) {
            // 被暴击,抛出暴击事件
            target.getObserveController().fire(ICreatureBeCrit.class, iCreatureCrit -> ICreatureBeCrit.afterBeCrit(effector, target, skill));
        }

        // 攻击事件
        effect.getObserveController().fire(IcreatureAttack.class, iCreatureAttack.affterBeattack(target, effect, skill));
        // 被攻击事件
        target.getObserveController().fire(IcreatureBeAttack.class, iCreatureBeAttack -> iCreatureBeAttack.afterBeAttack(target, effector, skill));
        if(damageTargetHandler != null) {
            damageTargeterHandler.handle(effectot, skill, effectResource, target, damageBoard);
        }
        return EffectResult.SUCCESS;
        });
    }

}

战斗管理器

@Component
public class FightManager {
    private static FightManager instance;

    @IConfigValueInject("闪避计算系数A")
    public double fightOddMissA;

    @IConfigValueInject("暴击力系数")
    public double fightOddsCrit;


    // 斩魔系数
    private TreeMap<Integer, Integer> toMonsterCritProbMap;

    // 幸运值系数
    private TreeMap<Integer,Integer> luckProbMap;

    // 诅咒系数
    private TreeMap<Integer, Integer> curseProbMap;

    // 计算伤害
    public DamageBoard calDamage(AbstractCreature attacker, AbstractCreature defender, SkillResource skillResource, EffectResource effectResource, DamageCfg damageCfg) {
        if(damageCfg == null) {
            damageCfg = DamageCfg.EMPTY_CFG;
        }
        // 伤害黑板
        DamageBoard damageBoard = new DamageBorad(attaker, defender, skillResource, effectResource, damageCfg);
        // 闪避
        if(!damageCfg.isIgnoreMiss() && isMiss(attacker, defender)) {
            damageBoard.mark(DamageShowType.MISS);
        } else {
            damageBoard.mark(DamageShowType.NORMAL);
            // 攻击类型
            damageBoard.damageType = getDamageType(attackerr, effectResource);
            // 战力力压制信息
            intFightForceSubdue(attacker, defender, damageBoard);
            // 计算最终伤害
            damageBoard.damage = DamageChain.finalDmage.cal(damageBoard);
        }
        return damageBoard;
    }

    // 计算基础伤害
    public DamageBoard calBaseDamage(AbstractCreature attacker, AbstractCreature defender, SkillResource skillResource, EffectResource effectResource, DamageCfg damageCfg) {
        if(damageCfg == null) {
            damageCfg = DamageCfg.EMPTY_CFG;
        }
        // 伤害黑板
        DamageBoard damageBoard = new DamageBorad(attaker, defender, skillResource, effectResource, damageCfg);
        // 攻击类型
        damageBoard.damageType = getDamageType(attackerr, effectResource);
        // 计算最终伤害
        damageBoard.damage = DamageChain.finalDmage.cal(damageBoard);
        return damageBoard;
    }

    // 计算是否闪避
    private boolean isMiss(AbstractCreature attacker, Ab) {
        long aExcat = attacker.getGameStats().getCurrentStat(StatEnum.EXACT)
        double aLevel = attacker.getLevel();
        long dMiss = defender.getGameStats().getCurrentStat(StatEnum.MISS);
        // 命中
        double exact = (aExact * fightOddsMissA + dMisss * fightOddsMissB) / (aExct + dMiss);
        return !RandomUtils.isHit(exact);
    }

    // 计算暴击伤害
    public long calCrit(DamageBoard damageBoard) {
        AbstractCreature attacker = damageBoard.attacker;
        AbstractCreature defender = damageBoard.defender;
        long aCritProb = attacker.getGameStats().getCurrentStat(StatEnum.CRIT_PROB);
        long aCritProb = attacker.getGameStats().getCurrentStat(StatEnum.CRIT_PROB_DEFEND);
        // 暴击率
        long critProb = aCritProb - dCritProbDefend;
        // 天赋修正
        critProb += attacker.getSkillController().cutNumber(
            dmmageBoard.skillResource().getId();
            damageBoard.effectResource().getId();
            InnateType.damageCfg_critR, defender, critProb
        );
    if(RandomUtils.isHit(critProb)) {
        // 暴击
        long aCrit = attacker.getGameStats().getCurrentStat(StatEnum.CRIT);
        // 爆抗
        long dCritDefend = defendeer.getGameStats().getCurrentStat(StatEnum.CRIT_HURT_DEFEND);
        // 爆免
        double dCritHurtDec = defender.getGameStats().getCurrentStatWithOdds(StatEnum.CRIT_HURT_DEC);

        // 处理暴击
        long crit = RandomUtils.range(aCrit, fightOddsCrit, 1);
        crit -= RandomUtils.range(dCritDefend, fightOddsCritDefendA, fightOddsCritDefendB);
        crit *= (1 - dCritHurtDec);
        if(crit > 0) {
            return crit;
        }
        return 0;
    }

    // 根据伤害类型,获取指定单位的防御力
    public long getDefend(AbstractCreature creature, DamageType damageType) {

    }

    // 计算神圣伤害
    public long calHoly(DamageBoard damageBoard) {

    }

    // 根据职业获取最小攻击力
    public long getMinAttack(AbstractCreature attack) {

    }

    // 初始化战力压制信息
    private void intFightForceSubdue(AbstractCreature attacker, AbsreactCreature defender, DamageBaord DmageBoard) {

    }

    // 判断是否为pvp战斗
    public boolean isPvp(DamageBoard damageBoard) {

    }

    // 计算斩魔伤害
    public long calToMonsterCrit(AbcstactCreature attacker, AbstractCreature defender) {

    }

    // 吸血
    public void suck(DamageBoard damageBoard) {

    }

    // 对自己混乱伤害
    public void chaos(DamageBoard damageBoard) {

    }

}

伤害板,用于记录伤害计算中的各种数据,均为当前值


public class DamageBoars {
    // 攻击方
    public AbstractCreature attacker;
    // 防御者
    public AbstractCreature defender;
    // 技能配置
    public SkillResouece skillResource;
    // 效果配置
    public EffectReeouce effectResource;
    // 技能伤害信息配置
    public DamageCfg damageCfg;
    // 战斗力压制信息
    public FightForceSubdueResource subdueResource;
    // 压制倍数
    public int subdueMulti;
    // 伤害类型
    public DamageType damageType;
    // 缓存计算公式各阶段的伤害
    public long[] damage;
    // 最终伤害
    public long damage;
    // 记录各种伤害类型标记
    private int damageMark;
    // 反弹伤害
    private long thorns;
    // 吸血
    public long suckHp;
    // 混乱伤害
    public long chaosDmg;
    // 守护装备:玄灵盾降低的伤害量
    public long xuanLingDec;

    // 构造.....

    // 转换为伤害协议
    public DamageResp toResp() {
        //....
    }

    // 伤害显示类型
    public void mark(DamageShowType damageShowType) {
        damageMark |= damageShowType.getMark();
    }
    // 记录伤害
    public void addDamage(DamageChain damageChain, long damage) {
        damages[damageChain.ordinal()] = damage];
    }

    // 获取指定阶段的伤害值
    public long getDamage(DmageChain damageChain) {
        return damages[damageChain.ordinal()];
    }
    // 获取多个阶段的总伤害值
    public long getDamageSum(DamageChain ) {
        long value = 0;
        for(DamageChain damageChain : damageChains) {
            vlaue += getDamage(damageChain);
        }
        return vlaue;
    }

    // 根据新的伤害总值,重新设置各阶段的伤害值,同比例方法缩小
    public void tryRestDamage(long newDmage) {
        if(newDamage == damage) {
            return;
        }
        if(damage == 0) {
            // 如果原来的伤害为0,则则将伤害值设置基础值
            addDamage(DamageChain.baseDamage, newDamage);
        } else {
            // 原伤害不为0,同比例放大缩小
            double multi = newDamage / (double) damage;
            for(int i=0; i<damage.length; i++) {
                damages[i] *= multi;
            }
        }
        this.damage = newDamage;
    }


}