战斗切精灵失效bug待修复
This commit is contained in:
@@ -95,9 +95,9 @@ var dualElementMap = map[int][2]int{
|
||||
|
||||
// 元素组合结构体
|
||||
type ElementCombination struct {
|
||||
primary ElementType // 主属性(1-17)
|
||||
secondary *ElementType // 副属性(1-17,双属性时非空)
|
||||
id int // 组合ID
|
||||
Primary ElementType // 主属性(1-17)
|
||||
Secondary *ElementType // 副属性(1-17,双属性时非空)
|
||||
ID int // 组合ID
|
||||
}
|
||||
|
||||
// 创建元素组合(严格验证范围)
|
||||
@@ -116,9 +116,9 @@ func NewElementCombination(id int) (*ElementCombination, error) {
|
||||
primary, secondary = secondary, primary
|
||||
}
|
||||
return &ElementCombination{
|
||||
primary: primary,
|
||||
secondary: &secondary,
|
||||
id: id,
|
||||
Primary: primary,
|
||||
Secondary: &secondary,
|
||||
ID: id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -126,36 +126,36 @@ func NewElementCombination(id int) (*ElementCombination, error) {
|
||||
return nil, fmt.Errorf("单属性ID必须为1-17,实际: %d", id)
|
||||
}
|
||||
return &ElementCombination{
|
||||
primary: ElementType(id),
|
||||
secondary: nil,
|
||||
id: id,
|
||||
Primary: ElementType(id),
|
||||
Secondary: nil,
|
||||
ID: id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 判断是否为双属性
|
||||
func (ec *ElementCombination) IsDual() bool {
|
||||
return ec.secondary != nil
|
||||
return ec.Secondary != nil
|
||||
}
|
||||
|
||||
// 获取所有属性
|
||||
func (ec *ElementCombination) Elements() []ElementType {
|
||||
if ec.IsDual() {
|
||||
return []ElementType{ec.primary, *ec.secondary}
|
||||
return []ElementType{ec.Primary, *ec.Secondary}
|
||||
}
|
||||
return []ElementType{ec.primary}
|
||||
return []ElementType{ec.Primary}
|
||||
}
|
||||
|
||||
// 缓存键
|
||||
func (ec *ElementCombination) CacheKey() string {
|
||||
return fmt.Sprintf("id_%d", ec.id)
|
||||
return fmt.Sprintf("id_%d", ec.ID)
|
||||
}
|
||||
|
||||
// 字符串展示
|
||||
func (ec *ElementCombination) String() string {
|
||||
if ec.IsDual() {
|
||||
return fmt.Sprintf("(%v, %v)", ec.primary, *ec.secondary)
|
||||
return fmt.Sprintf("(%v, %v)", ec.Primary, *ec.Secondary)
|
||||
}
|
||||
return fmt.Sprintf("(%vv)", ec.primary)
|
||||
return fmt.Sprintf("(%vv)", ec.Primary)
|
||||
}
|
||||
|
||||
// 元素计算器(全属性支持+缓存)
|
||||
@@ -375,85 +375,85 @@ func (c *ElementCalculator) GetOffensiveMultiplier(attackerXID, defenderYID int)
|
||||
|
||||
// 核心计算逻辑(严格遵循橙汁学姐规则)
|
||||
func (c *ElementCalculator) calculateMultiplier(attackerX, defenderY *ElementCombination) float64 {
|
||||
// 1. 单属性→单属性:直接查表
|
||||
if !attackerX.IsDual() && !defenderY.IsDual() {
|
||||
return c.tableMatrix[attackerX.primary][defenderY.primary]
|
||||
}
|
||||
// 1. 单属性→单属性:直接查表
|
||||
if !attackerX.IsDual() && !defenderY.IsDual() {
|
||||
return c.tableMatrix[attackerX.Primary][defenderY.Primary]
|
||||
}
|
||||
|
||||
// 2. 单属性→双属性:拆分防守方,分类计算
|
||||
if !attackerX.IsDual() {
|
||||
y1, y2 := defenderY.primary, *defenderY.secondary
|
||||
m1 := c.tableMatrix[attackerX.primary][y1]
|
||||
m2 := c.tableMatrix[attackerX.primary][y2]
|
||||
// 2. 单属性→双属性:拆分防守方,分类计算
|
||||
if !attackerX.IsDual() {
|
||||
y1, y2 := defenderY.Primary, *defenderY.Secondary
|
||||
m1 := c.tableMatrix[attackerX.Primary][y1]
|
||||
m2 := c.tableMatrix[attackerX.Primary][y2]
|
||||
|
||||
// 单→双规则:双克制=4,含无效÷4,其他÷2
|
||||
if m1 == 2 && m2 == 2 {
|
||||
return 4.0
|
||||
} else if m1 == 0 || m2 == 0 {
|
||||
return (m1 + m2) / 4.0
|
||||
} else {
|
||||
return (m1 + m2) / 2.0
|
||||
}
|
||||
}
|
||||
// 单→双规则:双克制=4,含无效÷4,其他÷2
|
||||
if m1 == 2 && m2 == 2 {
|
||||
return 4.0
|
||||
} else if m1 == 0 || m2 == 0 {
|
||||
return (m1 + m2) / 4.0
|
||||
} else {
|
||||
return (m1 + m2) / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 双属性→单属性:拆分攻击方,分类计算
|
||||
if !defenderY.IsDual() {
|
||||
x1, x2 := attackerX.primary, *attackerX.secondary
|
||||
k1 := c.tableMatrix[x1][defenderY.primary]
|
||||
k2 := c.tableMatrix[x2][defenderY.primary]
|
||||
// 3. 双属性→单属性:拆分攻击方,分类计算
|
||||
if !defenderY.IsDual() {
|
||||
x1, x2 := attackerX.Primary, *attackerX.Secondary
|
||||
k1 := c.tableMatrix[x1][defenderY.Primary]
|
||||
k2 := c.tableMatrix[x2][defenderY.Primary]
|
||||
|
||||
// 补全默认值(未定义的普通关系为1.0)
|
||||
if k1 == 0 && c.tableMatrix[x1][defenderY.primary] != 0 {
|
||||
k1 = 1.0
|
||||
}
|
||||
if k2 == 0 && c.tableMatrix[x2][defenderY.primary] != 0 {
|
||||
k2 = 1.0
|
||||
}
|
||||
// 补全默认值(未定义的普通关系为1.0)
|
||||
if k1 == 0 && c.tableMatrix[x1][defenderY.Primary] != 0 {
|
||||
k1 = 1.0
|
||||
}
|
||||
if k2 == 0 && c.tableMatrix[x2][defenderY.Primary] != 0 {
|
||||
k2 = 1.0
|
||||
}
|
||||
|
||||
// 双→单规则:双克制=4,含无效÷4,其他÷2
|
||||
if k1 == 2 && k2 == 2 {
|
||||
return 4.0
|
||||
} else if k1 == 0 || k2 == 0 {
|
||||
return (k1 + k2) / 4.0
|
||||
} else {
|
||||
return (k1 + k2) / 2.0
|
||||
}
|
||||
}
|
||||
// 双→单规则:双克制=4,含无效÷4,其他÷2
|
||||
if k1 == 2 && k2 == 2 {
|
||||
return 4.0
|
||||
} else if k1 == 0 || k2 == 0 {
|
||||
return (k1 + k2) / 4.0
|
||||
} else {
|
||||
return (k1 + k2) / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 双属性→双属性:拆分防守方为两个单属性,分别计算双→单后取平均
|
||||
x1, x2 := attackerX.primary, *attackerX.secondary
|
||||
y1, y2 := defenderY.primary, *defenderY.secondary
|
||||
// 4. 双属性→双属性:拆分防守方为两个单属性,分别计算双→单后取平均
|
||||
x1, x2 := attackerX.Primary, *attackerX.Secondary
|
||||
y1, y2 := defenderY.Primary, *defenderY.Secondary
|
||||
|
||||
// 计算攻击方对防守方第一个单属性(y1)的双→单系数
|
||||
coeffY1 := c.calculateDualToSingle(x1, x2, y1)
|
||||
// 计算攻击方对防守方第二个单属性(y2)的双→单系数
|
||||
coeffY2 := c.calculateDualToSingle(x1, x2, y2)
|
||||
// 计算攻击方对防守方第一个单属性(y1)的双→单系数
|
||||
coeffY1 := c.calculateDualToSingle(x1, x2, y1)
|
||||
// 计算攻击方对防守方第二个单属性(y2)的双→单系数
|
||||
coeffY2 := c.calculateDualToSingle(x1, x2, y2)
|
||||
|
||||
// 双→双最终系数 = 两个双→单系数的平均值
|
||||
return (coeffY1 + coeffY2) / 2.0
|
||||
// 双→双最终系数 = 两个双→单系数的平均值
|
||||
return (coeffY1 + coeffY2) / 2.0
|
||||
}
|
||||
|
||||
// 辅助函数:双属性攻击单属性的核心计算(提取复用逻辑)
|
||||
func (c *ElementCalculator) calculateDualToSingle(attacker1, attacker2, defender ElementType) float64 {
|
||||
k1 := c.tableMatrix[attacker1][defender]
|
||||
k2 := c.tableMatrix[attacker2][defender]
|
||||
k1 := c.tableMatrix[attacker1][defender]
|
||||
k2 := c.tableMatrix[attacker2][defender]
|
||||
|
||||
// 补全默认值(未定义的普通关系为1.0)
|
||||
if k1 == 0 && c.tableMatrix[attacker1][defender] != 0 {
|
||||
k1 = 1.0
|
||||
}
|
||||
if k2 == 0 && c.tableMatrix[attacker2][defender] != 0 {
|
||||
k2 = 1.0
|
||||
}
|
||||
// 补全默认值(未定义的普通关系为1.0)
|
||||
if k1 == 0 && c.tableMatrix[attacker1][defender] != 0 {
|
||||
k1 = 1.0
|
||||
}
|
||||
if k2 == 0 && c.tableMatrix[attacker2][defender] != 0 {
|
||||
k2 = 1.0
|
||||
}
|
||||
|
||||
// 双→单规则应用
|
||||
if k1 == 2 && k2 == 2 {
|
||||
return 4.0
|
||||
} else if k1 == 0 || k2 == 0 {
|
||||
return (k1 + k2) / 4.0
|
||||
} else {
|
||||
return (k1 + k2) / 2.0
|
||||
}
|
||||
// 双→单规则应用
|
||||
if k1 == 2 && k2 == 2 {
|
||||
return 4.0
|
||||
} else if k1 == 0 || k2 == 0 {
|
||||
return (k1 + k2) / 4.0
|
||||
} else {
|
||||
return (k1 + k2) / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
// 全场景测试用例
|
||||
|
||||
@@ -54,7 +54,7 @@ func (h *Controller) PetRelease(
|
||||
t := blservice.NewUserService(c.Info.UserID).PetM(int(data.CatchTime), int(data.Flag))
|
||||
switch data.Flag {
|
||||
case 0:
|
||||
//todo 仓库
|
||||
|
||||
removeIndex := -1
|
||||
for i, v := range c.Info.PetList {
|
||||
if v.CatchTime == uint32(data.CatchTime) {
|
||||
@@ -66,16 +66,16 @@ func (h *Controller) PetRelease(
|
||||
if removeIndex != -1 {
|
||||
c.Info.PetList = append(c.Info.PetList[:removeIndex], c.Info.PetList[removeIndex+1:]...)
|
||||
}
|
||||
if len(c.Info.PetList) > 0 {
|
||||
result.FirstPetTime = c.Info.PetList[0].CatchTime //设置首发
|
||||
}
|
||||
|
||||
case 1:
|
||||
//todo 背包
|
||||
c.Info.PetList = append(c.Info.PetList, t)
|
||||
result.PetInfo = t
|
||||
}
|
||||
|
||||
}
|
||||
if len(c.Info.PetList) > 0 {
|
||||
result.FirstPetTime = c.Info.PetList[0].CatchTime //设置首发
|
||||
}
|
||||
//service.NewUserService(c.Info.UserID).PetAdd( *r)
|
||||
return result, 0
|
||||
}
|
||||
|
||||
@@ -39,6 +39,26 @@ func (a *BattlePetEntity) Value(tt uint32) uint32 {
|
||||
func (a *BattlePetEntity) Speed() uint32 {
|
||||
return uint32(calculateRealValue(int64(a.Info.Speed), int(a.Prop.Speed)))
|
||||
|
||||
}
|
||||
func (a *BattlePetEntity) Attack() uint32 {
|
||||
return uint32(calculateRealValue(int64(a.Info.Attack), int(a.Prop.Attack)))
|
||||
|
||||
}
|
||||
func (a *BattlePetEntity) Defense() uint32 {
|
||||
return uint32(calculateRealValue(int64(a.Info.Defence), int(a.Prop.Defence)))
|
||||
|
||||
}
|
||||
func (a *BattlePetEntity) SAttack() uint32 {
|
||||
return uint32(calculateRealValue(int64(a.Info.SpecialAttack), int(a.Prop.SpecialAttack)))
|
||||
|
||||
}
|
||||
func (a *BattlePetEntity) SDefense() uint32 {
|
||||
return uint32(calculateRealValue(int64(a.Info.SpecialDefence), int(a.Prop.SpecialDefence)))
|
||||
|
||||
}
|
||||
func (a *BattlePetEntity) Accuracy(b int64) uint32 {
|
||||
return uint32(calculateRealValue(b, int(a.Prop.Accuracy)))
|
||||
|
||||
}
|
||||
|
||||
type BattlePetEntity struct {
|
||||
@@ -53,14 +73,14 @@ type BattlePetEntity struct {
|
||||
}
|
||||
|
||||
// 创建精灵实例
|
||||
func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Source) *BattlePetEntity {
|
||||
func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Rand) *BattlePetEntity {
|
||||
ret := &BattlePetEntity{}
|
||||
|
||||
ret.PetInfo = xmlres.PetMAP[int(info.ID)] //注入精灵信息
|
||||
ret.Info = *info
|
||||
for i := 0; i < 4; i++ {
|
||||
//todo 技能信息应该每回合进行深拷贝,保证每次的技能效果都是不一样的
|
||||
ret.Skills[i] = CreateBattleSkillWithInfinity(&info.SkillList[i], rand)
|
||||
ret.Skills[i] = CreateBattleSkillWithInfinity(&info.SkillList[i], rand, ret)
|
||||
}
|
||||
|
||||
return ret
|
||||
@@ -92,9 +112,16 @@ func calculateRealValue(value int64, stat int) int64 {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *BattlePetEntity) Type() element.ElementType {
|
||||
func (u *BattlePetEntity) Type() *element.ElementCombination {
|
||||
var ff *element.ElementCombination
|
||||
for _, v := range xmlres.PetMAP {
|
||||
if v.ID == int(u.Info.ID) {
|
||||
ff, _ = element.NewElementCombination(v.Type)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//todo 待实现获取精灵的类型
|
||||
|
||||
return element.ElementType(0)
|
||||
return ff
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ var Category = enum.New[struct {
|
||||
Fixed EnumCategory // 固定伤害
|
||||
Percent EnumCategory // 百分比伤害
|
||||
True EnumCategory // 真伤
|
||||
ALL EnumCategory //任何类型
|
||||
}]()
|
||||
|
||||
// BattleSkillEntity 战斗技能实体
|
||||
@@ -41,21 +42,25 @@ type BattleSkillEntity struct {
|
||||
PP int
|
||||
DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值
|
||||
DamageValue decimal.Decimal // 伤害值
|
||||
Rand rand.Source
|
||||
Rand *rand.Rand
|
||||
Pet *BattlePetEntity
|
||||
// 技能类型属性
|
||||
//SkillType EnumCategory // 技能类型(物理/特殊/状态)
|
||||
|
||||
}
|
||||
|
||||
// CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP)
|
||||
func CreateBattleSkillWithInfinity(skill *model.SkillInfo, rand *rand.Source) *BattleSkillEntity {
|
||||
func CreateBattleSkillWithInfinity(skill *model.SkillInfo, rand *rand.Rand, pet *BattlePetEntity) *BattleSkillEntity {
|
||||
//如果PP是-1 ,那就是无限PP
|
||||
// ID小于10001的视为无效技能
|
||||
|
||||
if skill.ID < 10001 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ret BattleSkillEntity
|
||||
ret.Rand = rand
|
||||
ret.Pet = pet
|
||||
// 从资源仓库获取技能数据
|
||||
move, ok := xmlres.SkillMap[int(skill.ID)]
|
||||
|
||||
@@ -116,8 +121,9 @@ func (s *BattleSkillEntity) Category() EnumCategory {
|
||||
}
|
||||
|
||||
// 获取技能属性
|
||||
func (s *BattleSkillEntity) Type() element.ElementType {
|
||||
return element.ElementType(s.Move.Type)
|
||||
func (s *BattleSkillEntity) Type() *element.ElementCombination {
|
||||
ret, _ := element.NewElementCombination(s.Move.Type)
|
||||
return ret
|
||||
}
|
||||
|
||||
// // 技能产生effect
|
||||
@@ -235,108 +241,112 @@ func (s *BattleSkillEntity) PutDamageZone(e EnumCategory, dtype EnumsZoneType, v
|
||||
// }
|
||||
|
||||
// 暴击伤害 返回暴击率和是否暴击
|
||||
func (s *BattleSkillEntity) CriticalRate() decimal.Decimal {
|
||||
func (s *BattleSkillEntity) CriticalRate() (decimal.Decimal, uint32) {
|
||||
|
||||
return decimal.NewFromFloat(2)
|
||||
return decimal.NewFromFloat(1), 1
|
||||
|
||||
}
|
||||
|
||||
// func (s *BattleSkillEntity) criticalrandom() decimal.Decimal {
|
||||
// //这里应该算上威力区
|
||||
// // 初始化随机值,范围217~255
|
||||
// 计算是否命中
|
||||
func (s *BattleSkillEntity) CriticalisCritical() uint32 {
|
||||
|
||||
// randomnum := s.Random().NextLongN(39) + 217
|
||||
// // 10. 随机倍率,随机值除以255
|
||||
// randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255))
|
||||
// return randomFactor
|
||||
if int64(s.Pet.Accuracy(int64(s.Accuracy))) > s.Rand.Int63n(100) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
|
||||
// }
|
||||
}
|
||||
func (s *BattleSkillEntity) CriticalsameTypeBonus() decimal.Decimal {
|
||||
|
||||
// // 计算技能威力
|
||||
// func (s *BattleSkillEntity) CalculatePower(p *BattlePetEntity) int64 {
|
||||
// 6. 同系加成(属性相同则乘以同系加成倍率,否则1)
|
||||
sameTypeBonus := decimal.NewFromFloat(1.0)
|
||||
if s.Type() == s.Pet.Type() { //使用本系
|
||||
sameTypeBonus = decimal.NewFromFloat(1.5)
|
||||
}
|
||||
|
||||
// pet, _ := s.Pet()
|
||||
stype := s.Type()
|
||||
ptype := s.Pet.Type()
|
||||
|
||||
// // 1. 计算等级因子 (level * 0.4 + 2)
|
||||
// levelFactor := decimal.NewFromInt(int64(pet.Level)).
|
||||
// Mul(decimal.NewFromFloat(0.4)).Add(decimal.NewFromInt(2))
|
||||
if stype.Secondary == nil && ptype.Secondary != nil && (stype.Primary == ptype.Primary || stype.Primary == *ptype.Secondary) { //判断技能属性是否是精灵双属性之一
|
||||
sameTypeBonus = decimal.NewFromFloat(1.5)
|
||||
}
|
||||
return sameTypeBonus
|
||||
}
|
||||
|
||||
// // 2. 计算威力因子 (基础威力 + 加算) * 乘算
|
||||
func (s *BattleSkillEntity) criticalrandom() decimal.Decimal {
|
||||
|
||||
// //powerAdd := decimal.NewFromFloat(s.GetAddValue(EnumCategory., true)) //威力加算区
|
||||
randomnum := s.Rand.Int31n(39) + 217
|
||||
// 10. 随机倍率,随机值除以255
|
||||
randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255))
|
||||
return randomFactor
|
||||
|
||||
// powerMul := decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.POWER_MUL]) //威力乘算区
|
||||
// powerZone := decimal.NewFromInt(int64(s.Power)).Add(powerAdd).Mul(powerMul)
|
||||
}
|
||||
|
||||
// var (
|
||||
// attackDec decimal.Decimal //攻击值
|
||||
// defenseDec decimal.Decimal //防御值
|
||||
// damageReduction decimal.Decimal //伤害百分比减免
|
||||
// )
|
||||
// switch s.Category() { //判断技能类型
|
||||
// case Category.PHYSICAL:
|
||||
// attackDec = decimal.NewFromInt(int64(pet.UnitAttributes[AttrType.Attack].Value()))
|
||||
// defenseDec = decimal.NewFromInt(int64(p.UnitAttributes[AttrType.Defense].Value()))
|
||||
// damageReduction = decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.ATK_RESISTANCE])
|
||||
// 计算技能威力
|
||||
func (s *BattleSkillEntity) CalculatePower(deftype int) uint32 {
|
||||
|
||||
// case Category.SPECIAL:
|
||||
// attackDec = decimal.NewFromInt(int64(pet.UnitAttributes[AttrType.Attack].Value()))
|
||||
// defenseDec = decimal.NewFromInt(int64(p.UnitAttributes[AttrType.Speed].Value()))
|
||||
// damageReduction = decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.SP_ATK_RESISTANCE])
|
||||
// }
|
||||
// //攻击次数结算
|
||||
// attackCount := decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE])
|
||||
// // 5. 基础伤害公式:等级因子 * 威力因子 * 攻击 / 防御 / 50 + 2,然后乘以攻击次数
|
||||
// baseDamage := levelFactor.
|
||||
// Mul(powerZone).
|
||||
// Mul(attackDec).
|
||||
// Div(defenseDec).
|
||||
// Div(decimal.NewFromInt(50)).
|
||||
// Add(decimal.NewFromInt(2)).
|
||||
// Mul(attackCount)
|
||||
// 1. 计算等级因子 (level * 0.4 + 2)
|
||||
levelFactor := decimal.NewFromInt(int64(s.Pet.Info.Level)).
|
||||
Mul(decimal.NewFromFloat(0.4)).Add(decimal.NewFromInt(2))
|
||||
|
||||
// // 6. 同系加成(属性相同则乘以同系加成倍率,否则1)
|
||||
// sameTypeBonus := decimal.NewFromFloat(1.0)
|
||||
// if s.Type() == pet.Type() {
|
||||
// sameTypeBonus = decimal.NewFromFloat(1.5)
|
||||
// }
|
||||
// 2. 计算威力因子 (基础威力 + 加算) * 乘算
|
||||
|
||||
// t, _ := element.NewElementCalculator().GetOffensiveMultiplier(int(pet.Type()), int(pet.Type()))
|
||||
//powerAdd := decimal.NewFromFloat(s.GetAddValue(EnumCategory., true)) //威力加算区
|
||||
powerAdd_all := s.GetAddValue(Category.ALL, DamageC.boost)
|
||||
powerMul_all := s.GetMulValue(Category.ALL, DamageC.boost)
|
||||
|
||||
// typeRate := decimal.NewFromFloat(t)
|
||||
var (
|
||||
powerAdd_p decimal.Decimal //威力加算
|
||||
powerMul_p decimal.Decimal //威力乘算
|
||||
attackDec decimal.Decimal //攻击值
|
||||
defenseDec decimal.Decimal //防御值
|
||||
//damageReduction decimal.Decimal //伤害百分比减免
|
||||
)
|
||||
switch s.Category() { //判断技能类型
|
||||
case Category.PHYSICAL:
|
||||
|
||||
// // 8. 暴击倍率(暴击时使用暴击倍率,否则1)
|
||||
powerAdd_p = powerAdd_all.Add(s.GetAddValue(Category.PHYSICAL, DamageC.boost))
|
||||
powerMul_p = powerMul_all.Add(s.GetMulValue(Category.PHYSICAL, DamageC.boost))
|
||||
attackDec = decimal.NewFromInt(int64(s.Pet.Attack()))
|
||||
defenseDec = decimal.NewFromInt(int64(s.Pet.Defense()))
|
||||
//damageReduction = decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.ATK_RESISTANCE])
|
||||
|
||||
// criticalRate := decimal.NewFromFloat(1.0)
|
||||
// if s.isCritical {
|
||||
// criticalRate = s.CriticalRate()
|
||||
// }
|
||||
case Category.SPECIAL:
|
||||
powerAdd_p = powerAdd_all.Add(s.GetAddValue(Category.SPECIAL, DamageC.boost))
|
||||
powerMul_p = powerMul_all.Add(s.GetMulValue(Category.SPECIAL, DamageC.boost))
|
||||
attackDec = decimal.NewFromInt(int64(s.Pet.SAttack()))
|
||||
defenseDec = decimal.NewFromInt(int64(s.Pet.SDefense()))
|
||||
//damageReduction = decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.SP_ATK_RESISTANCE])
|
||||
|
||||
// // 9. 技能特殊效果倍率
|
||||
// specialEffect := decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.SPECIAL_EFFECT_MUL])
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
|
||||
// // 11. 计算总伤害
|
||||
// damage := baseDamage.
|
||||
// Mul(sameTypeBonus). // 同属性加成
|
||||
// Mul(typeRate). // 克制系数
|
||||
// Mul(criticalRate). //暴击系数
|
||||
// Mul(damageReduction). //减伤计算
|
||||
// Mul(specialEffect). //特殊效果
|
||||
// Mul(s.criticalrandom()) //随机波动
|
||||
if powerMul_p.IntPart() == 0 {
|
||||
powerMul_p = decimal.NewFromInt(1)
|
||||
}
|
||||
powerZone := decimal.NewFromInt(int64(s.Power)).Add(powerAdd_p).Mul(powerMul_p)
|
||||
// 5. 基础伤害公式:等级因子 * 威力因子 * 攻击 / 防御 / 50 + 2
|
||||
baseDamage := levelFactor.
|
||||
Mul(powerZone).
|
||||
Mul(attackDec).
|
||||
Div(defenseDec).
|
||||
Div(decimal.NewFromInt(50)).
|
||||
Add(decimal.NewFromInt(2))
|
||||
|
||||
// // 12. 存储真实伤害到额外倍率,方便后续查询
|
||||
// //context.PutExtraRate("REAL_DAMAGE", damage)
|
||||
t, _ := element.NewElementCalculator().GetOffensiveMultiplier(s.Type().ID, deftype)
|
||||
|
||||
// // 13. 应用固定伤害减免,伤害不能低于0
|
||||
// fixReduction := decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.DEFENSE_ZONE])
|
||||
// if fixReduction.GreaterThan(decimal.Zero) {
|
||||
// damage = damage.Sub(fixReduction)
|
||||
// if damage.LessThan(decimal.Zero) {
|
||||
// damage = decimal.Zero
|
||||
// }
|
||||
// }
|
||||
typeRate := decimal.NewFromFloat(t)
|
||||
|
||||
// // 返回最终伤害(整数部分)
|
||||
// return damage.IntPart()
|
||||
damage := baseDamage.
|
||||
Mul(s.CriticalsameTypeBonus()). // 同属性加成
|
||||
Mul(typeRate). // 克制系数
|
||||
|
||||
// }
|
||||
Mul(s.criticalrandom()) //随机波动
|
||||
v, ok := s.CriticalRate()
|
||||
if ok == 1 {
|
||||
damage.Mul(v)
|
||||
}
|
||||
return uint32(damage.IntPart())
|
||||
|
||||
}
|
||||
|
||||
@@ -171,7 +171,8 @@ func (t *NoteReadyToFightInfo) onBothFinished() {
|
||||
// ReadyFightPetInfo 准备战斗的精灵信息结构体,ReadyFightPetInfo类
|
||||
type ReadyFightPetInfo struct {
|
||||
// 精灵ID,@UInt long
|
||||
ID uint32 `fieldDesc:"精灵ID" `
|
||||
ID uint32 `fieldDesc:"精灵ID" `
|
||||
NotAlive bool `struc:"skip"`
|
||||
|
||||
// 精灵等级,@UInt long
|
||||
Level uint32 `fieldDesc:"精灵等级" `
|
||||
|
||||
@@ -35,11 +35,12 @@ type FightC struct {
|
||||
OurCurrentPet *info.BattlePetEntity //我方精灵
|
||||
Opp PlayerI
|
||||
OppCurrentPet *info.BattlePetEntity //对方当前精灵
|
||||
MAXPET uint32 // 最大精灵数
|
||||
OwnerID uint32 // 战斗发起者ID
|
||||
AFinished bool
|
||||
BFinished bool
|
||||
//random *rand.Rand //随机数种子
|
||||
|
||||
MAXPET uint32 // 最大精灵数
|
||||
OwnerID uint32 // 战斗发起者ID
|
||||
AFinished bool
|
||||
BFinished bool
|
||||
random *rand.Rand //随机数种子
|
||||
StartTime time.Time
|
||||
actionChan chan info.BattleActionI // 所有操作统一从这里进入
|
||||
Round int //回合数
|
||||
@@ -65,23 +66,25 @@ func (f *FightC) ChangePet(c PlayerI, id int32) {
|
||||
PlayerID: c.ID(),
|
||||
}
|
||||
|
||||
rett := func(t PlayerI) {
|
||||
rett := func(t PlayerI) *info.BattlePetEntity {
|
||||
for _, v := range t.GetPetInfo() {
|
||||
if v.CatchTime == uint32(id) {
|
||||
f.OurCurrentPet = info.CreateBattlePetEntity(v, f.Random()) //存入自己的精灵信息
|
||||
fs := info.CreateBattlePetEntity(v, f.Random()) //存入自己的精灵信息
|
||||
copier.Copy(&ret.Reason, &v)
|
||||
ret.Reason.UserId = c.ID()
|
||||
return fs
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if c == f.Our {
|
||||
|
||||
rett(f.Our)
|
||||
f.OurCurrentPet = rett(f.Our)
|
||||
|
||||
} else {
|
||||
|
||||
rett(f.Opp)
|
||||
f.OppCurrentPet = rett(f.Opp)
|
||||
}
|
||||
f.actionChan <- ret
|
||||
}
|
||||
@@ -152,13 +155,14 @@ func (f *FightC) ReadyFight(c PlayerI) {
|
||||
rrsult()
|
||||
}
|
||||
}
|
||||
func (f *FightC) Random() *rand.Source {
|
||||
func (f *FightC) Random() *rand.Rand {
|
||||
//先产生战斗的随机数
|
||||
// 组合「时间戳(纳秒精度)+ 双方ID + 回合数」生成种子
|
||||
|
||||
seed := f.StartTime.UnixNano() ^ int64(f.OwnerID) ^ int64(f.Our.ID()) ^ int64(f.Round) // 用异或运算混合多维度信息
|
||||
ret := rand.NewSource(seed)
|
||||
return &ret
|
||||
ret := rand.New(rand.NewSource(seed))
|
||||
|
||||
return ret
|
||||
|
||||
}
|
||||
|
||||
@@ -176,7 +180,15 @@ func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI, mo *model
|
||||
f.Info = i
|
||||
f.StartTime = time.Now()
|
||||
f.actionChan = make(chan info.BattleActionI, 2) // 初始化全局操作通道
|
||||
f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0], f.Random())
|
||||
fmt.Println("战斗开始精灵", plays.GetPetInfo()[0].CatchTime)
|
||||
|
||||
for _, v := range plays.GetPetInfo() {
|
||||
if v.Hp > 0 {
|
||||
f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0], f.Random())
|
||||
}
|
||||
}
|
||||
// }
|
||||
// f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0], f.Random())
|
||||
if mo != nil {
|
||||
f.OppCurrentPet = info.CreateBattlePetEntity(mo, f.Random())
|
||||
}
|
||||
@@ -222,12 +234,47 @@ func (f *FightC) BroadcastSkill(t info.AttackValueS) {
|
||||
f.Opp.SendAttackValue(t)
|
||||
}
|
||||
|
||||
// 检查战斗是否结束
|
||||
func (f *FightC) CheakEnd(b uint32) bool {
|
||||
fmt.Println(f.Round, "检查战斗是否结束")
|
||||
var tt []info.ReadyFightPetInfo
|
||||
for _, v := range f.Info.OurPetList {
|
||||
if v.CatchTime == b {
|
||||
v.NotAlive = true
|
||||
|
||||
}
|
||||
tt = append(tt, v)
|
||||
}
|
||||
f.Info.OurPetList = tt
|
||||
var tt1 []info.ReadyFightPetInfo
|
||||
for _, v := range f.Info.OpponentPetList {
|
||||
if v.CatchTime == b {
|
||||
v.NotAlive = true
|
||||
|
||||
}
|
||||
tt1 = append(tt1, v)
|
||||
}
|
||||
f.Info.OpponentPetList = tt1
|
||||
for _, v := range f.Info.OurPetList {
|
||||
if !v.NotAlive {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
for _, v := range f.Info.OpponentPetList {
|
||||
if !v.NotAlive {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 战斗回合循环
|
||||
func (f *FightC) battleLoop() {
|
||||
for {
|
||||
|
||||
f.Round++ //回合数自增
|
||||
// f.AFinished = false
|
||||
// f.BFinished = false
|
||||
|
||||
if f.Round > 250 { //回合数超过250,战斗平局结束
|
||||
|
||||
}
|
||||
@@ -242,7 +289,7 @@ func (f *FightC) battleLoop() {
|
||||
continue
|
||||
}
|
||||
if a, isExpelled := action.(*info.ActiveSwitchAction); isExpelled {
|
||||
fmt.Println("对方死亡切换")
|
||||
//fmt.Println("对方死亡切换")
|
||||
f.Broadcast(a)
|
||||
if !a.Type {
|
||||
continue
|
||||
@@ -295,8 +342,20 @@ func (f *FightC) battleLoop() {
|
||||
}
|
||||
|
||||
var p_skill [2]*info.SelectSkillAction
|
||||
var currpet [2]*info.BattlePetEntity
|
||||
var currpetvale [2]int // 伤害值
|
||||
if BattleActionI[0].GetPlayerID() == f.OwnerID { //先反转战斗属性
|
||||
|
||||
currpet[0] = f.OurCurrentPet
|
||||
currpet[1] = f.OppCurrentPet
|
||||
|
||||
} else {
|
||||
currpet[0] = f.OppCurrentPet
|
||||
currpet[1] = f.OurCurrentPet
|
||||
}
|
||||
fmt.Println("当前", currpet[0].Info.CatchTime, "敌方", currpet[1].Info.CatchTime)
|
||||
for i := 0; i < 2; i++ {
|
||||
|
||||
// TODO: 在这里调用技能结算逻辑
|
||||
|
||||
p_skill[i] = BattleActionI[i].(*info.SelectSkillAction)
|
||||
@@ -321,41 +380,65 @@ func (f *FightC) battleLoop() {
|
||||
}
|
||||
|
||||
}
|
||||
spower := p_skill[i].Skill.CalculatePower(currpet[i].Type().ID)
|
||||
|
||||
//开始计算技能效果battleLoop
|
||||
_, ok := p_skill[i].Skill.CriticalRate()
|
||||
//CalculatePower()
|
||||
//记录伤害,到后手方出手时计算伤害
|
||||
currpetvale[i] = int(spower)
|
||||
|
||||
fmt.Println("技能伤害", spower, "剩余血量", currpet[i].Info.Hp)
|
||||
p_skill[i].Attack = info.AttackValue{
|
||||
p_skill[i].PlayerID,
|
||||
uint32(p_skill[i].Skill.ID),
|
||||
1,
|
||||
200,
|
||||
p_skill[i].Skill.CriticalisCritical(),
|
||||
spower,
|
||||
0,
|
||||
int32(f.OurCurrentPet.Info.MaxHp),
|
||||
f.OurCurrentPet.Info.MaxHp,
|
||||
int32(currpet[i].Info.Hp),
|
||||
currpet[i].Info.MaxHp,
|
||||
0,
|
||||
0,
|
||||
[]model.SkillInfo{},
|
||||
1,
|
||||
ok,
|
||||
info.StatusDict{},
|
||||
info.PropDict{},
|
||||
}
|
||||
|
||||
}
|
||||
p_skill[1].Attack = info.AttackValue{
|
||||
p_skill[1].PlayerID,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
[]model.SkillInfo{},
|
||||
0,
|
||||
info.StatusDict{},
|
||||
info.PropDict{},
|
||||
p_skill[0].Attack.RemainHp = int32(int(currpet[0].Info.Hp) - currpetvale[1])
|
||||
currpet[0].Info.Hp = uint32(p_skill[0].Attack.RemainHp)
|
||||
p_skill[1].Attack.RemainHp = int32(int(currpet[1].Info.Hp) - currpetvale[0])
|
||||
currpet[1].Info.Hp = uint32(p_skill[1].Attack.RemainHp)
|
||||
if p_skill[1].Attack.RemainHp <= 0 { //如果后手方被打死
|
||||
p_skill[1].Attack = info.AttackValue{
|
||||
p_skill[1].PlayerID,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
[]model.SkillInfo{},
|
||||
0,
|
||||
info.StatusDict{},
|
||||
info.PropDict{},
|
||||
}
|
||||
fmt.Println(currpet[1].Info.CatchTime, "被打死")
|
||||
if f.CheakEnd(currpet[1].Info.CatchTime) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if p_skill[0].Attack.RemainHp <= 0 {
|
||||
|
||||
if f.CheakEnd(currpet[0].Info.CatchTime) {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println("P1", p_skill[0].Attack.RemainHp, "P2", p_skill[1].Attack.RemainHp)
|
||||
f.BroadcastSkill(info.AttackValueS{
|
||||
p_skill[0].Attack, p_skill[1].Attack,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user