614 lines
28 KiB
C#
614 lines
28 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description:
|
||
* @Date: 2025年11月15日 星期五
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using Logic.Action;
|
||
using MemoryPack;
|
||
using RuntimeData;
|
||
using TH1_Anim.Fragments;
|
||
using TH1_DataAssetsScript;
|
||
using TH1_Logic.Core;
|
||
using TH1Renderer;
|
||
using UnityEngine;
|
||
|
||
|
||
namespace Logic.Skill
|
||
{
|
||
// 大吉/吉/凶/大凶 四种等级
|
||
public enum SanaeDivineType
|
||
{
|
||
BigLucky,
|
||
Lucky,
|
||
Unlucky,
|
||
BigUnlucky
|
||
}
|
||
|
||
|
||
public partial class SanaeDivineSkill : SkillBase
|
||
{
|
||
private int _bigLuckyDmg = 4;
|
||
private int _bigLuckyHeal = 4;
|
||
private int _bigUnluckyEnemyDmg = 6;
|
||
private int _bigUnluckyFriendDmg = 3;
|
||
|
||
private class OmikujiActionContext
|
||
{
|
||
public bool ForceFirstExtreme;
|
||
public bool IsFirstRoll = true;
|
||
public bool Rolled;
|
||
public bool HasExtreme;
|
||
|
||
public void Record(SanaeDivineType divine)
|
||
{
|
||
Rolled = true;
|
||
if (IsExtreme(divine)) HasExtreme = true;
|
||
}
|
||
}
|
||
|
||
public SanaeDivineSkill()
|
||
{
|
||
IsPermanent = true;
|
||
TurnsLimit = 0;
|
||
Score = 2;
|
||
}
|
||
|
||
public override SkillType GetSkillType()
|
||
{
|
||
return SkillType.SANAEDIVINE;
|
||
}
|
||
|
||
public override void OnHealOther(MapData mapData, UnitData origin,UnitData target, HealType healType)
|
||
{
|
||
if (healType != HealType.AttackAllyHeal) return;
|
||
if (mapData == null || origin == null || target == null) return;
|
||
var originId = origin.Id;
|
||
var targetId = target.Id;
|
||
if (!TryGetLiveUnit(mapData, originId, out origin) || !TryGetLiveUnit(mapData, targetId, out target)) return;
|
||
|
||
var omikujiContext = CreateOmikujiActionContext(origin);
|
||
try
|
||
{
|
||
//处理三连发
|
||
if (origin.Skills != null && origin.GetSkill(SkillType.SANAENINE, out var _))
|
||
{
|
||
bool again = false;
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
if (!TryGetLiveUnit(mapData, originId, out origin) || !TryGetLiveUnit(mapData, targetId, out target)) return;
|
||
var divine = GetBuff(mapData, origin,true, out var skill, omikujiContext);
|
||
if(divine is SanaeDivineType.BigUnlucky or SanaeDivineType.BigLucky)
|
||
again = true;
|
||
|
||
//Debug.Log(divine);
|
||
var timer = Timer.Instance;
|
||
System.Action playOmikuji = () =>
|
||
{
|
||
if (!TryGetLiveUnitGrid(mapData, originId, out _, out var originGrid)) return;
|
||
if (!TryGetLiveUnitGrid(mapData, targetId, out _, out var targetGrid)) return;
|
||
//处理投掷神签动画
|
||
OmikujiAnim(mapData, originGrid, targetGrid, divine);
|
||
};
|
||
if (timer == null)
|
||
playOmikuji();
|
||
else
|
||
timer.TimerRegister(this, playOmikuji,1.1f * i,"SANAEDIVINE - SANAENINE - OnHeal");
|
||
//处理大凶
|
||
if (divine == SanaeDivineType.BigUnlucky)
|
||
{
|
||
var targetGrid = target.Grid(mapData);
|
||
if (targetGrid != null)
|
||
BigUnlucky(mapData, origin,targetGrid,1.1f * i);
|
||
}
|
||
else
|
||
{
|
||
if (!TryGetLiveUnit(mapData, targetId, out target)) return;
|
||
target.AddSkill_Legacy(skill,mapData,false,1,false,-1,false,SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||
if (divine == SanaeDivineType.BigLucky)
|
||
{
|
||
var targetGrid = target.Grid(mapData);
|
||
if (targetGrid != null)
|
||
BigLucky(mapData, origin,targetGrid,1.1f * i);
|
||
}
|
||
}
|
||
|
||
}
|
||
if(again)
|
||
{
|
||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||
origin.SetFullActionPoint_AllSkillRefresh();
|
||
}
|
||
}
|
||
//处理单次效果
|
||
else
|
||
{
|
||
if (!TryGetLiveUnit(mapData, originId, out origin) || !TryGetLiveUnit(mapData, targetId, out target)) return;
|
||
var divine = GetBuff(mapData, origin, true, out var skill, omikujiContext);
|
||
//处理投掷神签动画
|
||
var originGrid = origin.Grid(mapData);
|
||
var targetGrid = target.Grid(mapData);
|
||
if (originGrid == null || targetGrid == null) return;
|
||
OmikujiAnim(mapData, originGrid, targetGrid, divine);
|
||
//处理大凶
|
||
if (divine == SanaeDivineType.BigUnlucky)
|
||
{
|
||
BigUnlucky(mapData, origin,targetGrid,0);
|
||
//origin.
|
||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||
origin.SetFullActionPoint_AllSkillRefresh();
|
||
}
|
||
else
|
||
{
|
||
if (!TryGetLiveUnit(mapData, targetId, out target)) return;
|
||
target.AddSkill_Legacy(skill,mapData,false,1,false, -1,false,SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||
if (divine == SanaeDivineType.BigLucky)
|
||
{
|
||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||
origin.SetFullActionPoint_AllSkillRefresh();
|
||
BigLucky(mapData, origin,targetGrid,0f);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
FinishOmikujiAction(mapData, originId, omikujiContext);
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
public override void OnDamageOther(MapData mapData, SettlementInfo info)
|
||
{
|
||
if (mapData == null || info?.DamageOrigin == null || info.DamageTargetGrid == null) return;
|
||
if (info.DamageType != DamageType.ActiveAttack) return;
|
||
var originId = info.DamageOrigin.Id;
|
||
var targetGridId = info.DamageTargetGrid.Id;
|
||
var targetId = info.DamageTarget?.Id ?? 0;
|
||
if (!TryGetLiveUnitGrid(mapData, originId, out var origin, out _)) return;
|
||
if (!TryGetLiveGrid(mapData, targetGridId, out var targetGrid)) return;
|
||
|
||
var omikujiContext = CreateOmikujiActionContext(origin);
|
||
try
|
||
{
|
||
//如果是三连发
|
||
if (origin.Skills != null && origin.GetSkill(SkillType.SANAENINE,out var _))
|
||
{
|
||
bool again = false;
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
if (!TryGetLiveUnitGrid(mapData, originId, out origin, out _)) return;
|
||
if (!TryGetLiveGrid(mapData, targetGridId, out targetGrid)) return;
|
||
var divine = GetBuff(mapData, origin,false, out var skill, omikujiContext);
|
||
if(divine is SanaeDivineType.BigUnlucky or SanaeDivineType.BigLucky)
|
||
again = true;
|
||
|
||
System.Action playOmikuji = () =>
|
||
{
|
||
if (!TryGetLiveUnitGrid(mapData, originId, out _, out var originGrid)) return;
|
||
if (!TryGetLiveGrid(mapData, targetGridId, out var liveTargetGrid)) return;
|
||
//处理投掷神签动画
|
||
OmikujiAnim(mapData, originGrid, liveTargetGrid, divine);
|
||
};
|
||
if (Timer.Instance == null)
|
||
playOmikuji();
|
||
else
|
||
Timer.Instance.TimerRegister(this, playOmikuji,1.1f * i,"SANAEDIVINE - SANAENINE");
|
||
//处理大凶
|
||
if (divine == SanaeDivineType.BigUnlucky)
|
||
BigUnlucky(mapData, origin,targetGrid,1.1f * i);
|
||
|
||
else
|
||
{
|
||
//skill = SkillType.DIVINE_E4_KILL;
|
||
if (targetId != 0 && TryGetLiveUnit(mapData, targetId, out var liveTarget))
|
||
liveTarget.AddSkill_Legacy(skill,mapData,false,1,false, -1,false, SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||
if (divine == SanaeDivineType.BigLucky)
|
||
{
|
||
BigLucky(mapData, origin,targetGrid,1.1f * i);
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
if(again)
|
||
{
|
||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||
origin.SetFullActionPoint_AllSkillRefresh();
|
||
}
|
||
}
|
||
//如果是单发
|
||
else
|
||
{
|
||
if (!TryGetLiveUnitGrid(mapData, originId, out origin, out var originGrid)) return;
|
||
if (!TryGetLiveGrid(mapData, targetGridId, out targetGrid)) return;
|
||
var divine = GetBuff(mapData, origin,false, out var skill, omikujiContext);
|
||
//处理投掷神签动画
|
||
if (originGrid == null) return;
|
||
OmikujiAnim(mapData, originGrid, targetGrid, divine);
|
||
|
||
//处理大凶
|
||
if (divine == SanaeDivineType.BigUnlucky)
|
||
{
|
||
BigUnlucky(mapData, origin,targetGrid,0f);
|
||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||
origin.SetFullActionPoint_AllSkillRefresh();
|
||
}
|
||
else
|
||
{
|
||
//skill = SkillType.DIVINE_E4_KILL;
|
||
if (targetId != 0 && TryGetLiveUnit(mapData, targetId, out var liveTarget))
|
||
liveTarget.AddSkill_Legacy(skill,mapData,false,1,false,-1,false,SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||
if (divine == SanaeDivineType.BigLucky)
|
||
{
|
||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||
origin.SetFullActionPoint_AllSkillRefresh();
|
||
BigLucky(mapData, origin,targetGrid,0f);
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
FinishOmikujiAction(mapData, originId, omikujiContext);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
private void OmikujiAnim(MapData mapData,GridData origin,GridData target, SanaeDivineType divine)
|
||
{
|
||
if (mapData == null || origin == null || target == null) return;
|
||
var mainMap = Main.MapData;
|
||
if (mapData != mainMap || mainMap?.GridMap == null || mainMap.PlayerMap?.SelfPlayerData?.Sight == null) return;
|
||
if (origin.InMainSight() || target.InMainSight())
|
||
{
|
||
if (Table.Instance == null) return;
|
||
var startPos = Table.Instance.GridToWorld(origin);
|
||
var endPos = Table.Instance.GridToWorld(target);
|
||
ProjectileType omikuji = ProjectileType.SanaeOmikuji;
|
||
ProjectileTypeInfo projInfo = null;
|
||
if(Table.Instance.ProjectileTypeDataAssets != null &&
|
||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(omikuji, out projInfo))
|
||
MapRenderer.Instance?.ProjectileManager?.CreateProjectile(startPos,endPos,omikuji);
|
||
var targetGridId = target.Id;
|
||
var map = mapData;
|
||
System.Action playOmikujiVfx = () =>
|
||
{
|
||
if (!TryGetLiveGrid(map, targetGridId, out var liveTargetGrid)) return;
|
||
var vfx1 = divine switch
|
||
{
|
||
SanaeDivineType.BigLucky => GridVFXType.BigLucky,
|
||
SanaeDivineType.Lucky => GridVFXType.Lucky,
|
||
SanaeDivineType.Unlucky => GridVFXType.Unlucky,
|
||
_ => GridVFXType.BigUnlucky
|
||
};
|
||
var vfx2 = divine switch
|
||
{
|
||
SanaeDivineType.BigLucky => GridVFXType.BigLuckyText,
|
||
SanaeDivineType.Lucky => GridVFXType.LuckyText,
|
||
SanaeDivineType.Unlucky => GridVFXType.UnluckyText,
|
||
_ => GridVFXType.BigUnluckyText
|
||
};
|
||
|
||
var renderer = liveTargetGrid.Renderer(map);
|
||
renderer?.PlayVFXInSight(new GridVFXParams(vfx1));
|
||
renderer?.PlayVFXInSight(new GridVFXParams(vfx2));
|
||
|
||
};
|
||
if (Timer.Instance == null)
|
||
playOmikujiVfx();
|
||
else
|
||
Timer.Instance.TimerRegister(this, playOmikujiVfx,projInfo?.AnimTime ?? 0f,"SANAEDIVINE OMIKUJI ANIM");
|
||
}
|
||
}
|
||
|
||
private void BigUnlucky(MapData mapData, UnitData originUnit,GridData targetGrid,float waitTime)
|
||
{
|
||
var originId = originUnit?.Id ?? 0;
|
||
var gridId = targetGrid?.Id ?? 0;
|
||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) return;
|
||
if (!TryGetLiveGrid(mapData, gridId, out var grid)) return;
|
||
|
||
ProjectileTypeInfo projInfo = null;
|
||
if ((grid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||
&& Table.Instance?.ProjectileTypeDataAssets != null)
|
||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(ProjectileType.SanaeOmikuji, out projInfo);
|
||
var aroundBuf = RentAroundBuf();
|
||
mapData.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
|
||
foreach (var round in aroundBuf)
|
||
{
|
||
if (round == null) continue;
|
||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) break;
|
||
if (!round.RealUnit(mapData, out var unit)) continue;
|
||
if (!unit.IsValidOnMap(mapData, round)) continue;
|
||
if (!unit.IsAlive()) continue;
|
||
bool sameUnion = mapData.SameUnionByUnitId(unit.Id, originUnit.Id);
|
||
var map = mapData;
|
||
var tmpGridId = round.Id;
|
||
var tmpUnitId = unit.Id;
|
||
var dmg = sameUnion ? _bigUnluckyFriendDmg : _bigUnluckyEnemyDmg;
|
||
var canBeKilled = unit.CanBeKilled(mapData);
|
||
var visualCollector = ActionVisualEventCollector.Current;
|
||
var targetRenderer = mapData == Main.MapData ? unit.Renderer(mapData) : null;
|
||
var dmgInfo = visualCollector != null && mapData == Main.MapData
|
||
? visualCollector.SettleDamageWithVisual(
|
||
originUnit,
|
||
unit,
|
||
dmg,
|
||
sameUnion ? DamageType.KillSelf : DamageType.Splash,
|
||
AnimPhase.AttackImpact + 50,
|
||
(projInfo?.AnimTime ?? 0f) + waitTime,
|
||
showoff: true)
|
||
: Main.UnitLogic.DamageSettlement(mapData, originUnit, unit, dmg , sameUnion ? DamageType.KillSelf : DamageType.Splash);
|
||
if (dmgInfo?.DamageTargetGrid == null) continue;
|
||
if (visualCollector != null && mapData == Main.MapData) continue;
|
||
//处理视觉
|
||
if (mapData == Main.MapData)
|
||
{
|
||
RegisterOrRunTimer(() =>
|
||
{
|
||
if (!TryGetLiveGrid(map, tmpGridId, out var tmpGrid)) return;
|
||
var gridRenderer = tmpGrid.Renderer(map);
|
||
if (tmpGrid.InMainSight())
|
||
{
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage,dmg));
|
||
}
|
||
if (dmgInfo.IsKill)
|
||
{
|
||
if (tmpGrid.InMainSight())
|
||
{
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
|
||
if (canBeKilled)
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
|
||
}
|
||
targetRenderer?.Die();
|
||
gridRenderer?.InstantUpdateGrid();
|
||
MapRenderer.Instance?.UpdateAroundHighlight(map, tmpGrid);
|
||
return;
|
||
}
|
||
if (TryGetLiveUnit(map, tmpUnitId, out var liveUnit))
|
||
(targetRenderer ?? liveUnit.Renderer(map))?.InstantUpdateUnit(showoff: true);
|
||
|
||
},(projInfo?.AnimTime ?? 0f )+ waitTime,"SANAEDIVINE OMIKUJI BigUnlucky Anim");
|
||
}
|
||
|
||
}
|
||
ReturnAroundBuf();
|
||
}
|
||
|
||
private void BigLucky(MapData mapData, UnitData originUnit,GridData targetGrid,float waitTime)
|
||
{
|
||
var originId = originUnit?.Id ?? 0;
|
||
var gridId = targetGrid?.Id ?? 0;
|
||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) return;
|
||
if (!TryGetLiveGrid(mapData, gridId, out var grid)) return;
|
||
|
||
ProjectileTypeInfo projInfo = null;
|
||
if ((grid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||
&& Table.Instance?.ProjectileTypeDataAssets != null)
|
||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(ProjectileType.SanaeOmikuji, out projInfo);
|
||
var aroundBuf = RentAroundBuf();
|
||
mapData.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
|
||
foreach (var round in aroundBuf)
|
||
{
|
||
if (round == null) continue;
|
||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) break;
|
||
if (!round.RealUnit(mapData, out var unit)) continue;
|
||
if (!unit.IsValidOnMap(mapData, round)) continue;
|
||
bool sameUnion = mapData.SameUnionByUnitId(unit.Id, originUnit.Id);
|
||
var map = mapData;
|
||
var tmpGridId = round.Id;
|
||
var tmpUnitId = unit.Id;
|
||
//处理敌人
|
||
if (!sameUnion)
|
||
{
|
||
var canBeKilled = unit.CanBeKilled(mapData);
|
||
var visualCollector = ActionVisualEventCollector.Current;
|
||
var targetRenderer = mapData == Main.MapData ? unit.Renderer(mapData) : null;
|
||
var dmgInfo = visualCollector != null && mapData == Main.MapData
|
||
? visualCollector.SettleDamageWithVisual(
|
||
originUnit,
|
||
unit,
|
||
_bigLuckyDmg,
|
||
DamageType.Splash,
|
||
AnimPhase.AttackImpact + 50,
|
||
(projInfo?.AnimTime ?? 0f) + waitTime,
|
||
showoff: true)
|
||
: Main.UnitLogic.DamageSettlement(mapData, originUnit, unit, _bigLuckyDmg , DamageType.Splash);
|
||
if (dmgInfo?.DamageTargetGrid == null) continue;
|
||
if (visualCollector != null && mapData == Main.MapData) continue;
|
||
//处理视觉
|
||
if (mapData == Main.MapData)
|
||
{
|
||
RegisterOrRunTimer(() =>
|
||
{
|
||
if (!TryGetLiveGrid(map, tmpGridId, out var tmpGrid)) return;
|
||
var gridRenderer = tmpGrid.Renderer(map);
|
||
if (tmpGrid.InMainSight())
|
||
{
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage,4));
|
||
}
|
||
if (dmgInfo.IsKill)
|
||
{
|
||
if (tmpGrid.InMainSight())
|
||
{
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
|
||
if (canBeKilled)
|
||
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
|
||
}
|
||
targetRenderer?.Die();
|
||
gridRenderer?.InstantUpdateGrid();
|
||
MapRenderer.Instance?.UpdateAroundHighlight(map, tmpGrid);
|
||
return;
|
||
}
|
||
|
||
if (TryGetLiveUnit(map, tmpUnitId, out var liveUnit))
|
||
(targetRenderer ?? liveUnit.Renderer(map))?.InstantUpdateUnit(showoff: true);
|
||
|
||
},(projInfo?.AnimTime ?? 0f) + waitTime,"SANAEDIVINE OMIKUJI BigUnlucky Anim");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
//TODO 这里用timer 延迟了逻辑,因为recoverHealth 逻辑和视觉绑定了。后续要拆开
|
||
Main.UnitLogic.RecoverHealth_Legacy(map,originUnit,unit,_bigLuckyHeal);
|
||
//处理视觉
|
||
if (unit.Grid(map)?.InMainSight()??false)
|
||
{
|
||
RegisterOrRunTimer(() =>
|
||
{
|
||
if (!TryGetLiveGrid(map, tmpGridId, out var tmpGrid)) return;
|
||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Heal));
|
||
if (TryGetLiveUnit(map, tmpUnitId, out var liveUnit))
|
||
liveUnit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||
|
||
},projInfo?.AnimTime ?? 0f,"SANAEDIVINE OMIKUJI BigUnlucky Anim");
|
||
}
|
||
else
|
||
Main.UnitLogic.RecoverHealth_Legacy(map,originUnit,unit,_bigLuckyHeal);
|
||
}
|
||
|
||
|
||
}
|
||
ReturnAroundBuf();
|
||
}
|
||
|
||
private void RegisterOrRunTimer(System.Action action, float delay, string message)
|
||
{
|
||
if (action == null) return;
|
||
var timer = Timer.Instance;
|
||
if (timer == null)
|
||
{
|
||
action();
|
||
return;
|
||
}
|
||
|
||
timer.TimerRegister(this, action, delay, message);
|
||
}
|
||
|
||
private static bool TryGetLiveUnit(MapData mapData, uint unitId, out UnitData unit)
|
||
{
|
||
unit = null;
|
||
if (unitId == 0 || mapData?.UnitMap == null) return false;
|
||
return mapData.UnitMap.GetUnitDataByUnitId(unitId, out unit)
|
||
&& unit != null
|
||
&& unit.IsValidOnMap(mapData);
|
||
}
|
||
|
||
private static bool TryGetLiveGrid(MapData mapData, uint gridId, out GridData grid)
|
||
{
|
||
grid = null;
|
||
if (gridId == 0 || mapData?.GridMap == null) return false;
|
||
return mapData.GridMap.GetGridDataByGid(gridId, out grid) && grid != null;
|
||
}
|
||
|
||
private static bool TryGetLiveUnitGrid(MapData mapData, uint unitId, out UnitData unit, out GridData grid)
|
||
{
|
||
grid = null;
|
||
if (!TryGetLiveUnit(mapData, unitId, out unit)) return false;
|
||
return mapData.GetGridDataByUnitId(unit.Id, out grid) && grid != null;
|
||
}
|
||
|
||
public SanaeDivineType GetBuff(MapData map, UnitData self,bool IsHeal, out SkillType skill)
|
||
{
|
||
return GetBuff(map, self, IsHeal, out skill, null);
|
||
}
|
||
|
||
private SanaeDivineType GetBuff(MapData map, UnitData self,bool IsHeal, out SkillType skill, OmikujiActionContext context)
|
||
{
|
||
skill = SkillType.NONE;
|
||
if (map?.Net == null || self == null) return SanaeDivineType.Lucky;
|
||
|
||
var forceExtreme = context is { IsFirstRoll: true, ForceFirstExtreme: true };
|
||
if (context != null) context.IsFirstRoll = false;
|
||
var buff = forceExtreme
|
||
? GetForcedExtremeBuff(map, IsHeal, out skill)
|
||
: GetNormalBuff(map, IsHeal, out skill);
|
||
|
||
if (IsExtreme(buff))
|
||
ClearDivinePending(map, self);
|
||
|
||
context?.Record(buff);
|
||
if (map.GetPlayerDataByUnitId(self.Id, out var player))
|
||
{
|
||
foreach (var kv in player.PlayerHeroData.HeroTaskDict)
|
||
kv.Value.OnSanaeDevine(map, player, buff);
|
||
}
|
||
return buff;
|
||
}
|
||
|
||
private static OmikujiActionContext CreateOmikujiActionContext(UnitData self)
|
||
{
|
||
var context = new OmikujiActionContext();
|
||
if (self != null &&
|
||
self.GetSkill(SkillType.LUCK, out var pending) &&
|
||
pending.Level >= LuckSkill.DivinePendingLimit)
|
||
{
|
||
context.ForceFirstExtreme = true;
|
||
}
|
||
|
||
return context;
|
||
}
|
||
|
||
private static void FinishOmikujiAction(MapData map, uint originId, OmikujiActionContext context)
|
||
{
|
||
if (context == null || !context.Rolled || context.HasExtreme) return;
|
||
if (!TryGetLiveUnit(map, originId, out var origin)) return;
|
||
origin.AddSkill_Legacy(SkillType.LUCK, map, true, 0, true, 1, true, SpecialAddSkillType.AddLevel, origin.Id);
|
||
}
|
||
|
||
private static void ClearDivinePending(MapData map, UnitData self)
|
||
{
|
||
if (self == null) return;
|
||
if (self.GetSkill(SkillType.LUCK, out _))
|
||
self.RemoveSkill(SkillType.LUCK, map);
|
||
}
|
||
|
||
private static SanaeDivineType GetForcedExtremeBuff(MapData map, bool isHeal, out SkillType skill)
|
||
{
|
||
skill = SkillType.NONE;
|
||
var roll = map.Net.GetRandom(map).Next(1, 101);
|
||
if (roll <= 50) return SanaeDivineType.BigUnlucky;
|
||
skill = roll <= 75
|
||
? (isHeal ? SkillType.DIVINE_F4_ATK : SkillType.DIVINE_E4_KILL)
|
||
: (isHeal ? SkillType.DIVINE_F4_KILL : SkillType.DIVINE_E4_DEFENSE);
|
||
return SanaeDivineType.BigLucky;
|
||
}
|
||
|
||
private static SanaeDivineType GetNormalBuff(MapData map, bool isHeal, out SkillType skill)
|
||
{
|
||
skill = SkillType.NONE;
|
||
var roll = map.Net.GetRandom(map).Next(1, 101); // 生成1到100的随机数
|
||
if (roll <= 10) return SanaeDivineType.BigUnlucky; // 大凶
|
||
if (roll <= 45)
|
||
{
|
||
skill = (roll <= 27) ? (isHeal?SkillType.DIVINE_F2_DEFENSE:SkillType.DIVINE_E2_ATK) : (isHeal?SkillType.DIVINE_F2_RESIST:SkillType.DIVINE_E2_MOVE);
|
||
return SanaeDivineType.Unlucky; // 凶
|
||
}
|
||
if (roll <= 90)
|
||
{
|
||
skill = (roll <= 67) ? (isHeal ? SkillType.DIVINE_F3_MOVE:SkillType.DIVINE_E3_HP) : (isHeal ? SkillType.DIVINE_F3_MOVE:SkillType.DIVINE_E3_COUNTER);
|
||
return SanaeDivineType.Lucky; // 吉
|
||
}
|
||
skill = (roll <= 95) ? (isHeal ? SkillType.DIVINE_F4_ATK:SkillType.DIVINE_E4_KILL) : (isHeal ? SkillType.DIVINE_F4_KILL:SkillType.DIVINE_E4_DEFENSE);
|
||
return SanaeDivineType.BigLucky; // 大吉
|
||
}
|
||
|
||
private static bool IsExtreme(SanaeDivineType divine)
|
||
{
|
||
return divine is SanaeDivineType.BigUnlucky or SanaeDivineType.BigLucky;
|
||
}
|
||
}
|
||
}
|