feat(fight): 实现属性变化还原机制并优化属性操作逻辑

- 为多个效果(effect_38、effect_45、effect_51、effect_55、effect_56)添加 `Alive` 方法,
  用于在效果结束时还原精灵被修改的属性(如 MaxHp、Prop[0]、Prop[1]、PetInfo.Type)。
- 统一将对精灵属性类型的访问由 `PType` 修改为 `PetInfo.Type`,提升代码一致性与可维护性。
- 移除旧的回合开始/结束时手动保存和还原精灵信息的逻辑
This commit is contained in:
2025-11-15 00:15:09 +08:00
parent a86782b1ea
commit d73eb9eb26
12 changed files with 206 additions and 187 deletions

View File

@@ -31,7 +31,7 @@ func (e *Effect38) OnSkill() bool {
// 命中之后
func (e *Effect38_sub) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
if uint32(e.Args()[0]) < e.Ctx().Our.CurrentPet.Info.MaxHp {
e.oldtype = e.Ctx().Our.CurrentPet.Info.MaxHp
e.Ctx().Our.CurrentPet.Info.MaxHp -= uint32(e.Args()[0])
}
@@ -42,6 +42,21 @@ func (e *Effect38_sub) Switch(in *input.Input, at info.AttackValue, oldpet *info
type Effect38_sub struct {
node.EffectNode
oldtype uint32
}
func (e *Effect38_sub) Alive(t ...bool) bool {
if !e.Hit() {
return e.EffectNode.Alive()
}
e.EffectNode.Alive(t...)
if len(t) > 0 {
if !t[0] { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.MaxHp = e.oldtype
}
}
return e.EffectNode.Alive()
}
func init() {

View File

@@ -11,6 +11,7 @@ import (
*/
type Effect45 struct {
node.EffectNode
oldtype uint32
}
func (e *Effect45) OnSkill() bool {
@@ -24,6 +25,7 @@ func (e *Effect45) Turn_Start(fattack *action.SelectSkillAction, sattack *action
if !e.Hit() {
return
}
e.oldtype = e.Ctx().Opp.CurrentPet.Info.Prop[1]
e.Ctx().Our.CurrentPet.Info.Prop[1] = e.Ctx().Opp.CurrentPet.Info.Prop[1]
}
func init() {
@@ -38,3 +40,16 @@ func (e *Effect45) SetArgs(t *input.Input, a ...int) {
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect45) Alive(t ...bool) bool {
if !e.Hit() {
return e.EffectNode.Alive()
}
e.EffectNode.Alive(t...)
if len(t) > 0 {
if !t[0] { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.Prop[1] = e.oldtype
}
}
return e.EffectNode.Alive()
}

View File

@@ -11,6 +11,7 @@ import (
*/
type Effect51 struct {
node.EffectNode
oldtype uint32
}
func (e *Effect51) OnSkill() bool {
@@ -24,6 +25,7 @@ func (e *Effect51) Turn_Start(fattack *action.SelectSkillAction, sattack *action
if !e.Hit() {
return
}
e.oldtype = e.Ctx().Opp.CurrentPet.Info.Prop[0]
e.Ctx().Our.CurrentPet.Info.Prop[0] = e.Ctx().Opp.CurrentPet.Info.Prop[0]
}
func init() {
@@ -38,3 +40,16 @@ func (e *Effect51) SetArgs(t *input.Input, a ...int) {
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect51) Alive(t ...bool) bool {
if !e.Hit() {
return e.EffectNode.Alive()
}
e.EffectNode.Alive(t...)
if len(t) > 0 {
if !t[0] { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.Prop[0] = e.oldtype
}
}
return e.EffectNode.Alive()
}

View File

@@ -24,7 +24,7 @@ func (e *Effect55) Turn_Start(fattack *action.SelectSkillAction, sattack *action
if !e.Hit() {
return
}
e.Ctx().Our.CurrentPet.PType, e.Ctx().Opp.CurrentPet.PType = e.Ctx().Opp.CurrentPet.PType, e.Ctx().Our.CurrentPet.PType
e.Ctx().Our.CurrentPet.PetInfo.Type, e.Ctx().Opp.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type, e.Ctx().Our.CurrentPet.PetInfo.Type
}
func init() {
ret := &Effect55{}
@@ -38,3 +38,15 @@ func (e *Effect55) SetArgs(t *input.Input, a ...int) {
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect55) Alive(t ...bool) bool {
if !e.Hit() {
return e.EffectNode.Alive()
}
e.EffectNode.Alive(t...)
if len(t) > 0 {
if !t[0] { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
e.Ctx().Our.CurrentPet.PetInfo.Type, e.Ctx().Opp.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type, e.Ctx().Our.CurrentPet.PetInfo.Type
}
}
return e.EffectNode.Alive()
}

View File

@@ -11,6 +11,7 @@ import (
*/
type Effect56 struct {
node.EffectNode
oldtype int
}
func (e *Effect56) OnSkill() bool {
@@ -24,7 +25,8 @@ func (e *Effect56) Turn_Start(fattack *action.SelectSkillAction, sattack *action
if !e.Hit() {
return
}
e.Ctx().Our.CurrentPet.PType = e.Ctx().Opp.CurrentPet.PType
e.oldtype = e.Ctx().Opp.CurrentPet.PetInfo.Type
e.Ctx().Our.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type
}
func init() {
ret := &Effect56{}
@@ -38,3 +40,16 @@ func (e *Effect56) SetArgs(t *input.Input, a ...int) {
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect56) Alive(t ...bool) bool {
if !e.Hit() {
return e.EffectNode.Alive()
}
e.EffectNode.Alive(t...)
if len(t) > 0 {
if !t[0] { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.PetInfo.Type = e.oldtype
}
}
return e.EffectNode.Alive()
}

View File

@@ -98,7 +98,7 @@ func conditionIsFrozen(e *EffectConditionalAddDamage) bool {
// conditionIsTypeX判断对方是否为X属性需根据实际属性枚举调整
func conditionIsTypeX(e *EffectConditionalAddDamage) bool {
// 示例假设Args[0]为目标属性值,判断对方属性是否匹配
return e.Ctx().Opp.CurrentPet.PType == e.Args()[0]
return e.Ctx().Opp.CurrentPet.PetInfo.Type == e.Args()[0]
}
// conditionIsAbnormal判断对方是否处于任意异常状态

View File

@@ -78,7 +78,7 @@ func init() {
return o.StatEffect_Exist(info.PetStatus.Sleep)
})
registerStatusFunc(401, func(i, o *input.Input) bool {
return i.CurrentPet.PType == o.CurrentPet.PType
return i.CurrentPet.PetInfo.Type == o.CurrentPet.PetInfo.Type
})
}

View File

@@ -128,26 +128,24 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
// 神罗、圣华登场时魂免“登场时xx”等效果
//阿枫的效果也在这里判断
var oldpet [2]*model.PetInfo
var oldpettype [2]int
var oldhp [2]uint32
var oldskill [2][]model.SkillInfo
// var oldpet [2]*model.PetInfo
oldpet[0], oldpet[1] = f.copypet(f.Our.CurrentPet.Info), f.copypet(f.Opp.CurrentPet.Info)
// var oldhp [2]uint32
// var oldskill [2][]model.SkillInfo
oldpettype[0], oldpettype[1] = f.Our.CurrentPet.PType, f.Opp.CurrentPet.PType
// oldpet[0], oldpet[1] = f.copypet(f.Our.CurrentPet.Info), f.copypet(f.Opp.CurrentPet.Info)
fmt.Println("开始时对方最大体力值", f.Opp.CurrentPet.Info.MaxHp)
defer func() {
oldhp[0], oldhp[1] = f.Opp.CurrentPet.Info.Hp, f.Our.CurrentPet.Info.Hp
oldskill[0], oldskill[1] = f.Opp.CurrentPet.Info.SkillList, f.Our.CurrentPet.Info.SkillList
f.Our.CurrentPet.Info, f.Opp.CurrentPet.Info = oldpet[0], oldpet[1] //还原精灵信息
f.Opp.CurrentPet.Info.Hp, f.Our.CurrentPet.Info.Hp = oldhp[0], oldhp[1]
f.Opp.CurrentPet.Info.SkillList, f.Our.CurrentPet.Info.SkillList = oldskill[0], oldskill[1]
f.Our.CurrentPet.PType, f.Opp.CurrentPet.PType = oldpettype[0], oldpettype[1] //还原精灵属性
fmt.Println("结束时对方最大体力值", f.Opp.CurrentPet.Info.MaxHp)
// fmt.Println("开始时对方最大体力值", f.Opp.CurrentPet.Info.MaxHp)
// defer func() {
// oldhp[0], oldhp[1] = f.Opp.CurrentPet.Info.Hp, f.Our.CurrentPet.Info.Hp
// oldskill[0], oldskill[1] = f.Opp.CurrentPet.Info.SkillList, f.Our.CurrentPet.Info.SkillList
// f.Our.CurrentPet.Info, f.Opp.CurrentPet.Info = oldpet[0], oldpet[1] //还原精灵信息
// f.Opp.CurrentPet.Info.Hp, f.Our.CurrentPet.Info.Hp = oldhp[0], oldhp[1]
// f.Opp.CurrentPet.Info.SkillList, f.Our.CurrentPet.Info.SkillList = oldskill[0], oldskill[1]
}()
// fmt.Println("结束时对方最大体力值", f.Opp.CurrentPet.Info.MaxHp)
// }()
f.Our.Exec(func(t input.Effect) bool { //回合开始前
//结算状态

View File

@@ -26,7 +26,7 @@ type BattlePetEntity struct {
xmlres.PetInfo
Info *model.PetInfo //通过偏移赋值
//*input.Input
PType int
//PType int
statusConditions sync.Map // key: StatusCondition, value: int (剩余回合)
Skills [4]*SkillEntity // 技能槽最多4个技能
//Status StatusDict //精灵的状态
@@ -49,15 +49,6 @@ func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Rand) *BattlePetEntit
}
ret.PType = 8
for _, v := range xmlres.PetMAP {
if v.ID == int(ret.Info.ID) {
ret.PType = v.Type
break
}
}
return ret
}
@@ -100,7 +91,7 @@ func (u *BattlePetEntity) Type() *element.ElementCombination {
// 1. 遍历宠物配置查找对应元素类型ID
// 3. 从预加载的组合池中获取实例(无需创建,直接读取)
combo, err := element.Calculator.GetCombination(u.PType)
combo, err := element.Calculator.GetCombination(u.PetInfo.Type)
if err != nil {
// 极端情况typeID无效强制使用默认普通属性
// (从池中获取默认值,确保实例一致性)

View File

@@ -41,8 +41,8 @@ type Effect interface {
// OnOwnerSwitchIn() bool // 所属玩家精灵出战时触发
// OnOwnerSwitchOut() bool // 所属玩家精灵下场时触发
Turn_End() //回合结束计算
PreBattleEnd() bool //战斗结束前
Turn_End() //回合结束计算
//PreBattleEnd() bool //战斗结束前
OnBattleEnd() bool //战斗结束
Prop_Befer(in *Input, prop, level int8, ptype info.EnumAbilityOpType) bool //锁定属性
//效果添加时候应该区分主动方和被动方来确认是主动添加的还是受击添加的

View File

@@ -6,168 +6,120 @@ import (
"fmt"
)
// SetProp 处理属性操作(提升/下降/消除/偷取等)
// our当前执行操作的主体操作发起方
// target输入源操作的源头输入对象可能是我方或对方
// prop属性类型
// level操作幅度强化/弱化的程度)
// opType操作类型明确区分提升/下降/消除等)
func (our *Input) SetProp(target *Input, prop int8, level int8, opType info.EnumAbilityOpType) bool {
// 前置检查:输入源是否允许该操作(基于输入源的状态)
if !our.checkPreCondition(target, prop, level, opType) {
return false
}
// 根据操作类型处理(明确区分不同操作的逻辑)
switch opType {
case info.AbilityOpType.ADD: // 能力提升(强化):仅正向增加,不处理负数
return our.handleStrengthen(target, prop, level)
case info.AbilityOpType.SUB: // 能力下降(弱化):仅负向减少,不处理正数
return our.handleWeaken(target, prop, level)
case info.AbilityOpType.RESET: // 能力消除重置清除强化或弱化恢复0
return our.handleReset(target, prop, level)
case info.AbilityOpType.StealStrengthen: // 偷取强化:从对方输入源偷取到自身
return our.handleStealStrengthen(target, prop)
case info.AbilityOpType.Reverse: // 反转:强化转弱化,弱化转强化
return our.handleReverse(target, prop, level)
case info.AbilityOpType.BounceWeaken: // 反弹弱化:将输入源的弱化反弹给对方
return our.handleBounceWeaken(target, prop)
case info.AbilityOpType.COPY: // 复制:复制对方属性到输入源
return our.handleCopy(target, prop)
default:
return false
}
}
// checkPreCondition 检查输入源是否允许操作(基于输入源的状态)
func (our *Input) checkPreCondition(inputSource *Input, prop, level int8, opType info.EnumAbilityOpType) bool {
return our.Exec(func(e Effect) bool {
// 检查输入源是否允许该操作e.Prop_Befer的参数是输入源
return e.Prop_Befer(inputSource, prop, level, opType)
// 攻击,防御,特攻,特防,速度,命中
// 施加方source属性类型prop等级level操作类别opType返回是否成功
func (target *Input) SetProp(source *Input, prop, level int8, opType info.EnumAbilityOpType) bool {
// 前置状态结算:判断是否允许执行属性操作
canExecute := target.Exec(func(effect Effect) bool {
// 执行前置效果返回true表示可以继续操作
return effect.Prop_Befer(source, prop, level, opType)
})
}
if !canExecute {
return false
}
// ------------------------------
// 1. 能力提升强化仅处理正向增加上限6
// ------------------------------
func (our *Input) handleStrengthen(inputSource *Input, prop, level int8) bool {
if level <= 0 {
fmt.Printf("强化失败幅度必须为正数level=%d\n", level)
return false
}
current := inputSource.AttackValue.Prop[prop]
newVal := utils.Min(current+level, 6) // 强化上限6
if newVal == current {
fmt.Printf("属性[%d]强化无变化(当前%d已达上限6\n", prop, current)
return false
}
inputSource.AttackValue.Prop[prop] = newVal
fmt.Printf("属性[%d]强化:%d → %d+%d\n", prop, current, newVal, level)
return true
}
var newValue int8
// 计算新属性值并判断操作是否有效(属性是否会发生变化)
calcNewValue := func(p, l int8, t info.EnumAbilityOpType) bool {
switch t {
case info.AbilityOpType.ADD:
// 属性提升上限为6
newValue = utils.Min(target.AttackValue.Prop[p]+l, 6)
if newValue > target.AttackValue.Prop[p] {
fmt.Println("属性值会增加")
return true
}
fmt.Println("属性值不会增加")
return false
// ------------------------------
// 2. 能力下降(弱化):仅处理负向减少,下限-6
// ------------------------------
func (our *Input) handleWeaken(inputSource *Input, prop, level int8) bool {
if level >= 0 {
fmt.Printf("弱化失败幅度必须为负数level=%d\n", level)
return false
}
current := inputSource.AttackValue.Prop[prop]
newVal := utils.Max(current+level, -6) // 弱化下限-6
if newVal == current {
fmt.Printf("属性[%d]弱化无变化(当前%d已达下限-6\n", prop, current)
return false
}
inputSource.AttackValue.Prop[prop] = newVal
fmt.Printf("属性[%d]弱化:%d → %d%d\n", prop, current, newVal, level)
return true
}
case info.AbilityOpType.SUB:
// 属性降低,下限-6
newValue = utils.Max(target.AttackValue.Prop[p]+l, -6)
if newValue < target.AttackValue.Prop[p] {
fmt.Println("属性值会减少")
return true
}
fmt.Println("属性值不会减少")
return false
// ------------------------------
// 3. 能力消除(重置):仅清除对应状态(强化/弱化),不影响正常状态
// ------------------------------
func (our *Input) handleReset(inputSource *Input, prop, level int8) bool {
current := inputSource.AttackValue.Prop[prop]
// 规则level>0清除强化current>0level<0清除弱化current<0不处理正常状态current=0
if (level > 0 && current <= 0) || (level < 0 && current >= 0) {
fmt.Printf("重置失败:属性[%d]当前状态(%d与操作level=%d不匹配\n", prop, current, level)
case info.AbilityOpType.RESET:
// 重置属性level>0时清除强化属性>0则置0level<0时清除弱化属性<0则置0
if (level > 0 && target.AttackValue.Prop[p] > 0) ||
(level < 0 && target.AttackValue.Prop[p] < 0) {
newValue = 0
return true
}
return false
}
return false
}
inputSource.AttackValue.Prop[prop] = 0
fmt.Printf("属性[%d]重置:%d → 0level=%d\n", prop, current, level)
return true
}
// ------------------------------
// 4. 偷取强化:从对方输入源偷取强化到自身输入源
// ------------------------------
func (our *Input) handleStealStrengthen(inputSource *Input, prop int8) bool {
// 对方输入源的强化值(必须为正)
oppProp := our.Opp.AttackValue.Prop[prop]
if oppProp <= 0 {
fmt.Printf("偷取失败:对方属性[%d]无强化(%d\n", prop, oppProp)
switch opType {
case info.AbilityOpType.StealStrengthen:
// 窃取强化:获取对手的强化属性并转移到自身
oppProp := target.Opp.AttackValue.Prop[prop]
if oppProp <= 0 { // 对手无强化,无法窃取
return false
}
// 尝试添加对手的强化值到自身
if calcNewValue(prop, oppProp, info.AbilityOpType.ADD) {
target.AttackValue.Prop[prop] = newValue
// 窃取后清除对手的强化
target.Opp.SetProp(source, prop, 1, info.AbilityOpType.RESET)
return true
}
return false
}
// 自身输入源增加偷取的强化值
if !our.handleStrengthen(inputSource, prop, oppProp) {
return false
}
// 清除对方输入源的强化用level>0重置
our.Opp.SetProp(our.Opp, prop, 1, info.AbilityOpType.RESET)
return true
}
// ------------------------------
// 5. 反转:输入源的强化转弱化,或弱化转强化
// ------------------------------
func (our *Input) handleReverse(inputSource *Input, prop, level int8) bool {
current := inputSource.AttackValue.Prop[prop]
switch {
case level > 0 && current > 0: // 强化转弱化幅度为当前强化值的2倍
// 例:当前+2 → 弱化-4level>0指定强化转弱化
return our.handleWeaken(inputSource, prop, -current*2)
case level < 0 && current < 0: // 弱化转强化幅度为当前弱化值的2倍
// 例:当前-2 → 强化+4level<0指定弱化转强化
return our.handleStrengthen(inputSource, prop, -current*2)
case info.AbilityOpType.Reverse:
currentProp := target.AttackValue.Prop[prop]
if level > 0 { // 反转强化(仅当有强化时生效)
if currentProp <= 0 {
return false
}
// 强化反转当前值currentProp → -currentProp调整量为-2*currentProp
if calcNewValue(prop, -2*currentProp, info.AbilityOpType.ADD) {
target.AttackValue.Prop[prop] = newValue
return true
}
return false
} else { // 反转弱化(仅当有弱化时生效)
if currentProp >= 0 {
return false
}
// 弱化反转当前值currentProp → -currentProp调整量为-2*currentProp
if calcNewValue(prop, -2*currentProp, info.AbilityOpType.ADD) {
target.AttackValue.Prop[prop] = newValue
return true
}
return false
}
case info.AbilityOpType.BounceWeaken:
// 反弹弱化:将自身弱化转移给对手并清除自身弱化
currentProp := target.AttackValue.Prop[prop]
if currentProp >= 0 { // 无弱化可反弹
return false
}
// 向对手施加同等弱化
if target.Opp.SetProp(source, prop, currentProp, info.AbilityOpType.SUB) {
// 清除自身弱化
target.SetProp(source, prop, -1, info.AbilityOpType.RESET)
return true
}
return false
case info.AbilityOpType.COPY:
// 复制对手属性:将自身属性调整为与对手一致(在范围内)
oppProp := target.Opp.AttackValue.Prop[prop]
adjustLevel := oppProp - target.AttackValue.Prop[prop]
return target.SetProp(source, prop, adjustLevel, info.AbilityOpType.ADD)
default:
fmt.Printf("反转失败:当前值(%d与操作方向level=%d不匹配\n", current, level)
// 处理常规操作ADD/SUB/RESET
if calcNewValue(prop, level, opType) {
target.AttackValue.Prop[prop] = newValue
return true
}
return false
}
}
// ------------------------------
// 6. 反弹弱化:将输入源的弱化反弹给对方,同时清除输入源的弱化
// ------------------------------
func (our *Input) handleBounceWeaken(inputSource *Input, prop int8) bool {
// 输入源的弱化值(必须为负)
currentWeak := inputSource.AttackValue.Prop[prop]
if currentWeak >= 0 {
fmt.Printf("反弹失败:输入源属性[%d]无弱化(%d\n", prop, currentWeak)
return false
}
// 反弹给对方:对方输入源承受相同弱化(用弱化操作)
if !our.Opp.SetProp(our.Opp, prop, currentWeak, info.AbilityOpType.SUB) {
return false
}
// 清除输入源的弱化用level<0重置
return our.handleReset(inputSource, prop, -1)
}
// ------------------------------
// 7. 复制:将对方属性复制到输入源(强化/弱化均复制)
// ------------------------------
func (our *Input) handleCopy(inputSource *Input, prop int8) bool {
oppProp := our.Opp.AttackValue.Prop[prop]
if oppProp == 0 {
fmt.Printf("复制无变化:对方属性[%d]为0\n", prop)
return true // 无变化也算成功
}
// 根据对方属性类型选择强化/弱化操作
if oppProp > 0 {
return our.handleStrengthen(inputSource, prop, oppProp) // 复制强化
} else {
return our.handleWeaken(inputSource, prop, oppProp) // 复制弱化oppProp是负数
}
}

View File

@@ -38,11 +38,17 @@ func (f *FightC) battleLoop() {
}
f.Broadcast(func(ff *input.Input) {
//todo 将血量和技能pp传回enterturn
//todo 将血量和技能pp传回enterturn
ff.Exec(func(tt input.Effect) bool {
tt.OnBattleEnd()
tt.Alive(false) //将所有属性变化失效掉
return true
})
ff.Player.SendFightEndInfo(f.FightOverInfo)
})
close(f.actionChan)
fmt.Println("战斗循环结束")
close(f.over)