技能系统学习
技能的配置
@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;
}
}