找回密码
 立即注册

QQ登录

只需一步,快速开始

[Skillw] ⭐ AttributeSystem & FightSystem⭐ - 可定制的NBT/LORE属性 ...

clok 3 天前 综合 阅读 77 来自 中国山东临沂
服务器插件
中文名称: 属性系统 & 战斗系统
英文名称: AttributeSystem & FightSystem
插件来源: 转载
适用服务端: Spigot Paper Purpur 
插件类型: RPG
语言支持: 中文 英文 
适用版本: 1.9.x 1.10.x 1.11.x 1.12.x 1.13.x 1.14.x 1.15.x 1.16.x 1.17.x 1.18.x 1.19.x 1.20.x 
前置插件/mod: Pouvoir
下载地址: https://qm.qq.com/q/6ezONJYoDe
原贴地址: https://github.com/Skillw/AttributeSystem

马上登录/注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 clok 于 2024-7-4 10:45 编辑

GitHub License
GitHub Release
Langs back

阅读前须知

  • 若您习惯与AP的舒适则我不建议你使用该插件,该插件也不建议新手或菜鸟使用
  • 该精通插件可以让您省去相比普通属性插件如(AP,SX)等90%的时间或资金的消耗

介绍

AttributeSystem

AttributeSystem 是基于 TabooLib VI & Pouvoir 编写的一款多线程属性引擎, 兼容 1.9~1.20.4
不同于市面上,AttributeSystem是全面客制化的属性插件,你可以在这里定义属于你的属性,且几乎不用碰代码。
如果你想实现自主一套完整的模块化的战斗,那么FightSystem将是你的不二之选
你可以用 JavaScript 亦或是 字符串Asahi 来书写你的逻辑,这些全都由你来决定。具体可见 WIKI
本插件优化了lore属性读取性能,即便如此,我还是建议lore仅用作展示,将属性塞到NBT里

FightSystem

FightSystemAttributeSystem的附属,如果你只装载了AttributeSystem,哪么它就只是一副没有灵魂的躯壳AttributeSystem不干涉你任何的战斗机制
FightSystem提供了一套完整的战斗系统,它的吸血,攻击,暴击,反弹等机制代码都是通过JS暴漏在外,用户随意更改


典型实例

AttributeSystem

属性

不同于市面上大多数属性系统,AS的属性系统处处都可以自定义,例如你要写一个属性,名称为攻击力

# 这是一个自定义属性
PhysicalDamage:
  names:
    - "攻击力"
    - "物理伤害"
    - "物理攻击"
  read-pattern: Default
#快速声明一个属性
快速属性: { }
#下面是字符串属性,感兴趣的可以看看
StringAtt:
  names: [ "唯一字符串属性" ]
  read-pattern: StrSkip

StringAppendAtt:
  names: [ "拼接字符串属性" ]
  read-pattern: StrAppend

RomenAtt:
  names: [ "罗马数字" ]
  read-pattern: StrRoman

这就是自定义属性
read-pattern为自定义捕获组,下面为范例

自定义捕获组

Default:
  type: number
  matchers:
    #左边是捕获组id 右边是运算操作
    #捕获组id只能包含 a-z A-Z 0-9
    #运算操作:
    #- plus 加
    #- max 取最大
    #- min 取最小
    #- reduce 减
    #- scalar 乘
    percentMax: plus
    percentMin: plus
    valueMin: plus
    valueMax: plus
    percent: plus
    value: plus
    valueAddition: plus
    percentAddition: plus
    mul: scalar
  #匹配模式(正则)
  #从上到下先后匹配
  #特殊字符要转义
  #捕获组id只能包含 a-z A-Z 0-9
  patterns:
    # 攻击力: 11-23 %
    - "{name}.*?<percentMin>-<percentMax>.*?%"
    # 攻击力: 10-20
    - "{name}.*?<valueMin>-<valueMax>"
    # 攻击力: 10 (+20) %
    - "{name}.*?<percent>.*?\\(<percentAddition>\\).*?%"
    # 攻击力: 10 %
    - "{name}.*?<percent>.*?%"
    #  攻击力*10
    - "{name}.*?\\*.*?<mul>"
    # 攻击力: 100 (+50)
    - "{name}.*?<value>.*?\\(<valueAddition>\\)"
    # 攻击力: 100  /  攻击力 100
    - "{name}.*?<value>"
    #  100 攻击力 +100
    - "<value>.*?{name}.*?<valueAddition>"
    #  100 攻击力
    - "<value>.*?{name}"
  #变量(PAPI / PouPAPI)
  #调用变量格式: %as_att:属性ID_下面的id%
  placeholders:
    #占位符id
    # 可通过 %as_att:属性id_占位符id 调用%
    #可带入捕获组 与 其他 占位符 的值
    #优先带入捕获组的
    # total min max 必须写
    total: "( <valueRandom> )*( 1 + (<percentRandom>) ) * { if check <mul> == 0 then 1 else <mul> }"
    min: "(<value> + <valueAddition> + <valueMin>)*( 1 + (<percentRandom>) ) "
    max: "(<value> + <valueAddition> + <valueMax>)*( 1 + (<percentRandom>) )"
    mul: <mul>
    value: <value> + <valueAddition>
    percent: (<percent> + <percentAddition>) /100
    valueMin: <valueMin> + <valueAddition>
    valueMax: <valueMax> + <valueAddition>
    percentMin: (<percentMin> + <percentAddition>) /100
    percentMax: (<percentMax> + <percentAddition>) /100
    valueRandom: <value> + <valueAddition> + {random <valueMin> to <valueMax>}
    percentRandom: ((<percent> + (<percentAddition>)/100) + {random <percentMin> to <percentMax>}/100)

这就是一个捕获组,它可以自定义属性的读取模式,以及自定义一个数值的释放器来达到你所预期的结果

原版属性

AttributeSystem可不止这些,它还有一个更厉害的,就是原版属性的颠覆,任何原版属性都可以

#支持 PAPI/PPAPI 字符串内联函数
#会影响实体的原版属性 / 其它属性
#支持任何原版属性,例如飞行速度FlySpeed
#fly-speed:
# enable: true
# vanilla: true
# value: %as_att:FlySpeed%
max-health:
  enable: true
  vanilla: true
  #玩家默认血量
  default: 20
  value: "%as_att:MaxHealth%"
movement-speed:
  enable: true
  vanilla: true
  value: "%as_att:MovementSpeed% / 2250"
knockback-resistance:
  #击退抗性
  enable: true
  vanilla: true
  value: "%as_att:Resistance%"
#下面这些只支持玩家
attack-speed:
  #单位为 攻击次数/s
  enable: true
  vanilla: true
  value: "%as_att:AttackSpeed%"
luck:
  enable: true
  vanilla: true
  value: "%as_att:Luck%"

像这样,可以把所有原版属性都放进去

槽位

AttributeSystem支持龙核 萌芽的槽位,还支持原版槽位

#左ID 右槽位
player: { }
#左AS内部槽位key 右原版槽位
#  2.1.0-beta 后已内置
#  "头盔": "HEAD"
#  "胸甲": "CHEST"
#  "护腿": "LEGS"
#  "靴子": "FEET"
#  "主手": "HAND"
#  "副手": "OFFHAND"
#读取槽位20的装备 以20th为id存入装备栏
#  "20th": "20"
#这样写可以给放到槽位的装备加限制:
#  "20th":
#    slot: 20
#    require: "槽位: 饰品"
entity: { }
#  2.1.0-beta 后已内置
#  "头盔": "HEAD"
#  "胸甲": "CHEST"
#  "护腿": "LEGS"
#  "靴子": "FEET"
#  "主手": "HAND"
#  "副手": "OFFHAND"
# 萌芽槽位
germ-slots:
  - "example"

以上是AttributeSystem所有内容

FightSystem

如果说AttributeSystem只是一副躯壳,哪么FS(FightSystem)就是一副灵魂

自定义战斗组

#战斗机制组ID
# attack-damage 普通攻击
# skill-api-技能id-标识符 SkillAPI技能
# damage-cause-id小写 伤害事件(会覆盖)
# https://bukkit.windit.net/javadoc/org/bukkit/event/entity/EntityDamageEvent.DamageCause.html
# 这3个是固定的
attack-damage:
  namespaces: [ common fightsystem ]
  #伤害类型
  Physical:
    #是否启用
    enable: true
    mechanics:
      #机制id
      - mechanic: damage
        #战斗数据
        #攻击者变量: {a.PAPI变量/PouPAPI变量}
        #防御者变量: {d.PAPI变量/PouPAPI变量}
        #PouPAPI支持存活实体
        #AS提供的变量
        # origin AS处理前的伤害 一般是原版伤害 (全局)
        # force 蓄力程度  弓箭蓄力程度 或 普攻蓄力程度 (仅attack-damage)
        # type 攻击类型 PVP PVE EVE (全局)
        # projectile 是否是远程攻击 true / false (全局)
        enable: |-
          check random 0 to 1 < calculate '{a.as_att:PhysicalHitChance}-{d.as_att:PhysicalDodgeChance}'
        value: |-
          set type = when of {type} {
            case == 'PVP' -> '{a.as_att:PVPDamage} - {d.as_att:PVPDefense}'
            case == 'PVE' -> '{a.as_att:PVEDamage} - {d.as_att:PVEDefense}'
            else -> 0
          }
          set projectile to if check {projectile} == true then '{a.as_att:ProjectileDamage} - {d.as_att:ProjectileDefense}' else '0'
          set damage to '{a.as_att:PhysicalDamage} + {origin}'
          set defense to if check random 0 to 1 < {a.as_att:PhysicalDefenseIgnore} then 0 else '{d.as_att:PhysicalDefense} - {a.as_att:PhysicalPenetration}'
          set force to if has force then {force} else 1
          calculate '{&damage} + {$type} + {&projectile} - {&defense} ) * {&force}'
      #机制从上到下按顺序执行
      - mechanic: crit
        enable: "check random 0 to 1 < {a.as_att:PhysicalCriticalChance}"
        #下面的机制数据可以调用上面已执行机制的执行结果 格式为{id}
        multiplier: |-
          calculate '{a.as_att:PhysicalCriticalMultiple} - {d.as_att:PhysicalCriticalDefense}'

      - mechanic: vampire
        enable: "check random 0 to 1 < calculate {a.as_att:VampireChance}"
        value: |-
          calculate '{a.as_att:VampireMultiple} - {d.as_att:VampireDefense}'

      - mechanic: flame
        enable: "check random 0 1 < {a.as_att:燃烧几率}"
        damage: |-
          max 1 {a.as_att:燃烧伤害}
        duration: |-
          max 20 calculate '{a.as_att:燃烧伤害}*3'

      - mechanic: frozen
        enable: "check random 0 1 < {a.as_att:冰冻几率}"
        value: |-
          max 1 {a.as_att:冰冻强度}
        duration: |-
          max 20 calculate '{a.as_att:冰冻强度}*3'

      - mechanic: thunder
        enable: "check random 0 1 < {a.as_att:雷击几率}"
        damage: "max 1 {a.as_att:雷击伤害}"

      - mechanic: rebound
        enable: "check random 0 1 < {d.as_att:反弹几率}"
        multiplier: "max 0.1 {d.as_att:反弹倍率}"

      - mechanic: shield
        enable: "check random 0 1 < calculate '1-{a.as_att:BlockingIgnore}'"
        reduce: "{d.as_att:Blocking}"
        #tick
        # {reduced}是实际减伤
        cooldown: "calculate '({reduced}/4)*20'"
  Real:
    enable: 'check {a.as_att:RealDamage} != 0.0'
    mechanics:
      - mechanic: damage
        enable: |-
          check random 0 to 1 < calculate '{a.as_att:PhysicalHitChance}-{d.as_att:PhysicalDodgeChance}'
        value: '{a.as_att:RealDamage}'

如果你不会js,你就可以玩这个,它可比市面上所有属性插件都要强大

自定义伤害显示

#伤害类型id
Physical:
  #名称
  name: "&6物理伤害"
  #伤害显示
  display:
    #攻击者
    attack:
      holo: |-
        set result to number {result}
        set crit to number {crit}
        set vampire to number {vampire}
        set common to if check &result > 0.0 then analysis "&6{format &result '#.##'}" else '&7&lMISS'
        set crit to if check &crit > 0.0 then '&4✵' else ''
        set vampire to if check &vampire > 0.0 then analysis "&a+{format &vampire '#.##'}" else ''
        join [ &crit &common &vampire ]
      chat: |-
        set result to number {result}
        set crit to number {crit}
        set vampire to number {vampire}
        set prefix to '&d{name}&5: '
        set common to if check &result > 0.0 then "&6{format &result '#.##'}" else '&7&lMISS'
        set crit to if check &crit > 0.0 then '&4✵' else ''
        set vampire to if check &vampire > 0.0 then "&a+{ format &vampire '#.##' }" else ''
        join [ &prefix &crit &common &vampire ]
      title: "null"
      sub-title: |-
        set result to number {result}
        set vampire to number {vampire}

        set crit to number {crit}
        set crit to if check &crit > 0.0 then '&4暴击' else '&4'
        set common to if check &result > 0.0 then "{&crit}                &c{ format &result '#.##' }" else '&7&lMISS'
        set vampire to if check &vampire > 0.0 then "&a+{ format &vampire '#.##' }" else ''

        join [ '!' &common &vampire ]
      action-bar: |-
        set result to number {result}
        set crit to number {crit}
        set vampire to number {vampire}

        set prefix to '&d{name}&5: '
        set common to if check &result > 0.0 then "&6{ format &result '#.##' }" else '&7&lMISS'
        set crit to if check &crit > 0.0 then '&4✵' else ''
        set vampire to if check &vampire > 0.0 then "&c吸血&a{ format &vampire '#.##' }" else ''
        join [ &prefix &crit &common &vampire ]
    defend:
      holo: |-
        set result to number {result}
        set crit to number {crit}

        set subtract to '&c- '
        set common to if check &result != 0 then "&6{format &result '#.##'}" else '&7&lMISS'
        set crit to if check &crit > 0.0 then '&4✵' else ''
        join [ &subtract &crit &common ]
      chat: |-
        set result to number {result}
        set crit to number {crit}

        set prefix to '&d{name}&5: '
        set common to if check &result != 0 then "&6{format &result '#.##'}" else '&7&lMISS'
        set crit to if check &crit > 0.0 then '&4✵' else ''
        join [ &prefix &crit &common ]
      title: |-
        set crit to number {crit}

        if check &crit != 0 then '&4受到暴击' else '&4'
      sub-title: |-
        set result to number {result}
        set vampire to number {vampire}
        set crit to if check &crit > 0.0 then '&c-&4✵ ' else '&c- '
        set common to if check &result > 0.0 then "&6{ format &result '#.##' }" else '&7&lMISS'
        join [ '!' &crit &common ]
      action-bar: |-
        set result to number {result}
        set crit to number {crit}
        set vampire to number {vampire}

        set prefix to '&d{name}&5: '
        set common to if check &result > 0.0 then "&6{ format &result '#.##' }" else '&7&lMISS'
        set crit to if check &crit > 0.0 then '&4✵' else ''
        join [ &prefix &crit &common ]

用于显示伤害,当你看到holo,chat,title,sub-title,actionbar这类用于信息输出的,你应该就明白了,FS自带一套完美的伤害显示系统!还可以让玩家个性化选择需要的伤害显示

自定义机制(JS党狂喜)

//@Mechanic(flame)
function flame(data, context, damageType) {
    const enable = data.handle(context.get("enable"));
    if (enable.toString() != "true") {
        return 0.0;
    }
    const attacker = data.attacker;
    const defender = data.defender;
    const damage = toDouble(data.handle(context.get("damage")));
    const duration = toDouble(data.handle(context.get("duration")));
    task(function (task) {
        defender.setFireTicks(duration);
    });
    data.damageSources.put("fire", Plus.element(damage));
    if (attacker instanceof Player)
        attacker.sendMessage(
            color(
                "&c&l燃烧!&f你点燃了对方,持续 &b" +
                duration / 20 +
                "s &f, 造成了&6&l" +
                damage +
                "&f点伤害!"
            )
        );
    if (defender instanceof Player)
        defender.sendMessage(
            color(
                "&c&l燃烧!&f对方点燃了你,持续 &b" +
                duration / 20 +
                "s &f, 造成了&6&l" +
                damage +
                "&f点伤害!"
            )
        );
    return damage;
}

// 冰冻

//@Mechanic(frozen)
function frozen(data, context, damageType) {
    const enable = data.handle(context.get("enable"));
    if (enable.toString() != "true") {
        return 0.0;
    }
    const attacker = data.attacker;
    const defender = data.defender;
    const value = toDouble(data.handle(context.get("value")));
    const duration = toDouble(data.handle(context.get("duration")));

    AttrAPI.addAttribute(
        defender,
        "frozen",
        listOf("移动速度: -" + value),
        false
    );
    taskLater(
        duration.longValue(),
        function (task) {
            AttrAPI.removeAttribute(defender, "frozen");
        }
    );
    if (attacker instanceof Player)
        attacker.sendMessage(
            color(
                "&b&l冰冻!&f你冰冻了对方,持续 &9" +
                duration / 20 +
                "s &f, 减少了&6&l" +
                value +
                "&f点移动速度!"
            )
        );
    if (defender instanceof Player)
        defender.sendMessage(
            color(
                "&b&l冰冻!&f对方冰冻了你,持续 &9" +
                duration / 20 +
                "s &f, 减少了&6&l" +
                value +
                "&f点移动速度!"
            )
        );
    return value;
}

// 雷击

//@Mechanic(thunder)
function thunder(data, context, damageType) {
    const enable = data.handle(context.get("enable"));
    if (enable.toString() != "true") {
        return 0.0;
    }
    const attacker = data.attacker;
    const defender = data.defender;
    const damage = toDouble(data.handle(context.get("damage")));
    task(function (task) {
        defender.world.strikeLightningEffect(defender.location);
    });
    data.damageSources.put("thunder", Plus.element(damage));
    if (attacker instanceof Player)
        attacker.sendMessage(
            color("&e&l雷击!&f你雷击了对方,造成了&6&l" + damage + "&f点伤害!")
        );
    if (defender instanceof Player)
        defender.sendMessage(
            color("&e&l雷击!&f对方雷击了你,造成了&6&l" + damage + "&f点伤害!")
        );
    return damage;
}

// 反弹
//@Mechanic(rebound)
function rebound(data, context, damageType) {
    const enable = data.handle(context.get("enable"));
    if (enable.toString() != "true") {
        return 0.0;
    }
    const attacker = data.attacker;
    const defender = data.defender;
    const multiplier = toDouble(data.handle(context.get("multiplier")));
    const damage = data.calResult() * multiplier;
    if (damage <= 0) return 0;
    task(function (task) {
        AttributeSystemAPI.skipNextDamageCal();
        attacker.damage(damage, defender);
    });
    if (attacker instanceof Player)
        attacker.sendMessage(
            color("&e&l反弹!&f对方反弹了你,造成了&6&l" + damage + "&f点伤害!")
        );
    if (defender instanceof Player)
        defender.sendMessage(
            color("&e&l反弹!&f你反弹了对方,造成了&6&l" + damage + "&f点伤害!")
        );
    return damage;
}

PotionEffectType = find("org.bukkit.potion.PotionEffectType");
PotionEffect = find("org.bukkit.potion.PotionEffect");
// 药水
//@Mechanic(potion)
function potion(data, context, damageType) {
    const enable = data.handle(context.get("enable"));
    if (enable.toString() != "true") {
        return 0.0;
    }
    const attacker = data.attacker;
    const defender = data.defender;
    const type = toDouble(data.handle(context.get("type")));
    if (Data.containsKey(attacker.uniqueId + type)) return -1;
    const potionType = PotionEffectType.getByName(type);
    if (potionType == null) return -2;
    const level = toDouble(data.handle(context.get("level")));
    const duration = toDouble(data.handle(context.get("duration")));
    const cooldown = toDouble(data.handle(context.get("cooldown")));
    task(function (task) {
        Data.put(attacker.uniqueId + type, true);
        defender.addPotionEffect(new PotionEffect(potionType, duration, level));
    });
    taskLater(
        cooldown,
        function (task) {
            Data.remove(attacker.uniqueId + type);
        }
    );
    return duration;
}
function toDouble(obj) {
    if (obj === null || typeof obj === "undefined") {
        return 0.0;
    }
    if (typeof obj === "number" || obj instanceof Number) {
        return Number(obj);
    }
    var parsed = parseFloat(obj);
    if (!isNaN(parsed)) {
        return parsed;
    }
    return 0.0;
}

依赖Pouvoir强大的JS系统与脚本注解系统,可以快速自定义一个机制!


玩家个性化系统

允许玩家选择自定义的messagetype,目前自带的有holo,chat,title,sub-title,actionbar,当然了,也可以使用脚本注解进行拓展

支持的插件

  • MythicMobs
  • 龙核
  • 萌芽
  • Magic
  • crackshot枪械
  • PVPManager
  • SkillAPI
    MythicMobs支持技能,甚至怪物普攻的替换
    龙核萌芽支持伤害显示与槽位
    Magic支持技能的战斗机制组
    枪械支持自定义战斗机制组
    SkillAPI支持自定义战斗机制组

未来计划

  1. 迁移至Minestom核心,目前SkillW已经在写RPGMaker与DevoutServer,RPGMaker是转为RPG服务器所写的多线程服务端核心,预计2025年下半年完成
  2. 提提建议,多提issues

下载

相关链接

相关链接

Github https://github.com/Glom-c/AttributeSystem
QQ群 https://qm.qq.com/q/2kaZq7PEqo
WIKI https://www.skillw.com/zh-CN/docs/attsystem/intro
JavaDoc http://doc.skillw.com/attsystem/
爱发电 https://afdian.net/@glom_


附属列表

最后

感谢所有AttributeSystem & FightSystem项目的贡献者

如果你喜欢该项目,不妨评个分 把项目star一下

(0)
clokLv1-土块

帖子地址: 

发表回复

使用道具 举报