Squashes 146 commits from battle-engine-extraction. Net: 2,045 files changed, +11,896 / -158,687 lines. Ships engine passes 4-7 (dead-code cull, view-layer stub, receive-path shrink) plus the Phase-5 AsyncLocal ambient deletion that turns concurrent battles into a type-system property rather than a scope contract. ## What landed **Passes 4-7 (chunks 1-34):** Extended the Phase-4 const-false collapse into a cascading cull across the skill graph, view layer, and receive-path periphery. Six mode flags (IsWatchBattle/IsReplayBattle/IsAdmin/IsAdminWatch/IsPuzzleQuest/ IsAINetwork) became `const false`, every guarded block deleted. Field*.cs subclass ctors + BackGroundBase + ObjectChecker culled to no-ops. Mulligan family reworked to take a mgr param through IMulliganMgr.InitMulligan. Emotion/Recovery/Resource clusters null-stubbed. Prediction/OperationSimulator/ skill filters converted from static ambient reads to per-mgr reads via SkillPrm.ownerCard.SelfBattlePlayer.BattleMgr / ins.BattleMgr / this.BattleMgr. **Phase-5 ambient rip (chunks 35-47):** Deleted BattleAmbient / BattleAmbient- Context / TestBattleScope in full. Every per-battle mutable slot now lives on the mgr instance itself: mgr.InstanceIsForecast / InstanceIsRandomDraw / InstanceRecoveryInfo / InstanceViewerId / InstanceNetworkAgent / GameMgr BattleManagerBase.GetIns() returns null unconditionally; the residual static flags + 3 façades (Certification.ViewerId, Data.BattleRecoveryInfo, ToolboxGame.RealTimeNetworkAgent) are null-tolerant defaults kept for the handful of engine-internal readers that still reference their types. Zero BattleAmbient references anywhere in engine + node + tests. Added pre-seeded GameMgr ctor overload threaded through the mgr chain (BattleManagerBase → SingleBattleMgr / NetworkBattleManagerBase → NetworkStandard- BattleMgr → HeadlessBattleMgr / HeadlessNetworkBattleMgr). Fixtures build a GameMgr, seed it via HeadlessEngineEnv.SeedCharaIds/SeedNetUser, and pass it to the mgr's ctor — no ambient reach. Node side (SVSim.BattleNode/SessionBattleEngine): _ctx replaced with a plain GameMgr field; 34 `using var _ambient = BattleAmbient.Enter(_ctx)` scope wraps ripped from every accessor and mutator; EngineGlobalInit.WirePerSessionGameMgr takes GameMgr as a param and runs from SessionBattleEngine.SetupInternal BEFORE mgr construction. Test side: TestBattleScope deleted; 18 fixture [SetUp]s migrated to `HeadlessEngineEnv.EnsureProcessGlobals()`; MultiInstanceEngineTests rewritten around per-mgr construction (GetIns() → null is the pinned invariant). ## Regression fixes - **chunk-48** (MulliganCtrl): chunk-35's `= null` stubs on card lookups broke the live receive-driven Deal path (BattlePlayerBase.DrawCard NRE'd downstream of NetworkPlayerMulliganCtrl.StartMulliganVfx). Restored the three lookups via `_battlePlayer.BattleMgr.GetBattleCardIdx`. Engine tests were satisfied by the WireMulliganPhase seam; unit tests exposed the live-path gap. ## Ship state - SVSim.BattleEngine.Tests: 56/56 pass, 2 skip - SVSim.UnitTests: 1554/1554 pass (was 1523/31-fail before chunk 48) - Solution build: 0 source warnings (40 pre-existing NU1902 MessagePack CVEs in SVSim.EmulatedEntrypoint, unrelated) - Sequential PVP smoke: verified live (two back-to-back battles, no regression on cleanup/spinup) - Concurrent PVP smoke: verified live Adds tools/engine-port/ClosureAnalyzer/ — the Roslyn transitive-type-closure analyzer needed to make future cascade cleanup safe (per feedback memory "Engine cleanup needs closure tool" from the 2026-06-28 pass-3 failure). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1061 lines
27 KiB
C#
1061 lines
27 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Cute;
|
|
using LitJson;
|
|
using Wizard;
|
|
using Wizard.AutoTest;
|
|
using Wizard.Battle.Recovery;
|
|
|
|
public class DataMgr
|
|
{
|
|
public enum SpecialBattleResultType
|
|
{
|
|
None }
|
|
|
|
public class SpecialBattleSetting
|
|
{
|
|
public string Id { get; private set; }
|
|
|
|
public bool? IsPlayerFirstTurn { get; private set; }
|
|
|
|
public string PlayerAttachSkillText { get; private set; }
|
|
|
|
public string[] PlayerAttachSkills { get; private set; }
|
|
|
|
public string EnemyAttachSkillText { get; private set; }
|
|
|
|
public string[] EnemyAttachSkills { get; private set; }
|
|
|
|
public int PlayerStartPp { get; private set; }
|
|
|
|
public int EnemyStartPp { get; private set; }
|
|
|
|
public int PlayerStartLife { get; set; }
|
|
|
|
public int PlayerStartMaxLife { get; private set; }
|
|
|
|
public int EnemyStartMaxLife { get; private set; }
|
|
|
|
public string IdOverrideInBattleLogText { get; private set; }
|
|
|
|
public Dictionary<int, int> IdOverridePairDict { get; private set; }
|
|
|
|
public string BanishEffectOverRideText { get; private set; }
|
|
|
|
public string[] BanishEffectOverRideIds { get; private set; }
|
|
|
|
public string TokenDrawEffectOverrideText { get; private set; }
|
|
|
|
public Dictionary<int, string> TokenDrawOverrideEffectPair { get; private set; }
|
|
|
|
public string SpecialTokenDrawEffectOverrideText { get; private set; }
|
|
|
|
public Dictionary<int, string> SpecialTokenDrawOverrideEffectPair { get; private set; }
|
|
|
|
public bool IsVsEffectOverride { get; private set; }
|
|
|
|
public int ClassDestroyEffectOverride { get; private set; }
|
|
|
|
public SpecialBattleSetting(string id, bool? isPlayerFirst, string playerSkill, string enemySkill, int playerPp, int enemyPp, int playerLife, int playerMaxLife, int enemyMaxLife, string idOverrideBattleLogText, string banishEffectOverride, string tokenDrawEffectOverride, string specialTokenDrawEffectOverride, bool isVsEffectOverride, int classDestroyEffectOverride)
|
|
{
|
|
Id = id;
|
|
IsPlayerFirstTurn = isPlayerFirst;
|
|
PlayerAttachSkillText = playerSkill;
|
|
PlayerAttachSkills = SplitSpecialBattleDataText(PlayerAttachSkillText);
|
|
EnemyAttachSkillText = enemySkill;
|
|
EnemyAttachSkills = SplitSpecialBattleDataText(EnemyAttachSkillText);
|
|
PlayerStartPp = playerPp;
|
|
EnemyStartPp = enemyPp;
|
|
PlayerStartLife = playerLife;
|
|
PlayerStartMaxLife = playerMaxLife;
|
|
EnemyStartMaxLife = enemyMaxLife;
|
|
IdOverrideInBattleLogText = idOverrideBattleLogText;
|
|
IdOverridePairDict = ParseIdOverrideText(IdOverrideInBattleLogText);
|
|
BanishEffectOverRideText = banishEffectOverride;
|
|
BanishEffectOverRideIds = SplitSpecialBattleDataText(BanishEffectOverRideText);
|
|
TokenDrawEffectOverrideText = tokenDrawEffectOverride;
|
|
TokenDrawOverrideEffectPair = SplitSpecialBattleDataPair(TokenDrawEffectOverrideText);
|
|
SpecialTokenDrawEffectOverrideText = specialTokenDrawEffectOverride;
|
|
SpecialTokenDrawOverrideEffectPair = SplitSpecialBattleDataPair(SpecialTokenDrawEffectOverrideText);
|
|
IsVsEffectOverride = isVsEffectOverride;
|
|
ClassDestroyEffectOverride = classDestroyEffectOverride;
|
|
}
|
|
}
|
|
|
|
public enum BattleType
|
|
{
|
|
FreeBattle = 0,
|
|
RankBattle = 1,
|
|
TwoPick = 2,
|
|
RoomBattle = 3,
|
|
Story = 4,
|
|
Practice = 5,
|
|
RoomTwoPick = 6,
|
|
TwoPickBackdraft = 7,
|
|
ColosseumNormal = 8,
|
|
ColosseumTwoPick = 9,
|
|
ColosseumHof = 31,
|
|
Sealed = 32,
|
|
ColosseumWindFall = 33,
|
|
Gathering = 34,
|
|
Quest = 37,
|
|
OfflineEvent = 40,
|
|
CompetitionNormal = 42,
|
|
BossRushQuest = 45,
|
|
SecretBossQuest = 46,
|
|
CompetitionTwoPick = 47,
|
|
Avatar = 48,
|
|
ColosseumAvatar = 49,
|
|
None = 100
|
|
}
|
|
|
|
private int _selectDeckId;
|
|
|
|
private Format _selectDeckFormat;
|
|
|
|
private IList<int> _currentDeckCardIdList;
|
|
|
|
private int _deckMaxCardCount;
|
|
|
|
private int _enemyDeckMaxCardCount;
|
|
|
|
private IList<int> _currentEnemyDeckData;
|
|
|
|
private int _playerCharaId;
|
|
|
|
private int _playerSubClassId;
|
|
|
|
private long _playerSleeveId;
|
|
|
|
private string _playerEmotionId = "";
|
|
|
|
private int _enemyCharaId;
|
|
|
|
private int _enemySubClassId;
|
|
|
|
private long _enemySleeveId;
|
|
|
|
private string _enemyEmotionId = "";
|
|
|
|
public AIDataLibrary m_AIDataLibrary;
|
|
|
|
private int _soroPlay3DFieldId = 1;
|
|
|
|
private string _storyBgmId = "NONE";
|
|
|
|
public int m_EnemyAIDifficulty;
|
|
|
|
public int m_EnemyAILogicLevel;
|
|
|
|
public int m_EnemyAIDeckId;
|
|
|
|
public int m_EnemyAIStyleId;
|
|
|
|
public int m_EnemyAIEmoteId;
|
|
|
|
// Default 20 mirrors the historic AITestGlobal.AI_MAX_LIFE static default. Callers that don't
|
|
// invoke SetEnemyAI (e.g. non-AI test fixtures) still get a sensible enemy leader HP.
|
|
public int m_EnemyAIMaxLife = 20;
|
|
|
|
public bool m_EnemyAIUseInnerEmote = true;
|
|
|
|
private IDictionary<int, int> _possessionCardDict;
|
|
|
|
private IDictionary<int, int> _possessionCardDictIncludingSpotCard;
|
|
|
|
private IDictionary<int, bool> _isNewCardDict = new Dictionary<int, bool>();
|
|
|
|
private int[] _maintenanceCardIds;
|
|
|
|
private IDictionary<int, ClassCharaPrm> _classPrmDict;
|
|
|
|
private bool _isDirtyPossessionCardDict;
|
|
|
|
public BattleType m_BattleType = BattleType.None;
|
|
|
|
public TwoPickFormat TwoPickFormat;
|
|
|
|
public string BattleId = "";
|
|
|
|
private static string[] ClanNameTextIdList = new string[9] { "Common_0104", "Common_0105", "Common_0106", "Common_0107", "Common_0108", "Common_0109", "Common_0110", "Common_0111", "Common_0112" };
|
|
|
|
public DeckAttributeType LastSelectDeckAttributeType { private get; set; }
|
|
|
|
public int PracticeDifficultyDegreeId { get; set; }
|
|
|
|
public int Practice3DfieldId { get; set; }
|
|
|
|
public List<int> FavoriteCardList { get; private set; }
|
|
|
|
public DeckGroupListData CurrentDeckListParamData { get; set; }
|
|
|
|
public SpecialBattleSetting SpecialBattleSettingInfo { get; set; }
|
|
|
|
public BattleManagerBase.MissionNecessaryInformation MissionNecessaryInformation { get; set; } = new BattleManagerBase.MissionNecessaryInformation(new Dictionary<string, string>());
|
|
|
|
private MyRotationInfo _playerMyRotationInfo { get; set; }
|
|
|
|
private MyRotationInfo _enemyMyRotationInfo { get; set; }
|
|
|
|
private AvatarBattleInfo _playerAvatarBattleInfo { get; set; }
|
|
|
|
private AvatarBattleInfo _enemyAvatarBattleInfo { get; set; }
|
|
|
|
public QuestBattleData QuestBattleData { get; private set; }
|
|
|
|
public BossRushBattleData BossRushBattleData { get; private set; }
|
|
|
|
public int PuzzleQuestId { get; set; }
|
|
|
|
public int PuzzleDifficulty { get; set; }
|
|
|
|
public int PuzzleEnemyClass { get; set; }
|
|
|
|
public QuestSelectionPage.FirstSelectType QuestFirstSelectType { get; set; }
|
|
|
|
public int StoryEnemyClassId { get; set; }
|
|
|
|
public JsonData RecoveryData { get; private set; }
|
|
|
|
public SpecialBattleResultType SkipStorySpecialBattleResult { get; private set; }
|
|
|
|
public SpotCardData SpotCardData { get; set; }
|
|
|
|
public string TitleId { get; set; } = "0";
|
|
|
|
public bool IsLastSelectDeckAttributeType(DeckAttributeType deckAttributeType)
|
|
{
|
|
return deckAttributeType == LastSelectDeckAttributeType;
|
|
}
|
|
|
|
public void SetMissionNecessaryInformation(JsonData data)
|
|
{
|
|
Dictionary<string, string> dictionary = new Dictionary<string, string>();
|
|
if (data.Count > 0)
|
|
{
|
|
foreach (string key in data.Keys)
|
|
{
|
|
dictionary.Add(key, data.ToStringOrDefault(key, string.Empty));
|
|
}
|
|
}
|
|
MissionNecessaryInformation = new BattleManagerBase.MissionNecessaryInformation(dictionary);
|
|
}
|
|
|
|
public void SetQuestBattleData(QuestBattleData battleData)
|
|
{
|
|
QuestBattleData = battleData;
|
|
}
|
|
|
|
public void SetBossRushBattleData(BossRushBattleData battleData)
|
|
{
|
|
BossRushBattleData = battleData;
|
|
}
|
|
|
|
public void SetRecoveryData(JsonData recoveryData)
|
|
{
|
|
RecoveryData = recoveryData;
|
|
}
|
|
|
|
public bool IsDipslayHighRankFormat()
|
|
{
|
|
switch (m_BattleType)
|
|
{
|
|
case BattleType.TwoPick:
|
|
case BattleType.Story:
|
|
case BattleType.Practice:
|
|
case BattleType.RoomTwoPick:
|
|
case BattleType.TwoPickBackdraft:
|
|
case BattleType.ColosseumTwoPick:
|
|
case BattleType.ColosseumHof:
|
|
case BattleType.Sealed:
|
|
case BattleType.ColosseumWindFall:
|
|
case BattleType.Quest:
|
|
case BattleType.BossRushQuest:
|
|
case BattleType.SecretBossQuest:
|
|
case BattleType.CompetitionTwoPick:
|
|
case BattleType.Avatar:
|
|
return true;
|
|
default:
|
|
if (Data.CurrentFormat != Format.Max && Data.CurrentFormat != Format.Windfall && Data.CurrentFormat != Format.MyRotation)
|
|
{
|
|
return Data.CurrentFormat == Format.Avatar;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public bool IsQuestBattleType()
|
|
{
|
|
return IsQuestBattleType(m_BattleType);
|
|
}
|
|
|
|
public static bool IsQuestBattleType(BattleType battleType)
|
|
{
|
|
if (battleType == BattleType.Quest || (uint)(battleType - 45) <= 1u)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsRoomBattleType()
|
|
{
|
|
BattleType battleType = m_BattleType;
|
|
if (battleType == BattleType.RoomBattle || (uint)(battleType - 6) <= 1u)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public DataMgr()
|
|
{
|
|
_possessionCardDict = new Dictionary<int, int>();
|
|
_possessionCardDictIncludingSpotCard = new Dictionary<int, int>();
|
|
_maintenanceCardIds = null;
|
|
m_AIDataLibrary = new AIDataLibrary();
|
|
FavoriteCardList = new List<int>();
|
|
PracticeDifficultyDegreeId = 400001;
|
|
}
|
|
|
|
public void Load()
|
|
{
|
|
LoadClassData();
|
|
}
|
|
|
|
public void LoadEnemy()
|
|
{
|
|
LoadEnemyClassData();
|
|
}
|
|
|
|
public void LoadClassData()
|
|
{
|
|
if (_playerCharaId == 0)
|
|
{
|
|
SetPlayerCharaId(1);
|
|
}
|
|
SetPlayerSleeveId(_playerSleeveId);
|
|
}
|
|
|
|
public void ResetEnemyData()
|
|
{
|
|
_currentEnemyDeckData = null;
|
|
}
|
|
|
|
public void LoadEnemyClassData()
|
|
{
|
|
if (_enemyCharaId == 0)
|
|
{
|
|
SetEnemyCharaId(1);
|
|
}
|
|
SetEnemySleeveId(_enemySleeveId);
|
|
}
|
|
|
|
public void RegisterAICommonData()
|
|
{
|
|
for (int i = 0; i < Data.Master.AIBasicDataList.Set.Count; i++)
|
|
{
|
|
AICardDataAsset asset = Data.Master.AIBasicDataList.Set[i];
|
|
m_AIDataLibrary.RegisterBasicData(asset);
|
|
}
|
|
for (int j = 0; j < Data.Master.AICommonDataList.Set.Count; j++)
|
|
{
|
|
AICardDataAsset asset2 = Data.Master.AICommonDataList.Set[j];
|
|
m_AIDataLibrary.RegisterCommonData(asset2);
|
|
}
|
|
for (int k = 0; k < Data.Master.AIAllyCommonDataList.Set.Count; k++)
|
|
{
|
|
AICardDataAsset asset3 = Data.Master.AIAllyCommonDataList.Set[k];
|
|
m_AIDataLibrary.RegisterAllyCommonData(asset3);
|
|
}
|
|
m_AIDataLibrary.RegisterCommonStyle(Data.Master.AIStyleCommonDataList);
|
|
}
|
|
|
|
public void RegisterAIDeckData()
|
|
{
|
|
if (Data.Master.AIDeckDic == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (KeyValuePair<string, AICardDataAssetSet> item in Data.Master.AIDeckDic)
|
|
{
|
|
m_AIDataLibrary.RegisterDeckToDeckDic(item.Key, item.Value.Set);
|
|
}
|
|
}
|
|
|
|
public void RegisterAIStyleData()
|
|
{
|
|
foreach (KeyValuePair<string, List<AIPolicyDataAsset>> item in Data.Master.AIStyleDic)
|
|
{
|
|
m_AIDataLibrary.RegisterDeckStyle(item.Key, item.Value);
|
|
}
|
|
}
|
|
|
|
public void RegisterAIEmoteData()
|
|
{
|
|
foreach (KeyValuePair<string, List<AIEmoteDataAsset>> item in Data.Master.AIEmoteDic)
|
|
{
|
|
AIEmoteSet aIEmoteSet = new AIEmoteSet();
|
|
aIEmoteSet.CreateFromAsset(item.Value);
|
|
m_AIDataLibrary.RegisterEmoteSet(item.Key, aIEmoteSet);
|
|
}
|
|
}
|
|
|
|
public void RegisterAllAIData()
|
|
{
|
|
m_AIDataLibrary.Clear();
|
|
RegisterAICommonData();
|
|
RegisterAIDeckData();
|
|
RegisterAIStyleData();
|
|
RegisterAIEmoteData();
|
|
}
|
|
|
|
public void SetPlayerCharaId(int charaId)
|
|
{
|
|
_playerCharaId = charaId;
|
|
SetPlayerSubClassID(10);
|
|
SetPlayerMyRotationInfo("");
|
|
}
|
|
|
|
public void SetPlayerSubClassID(int subClassId)
|
|
{
|
|
_playerSubClassId = subClassId;
|
|
}
|
|
|
|
public void SetPlayerMyRotationInfo(string myRotationId)
|
|
{
|
|
_playerMyRotationInfo = Data.MyRotationAllInfo.Get(myRotationId);
|
|
}
|
|
|
|
public void SetPlayerAvatarBattleInfo(string id)
|
|
{
|
|
_playerAvatarBattleInfo = Data.AvatarBattleAllInfo.Get(id);
|
|
}
|
|
|
|
public void SetPlayerCharaIdByClassId(int classId, bool isCurrentChara = true)
|
|
{
|
|
SetPlayerCharaId(GetCharaPrmByClassId(classId, isCurrentChara).chara_id);
|
|
}
|
|
|
|
public void SetPlayerCharaIdBySkinId(int skinId)
|
|
{
|
|
SetPlayerCharaId(GetCharaPrmBySkinId(skinId).chara_id);
|
|
}
|
|
|
|
public void SetPlayerSleeveId(long sleeveId)
|
|
{
|
|
_playerSleeveId = Toolbox.ResourcesManager.GetExistingSleeveId(GetAbleSleeveId(sleeveId));
|
|
}
|
|
|
|
public void SetEnemyCharaId(int charaId)
|
|
{
|
|
_enemyCharaId = charaId;
|
|
SetEnemySubClassID(10);
|
|
SetEnemyMyRotationInfo("");
|
|
}
|
|
|
|
public void SetEnemySubClassID(int classId)
|
|
{
|
|
_enemySubClassId = classId;
|
|
}
|
|
|
|
public void SetEnemyMyRotationInfo(string myRotationId)
|
|
{
|
|
_enemyMyRotationInfo = Data.MyRotationAllInfo.Get(myRotationId);
|
|
}
|
|
|
|
public void ClearEnemyAvatarBattleInfo()
|
|
{
|
|
_enemyAvatarBattleInfo = null;
|
|
}
|
|
|
|
public void SetEnemySleeveId(long sleeveId)
|
|
{
|
|
_enemySleeveId = Toolbox.ResourcesManager.GetExistingSleeveId(GetAbleSleeveId(sleeveId));
|
|
}
|
|
|
|
public bool GetSelectDefDeck()
|
|
{
|
|
if (_selectDeckId == 0)
|
|
{
|
|
return PlayerPrefsWrapper.GetBool(PlayerPrefsWrapper.LAST_BATTLE_IS_DEFDECK);
|
|
}
|
|
return IsLastSelectDeckAttributeType(DeckAttributeType.DefaultDeck);
|
|
}
|
|
|
|
public void SetSelectDeckId(int id)
|
|
{
|
|
_selectDeckId = id;
|
|
}
|
|
|
|
public void SetSelectDeckFormat(Format format)
|
|
{
|
|
_selectDeckFormat = format;
|
|
}
|
|
|
|
public Format GetSelectDeckFormat()
|
|
{
|
|
return _selectDeckFormat;
|
|
}
|
|
|
|
public void SetCurrentDeckData(IList<int> deckdata)
|
|
{
|
|
_currentDeckCardIdList = deckdata;
|
|
}
|
|
|
|
public void SetCurrentEnemyDeckData(IList<int> deckdata)
|
|
{
|
|
_currentEnemyDeckData = deckdata;
|
|
}
|
|
|
|
public void SetDeckMaxCount(int count, bool isSelf)
|
|
{
|
|
if (count != -1 && count != 0)
|
|
{
|
|
if (isSelf)
|
|
{
|
|
_deckMaxCardCount = count;
|
|
}
|
|
else
|
|
{
|
|
_enemyDeckMaxCardCount = count;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetQuestAILogicAndDeckData(int classId, int enemyAiId)
|
|
{
|
|
StoryAISettingData settingData = Data.Master.QuestAISettingList.GetSettingData(enemyAiId);
|
|
SetCurrentEnemyDeckDataFromAIDeck(classId, -1, settingData.LogicLevel, 20, settingData.DeckId, settingData.StyleId, settingData.EmoteId, settingData.UseInnerEmote, enemyAiId);
|
|
}
|
|
|
|
public void SetCurrentEnemyDeckDataFromAIDeck(int classID, int difficulty, int logicLevel, int maxLife, int deckId, int styleId, int emoteId, bool useInnerEmote, int enemyAiID = -1, List<int> specialAbilityIdList = null)
|
|
{
|
|
if (classID == 0)
|
|
{
|
|
classID = 8;
|
|
}
|
|
m_EnemyAIDifficulty = difficulty;
|
|
m_EnemyAIDeckId = deckId;
|
|
m_EnemyAIStyleId = styleId;
|
|
m_EnemyAIEmoteId = emoteId;
|
|
m_EnemyAILogicLevel = logicLevel;
|
|
m_EnemyAIMaxLife = maxLife;
|
|
m_EnemyAIUseInnerEmote = useInnerEmote;
|
|
AI_LOGIC_LV logicLv = AI_LOGIC_LV.STRONG;
|
|
switch (logicLevel)
|
|
{
|
|
case 0:
|
|
logicLv = AI_LOGIC_LV.WEAK;
|
|
break;
|
|
case 1:
|
|
logicLv = AI_LOGIC_LV.MIDDLE;
|
|
break;
|
|
case 2:
|
|
logicLv = AI_LOGIC_LV.STRONG;
|
|
break;
|
|
}
|
|
string text = "ai/" + Data.Master.AIDeckFileNameList.GetFileName(deckId);
|
|
string styleName = "ai/" + Data.Master.AIStyleFileNameList.GetFileName(styleId);
|
|
string emoteName = "ai/" + Data.Master.AIEmoteFileNameList.GetFileName(emoteId);
|
|
m_AIDataLibrary.SaveBattleSetUpInfo(classID, logicLv, text, styleName, emoteName, useEmote: true, useInnerEmote, enemyAiID, specialAbilityIdList);
|
|
SetCurrentEnemyDeckDataFromAIDeck(text);
|
|
}
|
|
|
|
public void SetEnemyAIDeckFromCustomDeck(int classId, IList<int> deck, int difficulty = 2, int logicLevel = 2, int maxLife = 20, int styleId = 0, int emoteId = 0, bool useInnerEmote = true, int enemyAiID = -1)
|
|
{
|
|
m_EnemyAIDifficulty = difficulty;
|
|
m_EnemyAIDeckId = int.MinValue;
|
|
m_EnemyAIStyleId = styleId;
|
|
m_EnemyAIEmoteId = emoteId;
|
|
m_EnemyAILogicLevel = logicLevel;
|
|
m_EnemyAIMaxLife = maxLife;
|
|
m_EnemyAIUseInnerEmote = useInnerEmote;
|
|
AI_LOGIC_LV logicLv = AI_LOGIC_LV.STRONG;
|
|
switch (logicLevel)
|
|
{
|
|
case 0:
|
|
logicLv = AI_LOGIC_LV.WEAK;
|
|
break;
|
|
case 1:
|
|
logicLv = AI_LOGIC_LV.MIDDLE;
|
|
break;
|
|
case 2:
|
|
logicLv = AI_LOGIC_LV.STRONG;
|
|
break;
|
|
}
|
|
string styleName = "ai/" + Data.Master.AIStyleFileNameList.GetFileName(styleId);
|
|
string emoteName = "ai/" + Data.Master.AIEmoteFileNameList.GetFileName(emoteId);
|
|
m_AIDataLibrary.SaveBattleSetUpInfo(classId, logicLv, "", styleName, emoteName, useEmote: true, m_EnemyAIUseInnerEmote, enemyAiID, null);
|
|
SetCurrentEnemyDeckData(deck);
|
|
}
|
|
|
|
public void SetCurrentEnemyDeckDataFromAIDeck(string deckName)
|
|
{
|
|
AIDeckData aIDeckData = m_AIDataLibrary.SearchDeckData(deckName);
|
|
if (aIDeckData == null)
|
|
{
|
|
return;
|
|
}
|
|
_currentEnemyDeckData = new List<int>();
|
|
foreach (KeyValuePair<int, AICardData> item in aIDeckData.CardDic)
|
|
{
|
|
for (int i = 0; i < item.Value.CardNum; i++)
|
|
{
|
|
_currentEnemyDeckData.Add(item.Key);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetSoroPlay3DFieldID(int fieldID)
|
|
{
|
|
_soroPlay3DFieldId = fieldID;
|
|
}
|
|
|
|
public void SetStoryBgmID(string bgmID)
|
|
{
|
|
_storyBgmId = bgmID;
|
|
}
|
|
|
|
public void SetSpecialBattleSetting(bool? isPlayerFirst, string playerSkill, string enemySkill, int playerPp, int enemyPp, int playerLife, int playerMaxLife, int enemyMaxLife, string idOverrideBattleLogText, string id = "", string banishEffectOverride = "", string tokenDrawEffectOverride = "", string specialTokenDrawEffectOverride = "", int skipResult = 0, bool isVsEffectOverride = false, int classDestroyEffectOverride = 0)
|
|
{
|
|
SpecialBattleSettingInfo = new SpecialBattleSetting(id, isPlayerFirst, playerSkill, enemySkill, playerPp, enemyPp, playerLife, playerMaxLife, enemyMaxLife, idOverrideBattleLogText, banishEffectOverride, tokenDrawEffectOverride, specialTokenDrawEffectOverride, isVsEffectOverride, classDestroyEffectOverride);
|
|
SkipStorySpecialBattleResult = (SpecialBattleResultType)skipResult;
|
|
}
|
|
|
|
public void ClearSpecialBattleSettingInfo()
|
|
{
|
|
SpecialBattleSettingInfo = null;
|
|
}
|
|
|
|
private static Dictionary<int, int> ParseIdOverrideText(string idOverrideText)
|
|
{
|
|
if (string.IsNullOrEmpty(idOverrideText))
|
|
{
|
|
return null;
|
|
}
|
|
Dictionary<int, int> dictionary = new Dictionary<int, int>();
|
|
string[] array = SplitSpecialBattleDataText(idOverrideText);
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
string[] array2 = array[i].Split('=');
|
|
dictionary.Add(int.Parse(array2[0]), int.Parse(array2[1]));
|
|
dictionary.Add(int.Parse(array2[0]) + 1, int.Parse(array2[1]) + 1);
|
|
}
|
|
return dictionary;
|
|
}
|
|
|
|
private static string[] SplitSpecialBattleDataText(string text)
|
|
{
|
|
return text.Split(',');
|
|
}
|
|
|
|
private static Dictionary<int, string> SplitSpecialBattleDataPair(string text)
|
|
{
|
|
string[] array = text.Split(',');
|
|
Dictionary<int, string> dictionary = new Dictionary<int, string>();
|
|
for (int i = 0; i < array.Count(); i++)
|
|
{
|
|
string[] array2 = array[i].Split('=');
|
|
if (array2.Length == 2)
|
|
{
|
|
int key = int.Parse(array2[0]);
|
|
dictionary[key] = array2[1];
|
|
}
|
|
}
|
|
return dictionary;
|
|
}
|
|
|
|
public string GetClanNameByKey(int intclantype)
|
|
{
|
|
if (intclantype < ClanNameTextIdList.Length)
|
|
{
|
|
return Data.SystemText.Get(ClanNameTextIdList[intclantype]);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
public ClassCharaPrm GetClassPrm(int classId)
|
|
{
|
|
return _classPrmDict[classId];
|
|
}
|
|
|
|
public ClassCharacterMasterData GetCharaPrmByClassId(int classId, bool isCurrentChara = true)
|
|
{
|
|
ClassCharaPrm classPrm = GetClassPrm(classId);
|
|
if (!isCurrentChara)
|
|
{
|
|
return classPrm.DefaultCharaData;
|
|
}
|
|
return classPrm.CurrentCharaData;
|
|
}
|
|
|
|
public ClassCharacterMasterData GetCharaPrmByCharaId(int charaId)
|
|
{
|
|
return Data.Master.ClassCharacterList.Find((ClassCharacterMasterData x) => x.chara_id == charaId);
|
|
}
|
|
|
|
public ClassCharacterMasterData GetCharaPrmBySkinId(int skinId)
|
|
{
|
|
return Data.Master.ClassCharacterList.Find((ClassCharacterMasterData x) => x.skin_id == skinId && x.is_usable);
|
|
}
|
|
|
|
public int GetPlayerCharaId()
|
|
{
|
|
if (_playerCharaId == 0)
|
|
{
|
|
return PlayerPrefsWrapper.GetValue(PlayerPrefsWrapper.LAST_BATTLE_LEADER_ID);
|
|
}
|
|
return _playerCharaId;
|
|
}
|
|
|
|
public int GetPlayerSubClassId()
|
|
{
|
|
return _playerSubClassId;
|
|
}
|
|
|
|
public bool TryGetPlayerMyRotationInfo(out MyRotationInfo myRotationInfo)
|
|
{
|
|
myRotationInfo = _playerMyRotationInfo;
|
|
return myRotationInfo != null;
|
|
}
|
|
|
|
public bool TryGetPlayerAvatarBattleInfo(out AvatarBattleInfo avatarBattleInfo)
|
|
{
|
|
avatarBattleInfo = _playerAvatarBattleInfo;
|
|
return avatarBattleInfo != null;
|
|
}
|
|
|
|
public ClassCharacterMasterData GetPlayerCharaData()
|
|
{
|
|
return GetCharaPrmByCharaId(GetPlayerCharaId());
|
|
}
|
|
|
|
public int GetPlayerClassId()
|
|
{
|
|
return GetPlayerCharaData().class_id;
|
|
}
|
|
|
|
public int GetPlayerSkinId()
|
|
{
|
|
return GetPlayerCharaData().skin_id;
|
|
}
|
|
|
|
public long GetPlayerSleeveId()
|
|
{
|
|
return GetAbleSleeveId(_playerSleeveId);
|
|
}
|
|
|
|
public string GetPlayerEmotionId()
|
|
{
|
|
if (!(_playerEmotionId == ""))
|
|
{
|
|
return _playerEmotionId;
|
|
}
|
|
return GetPlayerSkinId().ToString();
|
|
}
|
|
|
|
public void SetPlayerEmotionId(string id)
|
|
{
|
|
_playerEmotionId = id;
|
|
}
|
|
|
|
public string GetEnemyEmotionId()
|
|
{
|
|
if (!(_enemyEmotionId == ""))
|
|
{
|
|
return _enemyEmotionId;
|
|
}
|
|
return GetEnemySkinId().ToString();
|
|
}
|
|
|
|
public void SetEnemyEmotionId(string id)
|
|
{
|
|
_enemyEmotionId = id;
|
|
}
|
|
|
|
public int GetEnemyCharaId()
|
|
{
|
|
if (_enemyCharaId == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
return _enemyCharaId;
|
|
}
|
|
|
|
public int GetEnemySubClassId()
|
|
{
|
|
return _enemySubClassId;
|
|
}
|
|
|
|
public ClassCharacterMasterData GetEnemyCharaData()
|
|
{
|
|
return GetCharaPrmByCharaId(GetEnemyCharaId());
|
|
}
|
|
|
|
public int GetEnemyClassId()
|
|
{
|
|
if (false /* Pre-Phase-5b: IsPuzzleQuest const-false */)
|
|
{
|
|
return PuzzleEnemyClass;
|
|
}
|
|
if (m_BattleType == BattleType.Story)
|
|
{
|
|
return StoryEnemyClassId;
|
|
}
|
|
return GetEnemyCharaData().class_id;
|
|
}
|
|
|
|
public int GetEnemySkinId()
|
|
{
|
|
return GetEnemyCharaData().skin_id;
|
|
}
|
|
|
|
public bool TryGetEnemyMyRotationInfo(out MyRotationInfo myRotationInfo)
|
|
{
|
|
myRotationInfo = _enemyMyRotationInfo;
|
|
return myRotationInfo != null;
|
|
}
|
|
|
|
public bool TryGetEnemyAvatarBattleInfo(out AvatarBattleInfo avatarBattleInfo)
|
|
{
|
|
avatarBattleInfo = _enemyAvatarBattleInfo;
|
|
return avatarBattleInfo != null;
|
|
}
|
|
|
|
public long GetEnemySleeveId()
|
|
{
|
|
return GetAbleSleeveId(_enemySleeveId);
|
|
}
|
|
|
|
public bool IsHighRankSkinPlayer()
|
|
{
|
|
return GetPlayerCharaData().IsHighRank;
|
|
}
|
|
|
|
public bool Is3DSkin(bool isPlayer)
|
|
{
|
|
if (isPlayer)
|
|
{
|
|
return GetPlayerCharaData().Is3d;
|
|
}
|
|
return GetEnemyCharaData().Is3d;
|
|
}
|
|
|
|
public bool IsEvolveSkin(bool isPlayer)
|
|
{
|
|
if (isPlayer)
|
|
{
|
|
return GetPlayerCharaData().IsEvolveSkin;
|
|
}
|
|
return GetEnemyCharaData().IsEvolveSkin;
|
|
}
|
|
|
|
public IList<int> GetCurrentDeckData()
|
|
{
|
|
return _currentDeckCardIdList;
|
|
}
|
|
|
|
public IList<int> GetCurrentEnemyDeckData()
|
|
{
|
|
return _currentEnemyDeckData;
|
|
}
|
|
|
|
public int GetDeckMaxCount(bool isSelf)
|
|
{
|
|
if (!isSelf)
|
|
{
|
|
return _enemyDeckMaxCardCount;
|
|
}
|
|
return _deckMaxCardCount;
|
|
}
|
|
|
|
public IDictionary<int, int> GetUserOwnCardData(bool isIncludingSpotCard)
|
|
{
|
|
if (isIncludingSpotCard)
|
|
{
|
|
if (_isDirtyPossessionCardDict)
|
|
{
|
|
UpdatePossessionCardDictIncludingSpotCard();
|
|
_isDirtyPossessionCardDict = false;
|
|
}
|
|
return _possessionCardDictIncludingSpotCard;
|
|
}
|
|
return _possessionCardDict;
|
|
}
|
|
|
|
public Dictionary<int, int> ClonePossessionCardDictionary(bool isIncludingSpotCard)
|
|
{
|
|
return new Dictionary<int, int>(GetUserOwnCardData(isIncludingSpotCard));
|
|
}
|
|
|
|
public bool HasPossesionCardInfo(int cardId, bool isIncludingSpotCard)
|
|
{
|
|
return GetUserOwnCardData(isIncludingSpotCard).ContainsKey(cardId);
|
|
}
|
|
|
|
public int GetPossessionCardNum(int cardId, bool isIncludingSpotCard)
|
|
{
|
|
int value = 0;
|
|
GetUserOwnCardData(isIncludingSpotCard).TryGetValue(cardId, out value);
|
|
return value;
|
|
}
|
|
|
|
public static int GetPossessionBaseCardNum(int baseCardId, IDictionary<int, int> cardPool, CardMaster.CardMasterId cardMasterId)
|
|
{
|
|
CardMaster instance = CardMaster.GetInstance(cardMasterId);
|
|
int num = 0;
|
|
foreach (KeyValuePair<int, int> item in cardPool)
|
|
{
|
|
if (instance.GetCardParameterFromId(item.Key).BaseCardId == baseCardId)
|
|
{
|
|
try
|
|
{
|
|
num = checked(num + item.Value);
|
|
}
|
|
catch (OverflowException)
|
|
{
|
|
return int.MaxValue;
|
|
}
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public int GetPossessionBaseCardNum(int baseCardId, bool isIncludingSpotCard, CardMaster.CardMasterId cardMasterId)
|
|
{
|
|
return GetPossessionBaseCardNum(baseCardId, GetUserOwnCardData(isIncludingSpotCard), cardMasterId);
|
|
}
|
|
|
|
public Dictionary<int, int> GetPossessionBaseCardDictionary(bool isIncludingSpotCard, CardMaster.CardMasterId cardMasterId)
|
|
{
|
|
CardMaster instance = CardMaster.GetInstance(cardMasterId);
|
|
Dictionary<int, int> dictionary = new Dictionary<int, int>();
|
|
foreach (KeyValuePair<int, int> userOwnCardDatum in GetUserOwnCardData(isIncludingSpotCard))
|
|
{
|
|
int baseCardId = instance.GetCardParameterFromId(userOwnCardDatum.Key).BaseCardId;
|
|
int value = 0;
|
|
if (dictionary.TryGetValue(baseCardId, out value))
|
|
{
|
|
try
|
|
{
|
|
dictionary[baseCardId] = checked(value + userOwnCardDatum.Value);
|
|
}
|
|
catch (OverflowException)
|
|
{
|
|
dictionary[baseCardId] = int.MaxValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dictionary.Add(baseCardId, userOwnCardDatum.Value);
|
|
}
|
|
}
|
|
return dictionary;
|
|
}
|
|
|
|
private void UpdatePossessionCardDictIncludingSpotCard()
|
|
{
|
|
_possessionCardDictIncludingSpotCard = SpotCardData.CreateDictionaryIncludingSpotCard(_possessionCardDict);
|
|
}
|
|
|
|
public void SetDirtyPossessionCardDict()
|
|
{
|
|
_isDirtyPossessionCardDict = true;
|
|
}
|
|
|
|
public void UpdateUserOwnCardData(int cardid, int num)
|
|
{
|
|
bool isNew = !HasPossesionCardInfo(cardid, isIncludingSpotCard: false);
|
|
SetIsNewCard(cardid, isNew);
|
|
if (_possessionCardDict.ContainsKey(cardid))
|
|
{
|
|
_possessionCardDict[cardid] = num;
|
|
}
|
|
else
|
|
{
|
|
_possessionCardDict.Add(cardid, num);
|
|
}
|
|
SetDirtyPossessionCardDict();
|
|
}
|
|
|
|
public bool IsNewCard(int cardId)
|
|
{
|
|
if (!_isNewCardDict.TryGetValue(cardId, out var value))
|
|
{
|
|
return false;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public void SetIsNewCard(int cardId, bool isNew)
|
|
{
|
|
_isNewCardDict[cardId] = isNew;
|
|
}
|
|
|
|
public void RegisterUserOwnCardData(int cardId, int num)
|
|
{
|
|
_possessionCardDict.Add(cardId, num);
|
|
SetDirtyPossessionCardDict();
|
|
}
|
|
|
|
public void UnregisterUserOwnCardData(int cardId)
|
|
{
|
|
_possessionCardDict.Remove(cardId);
|
|
SetDirtyPossessionCardDict();
|
|
}
|
|
|
|
public int GetSoroPlay3DFieldID()
|
|
{
|
|
return _soroPlay3DFieldId;
|
|
}
|
|
|
|
public string GetStoryBgmID()
|
|
{
|
|
return _storyBgmId;
|
|
}
|
|
|
|
public void SetMaintenanceCardIds(JsonData responseData)
|
|
{
|
|
if (responseData == null)
|
|
{
|
|
_maintenanceCardIds = null;
|
|
return;
|
|
}
|
|
_maintenanceCardIds = new int[responseData.Count];
|
|
for (int i = 0; i < responseData.Count; i++)
|
|
{
|
|
_maintenanceCardIds[i] = responseData[i]["card_id"].ToInt();
|
|
}
|
|
}
|
|
|
|
public void SetMaintenanceCardIds(int[] ids)
|
|
{
|
|
_maintenanceCardIds = ids;
|
|
}
|
|
|
|
public bool IsMaintenanceCard(int id)
|
|
{
|
|
if (_maintenanceCardIds != null)
|
|
{
|
|
return _maintenanceCardIds.Contains(id);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public Dictionary<ClassCharaPrm.EmotionType, Emotion> GetEmotionDataBySkinId(string skinId)
|
|
{
|
|
if (!Data.Master._emotionDic.ContainsKey(skinId))
|
|
{
|
|
LocalLog.AccumulateTraceLog("Not contain key given. skinId : " + skinId + " emotionMasterKeyCount : " + Data.Master._emotionDic.Keys.Count);
|
|
}
|
|
return Data.Master._emotionDic[skinId];
|
|
}
|
|
|
|
public static long GetAbleSleeveId(long sleeveId)
|
|
{
|
|
return Data.Master.SleeveMgr.Get(sleeveId).sleeve_id;
|
|
}
|
|
}
|