diff --git a/.editorconfig b/.editorconfig index f93ffb19d..1fc667073 100644 --- a/.editorconfig +++ b/.editorconfig @@ -29,8 +29,8 @@ dotnet_style_qualification_for_method = false dotnet_style_qualification_for_property = false # Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true -dotnet_style_predefined_type_for_member_access = true +dotnet_style_predefined_type_for_locals_parameters_members = false # Int32 value = 1; +dotnet_style_predefined_type_for_member_access = false # Int32.Parse # Parentheses preferences dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity diff --git a/.gitignore b/.gitignore index bb25283bf..8b9e81eac 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,14 @@ # Данный GITIGNORE-файл был автоматически создан Microsoft(R) Visual Studio. ################################################################################ +.idea/ +.vs/ bin/ obj/ /packages/ /Output/ -/.idea/ -/.vs/ /ipch/ +/References *.suo *.user *.DotSettings* @@ -19,5 +20,4 @@ obj/ *.sdf *.tlog *.meta -/References *.log diff --git a/Assembly-CSharp/Assembly-CSharp.csproj b/Assembly-CSharp/Assembly-CSharp.csproj index 6a84b925f..88fe72f90 100644 --- a/Assembly-CSharp/Assembly-CSharp.csproj +++ b/Assembly-CSharp/Assembly-CSharp.csproj @@ -1,5 +1,5 @@  - + @@ -15,7 +15,6 @@ $(SolutionDir)\References\ - latest AnyCPU @@ -28,7 +27,6 @@ 4 true CS0414;CS0649;CS0169;CS0108;CS0618 - false AnyCPU @@ -39,12 +37,15 @@ prompt 4 true - false ..\References\Assembly-CSharp-firstpass.dll + + True + + ..\References\UnityEngine.dll False @@ -341,9 +342,21 @@ + + + + + + + + + + + + @@ -1215,11 +1228,9 @@ - - + + - - @@ -1376,7 +1387,6 @@ - PreserveNewest @@ -1385,6 +1395,9 @@ PreserveNewest + + + diff --git a/Assembly-CSharp/Assets/Sources/Scripts/UI/Common/FF9TextTool.cs b/Assembly-CSharp/Assets/Sources/Scripts/UI/Common/FF9TextTool.cs index 9e017fdd6..b262ee858 100644 --- a/Assembly-CSharp/Assets/Sources/Scripts/UI/Common/FF9TextTool.cs +++ b/Assembly-CSharp/Assets/Sources/Scripts/UI/Common/FF9TextTool.cs @@ -19,6 +19,7 @@ public class FF9TextTool : PersistenSingleton public static Color Cyan => new Color(0.407843143f, 0.7529412f, 0.847058833f); public static Color Red => new Color(0.8156863f, 0.3764706f, 0.3137255f); public static Color Yellow => new Color(0.784313738f, 0.6901961f, 0.2509804f); + public static Color DarkYellow => new Color(0.588f, 0.584f, 0.267f); public static Color Magenta => new Color(0.721568644f, 0.5019608f, 0.8784314f); public static Int32 FieldZoneId => fieldZoneId; @@ -708,4 +709,4 @@ private static void ProcessEntryId(ref String entry, ref Int32 id) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/FF9/Param.cs b/Assembly-CSharp/FF9/Param.cs index 8aab71abf..cad8ff376 100644 --- a/Assembly-CSharp/FF9/Param.cs +++ b/Assembly-CSharp/FF9/Param.cs @@ -38,7 +38,9 @@ public class Param public const Byte FIG_STAT_INFO_REGENE_DMG = 8; - public const Byte WPN_CATEGORY_SHORT_RANGE = 1; + public const Byte FIG_STAT_INFO_REGENE_MP = 16; + + public const Byte WPN_CATEGORY_SHORT_RANGE = 1; public const Byte WPN_CATEGORY_LONG_RANGE = 2; diff --git a/Assembly-CSharp/FF9/btl_mot.cs b/Assembly-CSharp/FF9/btl_mot.cs index fcd135c49..b0f293370 100644 --- a/Assembly-CSharp/FF9/btl_mot.cs +++ b/Assembly-CSharp/FF9/btl_mot.cs @@ -203,65 +203,22 @@ public static Boolean IsLoopingMotion(BattlePlayerCharacter.PlayerMotionIndex in public static void PlayAnim(BTL_DATA btl) { - btl._smoothUpdatePlayingAnim = false; - if (btl.currentAnimationName == null) + if (btl.currentAnimationName == null || btl.bi.stop_anim != 0) return; - GameObject gameObject = btl.gameObject; - String currentAnimationName = btl.currentAnimationName; - UInt16 animMaxFrame = GeoAnim.geoAnimGetNumFrames(btl, currentAnimationName); - Boolean reverseSpeed = btl.animSpeed < 0f; - Single animFrame = btl.evt.animFrame; // + (reverseSpeed ? -btl.animFrameFrac : btl.animFrameFrac); - if (!gameObject.GetComponent().IsPlaying(currentAnimationName)) - { - if (gameObject.GetComponent().GetClip(currentAnimationName) == null) + + Animation anim = btl.gameObject.GetComponent(); + String animName = btl.currentAnimationName; + Int32 animMaxFrame = GeoAnim.geoAnimGetNumFrames(btl, animName); + if (!anim.IsPlaying(animName)) + { + if (anim.GetClip(animName) == null) return; - gameObject.GetComponent().Play(currentAnimationName); - } - AnimationState clipState = gameObject.GetComponent()[currentAnimationName]; - Single time = animMaxFrame == 0 ? 0f : Mathf.Clamp(animFrame / animMaxFrame * clipState.length, 0f, clipState.length); - Int32 animLoopFrame = GeoAnim.getAnimationLoopFrame(btl); - clipState.speed = 0f; - btl._smoothUpdatePlayingAnim = true; - btl._smoothUpdateAnimTimePrevious = clipState.time; - if (animMaxFrame != 0 && btl.bi.disappear == 0 && !btl_mot.IsAnimationFrozen(btl)) - { - if (btl.evt.animFrame == 0 && !reverseSpeed) - btl._smoothUpdateAnimTimePrevious = time - btl.animSpeed / animMaxFrame * clipState.length; - else if (btl.evt.animFrame == animLoopFrame && reverseSpeed) - btl._smoothUpdateAnimTimePrevious = time + btl.animSpeed / animMaxFrame * clipState.length; - } - btl._smoothUpdateAnimTimeActual = time; - clipState.time = time; - gameObject.GetComponent().Sample(); - if (btl.evt.animFrame == animLoopFrame && !reverseSpeed) - { - // Try to smoothen standard animation chains - if (btl_mot.checkMotion(btl, BattlePlayerCharacter.PlayerMotionIndex.MP_RUN)) - { - gameObject.GetComponent().CrossFade(btl.mot[(Int32)BattlePlayerCharacter.PlayerMotionIndex.MP_RUN_TO_ATTACK], 1f / FPSManager.GetMainLoopSpeed()); - btl._smoothUpdatePlayingAnim = false; - } - else if (btl_mot.checkMotion(btl, BattlePlayerCharacter.PlayerMotionIndex.MP_RUN_TO_ATTACK)) - { - gameObject.GetComponent().CrossFade(btl.mot[(Int32)BattlePlayerCharacter.PlayerMotionIndex.MP_ATTACK], 1f / FPSManager.GetMainLoopSpeed()); - btl._smoothUpdatePlayingAnim = false; - } - else if (btl_mot.checkMotion(btl, BattlePlayerCharacter.PlayerMotionIndex.MP_ATTACK)) - { - gameObject.GetComponent().CrossFade(btl.mot[(Int32)BattlePlayerCharacter.PlayerMotionIndex.MP_BACK], 1f / FPSManager.GetMainLoopSpeed()); - btl._smoothUpdatePlayingAnim = false; - } - else if (btl_mot.checkMotion(btl, BattlePlayerCharacter.PlayerMotionIndex.MP_BACK)) - { - gameObject.GetComponent().CrossFade(btl.mot[(Int32)BattlePlayerCharacter.PlayerMotionIndex.MP_ATK_TO_NORMAL], 1f / FPSManager.GetMainLoopSpeed()); - btl._smoothUpdatePlayingAnim = false; - } - else if (btl_mot.checkMotion(btl, BattlePlayerCharacter.PlayerMotionIndex.MP_ATK_TO_NORMAL)) - { - gameObject.GetComponent().CrossFade(btl.mot[(Int32)BattlePlayerCharacter.PlayerMotionIndex.MP_IDLE_NORMAL], 1f / FPSManager.GetMainLoopSpeed()); - btl._smoothUpdatePlayingAnim = false; - } + anim.Play(animName); } + AnimationState animState = anim[animName]; + animState.speed = 0f; + animState.time = (Single)btl.evt.animFrame / animMaxFrame * animState.length; + anim.Sample(); } public static Int32 GetDirection(BTL_DATA btl) @@ -547,7 +504,7 @@ public static void SetDefaultIdle(BTL_DATA btl, Boolean isEndOfAnim = false) BattlePlayerCharacter.PlayerMotionIndex currentAnim = btl_mot.getMotion(btl); if (btl_stat.CheckStatus(btl, BattleStatusConst.Immobilized)) { - if (btl.bi.player != 0 && !btl.is_monster_transform && btl_stat.CheckStatus(btl, BattleStatus.Venom & BattleStatusConst.IdleDying)) + if (btl.bi.player != 0 && !btl.is_monster_transform && btl_stat.CheckStatus(btl, BattleStatusConst.Immobilized & BattleStatusConst.IdleDying)) { btl_mot.setMotion(btl, BattlePlayerCharacter.PlayerMotionIndex.MP_IDLE_DYING); btl.evt.animFrame = 0; @@ -599,15 +556,15 @@ public static void SetDefaultIdle(BTL_DATA btl, Boolean isEndOfAnim = false) targetAnim = BattlePlayerCharacter.PlayerMotionIndex.MP_ESCAPE; else if (btl.bi.cmd_idle == 1) targetAnim = BattlePlayerCharacter.PlayerMotionIndex.MP_IDLE_CMD; - if (currentAnim == targetAnim) + if (currentAnim == targetAnim) { if (isEndOfAnim) btl.evt.animFrame = 0; return; } - BattlePlayerCharacter.PlayerMotionStance previousStance = btl_mot.EndingMotionStance(currentAnim); + BattlePlayerCharacter.PlayerMotionStance previousStance = btl_mot.EndingMotionStance(currentAnim); BattlePlayerCharacter.PlayerMotionStance nextStance = btl_mot.StartingMotionStance(targetAnim); - if (previousStance == BattlePlayerCharacter.PlayerMotionStance.SPECIAL_ANY_IDLE) + if (previousStance == BattlePlayerCharacter.PlayerMotionStance.SPECIAL_ANY_IDLE) { if (nextStance == BattlePlayerCharacter.PlayerMotionStance.NORMAL || nextStance == BattlePlayerCharacter.PlayerMotionStance.CMD || nextStance == BattlePlayerCharacter.PlayerMotionStance.DYING || nextStance == BattlePlayerCharacter.PlayerMotionStance.DEFEND) { @@ -910,4 +867,4 @@ public static void SetPlayerDefMotion(BTL_DATA btl, CharacterSerialNumber serial btl.animEndFrame = false; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/FF9/btl_sys.cs b/Assembly-CSharp/FF9/btl_sys.cs index 145dc7a20..166de5a2e 100644 --- a/Assembly-CSharp/FF9/btl_sys.cs +++ b/Assembly-CSharp/FF9/btl_sys.cs @@ -90,12 +90,8 @@ public static void CheckBattlePhase(BTL_DATA btl) { BattleUnit unit = new BattleUnit(next); Character player = unit.Player; - if (player.Equipment.Accessory == RegularItem.PhoenixDown && ff9item.FF9Item_GetCount(RegularItem.PhoenixDown) > 9 && ff9item.FF9Item_GetCount(RegularItem.PhoenixDown) > (Comn.random16() % 100)) - { - ff9item.FF9Item_Remove(RegularItem.PhoenixDown, 99); - ff9item.FF9Item_Add(RegularItem.PhoenixDown, Comn.random16() % 10); + if (player.Equipment.Accessory == RegularItem.PhoenixPinion && ff9item.FF9Item_GetCount(RegularItem.PhoenixPinion) > Comn.random8()) procRebirthFlame = true; - } } else { @@ -319,9 +315,9 @@ public static void CheckEscape(Boolean calc_check) } else { - if (calc_check && UIManager.Battle.FF9BMenu_IsEnableAtb()) + if (calc_check && UIManager.Battle.IsNativeEnableAtb()) SBattleCalculator.CalcMain(null, null, null, fleeScriptId); } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/FF9/btl_util.cs b/Assembly-CSharp/FF9/btl_util.cs index 38632303d..a52686d10 100644 --- a/Assembly-CSharp/FF9/btl_util.cs +++ b/Assembly-CSharp/FF9/btl_util.cs @@ -282,7 +282,7 @@ public static Boolean IsCommandDeclarable(BattleCommandId cmdNo) public static BattleAbilityId GetCommandMainActionIndex(CMD_DATA cmd) { - if (cmd.regist != null && cmd.regist.bi.player == 0) + if (cmd.regist != null && cmd.regist.bi.player == 0) return BattleAbilityId.Void; if (IsCommandMonsterTransform(cmd)) return BattleAbilityId.Void; @@ -307,24 +307,26 @@ public static BattleAbilityId GetCommandMainActionIndex(CMD_DATA cmd) } } - public static RegularItem GetCommandItem(CMD_DATA cmd) - { - if (cmd.regist != null && cmd.regist.bi.player == 0) - return RegularItem.NoItem; - if (IsCommandMonsterTransform(cmd) || IsCommandMonsterTransformAttack(cmd)) - return RegularItem.NoItem; - switch (cmd.cmd_no) - { - case BattleCommandId.Throw: - case BattleCommandId.Item: - case BattleCommandId.AutoPotion: - return (RegularItem)cmd.sub_no; - default: - return RegularItem.NoItem; - } - } - - public static AA_DATA GetCommandMonsterAttack(CMD_DATA cmd) + public static RegularItem GetCommandItem(CMD_DATA cmd) + { + if (cmd.regist != null && cmd.regist.bi.player == 0) + return RegularItem.NoItem; + if (IsCommandMonsterTransform(cmd) || IsCommandMonsterTransformAttack(cmd)) + return RegularItem.NoItem; + if (BattleHUD.MixCommandSet.Contains(cmd.cmd_no)) + return ff9mixitem.MixItemsData[cmd.sub_no].Result; + switch (cmd.cmd_no) + { + case BattleCommandId.Throw: + case BattleCommandId.Item: + case BattleCommandId.AutoPotion: + return (RegularItem)cmd.sub_no; + default: + return RegularItem.NoItem; + } + } + + public static AA_DATA GetCommandMonsterAttack(CMD_DATA cmd) { if (IsCommandMonsterTransform(cmd)) return cmd.regist.monster_transform.spell[cmd.sub_no]; @@ -347,7 +349,9 @@ public static AA_DATA GetCommandAction(CMD_DATA cmd) public static Int32 GetCommandScriptId(CMD_DATA cmd) { - switch (cmd.cmd_no) + if (BattleHUD.MixCommandSet.Contains(cmd.cmd_no)) + return ff9item.GetItemEffect(btl_util.GetCommandItem(cmd)).Ref.ScriptId; + switch (cmd.cmd_no) { case BattleCommandId.Jump: case BattleCommandId.Jump2: diff --git a/Assembly-CSharp/Global/AbilityUI.cs b/Assembly-CSharp/Global/AbilityUI.cs index 0857c23d2..7c32f5b97 100644 --- a/Assembly-CSharp/Global/AbilityUI.cs +++ b/Assembly-CSharp/Global/AbilityUI.cs @@ -140,31 +140,132 @@ public override void Show(SceneVoidDelegate afterFinished = null) this.DisplayAllButton(); this.activeAbilityScrollList.ScrollButton.DisplayScrollButton(false, false); this.supportAbilityScrollList.ScrollButton.DisplayScrollButton(false, false); + this.CommandPanel.SetActive(true); + this.MagicStonePanel.SetActive(false); + this.UpdateUserInterface(); } public void UpdateUserInterface() { if (!Configuration.Interface.IsEnabled) return; + + _abilityPanel.ScrollButton.Panel.alpha = 0.5f; + _supportPanel.ScrollButton.Panel.alpha = 0.5f; const Int32 originalLineCount = 6; + const Int32 originalColumnCount = 2; const Single buttonOriginalHeight = 92f; const Single panelOriginalWidth = 1488f; const Single panelOriginalHeight = originalLineCount * buttonOriginalHeight; + + // ----------- ACTIVE ABILITIES ----------- // + Int32 linePerPage = Configuration.Interface.MenuAbilityRowCount; + Int32 columnPerPage = (Int32)Math.Floor((Single)(originalColumnCount * ((Single)linePerPage / originalLineCount))); + + if (originalColumnCount * originalLineCount >= this.aaIdList.Count) // 2 columns suffice + { + linePerPage = originalLineCount; + columnPerPage = originalColumnCount; + } + else if (linePerPage >= originalLineCount * 2 && (originalColumnCount + 1) * (originalLineCount + originalLineCount / originalColumnCount) >= this.aaIdList.Count) // 3 columns suffice + { + linePerPage = originalLineCount + originalLineCount / originalColumnCount; + columnPerPage = originalColumnCount + 1; + } + else if (columnPerPage == 4 && this.aaIdList.Count > 27 && this.aaIdList.Count <= 30) + { + columnPerPage = 3; + linePerPage = 10; + } + else if (columnPerPage == 4 && this.aaIdList.Count > 30 && this.aaIdList.Count <= 33) + { + columnPerPage = 3; + linePerPage = 11; + } + else if (columnPerPage == 4 && this.aaIdList.Count > 33 && this.aaIdList.Count <= 36) + { + columnPerPage = 3; + linePerPage = 12; + } Int32 lineHeight = (Int32)Math.Round(panelOriginalHeight / linePerPage); Single scaleFactor = lineHeight / buttonOriginalHeight; - _abilityPanel.SubPanel.ChangeDims(2, linePerPage, panelOriginalWidth / 2f, lineHeight); + + Single alphaColumnTitles = (columnPerPage > originalColumnCount) ? 0f : 1f; + _abilityPanel.Background.Panel.Name.Label.alpha = alphaColumnTitles; + _abilityPanel.Background.Panel.Info.Label.alpha = alphaColumnTitles; + _abilityPanel.Background.Panel.Name2.Label.alpha = alphaColumnTitles; + _abilityPanel.Background.Panel.Info2.Label.alpha = alphaColumnTitles; + + if (columnPerPage * linePerPage >= this.aaIdList.Count) + { + _abilityPanel.ScrollButton.Panel.alpha = 0f; + } + + _abilityPanel.SubPanel.ChangeDims(columnPerPage, linePerPage, panelOriginalWidth / columnPerPage, lineHeight); _abilityPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _abilityPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.091f, relRight: 0.795f); - _abilityPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _abilityPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.8f, relRight: 0.92f); _abilityPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _abilityPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _abilityPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _abilityPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.8f, relRight: 0.92f); _abilityPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _abilityPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _abilityPanel.SubPanel.RecycleListPopulator.RefreshTableView(); - _supportPanel.SubPanel.ChangeDims(2, linePerPage, panelOriginalWidth / 2f, lineHeight); + + // ----------- SUPPORT ABILITIES ----------- // + + linePerPage = Configuration.Interface.MenuAbilityRowCount; + columnPerPage = (Int32)Math.Floor((Single)(originalColumnCount * ((Single)linePerPage / originalLineCount))); + if (originalColumnCount * originalLineCount >= this.saIdList.Count) // 2 columns suffice + { + linePerPage = originalLineCount; + columnPerPage = originalColumnCount; + } + else if (linePerPage >= originalLineCount * 2 && (originalColumnCount + 1) * (originalLineCount + originalLineCount / originalColumnCount) >= this.saIdList.Count) // 3 columns suffice + { + linePerPage = originalLineCount + originalLineCount / originalColumnCount; + columnPerPage = originalColumnCount + 1; + } + else if (columnPerPage == 4 && this.saIdList.Count > 27 && this.saIdList.Count <= 30) + { + columnPerPage = 3; + linePerPage = 10; + } + else if (columnPerPage == 4 && this.saIdList.Count > 30 && this.saIdList.Count <= 33) + { + columnPerPage = 3; + linePerPage = 11; + } + else if (columnPerPage == 4 && this.saIdList.Count > 33 && this.saIdList.Count <= 36) + { + columnPerPage = 3; + linePerPage = 12; + } + lineHeight = (Int32)Math.Round(panelOriginalHeight / linePerPage); + scaleFactor = lineHeight / buttonOriginalHeight; + + alphaColumnTitles = (columnPerPage > originalColumnCount) ? 0f : 1f; + _supportPanel.Background.Panel.Name.Label.alpha = alphaColumnTitles; + _supportPanel.Background.Panel.Info.Label.alpha = alphaColumnTitles; + _supportPanel.Background.Panel.Name2.Label.alpha = alphaColumnTitles; + _supportPanel.Background.Panel.Info2.Label.alpha = alphaColumnTitles; + + if (columnPerPage * linePerPage >= this.saIdList.Count) + { + _supportPanel.ScrollButton.Panel.alpha = 0f; + } + + _supportPanel.SubPanel.ChangeDims(columnPerPage, linePerPage, panelOriginalWidth / columnPerPage, lineHeight); _supportPanel.SubPanel.ButtonPrefab.IconSprite.SetAnchor(target: _supportPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.09f, relRight: 0.176f); + _supportPanel.SubPanel.ButtonPrefab.IconSprite.width = _supportPanel.SubPanel.ButtonPrefab.IconSprite.height; + _supportPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _supportPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.24f, relRight: 0.795f); - _supportPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _supportPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.8f, relRight: 0.92f); _supportPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _supportPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _supportPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _supportPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.152f, relTop: 0.848f, relLeft: 0.8f, relRight: 0.92f); _supportPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _supportPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _supportPanel.SubPanel.RecycleListPopulator.RefreshTableView(); } @@ -230,12 +331,12 @@ public override Boolean OnKeyConfirm(GameObject go) Character player = FF9StateSystem.Common.FF9.party.GetCharacter(this.currentPartyIndex); this.currentAbilityIndex = go.GetComponent().ItemDataIndex; Int32 abilId = this.aaIdList[this.currentAbilityIndex]; - if (abilId != 0 && ff9abil.IsAbilityActive(abilId)) - { - BattleAbilityId battleAbilId = ff9abil.GetActiveAbilityFromAbilityId(abilId); - BattleAbilityId patchedId = this.PatchAbility(battleAbilId); - this.canMultiTarget = this.IsMulti(patchedId); - if (this.CheckAAType(abilId, player) == AbilityType.Enable) + if (abilId != 0 && ff9abil.IsAbilityActive(abilId)) + { + BattleAbilityId battleAbilId = ff9abil.GetActiveAbilityFromAbilityId(abilId); + BattleAbilityId patchedId = this.PatchAbility(battleAbilId); + this.canMultiTarget = this.IsMulti(patchedId); + if (this.CheckAAType(abilId, player) == AbilityType.Enable) { if (this.canMultiTarget) { @@ -321,7 +422,7 @@ public override Boolean OnKeyConfirm(GameObject go) List boostedList = ff9abil.GetBoostedAbilityList(supportId); Boolean enableNext = boostLevel < boostMaxLevel; if (enableNext) - { + { CharacterAbilityGems nextBoost = ff9abil._FF9Abil_SaData[boostedList[boostLevel]]; enableNext = this.CheckSAType(ff9abil.GetAbilityIdFromSupportAbility(nextBoost.Id), player) == AbilityType.Enable; if (enableNext) @@ -333,14 +434,14 @@ public override Boolean OnKeyConfirm(GameObject go) if (!enableNext) { foreach (SupportAbility boosted in boostedList) - { + { if (ff9abil.FF9Abil_IsEnableSA(player.Data.saExtended, boosted)) { CharacterAbilityGems boostedGem = ff9abil._FF9Abil_SaData[boosted]; ff9abil.FF9Abil_SetEnableSA(player.Data, boosted, false); player.Data.cur.capa += boostedGem.GemsCount; } - } + } ff9abil.FF9Abil_SetEnableSA(player.Data, supportId, false); player.Data.cur.capa += saData.GemsCount; } @@ -375,8 +476,8 @@ public override Boolean OnKeyConfirm(GameObject go) Int32 memberIndex = go.transform.GetSiblingIndex(); PLAYER caster = FF9StateSystem.Common.FF9.party.member[this.currentPartyIndex]; BattleAbilityId abilId = ff9abil.GetActiveAbilityFromAbilityId(this.aaIdList[this.currentAbilityIndex]); - BattleAbilityId patchedId = this.PatchAbility(abilId); - AA_DATA aaData = FF9StateSystem.Battle.FF9Battle.aa_data[patchedId]; + BattleAbilityId patchedId = this.PatchAbility(abilId); + AA_DATA aaData = FF9StateSystem.Battle.FF9Battle.aa_data[patchedId]; if (!this.multiTarget) { canUseAbility = SFieldCalculator.FieldCalcMain(caster, FF9StateSystem.Common.FF9.party.member[memberIndex], aaData, aaData.Ref.ScriptId, 0U); @@ -513,9 +614,9 @@ public override Boolean OnKeySpecial(GameObject go) player.Data.cur.capa -= boostedGem.GemsCount; } else - { + { break; - } + } } } ff9play.FF9Play_Update(player.Data); @@ -586,6 +687,7 @@ public override Boolean OnKeyLeftBumper(GameObject go) this.ShowPointerWhenLoading = false; }); this.SwitchCharacter(false); + UpdateUserInterface(); } } } @@ -626,6 +728,7 @@ public override Boolean OnKeyRightBumper(GameObject go) this.ShowPointerWhenLoading = false; }); this.SwitchCharacter(false); + UpdateUserInterface(); } } } @@ -887,7 +990,7 @@ private void DisplayAA() this.activeAbilityScrollList.SetOriginalData(inDataList); if (ButtonGroupState.HaveCursorMemorize(ActionAbilityGroupButton)) return; - this.activeAbilityScrollList.JumpToIndex(this.firstActiveAbility, false); + this.activeAbilityScrollList.JumpToIndex(this.firstActiveAbility, true); } } @@ -908,8 +1011,8 @@ private void DisplayAADetail(Transform item, ListDataTypeBase data, Int32 index, BattleAbilityId battleAbilId = ff9abil.GetActiveAbilityFromAbilityId(abilityListData.Id); itemListDetailHud.Content.SetActive(true); ButtonGroupState.SetButtonAnimation(itemListDetailHud.Self, abilityListData.Type == AbilityType.Enable); - BattleAbilityId patchedId = this.PatchAbility(battleAbilId); - Int32 mp = GetMp(FF9StateSystem.Battle.FF9Battle.aa_data[patchedId]); + BattleAbilityId patchedId = this.PatchAbility(battleAbilId); + Int32 mp = GetMp(FF9StateSystem.Battle.FF9Battle.aa_data[patchedId]); itemListDetailHud.NameLabel.text = FF9TextTool.ActionAbilityName(patchedId); itemListDetailHud.NumberLabel.text = mp != 0 ? mp.ToString() : String.Empty; if (abilityListData.Type == AbilityType.CantSpell) @@ -964,7 +1067,7 @@ private void DisplaySA() this.supportAbilityScrollList.SetOriginalData(inDataList); if (ButtonGroupState.HaveCursorMemorize(SupportAbilityGroupButton)) return; - this.supportAbilityScrollList.JumpToIndex(this.firstActiveAbility, false); + this.supportAbilityScrollList.JumpToIndex(this.firstActiveAbility, true); } } @@ -1049,8 +1152,8 @@ private void DisplayTarget() charHud.Content.SetActive(true); FF9UIDataTool.DisplayCharacterDetail(player, charHud); FF9UIDataTool.DisplayCharacterAvatar(player, new Vector2(), new Vector2(), charHud.AvatarSprite, false); - AA_DATA patchedAbil = FF9StateSystem.Battle.FF9Battle.aa_data[this.PatchAbility(ff9abil.GetActiveAbilityFromAbilityId(this.aaIdList[this.currentAbilityIndex]))]; - switch (patchedAbil.Info.DisplayStats) + AA_DATA patchedAbil = FF9StateSystem.Battle.FF9Battle.aa_data[this.PatchAbility(ff9abil.GetActiveAbilityFromAbilityId(this.aaIdList[this.currentAbilityIndex]))]; + switch (patchedAbil.Info.DisplayStats) { case TargetDisplay.None: case TargetDisplay.Hp: @@ -1099,7 +1202,7 @@ private Boolean IsMulti(BattleAbilityId battleAbilityId) private AbilityType CheckAAType(Int32 abilityId, Character player) { BattleAbilityId patchedId = this.PatchAbility(ff9abil.GetActiveAbilityFromAbilityId(abilityId)); - AA_DATA patchedAbil = FF9BattleDB.CharacterActions[patchedId]; + AA_DATA patchedAbil = FF9BattleDB.CharacterActions[patchedId]; if (!this.equipmentPartInAbilityDict.ContainsKey(abilityId)) { @@ -1157,7 +1260,7 @@ private AbilityType CheckSAType(Int32 abilityId, Character player) private static Int32 GetMp(AA_DATA aa_data) { Int32 mpCost = aa_data.MP; - if ((aa_data.Type & 4) != 0 && FF9StateSystem.EventState.gEventGlobal[18] != 0) + if ((aa_data.Type & 4) != 0 && battle.GARNET_SUMMON_FLAG != 0) mpCost <<= 2; return mpCost; } diff --git a/Assembly-CSharp/Global/AllSoundDispatchPlayer.cs b/Assembly-CSharp/Global/AllSoundDispatchPlayer.cs index 0d47f24f1..1ad9246bd 100644 --- a/Assembly-CSharp/Global/AllSoundDispatchPlayer.cs +++ b/Assembly-CSharp/Global/AllSoundDispatchPlayer.cs @@ -119,8 +119,7 @@ public void FF9SOUND_SONG_LOAD(Int32 ObjNo) this.CreateSound(soundProfile); soundProfile.SoundVolume = 1f; ISdLibAPIProxy.Instance.SdSoundSystem_SoundCtrl_SetVolume(soundProfile.SoundID, SoundLib.MusicPlayer.Volume, 0); - ISdLibAPIProxy.Instance.SdSoundSystem_SoundCtrl_SetPause(soundProfile.SoundID, 1, 0); - Int16 fldMapNo = FF9StateSystem.Common.FF9.fldMapNo; + Int16 fldMapNo = FF9StateSystem.Common.FF9.fldMapNo; if (fldMapNo == 503 && PersistenSingleton.Instance.eBin.getVarManually(EBin.SC_COUNTER_SVR) == 2970 && PersistenSingleton.Instance.eBin.getVarManually(EBin.MAP_INDEX_SVR) == 11 && ObjNo == 35) { // What is this for ? - SamsamTS @@ -129,7 +128,8 @@ public void FF9SOUND_SONG_LOAD(Int32 ObjNo) ISdLibAPIProxy.Instance.SdSoundSystem_SoundCtrl_SetVolume(soundProfile.SoundID, 0f, 0); } ISdLibAPIProxy.Instance.SdSoundSystem_SoundCtrl_Start(soundProfile.SoundID, 0); - this.currentMusicID = ObjNo; + ISdLibAPIProxy.Instance.SdSoundSystem_SoundCtrl_SetPause(soundProfile.SoundID, 1, 0); + this.currentMusicID = ObjNo; this.StopAndClearSuspendBGM(ObjNo, true); }); } diff --git a/Assembly-CSharp/Global/BGOVERLAY_DEF.cs b/Assembly-CSharp/Global/BGOVERLAY_DEF.cs index f47f43bb9..cf04773ec 100644 --- a/Assembly-CSharp/Global/BGOVERLAY_DEF.cs +++ b/Assembly-CSharp/Global/BGOVERLAY_DEF.cs @@ -3,130 +3,138 @@ using System.IO; using UnityEngine; +/// Defines individual background layers public partial class BGOVERLAY_DEF { - public BGOVERLAY_DEF() - { - this.startOffset = 0L; - this.spriteList = new List(); - this.canCombine = true; - this.isCreated = false; - } - - public void SetFlags(OVERLAY_FLAG flagDiff, Boolean isSet) - { - if (isSet) - { - this.flags |= flagDiff; - if ((this.flags & OVERLAY_FLAG.Active) != 0) - this.transform.gameObject.SetActive(true); - } - else - { - this.flags &= ~flagDiff; - if ((this.flags & OVERLAY_FLAG.Active) == 0) - this.transform.gameObject.SetActive(false); - } - } - - public void ReadData(BinaryReader reader) - { - this.startOffset = reader.BaseStream.Position; - UInt32 buffer = reader.ReadUInt32(); - this.oriData = buffer; - this.flags = (OVERLAY_FLAG)(buffer & 0xFFu); - this.curZ = (UInt16)(buffer >> 8 & 0xFFFu); - this.orgZ = (UInt16)(buffer >> 20 & 0xFFFu); - this.w = reader.ReadUInt16(); - this.h = reader.ReadUInt16(); - this.orgX = (float)reader.ReadInt16(); - this.orgY = (float)reader.ReadInt16(); - this.curX = (float)reader.ReadInt16(); - this.curY = (float)reader.ReadInt16(); - this.minX = reader.ReadInt16(); - this.maxX = reader.ReadInt16(); - this.minY = reader.ReadInt16(); - this.maxY = reader.ReadInt16(); - this.scrX = (float)reader.ReadInt16(); - this.scrY = (float)reader.ReadInt16(); - this.scrollX = reader.ReadInt16(); - this.scrollY = reader.ReadInt16(); - this.fracX = reader.ReadInt16(); - this.fracY = reader.ReadInt16(); - Byte bitPos = 0; - buffer = reader.ReadUInt32(); - this.camNdx = (Byte)BitUtil.ReadBits(buffer, ref bitPos, 8); - this.isXOffset = (Byte)BitUtil.ReadBits(buffer, ref bitPos, 1); - this.viewportNdx = (Byte)BitUtil.ReadBits(buffer, ref bitPos, 7); - this.spriteCount = (UInt16)BitUtil.ReadBits(buffer, ref bitPos, 16); - this.locOffset = reader.ReadUInt32(); - this.prmOffset = reader.ReadUInt32(); - this.sprtWork = reader.ReadUInt32(); - this.tpageWork = reader.ReadUInt32(); - } - - public OVERLAY_FLAG flags; - - public UInt16 curZ; - public UInt16 orgZ; - public UInt16 w; - public UInt16 h; - public float orgX; - public float orgY; - public float curX; - public float curY; - public float prevX; - public float prevY; - - public Int16 minX; - public Int16 maxX; - public Int16 minY; - public Int16 maxY; - - public float scrX; - public float scrY; - - public Int16 scrollX; // negative is slower (further) than main, positive faster (closer) - public Int16 scrollY; - - public Int16 fracX; - public Int16 fracY; - - public Byte camNdx; - - public Byte isXOffset; - public UInt32 indnum; - public Byte viewportNdx; - - public UInt16 spriteCount; - - public UInt32 locOffset; - public UInt32 prmOffset; - public UInt32 sprtWork; - public UInt32 tpageWork; - public Int64 startOffset; - - public UInt32 oriData; - - public List spriteList; - - public Transform transform; - - public Boolean canCombine; - public Boolean isCreated; - - public Boolean isMemoria = false; - public Vector2 memoriaSize; - public Texture2D memoriaImage; - public Material memoriaMaterial; - - [Flags] - public enum OVERLAY_FLAG - { - ScreenAnchored = 1, - Active = 2, - Loop = 4, - Parallax = 8, - ScrollWithOffset = 128 - } + public BGOVERLAY_DEF() + { + this.startOffset = 0L; + this.spriteList = new List(); + this.canCombine = true; + this.isCreated = false; + this.timedMoveDuration = 0; + } + + public void SetFlags(OVERLAY_FLAG flagDiff, Boolean isSet) + { + if (isSet) + { + this.flags |= flagDiff; + if ((this.flags & OVERLAY_FLAG.Active) != 0) + this.transform.gameObject.SetActive(true); + } + else + { + this.flags &= ~flagDiff; + if ((this.flags & OVERLAY_FLAG.Active) == 0) + this.transform.gameObject.SetActive(false); + } + } + + public void ReadData(BinaryReader reader) + { + this.startOffset = reader.BaseStream.Position; + UInt32 buffer = reader.ReadUInt32(); + this.oriData = buffer; + this.flags = (OVERLAY_FLAG)(buffer & 0xFFu); + this.curZ = (UInt16)(buffer >> 8 & 0xFFFu); + this.orgZ = (UInt16)(buffer >> 20 & 0xFFFu); + this.w = reader.ReadUInt16(); + this.h = reader.ReadUInt16(); + this.orgX = (float)reader.ReadInt16(); + this.orgY = (float)reader.ReadInt16(); + this.curX = (float)reader.ReadInt16(); + this.curY = (float)reader.ReadInt16(); + this.minX = reader.ReadInt16(); + this.maxX = reader.ReadInt16(); + this.minY = reader.ReadInt16(); + this.maxY = reader.ReadInt16(); + this.scrX = (float)reader.ReadInt16(); + this.scrY = (float)reader.ReadInt16(); + this.scrollX = reader.ReadInt16(); + this.scrollY = reader.ReadInt16(); + this.fracX = reader.ReadInt16(); + this.fracY = reader.ReadInt16(); + Byte bitPos = 0; + buffer = reader.ReadUInt32(); + this.camNdx = (Byte)BitUtil.ReadBits(buffer, ref bitPos, 8); + this.isXOffset = (Byte)BitUtil.ReadBits(buffer, ref bitPos, 1); + this.viewportNdx = (Byte)BitUtil.ReadBits(buffer, ref bitPos, 7); + this.spriteCount = (UInt16)BitUtil.ReadBits(buffer, ref bitPos, 16); + this.locOffset = reader.ReadUInt32(); + this.prmOffset = reader.ReadUInt32(); + this.sprtWork = reader.ReadUInt32(); + this.tpageWork = reader.ReadUInt32(); + } + + public OVERLAY_FLAG flags; + + public UInt16 curZ; + public UInt16 orgZ; + /// Overlay width + public UInt16 w; + /// Overlay height + public UInt16 h; + public float orgX; + public float orgY; + public float curX; + public float curY; + + /// Limits overlay's movement (Fieldmap.EBG_overlayMove) + public Int16 minX, maxX, minY, maxY; + + public float scrX; + public float scrY; + + /// Scroll: Overlay horizontal scrolling speed, (negative: left) / Parallax: position ratio to player (256 = half speed, -256 = double speed) + public Int16 scrollX, scrollY; + + + /// (Obsolete) used to contain fractional position value + public Int16 fracX, fracY; + + public Byte camNdx; + + public Byte isXOffset; + public UInt32 indnum; + public Byte viewportNdx; + + public UInt16 spriteCount; + + public UInt32 locOffset; + public UInt32 prmOffset; + public UInt32 sprtWork; + public UInt32 tpageWork; + public Int64 startOffset; + + public UInt32 oriData; + + public List spriteList; + + public Transform transform; + + public Boolean canCombine; + public Boolean isCreated; + + // For EBG_overlayMoveTimed + public Single dxTimed; + public Single dyTimed; + public Int16 dzTimed; + public Int32 timedMoveDuration; + + // Custom overlay using an unmixed image instead of tiles + public Boolean isMemoria = false; + public Vector2 memoriaSize; + public Texture2D memoriaImage; + public Material memoriaMaterial; + + [Flags] + public enum OVERLAY_FLAG + { + ScreenAnchored = 1, + Active = 2, + Loop = 4, + Parallax = 8, + ScrollWithOffset = 128 + } } diff --git a/Assembly-CSharp/Global/BGSPRITE_LOC_DEF.cs b/Assembly-CSharp/Global/BGSPRITE_LOC_DEF.cs index fd3ccd062..55e830a3f 100644 --- a/Assembly-CSharp/Global/BGSPRITE_LOC_DEF.cs +++ b/Assembly-CSharp/Global/BGSPRITE_LOC_DEF.cs @@ -2,6 +2,7 @@ using System.IO; using UnityEngine; +/// Class for individual tiles in an overlay public class BGSPRITE_LOC_DEF { public void ReadData_BGSPRITE_DEF(BinaryReader reader) diff --git a/Assembly-CSharp/Global/BTL_DATA.cs b/Assembly-CSharp/Global/BTL_DATA.cs index d1d79fd33..12ba86520 100644 --- a/Assembly-CSharp/Global/BTL_DATA.cs +++ b/Assembly-CSharp/Global/BTL_DATA.cs @@ -172,7 +172,8 @@ public void CheckDelayedModifier() public List saMonster; public Int32 fig_regene_hp; - public Int32 fig_poison_hp; + public Int32 fig_regene_mp; + public Int32 fig_poison_hp; public Int32 fig_poison_mp; public Byte fig_stat_info; @@ -292,4 +293,4 @@ public class DelayedModifier public IsDelayedDelegate isDelayed = null; public ApplyDelegate apply = null; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/Bubble/BubbleUI.cs b/Assembly-CSharp/Global/Bubble/BubbleUI.cs index 127f87944..fe163aef7 100644 --- a/Assembly-CSharp/Global/Bubble/BubbleUI.cs +++ b/Assembly-CSharp/Global/Bubble/BubbleUI.cs @@ -501,6 +501,15 @@ private void SetupParent() public static readonly Vector3 UIDefaultOffset = new Vector3(0f, 50f, 0f); + public enum IconType : int + { + Question = 0, + Exclamation = 1, + ExclamationAndDuel = 2, + Beach = 3, + ExclamationAndBeach = 4, + } + public enum Flag { EXCLAMATION, diff --git a/Assembly-CSharp/Global/CMD_DATA.cs b/Assembly-CSharp/Global/CMD_DATA.cs index 705866adb..e426288b1 100644 --- a/Assembly-CSharp/Global/CMD_DATA.cs +++ b/Assembly-CSharp/Global/CMD_DATA.cs @@ -53,6 +53,11 @@ public void SetAAData(AA_DATA value) } } + public Int32 GetCommandMPCost() + { + return info.CustomMPCost ?? aa?.MP ?? 0; + } + public class SELECT_INFO { public Byte cursor; @@ -65,17 +70,23 @@ public class SELECT_INFO public Byte short_summon; public Byte mon_reflec; - // Custom fields - public command_mode_index mode; + // Custom fields + public BattleCommandMenu cmdMenu; + public command_mode_index mode; public Boolean cmd_motion; // For multi-hit attacks (this counter allows to keep track of the hit number, for having different effects) public Int32 effect_counter; - public Boolean IsZeroMP { get; set; } - public Int32 CustomMPCost { get; set; } + public Int32? CustomMPCost { get; set; } public Boolean ReflectNull { get; set; } public Boolean HasCheckedReflect { get; set; } - public void Reset() + public Boolean IsZeroMP + { + get => CustomMPCost == 0; + set => CustomMPCost = value ? 0 : null; + } + + public void Reset() { cursor = 0; stat = 0; @@ -86,11 +97,12 @@ public void Reset() meteor_miss = 0; short_summon = 0; mon_reflec = 0; - mode = command_mode_index.CMD_MODE_INSPECTION; + cmdMenu = BattleCommandMenu.None; + mode = command_mode_index.CMD_MODE_INSPECTION; cmd_motion = true; effect_counter = 0; IsZeroMP = false; - CustomMPCost = -1; + CustomMPCost = null; ReflectNull = false; HasCheckedReflect = false; } diff --git a/Assembly-CSharp/Global/ChocographUI.cs b/Assembly-CSharp/Global/ChocographUI.cs index f48f0aef7..1b37b9adb 100644 --- a/Assembly-CSharp/Global/ChocographUI.cs +++ b/Assembly-CSharp/Global/ChocographUI.cs @@ -64,6 +64,7 @@ public void UpdateUserInterface() button.IconSprite.SetAnchor(target: button.Transform, relBottom: 0.5f, relTop: 0.5f, bottom: -36f * scaleFactor, top: 36f * scaleFactor, relLeft: 0.064f, relRight: 0.064f, right: 72f * scaleFactor); button.NameLabel.SetAnchor(target: button.Transform, relBottom: 0.081f, relTop: 0.919f, relLeft: 0.064f, left: 90f * scaleFactor, relRight: 1f); button.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + button.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); } } diff --git a/Assembly-CSharp/Global/Cloud/CloudUI.cs b/Assembly-CSharp/Global/Cloud/CloudUI.cs index 96767c070..ca097bc23 100644 --- a/Assembly-CSharp/Global/Cloud/CloudUI.cs +++ b/Assembly-CSharp/Global/Cloud/CloudUI.cs @@ -303,7 +303,7 @@ private void DisplayFileInfo(CloudUI.FileCloudInfoHUD fileHud, SharedDataPreview } fileHud.LeaderNameLabel.text = text; fileHud.LeaderLvLabel.text = num.ToString(); - fileHud.GilLabel.text = file.Gil.ToString() + "[YSUB=1.3][sub]G"; + fileHud.GilLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", file.Gil.ToString()); fileHud.LocationNameLabel.text = file.Location; Color color = FF9TextTool.White; Double num3 = (Double)(file.PlayDuration % 360000f); diff --git a/Assembly-CSharp/Global/Config/ConfigUI.cs b/Assembly-CSharp/Global/Config/ConfigUI.cs index 9ba9a529f..01e49a405 100644 --- a/Assembly-CSharp/Global/Config/ConfigUI.cs +++ b/Assembly-CSharp/Global/Config/ConfigUI.cs @@ -180,7 +180,13 @@ public enum ATBMode private OnScreenButton hitpointScreenButton; + [NonSerialized] + private GameObject controlTutorialGameObject; + [NonSerialized] + private GameObject combatTutorialGameObject; private GameObject toTitleGameObject; + [NonSerialized] + private GameObject quitGameGameObject; private GameObject masterSkillButtonGameObject; private GameObject lvMaxButtonGameObject; private GameObject gilMaxButtonGameObject; @@ -673,6 +679,20 @@ public override void Show(SceneVoidDelegate afterFinished = null) } ButtonGroupState.HelpEnabled = false; HelpDespLabelGameObject.SetActive(false); + WarningDialog.SetActive(false); + // Disable soft-reset and tutorials in battles (it leads to bugs because things are not cleaned correctly yet) + if (PersistenSingleton.Instance.UnityScene == UIManager.Scene.Battle) + { + controlTutorialGameObject.GetChild(0).GetComponent().color = FF9TextTool.Gray; + combatTutorialGameObject.GetChild(0).GetComponent().color = FF9TextTool.Gray; + toTitleGameObject.GetChild(0).GetComponent().color = FF9TextTool.Gray; + } + else + { + controlTutorialGameObject.GetChild(0).GetComponent().color = FF9TextTool.White; + combatTutorialGameObject.GetChild(0).GetComponent().color = FF9TextTool.White; + toTitleGameObject.GetChild(0).GetComponent().color = FF9TextTool.White; + } NGUIText.ForceShowButton = true; } @@ -724,6 +744,11 @@ public override Boolean OnKeyConfirm(GameObject go) } else if (config?.Configurator == Configurator.Title) { + if (PersistenSingleton.Instance.UnityScene == UIManager.Scene.Battle) + { + FF9Sfx.FF9SFX_Play(102); + return true; + } FF9Sfx.FF9SFX_Play(103); hitpointScreenButton.KeyCommand = Control.None; WarningDialogHitPoint.SetActive(true); @@ -738,6 +763,11 @@ public override Boolean OnKeyConfirm(GameObject go) } else if (config?.Configurator == Configurator.ControlTutorial) { + if (PersistenSingleton.Instance.UnityScene == UIManager.Scene.Battle) + { + FF9Sfx.FF9SFX_Play(102); + return true; + } FF9Sfx.FF9SFX_Play(103); hitpointScreenButton.KeyCommand = Control.Confirm; WarningDialogHitPoint.SetActive(true); @@ -754,6 +784,11 @@ public override Boolean OnKeyConfirm(GameObject go) } else if (config?.Configurator == Configurator.CombatTutorial) { + if (PersistenSingleton.Instance.UnityScene == UIManager.Scene.Battle) + { + FF9Sfx.FF9SFX_Play(102); + return true; + } FF9Sfx.FF9SFX_Play(103); NextSceneIsModal = true; fastSwitch = true; @@ -1656,8 +1691,19 @@ private void Awake() toTitleGameObject = configTopObj; UIEventListener.Get(configTopObj).onClick += onClick; } - else if (configField.Configurator == Configurator.ControlTutorial || configField.Configurator == Configurator.CombatTutorial || configField.Configurator == Configurator.QuitGame) + else if (configField.Configurator == Configurator.ControlTutorial) + { + controlTutorialGameObject = configTopObj; + UIEventListener.Get(configTopObj).onClick += onClick; + } + else if (configField.Configurator == Configurator.CombatTutorial) + { + combatTutorialGameObject = configTopObj; + UIEventListener.Get(configTopObj).onClick += onClick; + } + else if (configField.Configurator == Configurator.QuitGame) { + quitGameGameObject = configTopObj; UIEventListener.Get(configTopObj).onClick += onClick; } else @@ -1723,4 +1769,4 @@ private void Awake() ConfigFieldList[ConfigFieldList.Count - 1].ConfigParent.GetComponent().onDown = masterSkillButtonGameObject; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/EBin.cs b/Assembly-CSharp/Global/EBin.cs index 472c3e941..8de407b31 100644 --- a/Assembly-CSharp/Global/EBin.cs +++ b/Assembly-CSharp/Global/EBin.cs @@ -114,93 +114,58 @@ public Int32 ProcessCode(ObjList objList) while (_objectExists) { s1 = s0.obj; - int a1 = s1.state; - if (a1 == EventEngine.stateNew) + if (s1.state == EventEngine.stateNew) { - Int32 state = EventEngine.stateInit; - s1.state = (Byte)state; + s1.state = EventEngine.stateInit; next0(); continue; } - Int32 a0 = EventEngine.stateSuspend; _s2 = 0; - if (a1 == a0) + if (s1.state == EventEngine.stateSuspend) { next0(); continue; } _nextCodeIndex = s1.ip; - a0 = s1.wait; if (_nextCodeIndex == _eventEngine.nil) { next0(); continue; } - Int32 a2 = 1; - if (a0 != 0) + if (s1.wait != 0) { - a1 = 255; - if (a0 != 254) + if (s1.wait == 254) // Wait for a window to close { - if (a0 == a1) + if (s1.winnum == 255) { - next0(); + s1.wait = 0; } - else + else if (!_eTb.MesWinActive(s1.winnum)) { - a0 = s1.wait; - a0--; - s1.wait = (Byte)a0; - next0(); + s1.winnum = 255; + s1.wait = 0; } } else { - a0 = s1.winnum; - if (a0 == 255) - { - ad4(); - } - else - { - Boolean flag = _eTb.MesWinActive(a0); - a0 = 255; - if (flag) - { - next0(); - } - else - { - s1.winnum = (Byte)a0; - ad4(); - } - } + if (s1.wait != 255) // Wait indefinitely (255) or during N frames + s1.wait--; } + next0(); continue; } - a1 = s1.vofs; _eventEngine.gExec = s1; - a1 <<= 2; - a0 = s1.cid; _instance = s1.buffer; - _instanceVOfs = a1; + _instanceVOfs = s1.vofs << 2; objV0 = s1; _v0 = s1.ip; - if (a0 != a2) - { - result = ad3(a0); - } - else - { - a0 = s1.uid; - a0 -= 64; - objV0 = _eventEngine.FindObjByUID(a0); - result = ad3(a0); - } + if (s1.cid == 1) // Script executed with "STARTSEQ" (aka. "RunSharedScript") + objV0 = _eventEngine.FindObjByUID(s1.uid - EventEngine.cSeqOfs); + result = ad3(); objV0 = null; } return result; @@ -212,28 +177,13 @@ private void adFin() _objectExists = false; } - public Int32 ad3(Int32 arg0) + public Int32 ad3() { Int32 gMode = _eventEngine.gMode; _eventEngine.gCur = objV0; - Int32 result; - if (gMode != 2) - { - result = next(gMode); - } - else - { + if (gMode == 2) _eventEngine.ProcessCodeExt(s1); - result = next(gMode); - } - return result; - } - - private void ad4() - { - Int32 a0 = 0; - s1.wait = (Byte)a0; - next0(); + return next(gMode); } public Int32 next(Int32 gMode) @@ -1743,6 +1693,8 @@ private Int32 GetMemoriaCustomVariable(memoria_variable varCode) return QuadMistDatabase.MiniGame_GetCollectorLevel(); case memoria_variable.TREASURE_HUNTER_POINTS: return FF9StateSystem.EventState.GetTreasureHunterPoints(); + case memoria_variable.BATTLE_RUNAWAY: + return FF9StateSystem.Battle.FF9Battle.btl_scene.Info.Runaway ? 1 : 0; } return 0; } @@ -1760,6 +1712,9 @@ private void SetMemoriaCustomVariable(memoria_variable varCode, Int32 val) case memoria_variable.TETRA_MASTER_DRAW: FF9StateSystem.MiniGame.SavedData.sDraw = (Int16)val; break; + case memoria_variable.BATTLE_RUNAWAY: + FF9StateSystem.Battle.FF9Battle.btl_scene.Info.Runaway = val != 0; + break; } } @@ -2386,6 +2341,7 @@ public enum event_code_binary AANIM_EX, VECTOR_CLEAR, DICTIONARY_CLEAR, + BGLMOVE_TIMED, } public enum flexible_varfunc : ushort @@ -2425,6 +2381,7 @@ public enum memoria_variable : ushort TETRA_MASTER_POINTS, TETRA_MASTER_RANK, TREASURE_HUNTER_POINTS, + BATTLE_RUNAWAY, } public enum op_binary @@ -2581,4 +2538,4 @@ public enum VariableType VectorSize = 2, Dictionary = 3, } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/EIcon.cs b/Assembly-CSharp/Global/EIcon.cs index 1d0468928..96f5aa6d4 100644 --- a/Assembly-CSharp/Global/EIcon.cs +++ b/Assembly-CSharp/Global/EIcon.cs @@ -73,7 +73,7 @@ public static Boolean IsDialogBubble } } - public static Int32 SFIconType + public static BubbleUI.IconType SFIconType { get { @@ -92,7 +92,7 @@ public static void InitFIcon() EIcon.HideDelay = 0f; } - public static void PollFIcon(Int32 type) + public static void PollFIcon(BubbleUI.IconType type) { EIcon.lastPollType = EIcon.PollType.EVENT_SCRIPT; EIcon.sFIconPolled = true; @@ -114,12 +114,12 @@ public static Boolean PollCollisionIcon(Obj targetObject) Boolean flag2 = instance.GetIP((Int32)targetObject.sid, 8, targetObject.ebData) != instance.nil && 1 < targetObject.level; if (flag && flag2) { - EIcon.PollFIcon(2); + EIcon.PollFIcon(BubbleUI.IconType.ExclamationAndDuel); result = true; } else if (flag && instance.IsActuallyTalkable(targetObject)) { - EIcon.PollFIcon(1); + EIcon.PollFIcon(BubbleUI.IconType.Exclamation); result = true; } } @@ -129,9 +129,9 @@ public static Boolean PollCollisionIcon(Obj targetObject) if (flag) { if (EMinigame.CheckBeachMinigame() && !EventCollision.IsWorldTrigger()) - EIcon.PollFIcon(4); + EIcon.PollFIcon(BubbleUI.IconType.ExclamationAndBeach); else - EIcon.PollFIcon(1); + EIcon.PollFIcon(BubbleUI.IconType.Exclamation); result = true; } } @@ -200,20 +200,16 @@ public static void ProcessFIcon() EIcon.HideBubble(); } else if (!EIcon.hereIconShow && instance2.IsActive) - { - Boolean flag = false; - if (EIcon.sFIconType != EIcon.sFIconLastType) - { - flag = true; - } - if (flag) - { - EIcon.HideBubble(); - EIcon.sFIconPolled = false; - EIcon.sFIconLastPolled = EIcon.sFIconPolled; - } - } - EIcon.sFIconLastType = EIcon.sFIconType; + { + Boolean flag = sFIconType != sFIconLastType; + if (flag) + { + EIcon.HideBubble(); + EIcon.sFIconPolled = false; + EIcon.sFIconLastPolled = EIcon.sFIconPolled; + } + } + EIcon.sFIconLastType = EIcon.sFIconType; } private static void ShowBubble() @@ -295,7 +291,7 @@ public static void ShowDialogBubble(Boolean useAlternativeKey = false) { EIcon.dialogBubble = true; EIcon.dialogAlternativeKey = useAlternativeKey; - EIcon.sFIconType = 1; + EIcon.sFIconType = BubbleUI.IconType.Exclamation; EIcon.ShowWorldBubble(); } @@ -329,37 +325,20 @@ public static Vector3 GetWorldActorOffset(out Vector3 actorOffset, ref Vector3 u return actorOffset; } - public static BubbleUI.Flag[] GetBubbleFlagData(Int32 pollCode) - { - switch (pollCode) - { - case 0: - return new BubbleUI.Flag[] - { - BubbleUI.Flag.QUESTION - }; - case 2: - return new BubbleUI.Flag[] - { - BubbleUI.Flag.EXCLAMATION, - BubbleUI.Flag.DUEL - }; - case 3: - return new BubbleUI.Flag[] - { - BubbleUI.Flag.BEACH - }; - case 4: - return new BubbleUI.Flag[] - { - BubbleUI.Flag.EXCLAMATION, - BubbleUI.Flag.BEACH - }; - } - return new BubbleUI.Flag[1]; - } + public static BubbleUI.Flag[] GetBubbleFlagData(BubbleUI.IconType pollCode) + { + return pollCode switch + { + BubbleUI.IconType.Question => [BubbleUI.Flag.QUESTION], + BubbleUI.IconType.Exclamation => [BubbleUI.Flag.EXCLAMATION], + BubbleUI.IconType.ExclamationAndDuel => [BubbleUI.Flag.EXCLAMATION, BubbleUI.Flag.DUEL], + BubbleUI.IconType.Beach => [BubbleUI.Flag.BEACH], + BubbleUI.IconType.ExclamationAndBeach => [BubbleUI.Flag.EXCLAMATION, BubbleUI.Flag.BEACH], + _ => [BubbleUI.Flag.EXCLAMATION] + }; + } - public static void SetHereIcon(Int32 f) + public static void SetHereIcon(Int32 f) { EventEngine instance = PersistenSingleton.Instance; if (f <= 0 || EventHUD.CurrentHUD == MinigameHUD.ChocoHot) @@ -504,9 +483,9 @@ public static void SetAIcon(Int32 mode) private static Boolean sFIconLastPolled; - private static Int32 sFIconType; + private static BubbleUI.IconType sFIconType; - private static Int32 sFIconLastType; + private static BubbleUI.IconType sFIconLastType; private static EIcon.PollType lastPollType; diff --git a/Assembly-CSharp/Global/ENEMY/ENEMY.cs b/Assembly-CSharp/Global/ENEMY/ENEMY.cs index e0bda032f..ef74405ae 100644 --- a/Assembly-CSharp/Global/ENEMY/ENEMY.cs +++ b/Assembly-CSharp/Global/ENEMY/ENEMY.cs @@ -37,7 +37,13 @@ public class ENEMY_INFO public Byte die_fade_rate; public Byte die_atk; public Byte die_dmg; - public Byte multiple; + public Byte die_unused3; + public Byte die_unused4; + public Byte die_unused5; + public Byte die_unused6; + public Byte die_unused7; + public Byte die_unused8; + public Byte multiple; public Byte slave; public Int32 reserve; public UInt16 flags; diff --git a/Assembly-CSharp/Global/EquipUI.cs b/Assembly-CSharp/Global/EquipUI.cs index 125b6cfc7..0d23a8f06 100644 --- a/Assembly-CSharp/Global/EquipUI.cs +++ b/Assembly-CSharp/Global/EquipUI.cs @@ -81,12 +81,18 @@ public void UpdateUserInterface() Int32 linePerPage = Configuration.Interface.MenuEquipRowCount; Int32 lineHeight = (Int32)Math.Round(panelOriginalHeight / linePerPage); Single scaleFactor = lineHeight / buttonOriginalHeight; + _equipSelectPanel.SubPanel.ChangeDims(1, linePerPage, panelOriginalWidth, lineHeight); _equipSelectPanel.SubPanel.ButtonPrefab.IconSprite.SetAnchor(target: _equipSelectPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.144f, relTop: 0.856f, relLeft: 0.044f, relRight: 0.13f); + _equipSelectPanel.SubPanel.ButtonPrefab.IconSprite.width = _equipSelectPanel.SubPanel.ButtonPrefab.IconSprite.height; + _equipSelectPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _equipSelectPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.144f, relTop: 0.856f, relLeft: 0.154f, relRight: 0.795f); - _equipSelectPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _equipSelectPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.144f, relTop: 0.856f, relLeft: 0.8f, relRight: 0.92f); _equipSelectPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _equipSelectPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _equipSelectPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _equipSelectPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.144f, relTop: 0.856f, relLeft: 0.8f, relRight: 0.92f); _equipSelectPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _equipSelectPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _equipSelectPanel.SubPanel.RecycleListPopulator.RefreshTableView(); } @@ -376,8 +382,8 @@ public override Boolean OnKeySpecial(GameObject go) public override Boolean OnKeyLeftBumper(GameObject go) { if (!base.OnKeyLeftBumper(go) - || (ButtonGroupState.ActiveGroup != EquipUI.SubMenuGroupButton && ButtonGroupState.ActiveGroup != EquipUI.EquipmentGroupButton) - || !this.CharacterArrowPanel.activeSelf) + || (ButtonGroupState.ActiveGroup != EquipUI.SubMenuGroupButton && ButtonGroupState.ActiveGroup != EquipUI.EquipmentGroupButton) + || !this.CharacterArrowPanel.activeSelf) return true; FF9Sfx.FF9SFX_Play(1047); @@ -403,8 +409,8 @@ public override Boolean OnKeyLeftBumper(GameObject go) public override Boolean OnKeyRightBumper(GameObject go) { if (!base.OnKeyRightBumper(go) - || (ButtonGroupState.ActiveGroup != SubMenuGroupButton && ButtonGroupState.ActiveGroup != EquipmentGroupButton) - || !CharacterArrowPanel.activeSelf) + || (ButtonGroupState.ActiveGroup != SubMenuGroupButton && ButtonGroupState.ActiveGroup != EquipmentGroupButton) + || !CharacterArrowPanel.activeSelf) return true; FF9Sfx.FF9SFX_Play(1047); @@ -1505,4 +1511,4 @@ public class EquipInventoryListData : ListDataTypeBase { public FF9ITEM ItemData; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/Event/Engine/EventEngine.DoEventCode.cs b/Assembly-CSharp/Global/Event/Engine/EventEngine.DoEventCode.cs index b82a58930..6b2046e88 100644 --- a/Assembly-CSharp/Global/Event/Engine/EventEngine.DoEventCode.cs +++ b/Assembly-CSharp/Global/Event/Engine/EventEngine.DoEventCode.cs @@ -1362,11 +1362,11 @@ public Int32 DoEventCode() } case EBin.event_code_binary.FICON: { - Int32 type = this.getv1(); - if ((Int32)FF9StateSystem.Common.FF9.fldMapNo == 2955) + BubbleUI.IconType type = (BubbleUI.IconType)this.getv1(); + if (FF9StateSystem.Common.FF9.fldMapNo == 2955) { - if ((Int32)this.gCur.uid == 24) - EIcon.PollFIcon(2); + if (this.gCur.uid == 24) + EIcon.PollFIcon(BubbleUI.IconType.ExclamationAndDuel); else EIcon.PollFIcon(type); } @@ -2876,6 +2876,11 @@ public Int32 DoEventCode() dict.Clear(); return 0; } + case EBin.event_code_binary.BGLMOVE_TIMED: + { + this.fieldmap.EBG_overlayMoveTimed(this.getv3(), this.getv3(), this.getv3(), this.getv3(), this.getv3()); + return 0; + } default: { switch (this.gMode) @@ -3099,4 +3104,4 @@ internal void SetActorPosition(PosObj po, Single x, Single y, Single z) ((Actor)po).wmActor.SetPosition(po.pos[0], po.pos[1], po.pos[2]); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/Event/Engine/EventEngine.MoveToward.cs b/Assembly-CSharp/Global/Event/Engine/EventEngine.MoveToward.cs index a6d71b19f..8497039e6 100644 --- a/Assembly-CSharp/Global/Event/Engine/EventEngine.MoveToward.cs +++ b/Assembly-CSharp/Global/Event/Engine/EventEngine.MoveToward.cs @@ -137,7 +137,7 @@ private Boolean MoveToward_mixed_ex(Actor actor, Int32 speed, Single x, Single y } EventEngine.GetMoveVector(out Vector3 moveVec, movingPitch, movingAngle, speed); - if (Configuration.Control.PSXMovementMethod && (flags & 2) == 0 && actorController != null) + if (Configuration.Control.PSXMovementMethod && (flags & 2) == 0 && actorController != null && (FF9StateSystem.Common.FF9.fldMapNo != 758)) moveVec *= actorController.fieldMap.walkMesh.GetTriangleSlopeFactor(actorController.activeTri); if (actorController != null && actorController.name == actorController.fieldMap.debugObjName) diff --git a/Assembly-CSharp/Global/Event/Engine/EventEngine.ProcessAnime.cs b/Assembly-CSharp/Global/Event/Engine/EventEngine.ProcessAnime.cs index c045a5cc7..86402709c 100644 --- a/Assembly-CSharp/Global/Event/Engine/EventEngine.ProcessAnime.cs +++ b/Assembly-CSharp/Global/Event/Engine/EventEngine.ProcessAnime.cs @@ -104,11 +104,7 @@ private void ProcessAnime(Actor actor) } else { - int num3 = this.NextFrame(actor); - if (actor.sid == 17) - { - } - if (num3 >= (int)actor.frameN) + if (NextFrame(actor) >= actor.frameN) { actor.animFrame = 0; if (actor.anim == actor.idle) @@ -225,4 +221,4 @@ private void FinishJump(Actor actor) actor.inFrame = (Byte)0; actor.outFrame = Byte.MaxValue; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/Event/Engine/EventEngineUtils.cs b/Assembly-CSharp/Global/Event/Engine/EventEngineUtils.cs index 6d41ae233..5cd4be039 100644 --- a/Assembly-CSharp/Global/Event/Engine/EventEngineUtils.cs +++ b/Assembly-CSharp/Global/Event/Engine/EventEngineUtils.cs @@ -1839,15 +1839,7 @@ public static Int32 GetCharAnimFrame(GameObject go, Int32 AnmNo) if (go.GetComponent().GetClip(name) == null) return -1; Single f = go.GetComponent()[name].clip.length * go.GetComponent()[name].clip.frameRate; - Int32 int1 = Mathf.CeilToInt(f); - Int32 int2 = Mathf.FloorToInt(f); - Int32 int3 = Mathf.RoundToInt(f); - Int32 num = int1; - if (int3 == int1) - num = int1; - else if (int3 == int2) - num = int2; - return num + 1; + return Mathf.RoundToInt(f) + 1; } public static Byte[] loadEventData(String ebFileName, String ebSubFolder) @@ -1930,7 +1922,7 @@ public class BinaryScript public List entries; public BinaryScript(Byte[] raw) - { + { if (raw.Length < 4) return; if (raw[0] != 'E' || raw[1] != 'V') @@ -1980,7 +1972,7 @@ public HashSet GetVariableUsage(Boolean withGeneral = true, Boolean with } public static Boolean IsVariableInUsage(HashSet pool, UInt32 specific) - { + { if (pool.Contains(specific)) return true; if ((specific & NON_BOOLEAN_FLAG) != 0) @@ -1992,10 +1984,10 @@ public static Boolean IsVariableInUsage(HashSet pool, UInt32 specific) else if (pool.Contains((specific & 0xFFFFFFF8u) | NON_BOOLEAN_FLAG)) return true; return false; - } + } public static UInt32 GetVariableFromIndex(EBin.VariableSource source, UInt16 index, Boolean isBoolType = false) - { + { if (isBoolType) return index | ((UInt32)source << 26); return NON_BOOLEAN_FLAG | (UInt32)(index << 3) | ((UInt32)source << 26); @@ -2009,16 +2001,16 @@ public class Entry public Byte flags; public List functions; public Entry(Byte[] raw, ref UInt32 pos, Byte id, Byte lvc, Byte fl, UInt32 maxPosEntry) - { + { sid = id; localVarCount = lvc; flags = fl; functions = new List(); if (maxPosEntry <= pos) - { + { type = 0xFF; return; - } + } type = raw[pos++]; Int32 funcCount = raw[pos++]; UInt16[] funcTag = new UInt16[funcCount]; @@ -2054,7 +2046,7 @@ public UInt32 GetBinarySize() } public class Function - { + { public Int32 tagNumber; public List codes; @@ -2067,28 +2059,28 @@ public Function(Byte[] raw, ref UInt32 pos, Int32 tag, UInt32 maxPosFunc) } public HashSet GetVariableUsage(Boolean withGeneral = true, Boolean withGlobal = true, Boolean withLocal = true) - { + { HashSet result = new HashSet(); HashSet piece; Int32 i; foreach (Code c in codes) for (i = 0; i < c.arguments.Count; i++) - { + { piece = c.arguments[i].GetVariableUsage(withGeneral, withGlobal, withLocal); if (piece != null) result.UnionWith(piece); - } + } return result; } public class Code - { + { public UInt16 opcode; public Byte argFlag; public List arguments; public Code(Byte[] raw, ref UInt32 pos) - { + { arguments = new List(); opcode = raw[pos++]; if (opcode == 0xFF) @@ -2115,7 +2107,7 @@ public Code(Byte[] raw, ref UInt32 pos) } public UInt32 GetBinarySize() - { + { UInt32 size = opcode >= 0x100 ? 2u : 1u; if (opcode >= 0x10 && opArgCount[opcode] != 0) size++; @@ -2148,7 +2140,7 @@ public UInt32 GetBinarySize() }; Byte GetArgTypeSize(UInt16 op, Int32 i) - { + { if (op == 0x29) return 4; if (op == 0x06 || op == 0x0B || op == 0x0D) @@ -2178,14 +2170,14 @@ Byte GetArgTypeSize(UInt16 op, Int32 i) }; public abstract class Argument - { + { public abstract Boolean IsConstantValue(); public abstract HashSet GetVariableUsage(Boolean withGeneral = true, Boolean withGlobal = true, Boolean withLocal = true); public abstract UInt32 GetBinarySize(); } public class ArgumentConstant : Argument - { + { public Int64 value; public Byte size; public override Boolean IsConstantValue() => true; @@ -2193,7 +2185,7 @@ public class ArgumentConstant : Argument public override UInt32 GetBinarySize() => size; public ArgumentConstant(Byte[] raw, ref UInt32 pos, Byte sz) - { + { size = sz; if (size == 1) value = raw[pos++]; @@ -2211,7 +2203,7 @@ public class ArgumentExpression : Argument public List operations; public ArgumentExpression(Byte[] raw, ref UInt32 pos) - { + { operations = new List(); do operations.Add(new ExpressionOperation(raw, ref pos)); @@ -2220,10 +2212,10 @@ public ArgumentExpression(Byte[] raw, ref UInt32 pos) public override Boolean IsConstantValue() => false; public override HashSet GetVariableUsage(Boolean withGeneral = true, Boolean withGlobal = true, Boolean withLocal = true) - { + { HashSet result = new HashSet(); foreach (ExpressionOperation op in operations) - { + { if ((op.IsGeneralVariable() && withGeneral) || (op.IsGlobalVariable() && withGlobal) || (op.IsLocalVariable() && withLocal)) { UInt32 variable = op.IsGeneralVariable() ? (UInt32)EBin.VariableSource.Global << 26 : (op.IsGlobalVariable() ? (UInt32)EBin.VariableSource.Map << 26 : (UInt32)EBin.VariableSource.Instance << 26); @@ -2249,11 +2241,11 @@ public override HashSet GetVariableUsage(Boolean withGeneral = true, Boo result.Add(variable); } } - } + } return result; } public override UInt32 GetBinarySize() - { + { UInt32 result = 0; foreach (ExpressionOperation op in operations) result += 1u + (op.arguments == null ? 0u : (UInt32)op.arguments.Length); @@ -2262,12 +2254,12 @@ public override UInt32 GetBinarySize() } public class ExpressionOperation - { + { public Byte operation; public Byte[] arguments; public ExpressionOperation(Byte[] raw, ref UInt32 pos) - { + { operation = raw[pos++]; if (!IsConstantValue() && !IsVariable()) { @@ -2304,10 +2296,10 @@ public ExpressionOperation(Byte[] raw, ref UInt32 pos) public Boolean IsConstantValue() => operation == 0x7D || operation == 0x7E; } } - } - } + } + } private const UInt32 NON_BOOLEAN_FLAG = 0x40000u; - } - #endregion -} \ No newline at end of file + } + #endregion +} diff --git a/Assembly-CSharp/Global/Event/EventCollision.cs b/Assembly-CSharp/Global/Event/EventCollision.cs index 2820a4561..dede999a9 100644 --- a/Assembly-CSharp/Global/Event/EventCollision.cs +++ b/Assembly-CSharp/Global/Event/EventCollision.cs @@ -302,7 +302,7 @@ public static void CollisionRequest(PosObj po) { if (instance.GetIP((Int32)obj.sid, 8, obj.ebData) != instance.nil) { - EIcon.PollFIcon(2); + EIcon.PollFIcon(BubbleUI.IconType.ExclamationAndDuel); } else { @@ -311,7 +311,7 @@ public static void CollisionRequest(PosObj po) { if (EventCollision.CheckQuadTalk(po, obj)) { - EIcon.PollFIcon(1); + EIcon.PollFIcon(BubbleUI.IconType.Exclamation); } } } @@ -326,11 +326,11 @@ public static void CollisionRequest(PosObj po) { if (EventCollision.IsChocoboWalkingOrFlyingInForestArea()) { - EIcon.PollFIcon(1); + EIcon.PollFIcon(BubbleUI.IconType.Exclamation); } else if (!flag && EMinigame.CheckBeachMinigame()) { - EIcon.PollFIcon(3); + EIcon.PollFIcon(BubbleUI.IconType.Beach); } } } @@ -577,7 +577,7 @@ private static Boolean IsNPCTalkable(Obj npc) } } } - else if (npc.uid == 4 && Singleton.Instance.IsActive && EIcon.SFIconType == 1) + else if (npc.uid == 4 && Singleton.Instance.IsActive && EIcon.SFIconType == BubbleUI.IconType.Exclamation) { flag = false; } @@ -607,7 +607,7 @@ private static Boolean IsNPCTalkable(Obj npc) } } } - else if (npc.uid == 10 && Singleton.Instance.IsActive && EIcon.SFIconType == 1) + else if (npc.uid == 10 && Singleton.Instance.IsActive && EIcon.SFIconType == BubbleUI.IconType.Exclamation) { flag = false; } diff --git a/Assembly-CSharp/Global/Field/Map/Actor/FieldMapActorController.cs b/Assembly-CSharp/Global/Field/Map/Actor/FieldMapActorController.cs index e3208b526..b04adf33d 100644 --- a/Assembly-CSharp/Global/Field/Map/Actor/FieldMapActorController.cs +++ b/Assembly-CSharp/Global/Field/Map/Actor/FieldMapActorController.cs @@ -405,7 +405,6 @@ public void UpdateMovement(Boolean copyLastPos = true) private void PlayAnimationViaEventScript() { String curAnim = FF9DBAll.AnimationDB.GetValue(this.originalActor.anim); - this._smoothUpdatePlayingAnim = false; if (!this.animation.IsPlaying(curAnim)) { AnimationClip clip = this.animation.GetClip(curAnim); @@ -426,9 +425,6 @@ private void PlayAnimationViaEventScript() { Single time = (Single)this.originalActor.animFrame / (Single)this.originalActor.frameN * this.animation[curAnim].length; this.animation[curAnim].speed = 0f; - this._smoothUpdatePlayingAnim = true; - this._smoothUpdateAnimTimePrevious = this.animation[curAnim].time; - this._smoothUpdateAnimTimeActual = time; this.animation[curAnim].time = time; this.animation.Sample(); } diff --git a/Assembly-CSharp/Global/Field/Map/FieldMap.cs b/Assembly-CSharp/Global/Field/Map/FieldMap.cs index bb91c007f..6b504b60a 100644 --- a/Assembly-CSharp/Global/Field/Map/FieldMap.cs +++ b/Assembly-CSharp/Global/Field/Map/FieldMap.cs @@ -322,8 +322,16 @@ public override void HonoLateUpdate() this.CenterCameraOnPlayer(); this.SceneServiceScroll(this.scene); this.UpdateOverlayAll(); + + if (PersistenSingleton.Instance.eBin.getVarManually(EBin.SC_COUNTER_SVR) != currentCounterNumber) + { + currentCounterNumber = PersistenSingleton.Instance.eBin.getVarManually(EBin.SC_COUNTER_SVR); + Log.Message("Map: " + FF9StateSystem.Common.FF9.fldMapNo + " | Scenario counter: " + PersistenSingleton.Instance.eBin.getVarManually(EBin.SC_COUNTER_SVR)); + } } + public int currentCounterNumber = 0; + public override void HonoOnGUI() { if (this.walkMesh != null) @@ -426,7 +434,7 @@ public void SetCurrentCameraIndex(Int32 newCamIdx) this.flags |= FieldMapFlags.Unknown128; this.walkMesh.ProcessBGI(); this.walkMesh.UpdateActiveCameraWalkmesh(); - SmoothCamDelay = 6; + SmoothCamDelay = 4; SmoothCamActive = (!SmoothCamExcludeMaps.Contains(FF9StateSystem.Common.FF9.fldMapNo)); String camIdxIfCam = this.scene.cameraList.Count > 1 ? "-" + this.camIdx : ""; PlayerWindow.Instance.SetTitle($"Map: {FF9StateSystem.Common.FF9.fldMapNo}{camIdxIfCam} ({FF9StateSystem.Common.FF9.mapNameStr}) | Index/Counter: {PersistenSingleton.Instance.eBin.getVarManually(EBin.MAP_INDEX_SVR)}/{PersistenSingleton.Instance.eBin.getVarManually(EBin.SC_COUNTER_SVR)} | Loc: {FF9StateSystem.Common.FF9.fldLocNo}"); @@ -476,25 +484,6 @@ public void LoadFieldMap(String name) FPSManager.DelayMainLoop(Time.realtimeSinceStartup - loadStartTime); if (dbug) Log.Message("_ LoadFieldMap | ShaderMulX: " + ShaderMulX + " | bgCamera.depthOffset: " + bgCamera.depthOffset + " | bgCamera.vrpMaxX " + bgCamera.vrpMaxX + " | bgCamera.depthOffset: " + bgCamera.depthOffset + " | this.scene.maxX: " + this.scene.maxX); } - public static readonly HashSet SmoothCamExcludeMaps = new HashSet() - { - 575, // Hunting festival - 767, // Burmecia, the queen slides from her layer - 1754, // Fast scroll on Iifa platform buggy - 3000, // ending - 3001, - 3002, - 3003, - 3004, - 3005, - 3006, - 3007, - 3008, - 3009, - 3010, - 3011, - 3012, - }; public void ActivateCamera() { @@ -712,7 +701,17 @@ public void CenterCameraOnPlayer() Int32 threshmargin = Math.Min((Int32)bgCamera.w - PsxFieldWidth, 0); // Offset value for fields that are between 320 & 398 //if (dbug) Log.Message("PsxFieldWidth" + PsxFieldWidth); - if (mapWidth > PsxFieldWidth && map != 507) // Cargo Ship/Deck + if (map == 1205 || map == 1652 || map == 2552 || map == 154 || map == 1215 || map == 1807) // A. Castle/Chapel, Iifa Tree/Roots, Earth Shrine/Interior, Alex grand hall + { + if (map == 1652 && this.camIdx == 0) // Iifa Tree/Roots + threshmargin += 16; + + Int32 threshright = bgCamera.w - PsxFieldWidth - threshmargin; + + CamPositionX = (float)Math.Max(threshmargin, CamPositionX); + CamPositionX = (float)Math.Min(threshright, CamPositionX); + } + else if (mapWidth > PsxFieldWidth && map != 507) // Cargo Ship/Deck { foreach (KeyValuePair entry in NarrowMapList.mapCameraMargin) if (map == entry.Key) @@ -730,16 +729,6 @@ public void CenterCameraOnPlayer() CamPositionX = (float)Math.Max(threshmargin, CamPositionX); CamPositionX = (float)Math.Min(threshright, CamPositionX); } - else if (map == 1205 || map == 1652 || map == 2552 || map == 154 || map == 1215 || map == 1807) // A. Castle/Chapel, Iifa Tree/Roots, Earth Shrine/Interior, Alex grand hall - { - if (map == 1652 && this.camIdx == 0) // Iifa Tree/Roots - threshmargin += 16; - - Int32 threshright = bgCamera.w - PsxFieldWidth - threshmargin; - - CamPositionX = (float)Math.Max(threshmargin, CamPositionX); - CamPositionX = (float)Math.Min(threshright, CamPositionX); - } else if (IsNarrowMap()) { if (mapWidth <= PsxFieldWidth && mapWidth > 320) @@ -747,7 +736,6 @@ public void CenterCameraOnPlayer() CamPositionX = (float)((bgCamera.w - mapWidth) / 2); } } - switch (map) // offsets for scrolling maps stretched to WS { case 456: // Dali Mountain/Summit @@ -758,6 +746,9 @@ public void CenterCameraOnPlayer() CamPositionX = Configuration.Graphics.ScreenIs16to10() ? 140 : 175; break; case 2716: // fix for Kuja descending camera too high CamPositionY = (float)Math.Min(0, CamPositionY); break; + case 2903: // Dali Mountain/Summit + if (ActualPsxScreenWidth > 510) + CamPositionX = 0; break; default: break; } @@ -910,6 +901,7 @@ public Int32 EBG_sceneGetVRP(ref Int16 x, ref Int16 y) return 1; } + /// EBG - set if overlay is active (inactive isn't visible) public Int32 EBG_overlaySetActive(Int32 overlayNdx, Int32 activeFlag) { BGOVERLAY_DEF bgOverlay = this.scene.overlayList[overlayNdx]; @@ -948,6 +940,7 @@ public Int32 EBG_overlaySetViewport(Int32 overlayNdx, Int32 viewportNdx) return 1; } + /// EBG - set if overlay is type LOOP public Int32 EBG_overlaySetLoop(Int32 overlayNdx, UInt32 flag, Int32 dx, Int32 dy) { BGOVERLAY_DEF bgOverlay = this.scene.overlayList[overlayNdx]; @@ -986,6 +979,7 @@ public Int32 EBG_overlaySetLoopType(Int32 overlayNdx, UInt32 isScreenAnchored) return 1; } + /// EBG - set overlay is scrolling - potentially in diagonal public Int32 EBG_overlaySetScrollWithOffset(Int32 overlayNdx, UInt32 flag, Int32 delta, Int32 offset, UInt32 isXOffset) { BGOVERLAY_DEF bgOverlay = this.scene.overlayList[overlayNdx]; @@ -1038,6 +1032,7 @@ public Int32 EBG_charAttachOverlay(Int32 overlayNdx, Int16 attachX, Int16 attach return 1; } + /// EBG - anim - define if animation is running in a loop | TODO get the difference with EBG_animSetActive public Int32 EBG_animAnimate(Int32 animNdx, Int32 frameNdx) { if (dbug) Log.Message("EBG_animAnimate | anim:" + animNdx + " frame:" + frameNdx); @@ -1048,6 +1043,7 @@ public Int32 EBG_animAnimate(Int32 animNdx, Int32 frameNdx) return 1; } + /// EBG - anim - show specific frame public Int32 EBG_animShowFrame(Int32 animNdx, Int32 frameNdx) { if (dbug) Log.Message("EBG_animShowFrame | anim:" + animNdx + " frame:" + frameNdx); @@ -1060,6 +1056,7 @@ public Int32 EBG_animShowFrame(Int32 animNdx, Int32 frameNdx) return 1; } + /// EBG - anim - define if animation is running in a loop public Int32 EBG_animSetActive(Int32 animNdx, Int32 flag) { BGANIM_DEF bgAnim = this.scene.animList[animNdx]; @@ -1076,6 +1073,7 @@ public Int32 EBG_animSetActive(Int32 animNdx, Int32 flag) return 1; } + /// EBG - anim - define animation framerate public Int32 EBG_animSetFrameRate(Int32 animNdx, Int32 frameRate) { if (dbug) Log.Message("EBG_animSetFrameRate | anim:" + animNdx + " frameRate:" + frameRate); @@ -1166,12 +1164,13 @@ public Int32 EBG_overlaySetShadeColor(Int32 overlayNdx, Byte r, Byte g, Byte b) return 1; } + /// EBG - set position of overlay public Int32 EBG_overlayMove(Int32 overlayNdx, Int16 dx, Int16 dy, Int16 dz) { BGOVERLAY_DEF bgOverlay = this.scene.overlayList[overlayNdx]; FieldMapInfo.fieldmapExtraOffset.UpdateOverlayOffset(this.mapName, overlayNdx, ref dz); - float destX = (float)Mathf.Clamp(bgOverlay.orgX + dx, bgOverlay.minX, bgOverlay.maxX); - float destY = (float)Mathf.Clamp(bgOverlay.orgY + dy, bgOverlay.minY, bgOverlay.maxY); + Single destX = Mathf.Clamp(bgOverlay.orgX + dx, bgOverlay.minX, bgOverlay.maxX); + Single destY = Mathf.Clamp(bgOverlay.orgY + dy, bgOverlay.minY, bgOverlay.maxY); // TODO Check Native: #147 UInt16 destZ; @@ -1191,6 +1190,17 @@ public Int32 EBG_overlayMove(Int32 overlayNdx, Int16 dx, Int16 dy, Int16 dz) return 1; } + /// New EBG - set position of overlay, with movement for a time ( + public void EBG_overlayMoveTimed(Int32 overlayNdx, Int32 dx, Int32 dy, Int32 dz, Int32 t) + { + BGOVERLAY_DEF bgOverlay = this.scene.overlayList[overlayNdx]; + bgOverlay.dxTimed = (Single)dx / t; + bgOverlay.dyTimed = (Single)dy / t; + bgOverlay.dzTimed = (Int16)(dz / t); + bgOverlay.timedMoveDuration = t; + if (dbug) Log.Message($"EBG_overlayMoveTimed {overlayNdx} | dx:{dx} dy:{dy} dz:{dz} t:{t}"); + } + public Int32 EBG_overlaySetOrigin(Int32 overlayNdx, Int32 orgX, Int32 orgY) { BGOVERLAY_DEF bgOverlay = this.scene.overlayList[overlayNdx]; @@ -1269,6 +1279,7 @@ private void UpdateOverlay(Int32 ovrNdx, BGOVERLAY_DEF bgOverlay, Vector2 realVr anchorX = (float)(HalfFieldWidth - realVrp.x + this.scrollWindowPos[(int)bgOverlay.viewportNdx][0]); anchorY = (float)(HalfFieldHeight - realVrp.y + this.scrollWindowPos[(int)bgOverlay.viewportNdx][1]); } + if (bgOverlay.scrollX != 0) { if (bgOverlay.scrollX < 0) @@ -1419,15 +1430,15 @@ private void UpdateOverlay(Int32 ovrNdx, BGOVERLAY_DEF bgOverlay, Vector2 realVr else { short xOffset = 0; - short xOffsetAdjusted = (short)(screenX + (short)bgSprite.offX); - if (xOffsetAdjusted + 16 >= (short)bgOverlay.w) + float xOffsetAdjusted = (float)(screenX + (float)bgSprite.offX); + if (xOffsetAdjusted + 16f >= (short)bgOverlay.w) { - xOffsetAdjusted = (short)(xOffsetAdjusted - (short)bgOverlay.w); + xOffsetAdjusted = (float)(xOffsetAdjusted - (float)bgOverlay.w); xOffset = (short)(-bgOverlay.scrollY); } - else if (xOffsetAdjusted <= -16) + else if (xOffsetAdjusted <= -16f) { - xOffsetAdjusted = (short)(xOffsetAdjusted + (short)bgOverlay.w); + xOffsetAdjusted = (float)(xOffsetAdjusted + (float)bgOverlay.w); xOffset = (short)(bgOverlay.scrollY); } localPosition.x = (float)(xOffsetAdjusted + anchorX); @@ -1459,21 +1470,6 @@ private void UpdateOverlay(Int32 ovrNdx, BGOVERLAY_DEF bgOverlay, Vector2 realVr } } - public static readonly Int32[][] FixDepthOfLayer = - { - // [mapNo,camIdx,ovrNdx,Z], - [403,0,23,560], // Dali underground wall over box - [403,0,27,1523], // Dali underground barrel - [951,0,2,1214], // Gargan Roo's railing - [1000,0,12,0], // Clayra's Trunk text - [1652,1,5,911], // Iifa platform - [1656,0,3,998], // Iifa statue glow (was not active on PSX) - [2922,0,8,4329], // Crystal world (was not active on PSX) - [2922,0,10,3179], // Crystal world (was not active on PSX) - [2922,0,11,3179], // Crystal world (was not active on PSX) - [2922,0,12,6080], // Crystal world (was not active on PSX) - }; - public void EBG_scene2DScroll(Int16 destX, Int16 destY, UInt16 frameCount, UInt32 scrollType) { if (!IsActive) @@ -1645,6 +1641,7 @@ private Int32 BgAttachService() return 1; } + /// Move special overlays (scroll / parallax / timedmove) public Int32 SceneServiceScroll(BGSCENE_DEF bgScene) { Int16 map = FF9StateSystem.Common.FF9.fldMapNo; @@ -1669,12 +1666,15 @@ public Int32 SceneServiceScroll(BGSCENE_DEF bgScene) { switch (map) { - case 1651: // Iifa roots 1 - bgOverlay.curX = 200; break; - case 1758: // Iifa roots 2 - bgOverlay.curX = 200; bgOverlay.curY = 0; break; + case 1651: case 1758: // Iifa roots + bgOverlay.curX = 200; + if (ActualPsxScreenWidth > 400) + { + bgOverlay.transform.localScale = new Vector3(1.7f, 1f, 1f); + bgOverlay.curX = 300; + } + break; } - } } if ((bgOverlay.flags & BGOVERLAY_DEF.OVERLAY_FLAG.ScrollWithOffset) != 0) // loop in diagonal (816) or loop + parallax (2904) @@ -1703,29 +1703,141 @@ public Int32 SceneServiceScroll(BGSCENE_DEF bgScene) { switch (map) { - case 1651: // Iifa roots 1 - bgOverlay.transform.localScale = new Vector3(1.1f, 1.1f, 1f); bgOverlay.curX = -8; break; + case 312: + if (ActualPsxScreenWidth > 400) + { + bgOverlay.curX = 0f; + } + break; + case 805: case 808: + if (ActualPsxScreenWidth > 400) + { + bgOverlay.transform.localScale = new Vector3(1.3f, 1.3f, 1f); + bgOverlay.curX = 0f; + } + break; + case 908: case 1908: + if (i == 14 && ActualPsxScreenWidth > 400) + { + bgOverlay.curX = 0f; + } + break; + case 1108: // Clayra temple light + bgOverlay.curX = 0f; break; + case 1651: case 1758:// Iifa roots + bgOverlay.transform.localScale = new Vector3(1.1f, 1.1f, 1f); bgOverlay.curX = -8f; break; case 1657: - bgOverlay.curX = this.mainCamera.transform.localPosition.x * (bgOverlay.scrollX / 256f) - (float)0.25; break; - case 1758: // Iifa roots 2 - bgOverlay.transform.localScale = new Vector3(1.1f, 1.1f, 1f); bgOverlay.curX = -8; break; + bgOverlay.curX = this.mainCamera.transform.localPosition.x * (bgOverlay.scrollX / 256f) - 0.25f; break; + case 1660: + bgOverlay.curX = 0f; break; + case 2251: + if (ActualPsxScreenWidth > 400) + { + bgOverlay.curX = 0f; + } + break; + case 2252: + if (ActualPsxScreenWidth >= 480) + { + bgOverlay.curX = 0f; + } + break; case 2600: // 464/416 - bgOverlay.transform.localScale = new Vector3(1.12f, 1.12f, 1f); bgOverlay.curX -= 24; break; + if ((i > 0 && i <= 7) || i == 13) + { + bgOverlay.transform.localScale = new Vector3(1.14f, 1.14f, 1f); bgOverlay.curX -= 24f; + if (ActualPsxScreenWidth >= 464) bgOverlay.curX = -12f; + } + break; case 2602: // 384/328 - bgOverlay.transform.localScale = new Vector3(1.05f, 1.05f, 1f); bgOverlay.curX = 28; break; + bgOverlay.transform.localScale = new Vector3(1.05f, 1.05f, 1f); bgOverlay.curX = 28f; break; + case 2604: // 512/448 + if (ActualPsxScreenWidth >= 448) + { + bgOverlay.transform.localScale = new Vector3(1.15f, 1.15f, 1f); + bgOverlay.curX = 0f; + } + break; case 2605: // 400/368 - bgOverlay.transform.localScale = new Vector3(1.1f, 1.1f, 1f); bgOverlay.curX -= 16; break; + bgOverlay.transform.localScale = new Vector3(1.1f, 1.1f, 1f); bgOverlay.curX -= 16f; + if (ActualPsxScreenWidth > 400) + { + bgOverlay.transform.localScale = new Vector3(1.45f, 1.45f, 1f); + bgOverlay.curX = -16f; + } + if (ActualPsxScreenWidth >= 500) + { + bgOverlay.transform.localScale = new Vector3(1.75f, 1.75f, 1f); + bgOverlay.curX = -16f; + } + break; case 2606: bgOverlay.curX = this.mainCamera.transform.localPosition.x * (bgOverlay.scrollX / 256f); break; case 2607: // 416/400 - bgOverlay.transform.localScale = new Vector3(1.05f, 1.05f, 1f); bgOverlay.curX -= 8; bgOverlay.curY -= 8; break; + bgOverlay.transform.localScale = new Vector3(1.05f, 1.05f, 1f); bgOverlay.curX -= 8f; bgOverlay.curY -= 8f; + if (ActualPsxScreenWidth > 400) + { + bgOverlay.transform.localScale = new Vector3(1.1f, 1.1f, 1f); + bgOverlay.curX = 0f; + } + break; case 2651: - bgOverlay.transform.localScale = new Vector3(1.2f, 1.2f, 1f); bgOverlay.curX -= 56; bgOverlay.curY -= 16; break; + if (i == 3 || i == 4) // exclude parallax text + { + bgOverlay.transform.localScale = new Vector3(1.2f, 1.2f, 1f); bgOverlay.curX -= 56f; bgOverlay.curY -= 16f; + if (ActualPsxScreenWidth > 400) + { + bgOverlay.transform.localScale = new Vector3(1.5f, 1.5f, 1f); + bgOverlay.curX -= 70f; + } + } + break; case 2660: // 536/528 - bgOverlay.transform.localScale = new Vector3(1.02f, 1.02f, 1f); bgOverlay.curX -= 8; break; + bgOverlay.transform.localScale = new Vector3(1.02f, 1.02f, 1f); bgOverlay.curX -= 8f; + if (ActualPsxScreenWidth > 400) + { + bgOverlay.transform.localScale = new Vector3(1.15f, 1.15f, 1f); + bgOverlay.curX = 0f; + } + break; + case 2916: + bgOverlay.transform.localScale = new Vector3(1.02f, 1.02f, 1f); bgOverlay.curX -= 4f; + if (ActualPsxScreenWidth > 400) + { + bgOverlay.curX = -4f; + } + break; + case 2922: + if (ActualPsxScreenWidth > 364 && (i < 4 || i == 8 || i == 9)) + { + bgOverlay.curX = 0; + } + break; + case 2923: + if (ActualPsxScreenWidth > 400 && (i == 2 || (i >= 4 && i <= 13) || i == 19)) + { + bgOverlay.curX = 48; + } + if (ActualPsxScreenWidth > 400 && (i == 1 || i == 3)) + { + bgOverlay.curX = 0; + } + break; } } } + if (bgOverlay.timedMoveDuration > 0) + { + bgOverlay.orgX += bgOverlay.dxTimed; + bgOverlay.orgY += bgOverlay.dyTimed; + bgOverlay.orgZ = (UInt16)Mathf.Clamp(bgOverlay.orgZ + bgOverlay.dzTimed, 0, UInt16.MaxValue); + bgOverlay.curX = bgOverlay.orgX; + bgOverlay.curY = bgOverlay.orgY; + bgOverlay.curZ = bgOverlay.orgZ; + bgOverlay.transform.localPosition = new Vector3(bgOverlay.orgX, bgOverlay.orgY, bgOverlay.orgZ); + bgOverlay.timedMoveDuration--; + if (dbug) Log.Message($"SceneServiceScroll {i} | TimedMove | X:{bgOverlay.curX} Y:{bgOverlay.curY} Z:{bgOverlay.curZ}"); + } } if ((this.flags & FieldMapFlags.Unknown128) != 0u) { @@ -1736,6 +1848,7 @@ public Int32 SceneServiceScroll(BGSCENE_DEF bgScene) return 1; } + /// Move camera to point - with or without cosinus effect public void SceneService2DScroll() { if (!IsActive) @@ -2236,6 +2349,7 @@ public EbgCombineMeshData() internal static readonly Int16 PsxScreenHeightNative = 220; internal static volatile Int16 PsxScreenWidth = CalcPsxScreenWidth(); + internal static volatile Int16 ActualPsxScreenWidth = CalcActualPsxScreenWidth(); internal static readonly Int16 HalfScreenHeight = (Int16)(PsxScreenHeightNative / 2); internal static volatile Int16 HalfScreenWidth = (Int16)(PsxScreenWidth / 2); @@ -2253,29 +2367,17 @@ public static void OnWidescreenSupportChanged() Int32 mapWidth = NarrowMapList.MapWidth(map); //Log.Message("Configuration.Graphics.WidescreenSupport " + Configuration.Graphics.WidescreenSupport + " CalcPsxFieldWidth() " + CalcPsxFieldWidth() + " PsxScreenWidth 1 " + CalcPsxScreenWidth() + " Screen.width " + Screen.width + " Screen.height " + Screen.height + "mapWidth " + mapWidth); - if (mapWidth <= PsxScreenWidth && PersistenSingleton.Instance.CurrentScene != "BattleMap") + if (mapWidth <= PsxScreenWidth && PersistenSingleton.Instance.CurrentScene != "BattleMap" && PersistenSingleton.Instance.CurrentScene != "WorldMap" ) { PsxFieldWidth = (Int16)mapWidth; PsxScreenWidth = (Int16)mapWidth; //Log.Message("PsxScreenWidth 2 " + PsxScreenWidth); } } - if (map >= 3000 && map <= 3012) //pre-#324 way of doing to fix narrows in ending { - PsxFieldWidth = Configuration.Graphics.WidescreenSupport ? CalcPsxFieldWidth() : PsxFieldWidthNative; - PsxScreenWidth = Configuration.Graphics.WidescreenSupport ? CalcPsxScreenWidth() : PsxScreenWidthNative; - if (Configuration.Graphics.InitializeWidescreenSupport() && IsNarrowMap()) - { - foreach (KeyValuePair entry in NarrowMapList.actualNarrowMapWidthDict) - { - if (FF9StateSystem.Common.FF9.fldMapNo == entry.Key) - { - PsxFieldWidth = (Int16)(entry.Value); - PsxScreenWidth = PsxFieldWidth; - } - } - } + PsxFieldWidth = PsxScreenWidth = 320; + Configuration.Graphics.DisableWidescreenSupportForSingleMap(); } HalfFieldWidth = (Int16)(PsxFieldWidth / 2); HalfScreenWidth = (Int16)(PsxScreenWidth / 2); @@ -2289,6 +2391,7 @@ public static void OnWidescreenSupportChanged() private static Int16 CalcPsxFieldWidth() => Configuration.Graphics.InitializeWidescreenSupport() ? (Int16)(PsxFieldHeightNative * Screen.width / Screen.height) : PsxFieldWidthNative; private static Int16 CalcPsxScreenWidth() => Configuration.Graphics.InitializeWidescreenSupport() ? (Int16)(PsxScreenHeightNative * Screen.width / Screen.height) : PsxScreenWidthNative; + private static Int16 CalcActualPsxScreenWidth() => (Int16)(PsxScreenHeightNative * Screen.width / Screen.height); private static Single CalcShaderMulX() => 1f / HalfFieldWidth; private static Single CalcShaderMulY() => 1f / HalfFieldHeight; @@ -2338,4 +2441,99 @@ private Int16 SmoothCamPercent() private Int16 SmoothCamDelay; private Vector2 SmoothCamDelta; private Boolean SmoothCamActive; + + public static readonly Int32[][] FixDepthOfLayer = + { + // [mapNo,camIdx,LayerIndex,Depth], + [51,1,20,600], // Kidnap scene, candle light + [202,0,20,0], // Prima Vista light + [252,0,6,1600], // Evil Forest light + [350,0,0,730], // Dali shop door cropped + [350,0,4,805], // Dali shop door cropped + [350,0,6,820], // Dali shop door cropped + [350,0,7,820], // Dali shop door cropped + [350,0,26,1300], // Dali windmill shadow cropped + [350,0,27,1300], // Dali windmill shadow cropped + [350,0,28,1300], // Dali windmill shadow cropped + [350,0,29,1300], // Dali windmill shadow cropped + [350,0,30,1300], // Dali windmill shadow cropped + [350,0,31,1300], // Dali windmill shadow cropped + [355,0,5,1880], // Dali pub left light + [403,0,23,560], // Dali underground wall over box + [403,0,27,1523], // Dali underground barrel + [408,0,9,2000], // Dali underground light + [408,0,10,2000], // Dali underground light + [408,0,12,2500], // Dali underground light + [562,0,23,0], // Lindblum armorer light + [562,0,24,1], // Lindblum armorer armor + [609,0,7,3900], // Lindblum castle anim + [609,0,8,3900], // Lindblum castle anim + [609,0,9,3900], // Lindblum castle anim + [609,0,10,3900], // Lindblum castle anim + [609,0,11,3900], // Lindblum castle anim + [1206,0,5,1280], // Fireplace under floor 1 tile + [1801,0,5,1280], // Fireplace under floor 1 tile + [1359,0,7,3900], // Lindblum castle anim + [1359,0,8,3900], // Lindblum castle anim + [1359,0,9,3900], // Lindblum castle anim + [1359,0,10,3900], // Lindblum castle anim + [1359,0,11,3900], // Lindblum castle anim + [900,0,20,500], // Treno Thug Inn light + [913,0,0,100], // Treno Tower lights + [913,0,3,0], // Treno Tower lights + [913,0,4,0], // Treno Tower lights + [951,0,2,1214], // Gargan Roo's railing + [1000,0,12,0], // Clayra's Trunk text (in English version) + [1206,0,21,800], // Alexandria, purple chadelier + [1309,0,23,0], // Lindblum armorer light + [1309,0,24,1], // Lindblum armorer armor + [1406,0,20,2600], // Water layer masking actual water waves + [1418,0,10,500], // Light in mine + [1501,0,3,920], // Head crop through rock in Conde Petite + [1502,0,0,1350], // Light in Conde Petite + [1652,1,5,911], // Iifa platform + [1656,0,3,998], // Iifa statue glow (was not active on PSX) + [1950,0,11,1100], // Qwan's dwelling cropped anim. + [2008,0,41,600], // Candle light behind statues in Alex Castle + [2107,0,15,1862], // Lindblum plaza smoke layer + [2109,0,23,0], // Lindblum armorer light + [2109,0,24,1], // Lindblum armorer armor + [2207,0,1,0], // Desert palace teleporter light 1 + [2207,0,2,0], // Desert palace teleporter light 2 + [2207,0,3,0], // Desert palace teleporter light 3 + [2207,0,4,0], // Desert palace teleporter light 4 + [2207,0,5,0], // Desert palace teleporter light 5 + [2209,0,0,0], // Desert palace teleporter light + [2211,0,8,400], // Desert palace teleporter light + [2221,0,17,2200], // Candle light + [2222,0,2,1000], // Desert palace teleporter light + [2502,0,14,1400], // Ypsen, entrance light + [2600,0,1,5000], // Branbal, background + [2600,0,2,5000], // Branbal, background + [2600,0,3,5000], // Branbal, background + [2600,0,4,5000], // Branbal, background + [2600,0,5,5000], // Branbal, background + [2600,0,6,5000], // Branbal, background + [2600,0,7,5000], // Branbal, background + [2600,0,13,8000], // Branbal, background + [2605,0,3,2200], // Branbal, light of light net + [2657,0,4,2040], // Branbal, light in the room + [2922,0,8,4329], // Crystal world (was not active on PSX) + [2922,0,10,3179], // Crystal world (was not active on PSX) + [2922,0,11,3179], // Crystal world (was not active on PSX) + [2922,0,12,6080], // Crystal world (was not active on PSX) + }; + + public static readonly HashSet SmoothCamExcludeMaps = new HashSet() + { + 51, // Candle fire moving away from candles + 575, // Hunting festival glich + 767, // Burmecia, the queen slides from her layer + 931, // Treno on the boat + 1655, // scrolling root + 1754, // Fast scroll on Iifa platform buggy + //1953, // Scene with Quan flashback + 2200, // Desert palace cells + 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, // ending glitches + }; } diff --git a/Assembly-CSharp/Global/Field/Map/NarrowMapList.cs b/Assembly-CSharp/Global/Field/Map/NarrowMapList.cs index fca747624..b89263d4c 100644 --- a/Assembly-CSharp/Global/Field/Map/NarrowMapList.cs +++ b/Assembly-CSharp/Global/Field/Map/NarrowMapList.cs @@ -1,47 +1,24 @@ using System; using System.Collections.Generic; -using System.Linq; -using Memoria; -using Memoria.Prime; public static class NarrowMapList { - public static Boolean IsCurrentMapNarrow(Int32 ScreenWidth) => IsNarrowMap(FF9StateSystem.Common.FF9.fldMapNo, PersistenSingleton.Instance?.fieldmap?.camIdx ?? -1, ScreenWidth); - public static Boolean IsNarrowMap(Int32 mapId, Int32 camId, Int32 ScreenWidth) + /// is mapId <= ScreenWidth + public static Boolean IsCurrentMapNarrow(Int32 ScreenWidth) { - if (SpecificScenesNarrow(mapId, camId)) - return true; - + Int32 mapId = FF9StateSystem.Common.FF9.fldMapNo; if (MapWidth(mapId) <= ScreenWidth) return true; - - //if (ListFullNarrow.Contains(mapId)) - // return true; - - //if (ListPartialNarrow.TryGetValue(mapId, out HashSet narrowCams) && narrowCams.Contains(camId)) - // return true; - //Log.Message("camId:" + camId + ", mapid:" + mapId); - return false; } - public static Boolean SpecificScenesNarrow(Int32 mapId, Int32 currCamera) + public static Boolean SpecificScenesNarrow(Int32 mapId) { Int32 currIndex = PersistenSingleton.Instance.eBin.getVarManually(EBin.MAP_INDEX_SVR); Int32 currCounter = PersistenSingleton.Instance.eBin.getVarManually(EBin.SC_COUNTER_SVR); - foreach (int[] entry in Map_Index_Narrow_List) - { - if (entry[0] == mapId && entry[1] == currIndex) - return true; - } - foreach (int[] entry in Map_Counter_Narrow_List) - { - if (entry[0] == mapId && entry[1] == currCounter) - return true; - } - foreach (int[] entry in Map_Camera_Narrow_List) + foreach (int[] entry in RestrictedWidthScenesList) { - if (entry[0] == mapId && entry[1] == currCamera) + if (entry[0] == mapId && (entry[1] == currIndex || entry[2] == currCounter)) return true; } return false; @@ -49,469 +26,899 @@ public static Boolean SpecificScenesNarrow(Int32 mapId, Int32 currCamera) public static Int32 MapWidth(Int32 mapId) { - Int32 width = 500; - Int32 currCamera = PersistenSingleton.Instance?.fieldmap?.camIdx ?? -1; - - if (ListFullNarrow.Contains(mapId) || SpecificScenesNarrow(mapId, currCamera)) - width = 320; + if (SpecificScenesNarrow(mapId)) + return 320; - foreach (KeyValuePair entry in actualNarrowMapWidthDict) + foreach (int[] entry in MapWidthList) { - if (mapId == entry.Key && !SpecificScenesNarrow(entry.Key, currCamera)) - width = (Int32)entry.Value; + if (entry[0] == mapId) + return entry[1]; } - //Log.Message("width:" + width + "PersistenSingleton.Instance?.fieldmap?.camIdx" + PersistenSingleton.Instance?.fieldmap?.camIdx); - return width; + return 500; } - public static readonly int[][] Map_Index_Narrow_List = - { - // [mapNo,index], - [50,0], // first scene - [150,325], // Zidane infiltrate Alex Castle - [254,26], // MBG103 - Evil Forest - [352,3], // Arrival at Dali: vivi visible before sleeping - [355,18], // Steiner to the barmaid - [600,32], // Throne, meet cid - [615,57], // Meet garnet on Lindblum Tower - [615,58], // Meet garnet on Lindblum Tower (2) - [1206,0], // Queen and Kuja salon Alex, drug garnet - [1602,16], // scene at Madain Sari night w/ Vivi/Zidane/Eiko eavesdropping, bugged if you see too much - [1823,331], // Garnet coronation, garnet visible - [1815,0], // Love quiproquo at the docks - [1816,315], // Love quiproquo at the docks - [2007,2], // MBG111 - Alex castle changing - [2211,8], // Lindblum meeting after Alexander scene: ATE with kuja at his ship, Zorn & Thorn visible too soon and blending - [2404,25], // Baku seen waiting on the docks too soon - [2705,-1], // Pandemonium, you're not alone sequence, several glitches - [2706,-1], // Pandemonium, you're not alone sequence, several glitches - [2707,-1], // Pandemonium, you're not alone sequence, several glitches - [2708,-1], // Pandemonium, you're not alone sequence, several glitches - [2711,0], // Pandemonium, people are waiting in line after Kuja is defeated - }; - - public static readonly int[][] Map_Counter_Narrow_List = + /// Make these scenes widescreen (based on index [1] or counter [2]), -5 is ignored + public static readonly int[][] RestrictedWidthScenesList = { - // [mapNo,counter], - //[951,4500], // Gargan roo, secondary screen is smaller, but only visible in 1 scene - [1554,6300], // MBG109 - roots - [1554,6305], // MBG109 - roots - [2905,11620], // MBG118 - Memoria pink castle + // [mapNo, EBin.MAP_INDEX_SVR, EBin.SC_COUNTER_SVR], + [150, 325, -5], // Zidane infiltrate Alex Castle + [254, 26, -5], // MBG103 - Evil Forest + [352, 3, -5], // Arrival at Dali: vivi visible before sleeping + [1550, -5, 6270], // Mountain path - Quina stays there + [1554, -5, 6300], // MBG109 - roots + [1554, -5, 6305], // MBG109 - roots + [1602, 16, -5], // scene at Madain Sari night w/ Vivi/Zidane/Eiko eavesdropping, bugged if you see too much + [1652, -5, 6700], // Iifa entrance + [1652, -5, 6710], // Iifa entrance + [1815, 0, -5], // Love quiproquo at the docks + [1816, 315, -5], // Love quiproquo at the docks + [1901, -5, 7550], // Treno scene, people staying there + [2007, -5, 8340], // MBG111 - Alex castle changing + [2007, -5, 8400], // MBG111 - Alex castle changing + [2173, -5, 9050], // ATE Quina + [2211, 8, -5], // Lindblum meeting after Alexander scene: ATE with kuja at his ship, Zorn & Thorn visible too soon and blending + [2404, 25, -5], // Baku seen waiting on the docks too soon + [2705, -1, -5], // Pandemonium, you're not alone sequence, several glitches + [2706, -1, -5], // Pandemonium, you're not alone sequence, several glitches + [2707, -1, -5], // Pandemonium, you're not alone sequence, several glitches + [2708, -1, -5], // Pandemonium, you're not alone sequence, several glitches + [2711, 0, -5], // Pandemonium, people are waiting in line after Kuja is defeated + [2905, -5, 11620], // MBG118 - Memoria pink castle }; - public static readonly int[][] Map_Camera_Narrow_List = + /// List of fields with narrower cams than widescreen, [field#, cam#, PSXWidth] + public static readonly int[][] RestrictedCams = { - // [mapNo,camIdx], - //[951,1], // // Gargan roo, secondary screen is smaller, but only visible in 1 scene + // [mapNo,cam,width], + [50,1,320], + [63,0,320], + [116,1,320], + [153,0,320], + [154,0,352], + [355,1,320], + [600,1,320], + [615,1,320], + [801,1,336], + [932,1,320], + [951,1,336], + [1205,1,384], + [1206,1,320], + [1214,0,320], + [1215,0,352], + [1462,0,320], + //[1652,1,336], // resorted back to limiting the scene, as there's still a ~23px offset with 3D objects + [1759,1,336], + [1801,1,320], + [1806,0,320], + [1807,0,352], + [1823,1,320], + [2150,1,320], + [2172,1,320], + [2217,1,320], + [2217,2,320], + [2363,0,384], + [2363,1,336], + [2510,0,320], + [2755,1,336], }; - public static readonly HashSet ListFullNarrow = new HashSet() + /// List of fields of width smaller than widescreen, [field#,PSXWidth] + public static readonly int[][] MapWidthList = { - 0052, // Prima Vista/Meeting Rm - 0053, // Prima Vista/Meeting Rm - 0055, // Prima Vista/Music Room - 0056, // S. Gate - 0058, // Prima Vista/Storage - 0059, // Prima Vista/Interior - 0060, // Prima Vista/Interior - 0061, // Prima Vista/Interior - 0062, // Prima Vista/Interior - 0063, // Prima Vista/Interior - 0065, // Prima Vista/Interior - 0066, // Prima Vista/Interior - 0067, // Prima Vista/Interior - 0068, // A. Castle/Throne - 0069, // A. Castle/Throne - 0100, // Alexandria/Main Street - 0102, // Alexandria/Main Street - 0104, // Alexandria/Shop - 0105, // Alexandria/Alley - 0108, // Alexandria/Item Shop - 0109, // Alexandria/Wpn. Shop - 0114, // Alexandria/Residence - 0116, // Alexandria/Rooftop - 0150, // A. Castle/Guardhouse - 0151, // A. Castle/Throne - 0153, // A. Castle/Hallway - 0154, - 0157, // A. Castle/Kitchen - 0160, // A. Castle/Courtyard - 0161, // A. Castle/Courtyard - 0162, // A. Castle/West Tower - 0163, // A. Castle/West Tower - 0164, // A. Castle/West Tower - 0165, // A. Castle/West Tower - 0166, // A. Castle/West Tower - 0167, // A. Castle/Library - 0201, // Prima Vista/Bridge - 0203, // Prima Vista/Meeting Rm - 0205, // Prima Vista/Hallway - 0206, // Prima Vista/Crash Site - 0207, // Prima Vista/Cabin - 0209, // Prima Vista/Event - 0251, // Evil Forest/Trail - 0252, // Evil Forest/Trail - //0254, // Evil Forest/Swamp - 0255, // Evil Forest/Riverbank - 0256, // Evil Forest/Trail - 0259, // Evil Forest/Trail - 0261, // Evil Forest/Exit - 0262, // Evil Forest/Exit - 0300, // Ice Cavern/Entrance - 0301, // Ice Cavern/Ice Path - 0305, // Ice Cavern/Ice Path - 0306, // Ice Cavern/Cave - 0308, // Ice Cavern/Waterfall - 0309, // Ice Cavern/Waterfall - 0310, // Ice Cavern/Waterfall - 0311, // Ice Cavern/Exit - 0354, // Dali/Wpn. Shop - 0357, // Dali/Windmill 2F - 0358, // Dali/Windmill - 0359, // Dali/??? - 0400, // Dali/Underground - 0405, - 0407, - 0452, // Dali/Field - 0453, // Dali/Field - 0454, // Dali/Field - 0455, // Mountain/Base - 0456, // Mountain/Summit - 0457, // Mountain/Shack - 0500, // Cargo Ship/Deck - 0502, // Cargo Ship/Bridge - 0503, // Cargo Ship/Bridge - 0505, // Cargo Ship/Rear Deck - 0506, // Cargo Ship/Deck - 0550, - 0551, // Lindblum/B.D. Station - 0553, // Lindblum/Inn - 0556, - 0560, // Lindblum/Synthesist - 0561, - 0565, - 0566, - 0567, // Lindblum/Theater Ave. - 0568, - 0569, - 0570, // Lindblum/Industrial Wa - 0571, - 0574, // Lindblum/Festival - 0576, // Lindblum/Festival - //0600, // L. Castle/Royal Cham. - 0601, // L. Castle/Lift - 0606, // L. Castle/Event - 0607, // L. Castle/Hangar - 0609, // L. Castle/Castle Bridg - 0613, - 0620, - 0656, - 0657, - 0658, - 0659, - 0663, - 0701, // Gizamaluke/Entrance - 0705, - 0750, // Burmecia/Gate - 0751, - 0753, - 0754, // Burmecia/Residence - 0755, - 0758, // Burmecia/Pathway - 0760, // Burmecia/Uptown Area - 0764, // Burmecia/Vault - 0765, // Burmecia/Armory - 0766, // Burmecia/Palace - 0767, // Burmecia/Palace - 0800, // S. Gate/Bohden Gate - 0802, // S. Gate/Bohden Sta. - 0803, - 0806, - 0813, // S. Gate/Berkmea - 0814, // S. Gate/Berkmea - 0816, // S. Gate/Berkmea - 0851, - 0855, - 0901, - 0911, - 0913, - 0930, // Treno/Tot Residence - 0931, // Treno/Tot Residence - 0932, // Treno/Event - 0950, - 0951, // Gargan Roo/Passage - 0954, // Gargan Roo/Tunnel - 0955, - 1000, // Cleyra/Tree Roots - 1001, // Cleyra/Tree Roots - 1002, // Cleyra/Tree Roots - 1003, // Cleyra/Tree Trunk - 1006, // Cleyra/Tree Trunk - 1007, // Cleyra/Tree Trunk - 1009, // Cleyra/Tree Trunk - 1013, // Cleyra/Tree Trunk - 1017, // Cleyra/Tree Trunk - 1018, - 1050, // Cleyra/Tree Trunk - 1054, // Cleyra/Windmill Area - 1058, // Cleyra/Cathedral - 1100, // Cleyra/Tree Trunk - 1104, - 1108, // Cleyra/Cathedral - 1150, // Red Rose/Deck - 1151, // Red Rose/Cabin - 1153, // Red Rose/Bridge - 1200, // A. Castle/Throne - 1201, - 1205, // A. Castle/Chapel - 1208, // A. Castle/Dungeon - 1210, // A. Castle/West Tower - 1212, // A. Castle/East Tower - 1213, // A. Castle/Guardhouse - 1214, // A. Castle/Hallway - 1215, - //1216, - 1218, - 1221, // A. Castle/Courtyard - 1222, // A. Castle/Courtyard - 1226, // A. Castle/Library - 1250, // A. Castle/Event - 1251, // Pinnacle Rocks/Hole - 1252, // Pinnacle Rocks/Path - 1253, // Pinnacle Rocks/Path - 1254, - 1300, // Lindblum/Hunter’s Gate - 1301, // Lindblum/B.D. Station - 1303, // Lindblum/Inn - 1308, // Lindblum/Synthesist - 1312, - 1313, - 1314, // Lindblum/Theater Ave. - 1350, - 1351, - 1356, - 1357, // L. Castle/Hangar - 1359, - 1363, - 1370, - 1401, // Fossil Roo/Cavern - 1403, // Fossil Roo/Cavern - 1404, - 1406, // Fossil Roo/Nest - 1408, - 1410, // Fossil Roo/Nest - 1414, - 1424, - 1452, // Mage Village/Cemetery - 1453, // Mage Village/Cemetery - 1455, // Mage Village/Synthesis - 1456, - 1457, // Mage Village/Rooftop - 1458, - 1459, // Mage Village/Water Mil - 1463, // Dead Forest/Grove - 1464, // Dead Forest/Dead End - 1500, - 1506, - 1507, // Conde Petie/Pathway - 1508, - 1509, // Conde Petie/Item Shop - 1556, // Mountain Path/Roots - 1557, // Mountain Path/Roots - 1600, - 1601, - 1602, - 1604, // Mdn. Sari/Eidolon Wall - 1605, // Mdn. Sari/Eidolon Wall - 1606, // Mdn. Sari/Resting Room - 1607, // Mdn. Sari/Kitchen - 1608, // Mdn. Sari/Secret Room - 1609, // Mdn. Sari/Cove - 1610, // Mdn. Sari/Cove - 1650, - //1651, // Iifa Tree/Tree Roots - //1652, // Iifa Tree/Roots - 1655, // Iifa Tree/Tree Path - 1656, // Iifa Tree/Eidolon Moun - 1657, // Iifa Tree/Tree Roots - 1658, // Iifa Tree/Silver Dragon - 1660, - 1661, - 1662, - 1663, - 1700, - 1701, - 1702, - 1704, // Mdn. Sari/Eidolon Wall - 1705, // Mdn. Sari/Resting Room - 1706, // Mdn. Sari/Kitchen - 1707, // Mdn. Sari/Secret Room - 1750, // Iifa Tree/Hollow Roots - 1751, // Iifa Tree/Inner Roots - 1752, // Iifa Tree/Inner Roots - 1753, // Iifa Tree/Inner Roots - 1755, // Iifa Tree/Bottom - 1756, // Iifa Tree/Bottom - 1757, - //1758, // Iifa Tree/Tree Roots - 1800, // A. Castle/Tomb - 1803, // A. Castle/Guardhouse - 1806, // A. Castle/Hallway - 1807, // A. Castle/Hallway - //1808, - 1810, - 1813, // A. Castle/Courtyard - 1814, // A. Castle/Courtyard - //1816, // A. Castle/Courtyard - 1817, // A. Castle/Neptune - 1818, // A. Castle/Neptune - 1820, // A. Castle/West Tower - 1822, // A. Castle/Library - 1850, // Alexandria/Main Street - 1852, - 1854, // Alexandria/Alley - 1857, // Alexandria/Item Shop - 1858, // Alexandria/Wpn. Shop - 1863, - 1866, // Alexandria/Dock - 1901, - 1911, - 1913, - 1951, - 1952, - 1953, // Quan’s/Fishing Area - 2000, // Hilda Garde 2/Deck - 2002, - 2004, - 2005, // A. Castle/Altar - 2006, - //2007, // A. Castle/Altar - 2008, // A. Castle/Altar - 2050, // Alexandria/Main Street - 2052, - 2055, - 2101, // Lindblum/B.D. Station - 2103, // Lindblum/Inn - 2108, // Lindblum/Synthesist - //2109, // Lindblum/Wpn. Shop - 2112, - 2113, - 2114, // Lindblum/Theater Ave. - 2150, // L. Castle/Royal Cham. - 2151, // L. Castle/Lift - 2157, // L. Castle/Hangar - 2159, // L. Castle/Castle Bridg - 2163, - 2171, - 2200, - 2202, // Palace/Dungeon - 2203, // Palace/Rack - 2204, // Palace/Odyssey - 2205, // Palace/Odyssey - 2208, // Palace/Hallway - 2212, - 2213, - 2217, // Palace/Stairwell - 2222, - 2250, // Oeilvert/Outside - 2254, // Oeilvert/Ship Display - 2255, // Oeilvert/Stairwell - 2257, // Oeilvert/Display - 2260, // Oeilvert/Tombstone - 2261, // Oeilvert/Bridge - 2303, - 2305, // Esto Gaza/Path - 2351, // Gulug/Well - 2352, - 2353, - 2354, // Gulug/Room - 2355, - 2356, // Gulug/Room - 2361, // Gulug/Well - 2362, - 2363, // Gulug/Path - 2365, - 2400, // A. Castle/Neptune - 2405, // A. Castle/Courtyard - 2406, - 2450, // Alexandria/Main Street - 2451, - 2453, // Alexandria/Alley - 2458, // Alexandria/Dock - 2500, // I. Castle/Entrance - 2501, // I. Castle/Entrance - 2502, // I. Castle/Hall - 2503, - 2505, // I. Castle/Inverted Roo - 2510, // I. Castle/Mural Room - 2512, // I. Castle/Mural Room - 2513, - 2551, - 2552, // Earth Shrine/Interior - 2601, - 2602, // Terra/Stepping Stones - //2606, // Terra/Tree base - 2608, // Terra/Event - 2650, - 2654, // Bran Bal/Pond - 2657, // Bran Bal/Storage - 2658, - 2701, // Pand./Path - 2706, - 2715, // Pand./Event - 2719, // Pand./Exit - 2752, // Invincible/Bridge - 2756, // Red Rose/Bridge - 2851, // Hilda Garde 3/Engine - 2855, - 2856, - 2900, // Memoria/Outside - 2901, // Memoria/Entrance - 2902, // Memoria/Stairs of Time - 2904, // Memoria/Outer Path - 2906, - 2908, // Memoria/Time Interval - 2909, // Memoria/Ruins - 2910, // Memoria/Lost Memory - 2912, // Memoria/World Fusion - 2913, // Memoria/Portal - 2914, // Memoria/Birth - 2915, - 2917, // Memoria/Gaia’s Birth - 2918, // Memoria/Stairs - 2919, // Memoria/Gate to Space - 2920, - 2922, - 2924, - 2925, - 2926, - 2927, // Crystal World - 2928, - 2929, // last/cw mbg a - 2930, // last/cw mbg 0 - 2932, // last/cw brg 0 - 2933, // last/cw mbg 1 - 2934, // last/cw mbg 2 - 2950, // Chocobo’s Forest - 2953, // Chocobo’s Dream World - 3001, - 3003, - 3005, - 3006, - 3008, // Ending/Prima Vista - Meeting Room - 3009, - 3010, // Ending/TH - 3011, // Ending/TH - 3052, // Mage Village/Cemetery - 3054, // Mage Village/Synthesis - 3055, - 3056, // Mage Village/Rooftop - 3057, - 3058, // Mage Village/Water Mil - 3100, // Mog Post + [50,480], + [51,480], + [52,320], + [53,320], + [54,432], + [55,398], + [56,320], + [57,448], + [58,320], + [59,320], + [60,366], + [61,320], + [62,320], + [63,320], + [64,480], + [65,320], + [66,320], + [67,320], + [68,320], + [69,320], + [100,320], + [101,640], + [102,382], + [103,624], + [104,320], + [105,320], + [106,528], + [107,480], + [108,320], + [109,382], + [110,432], + [111,448], + [112,560], + [113,480], + [114,350], + [115,432], + [116,416], + [117,416], + [150,366], + [151,320], + [152,800], + [153,432], + [154,640], + [155,416], + [156,640], + [157,398], + [158,480], + [159,416], + [160,320], + [161,366], + [162,382], + [163,318], + [164,318], + [165,320], + [166,320], + [167,320], + [200,480], + [201,366], + [202,480], + [203,334], + [204,480], + [205,320], + [206,382], + [207,382], + [208,480], + [209,320], + [250,480], + [251,382], + [252,382], + [253,480], + [254,398], + [255,320], + [256,320], + [257,416], + [258,480], + [259,320], + [261,320], + [262,366], + [300,320], + [301,320], + [302,480], + [303,592], + [304,432], + [305,320], + [306,320], + [307,464], + [308,320], + [309,320], + [310,320], + [311,320], + [312,478], + [350,448], + [351,480], + [352,480], + [353,416], + [354,320], + [355,416], + [356,416], + [357,320], + [358,320], + [359,320], + [400,320], + [401,640], + [402,480], + [403,640], + [404,432], + [405,398], + [406,480], + [407,382], + [408,448], + [450,432], + [451,480], + [452,320], + [453,320], + [454,320], + [455,318], + [456,398], + [457,320], + [500,320], + [501,512], + [502,320], + [503,320], + [504,432], + [505,398], + [506,320], + [507,512], + [550,350], + [551,320], + [552,448], + [553,382], + [554,480], + [555,480], + [556,382], + [557,480], + [558,416], + [559,512], + [560,320], + [561,398], + [562,416], + [563,432], + [564,432], + [565,366], + [566,398], + [567,320], + [568,398], + [569,398], + [570,320], + [571,398], + [572,416], + [573,432], + [574,320], + [575,416], + [576,320], + [600,448], + [601,320], + [602,480], + [603,544], + [604,448], + [605,432], + [606,318], + [607,320], + [608,448], + [609,320], + [610,448], + [611,576], + [612,544], + [613,398], + [614,544], + [615,512], + [616,480], + [617,544], + [618,464], + [619,432], + [620,350], + [650,512], + [651,640], + [652,480], + [653,640], + [654,640], + [655,512], + [656,398], + [657,398], + [658,398], + [659,398], + [660,640], + [661,432], + [662,448], + [663,398], + [701,320], + [702,624], + [703,576], + [704,576], + [705,382], + [706,448], + [707,480], + [750,320], + [751,382], + [752,480], + [753,398], + [754,320], + [755,398], + [756,416], + [757,480], + [758,320], + [759,418], + [760,334], + [761,544], + [762,544], + [763,416], + [764,320], + [765,320], + [766,320], + [767,320], + [768,448], + [800,320], + [801,560], + [802,350], + [803,350], + [804,432], + [805,608], + [806,398], + [807,432], + [808,608], + [809,512], + [810,576], + [811,512], + [812,512], + [813,382], + [814,334], + [815,416], + [816,334], + [850,512], + [851,398], + [852,480], + [853,512], + [854,512], + [855,398], + [856,480], + [900,448], + [901,398], + [902,752], + [903,768], + [904,576], + [905,640], + [906,512], + [907,416], + [908,432], + [909,592], + [910,448], + [911,366], + [912,640], + [913,398], + [914,576], + [915,416], + [916,464], + [930,320], + [931,318], + [932,416], + [950,382], + [951,512], + [952,512], + [953,448], + [954,320], + [955,320], + [956,448], + [1000,320], + [1001,320], + [1002,320], + [1003,320], + [1004,512], + [1005,512], + [1006,320], + [1007,320], + [1008,416], + [1009,320], + [1010,640], + [1011,528], + [1012,464], + [1013,320], + [1014,640], + [1015,528], + [1016,528], + [1017,382], + [1018,382], + [1050,316], + [1051,416], + [1052,592], + [1053,608], + [1054,398], + [1055,478], + [1056,464], + [1057,560], + [1058,380], + [1059,526], + [1060,640], + [1100,320], + [1101,416], + [1102,592], + [1103,608], + [1104,398], + [1105,480], + [1106,464], + [1107,560], + [1108,380], + [1109,528], + [1110,638], + [1150,320], + [1151,334], + [1152,448], + [1153,398], + [1200,320], + [1201,382], + [1202,432], + [1203,432], + [1204,480], + [1205,416], + [1206,416], + [1207,480], + [1208,320], + [1209,640], + [1210,382], + [1211,448], + [1212,350], + [1213,366], + [1214,432], + [1215,640], + [1216,416], + [1217,640], + [1218,398], + [1219,480], + [1220,416], + [1221,320], + [1222,366], + [1223,416], + [1224,528], + [1225,416], + [1226,320], + [1227,480], + [1250,320], + [1251,366], + [1252,320], + [1253,320], + [1254,366], + [1255,432], + [1256,432], + [1300,350], + [1301,320], + [1302,448], + [1303,382], + [1304,480], + [1305,480], + [1306,416], + [1307,512], + [1308,320], + [1309,416], + [1310,432], + [1311,432], + [1312,366], + [1313,398], + [1314,320], + [1315,480], + [1350,320], + [1351,320], + [1352,480], + [1353,544], + [1354,448], + [1355,432], + [1356,320], + [1357,320], + [1358,448], + [1359,320], + [1360,448], + [1361,576], + [1362,544], + [1363,398], + [1364,544], + [1365,512], + [1366,480], + [1367,544], + [1368,464], + [1369,432], + [1370,350], + [1400,640], + [1401,320], + [1402,640], + [1403,366], + [1404,382], + [1405,528], + [1406,320], + [1407,512], + [1408,398], + [1409,512], + [1410,320], + [1411,496], + [1412,640], + [1413,512], + [1414,398], + [1415,512], + [1416,640], + [1417,528], + [1418,512], + [1419,608], + [1420,448], + [1421,512], + [1422,528], + [1423,800], + [1424,398], + [1425,480], + [1450,480], + [1451,432], + [1452,382], + [1453,382], + [1454,512], + [1455,320], + [1456,398], + [1457,320], + [1458,334], + [1459,320], + [1460,512], + [1461,320], + [1462,512], + [1463,320], + [1464,320], + [1500,334], + [1501,528], + [1502,416], + [1503,416], + [1504,512], + [1505,512], + [1506,334], + [1507,318], + [1508,350], + [1509,382], + [1550,576], + [1551,416], + [1552,416], + [1553,624], + [1554,464], + [1555,640], + [1556,320], + [1557,320], + [1600,398], + [1601,398], + [1602,398], + [1603,512], + [1604,398], + [1605,334], + [1606,334], + [1607,320], + [1608,334], + [1609,320], + [1610,320], + [1650,350], + [1651,434], + [1652,480], + [1653,512], + [1654,512], + [1655,320], + [1656,382], + [1657,346], + [1658,320], + [1659,480], + [1660,334], + [1661,334], + [1662,334], + [1663,320], + [1700,398], + [1701,398], + [1702,398], + [1703,512], + [1704,398], + [1705,334], + [1706,320], + [1707,334], + [1750,320], + [1751,334], + [1752,350], + [1753,320], + [1754,398], + [1755,320], + [1756,320], + [1757,350], + [1758,434], + [1759,480], + [1800,320], + [1801,416], + [1802,480], + [1803,366], + [1805,352], + [1806,432], + [1807,640], + [1808,416], + [1809,640], + [1810,398], + [1811,480], + [1812,416], + [1813,320], + [1814,366], + [1815,416], + [1816,416], + [1817,366], + [1818,320], + [1819,416], + [1820,382], + [1821,528], + [1822,320], + [1823,432], + [1824,480], + [1850,320], + [1851,640], + [1852,382], + [1853,624], + [1854,320], + [1855,528], + [1856,480], + [1857,320], + [1858,382], + [1859,432], + [1860,448], + [1861,560], + [1862,480], + [1863,350], + [1864,416], + [1865,432], + [1866,320], + [1900,448], + [1901,398], + [1902,752], + [1903,768], + [1904,576], + [1905,640], + [1906,512], + [1907,416], + [1908,432], + [1909,592], + [1910,448], + [1911,366], + [1912,640], + [1913,398], + [1914,576], + [1915,416], + [1950,496], + [1951,350], + [1952,350], + [1953,366], + [2000,350], + [2001,480], + [2002,366], + [2003,448], + [2004,366], + [2005,320], + [2006,366], + [2007,432], + [2008,320], + [2009,320], + [2050,320], + [2051,640], + [2052,382], + [2053,624], + [2054,480], + [2055,350], + [2101,320], + [2102,448], + [2103,382], + [2104,480], + [2105,480], + [2106,416], + [2107,512], + [2108,320], + [2109,416], + [2110,432], + [2111,432], + [2112,366], + [2113,398], + [2114,320], + [2150,448], + [2151,320], + [2152,480], + [2154,448], + [2153,544], + [2155,432], + [2157,320], + [2158,448], + [2159,320], + [2160,448], + [2161,576], + [2162,544], + [2163,398], + [2165,544], + [2166,512], + [2167,480], + [2168,544], + [2169,464], + [2170,432], + [2171,320], + [2172,512], + [2173,448], + [2200,382], + [2201,560], + [2202,334], + [2203,350], + [2204,334], + [2205,334], + [2206,560], + [2207,512], + [2208,334], + [2209,560], + [2211,928], + [2212,398], + [2213,398], + [2214,512], + [2215,480], + [2216,480], + [2217,432], + [2220,544], + [2221,512], + [2222,382], + [2250,320], + [2251,480], + [2252,480], + [2253,592], + [2254,334], + [2255,320], + [2256,672], + [2257,334], + [2258,592], + [2259,528], + [2260,320], + [2261,350], + [2300,512], + [2301,512], + [2302,512], + [2303,334], + [2304,512], + [2305,320], + [2350,656], + [2351,320], + [2352,398], + [2353,398], + [2354,320], + [2355,382], + [2356,350], + [2357,464], + [2358,544], + [2359,416], + [2360,448], + [2361,320], + [2362,350], + [2363,384], + [2364,512], + [2365,334], + [2400,366], + [2401,320], + [2402,416], + [2403,416], + [2404,416], + [2405,320], + [2406,382], + [2450,320], + [2451,382], + [2452,640], + [2453,320], + [2454,528], + [2455,448], + [2456,432], + [2457,416], + [2458,320], + [2500,350], + [2501,350], + [2502,366], + [2503,366], + [2504,512], + [2505,448], + [2506,512], + [2507,592], + [2508,432], + [2509,512], + [2510,320], + [2512,320], + [2513,334], + [2550,496], + [2551,398], + [2552,352], + [2553,416], + [2554,464], + [2600,464], + [2601,398], + [2602,382], + [2603,560], + [2604,512], + [2605,606], + [2606,512], + [2607,432], + [2608,320], + [2650,366], + [2651,520], + [2652,448], + [2653,512], + [2654,350], + [2655,416], + [2656,480], + [2657,382], + [2658,398], + [2659,464], + [2660,520], + [2661,480], + [2700,448], + [2701,320], + [2702,624], + [2703,464], + [2704,432], + [2705,320], + [2706,398], + [2707,640], + [2708,448], + [2709,480], + [2710,576], + [2711,624], + [2712,512], + [2713,592], + [2714,608], + [2715,320], + [2716,416], + [2717,528], + [2718,592], + [2719,320], + [2750,432], + [2751,432], + [2752,320], + [2753,448], + [2754,480], + [2755,496], + [2756,334], + [2771,350], + [2800,512], + [2801,480], + [2802,480], + [2803,496], + [2850,496], + [2851,382], + [2852,464], + [2853,512], + [2854,496], + [2855,382], + [2856,382], + [2900,320], + [2901,320], + [2902,320], + [2903,510], + [2904,366], + [2905,448], + [2906,398], + [2907,544], + [2908,320], + [2909,320], + [2910,320], + [2911,480], + [2912,320], + [2913,366], + [2914,320], + [2915,382], + [2916,414], + [2917,320], + [2918,320], + [2919,320], + [2920,320], + [2921,336], + [2922,384], + [2923,688], + [2924,320], + [2925,320], + [2926,320], + [2927,320], + [2928,366], + [2929,320], + [2930,320], + [2931,496], + [2932,334], + [2933,320], + [2934,320], + [2950,320], + [2951,480], + [2952,512], + [2953,320], + [2954,480], + [2955,576], + [3000,320], + [3001,320], + [3002,320], + [3003,320], + [3004,320], + [3005,320], + [3006,320], + [3007,320], + [3008,320], + [3009,320], + [3010,320], + [3011,320], + [3012,320], + [3050,480], + [3051,432], + [3052,382], + [3053,512], + [3054,320], + [3055,398], + [3056,320], + [3057,334], + [3058,320], + [3059,512], + [3100,366], }; + /// Left and right margin of camera (because it goes too far), [field#,PSXmargin] public static readonly Dictionary mapCameraMargin = new Dictionary { //{mapNo,pixels on each side to crop because of scrollable} @@ -519,207 +926,6 @@ public static Int32 MapWidth(Int32 mapId) {1057,17}, {1058,16}, {1060,17}, - {1652,16}, {1653,16}, - //{154,16}, - }; - - public static readonly Dictionary actualNarrowMapWidthDict = new Dictionary - { - //{mapNo,(actualWidth - 2)} - {163,318}, - {606,318}, - {1050,316}, - - {203,334}, - {760,334}, - {814,334}, - {816,334}, - {1151,334}, - {1458,334}, - {1500,334}, - {1506,334}, - {1605,334}, - {1606,334}, - {1608,334}, - {1660,334}, - {1661,334}, - {1662,334}, - {1705,334}, - {1707,334}, - {1751,334}, - {2202,334}, - {2204,334}, - {2205,334}, - {2208,334}, - {2254,334}, - {2257,334}, - {2303,334}, - {2365,334}, - {2513,334}, - {2756,334}, - {2932,334}, - {3057,334}, - {114,350}, - {550,350}, - {620,350}, - {802,350}, - {803,350}, - {1212,350}, - {1300,350}, - {1370,350}, - {1508,350}, - {1650,350}, - {1657,346}, - {1752,350}, - {1757,350}, - {1863,350}, - {1951,350}, - {1952,350}, - {2000,350}, - {2055,350}, - {2771,350}, - {2203,350}, - {2261,350}, - {2356,350}, - {2362,350}, - {2500,350}, - {2501,350}, - {2654,350}, - {60,366}, - {150,366}, - {161,366}, - {201,366}, - {262,366}, - {565,366}, - {911,366}, - {1213,366}, - {1222,366}, - {1251,366}, - {1254,366}, - {1312,366}, - {1403,366}, - {1803,366}, - {1814,366}, - {1817,366}, - {1911,366}, - {1953,366}, - {2002,366}, - {2004,366}, - {2006,366}, - {2112,366}, - {2400,366}, - {2502,366}, - {2503,366}, - {2650,366}, - {2904,366}, - {2913,366}, - {2928,366}, - {3100,366}, - {102,382}, - {109,382}, - {162,382}, - {206,382}, - {207,382}, - {251,382}, - {252,382}, - {407,382}, - {553,382}, - {556,382}, - {705,382}, - {751,382}, - {813,382}, - {950,382}, - {1017,382}, - {1018,382}, - {1058,380}, - {1108,380}, - {1201,382}, - {1210,382}, - {1303,382}, - {1404,382}, - {1452,382}, - {1453,382}, - {1509,382}, - {1656,382}, - {1820,382}, - {1852,382}, - {1858,382}, - {2052,382}, - {2103,382}, - {2200,382}, - {2222,382}, - {2355,382}, - {2406,382}, - {2451,382}, - {2602,382}, - {2657,382}, - {2851,382}, - {2855,382}, - {2856,382}, - {2915,382}, - {3052,382}, - {55,398}, - {157,398}, - {405,398}, - {456,398}, - {505,398}, - {561,398}, - {566,398}, - {568,398}, - {569,398}, - {571,398}, - {613,398}, - {656,398}, - {657,398}, - {658,398}, - {659,398}, - {663,398}, - {753,398}, - {755,398}, - {806,398}, - {851,398}, - {855,398}, - {901,398}, - {913,398}, - {1054,398}, - {1104,398}, - {1153,398}, - {1218,398}, - {1313,398}, - {1363,398}, - {1408,398}, - {1414,398}, - {1424,398}, - {1456,398}, - {1600,398}, - {1601,398}, - {1602,398}, - {1700,398}, - {1701,398}, - {1702,398}, - {1810,398}, - {1901,398}, - {1913,398}, - {2113,398}, - {2163,398}, - {2212,398}, - {2213,398}, - {2352,398}, - {2353,398}, - {2551,398}, - {2601,398}, - {2658,398}, - {2706,398}, - {2906,398}, - {3005,398}, - {3055,398}, - {1205,384}, - {154,352}, - {1215,352}, - {1805,352}, - {1807,352}, - //{1652,336}, - {2552,352}, }; } diff --git a/Assembly-CSharp/Global/Hono/HonoFading.cs b/Assembly-CSharp/Global/Hono/HonoFading.cs index 7524a1555..6a9d46710 100644 --- a/Assembly-CSharp/Global/Hono/HonoFading.cs +++ b/Assembly-CSharp/Global/Hono/HonoFading.cs @@ -31,12 +31,6 @@ public void SetAlphaTween(Single alphaFrom, Single alphaTo, Single duration, Sin public void Fade(Single alphaFrom, Single alphaTo, Single duration, Single delay, AnimationCurve animCurve, UIScene.SceneVoidDelegate callback = null) { - if (Configuration.Graphics.SkipIntros > 0) - { - duration = 0; - delay = 0; - } - if (base.gameObject.activeInHierarchy && !this.busy) { if (Configuration.Graphics.WidescreenSupport && widescreenRescale) @@ -65,12 +59,14 @@ public void Fade(Single alphaFrom, Single alphaTo, Single duration, Single delay public void FadeIn(UIScene.SceneVoidDelegate callback = null) { - this.Fade(this.fadeInFrom, this.fadeInTo, this.fadeInDuration, this.fadeInDelay, this.fadeInCurve, callback); + // We don't fade to black if fadeInDuration is too short to avoid flashing + this.Fade(this.fadeInFrom, (this.fadeInDuration > 0.05f) ? this.fadeInTo : this.fadeInFrom, this.fadeInDuration, this.fadeInDelay, this.fadeInCurve, callback); } public void FadeOut(UIScene.SceneVoidDelegate callback = null) - { - this.Fade(this.fadeOutFrom, this.fadeOutTo, this.fadeOutDuration, this.fadeOutDelay, this.fadeOutCurve, callback); + { + // We don't fade from black if fadeInDuration is too short to avoid flashing + this.Fade((this.fadeOutDuration > 0.05f) ? this.fadeOutFrom : this.fadeOutTo, this.fadeOutTo, this.fadeOutDuration, this.fadeOutDelay, this.fadeOutCurve, callback); } public void FadePingPong(UIScene.SceneVoidDelegate blackSceneCallback = null, UIScene.SceneVoidDelegate finishCallback = null) diff --git a/Assembly-CSharp/Global/Hono/HonoInputManager.cs b/Assembly-CSharp/Global/Hono/HonoInputManager.cs index bdd0f3f0f..c119c6693 100644 --- a/Assembly-CSharp/Global/Hono/HonoInputManager.cs +++ b/Assembly-CSharp/Global/Hono/HonoInputManager.cs @@ -679,16 +679,14 @@ private void CheckPersistentInput() { if (!this.isDisablePrimaryKey) { - GamePadState state = global::GamePad.GetState(PlayerIndex.One); + GamePadState state = GamePad.GetState(PlayerIndex.One); for (Int32 i = 0; i < (Int32)this.KeyName.Length; i++) { - Boolean flag = false; - if (HonoInputManager.VKKeyCodeMapping.ContainsKey(this.inputKeysPrimary[i])) + if (ApplicationIsActivated() && VKKeyCodeMapping.ContainsKey(this.inputKeysPrimary[i]) && GetAsyncKeyState(VKKeyCodeMapping[this.inputKeysPrimary[i]]) != 0) { - flag = (HonoInputManager.GetAsyncKeyState(HonoInputManager.VKKeyCodeMapping[this.inputKeysPrimary[i]]) != 0); + this.isInput[i] = true; } - Boolean flag2 = this.CheckRawXInput(this.joystickKeysPrimary[i], state); - if (HonoInputManager.ApplicationIsActivated() && (flag || flag2)) + if((Configuration.Control.AlwaysCaptureGamepad || ApplicationIsActivated()) && this.CheckRawXInput(this.joystickKeysPrimary[i], state)) { this.isInput[i] = true; } diff --git a/Assembly-CSharp/Global/Honolulu/HonoluluBattleMain.cs b/Assembly-CSharp/Global/Honolulu/HonoluluBattleMain.cs index 25eab9bc6..a2b0d92f1 100644 --- a/Assembly-CSharp/Global/Honolulu/HonoluluBattleMain.cs +++ b/Assembly-CSharp/Global/Honolulu/HonoluluBattleMain.cs @@ -1,13 +1,14 @@ using Assets.Scripts.Common; using Assets.Sources.Scripts.UI.Common; using FF9; +using Memoria; +using Memoria.Data; +using Memoria.Database; +using Memoria.Prime; using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using Memoria; -using Memoria.Data; -using Memoria.Database; using UnityEngine; #pragma warning disable 169 @@ -412,7 +413,7 @@ private void YMenu_ManagerActiveTime() { BTL_DATA btl = FF9StateSystem.Battle.FF9Battle.btl_list.next; UIManager.Battle.UpdateSlidingButtonState(); - if (UIManager.Battle.FF9BMenu_IsEnableAtb()) + if (UIManager.Battle.IsNativeEnableAtb()) ProcessActiveTime(btl); } @@ -421,29 +422,35 @@ private void ProcessActiveTime(BTL_DATA btl) Int32 battleSpeed = Configuration.Battle.Speed; BTL_DATA source = btl; - Boolean canContinute = false; - Boolean needContinue = battleSpeed == 1 || battleSpeed == 2; + Boolean canContinue = false; + Boolean needContinue = false; + Int32 maxLoop = 1000; + do { - HonoluluBattleMain.counterATB++; - for (btl = source; btl != null; btl = btl.next) + if (battleSpeed == 1 || battleSpeed == 2) { - if (btl.cur.hp == 0) - continue; - - if (btl.sel_mode != 0 || btl.sel_menu != 0 || btl.bi.atb == 0) + // Check if someone has some atb, we don't want to advance atb instantly in some cases + // This is necessary for some fights starting with a conversation where atb is forced to 0 (see issue #430) + needContinue = false; + foreach (BattleUnit unit in FF9StateSystem.Battle.FF9Battle.EnumerateBattleUnits()) { - // We need to refresh status for any alive characters in the fast or the turn-based mode - if (needContinue) + if (!unit.IsPlayer) continue; + if (unit.CurrentAtb > 0) { - // ============ Warning ============ - btl_para.CheckPointData(btl); - btl_stat.CheckStatusLoop(btl, true); - // ================================= + needContinue = true; + break; } + } + } + + Boolean advanceAtb = UIManager.Battle.FF9BMenu_IsEnableAtb(); + if (advanceAtb) HonoluluBattleMain.counterATB++; + for (btl = source; btl != null; btl = btl.next) + { + if (btl.cur.hp == 0 || btl.sel_mode != 0 || btl.bi.atb == 0) continue; - } POINTS current = btl.cur; POINTS maximum = btl.max; @@ -451,19 +458,14 @@ private void ProcessActiveTime(BTL_DATA btl) Boolean changed = false; if (current.at < maximum.at) { - if (btl.bi.player != 0) - canContinute = true; + if (btl.bi.player != 0 || (battleSpeed == 2 && BattleHUD.ForceNextTurn)) + canContinue = true; changed = true; - current.at += (Int16)Math.Max(1, current.at_coef * 4 ); - } - - if (needContinue) - { - // ============ Warning ============ - btl_para.CheckPointData(btl); - btl_stat.CheckStatusLoop(btl, true); - // ================================= + if (advanceAtb) + current.at += (Int16)Math.Max(1, current.at_coef * 4); + else + needContinue = false; } if (current.at < maximum.at) @@ -475,13 +477,18 @@ private void ProcessActiveTime(BTL_DATA btl) { if (changed) { + if (BattleHUD.ForceNextTurn) + { + BattleHUD.ForceNextTurn = false; + BattleHUD.switchBtlId = btl.btl_id; + } needContinue = false; } } - else + else if (!btl_stat.CheckStatus(btl, BattleStatusConst.PreventATBConfirm)) { - if (!btl_stat.CheckStatus(btl, BattleStatusConst.PreventATBConfirm)) - needContinue = false; + if (changed) BattleHUD.ForceNextTurn = false; + needContinue = false; } } else if (battleSpeed != 1 || !btl_stat.CheckStatus(btl, BattleStatusConst.PreventATBConfirm)) @@ -527,12 +534,30 @@ private void ProcessActiveTime(BTL_DATA btl) if (Array.IndexOf(FF9StateSystem.Battle.FF9Battle.seq_work_set.AnmOfsList, this.btlIDList[btl_scrp.FindBattleUnit(btl.btl_id).Data.typeNo]) < 0) Debug.LogError("Index out of range"); - UnityEngine.Random.Range(0, 4); if (FF9StateSystem.Battle.FF9Battle.btl_phase != 4) - break; + return; + } + } + + // Failsafe - some events might produce infinite loops (i.e. atb never advance) + if (--maxLoop <= 0) + { + Log.Warning($"[ProcessActiveTime] Failsafe activated - btlMapNo: {FF9StateSystem.Common.FF9.btlMapNo} fldMapNo: {FF9StateSystem.Common.FF9.fldMapNo} wldMapNo: {FF9StateSystem.Common.FF9.wldMapNo}"); + return; + } + + if (canContinue && needContinue) + { + // Update statuses before looping + for (btl = source; btl != null; btl = btl.next) + { + btl_para.CheckPointData(btl); + btl_stat.CheckStatusLoop(btl); } + // Events need to be processed (i.e. atb reset to 0, see issue #430) + PersistenSingleton.Instance.ServiceEvents(); } - } while (canContinute && needContinue); + } while (canContinue && needContinue); } private void Update() @@ -835,4 +860,4 @@ private static Boolean IsOver FF9StateSystem.Battle.FF9Battle.attr &= ~ff9btl.ATTR.EXITBATTLE; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/ItemUI.cs b/Assembly-CSharp/Global/ItemUI.cs index fc8e92548..833647970 100644 --- a/Assembly-CSharp/Global/ItemUI.cs +++ b/Assembly-CSharp/Global/ItemUI.cs @@ -132,33 +132,69 @@ public override void Show(SceneVoidDelegate afterFinished = null) HelpDespLabelGameObject.SetActive(FF9StateSystem.PCPlatform); _itemScrollList.ScrollButton.DisplayScrollButton(false, false); _keyItemScrollList.ScrollButton.DisplayScrollButton(false, false); + UpdateUserInterface(); } public void UpdateUserInterface() { if (!Configuration.Interface.IsEnabled) return; + _itemPanel.ScrollButton.Panel.alpha = 0.5f; + _keyItemPanel.ScrollButton.Panel.alpha = 0.5f; const Int32 originalLineCount = 8; + const Int32 originalColumnCount = 2; const Single buttonOriginalHeight = 98f; const Single panelOriginalWidth = 1490f; const Single panelOriginalHeight = originalLineCount * buttonOriginalHeight; + Int32 linePerPage = Configuration.Interface.MenuItemRowCount; + Int32 columnPerPage = (Int32)Math.Floor((Single)(originalColumnCount * ((Single)linePerPage / originalLineCount))); + if (originalColumnCount * originalLineCount >= this._itemIdList.Count) // 2 columns suffice + { + linePerPage = originalLineCount; + columnPerPage = originalColumnCount; + } + else if (linePerPage >= originalLineCount * 2 && (originalColumnCount + 1) * (originalLineCount + originalLineCount / originalColumnCount) >= this._itemIdList.Count) // 3 columns suffice + { + linePerPage = originalLineCount + originalLineCount / originalColumnCount; + columnPerPage = originalColumnCount + 1; + } + Int32 lineHeight = (Int32)Math.Round(panelOriginalHeight / linePerPage); Single scaleFactor = lineHeight / buttonOriginalHeight; - KeyItemDetailHUD keyItemPrefab = new KeyItemDetailHUD(_keyItemPanel.SubPanel.ButtonPrefab.GameObject); - _itemPanel.SubPanel.ChangeDims(2, linePerPage, panelOriginalWidth / 2f, lineHeight); + + Single alphaColumnTitles = (columnPerPage > originalColumnCount) ? 0f : 1f; + _itemPanel.Background.Panel.Name.Label.alpha = alphaColumnTitles; + _itemPanel.Background.Panel.Info.Label.alpha = alphaColumnTitles; + _itemPanel.Background.Panel.Name2.Label.alpha = alphaColumnTitles; + _itemPanel.Background.Panel.Info2.Label.alpha = alphaColumnTitles; + + _itemPanel.SubPanel.ChangeDims(columnPerPage, linePerPage, panelOriginalWidth / columnPerPage, lineHeight); _itemPanel.SubPanel.ButtonPrefab.IconSprite.SetAnchor(target: _itemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.105f, relRight: 0.191f); + _itemPanel.SubPanel.ButtonPrefab.IconSprite.width = _itemPanel.SubPanel.ButtonPrefab.IconSprite.height; + _itemPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _itemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.215f, relRight: 0.795f); - _itemPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _itemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.8f, relRight: 0.9f); _itemPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _itemPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _itemPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _itemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.8f, relRight: 0.9f); _itemPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _itemPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + _itemPanel.SubPanel.RecycleListPopulator.RefreshTableView(); + + KeyItemDetailHUD keyItemPrefab = new KeyItemDetailHUD(_keyItemPanel.SubPanel.ButtonPrefab.GameObject); _keyItemPanel.SubPanel.ChangeDims(2, linePerPage, panelOriginalWidth / 2f, lineHeight); + //snouz: can't make these icons work when extending the key item menu, so 2 columns it stays + //_keyItemPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _keyItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.105f, relRight: 0.75f); + //keyItemPrefab.NewIcon.SetAnchor(target: _keyItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.75f, relRight: 0.9f); keyItemPrefab.NewIcon.SetDimensions((Int32)Math.Round(117f * scaleFactor), (Int32)Math.Round(64f * scaleFactor)); keyItemPrefab.NewIconSprite.SetDimensions((Int32)Math.Round(44f * scaleFactor), (Int32)Math.Round(58f * scaleFactor)); keyItemPrefab.NewIconLabelSprite.SetDimensions((Int32)Math.Round(90f * scaleFactor), (Int32)Math.Round(58f * scaleFactor)); keyItemPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + keyItemPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _keyItemPanel.SubPanel.RecycleListPopulator.RefreshTableView(); + } [DebuggerHidden] @@ -1016,4 +1052,4 @@ public FieldKeyItemListData() { } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/JsonParser.cs b/Assembly-CSharp/Global/JsonParser.cs index d4cc1461a..c261fb7aa 100644 --- a/Assembly-CSharp/Global/JsonParser.cs +++ b/Assembly-CSharp/Global/JsonParser.cs @@ -250,6 +250,7 @@ public override void ParseToFF9StateSystem(JSONClass rootNode) public void ParseToFF9StateSystem(JSONNode rootNode) { + Boolean hasTime = false; JSONNode rootMainClass = rootNode["Data"]; if (rootMainClass == null) return; @@ -277,13 +278,12 @@ public void ParseToFF9StateSystem(JSONNode rootNode) player.bonus.cap = (UInt16)rootMainClass["94000_Common"]["00001_player_bonus"][i].AsUInt; } } - if (rootMainClass["50000_Setting"] != null && rootMainClass["95000_Setting"] != null && rootMainClass["50000_Setting"]["time"] != null && rootMainClass["95000_Setting"]["00001_time"] != null) - { - if (rootMainClass["50000_Setting"]["time"].AsFloat >= 0.0) - FF9StateSystem.Settings.time = rootMainClass["50000_Setting"]["time"].AsFloat; - else - FF9StateSystem.Settings.time = rootMainClass["95000_Setting"]["00001_time"].AsDouble; - } + if (rootMainClass["95000_Setting"] != null && rootMainClass["95000_Setting"]["00001_time"] != null) + { + //FF9StateSystem.Settings.time = rootMainClass["50000_Setting"]["time"].AsFloat; // This one is dummied (always saved as "-1f") + FF9StateSystem.Settings.time = rootMainClass["95000_Setting"]["00001_time"].AsDouble; + hasTime = true; + } if (rootMainClass["98000_Achievement"]["00001_abnormal_status"] != null) FF9StateSystem.Achievement.abnormal_status = rootMainClass["98000_Achievement"]["00001_abnormal_status"].AsUInt; if (rootMainClass["98000_Achievement"]["00002_summon_shiva"] != null) @@ -320,11 +320,18 @@ public void ParseToFF9StateSystem(JSONNode rootNode) FF9StateSystem.Achievement.summon_arc = rootMainClass["98000_Achievement"]["000017_summon_arc"].AsBool; JSONNode memoriaClass = rootNode["MemoriaExtraData"]; - Boolean isMemoriaValid = true; - if (memoriaClass["95000_Setting"] != null) - { - // Maybe check if memoriaClass["95000_Setting"]["00001_time"].AsDOuble == FF9StateSystem.Settings.time - } + Boolean isMemoriaValid = memoriaClass != null; + if (memoriaClass["95000_Setting"] != null) + { + if (hasTime && memoriaClass["95000_Setting"]["00001_time"] != null && Math.Abs(memoriaClass["95000_Setting"]["00001_time"].AsDouble - FF9StateSystem.Settings.time) > 1.0) + { + // The Memoria part of the save and the vanilla part were not generated at the same time + // It typically happens after retrieving a save from the cloud that overwrotes another save + isMemoriaValid = false; + if (memoriaClass["MetaDataFileName"] != null) + Log.Message($"[{nameof(JsonParser)}] Ignoring the Memoria save {memoriaClass["MetaDataFileName"]} because its internal save time ({TimeSpan.FromSeconds(memoriaClass["95000_Setting"]["00001_time"].AsDouble)}) differs from the base save time ({TimeSpan.FromSeconds(FF9StateSystem.Settings.time)})"); + } + } if (isMemoriaValid) { if (memoriaClass["20000_Event"] != null) @@ -1215,7 +1222,7 @@ private void ParseCommonJsonToData(JSONNode jsonData, Boolean oldSaveFormat = tr player.status = (BattleStatus)playerClass["status"].AsInt; if (playerClass["equip"] != null) for (Int32 j = 0; j < playerClass["equip"].Count && j < CharacterEquipment.Length; j++) - if (ff9item._FF9Item_Data.ContainsKey((RegularItem)playerClass["equip"][j].AsInt)) + if (ff9item._FF9Item_Data.ContainsKey((RegularItem)playerClass["equip"][j].AsInt)) // Check if custom items exist, otherwhise remove it from player equipment. player.equip[j] = (RegularItem)playerClass["equip"][j].AsInt; else player.equip[j] = RegularItem.NoItem; @@ -1268,7 +1275,7 @@ private void ParseCommonJsonToData(JSONNode jsonData, Boolean oldSaveFormat = tr else if (playerClass["sa_extended"] != null) { for (Int32 j = 0; j < playerClass["sa_extended"].Count; j++) - if (ff9abil.FF9Abil_GetIndex(player, playerClass["sa_extended"][j].AsInt) > 0) + if (ff9abil._FF9Abil_SaData.ContainsKey((SupportAbility)playerClass["sa_extended"][j].AsInt)) // Check if SA exist (specially custom SA otherwise loading save can softlock). ff9abil.FF9Abil_SetEnableSA(player, (SupportAbility)playerClass["sa_extended"][j].AsInt, true); } } diff --git a/Assembly-CSharp/Global/MainMenuUI.cs b/Assembly-CSharp/Global/MainMenuUI.cs index 966dbd643..abe66c3ec 100644 --- a/Assembly-CSharp/Global/MainMenuUI.cs +++ b/Assembly-CSharp/Global/MainMenuUI.cs @@ -3,11 +3,11 @@ using System.Linq; using Assets.Scripts.Common; using Assets.Sources.Scripts.UI.Common; +using Memoria; using Memoria.Data; using Memoria.Assets; using Memoria.Scenes; using UnityEngine; -using Object = System.Object; public class MainMenuUI : UIScene { @@ -101,7 +101,7 @@ public override void Hide(UIScene.SceneVoidDelegate afterFinished = null) else { this.screenFadePanel.depth = 7; - this.submenuTransition.AnimationTime = FF9StateSystem.Settings.IsFastForward ? 0.1f : 0.2f; + this.submenuTransition.AnimationTime = (!FF9StateSystem.Settings.IsFastForward) ? Configuration.Interface.FadeDuration : Configuration.Interface.FadeDuration / FF9StateSystem.Settings.FastForwardFactor; this.submenuTransition.TweenOut(null); } base.Hide(afterHideAction); @@ -109,7 +109,7 @@ public override void Hide(UIScene.SceneVoidDelegate afterFinished = null) public void StartSubmenuTweenIn() { - this.submenuTransition.AnimationTime = ((!FF9StateSystem.Settings.IsFastForward) ? 0.2f : 0.1f); + this.submenuTransition.AnimationTime = (!FF9StateSystem.Settings.IsFastForward) ? Configuration.Interface.FadeDuration : Configuration.Interface.FadeDuration / FF9StateSystem.Settings.FastForwardFactor; this.submenuTransition.TweenIn((Action)null); } @@ -478,7 +478,7 @@ private void DisplayCharacter() private void DisplayGeneralInfo() { - this.gilLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.gilLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.locationNameLabel.text = FF9StateSystem.Common.FF9.mapNameStr; } diff --git a/Assembly-CSharp/Global/Model/ModelFactory.cs b/Assembly-CSharp/Global/Model/ModelFactory.cs index 4cabd9f95..dbd208550 100644 --- a/Assembly-CSharp/Global/Model/ModelFactory.cs +++ b/Assembly-CSharp/Global/Model/ModelFactory.cs @@ -82,7 +82,24 @@ public static GameObject CreateModel(String path, Boolean isBattle = false) renderer.material.SetTexture("_MainTex", texture); } } - Shader shader; + if (CustomModelField.Count > 0 && !isBattle) + { + foreach (KeyValuePair CustomModelFieldEntry in CustomModelField) + { + if (CustomModelFieldEntry.Key.Contains(modelNameId)) + { + string[] SplitEntry = CustomModelFieldEntry.Key.Split('#'); + Int32.TryParse(SplitEntry[0], out Int32 FieldID); + Renderer[] renderers = gameObject.GetComponentsInChildren(); + if (FF9StateSystem.Common.FF9.fldMapNo == FieldID) + { + String[] NewTextures = CustomModelFieldEntry.Value; + ChangeModelTexture(gameObject, NewTextures); + } + } + } + } + Shader shader; if (modelNameId.Contains("GEO_SUB_W0")) shader = ShadersLoader.Find(modelNameId.Contains("GEO_SUB_W0_025") ? "WorldMap/ShadowActor" : "WorldMap/Actor"); else @@ -1684,4 +1701,6 @@ public static GameObject CreateUIModel(PrimitiveType shape, Color color, Single "GEO_MAIN_B0_026", "GEO_MAIN_B0_027" }; + + public static Dictionary CustomModelField = new Dictionary(); } diff --git a/Assembly-CSharp/Global/NGUIText.cs b/Assembly-CSharp/Global/NGUIText.cs index 71b08ddfd..a2b267a07 100644 --- a/Assembly-CSharp/Global/NGUIText.cs +++ b/Assembly-CSharp/Global/NGUIText.cs @@ -2726,6 +2726,7 @@ public static void DebugLog(params Object[] objs) public const String SpacingY = "SPAY"; public const String KeyboardButtonIcon = "KCBT"; public const String JoyStickButtonIcon = "JCBT"; + public const String NoTurboDialog = "NTUR"; public static readonly String[] RenderOpcodeSymbols; @@ -2874,4 +2875,4 @@ public class GlyphInfo public Int32 channel; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/PSXCameraAspect.cs b/Assembly-CSharp/Global/PSXCameraAspect.cs index 9e2a8a506..9e8fd57ef 100644 --- a/Assembly-CSharp/Global/PSXCameraAspect.cs +++ b/Assembly-CSharp/Global/PSXCameraAspect.cs @@ -40,8 +40,17 @@ private void Start() private void LateUpdate() { Rect rect = base.GetComponent().rect; + Single camRestrictionRatio = 1f; - if (Configuration.Graphics.WidescreenSupport) + foreach (int[] entry in NarrowMapList.RestrictedCams) + { + if (entry[0] == FF9StateSystem.Common.FF9.fldMapNo && entry[1] == (PersistenSingleton.Instance?.fieldmap?.camIdx ?? -1) && FieldMap.ActualPsxScreenWidth < 401) + { + camRestrictionRatio = Mathf.Min(((Single)entry[2] / (Single)FieldMap.PsxFieldWidth), 1f); + } + } + + if (Configuration.Graphics.WidescreenSupport && camRestrictionRatio == 1f) { this.Ratio = 1f; @@ -65,7 +74,7 @@ private void LateUpdate() this.Ratio = Mathf.Min((Single)Screen.width / originalWidth, (Single)Screen.height / originalHeight); - Vector2 scaledSize = new Vector2(originalWidth * this.Ratio, originalHeight * this.Ratio); + Vector2 scaledSize = new Vector2(originalWidth * this.Ratio * camRestrictionRatio, originalHeight * this.Ratio); Single normalizedWidth = ((Single)Screen.width - scaledSize.x) / (Single)Screen.width; Single normalizedHeight = ((Single)Screen.height - scaledSize.y) / (Single)Screen.height; rect.width = scaledSize.x / (Single)Screen.width; diff --git a/Assembly-CSharp/Global/Quad/Mist/Game/QuadMistGame.cs b/Assembly-CSharp/Global/Quad/Mist/Game/QuadMistGame.cs index bec32ac70..3628d65ff 100644 --- a/Assembly-CSharp/Global/Quad/Mist/Game/QuadMistGame.cs +++ b/Assembly-CSharp/Global/Quad/Mist/Game/QuadMistGame.cs @@ -1357,7 +1357,7 @@ private IEnumerator ResultText(MatchResult result) case MatchResult.Type.WIN: if (result.perfect) { - sound = QuadMistSoundID.MINI_SE_PARFECT; + sound = QuadMistSoundID.MINI_SE_PERFECT; id = 3; } else @@ -1626,4 +1626,4 @@ private void UpdateBattleNumberPosition(Int32 i, QuadMistCardUI a) { SetBattleNumber(i, a, battleNumber[i].Text); } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/Quad/Mist/QuadMistSoundID.cs b/Assembly-CSharp/Global/Quad/Mist/QuadMistSoundID.cs index 7babe60a8..abb2ec64b 100644 --- a/Assembly-CSharp/Global/Quad/Mist/QuadMistSoundID.cs +++ b/Assembly-CSharp/Global/Quad/Mist/QuadMistSoundID.cs @@ -9,7 +9,7 @@ public enum QuadMistSoundID MINI_SE_CARD_MOVE, MINI_SE_COIN, MINI_SE_WALL, - MINI_SE_PARFECT, + MINI_SE_PERFECT, MINI_SE_FLASH, MINI_SE_COMB, MINI_SE_BOMB, diff --git a/Assembly-CSharp/Global/SFX/SFX.cs b/Assembly-CSharp/Global/SFX/SFX.cs index ca73d4586..3109e202a 100644 --- a/Assembly-CSharp/Global/SFX/SFX.cs +++ b/Assembly-CSharp/Global/SFX/SFX.cs @@ -2201,7 +2201,7 @@ public static void SoundPlayChant(Int32 dno, Int32 attr, Int32 position) if ((dno & 0xFFFFFF) == 3) { if (SFX.seChantIndex % 3 == 0) - SoundLib.PlaySoundEffect(REFLECT_SOUND_ID, 5f, 0f, 1f); // DEBUG: using 5f as sound volume because the current sound fix has a low volume... must fix that (same as SFXChannel.ExecuteLoop) + SoundLib.PlaySoundEffect(REFLECT_SOUND_ID, 1f, 0f, 1f); } else { @@ -2526,4 +2526,4 @@ public struct PSXMAT public static Int32 effectPointFrame = -1; public static UInt16 lastPlayedExeId = 0; -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/SaveLoadUI.cs b/Assembly-CSharp/Global/SaveLoadUI.cs index 9df32adae..c0e43289e 100644 --- a/Assembly-CSharp/Global/SaveLoadUI.cs +++ b/Assembly-CSharp/Global/SaveLoadUI.cs @@ -358,7 +358,7 @@ private void DisplayFileInfo(Int32 index, SharedDataPreviewSlot file) } fileInfoHUD.LeaderNameLabel.text = text; fileInfoHUD.LeaderLvLabel.text = num.ToString(); - fileInfoHUD.GilLabel.text = file.Gil.ToString() + "[YSUB=1.3][sub]G"; + fileInfoHUD.GilLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", file.Gil.ToString()); fileInfoHUD.LocationNameLabel.text = file.Location; Color color = FF9TextTool.White; Double num3 = (Double)(file.PlayDuration % 360000f); @@ -446,7 +446,6 @@ private void DisplaySuccessfulAccessDialog() private IEnumerator HideSuccessfulAccessDialog() { - yield return new WaitForSeconds(1.5f); this.SuccessfulAccessPanel.SetActive(false); FF9UIDataTool.DisplayTextLocalize(this.HelpTitleLabel, "SaveHelpBlock"); if (this.type == SaveLoadUI.SerializeType.Save) @@ -459,12 +458,7 @@ private IEnumerator HideSuccessfulAccessDialog() private IEnumerator RunProgressBar() { - this.progressBar.value = 0f; - while ((Double)this.progressBar.value < 0.95) - { - yield return new WaitForSeconds(0.01f); - this.progressBar.value += 0.01f; - } + this.progressBar.value = 1f; yield break; } @@ -544,8 +538,6 @@ private void OnFinishedLoadPreview(DataSerializerErrorCode errNo, Int32 slotID, private IEnumerator OnFinishedLoadPreview_delay(DataSerializerErrorCode errNo, Int32 slotID, List data) { - Single remainTime = Mathf.Max(2f - (Time.time - this.timeCounter), 0f); - yield return new WaitForSeconds(remainTime); base.Loading = false; if (errNo == DataSerializerErrorCode.Success) { @@ -608,10 +600,7 @@ private void OnFinishedLoadFile(DataSerializerErrorCode errNo, Int32 slotID, Int private IEnumerator OnFinishedLoadFile_delay(DataSerializerErrorCode errNo, Int32 slotID, Int32 saveID, Boolean isSuccess) { - Single remainTime = Mathf.Max(2f - (Time.time - this.timeCounter), 0f); - yield return new WaitForSeconds(remainTime); this.progressBar.value = 1f; - yield return new WaitForSeconds(0.1f); this.LoadingAccessPanel.SetActive(false); if (isSuccess && errNo == DataSerializerErrorCode.Success) { @@ -658,10 +647,7 @@ private void OnFinishedUploadToCloud(DataSerializerErrorCode errNo, Boolean isSu private IEnumerator OnFinishedSaveFile_delay(DataSerializerErrorCode errNo, Int32 slotID, Int32 saveID, Boolean isSuccess, SharedDataPreviewSlot data) { - Single remainTime = Mathf.Max(2f - (Time.time - this.timeCounter), 0f); - yield return new WaitForSeconds(remainTime); this.progressBar.value = 1f; - yield return new WaitForSeconds(0.1f); base.Loading = false; this.LoadingAccessPanel.SetActive(false); if (isSuccess && errNo == DataSerializerErrorCode.Success) @@ -686,10 +672,7 @@ private IEnumerator OnFinishedSaveFile_delay(DataSerializerErrorCode errNo, Int3 private IEnumerator OnFinishedUploadToCloud_delay(DataSerializerErrorCode errNo, Boolean isSuccess, SharedDataPreviewSlot localData, SharedDataPreviewSlot cloudData) { - Single remainTime = Mathf.Max(2f - (Time.time - this.timeCounter), 0f); - yield return new WaitForSeconds(remainTime); this.progressBar.value = 1f; - yield return new WaitForSeconds(0.1f); base.Loading = false; this.LoadingAccessPanel.SetActive(false); if (isSuccess && errNo == DataSerializerErrorCode.Success) diff --git a/Assembly-CSharp/Global/Shared/Data/SharedDataBytesStorage.cs b/Assembly-CSharp/Global/Shared/Data/SharedDataBytesStorage.cs index 3cd59b848..51096c24c 100644 --- a/Assembly-CSharp/Global/Shared/Data/SharedDataBytesStorage.cs +++ b/Assembly-CSharp/Global/Shared/Data/SharedDataBytesStorage.cs @@ -741,12 +741,18 @@ protected JSONClass Load(Boolean isAutoload, Int32 slotID, Int32 saveID) return (JSONClass)null; } JSONClass tree = this.ParseDataListToJsonTree(list, this.rootSchemaNode); - if (File.Exists(MetaData.GetMemoriaExtraSaveFilePath(isAutoload, slotID, saveID))) - { - JSONNode memoriaNode = JSONNode.LoadFromFile(MetaData.GetMemoriaExtraSaveFilePath(isAutoload, slotID, saveID)); - if (memoriaNode != null) - tree.Add("MemoriaExtraData", memoriaNode); - } + String memoriaSavePath = MetaData.GetMemoriaExtraSaveFilePath(isAutoload, slotID, saveID); + if (!String.IsNullOrEmpty(memoriaSavePath) && File.Exists(memoriaSavePath)) + { + JSONNode memoriaNode = JSONNode.LoadFromFile(memoriaSavePath); + if (memoriaNode != null) + { + memoriaNode.Add("MetaDataSlotID", slotID.ToString()); + memoriaNode.Add("MetaDataSaveID", saveID.ToString()); + memoriaNode.Add("MetaDataFileName", Path.GetFileName(memoriaSavePath)); + tree.Add("MemoriaExtraData", memoriaNode); + } + } return tree; } catch (Exception message3) diff --git a/Assembly-CSharp/Global/ShopUI.cs b/Assembly-CSharp/Global/ShopUI.cs index e350dca76..553ace58e 100644 --- a/Assembly-CSharp/Global/ShopUI.cs +++ b/Assembly-CSharp/Global/ShopUI.cs @@ -70,36 +70,102 @@ public void UpdateUserInterface() { if (!Configuration.Interface.IsEnabled) return; + _shopItemPanel.ScrollButton.Panel.alpha = 0.5f; + _shopWeaponPanel.ScrollButton.Panel.alpha = 0.5f; + _shopSellItemPanel.ScrollButton.Panel.alpha = 0.5f; const Int32 originalLineCount = 8; + Int32 originalColumnCount = 1; const Int32 reducedOriginalLineCount = 5; const Single buttonOriginalHeight = 98f; const Single buyPanelOriginalWidth = 916f; const Single panelOriginalHeight = originalLineCount * buttonOriginalHeight; const Single panelReducedOriginalHeight = reducedOriginalLineCount * buttonOriginalHeight; + + // ----------- SHOP CATALOG ----------- // + Int32 linePerPage = Configuration.Interface.MenuItemRowCount; + Int32 columnPerPage = (Int32)Math.Floor((Single)(originalColumnCount * ((Single)linePerPage / originalLineCount))); + if (originalColumnCount * originalLineCount >= this.itemIdList.Count) // 1 columns suffice + { + linePerPage = originalLineCount; + columnPerPage = originalColumnCount; + } + Int32 lineHeight = (Int32)Math.Round(panelOriginalHeight / linePerPage); Int32 reducedLinePerPage = (Int32)Math.Round(linePerPage * 0.65f); Int32 reducedLineHeight = (Int32)Math.Round(panelReducedOriginalHeight / reducedLinePerPage); Single scaleFactor = lineHeight / buttonOriginalHeight; - _shopItemPanel.SubPanel.ChangeDims(1, linePerPage, buyPanelOriginalWidth, lineHeight); + + + Single alphaColumnTitles = (columnPerPage > originalColumnCount) ? 0f : 1f; + _shopItemPanel.Background.Panel.Name.Label.alpha = alphaColumnTitles; + _shopItemPanel.Background.Panel.Info.Label.alpha = alphaColumnTitles; + _shopWeaponPanel.Background.Panel.Name.Label.alpha = alphaColumnTitles; + _shopWeaponPanel.Background.Panel.Info.Label.alpha = alphaColumnTitles; + + _shopItemPanel.SubPanel.ChangeDims(columnPerPage, linePerPage, buyPanelOriginalWidth / columnPerPage, lineHeight); _shopItemPanel.SubPanel.ButtonPrefab.IconSprite.SetAnchor(target: _shopItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.085f, relRight: 0.155f); + _shopItemPanel.SubPanel.ButtonPrefab.IconSprite.width = _shopItemPanel.SubPanel.ButtonPrefab.IconSprite.height; + _shopItemPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _shopItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.175f, relRight: 0.65f); - _shopItemPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _shopItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.65f, relRight: 0.92f); _shopItemPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _shopItemPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _shopItemPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _shopItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.65f, relRight: 0.92f); + _shopItemPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _shopItemPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _shopItemPanel.SubPanel.RecycleListPopulator.RefreshTableView(); - _shopWeaponPanel.SubPanel.ChangeDims(1, reducedLinePerPage, buyPanelOriginalWidth, reducedLineHeight); + + _shopWeaponPanel.SubPanel.ChangeDims(columnPerPage, reducedLinePerPage, buyPanelOriginalWidth / columnPerPage, reducedLineHeight); _shopWeaponPanel.SubPanel.ButtonPrefab.IconSprite.SetAnchor(target: _shopWeaponPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.085f, relRight: 0.155f); + _shopWeaponPanel.SubPanel.ButtonPrefab.IconSprite.width = _shopWeaponPanel.SubPanel.ButtonPrefab.IconSprite.height; + _shopWeaponPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _shopWeaponPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.175f, relRight: 0.65f); - _shopWeaponPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _shopWeaponPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.65f, relRight: 0.92f); _shopWeaponPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _shopWeaponPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _shopWeaponPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _shopWeaponPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.65f, relRight: 0.92f); + _shopWeaponPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _shopWeaponPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _shopWeaponPanel.SubPanel.RecycleListPopulator.RefreshTableView(); + + // ----------- SHOP SELLING ----------- // + + originalColumnCount = 2; + linePerPage = Configuration.Interface.MenuItemRowCount; + columnPerPage = (Int32)Math.Floor((Single)(originalColumnCount * ((Single)linePerPage / originalLineCount))); + if (originalColumnCount * originalLineCount >= this.sellItemIdList.Count) // 2 columns suffice + { + linePerPage = originalLineCount; + columnPerPage = originalColumnCount; + } + else if (linePerPage >= originalLineCount * 2 && (originalColumnCount + 1) * (originalLineCount + originalLineCount / originalColumnCount) >= this.sellItemIdList.Count) // 3 columns suffice + { + linePerPage = originalLineCount + originalLineCount / originalColumnCount; + columnPerPage = originalColumnCount + 1; + } + + lineHeight = (Int32)Math.Round(panelOriginalHeight / linePerPage); + scaleFactor = lineHeight / buttonOriginalHeight; + + alphaColumnTitles = (columnPerPage > originalColumnCount) ? 0f : 1f; + _shopSellItemPanel.Background.Panel.Name.Label.alpha = alphaColumnTitles; + _shopSellItemPanel.Background.Panel.Info.Label.alpha = alphaColumnTitles; + _shopSellItemPanel.Background.Panel.Name2.Label.alpha = alphaColumnTitles; + _shopSellItemPanel.Background.Panel.Info2.Label.alpha = alphaColumnTitles; + const Single sellPanelOriginalWidth = 1490f; - _shopSellItemPanel.SubPanel.ChangeDims(2, linePerPage, sellPanelOriginalWidth / 2f, lineHeight); + _shopSellItemPanel.SubPanel.ChangeDims(columnPerPage, linePerPage, sellPanelOriginalWidth / columnPerPage, lineHeight); _shopSellItemPanel.SubPanel.ButtonPrefab.IconSprite.SetAnchor(target: _shopSellItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.105f, relRight: 0.191f); + _shopSellItemPanel.SubPanel.ButtonPrefab.IconSprite.width = _shopSellItemPanel.SubPanel.ButtonPrefab.IconSprite.height; + _shopSellItemPanel.SubPanel.ButtonPrefab.NameLabel.SetAnchor(target: _shopSellItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.215f, relRight: 0.795f); - _shopSellItemPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _shopSellItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.8f, relRight: 0.9f); _shopSellItemPanel.SubPanel.ButtonPrefab.NameLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _shopSellItemPanel.SubPanel.ButtonPrefab.NameLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); + + _shopSellItemPanel.SubPanel.ButtonPrefab.NumberLabel.SetAnchor(target: _shopSellItemPanel.SubPanel.ButtonPrefab.Transform, relBottom: 0.184f, relTop: 0.816f, relLeft: 0.8f, relRight: 0.9f); _shopSellItemPanel.SubPanel.ButtonPrefab.NumberLabel.fontSize = (Int32)Math.Round(36f * scaleFactor); + _shopSellItemPanel.SubPanel.ButtonPrefab.NumberLabel.effectDistance = new Vector2((Int32)Math.Round(4f * scaleFactor), (Int32)Math.Round(4f * scaleFactor)); _shopSellItemPanel.SubPanel.RecycleListPopulator.RefreshTableView(); } @@ -594,7 +660,7 @@ private void DisplayInfo(ShopUI.ShopType shopType) if (shopType == ShopUI.ShopType.Item) { RegularItem itemId = this.itemIdList[this.currentItemIndex]; - this.itemFundLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.itemFundLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.itemCountLabel.text = ff9item.FF9Item_GetCount(itemId).ToString(); this.requiredItem1Hud.Self.SetActive(false); this.requiredItem2Hud.Self.SetActive(false); @@ -602,7 +668,7 @@ private void DisplayInfo(ShopUI.ShopType shopType) else if (shopType == ShopUI.ShopType.Weapon) { RegularItem itemId = this.itemIdList[this.currentItemIndex]; - this.weaponFundLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.weaponFundLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.weaponCountLabel.text = ff9item.FF9Item_GetCount(this.itemIdList[this.currentItemIndex]).ToString(); this.weaponEquipLabel.text = ff9item.FF9Item_GetEquipCount(this.itemIdList[this.currentItemIndex]).ToString(); if ((ff9item._FF9Item_Data[itemId].type & ItemType.AnyEquipment) != 0) @@ -621,7 +687,7 @@ private void DisplayInfo(ShopUI.ShopType shopType) else if (shopType == ShopUI.ShopType.Synthesis) { FF9MIX_DATA synth = this.mixItemList[this.currentItemIndex - this.mixStartIndex]; - this.weaponFundLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.weaponFundLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.weaponCountLabel.text = ff9item.FF9Item_GetCount(synth.Result).ToString(); this.weaponEquipLabel.text = ff9item.FF9Item_GetEquipCount(synth.Result).ToString(); if ((ff9item._FF9Item_Data[synth.Result].type & ItemType.AnyEquipment) != 0) @@ -681,9 +747,9 @@ private void DisplayItem() this.itemIdList.Clear(); this.isItemEnableList.Clear(); List list = new List(); - ShopItems assortiment = ff9buy.ShopItems[this.id]; + ShopItems assortiment = ff9buy.ShopItems[this.id]; - for (Int32 i = 0; i < assortiment.Length; i++) + for (Int32 i = 0; i < assortiment.Length; i++) { RegularItem itemId = assortiment[i]; FF9ITEM_DATA item = ff9item._FF9Item_Data[itemId]; @@ -742,9 +808,9 @@ private void DisplayWeapon() List list = new List(); if (this.type == ShopUI.ShopType.Weapon) { - ShopItems assortiment = ff9buy.ShopItems[this.id]; + ShopItems assortiment = ff9buy.ShopItems[this.id]; - for (Int32 i = 0; i < assortiment.Length; i++) + for (Int32 i = 0; i < assortiment.Length; i++) { RegularItem itemId = assortiment[i]; FF9ITEM_DATA item = ff9item._FF9Item_Data[itemId]; @@ -906,7 +972,7 @@ private void DisplayCharacterInfo() } else { - CharacterEquipment equipCopy = player.equip.Clone(); + CharacterEquipment equipCopy = player.equip.Clone(); equipCopy[equipPart] = currentItemId; oldRating = ff9shop.FF9Shop_GetDefence(equipPart, player.equip); newRating = ff9shop.FF9Shop_GetDefence(equipPart, equipCopy); @@ -960,13 +1026,13 @@ private void DisplayConfirmDialog(ShopUI.ShopType shopType) { FF9UIDataTool.DisplayTextLocalize(this.HelpLabel, "BuyQtyHelp"); FF9UIDataTool.DisplayItem(this.itemIdList[this.currentItemIndex], this.confirmItemHud.IconSprite, this.confirmItemHud.NameLabel, true); - this.confirmPriceLabel.text = (this.count * ff9item._FF9Item_Data[this.itemIdList[this.currentItemIndex]].price).ToString() + "[YSUB=1.3][sub]G"; + this.confirmPriceLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", (this.count * ff9item._FF9Item_Data[this.itemIdList[this.currentItemIndex]].price).ToString()); } else { FF9UIDataTool.DisplayTextLocalize(this.HelpLabel, "MixQtyHelp"); FF9UIDataTool.DisplayItem(this.mixItemList[this.currentItemIndex - this.mixStartIndex].Result, this.confirmItemHud.IconSprite, this.confirmItemHud.NameLabel, true); - this.confirmPriceLabel.text = (this.count * this.mixItemList[this.currentItemIndex - this.mixStartIndex].Price).ToString() + "[YSUB=1.3][sub]G"; + this.confirmPriceLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", (this.count * this.mixItemList[this.currentItemIndex - this.mixStartIndex].Price).ToString()); } } else @@ -979,9 +1045,9 @@ private void DisplayConfirmDialog(ShopUI.ShopType shopType) FF9UIDataTool.DisplayItem(itemId, this.confirmItemHud.IconSprite, this.confirmItemHud.NameLabel, true); UInt32 sellingPrice = ff9item._FF9Item_Data[itemId].price >> 1; this.confirmQuantityLabel.text = this.count.ToString(); - this.confirmPriceLabel.text = (this.count * sellingPrice).ToString() + "[YSUB=1.3][sub]G"; + this.confirmPriceLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", (this.count * sellingPrice).ToString()); Boolean isEquipment = (ff9item._FF9Item_Data[itemId].type & ItemType.AnyEquipment) != 0; - this.confirmFundLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.confirmFundLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.confirmCountLabel.text = ff9item.FF9Item_GetCount(itemId).ToString(); if (isEquipment) { @@ -1015,12 +1081,12 @@ private void ClearInfo(ShopUI.ShopType shopType) { if (shopType == ShopUI.ShopType.Item) { - this.itemFundLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.itemFundLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.itemCountLabel.text = "0"; } else if (shopType == ShopUI.ShopType.Weapon) { - this.weaponFundLabel.text = FF9StateSystem.Common.FF9.party.gil.ToString() + "[YSUB=1.3][sub]G"; + this.weaponFundLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", FF9StateSystem.Common.FF9.party.gil.ToString()); this.weaponCountLabel.text = "0"; this.weaponEquipTextLabel.color = FF9TextTool.Gray; this.weaponEquipLabel.color = FF9TextTool.Gray; @@ -1043,17 +1109,17 @@ private void UpdatePartyInfo() this.availableCharaList.Add(player.info.slot_no); } - private void InitializeMixList() - { - foreach (FF9MIX_DATA data in ff9mix.SynthesisData.Values) + private void InitializeMixList() + { + foreach (FF9MIX_DATA data in ff9mix.SynthesisData.Values) if (data.Shops.Contains(this.id) && data.Result != RegularItem.NoItem) mixItemList.Add(data); - foreach (FF9MIX_DATA data in mixItemList) + foreach (FF9MIX_DATA data in mixItemList) this.mixPartyList.Add((ff9item._FF9Item_Data[data.Result].type & ItemType.AnyEquipment) != 0); - } + } - private void StartCountItem() + private void StartCountItem() { RegularItem itemId = this.itemIdList[this.currentItemIndex]; Int32 itemCount = ff9item.FF9Item_GetCount(itemId); @@ -1139,6 +1205,7 @@ private void SetShopType(ShopUI.ShopType shopType) this.DisplaySellItem(); this.shopSellItemScrollList.JumpToIndex(0, false); } + this.UpdateUserInterface(); } private ShopUI.SubMenu GetSubMenuFromGameObject(GameObject go) diff --git a/Assembly-CSharp/Global/Sound/Effect/SoundEffect.cs b/Assembly-CSharp/Global/Sound/Effect/SoundEffect.cs index 412dbb0a2..83af6b673 100644 --- a/Assembly-CSharp/Global/Sound/Effect/SoundEffect.cs +++ b/Assembly-CSharp/Global/Sound/Effect/SoundEffect.cs @@ -22,7 +22,7 @@ public static void Stop(QuadMistSoundID type) { QuadMistSoundID.MINI_SE_CARD_MOVE, 1857 }, { QuadMistSoundID.MINI_SE_COIN, 1858 }, { QuadMistSoundID.MINI_SE_WALL, 1859 }, - { QuadMistSoundID.MINI_SE_PARFECT, 1852 }, + { QuadMistSoundID.MINI_SE_PERFECT, 1852 }, { QuadMistSoundID.MINI_SE_FLASH, 1861 }, { QuadMistSoundID.MINI_SE_COMB, 1862 }, { QuadMistSoundID.MINI_SE_BOMB, 1863 }, diff --git a/Assembly-CSharp/Global/Sound/SoLoud/SdLibAPIWithSoloud.cs b/Assembly-CSharp/Global/Sound/SoLoud/SdLibAPIWithSoloud.cs index ba263969c..b2dafe0de 100644 --- a/Assembly-CSharp/Global/Sound/SoLoud/SdLibAPIWithSoloud.cs +++ b/Assembly-CSharp/Global/Sound/SoLoud/SdLibAPIWithSoloud.cs @@ -33,6 +33,7 @@ public Sound(Int32 BankID) } public Int32 bankID; public Single volume = 1f; + public Int32 pauseStack = 0; } private Dictionary streams = new Dictionary(); @@ -86,14 +87,16 @@ public override void SdSoundSystem_Release() public override Int32 SdSoundSystem_Suspend() { SoundLib.Log("Suspend"); - soloud.setPauseAll(1); + foreach (var sound in sounds) + SdSoundSystem_SoundCtrl_SetPause(sound.Key, 1, 0); return 0; } public override Int32 SdSoundSystem_Resume() { SoundLib.Log("Resume"); - soloud.setPauseAll(0); + foreach (var sound in sounds) + SdSoundSystem_SoundCtrl_SetPause(sound.Key, 0, 0); return 0; } @@ -133,14 +136,16 @@ public override Int32 SdSoundSystem_RemoveData(Int32 bankID) public override Int32 SdSoundSystem_CreateSound(Int32 bankID) { - SoundLib.Log($"CreateSound({bankID})"); + if (!streams.ContainsKey(bankID)) return 0; + SoundLib.Log($"CreateSound({streams[bankID].profile.ResourceID})"); CleanUpSounds(); StreamInfo stream = streams[bankID]; - Int32 soundID = 0; + Int32 soundID; switch (stream.profile.SoundProfileType) { + case SoundProfileType.SoundEffect: case SoundProfileType.Sfx: soundID = (Int32)sfxBus.play(streams[bankID].data, 1, 0, 1); break; @@ -185,22 +190,59 @@ public override Int32 SdSoundSystem_SoundCtrl_GetPlayTime(Int32 soundID) public override Int32 SdSoundSystem_SoundCtrl_Start(Int32 soundID, Int32 offsetTimeMSec) { - SoundLib.Log($"SoundCtrl_Start({soundID}, {offsetTimeMSec})"); if (!sounds.ContainsKey(soundID)) return 0; + SoundLib.Log($"SoundCtrl_Start({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}), {offsetTimeMSec})"); + + Int32 bankID = sounds[soundID].bankID; + Int32 count = 0; + Int32 stopSoundID = 0; + Double maxPos = 0d; + foreach (var sound in sounds) + { + if (sound.Value.bankID == bankID && soloud.getPause((uint)sound.Key) == 0) + { + Double pos = soloud.getStreamTime((uint)sound.Key); + if (pos < 0.01d) + { + // Prevent same sound to play more than once at very close interval (<10ms) + SoundLib.Log($"Sound already playing ({streams[bankID].profile.ResourceID}). Stopping {sound.Key} pos {(Int32)(pos * 1000)}ms"); + soloud.stop((uint)sound.Key); + } + else + { + SoundLib.Log($"Sound already playing ({streams[bankID].profile.ResourceID}). Id {sound.Key} pos {(Int32)(pos * 1000)}ms"); + count++; + if (pos > maxPos) + { + stopSoundID = sound.Key; + maxPos = pos; + } + } + } + } + + if (count >= 2) + { + // Prevent same sound to play more than twice at the same time by stopping the oldest + SoundLib.Log($"Stopping {stopSoundID} pos {(Int32)(maxPos * 1000)}ms"); + soloud.fadeVolume((uint)stopSoundID, 0, 100 / 1000d); + soloud.scheduleStop((uint)stopSoundID, 100 / 1000d); + } if (offsetTimeMSec > 0) { soloud.seek((uint)soundID, offsetTimeMSec / 1000d); } - soloud.setPause((uint)soundID, 0); + if (sounds[soundID].pauseStack == 0) // SdLib doesn't resume paused sounds, we replicate the behavior + soloud.setPause((uint)soundID, 0); return 1; } public override void SdSoundSystem_SoundCtrl_Stop(Int32 soundID, Int32 transTimeMSec) { - SoundLib.Log($"SoundCtrl_Stop({soundID}, {transTimeMSec})"); if (!sounds.ContainsKey(soundID)) return; + SoundLib.Log($"SoundCtrl_Stop({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}), {transTimeMSec})"); if (transTimeMSec < 100) transTimeMSec = 100; // Add a small fade @@ -215,8 +257,15 @@ public override Int32 SdSoundSystem_SoundCtrl_IsExist(Int32 soundID) public override void SdSoundSystem_SoundCtrl_SetPause(Int32 soundID, Int32 pauseOn, Int32 transTimeMSec) { - SoundLib.Log($"SoundCtrl_SetPause({soundID}, {pauseOn}, {transTimeMSec})"); if (!sounds.ContainsKey(soundID)) return; + SoundLib.Log($"SoundCtrl_SetPause({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}), {pauseOn}, {transTimeMSec})"); + + if (pauseOn > 0) + sounds[soundID].pauseStack++; + else if (sounds[soundID].pauseStack > 0) + sounds[soundID].pauseStack--; + + if (pauseOn == 0 && sounds[soundID].pauseStack != 0) return; uint h = (uint)soundID; double t = transTimeMSec / 1000d; @@ -251,10 +300,10 @@ public override Int32 SdSoundSystem_SoundCtrl_IsPaused(Int32 soundID) public override void SdSoundSystem_SoundCtrl_SetVolume(Int32 soundID, Single volume, Int32 transTimeMSec) { - SoundLib.Log($"SoundCtrl_SetVolume({soundID}, {volume}, {transTimeMSec})"); if (!sounds.ContainsKey(soundID)) return; + SoundLib.Log($"SoundCtrl_SetVolume({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}), {volume}, {transTimeMSec})"); - if (volume < 0f || volume > 1f) Log.Message($"[SoLoud] Warning! Unexpected volume value. Volume = {volume} SoundID = {soundID}\n{Environment.StackTrace}"); + if (volume < 0f || volume > 1f) Log.Warning($"[SoLoud] Unexpected volume value. ResourceID = {streams[sounds[soundID].bankID].profile.ResourceID} Volume = {volume}\n{Environment.StackTrace}"); volume = Mathf.Clamp01(volume); sounds[soundID].volume = volume; @@ -277,7 +326,8 @@ public override Single SdSoundSystem_SoundCtrl_GetVolume(Int32 soundID) public override void SdSoundSystem_SoundCtrl_SetPitch(Int32 soundID, Single pitch, Int32 transTimeMSec) { // Soloud doesn't handle pitch (yet) - SoundLib.Log($"SoundCtrl_SetPitch({soundID}, {pitch}, {transTimeMSec})"); + if (!sounds.ContainsKey(soundID)) return; + SoundLib.Log($"SoundCtrl_SetPitch({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}), {pitch}, {transTimeMSec})"); // Play at different speed (changes the pitch) if (transTimeMSec > 0) @@ -292,8 +342,8 @@ public override void SdSoundSystem_SoundCtrl_SetPitch(Int32 soundID, Single pitc public override void SdSoundSystem_SoundCtrl_SetPanning(Int32 soundID, Single panning, Int32 transTimeMSec) { - SoundLib.Log($"SoundCtrl_SetPanning({soundID}, {panning}, {transTimeMSec})"); if (!sounds.ContainsKey(soundID)) return; + SoundLib.Log($"SoundCtrl_SetPanning({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}), {panning}, {transTimeMSec})"); if (transTimeMSec > 0) { @@ -307,8 +357,8 @@ public override void SdSoundSystem_SoundCtrl_SetPanning(Int32 soundID, Single pa public override void SdSoundSystem_SoundCtrl_SetNextLoopRegion(Int32 soundID) { - SoundLib.Log($"SoundCtrl_SetNextLoopRegion({soundID})"); if (!sounds.ContainsKey(soundID)) return; + SoundLib.Log($"SoundCtrl_SetNextLoopRegion({streams[sounds[soundID].bankID].profile.ResourceID}({soundID}))"); StreamInfo stream = streams[sounds[soundID].bankID]; if (stream.akbHeader.LoopEndAlternate > 0) diff --git a/Assembly-CSharp/Global/TextOpCodeModifier.cs b/Assembly-CSharp/Global/TextOpCodeModifier.cs index 9a3ec8f3b..26cfbfd71 100644 --- a/Assembly-CSharp/Global/TextOpCodeModifier.cs +++ b/Assembly-CSharp/Global/TextOpCodeModifier.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Assets.Sources.Scripts.UI.Common; +using UnityEngine; using XInputDotNetPure; public class TextOpCodeModifier @@ -121,20 +122,26 @@ private static String ReplacePotionShopText(String source) return source; } + /// Correcting position of yellow text path in Fossil Roo switches 1,3,4 private static String ReplaceFossilRouteText(String source) { if (FF9TextTool.FieldZoneId == 361) { - Int32 num = 0; - Int32 num2 = 1; - for (Int32 i = num; i <= num2; i++) + Int16 RealScreenSize = Math.Max(FieldMap.PsxScreenWidth, (Int16)(FieldMap.PsxScreenHeightNative * Screen.width / Screen.height)); + + if (source.Contains("[MPOS=224,12]")) // switch 1 { - String text = TextOpCodeModifier.FossilRouteTargetOpCode[i]; - if (source.Contains(text)) - { - source = source.Replace(text, TextOpCodeModifier.FossilRouteReplacedOpCode[i]); - } + source = source.Replace("[MPOS=224,12]", $"[MPOS={(Int16)(RealScreenSize - 90)},16]"); } + if (source.Contains("[MPOS=212,12]")) // switch 3/4 + { + source = source.Replace("[STRT=84,6][NANI][MPOS=212,12][IMME] ", "[STRT=84,6][NANI][MPOS=212,12][IMME] "); + source = source.Replace("[MPOS=212,12]", $"[MPOS={(Int16)(RealScreenSize - 102)},16]"); + } + + // was: + // "[MPOS=224,12]" -> "[MPOS=230,16]", + // "[MPOS=212,12]" -> "[MPOS=218,16]" } return source; } @@ -230,51 +237,51 @@ private static String ReplaceGyshalShopText(String source) } private static String ReplaceOreShopText(String source) - { - if (FF9TextTool.FieldZoneId != 166) - return source; - - String currentLanguage = FF9StateSystem.Settings.CurrentLanguage; - - Int32 num2; - Int32 num3; - switch (currentLanguage) - { - case "German": - num2 = 6; - num3 = 7; - break; - case "Spanish": - num2 = 4; - num3 = 5; - break; - case "French": - num2 = 2; - num3 = 3; - break; - case "Italian": - return source; - case "Japanese": - num2 = 0; - num3 = 1; - break; - default: - return source; - } - - for (Int32 i = num2; i <= num3; i++) - { - String text = TextOpCodeModifier.OreShopTargetOpCode[i]; - if (source.Contains(text)) - { - source = source.Replace(text, TextOpCodeModifier.OreShopReplacedOpCode[i]); - } - } - - return source; - } - - private static String ReplaceEikoCookingText(String source) + { + if (FF9TextTool.FieldZoneId != 166) + return source; + + String currentLanguage = FF9StateSystem.Settings.CurrentLanguage; + + Int32 num2; + Int32 num3; + switch (currentLanguage) + { + case "German": + num2 = 6; + num3 = 7; + break; + case "Spanish": + num2 = 4; + num3 = 5; + break; + case "French": + num2 = 2; + num3 = 3; + break; + case "Italian": + return source; + case "Japanese": + num2 = 0; + num3 = 1; + break; + default: + return source; + } + + for (Int32 i = num2; i <= num3; i++) + { + String text = TextOpCodeModifier.OreShopTargetOpCode[i]; + if (source.Contains(text)) + { + source = source.Replace(text, TextOpCodeModifier.OreShopReplacedOpCode[i]); + } + } + + return source; + } + + private static String ReplaceEikoCookingText(String source) { if (FF9TextTool.FieldZoneId == 358) { @@ -319,24 +326,24 @@ private static String ReplaceEikoCookingText(String source) private static String ReplacePandoniumText(String source) { - if (FF9TextTool.FieldZoneId != 344) - return source; - - String currentLanguage = FF9StateSystem.Settings.CurrentLanguage; - if (currentLanguage != "Japanese") - return source; - - Int32 num2 = 0; - Int32 num3 = 1; - for (Int32 i = num2; i <= num3; i++) - { - String text = TextOpCodeModifier.PandoniumTargetOpCode[i]; - if (source.Contains(text)) - { - source = source.Replace(text, TextOpCodeModifier.PandoniumReplacedOpcode[i]); - } - } - return source; + if (FF9TextTool.FieldZoneId != 344) + return source; + + String currentLanguage = FF9StateSystem.Settings.CurrentLanguage; + if (currentLanguage != "Japanese") + return source; + + Int32 num2 = 0; + Int32 num3 = 1; + for (Int32 i = num2; i <= num3; i++) + { + String text = TextOpCodeModifier.PandoniumTargetOpCode[i]; + if (source.Contains(text)) + { + source = source.Replace(text, TextOpCodeModifier.PandoniumReplacedOpcode[i]); + } + } + return source; } public static String ReplaceChanbaraArrow(String source) @@ -370,18 +377,6 @@ public static String ReplaceChanbaraArrow(String source) "[XTAB=77][YADD=1][DBTN=UP][MOBI=268][XTAB=126][DBTN=TRIANGLE][MOBI=272]\n[XTAB=64][DBTN=LEFT][MOBI=267][FEED=14][DBTN=RIGHT][MOBI=269][FEED=11][DBTN=SQUARE][MOBI=271][FEED=13][DBTN=CIRCLE][MOBI=273]\n[XTAB=77][YSUB=1][DBTN=DOWN][MOBI=270][XTAB=126][DBTN=CROSS][MOBI=274]" }; - public static readonly String[] FossilRouteTargetOpCode = new String[] - { - "[MPOS=224,12]", - "[MPOS=212,12]" - }; - - public static readonly String[] FossilRouteReplacedOpCode = new String[] - { - "[MPOS=230,16]", - "[MPOS=218,16]" - }; - public static readonly String[] AuctionTargetOpCode = new String[] { "[STRT=0,1][MPOS=33,80]", diff --git a/Assembly-CSharp/Global/TitleUI.cs b/Assembly-CSharp/Global/TitleUI.cs index d43d0e780..cae8b91c4 100644 --- a/Assembly-CSharp/Global/TitleUI.cs +++ b/Assembly-CSharp/Global/TitleUI.cs @@ -371,15 +371,8 @@ public override void Show(SceneVoidDelegate afterFinished = null) } // Replace title screen with modded version if it exists - externalPath = AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Sprites/title_bg", true, false); - if (!String.IsNullOrEmpty(externalPath)) - { - Texture2D texture = StreamingResources.LoadTexture2D(externalPath); - sprite2D.sprite2D = Sprite.Create(texture, sprite.rect, sprite.pivot); - sprite2D.sprite2D.name = sprite.name; - } - - externalPath = AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Sprites/title_bg.png", true, false); // also check .png for simplicity + externalPath = AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Sprites/title_bg.png", true, false); + externalPath = !String.IsNullOrEmpty(externalPath) ? externalPath : AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Sprites/title_bg", true, false); if (!String.IsNullOrEmpty(externalPath)) { Texture2D texture = StreamingResources.LoadTexture2D(externalPath); @@ -389,7 +382,10 @@ public override void Show(SceneVoidDelegate afterFinished = null) // Replace title logo with modded version if it exists (advice: replace with transparent and include logo in title_bg.png) UITexture texture2D = this.MenuPanelObject.GetChild(1).GetComponent(); - externalPath = AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Materials/title_logo", true, false); + externalPath = AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Materials/title_logo.png", true, false); + externalPath = !String.IsNullOrEmpty(externalPath) ? externalPath : AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Materials/title_logo", true, false); + externalPath = !String.IsNullOrEmpty(externalPath) ? externalPath : AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Sprites/title_logo.png", true, false); + externalPath = !String.IsNullOrEmpty(externalPath) ? externalPath : AssetManager.SearchAssetOnDisc("EmbeddedAsset/UI/Sprites/title_logo", true, false); if (!String.IsNullOrEmpty(externalPath)) { Texture2D texture = StreamingResources.LoadTexture2D(externalPath); @@ -1460,9 +1456,10 @@ private void PlaySplashScreen() ButtonGroupState.ActiveGroup = MenuGroupButton; if (Configuration.Graphics.SkipIntros > 2) - Configuration.Graphics.SkipIntros = 0; - - this.timer.Start(); + this.timer.Stop(); + else + this.timer.Start(); + if (this.IsJustLaunchApp) { SiliconStudio.Social.Authenticate(true); @@ -2085,25 +2082,22 @@ public void Play(Type kind, SceneVoidDelegate postMenuFadeOut, SceneVoidDelegate this.logoSprite.spriteName = this.logoIndex == 0 ? "logo_sqex" : "logo_sst"; this.honoFading.Fade(1f, 0f, 0.7f, 1.3f, this.honoFading.fadeInCurve, this.preLogoFadeOut); }; - if (Configuration.Graphics.SkipIntros > 1) - this.onLogoFinish = delegate { this.onMovieFinish(); }; - else - this.onLogoFinish = delegate + this.onLogoFinish = delegate + { + this.type = Type.Movie1; + postMenuFadeOut(); + this.logoContainer.gameObject.SetActive(false); + this.honoFading.Fade(1f, 0f, 1f, 0f, this.honoFading.fadeInCurve, delegate { - this.type = Type.Movie1; - postMenuFadeOut(); - this.logoContainer.gameObject.SetActive(false); - this.honoFading.Fade(1f, 0f, 1f, 0f, this.honoFading.fadeInCurve, delegate - { - }); + }); - MBG.Instance.SetFinishCallback(this.onMovieFinish); - MBG.Instance.gameObject.SetActive(true); - MBG.Instance.LoadMovie("FMV000"); - MBG.Instance.SetDepthForTitle(); - MBG.Instance.Play(); - this.stopEnable = true; - }; + MBG.Instance.SetFinishCallback(this.onMovieFinish); + MBG.Instance.gameObject.SetActive(true); + MBG.Instance.LoadMovie("FMV000"); + MBG.Instance.SetDepthForTitle(); + MBG.Instance.Play(); + this.stopEnable = true; + }; this.onMovieFinish = delegate { this.honoFading.Fade(0f, 1f, 1f, 0f, this.honoFading.fadeInCurve, delegate @@ -2111,6 +2105,23 @@ public void Play(Type kind, SceneVoidDelegate postMenuFadeOut, SceneVoidDelegate this.preMenuFadeIn(); }); }; + if (Configuration.Graphics.SkipIntros == 1 && kind == Type.Logo) + { + postMenuFadeOut(); + this.logoIndex = 2; + this.honoFading.Fade(0f, 1f, this.skipFadeInTime, 0f, this.honoFading.fadeOutCurve, this.onLogoFinish); + return; + } + else if (Configuration.Graphics.SkipIntros > 0 && (kind == Type.SplashScreen || kind == Type.Logo)) + { + postMenuFadeOut(); + postIdleScreenFadeOut(); + this.stopEnable = false; + this.honoFading.Fade(1f, 0f, this.skipFadeInTime, 0f, this.honoFading.fadeInCurve, delegate { + postMenuFadeIn(); + }); + return; + } switch (kind) { case Type.SplashScreen: @@ -2276,4 +2287,4 @@ private enum MenuLanguage EnglishUK, None, } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/UI/UIAtlas.cs b/Assembly-CSharp/Global/UI/UIAtlas.cs index e935c63ff..9ad2288ba 100644 --- a/Assembly-CSharp/Global/UI/UIAtlas.cs +++ b/Assembly-CSharp/Global/UI/UIAtlas.cs @@ -11,8 +11,8 @@ [AddComponentMenu("NGUI/UI/Atlas")] public class UIAtlas : MonoBehaviour { - public UIAtlas() - { + public UIAtlas() + { GameLoopManager.Start += OverrideAtlas; } @@ -71,8 +71,16 @@ private void OverrideAtlas() String[] modPath = Configuration.Mod.FolderNames; String atlasFilePath = GraphicResources.AtlasList[name]; foreach (AssetManager.AssetFolder folder in AssetManager.FolderLowToHigh) + { if (folder.TryFindAssetInModOnDisc(atlasFilePath, out String fullPath, AssetManagerUtil.GetResourcesAssetsPath(true) + "/")) + { ReadFromDisc(fullPath); + } + else if (folder.TryFindAssetInModOnDisc(atlasFilePath + ".png", out String fullPathpng, AssetManagerUtil.GetResourcesAssetsPath(true) + "/")) + { + ReadFromDisc(fullPathpng); + } + } } } @@ -88,13 +96,16 @@ public Boolean ReadFromDisc(String inputPath) if (newFullAtlas == null) newFullAtlas = new Texture2D(1, 1, AssetManager.DefaultTextureFormat, false); - ReadTPSheetFromDisc(newFullAtlas, inputPath + ".tpsheet"); + if (inputPath.Contains(".png") && File.Exists(inputPath.Remove(inputPath.Length - 4) + ".tpsheet")) + inputPath = inputPath.Remove(inputPath.Length - 4); - return true; + ReadTPSheetFromDisc(newFullAtlas, inputPath + ".tpsheet"); + + return true; } catch (Exception ex) { - Log.Error(ex, "[UIAtlas] Failed to override atlas."); + Log.Error(ex, "[UIAtlas] Failed to override atlas: " + inputPath); return false; } } @@ -156,15 +167,15 @@ private void ReadTPSheetFromDisc(Texture2D atlasTexture, String tpsheetPath) } } - private void SetTexture(Texture newTexture) - { - if (this.mReplacement != null) - this.mReplacement.SetTexture(newTexture); - else if (this.material != null) - this.material.mainTexture = newTexture; - } + private void SetTexture(Texture newTexture) + { + if (this.mReplacement != null) + this.mReplacement.SetTexture(newTexture); + else if (this.material != null) + this.material.mainTexture = newTexture; + } - public Material spriteMaterial + public Material spriteMaterial { get { diff --git a/Assembly-CSharp/Global/UI/UIKey/UIKeyTrigger.cs b/Assembly-CSharp/Global/UI/UIKey/UIKeyTrigger.cs index 78f508bbd..93fe012de 100644 --- a/Assembly-CSharp/Global/UI/UIKey/UIKeyTrigger.cs +++ b/Assembly-CSharp/Global/UI/UIKey/UIKeyTrigger.cs @@ -1,14 +1,14 @@ using Assets.Scripts.Common; -using System; -using System.Linq; -using System.Collections.Generic; using Memoria; using Memoria.Data; using Memoria.Prime; using Memoria.Prime.Text; using Memoria.Scenes; -using Memoria.Test; using Memoria.Speedrun; +using Memoria.Test; +using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; #pragma warning disable 169 @@ -25,6 +25,9 @@ public class UIKeyTrigger : MonoBehaviour private Single fastEventCounter; private Boolean triggleEventDialog; private Boolean quitConfirm; + private Single autoConfirmDownTime = 0; + private Boolean TurboKey; + public static Boolean preventTurboKey; public static Boolean IsShiftKeyPressed { get; private set; } @@ -128,10 +131,10 @@ private void Update() if (!UnityXInput.Input.anyKey && !isLockLazyInput) ResetKeyCode(); AccelerateKeyNavigation(); - if (handleMenuControlKeyPressCustomInput()) + if (HandleMenuControlKeyPressCustomInput()) return; HandleBoosterButton(); - handleDialogControlKeyPressCustomInput(); + HandleDialogControlKeyPressCustomInput(); } private void AccelerateKeyNavigation() @@ -263,13 +266,13 @@ public void HandleBoosterButton(BoosterType triggerType = BoosterType.None) PersistenSingleton.Instance.Booster.ShowWaringDialog(BoosterType.GilMax); } - if (Configuration.Mod.TranceSeek && UnityXInput.Input.GetKeyDown(KeyCode.F8) && PersistenSingleton.Instance.IsPause) // TRANCE SEEK - Reset game, back to main menu + if (Configuration.Mod.TranceSeek && UnityXInput.Input.GetKeyDown(KeyCode.F8) && PersistenSingleton.Instance.IsPause) // TRANCE SEEK - Hard reset, back to main menu { + preventTurboKey = false; PersistenSingleton.Instance.Dialogs.PauseAllDialog(true); PersistenSingleton.Instance.HideAllHUD(); ButtonGroupState.DisableAllGroup(true); UIManager.Battle.FF9BMenu_EnableMenu(false); - Configuration.Graphics.SkipIntros = 3; PersistenSingleton.Instance.PauseScene.Hide(null); EventHUD.Cleanup(); EventInput.ClearPadMask(); @@ -278,6 +281,13 @@ public void HandleBoosterButton(BoosterType triggerType = BoosterType.None) SceneDirector.Replace("Title", SceneTransition.FadeOutToBlack_FadeIn, true); return; } + if (UnityXInput.Input.GetKeyDown(KeyCode.F9) && Configuration.Control.TurboDialog) + { + if (TurboKey) + TurboKey = false; + else + TurboKey = true; + } } private void OnApplicationQuit() @@ -483,11 +493,12 @@ private static void BroadcastAll(String method) } } - private Boolean handleMenuControlKeyPressCustomInput(GameObject activeButton = null) + private Boolean HandleMenuControlKeyPressCustomInput(GameObject activeButton = null) { IsShiftKeyPressed = ShiftKey; UIScene sceneFromState = PersistenSingleton.Instance.GetSceneFromState(PersistenSingleton.Instance.State); + Boolean battelAutoConfirm = Configuration.Control.BattleAutoConfirm && (UIManager.Instance.State == UIManager.UIState.BattleHUD || UIManager.Instance.State == UIManager.UIState.BattleResult); if (ButtonGroupState.ActiveButton && ButtonGroupState.ActiveButton != PersistenSingleton.Instance.gameObject) activeButton = ButtonGroupState.ActiveButton; else if (activeButton == null) @@ -508,10 +519,27 @@ private Boolean handleMenuControlKeyPressCustomInput(GameObject activeButton = n } if (PersistenSingleton.Instance.IsInputDown(Control.Confirm) || keyCommand == Control.Confirm) { + if (battelAutoConfirm) + autoConfirmDownTime = Time.time; keyCommand = Control.None; sceneFromState.OnKeyConfirm(activeButton); return true; } + if (battelAutoConfirm && PersistenSingleton.Instance.IsInput(Control.Confirm)) + { + // If confirm is held more than 500ms it will auto confirm at an interval of 100ms + const Single delay = 0.5f; + if (autoConfirmDownTime > 0 && Time.time - autoConfirmDownTime > delay) + { + autoConfirmDownTime = Time.time - delay + 0.1f; + sceneFromState.OnKeyConfirm(activeButton); + return true; + } + } + if (battelAutoConfirm && PersistenSingleton.Instance.IsInputUp(Control.Confirm)) + { + autoConfirmDownTime = 0; + } if (PersistenSingleton.Instance.IsInputDown(Control.Pause) || keyCommand == Control.Pause) { keyCommand = Control.None; @@ -554,6 +582,11 @@ private Boolean handleMenuControlKeyPressCustomInput(GameObject activeButton = n } if (PersistenSingleton.Instance.IsInputDown(Control.LeftTrigger) || keyCommand == Control.LeftTrigger) { + if (UIManager.Battle.CanForceNextTurn) + { + BattleHUD.ForceNextTurn = true; + FF9Sfx.FF9SFX_Play(103); + } keyCommand = Control.None; sceneFromState.OnKeyLeftTrigger(activeButton); return true; @@ -630,7 +663,7 @@ private Boolean handleMenuControlKeyPressCustomInput(GameObject activeButton = n return false; } - private void handleDialogControlKeyPressCustomInput(GameObject activeButton = null) + private void HandleDialogControlKeyPressCustomInput(GameObject activeButton = null) { if (activeButton == null) activeButton = UICamera.selectedObject; @@ -639,10 +672,11 @@ private void handleDialogControlKeyPressCustomInput(GameObject activeButton = nu foreach (String key in Configuration.Control.DialogProgressButtons) if (key.TryEnumParse(out Control ctrl)) dialogConfirmKeys.Add(ctrl); - if (dialogConfirmKeys.Any(ctrl => PersistenSingleton.Instance.IsInputDown(ctrl) || keyCommand == ctrl)) + if (dialogConfirmKeys.Any(ctrl => PersistenSingleton.Instance.IsInputDown(ctrl) || keyCommand == ctrl) || ShouldTurboDialog(dialogConfirmKeys)) { keyCommand = Control.None; PersistenSingleton.Instance.Dialogs.OnKeyConfirm(activeButton); + preventTurboKey = false; if (PersistenSingleton.Instance.Dialogs.IsDialogNeedControl() || !PersistenSingleton.Instance.Dialogs.CompletlyVisible) return; @@ -653,6 +687,7 @@ private void handleDialogControlKeyPressCustomInput(GameObject activeButton = nu { keyCommand = Control.None; PersistenSingleton.Instance.Dialogs.OnKeyCancel(activeButton); + preventTurboKey = false; } else if (PersistenSingleton.Instance.IsInputDown(Control.Pause) || keyCommand == Control.Pause) { @@ -777,6 +812,24 @@ public Boolean ContainsAndroidQuitKey() return false; } + private Boolean ShouldTurboDialog(List confirmKeys) + { + if (!Configuration.Control.TurboDialog || preventTurboKey) + return false; + + if(TurboKey || ((HonoInputManager.Instance.IsInput(Control.RightBumper) || ShiftKey) && confirmKeys.Any(HonoInputManager.Instance.IsInput))) + { + if (UIManager.Instance.Dialogs.IsDialogNeedControl()) + return true; + + if (VoicePlayer.scriptRequestedButtonPress && !BubbleUI.Instance.IsActive && DialogManager.Instance.ActiveDialogList.Any(dial => dial.gameObject.activeInHierarchy && dial.CurrentState == Dialog.State.CompleteAnimation)) + { + EventInput.ReceiveInput(EventInput.Pcircle | EventInput.Lcircle); + } + } + return false; + } + private void Start() { UICamera.onNavigate = (UICamera.KeyCodeDelegate)Delegate.Combine(UICamera.onNavigate, (UICamera.KeyCodeDelegate)OnKeyNavigate); @@ -818,4 +871,4 @@ public static void OpenPartyMenu() EventService.OpenPartyMenu(party); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/UI/UIScene.cs b/Assembly-CSharp/Global/UI/UIScene.cs index 3627c5822..65ad97093 100644 --- a/Assembly-CSharp/Global/UI/UIScene.cs +++ b/Assembly-CSharp/Global/UI/UIScene.cs @@ -1,8 +1,8 @@ -using System; -using Assets.Scripts.Common; +using Assets.Scripts.Common; using Assets.Sources.Scripts.UI.Common; -using UnityEngine; using Memoria; +using System; +using UnityEngine; public class UIScene : MonoBehaviour { @@ -64,7 +64,8 @@ public virtual void Show(UIScene.SceneVoidDelegate action = null) } if (this.fading != (UnityEngine.Object)null && this.isNeedFade) { - this.fading.fadeOutDuration = ((!FF9StateSystem.Settings.IsFastForward) ? 0.3f : 0.15f); + this.fading.fadeOutDuration = ((!FF9StateSystem.Settings.IsFastForward) ? Configuration.Interface.FadeDuration : Configuration.Interface.FadeDuration / FF9StateSystem.Settings.FastForwardFactor); ; + this.fading.FadeOut(this.AfterSceneShown); this.Loading = true; } @@ -95,7 +96,8 @@ public virtual void Hide(UIScene.SceneVoidDelegate action = null) } if (this.fading != (UnityEngine.Object)null && this.isNeedFade) { - this.fading.fadeInDuration = ((!FF9StateSystem.Settings.IsFastForward) ? 0.3f : 0.15f); + this.fading.fadeInDuration = ((!FF9StateSystem.Settings.IsFastForward) ? Configuration.Interface.FadeDuration : Configuration.Interface.FadeDuration / FF9StateSystem.Settings.FastForwardFactor); + this.fading.FadeIn(this.AfterSceneHidden); this.Loading = true; } @@ -265,31 +267,31 @@ public virtual void onPress(GameObject go, Boolean isDown) Int32 currentTouchID = UICamera.currentTouchID; switch (currentTouchID + 2) { - case 1: - this.OnKeyConfirm(go); - break; - case 2: - case 3: - if (ButtonGroupState.ContainButtonInSecondaryGroup(go)) - { + case 1: this.OnKeyConfirm(go); - } - else - { - ButtonGroupState component = go.GetComponent(); - if (component) + break; + case 2: + case 3: + if (ButtonGroupState.ContainButtonInSecondaryGroup(go)) { - if (component.ProcessTouch()) - { - this.OnKeyConfirm(go); - } + this.OnKeyConfirm(go); } else { - this.OnKeyConfirm(go); + ButtonGroupState component = go.GetComponent(); + if (component) + { + if (component.ProcessTouch()) + { + this.OnKeyConfirm(go); + } + } + else + { + this.OnKeyConfirm(go); + } } - } - break; + break; } } } diff --git a/Assembly-CSharp/Global/WM/WMActor/WMActor.cs b/Assembly-CSharp/Global/WM/WMActor/WMActor.cs index 8da600a92..2d4f99bf0 100644 --- a/Assembly-CSharp/Global/WM/WMActor/WMActor.cs +++ b/Assembly-CSharp/Global/WM/WMActor/WMActor.cs @@ -178,33 +178,26 @@ public Vector3 RealLastPosition } } - public void UpdateAnimationViaScript() + public void UpdateAnimationViaScript() { - this._smoothUpdatePlayingAnim = false; GameObject go = this.originalActor.go; - if (go == null) - return; + if (go == null) + return; + Animation anim = go.GetComponent(); String animName = FF9DBAll.AnimationDB.GetValue(this.originalActor.anim); - if (!go.GetComponent().IsPlaying(animName)) + if (!anim.IsPlaying(animName)) { - if (go.GetComponent().GetClip(animName) == null) + if (anim.GetClip(animName) == null) return; - go.GetComponent().Play(animName); - } - else - { - this._smoothUpdatePlayingAnim = true; + anim.Play(animName); } - AnimationState clipState = go.GetComponent()[animName]; - Single time = (Single)this.originalActor.animFrame / (Single)this.originalActor.frameN * clipState.length; - clipState.speed = 0f; - this._smoothUpdateAnimTimePrevious = clipState.time; - this._smoothUpdateAnimTimeActual = time; - clipState.time = time; - go.GetComponent().Sample(); - } + AnimationState animState = anim[animName]; + animState.speed = 0f; + animState.time = (Single)this.originalActor.animFrame / this.originalActor.frameN * animState.length; + anim.Sample(); + } - public void LateUpdate() + public void LateUpdate() { } diff --git a/Assembly-CSharp/Global/WM/WMShadow.cs b/Assembly-CSharp/Global/WM/WMShadow.cs index fe7b9a8ed..93bfca261 100644 --- a/Assembly-CSharp/Global/WM/WMShadow.cs +++ b/Assembly-CSharp/Global/WM/WMShadow.cs @@ -1,9 +1,8 @@ -using System; -using UnityEngine; +using UnityEngine; -public class WMShadow : MonoBehaviour +public partial class WMShadow : MonoBehaviour { - public PosObj PosObj; + public PosObj PosObj; - public Material Material; + public Material Material; } diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Const.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Const.cs index 55484544d..fd45fca42 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Const.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Const.cs @@ -200,51 +200,51 @@ private static Boolean TryFormatRussianMagicSwordAbility(String abilityName, out return false; } - private static BattleCommandId GetCommandFromCommandIndex(ref CommandMenu commandIndex, Int32 playerIndex) + private static BattleCommandId GetCommandFromCommandIndex(ref BattleCommandMenu commandIndex, Int32 playerIndex) { BattleUnit player = FF9StateSystem.Battle.FF9Battle.GetUnit(playerIndex); CharacterPresetId presetId = FF9StateSystem.Common.FF9.party.GetCharacter(player.Position).PresetId; BattleCommandId result = BattleCommandId.None; switch (commandIndex) { - case CommandMenu.Attack: + case BattleCommandMenu.Attack: result = BattleCommandId.Attack; break; - case CommandMenu.Defend: + case BattleCommandMenu.Defend: result = BattleCommandId.Defend; - if (Configuration.Mod.TranceSeek) + if (Configuration.Mod.TranceSeek) // [DV] - Change Steiner/Amarant's Defend Command { - if (presetId == CharacterPresetId.Steiner) + if (presetId == CharacterPresetId.Steiner) // Sentinel result = (BattleCommandId)10015; - else if (presetId == CharacterPresetId.Amarant) + else if (presetId == CharacterPresetId.Amarant) // Dual result = (BattleCommandId)10016; } break; - case CommandMenu.Ability1: + case BattleCommandMenu.Ability1: { CharacterCommandSet commandSet = CharacterCommands.CommandSets[presetId]; Boolean underTrance = player.IsUnderAnyStatus(BattleStatus.Trance); result = commandSet.Get(underTrance, 0); break; } - case CommandMenu.Ability2: + case BattleCommandMenu.Ability2: { CharacterCommandSet commandSet = CharacterCommands.CommandSets[presetId]; Boolean underTrance = player.IsUnderAnyStatus(BattleStatus.Trance); result = commandSet.Get(underTrance, 1); break; } - case CommandMenu.Item: + case BattleCommandMenu.Item: result = BattleCommandId.Item; break; - case CommandMenu.Change: + case BattleCommandMenu.Change: result = BattleCommandId.Change; break; } if (player.Data.is_monster_transform && result == player.Data.monster_transform.base_command) { result = player.Data.monster_transform.new_command; - commandIndex = CommandMenu.Ability1; + commandIndex = BattleCommandMenu.Ability1; } return result; } @@ -348,4 +348,4 @@ private static Dictionary LoadBattleCommandTitles() return new Dictionary(); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Nested.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Nested.cs index 410a4281b..a0b06f943 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Nested.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Nested.cs @@ -25,17 +25,6 @@ private class BattleAbilityListData : ListDataTypeBase public Int32 Id; } - private enum CommandMenu - { - Attack, - Defend, - Ability1, - Ability2, - Item, - Change, - AccessMenu = 7, - } - private enum CursorGroup { Individual, @@ -126,6 +115,7 @@ public Boolean Changed(MagicSwordCondition other) private class CommandDetail { + public BattleCommandMenu Menu; public BattleCommandId CommandId; public Int32 SubId; public UInt16 TargetId; @@ -168,7 +158,7 @@ private class Message private class PlayerMemo { public PlayerMemo(PLAYER p, Boolean updateRow) - { + { original = p; if (p == null) return; @@ -198,13 +188,13 @@ public PlayerMemo(PLAYER p, Boolean updateRow) } public PLAYER original; - public POINTS max; - public ELEMENT elem; - public ItemDefence defence; - public HashSet saExtended; + public POINTS max; + public ELEMENT elem; + public ItemDefence defence; + public HashSet saExtended; public CharacterSerialNumber serialNo; public Byte row; public Byte battleRow; public BattleStatus battlePermanentStatus; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Public.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Public.cs index ec41465b1..ea6f06126 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Public.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Public.cs @@ -1,13 +1,13 @@ using Assets.Sources.Scripts.UI.Common; -using System; -using System.Collections.Generic; -using System.Linq; using FF9; using Memoria; +using Memoria.Assets; using Memoria.Data; using Memoria.Prime; using Memoria.Scenes; -using Memoria.Assets; +using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; using Object = System.Object; @@ -19,6 +19,10 @@ public partial class BattleHUD : UIScene public Boolean BtlWorkPeep => _currentPeepingMessageCount > 0; public GameObject PlayerTargetPanel => TargetPanel.GetChild(0); public GameObject EnemyTargetPanel => TargetPanel.GetChild(1); + public Boolean IsDoubleCast => DoubleCastSet.Contains(_currentCommandId) || MixCommandSet.Contains(_currentCommandId); + public Boolean IsMixCast => MixCommandSet.Contains(_currentCommandId); + public Boolean CanForceNextTurn => Configuration.Battle.Speed == 2 && UIManager.Battle.FF9BMenu_IsEnable() && !ForceNextTurn + && ReadyQueue.Count > 0 && FF9StateSystem.Battle.FF9Battle.cur_cmd == null && btl_cmd.GetFirstCommandReadyToDequeue(FF9StateSystem.Battle.FF9Battle) == null; public List ReadyQueue { get; } public List InputFinishList { get; } public Int32 CurrentPlayerIndex { get; private set; } @@ -26,7 +30,9 @@ public partial class BattleHUD : UIScene BattleCommandId.DoubleBlackMagic, BattleCommandId.DoubleWhiteMagic }; - public Boolean IsDoubleCast => DoubleCastSet.Contains(_currentCommandId); + public static HashSet MixCommandSet = new HashSet(); + public static Boolean ForceNextTurn = false; + public static Int32 switchBtlId = -1; public BattleHUD() { @@ -48,7 +54,7 @@ public BattleHUD() InputFinishList = new List(); _unconsciousStateList = new List(); _firstCommand = new CommandDetail(); - _commandCursorMemorize = new Dictionary(); + _commandCursorMemorize = new Dictionary(); _abilityCursorMemorize = new Dictionary(); _matchBattleIdPlayerList = new List(); _matchBattleIdEnemyList = new List(); @@ -57,7 +63,7 @@ public BattleHUD() _oneTime = true; } - public void SetBattleFollowMessage(BattleMesages pMes, params Object[] args) + public void SetBattleFollowMessage(BattleMesages pMes, Object arg = null, CMD_DATA msgCmd = null) { Int32 pMesNo = (Int32)pMes; String fmtMessage = FF9TextTool.BattleFollowText(pMesNo + 7); @@ -67,15 +73,14 @@ public void SetBattleFollowMessage(BattleMesages pMes, params Object[] args) Byte priority = (Byte)Char.GetNumericValue(fmtMessage[0]); String parsedMessage = fmtMessage.Substring(1); - if (args.Length > 0) + if (arg != null) { - String str3 = args[0].ToString(); - Int32 result; - parsedMessage = !Int32.TryParse(str3, out result) ? parsedMessage.Replace("%", str3) : parsedMessage.Replace("&", str3); + String argStr = arg.ToString(); + parsedMessage = !Int32.TryParse(argStr, out _) ? parsedMessage.Replace("%", argStr) : parsedMessage.Replace("&", argStr); } VoicePlayer.PlayBattleVoice(pMesNo + 7, fmtMessage, true); - SetBattleMessage(parsedMessage, priority); + SetBattleMessage(parsedMessage, priority, msgCmd); } public void SetBattleFollowMessage(Byte priority, String formatMessage, params Object[] args) @@ -108,6 +113,8 @@ public String GetBattleCommandTitle(CMD_DATA pCmd) return aaData.Name; return String.Empty; } + if (MixCommandSet.Contains(pCmd.cmd_no)) + return FF9TextTool.ItemName(ff9mixitem.MixItemsData[pCmd.sub_no].Result); switch (pCmd.cmd_no) { case BattleCommandId.Item: @@ -166,9 +173,10 @@ public void SetBattleLibra(BattleUnit pBtl, LibraInformation infos = LibraInform { if (Configuration.Interface.ScanDisplay) { + Single additionalWidth = 0.0f; String libraMessage = $"[{NGUIText.Center}]"; if ((infos & LibraInformation.Name) != 0) - libraMessage += pBtl.Name; + libraMessage += Singleton.Instance.PhraseLabel.PhrasePreOpcodeSymbol(pBtl.Name, ref additionalWidth); if ((infos & LibraInformation.Level) != 0) libraMessage += FF9TextTool.BattleLibraText(10) + pBtl.Level.ToString(); if ((infos & LibraInformation.NameLevel) != 0) @@ -252,7 +260,7 @@ public void SetBattleLibra(BattleUnit pBtl, LibraInformation infos = LibraInform _currentButtonGroup = !_hidingHud ? ButtonGroupState.ActiveGroup : _currentButtonGroup; FF9BMenu_EnableMenu(false); TutorialUI tutorialUI = PersistenSingleton.Instance.TutorialScene; - tutorialUI.libraTitle = pBtl.Name; + tutorialUI.libraTitle = Singleton.Instance.PhraseLabel.PhrasePreOpcodeSymbol(pBtl.Name, ref additionalWidth); tutorialUI.libraMessage = libraMessage; tutorialUI.libraPhoto = photo; tutorialUI.DisplayMode = TutorialUI.Mode.Libra; @@ -317,7 +325,7 @@ public void SetBattleTitle(CMD_DATA cmd, String str, Byte strPriority) DisplayBattleMessage(asMessage); } - public void SetBattleMessage(String str, Byte strPriority) + public void SetBattleMessage(String str, Byte strPriority, CMD_DATA cmd = null) { Message asMessage = new Message() { @@ -325,7 +333,7 @@ public void SetBattleMessage(String str, Byte strPriority) priority = strPriority, counter = 0f, isRect = false, - titleCmd = null + titleCmd = cmd }; _messageQueue[str] = asMessage; @@ -660,12 +668,16 @@ public Boolean FF9BMenu_IsEnableAtb() // Stops the ATB if any of these are true Boolean isMenuing = _commandPanel.IsActive || _targetPanel.IsActive || _itemPanel.IsActive || _abilityPanel.IsActive; - Boolean isEnemyActing = FF9StateSystem.Battle.FF9Battle.cur_cmd != null && FF9StateSystem.Battle.FF9Battle.cur_cmd.regist?.bi.player == 0; + //Boolean isEnemyActing = FF9StateSystem.Battle.FF9Battle.cur_cmd != null && FF9StateSystem.Battle.FF9Battle.cur_cmd.regist?.bi.player == 0; Boolean hasQueue = btl_cmd.GetFirstCommandReadyToDequeue(FF9StateSystem.Battle.FF9Battle) != null; - return !(isMenuing || hasQueue || isEnemyActing); + + if (ForceNextTurn && !hasQueue /*&& !isEnemyActing*/) + return true; + + return !(isMenuing || hasQueue /*|| isEnemyActing*/); } - internal Boolean IsNativeEnableAtb() + public Boolean IsNativeEnableAtb() { if (!_commandEnable) return false; @@ -773,7 +785,7 @@ public void SetIdle() BackButton.SetActive(false); _currentSilenceStatus = false; _currentMpValue = -1; - _currentCommandIndex = CommandMenu.Attack; + _currentCommandIndex = BattleCommandMenu.Attack; _currentSubMenuIndex = -1; CurrentPlayerIndex = -1; //currentTranceTrigger = false; @@ -806,7 +818,7 @@ public void ClearCursorMemorize(Int32 playerIndex, BattleCommandId commandId) } public Boolean IsAbilityAvailable(BattleUnit unit, Int32 abilId) - { + { if (!unit.IsPlayer) return true; return GetAbilityState(abilId, unit.GetIndex()) == AbilityStatus.Enable; diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Scene.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Scene.cs index d59e2e852..e4144c27e 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Scene.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Scene.cs @@ -1,11 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; +using Assets.Sources.Scripts.UI.Common; using FF9; using Memoria; using Memoria.Data; using Memoria.Database; using Memoria.Scenes; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; using UnityEngine; public partial class BattleHUD : UIScene @@ -58,7 +59,7 @@ public override void Hide(SceneVoidDelegate afterFinished = null) } public void UpdateSlidingButtonState() - { + { if (!Configuration.Interface.PSXBattleMenu || ButtonGroupState.ActiveGroup != CommandGroupButton) return; Boolean leftPressed = (ETb.sKey0 & (EventInput.Lleft | EventInput.Pleft)) != 0; @@ -75,15 +76,15 @@ public void UpdateSlidingButtonState() { Single rowCount = _commandPanel.AccessMenu == null ? 4f : 5f; Single row; - if (_currentCommandIndex == CommandMenu.Attack) + if (_currentCommandIndex == BattleCommandMenu.Attack) row = 0f; - else if (_currentCommandIndex == CommandMenu.Ability1) + else if (_currentCommandIndex == BattleCommandMenu.Ability1) row = 1f; - else if (_currentCommandIndex == CommandMenu.Ability2) + else if (_currentCommandIndex == BattleCommandMenu.Ability2) row = 2f; - else if (_currentCommandIndex == CommandMenu.Item) + else if (_currentCommandIndex == BattleCommandMenu.Item) row = 3f; - else if (_currentCommandIndex == CommandMenu.AccessMenu) + else if (_currentCommandIndex == BattleCommandMenu.AccessMenu) row = 4f; else return; @@ -93,11 +94,11 @@ public void UpdateSlidingButtonState() _buttonSliding.IsActive = true; _commandPanel.GetCommandButton(_buttonSlideInitial).SetActive(false); ButtonGroupState.ActiveButton = _buttonSliding; - _currentCommandIndex = (CommandMenu)_buttonSliding.Transform.GetSiblingIndex(); + _currentCommandIndex = (BattleCommandMenu)_buttonSliding.Transform.GetSiblingIndex(); } } if (_buttonSliding != null) - { + { if (_buttonSliding == _commandPanel.Change && leftPressed) _buttonSlideFactor += 0.3f; else if (_buttonSliding == _commandPanel.Defend && rightPressed) @@ -147,8 +148,8 @@ public override Boolean OnKeyConfirm(GameObject go) if (ButtonGroupState.ActiveGroup == CommandGroupButton) { FF9Sfx.FF9SFX_Play(103); - _currentCommandIndex = (CommandMenu)go.transform.GetSiblingIndex(); - CommandMenu menuType = _currentCommandIndex; + _currentCommandIndex = (BattleCommandMenu)go.transform.GetSiblingIndex(); + BattleCommandMenu menuType = _currentCommandIndex; _currentCommandId = GetCommandFromCommandIndex(ref menuType, CurrentPlayerIndex); ResetSlidingButton(); TryMemorizeCommand(); @@ -158,17 +159,17 @@ public override Boolean OnKeyConfirm(GameObject go) switch (menuType) { - case CommandMenu.Attack: + case BattleCommandMenu.Attack: SetCommandVisibility(false, false); SetTargetVisibility(true); break; - case CommandMenu.Defend: + case BattleCommandMenu.Defend: _targetCursor = 0; SendCommand(ProcessCommand(CurrentPlayerIndex, CursorGroup.Individual)); SetIdle(); break; - case CommandMenu.Ability1: - case CommandMenu.Ability2: + case BattleCommandMenu.Ability1: + case BattleCommandMenu.Ability2: CharacterCommand ff9Command = CharacterCommands.Commands[_currentCommandId]; if (ff9Command.Type == CharacterCommandType.Normal) { @@ -191,12 +192,12 @@ public override Boolean OnKeyConfirm(GameObject go) SetItemPanelVisibility(true, false); } break; - case CommandMenu.Item: + case BattleCommandMenu.Item: DisplayItem(false); SetCommandVisibility(false, false); SetItemPanelVisibility(true, false); break; - case CommandMenu.Change: + case BattleCommandMenu.Change: _targetCursor = 0; if (_isManualTrance) { @@ -211,7 +212,7 @@ public override Boolean OnKeyConfirm(GameObject go) SetIdle(); } break; - case CommandMenu.AccessMenu: + case BattleCommandMenu.AccessMenu: OpenMainMenu(Configuration.Battle.AccessMenus <= 2 ? FF9StateSystem.Battle.FF9Battle.GetUnit(CurrentPlayerIndex)?.Player?.Data : null); break; } @@ -264,11 +265,27 @@ public override Boolean OnKeyConfirm(GameObject go) { if (_itemIdList[_currentSubMenuIndex] != RegularItem.NoItem) { + ItemListDetailWithIconHUD detailHUD = new ItemListDetailWithIconHUD(go, true); + if (detailHUD.NameLabel.color == FF9TextTool.Gray || detailHUD.NameLabel.color == FF9TextTool.DarkYellow) + { + FF9Sfx.FF9SFX_Play(102); + return true; + } FF9Sfx.FF9SFX_Play(103); _currentSubMenuIndex = go.GetComponent().ItemDataIndex; _abilityCursorMemorize[new PairCharCommand(CurrentPlayerIndex, _currentCommandId)] = _currentSubMenuIndex; - SetItemPanelVisibility(false, false); - SetTargetVisibility(true); + if (IsMixCast && _doubleCastCount < 2) + { + ++_doubleCastCount; + _firstCommand = ProcessCommand(1, _cursorType); + DisplayItem(CharacterCommands.Commands[_firstCommand.CommandId].Type == CharacterCommandType.Throw); + SetItemPanelVisibility(true, true); + } + else + { + SetItemPanelVisibility(false, false); + SetTargetVisibility(true); + } } else { @@ -287,18 +304,18 @@ public override Boolean OnKeyCancel(GameObject go) { if (ButtonGroupState.ActiveGroup == TargetGroupButton) { - CommandMenu menuType = _currentCommandIndex; + BattleCommandMenu menuType = _currentCommandIndex; GetCommandFromCommandIndex(ref menuType, CurrentPlayerIndex); FF9Sfx.FF9SFX_Play(101); SetTargetVisibility(false); ClearModelPointer(); switch (menuType) { - case CommandMenu.Attack: + case BattleCommandMenu.Attack: SetCommandVisibility(true, true); break; - case CommandMenu.Ability1: - case CommandMenu.Ability2: + case BattleCommandMenu.Ability1: + case BattleCommandMenu.Ability2: if (_subMenuType == SubMenuType.Ability) { SetAbilityPanelVisibility(true, true); @@ -311,7 +328,7 @@ public override Boolean OnKeyCancel(GameObject go) } SetCommandVisibility(true, true); break; - case CommandMenu.Item: + case BattleCommandMenu.Item: SetItemPanelVisibility(true, true); break; } @@ -334,8 +351,18 @@ public override Boolean OnKeyCancel(GameObject go) else if (ButtonGroupState.ActiveGroup == ItemGroupButton) { FF9Sfx.FF9SFX_Play(101); - SetItemPanelVisibility(false, false); - SetCommandVisibility(true, true); + if (IsDoubleCast && _doubleCastCount > 0) + --_doubleCastCount; + if (_doubleCastCount == 0) + { + SetItemPanelVisibility(false, false); + SetCommandVisibility(true, true); + } + else + { + SetItemPanelVisibility(true, false); + DisplayItem(CharacterCommands.Commands[_currentCommandId].Type == CharacterCommandType.Throw); + } } else if (ButtonGroupState.ActiveGroup == String.Empty && UIManager.Input.ContainsAndroidQuitKey()) { @@ -376,14 +403,20 @@ public override Boolean OnKeyMenu(GameObject go) } } if (Configuration.Battle.Speed == 2) - // We defend if we end up with the same player - return OnKeyConfirm(_commandPanel.Defend.GameObject); + { + // If we end up with the same player + BattleHUD.ForceNextTurn = true; + return true; + } } else if (ReadyQueue.Count == 1) { if (Configuration.Battle.Speed == 2) - // We defend if no other players are ready - return OnKeyConfirm(_commandPanel.Defend.GameObject); + { + // If no other players are ready + BattleHUD.ForceNextTurn = true; + return true; + } else SwitchPlayer(ReadyQueue[0]); } @@ -467,8 +500,8 @@ public override Boolean OnItemSelect(GameObject go) { if (ButtonGroupState.ActiveGroup == CommandGroupButton) { - _currentCommandIndex = (CommandMenu)go.transform.GetSiblingIndex(); - if (_currentCommandIndex != CommandMenu.Defend && _currentCommandIndex != CommandMenu.Change) + _currentCommandIndex = (BattleCommandMenu)go.transform.GetSiblingIndex(); + if (_currentCommandIndex != BattleCommandMenu.Defend && _currentCommandIndex != BattleCommandMenu.Change) ResetSlidingButton(false); } else if (ButtonGroupState.ActiveGroup == AbilityGroupButton || ButtonGroupState.ActiveGroup == ItemGroupButton) @@ -516,7 +549,6 @@ private void OpenMainMenu(PLAYER singlePlayerMenu = null) FF9BMenu_EnableMenu(false); UpdatePlayersForMainMenu(); PersistenSingleton.Instance.SetPlayerControlEnable(false, null); - PersistenSingleton.Instance.SetUIPauseEnable(false); Hide(OpenMainMenuAfterHide); } @@ -568,7 +600,7 @@ private void ToggleAllTarget() { foreach (GONavigationButton button in _targetPanel.AllTargets) ButtonGroupState.SetButtonAnimation(button, true); - + ButtonGroupState.ActiveButton = ButtonGroupState.GetCursorStartSelect(TargetGroupButton); } _cursorType = CursorGroup.Individual; @@ -606,4 +638,4 @@ private void GeneratedShow() _usingMainMenu = false; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.UI.PanelCommand.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.UI.PanelCommand.cs index 68b18e5d3..4f85de92e 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.UI.PanelCommand.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.UI.PanelCommand.cs @@ -6,6 +6,7 @@ using Memoria.Scenes; using UnityEngine; using Object = System.Object; +using Memoria.Data; public partial class BattleHUD : UIScene { @@ -80,23 +81,23 @@ public IEnumerable EnumerateButtons(Boolean includeMenuIfPos yield break; } - public GameObject GetCommandButton(CommandMenu menu) + public GameObject GetCommandButton(BattleCommandMenu menu) { switch (menu) { - case CommandMenu.Attack: + case BattleCommandMenu.Attack: return Attack; - case CommandMenu.Defend: + case BattleCommandMenu.Defend: return Defend; - case CommandMenu.Ability1: + case BattleCommandMenu.Ability1: return Skill1; - case CommandMenu.Ability2: + case BattleCommandMenu.Ability2: return Skill2; - case CommandMenu.Item: + case BattleCommandMenu.Item: return Item; - case CommandMenu.Change: + case BattleCommandMenu.Change: return Change; - case CommandMenu.AccessMenu: + case BattleCommandMenu.AccessMenu: return AccessMenu; default: return Attack; @@ -121,4 +122,4 @@ public CaptionBackground(GameObject obj) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Unity.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Unity.cs index de9fd211c..575bf0861 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Unity.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.Unity.cs @@ -269,6 +269,16 @@ private void UpdatePlayer() } } + if(switchBtlId >= 0) + { + // Switch to player ready when ForceNextTurn (turn-based) + Int32 playerId = 0; + while (1 << playerId != switchBtlId) + ++playerId; + SwitchPlayer(playerId); + switchBtlId = -1; + } + if (ReadyQueue.Count <= 0 || CurrentPlayerIndex != -1) return; @@ -441,9 +451,9 @@ private Boolean ManageTargetCommand() if (_subMenuType == SubMenuType.Ability) { - AA_DATA aaData = GetSelectedActiveAbility(CurrentPlayerIndex, _currentCommandId, _currentSubMenuIndex, out _); + AA_DATA aaData = GetSelectedActiveAbility(CurrentPlayerIndex, _currentCommandId, _currentSubMenuIndex, out _, out BattleAbilityId abilId); - if (btl.CurrentMp < GetActionMpCost(aaData, btl)) + if (btl.CurrentMp < GetActionMpCost(aaData, btl, abilId)) { FF9Sfx.FF9SFX_Play(101); DisplayAbility(); @@ -592,7 +602,7 @@ private void SendAutoAttackCommand(Int32 playerIndex) if (cmd != null && btl_cmd.CheckUsingCommand(cmd)) return; CurrentPlayerIndex = playerIndex; - _currentCommandIndex = CommandMenu.Attack; + _currentCommandIndex = BattleCommandMenu.Attack; BattleUnit enemy = GetFirstAliveEnemy(); if (enemy != null) @@ -643,4 +653,4 @@ private void DisplayPartyRealtime() DisplayCharacterParameter(character, unit, hp, mp); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.cs b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.cs index 6f4becc2b..be665e7bc 100644 --- a/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.cs +++ b/Assembly-CSharp/Global/battle/BattleHUD/BattleHUD.cs @@ -1,8 +1,5 @@ using Assets.Sources.Scripts.UI.Common; using FF9; -using System; -using System.Linq; -using System.Collections.Generic; using Memoria; using Memoria.Assets; using Memoria.Data; @@ -10,6 +7,9 @@ using Memoria.Prime; using Memoria.Scenes; using NCalc; +using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; public partial class BattleHUD : UIScene @@ -20,7 +20,7 @@ public partial class BattleHUD : UIScene private readonly List _currentEnemyDieState; private readonly List _hpInfoVal; private readonly List _mpInfoVal; - private readonly Dictionary _commandCursorMemorize; + private readonly Dictionary _commandCursorMemorize; private readonly Dictionary _abilityCursorMemorize; private readonly List _matchBattleIdPlayerList; private readonly List _matchBattleIdEnemyList; @@ -69,7 +69,7 @@ public partial class BattleHUD : UIScene private Boolean _beforePauseCommandEnable; private Boolean _isFromPause; private Boolean _isNeedToInit; - private CommandMenu _currentCommandIndex; + private BattleCommandMenu _currentCommandIndex; private BattleCommandId _currentCommandId; private String _currentButtonGroup; private Int32 _currentSubMenuIndex; @@ -95,7 +95,7 @@ public partial class BattleHUD : UIScene private Boolean _oneTime; private Single _buttonSlideFactor; private Vector2 _buttonSlidePos; - private CommandMenu _buttonSlideInitial; + private BattleCommandMenu _buttonSlideInitial; private GONavigationButton _buttonSliding; private Int32 CurrentBattlePlayerIndex => _matchBattleIdPlayerList.IndexOf(CurrentPlayerIndex); @@ -177,9 +177,10 @@ private Boolean DisplayMessageLibra() if (_currentLibraMessageNumber == 1) { + Single additionalWidth = 0.0f; String str = String.Empty; if ((_libraEnabledMessage & LibraInformation.Name) != 0) - str += _libraBtlData.Name; + str += Singleton.Instance.PhraseLabel.PhrasePreOpcodeSymbol(_libraBtlData.Name, ref additionalWidth); if ((_libraEnabledMessage & LibraInformation.Level) != 0) str += FF9TextTool.BattleLibraText(10) + _libraBtlData.Level.ToString(); SetBattleMessage(str, 3); @@ -415,12 +416,12 @@ private void DisplayCommand() _isManualTrance = false; } - if (Configuration.Mod.TranceSeek) // TRANCE SEEK + if (Configuration.Mod.TranceSeek) // [DV] - Special commands { - if (presetId == CharacterPresetId.Zidane) + if (presetId == CharacterPresetId.Zidane) // Change Zidane's commands depending the weapon { CharacterCommands.CommandSets[presetId].Regular2 = btl_util.getSerialNumber(btl) == CharacterSerialNumber.ZIDANE_DAGGER ? BattleCommandId.SecretTrick : (BattleCommandId)10001; - command2 = btl_util.getSerialNumber(btl) == CharacterSerialNumber.ZIDANE_DAGGER ? BattleCommandId.SecretTrick : (BattleCommandId)10001; + command2 = btl.IsUnderAnyStatus(BattleStatus.Trance) ? CharacterCommands.CommandSets[presetId].Trance2 : btl_util.getSerialNumber(btl) == CharacterSerialNumber.ZIDANE_DAGGER ? BattleCommandId.SecretTrick : (BattleCommandId)10001; } else if (presetId == CharacterPresetId.Steiner) defendCmdId = (BattleCommandId)10015; // Gardien @@ -655,6 +656,10 @@ private void DisplayItem(Boolean isThrow) Count = ff9Item.count, Id = ff9Item.id }; + if (_doubleCastCount == 2 && battleItemListData.Id == (RegularItem)_firstCommand.SubId) + { + battleItemListData.Count--; + } inDataList.Add(battleItemListData); } } @@ -694,17 +699,18 @@ private Boolean CommandIsMonsterTransformCommand(Int32 playerIndex, BattleComman return btl.Data.is_monster_transform && btl.Data.monster_transform.new_command == cmdId; } - private AA_DATA GetSelectedActiveAbility(Int32 playerIndex, BattleCommandId cmdId, Int32 abilityIndex, out Int32 subNo) + private AA_DATA GetSelectedActiveAbility(Int32 playerIndex, BattleCommandId cmdId, Int32 abilityIndex, out Int32 subNo, out BattleAbilityId abilId) { CharacterCommand ff9Command = CharacterCommands.Commands[cmdId]; if (CommandIsMonsterTransformCommand(playerIndex, cmdId, out BTL_DATA.MONSTER_TRANSFORM transform)) { subNo = ff9Command.ListEntry[abilityIndex]; + abilId = BattleAbilityId.Void; return transform.spell[subNo]; } - BattleAbilityId abilityId = PatchAbility(ff9Command.GetAbilityId(abilityIndex)); - subNo = (Int32)abilityId; - return FF9StateSystem.Battle.FF9Battle.aa_data[abilityId]; + abilId = PatchAbility(ff9Command.GetAbilityId(abilityIndex)); + subNo = (Int32)abilId; + return FF9StateSystem.Battle.FF9Battle.aa_data[abilId]; } private void DisplayAbility() @@ -773,7 +779,7 @@ private void DisplayAbilityDetail(Transform item, ListDataTypeBase data, Int32 i else { BattleAbilityId patchedID = PatchAbility(ff9abil.GetActiveAbilityFromAbilityId(battleAbilityListData.Id)); - mp = GetActionMpCost(FF9StateSystem.Battle.FF9Battle.aa_data[patchedID], curUnit); + mp = GetActionMpCost(FF9StateSystem.Battle.FF9Battle.aa_data[patchedID], curUnit, patchedID); itemListDetailHud.NameLabel.text = FF9TextTool.ActionAbilityName(patchedID); itemListDetailHud.Button.Help.Text = FF9TextTool.ActionAbilityHelpDescription(patchedID); } @@ -799,21 +805,31 @@ private void UpdateTargetStates() Boolean shouldUpdatePointer = false; Int32 enemyCountOld = _enemyCount; Int32 playerCountOld = _playerCount; + List matchBattleIdPlayerCurrentList = new List(); + List matchBattleIdEnemyCurrentList = new List(); Int32 enemyCount = 0; Int32 playerCount = 0; foreach (BattleUnit unit in FF9StateSystem.Battle.FF9Battle.EnumerateBattleUnits()) { - if (!unit.IsTargetable) - continue; + Int32 index = unit.GetIndex(); - if (unit.IsPlayer) - playerCount++; - else - enemyCount++; + if (unit.IsTargetable) + { + if (unit.IsPlayer) + { + playerCount++; + matchBattleIdPlayerCurrentList.Add(index); + } + else + { + enemyCount++; + matchBattleIdEnemyCurrentList.Add(index); + } + } } - if (enemyCount != enemyCountOld || playerCount != playerCountOld) + if (enemyCount != enemyCountOld || playerCount != playerCountOld || !Enumerable.SequenceEqual(matchBattleIdPlayerCurrentList, _matchBattleIdPlayerList) || !Enumerable.SequenceEqual(matchBattleIdEnemyCurrentList, _matchBattleIdEnemyList)) { shouldUpdatePointer = true; _matchBattleIdPlayerList.Clear(); @@ -958,7 +974,7 @@ private void UpdateTargetStates() Int32 nextValidTarget = GetFirstAliveEnemyIndex(); if (nextValidTarget != -1) { - if (_currentCommandIndex == CommandMenu.Attack && FF9StateSystem.PCPlatform && _enemyCount > 1) + if (_currentCommandIndex == BattleCommandMenu.Attack && FF9StateSystem.PCPlatform && _enemyCount > 1) { if (_currentTargetIndex == nextValidTarget && nextValidTarget + 1 < _targetPanel.AllTargets.Length) nextValidTarget++; @@ -1114,11 +1130,22 @@ private void CheckDoubleCast(Int32 battleIndex, CursorGroup cursorGroup) ++_doubleCastCount; _firstCommand = ProcessCommand(battleIndex, cursorGroup); - _subMenuType = SubMenuType.Ability; + CharacterCommandType commandType = CharacterCommands.Commands[_firstCommand.CommandId].Type; - DisplayAbility(); - SetTargetVisibility(false); - SetAbilityPanelVisibility(true, true); + if (commandType == CharacterCommandType.Item || commandType == CharacterCommandType.Throw) + { + _subMenuType = commandType == CharacterCommandType.Item ? SubMenuType.Item : SubMenuType.Throw; + DisplayItem(commandType == CharacterCommandType.Throw); + SetTargetVisibility(false); + SetItemPanelVisibility(true, true); + } + else + { + _subMenuType = SubMenuType.Ability; + DisplayAbility(); + SetTargetVisibility(false); + SetAbilityPanelVisibility(true, true); + } BackButton.SetActive(FF9StateSystem.MobilePlatform); } } @@ -1174,11 +1201,13 @@ private void InitHpMp() } } - private Int32 GetActionMpCost(AA_DATA aaData, BattleUnit unit) + private Int32 GetActionMpCost(AA_DATA aaData, BattleUnit unit, BattleAbilityId abilId = BattleAbilityId.Void, Boolean considerCommandMenu = true) { Int32 mpCost = aaData.MP; - if ((aaData.Type & 4) != 0 && FF9StateSystem.EventState.gEventGlobal[18] != 0) - mpCost <<= 2; + BattleAbilityHelper.GetPatchedMPCost(abilId, unit, ref mpCost, ability: aaData, menu: considerCommandMenu ? _currentCommandIndex : BattleCommandMenu.None); + + if ((aaData.Type & 4) != 0 && battle.GARNET_SUMMON_FLAG != 0) + mpCost *= 4; mpCost = mpCost * unit.Player.Data.mpCostFactor / 100; @@ -1187,7 +1216,8 @@ private Int32 GetActionMpCost(AA_DATA aaData, BattleUnit unit) private AbilityStatus GetMonsterTransformAbilityState(Int32 abilId, Int32 playerIndex = -1) { - if (playerIndex < 0) + Boolean checkCurrentPlayer = playerIndex < 0; + if (checkCurrentPlayer) playerIndex = CurrentPlayerIndex; BattleUnit unit = FF9StateSystem.Battle.FF9Battle.GetUnit(playerIndex); if (!unit.IsMonsterTransform) @@ -1206,7 +1236,7 @@ private AbilityStatus GetMonsterTransformAbilityState(Int32 abilId, Int32 player return AbilityStatus.Disable; } - if (GetActionMpCost(aaData, unit) > unit.CurrentMp) + if (GetActionMpCost(aaData, unit, considerCommandMenu: checkCurrentPlayer) > unit.CurrentMp) return AbilityStatus.Disable; return AbilityStatus.Enable; @@ -1214,11 +1244,13 @@ private AbilityStatus GetMonsterTransformAbilityState(Int32 abilId, Int32 player private AbilityStatus GetAbilityState(Int32 abilId, Int32 playerIndex = -1) { - if (playerIndex < 0) + Boolean checkCurrentPlayer = playerIndex < 0; + if (checkCurrentPlayer) playerIndex = CurrentPlayerIndex; AbilityPlayerDetail abilityPlayerDetail = _abilityDetailDict[playerIndex]; BattleUnit unit = FF9StateSystem.Battle.FF9Battle.GetUnit(playerIndex); - AA_DATA patchedAbil = FF9StateSystem.Battle.FF9Battle.aa_data[BattleAbilityHelper.Patch(ff9abil.GetActiveAbilityFromAbilityId(abilId), unit.Player.Data)]; + BattleAbilityId patchedId = BattleAbilityHelper.Patch(ff9abil.GetActiveAbilityFromAbilityId(abilId), unit.Player.Data); + AA_DATA patchedAbil = FF9StateSystem.Battle.FF9Battle.aa_data[patchedId]; if ((Configuration.Battle.LockEquippedAbilities == 2 || Configuration.Battle.LockEquippedAbilities == 3) && abilityPlayerDetail.Player.Index != CharacterId.Quina && abilityPlayerDetail.HasAp && !abilityPlayerDetail.AbilityEquipList.ContainsKey(abilId) && ff9abil.IsAbilityActive(abilId)) return AbilityStatus.None; @@ -1244,7 +1276,12 @@ private AbilityStatus GetAbilityState(Int32 abilId, Int32 playerIndex = -1) return AbilityStatus.Disable; } - if (GetActionMpCost(patchedAbil, unit) > unit.CurrentMp) + if (Configuration.Mod.TranceSeek && (patchedAbil.Type & 16) != 0) // [DV] Unused (5) - To disable "Bandit !" if Zidane equip a Dagger, Mage Masher or Mythril Dagger. + { + return AbilityStatus.Disable; + } + + if (GetActionMpCost(patchedAbil, unit, patchedId, checkCurrentPlayer) > unit.CurrentMp) return AbilityStatus.Disable; return AbilityStatus.Enable; @@ -1377,7 +1414,7 @@ private void OnTargetNavigate(GameObject go, KeyCode key) private void InitialBattle() { - _currentCommandIndex = CommandMenu.Attack; + _currentCommandIndex = BattleCommandMenu.Attack; _currentSubMenuIndex = 0; CurrentPlayerIndex = -1; _subMenuType = SubMenuType.Normal; @@ -1435,9 +1472,11 @@ private CommandDetail ProcessCommand(Int32 targetIndex, CursorGroup cursor) { CommandDetail commandDetail = new CommandDetail { + Menu = _currentCommandIndex, CommandId = _currentCommandId, SubId = 0 }; + GetCommandFromCommandIndex(ref commandDetail.Menu, CurrentPlayerIndex); BattleCommandId cmdId = commandDetail.CommandId; @@ -1526,6 +1565,7 @@ private void SelectViviMagicInsteadOfAttack(Int32 targetIndex, CommandDetail com if (bestRating > 0) { + commandDetail.Menu = BattleCommandMenu.None; commandDetail.CommandId = BattleCommandId.BlackMagic; commandDetail.SubId = (Int32)bestAbility; caster.Data.cmd[0].info.IsZeroMP = true; @@ -1537,25 +1577,60 @@ private void SendCommand(CommandDetail command) BTL_DATA btl = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex]; CMD_DATA cmd = btl.cmd[0]; cmd.regist.sel_mode = 1; - btl_cmd.SetCommand(cmd, command.CommandId, command.SubId, command.TargetId, command.TargetType); + btl_cmd.SetCommand(cmd, command.CommandId, command.SubId, command.TargetId, command.TargetType, cmdMenu: command.Menu); SetPartySwapButtonActive(false); InputFinishList.Add(CurrentPlayerIndex); _partyDetail.SetBlink(CurrentPlayerIndex, false); } - private void SendDoubleCastCommand(CommandDetail first, CommandDetail secondCommand) + private void SendDoubleCastCommand(CommandDetail first, CommandDetail second) { - CMD_DATA cmd = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex].cmd[3]; - cmd.regist.sel_mode = 1; - btl_cmd.SetCommand(cmd, first.CommandId, first.SubId, first.TargetId, first.TargetType); - btl_cmd.SetCommand(FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex].cmd[0], secondCommand.CommandId, secondCommand.SubId, secondCommand.TargetId, secondCommand.TargetType); + CMD_DATA cmd1 = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex].cmd[3]; + CMD_DATA cmd2 = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex].cmd[0]; // The second command sent/performed is the main one (it resets the ATB correctly amongst other things) + cmd1.regist.sel_mode = 1; + btl_cmd.SetCommand(cmd1, first.CommandId, first.SubId, first.TargetId, first.TargetType, cmdMenu: first.Menu); + btl_cmd.SetCommand(cmd2, second.CommandId, second.SubId, second.TargetId, second.TargetType, cmdMenu: second.Menu); SetPartySwapButtonActive(false); InputFinishList.Add(CurrentPlayerIndex); _partyDetail.SetBlink(CurrentPlayerIndex, false); } + private void SendMixCommand(CommandDetail[] allInputs) + { + CommandDetail lastInput = allInputs[allInputs.Length - 1]; + MixItems mixRequest = new MixItems() + { + Id = -1, + Result = RegularItem.NoItem, + Ingredients = allInputs.Select(detail => (RegularItem)detail.SubId).ToList() + }; + Dictionary requestIngredients = mixRequest.GetIngredientsAsDict(); + Int32 mixId = -1; + foreach (MixItems mixCandidate in ff9mixitem.MixItemsData.Values) + { + if (mixCandidate.Length != mixRequest.Length) + continue; + Dictionary candidateIngredients = mixCandidate.GetIngredientsAsDict(); + if (candidateIngredients.All(kvp => requestIngredients.TryGetValue(kvp.Key, out Int32 cnt) && cnt == kvp.Value)) + { + mixId = mixCandidate.Id; + break; + } + } + BTL_DATA btl = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex]; + CMD_DATA cmd = btl.cmd[0]; + cmd.regist.sel_mode = 1; + if (mixId >= 0) + btl_cmd.SetCommand(cmd, lastInput.CommandId, mixId, lastInput.TargetId, lastInput.TargetType, cmdMenu: lastInput.Menu); + else // In case of mix fail, we use CommandId.Item with the first item picked instead + btl_cmd.SetCommand(cmd, BattleCommandId.Item, allInputs[0].SubId, lastInput.TargetId, lastInput.TargetType, cmdMenu: lastInput.Menu); + SetPartySwapButtonActive(false); + InputFinishList.Add(CurrentPlayerIndex); + _partyDetail.SetBlink(CurrentPlayerIndex, false); + } + private void SetCommandVisibility(Boolean isVisible, Boolean forceCursorMemo) { SetPartySwapButtonActive(isVisible); @@ -1600,7 +1675,7 @@ private void SetCommandVisibility(Boolean isVisible, Boolean forceCursorMemo) private void TryMemorizeCommand() { - if (Configuration.Interface.PSXBattleMenu && (_currentCommandIndex == CommandMenu.Defend || _currentCommandIndex == CommandMenu.Change)) + if (Configuration.Interface.PSXBattleMenu && (_currentCommandIndex == BattleCommandMenu.Defend || _currentCommandIndex == BattleCommandMenu.Change)) return; _commandCursorMemorize[CurrentPlayerIndex] = _currentCommandIndex; } @@ -1610,7 +1685,7 @@ private void TryGetMemorizedCommandObject(ref GameObject commandObject, Boolean if (!forceCursorMemo && (Int64)FF9StateSystem.Settings.cfg.cursor == 0L) return; - CommandMenu memorizedCommand; + BattleCommandMenu memorizedCommand; if (_commandCursorMemorize.TryGetValue(CurrentPlayerIndex, out memorizedCommand)) commandObject = _commandPanel.GetCommandButton(memorizedCommand); } @@ -1619,15 +1694,24 @@ private void SetItemPanelVisibility(Boolean isVisible, Boolean forceCursorMemo) { if (isVisible) { - ItemPanel.SetActive(true); - ButtonGroupState.RemoveCursorMemorize(ItemGroupButton); - PairCharCommand cursorKey = new PairCharCommand(CurrentPlayerIndex, _currentCommandId); - if (_abilityCursorMemorize.ContainsKey(cursorKey) && FF9StateSystem.Settings.cfg.cursor != 0 || forceCursorMemo) - _itemScrollList.JumpToIndex(_abilityCursorMemorize[cursorKey], true); + if (!ItemPanel.activeSelf) + { + ItemPanel.SetActive(true); + ButtonGroupState.RemoveCursorMemorize(ItemGroupButton); + PairCharCommand cursorKey = new PairCharCommand(CurrentPlayerIndex, _currentCommandId); + if (_abilityCursorMemorize.ContainsKey(cursorKey) && FF9StateSystem.Settings.cfg.cursor != 0 || forceCursorMemo) + _itemScrollList.JumpToIndex(_abilityCursorMemorize[cursorKey], true); + else + _itemScrollList.JumpToIndex(0, false); + } + if (IsDoubleCast && _doubleCastCount == 1) + ButtonGroupState.SetPointerNumberToGroup(1, ItemGroupButton); + else if (IsDoubleCast && _doubleCastCount == 2) + ButtonGroupState.SetPointerNumberToGroup(2, ItemGroupButton); else - _itemScrollList.JumpToIndex(0, false); - ButtonGroupState.RemoveCursorMemorize(ItemGroupButton); + ButtonGroupState.SetPointerNumberToGroup(0, ItemGroupButton); ButtonGroupState.ActiveGroup = ItemGroupButton; + ButtonGroupState.UpdateActiveButton(); } else { @@ -1671,7 +1755,7 @@ private void SetAbilityPanelVisibility(Boolean isVisible, Boolean forceCursorMem private void SetTargetVisibility(Boolean isVisible) { if (isVisible) - { + { TargetType targetType = 0; TargetDisplay subMode = 0; _defaultTargetAlly = false; @@ -1679,9 +1763,9 @@ private void SetTargetVisibility(Boolean isVisible) _defaultTargetDead = false; _targetDead = false; _bestTargetIndex = -1; - if (_currentCommandIndex == CommandMenu.Ability1 || _currentCommandIndex == CommandMenu.Ability2 || CommandIsMonsterTransformCommand(CurrentPlayerIndex, _currentCommandId, out _)) + if (_currentCommandIndex == BattleCommandMenu.Ability1 || _currentCommandIndex == BattleCommandMenu.Ability2 || CommandIsMonsterTransformCommand(CurrentPlayerIndex, _currentCommandId, out _)) { - AA_DATA aaData = GetSelectedActiveAbility(CurrentPlayerIndex, _currentCommandId, _currentSubMenuIndex, out Int32 subNo); + AA_DATA aaData = GetSelectedActiveAbility(CurrentPlayerIndex, _currentCommandId, _currentSubMenuIndex, out Int32 subNo, out _); targetType = aaData.Info.Target; _defaultTargetAlly = aaData.Info.DefaultAlly; _defaultTargetDead = aaData.Info.DefaultOnDead; @@ -1697,9 +1781,31 @@ private void SetTargetVisibility(Boolean isVisible) testCommand.SetAAData(aaData); testCommand.ScriptId = btl_util.GetCommandScriptId(testCommand); + if (Configuration.Mod.TranceSeek && _currentCommandId == BattleCommandId.Throw) // [DV] Change TargetType for throwing items (magic scrolls for Trance Seek) + { // Or i can make it with the DictionaryPatch.txt instead ? + ItemAttack weapon = ff9item.GetItemWeapon(_itemIdList[_currentSubMenuIndex]); + if (((weapon.Category & WeaponCategory.Throw) != 0) && (weapon.ModelId == 65535 || weapon.ModelId == 0)) + { + switch (weapon.Offset2) + { + case 1: + targetType = TargetType.SingleAlly; + break; + case 6: + targetType = TargetType.All; + break; + case 7: + targetType = TargetType.AllAlly; + break; + case 8: + targetType = TargetType.AllEnemy; + break; + } + } + } SelectBestTarget(targetType, testCommand); } - else if (_currentCommandIndex == CommandMenu.Item) + else if (_currentCommandIndex == BattleCommandMenu.Item) { RegularItem itemId = _itemIdList[_currentSubMenuIndex]; ITEM_DATA itemData = ff9item.GetItemEffect(itemId); @@ -1708,19 +1814,21 @@ private void SetTargetVisibility(Boolean isVisible) _defaultTargetDead = itemData.info.ForDead; _targetDead = itemData.info.ForDead; subMode = itemData.info.DisplayStats; - - CMD_DATA testCommand = new CMD_DATA + if (!MixCommandSet.Contains(_currentCommandId)) { - regist = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex], - cmd_no = _currentCommandId, - sub_no = (Int32)itemId - }; - testCommand.SetAAData(FF9StateSystem.Battle.FF9Battle.aa_data[BattleAbilityId.Void]); - testCommand.ScriptId = btl_util.GetCommandScriptId(testCommand); - - SelectBestTarget(targetType, testCommand); + CMD_DATA testCommand = new CMD_DATA + { + regist = FF9StateSystem.Battle.FF9Battle.btl_data[CurrentPlayerIndex], + cmd_no = _currentCommandId, + sub_no = (Int32)itemId + }; + + testCommand.SetAAData(FF9StateSystem.Battle.FF9Battle.aa_data[BattleAbilityId.Void]); + testCommand.ScriptId = btl_util.GetCommandScriptId(testCommand); + SelectBestTarget(targetType, testCommand); + } } - else if (_currentCommandIndex == CommandMenu.Attack && CurrentPlayerIndex > -1) + else if (_currentCommandIndex == BattleCommandMenu.Attack && CurrentPlayerIndex > -1) { BattleUnit btl = FF9StateSystem.Battle.FF9Battle.GetUnit(CurrentPlayerIndex); if (btl.IsHealingRod || btl.HasSupportAbility(SupportAbility1.Healer)) // Todo: should be coded as a SA feature instead of being hard-coded @@ -1942,7 +2050,7 @@ private void SetTargetDefault() if (targetIndex > -1) { targetIndex += HonoluluBattleMain.EnemyStartIndex; - if (_currentCommandIndex == CommandMenu.Attack && FF9StateSystem.PCPlatform) + if (_currentCommandIndex == BattleCommandMenu.Attack && FF9StateSystem.PCPlatform) ValidateDefaultTarget(ref targetIndex); GONavigationButton targetEnemy = _targetPanel.AllTargets[targetIndex]; ButtonGroupState.SetCursorStartSelect(targetEnemy, TargetGroupButton); @@ -1978,7 +2086,7 @@ private void SetTargetDefault() targetIndex = GetFirstAliveEnemyIndex(); if (targetIndex != -1) { - if (_currentCommandIndex == CommandMenu.Attack && FF9StateSystem.PCPlatform) + if (_currentCommandIndex == BattleCommandMenu.Attack && FF9StateSystem.PCPlatform) ValidateDefaultTarget(ref targetIndex); GONavigationButton currentEnemy = _targetPanel.AllTargets[targetIndex]; ButtonGroupState.SetCursorStartSelect(currentEnemy, TargetGroupButton); @@ -2317,7 +2425,10 @@ private void SetTarget(Int32 battleIndex) } } - if (IsDoubleCast) + if (IsMixCast) + try { SendMixCommand([_firstCommand, ProcessCommand(battleIndex, _cursorType)]); } catch (Exception err) { Log.Error(err); } + + else if (IsDoubleCast) SendDoubleCastCommand(_firstCommand, ProcessCommand(battleIndex, _cursorType)); else SendCommand(ProcessCommand(battleIndex, _cursorType)); @@ -2343,6 +2454,8 @@ private void DisplayItemDetail(Transform item, ListDataTypeBase data, Int32 inde { BattleItemListData battleItemListData = (BattleItemListData)data; ItemListDetailWithIconHUD detailWithIconHud = new ItemListDetailWithIconHUD(item.gameObject, true); + Boolean FirstIngredientMixed = _doubleCastCount == 2 && battleItemListData.Id == (RegularItem)_firstCommand.SubId; + if (isInit) DisplayWindowBackground(item.gameObject, null); @@ -2359,6 +2472,8 @@ private void DisplayItemDetail(Transform item, ListDataTypeBase data, Int32 inde { FF9UIDataTool.DisplayItem(battleItemListData.Id, detailWithIconHud.IconSprite, detailWithIconHud.NameLabel, true); detailWithIconHud.NumberLabel.text = battleItemListData.Count.ToString(); + detailWithIconHud.NameLabel.color = FirstIngredientMixed ? (battleItemListData.Count == 0 ? FF9TextTool.DarkYellow : FF9TextTool.Yellow) : (battleItemListData.Count == 0 ? FF9TextTool.Gray : FF9TextTool.White); + detailWithIconHud.NumberLabel.color = FirstIngredientMixed ? (battleItemListData.Count == 0 ? FF9TextTool.DarkYellow : FF9TextTool.Yellow) : (battleItemListData.Count == 0 ? FF9TextTool.Gray : FF9TextTool.White); detailWithIconHud.Button.Help.Enable = true; detailWithIconHud.Button.Help.TextKey = String.Empty; detailWithIconHud.Button.Help.Text = FF9TextTool.ItemBattleDescription(battleItemListData.Id); @@ -2501,4 +2616,4 @@ private void UpdateBattleAfterMainMenu() if (ItemPanel.activeSelf) DisplayItem(_subMenuType == SubMenuType.Throw); } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battle/BattleSPS.cs b/Assembly-CSharp/Global/battle/BattleSPS.cs index f020315ee..31cf5d27b 100644 --- a/Assembly-CSharp/Global/battle/BattleSPS.cs +++ b/Assembly-CSharp/Global/battle/BattleSPS.cs @@ -4,7 +4,7 @@ using Memoria.Scripts; using UnityEngine; -public class BattleSPS : MonoBehaviour +public partial class BattleSPS : MonoBehaviour { public void Init() { @@ -397,7 +397,13 @@ public void AnimateSHP() public Vector3 rot; - public Vector3 rotArg; + public Boolean rotate; + + public BTL_DATA btl; + + public Int32 bone; + + public Vector3 rotArg; public Vector3 posOffset; diff --git a/Assembly-CSharp/Global/battle/BattleSPSSystem.cs b/Assembly-CSharp/Global/battle/BattleSPSSystem.cs index 86d80de84..09ba4f547 100644 --- a/Assembly-CSharp/Global/battle/BattleSPSSystem.cs +++ b/Assembly-CSharp/Global/battle/BattleSPSSystem.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using Memoria; using Memoria.Data; using UnityEngine; -using Object = System.Object; public class BattleSPSSystem : MonoBehaviour { @@ -130,19 +128,36 @@ public void GenerateSPS() BattleSPS special_sps = this._specialSpsList[i]; if ((special_sps.type != 0 || special_sps.spsBin != null) && (special_sps.attr & 1) != 0 && special_sps.isUpdate) { - double rotation_cos = Math.Cos(2 * Math.PI * special_sps.curFrame / 10000) * this._specialSpsFadingList[i]; // 1 turn every 10 seconds - double rotation_sin = Math.Sin(2 * Math.PI * special_sps.curFrame / 10000) * this._specialSpsFadingList[i]; - Vector3 rotated_pos = BattleSPSSystem.statusTextures[special_sps.refNo].extraPos; - float tmp = rotated_pos.x; - rotated_pos.x = (float)(rotation_cos * tmp - rotation_sin * rotated_pos.z); - rotated_pos.z = (float)(rotation_sin * tmp + rotation_cos * rotated_pos.z); - for (int j = 0; j < special_sps.shpGo.Length; j++) - special_sps.shpGo[j].transform.localPosition = rotated_pos; + if (special_sps.rotate) + { + double rotation_cos = Math.Cos(2 * Math.PI * special_sps.curFrame / 10000) * this._specialSpsFadingList[i]; // 1 turn every 10 seconds + double rotation_sin = Math.Sin(2 * Math.PI * special_sps.curFrame / 10000) * this._specialSpsFadingList[i]; + Vector3 rotated_pos = BattleSPSSystem.statusTextures[special_sps.refNo].extraPos; + float tmp = rotated_pos.x; + rotated_pos.x = (float)(rotation_cos * tmp - rotation_sin * rotated_pos.z); + rotated_pos.z = (float)(rotation_sin * tmp + rotation_cos * rotated_pos.z); + for (int j = 0; j < special_sps.shpGo.Length; j++) + special_sps.shpGo[j].transform.localPosition = rotated_pos; + } + else + { + Vector3 sps_pos = statusTextures[special_sps.refNo].extraPos; + Vector3 bone_pos = special_sps.btl.gameObject.transform.GetChildByName("bone" + special_sps.bone.ToString("D3")).position; + btl2d.GetIconPosition(special_sps.btl, out Byte[] iconBones, out SByte[] iconOffsY, out SByte[] iconOffsZ); + Int16 dy = (Int16)(sps_pos.y * 8); + Int16 dz = (Int16)(sps_pos.z * 8); + Int32 angledx = ff9.rsin((Int32)(special_sps.btl.rot.eulerAngles.y / 360f * 4096f)); + Int32 angledz = ff9.rcos((Int32)(special_sps.btl.rot.eulerAngles.y / 360f * 4096f)); + bone_pos.x += dz * angledx >> 12; + bone_pos.y -= dy; + bone_pos.z += dz * angledz >> 12; + special_sps.pos = bone_pos; + } special_sps.isUpdate = show_special; special_sps.AnimateSHP(); special_sps.lastFrame = special_sps.curFrame; if (this._specialSpsRemovingList[i]) - this._specialSpsFadingList[i] -= 0.05f; + this._specialSpsFadingList[i] -= special_sps.rotate ? 0.05f : 1f; if (this._specialSpsFadingList[i] > 0.0f) special_sps.isUpdate = true; else @@ -154,7 +169,7 @@ public void GenerateSPS() private Boolean _loadSPSTexture() { - for (Int32 i = 0; i < BattleSPSSystem.statusTextures.Length; i++) + for (Int32 i = 0; i < BattleSPSSystem.statusTextures.Count; i++) { BattleSPSSystem.SPSTexture spstexture = BattleSPSSystem.statusTextures[i]; for (Int32 j = 0; j < spstexture.textures.Length; j++) @@ -384,10 +399,10 @@ public Int32 GetObjSpsIndex(BTL_DATA btl, BattleStatus status) return (Int32)(btl.bi.line_no * 12) + statusSPSIndex; } - public void AddBtlSPSObj(BattleUnit btl, BattleStatus status) + public void AddBtlSPSObj(BTL_DATA btl, BattleStatus status) { Int32 statusSPSIndex = this.GetStatusSPSIndex(status); - Int32 objSpsIndex = this.GetObjSpsIndex(btl.Data, status); + Int32 objSpsIndex = this.GetObjSpsIndex(btl, status); btl2d.STAT_ICON_TBL stat_ICON_TBL = btl2d.wStatIconTbl[statusSPSIndex]; this.SetBtlStatus(objSpsIndex, statusSPSIndex, stat_ICON_TBL.Abr, (Int32)stat_ICON_TBL.Type); } @@ -400,6 +415,13 @@ public void RemoveBtlSPSObj(BTL_DATA btl, BattleStatus status) this.SetBtlStatus(objSpsIndex, -1, stat_ICON_TBL.Abr, (Int32)stat_ICON_TBL.Type); } + public void ResetBtlSPSObj(BTL_DATA btl, BattleStatus status) + { + btl2d.STAT_ICON_TBL stat_ICON_TBL = btl2d.wStatIconTbl[GetStatusSPSIndex(status)]; + SetBtlStatus(GetObjSpsIndex(btl, status), -1, stat_ICON_TBL.Abr, (Int32)stat_ICON_TBL.Type); + SetBtlStatus(GetObjSpsIndex(btl, status), GetStatusSPSIndex(status), stat_ICON_TBL.Abr, (Int32)stat_ICON_TBL.Type); + } + public void SetActiveSHP(Boolean active) { for (Int32 i = 0; i < this._spsList.Count; i++) @@ -416,7 +438,7 @@ public void SetActiveSHP(Boolean active) } } - public void AddSpecialSPSObj(int specialid, uint spstype, Vector3 pos, float scale) + public void AddSpecialSPSObj(int specialid, uint spstype, BTL_DATA btl, int bone, float scale, out int SPSid, Boolean rotate = false) { BattleSPS special_sps; if (specialid < 0 || specialid > _specialSpsList.Count) @@ -445,10 +467,19 @@ public void AddSpecialSPSObj(int specialid, uint spstype, Vector3 pos, float sca this._specialSpsFadingList[specialid] = 1.0f; this._specialSpsRemovingList[specialid] = false; } - special_sps.pos = pos; + if (bone < 0 || bone > FF9StateSystem.Battle.FF9Battle.enemy[btl.bi.slot_no].et.icon_bone[5]) + { + btl2d.GetIconPosition(btl, out Byte[] iconBones, out _, out _); + bone = iconBones[3]; + } + SPSid = specialid; + special_sps.pos = btl.gameObject.transform.GetChildByName("bone" + bone.ToString("D3")).position; special_sps.curFrame = 0; special_sps.lastFrame = 0; special_sps.frameCount = 10000; + special_sps.rotate = rotate; + special_sps.btl = btl; + special_sps.bone = bone; special_sps.attr |= 1; special_sps.isUpdate = true; special_sps.refNo = (int)spstype; @@ -466,6 +497,7 @@ public void RemoveSpecialSPSObj(int specialid) } public String MapName; + public List SpsList { get => _spsList; } private Boolean _isReady; @@ -480,7 +512,7 @@ public void RemoveSpecialSPSObj(int specialid) public Vector3 rot; - public static BattleSPSSystem.SPSTexture[] statusTextures = new BattleSPSSystem.SPSTexture[] + public static List statusTextures = new List() { new BattleSPSSystem.SPSTexture("poison", "sps", 1, Vector3.zero, 6f, 4f), new BattleSPSSystem.SPSTexture("venom", "sps", 1, Vector3.zero, 2f, 1.5f), diff --git a/Assembly-CSharp/Global/battle/Result/BattleResultUI.cs b/Assembly-CSharp/Global/battle/Result/BattleResultUI.cs index fc4260687..b69262dfc 100644 --- a/Assembly-CSharp/Global/battle/Result/BattleResultUI.cs +++ b/Assembly-CSharp/Global/battle/Result/BattleResultUI.cs @@ -6,6 +6,7 @@ using FF9; using Memoria; using Memoria.Data; +using Memoria.Assets; using UnityEngine; using Object = System.Object; @@ -185,8 +186,8 @@ private void DisplayGilAndItemInfo() { this.EXPAndAPPhrasePanel.SetActive(false); this.GilAndItemPhrasePanel.SetActive(true); - this.receiveGilLabel.text = (this.gilValue.value - this.gilValue.current).ToString() + "[YSUB=1.3][sub]G"; - this.currentGilLabel.text = Mathf.Min(FF9StateSystem.Common.FF9.party.gil, 9999999f).ToString() + "[YSUB=1.3][sub]G"; + this.receiveGilLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", (this.gilValue.value - this.gilValue.current).ToString()); + this.currentGilLabel.text = Localization.GetWithDefault("GilSymbol").Replace("%", Mathf.Min(FF9StateSystem.Common.FF9.party.gil, 9999999f).ToString()); FF9UIDataTool.DisplayTextLocalize(this.infoLabelGameObject, "BattleResultInfoGilItem"); if (this.itemList.Count > 0) { @@ -433,17 +434,17 @@ private void InitialInfo() { this.AnalyzeBonusItem(); PLAYER[] party = FF9StateSystem.Common.FF9.party.member; - HashSet triggeredSA = new HashSet(); + HashSet triggeredSA = new HashSet(); for (Int32 playIndex = 0; playIndex < 4; playIndex++) { if (party[playIndex] == null) continue; foreach (SupportingAbilityFeature saFeature in ff9abil.GetEnabledSA(party[playIndex])) { - if (triggeredSA.Contains(saFeature.Id)) + if (triggeredSA.Contains(saFeature)) continue; if (saFeature.TriggerOnBattleResult(party[playIndex], battle.btl_bonus, this.itemList, "RewardAll", 0U)) - triggeredSA.Add(saFeature.Id); + triggeredSA.Add(saFeature); } } this.AnalyzeArgument(); @@ -501,7 +502,8 @@ private void InitialInfo() else this.gilValue.step = (UInt32)BattleResultUI.GilDefaultAdd; this.gilValue.current = 0u; - } + this.PostProcessItems(); + } public void ShutdownBattleResultUI() { @@ -544,9 +546,25 @@ private void AnalyzeArgument() this.defaultAp = battle.btl_bonus.ap; this.defaultGil = battle.btl_bonus.gil; this.defaultCard = QuadMistDatabase.MiniGame_GetAllCardCount() < Configuration.TetraMaster.MaxCardCount ? battle.btl_bonus.card : TetraMasterCardId.NONE; - } + } + + private void PostProcessItems() + { + for (Int32 i = 0; i < this.itemList.Count; i++) + { + for (Int32 j = i + 1; j < this.itemList.Count; j++) + { + if (this.itemList[i].id == this.itemList[j].id) + { + this.itemList[i].count = (Byte)Math.Min(this.itemList[i].count + this.itemList[j].count, Byte.MaxValue); + this.itemList[j].count = 0; + } + } + } + this.itemList.RemoveAll(it => it.id == RegularItem.NoItem || it.count == 0); + } - private void UpdateExp() + private void UpdateExp() { this.expEndTick = true; for (Int32 i = 0; i < 4; i++) diff --git a/Assembly-CSharp/Global/battle/battle.cs b/Assembly-CSharp/Global/battle/battle.cs index 937203fa2..dc3360d70 100644 --- a/Assembly-CSharp/Global/battle/battle.cs +++ b/Assembly-CSharp/Global/battle/battle.cs @@ -223,11 +223,8 @@ private static void BattleMainLoop(FF9StateGlobal sys, FF9StateBattleSystem btls } btl_para.CheckPointData(next); - - // ============ Warning ============ - if (Configuration.Battle.Speed == 0 || Configuration.Battle.Speed >= 3 || next.sel_mode != 0 || next.sel_menu != 0 || next.cur.hp == 0 || next.bi.atb == 0) - btl_stat.CheckStatusLoop(next, false); - // ================================= + btl_stat.CheckStatusLoop(next); + btl_stat.RotateAfterCheckStatusLoop(next); } if (flag) { @@ -564,4 +561,4 @@ public static void ff9ShutdownStateBattleResult() btlsnd.ff9btlsnd_song_vol_intplall(120, 0); SoundLib.GetAllSoundDispatchPlayer().StopCurrentSong(120); } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/battlebg.cs b/Assembly-CSharp/Global/battlebg.cs index 08c6792e2..7faffd4c4 100644 --- a/Assembly-CSharp/Global/battlebg.cs +++ b/Assembly-CSharp/Global/battlebg.cs @@ -183,7 +183,7 @@ public static void nf_BattleBG() { battlebg.nf_BbgSkyAngle_Y += battlebg.nf_BbgSkyRotation; Vector3 eulerAngles = transform.localRotation.eulerAngles; - eulerAngles.y = (Single)(battlebg.nf_BbgSkyAngle_Y >> 3) / 4096f * 360f; + eulerAngles.y = (battlebg.nf_BbgSkyAngle_Y / 8f) / 4096f * 360f; transform.localRotation = Quaternion.Euler(eulerAngles); num++; } diff --git a/Assembly-CSharp/Global/btl2d.cs b/Assembly-CSharp/Global/btl2d.cs index f860ecdff..a81a4af48 100644 --- a/Assembly-CSharp/Global/btl2d.cs +++ b/Assembly-CSharp/Global/btl2d.cs @@ -132,10 +132,18 @@ public static void Btl2dStatReq(BTL_DATA pBtl) BTL2D_ENT btl2D_ENT = btl2d.Btl2dReqMP(pBtl, pBtl.fig_poison_mp, 0, b); btl2D_ENT.NoClip = 1; btl2D_ENT.Yofs = -12; + b += 4; + } + if ((fig_stat_info & Param.FIG_STAT_INFO_REGENE_MP) != 0) + { + BTL2D_ENT btl2D_ENT = btl2d.Btl2dReqMP(pBtl, pBtl.fig_regene_mp, 192, b); + btl2D_ENT.NoClip = 1; + btl2D_ENT.Yofs = -12; } } pBtl.fig_stat_info = 0; pBtl.fig_regene_hp = 0; + pBtl.fig_regene_mp = 0; pBtl.fig_poison_hp = 0; pBtl.fig_poison_mp = 0; } @@ -703,4 +711,4 @@ public class S_InSpsWork public Int32 code; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/btl_cmd.cs b/Assembly-CSharp/Global/btl_cmd.cs index e8addb1ae..5c7bb9888 100644 --- a/Assembly-CSharp/Global/btl_cmd.cs +++ b/Assembly-CSharp/Global/btl_cmd.cs @@ -1,13 +1,13 @@ using Assets.Sources.Scripts.UI.Common; using FF9; -using System; -using System.Collections.Generic; -using System.Linq; using Memoria; using Memoria.Data; using Memoria.Scripts; -using UnityEngine; using NCalc; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; // ReSharper disable SuspiciousTypeConversion.Global // ReSharper disable EmptyConstructor @@ -145,7 +145,7 @@ public static void InitCommand(BTL_DATA btl) } } - public static void SetCommand(CMD_DATA cmd, BattleCommandId commandId, Int32 sub_no, UInt16 tar_id, UInt32 cursor, Boolean forcePriority = false) + public static void SetCommand(CMD_DATA cmd, BattleCommandId commandId, Int32 sub_no, UInt16 tar_id, UInt32 cursor, Boolean forcePriority = false, BattleCommandMenu cmdMenu = BattleCommandMenu.None) { if (btl_cmd.CheckUsingCommand(cmd)) return; @@ -164,6 +164,7 @@ public static void SetCommand(CMD_DATA cmd, BattleCommandId commandId, Int32 sub FF9StateSystem.Battle.FF9Battle.cmd_status |= 16; break; } + cmd.info.cmdMenu = cmdMenu; cmd.SetAAData(btl_util.GetCommandAction(cmd)); cmd.ScriptId = btl_util.GetCommandScriptId(cmd); // ScriptId 80: Double cast with AA specified by "Power" and "Rate" @@ -239,8 +240,8 @@ public static void SetCommand(CMD_DATA cmd, BattleCommandId commandId, Int32 sub first_cmd.regist.sel_mode = 1; first_cmd.info.CustomMPCost = cmd.aa.MP; second_cmd.info.CustomMPCost = 0; - btl_cmd.SetCommand(first_cmd, commandId, cmd.Power, first_tar_id, first_cursor); - btl_cmd.SetCommand(second_cmd, commandId, cmd.HitRate, second_tar_id, second_cursor); + btl_cmd.SetCommand(first_cmd, commandId, cmd.Power, first_tar_id, first_cursor, cmdMenu: cmdMenu); + btl_cmd.SetCommand(second_cmd, commandId, cmd.HitRate, second_tar_id, second_cursor, cmdMenu: cmdMenu); return; } @@ -254,7 +255,7 @@ public static void SetCommand(CMD_DATA cmd, BattleCommandId commandId, Int32 sub cmd.info.priority = 1; else btl_stat.RemoveStatus(caster, BattleStatus.Defend); - if (commandId < BattleCommandId.EnemyReaction || commandId > BattleCommandId.BoundaryUpperCheck) + if ((commandId < BattleCommandId.EnemyReaction || commandId > BattleCommandId.BoundaryUpperCheck) && cmd != caster.cmd[3]) // cmd != caster.cmd[3] => Prevent cancel animation with Double Cast. { //if (btl_util.getCurCmdPtr() != btl.cmd[4]) //{ @@ -542,7 +543,8 @@ public static CMD_DATA GetFirstCommandReadyToDequeue(FF9StateBattleSystem btlsys || btl_stat.CheckStatus(cmd.regist, BattleStatusConst.Immobilized) && cmd.cmd_no != BattleCommandId.SysDead && cmd.cmd_no != BattleCommandId.SysReraise && cmd.cmd_no != BattleCommandId.SysStone && cmd.cmd_no != BattleCommandId.SysEscape && cmd.cmd_no != BattleCommandId.SysLastPhoenix || Status.checkCurStat(cmd.regist, BattleStatus.Death) && cmd.cmd_no == BattleCommandId.SysPhantom || Configuration.Battle.Speed >= 4 && btl_util.IsBtlUsingCommandMotion(cmd.regist) - || Configuration.Battle.Speed >= 5 && cmd.regist.bi.cover != 0) + || Configuration.Battle.Speed >= 5 && cmd.regist.bi.cover != 0 + || (Configuration.Mod.TranceSeek && btl_stat.CheckStatus(cmd.regist, BattleStatus.EasyKill) && btl_stat.CheckStatus(cmd.regist, BattleStatus.Sleep))) // [DV] Prevent command cancel for boss. { if (Configuration.Battle.Speed == 4) { @@ -610,13 +612,16 @@ private static void RunCommandFromQueue(FF9StateBattleSystem btlsys) //} if (btl_stat.CheckStatus(btl, BattleStatus.Heat)) { - if (!Configuration.Mod.TranceSeek || btl.dms_geo_id != 512) // TRANCE SEEK - Ark overheat + if (Configuration.Mod.TranceSeek && btl_stat.CheckStatus(btl, BattleStatus.EasyKill)) // TRANCE SEEK - Boss don't die with Heat. { - /*int num = (int)*/ - BattleVoice.TriggerOnStatusChange(btl, "Used", BattleStatus.Heat); - btl_stat.AlterStatus(btl, BattleStatus.Death); + btlsys.cur_cmd_list.Add(cmd); + KillCommand(cmd); return; } + /*int num = (int)*/ + BattleVoice.TriggerOnStatusChange(btl, "Used", BattleStatus.Heat); + btl_stat.AlterStatus(btl, BattleStatus.Death); + return; } } btlsys.cur_cmd_list.Add(cmd); @@ -710,7 +715,10 @@ public static void CommandEngine(FF9StateBattleSystem btlsys) FF9StateSystem.EventState.IncreaseAAUsageCounter(aaIndex); } RegularItem itemId = btl_util.GetCommandItem(cmd); - if (itemId != RegularItem.NoItem) + if (BattleHUD.MixCommandSet.Contains(cmd.cmd_no)) + foreach (RegularItem ingredient in ff9mixitem.MixItemsData[cmd.sub_no].Ingredients) + UIManager.Battle.ItemUse(ingredient); + else if (itemId != RegularItem.NoItem) UIManager.Battle.ItemUse(itemId); cmd.info.mode = command_mode_index.CMD_MODE_LOOP; @@ -1032,8 +1040,21 @@ public static Boolean CheckCommandCondition(FF9StateBattleSystem btlsys, CMD_DAT if (btl_util.IsCommandMonsterTransform(cmd)) return true; - RegularItem itemId = btl_util.GetCommandItem(cmd); - if (itemId != RegularItem.NoItem && ff9item.FF9Item_GetCount(itemId) == 0) + Boolean notEnoughItems = false; + if (BattleHUD.MixCommandSet.Contains(cmd.cmd_no)) + { + Dictionary allIngredients = ff9mixitem.MixItemsData[cmd.sub_no].GetIngredientsAsDict(); + foreach (KeyValuePair requirement in allIngredients) + if (ff9item.FF9Item_GetCount(requirement.Key) < requirement.Value) + notEnoughItems = true; + } + else + { + RegularItem itemId = btl_util.GetCommandItem(cmd); + if (itemId != RegularItem.NoItem && ff9item.FF9Item_GetCount(itemId) == 0) + notEnoughItems = true; + } + if (notEnoughItems) { UIManager.Battle.SetBattleFollowMessage(BattleMesages.NotEnoughItems); return false; @@ -1054,10 +1075,10 @@ public static Boolean CheckCommandCondition(FF9StateBattleSystem btlsys, CMD_DAT cmd.tar_id = caster.Id; break; case BattleCommandId.MagicCounter: - UIManager.Battle.SetBattleFollowMessage(BattleMesages.ReturnMagic); + UIManager.Battle.SetBattleFollowMessage(BattleMesages.ReturnMagic, msgCmd: cmd); break; case BattleCommandId.AutoPotion: - UIManager.Battle.SetBattleFollowMessage(BattleMesages.AutoPotion); + UIManager.Battle.SetBattleFollowMessage(BattleMesages.AutoPotion, msgCmd: cmd); break; case BattleCommandId.SummonGarnet: case BattleCommandId.SummonEiko: @@ -1068,7 +1089,7 @@ public static Boolean CheckCommandCondition(FF9StateBattleSystem btlsys, CMD_DAT return DecideMagicSword(caster, cmd.aa.MP); case BattleCommandId.Counter: if (btl_util.GetCommandMainActionIndex(cmd) == BattleAbilityId.Attack) - UIManager.Battle.SetBattleFollowMessage(BattleMesages.CounterAttack); + UIManager.Battle.SetBattleFollowMessage(BattleMesages.CounterAttack, msgCmd: cmd); break; case BattleCommandId.SysEscape: if (btlsys.btl_phase == 4) @@ -1178,6 +1199,8 @@ public static Boolean CheckMagicCondition(CMD_DATA cmd) { if (!btl_stat.CheckStatus(cmd.regist, BattleStatus.Silence) || (cmd.AbilityCategory & 2) == 0) return true; + if (Configuration.Mod.TranceSeek && btl_stat.CheckStatus(cmd.regist, BattleStatus.EasyKill)) // [DV] - Bosses can use magic under silence but have malus. + return true; UIManager.Battle.SetBattleFollowMessage(BattleMesages.CannotCast); BattleVoice.TriggerOnStatusChange(cmd.regist, "Used", BattleStatus.Silence); return false; @@ -1247,9 +1270,10 @@ public static void ManageDequeueCommand(CMD_DATA cp, CMD_DATA ncp) private static Boolean CheckMpCondition(CMD_DATA cmd) { - Int32 mp = cmd.info.CustomMPCost >= 0 ? cmd.info.CustomMPCost : cmd.aa.MP; - if (cmd.info.IsZeroMP) - mp = 0; + Int32 mp = cmd.GetCommandMPCost(); + if (cmd.regist != null) + if (BattleAbilityHelper.GetPatchedMPCost(btl_util.GetCommandMainActionIndex(cmd), new BattleUnit(cmd.regist), ref mp, cmd: cmd)) + cmd.info.CustomMPCost = mp; if (battle.GARNET_SUMMON_FLAG != 0 && (cmd.AbilityType & 4) != 0) mp *= 4; @@ -1356,7 +1380,7 @@ public static void FinishCommand(FF9StateBattleSystem btlsys, CMD_DATA cmd) } else if (commandId == BattleCommandId.JumpTrance) { - if (Configuration.Mod.TranceSeek) + if (Configuration.Mod.TranceSeek) // [DV] - Freyja come back after Jump when in Trance { caster.RemoveStatus(BattleStatus.Jump); } @@ -1598,7 +1622,7 @@ public static void CheckCommandLoop(CMD_DATA cmd) } } - public static void ExecVfxCommand(BTL_DATA target, CMD_DATA cmd = null) + public static void ExecVfxCommand(BTL_DATA target, CMD_DATA cmd = null, BattleActionThread sfxThread = null) { if (cmd == null) cmd = btl_util.getCurCmdPtr(); @@ -1630,7 +1654,7 @@ public static void ExecVfxCommand(BTL_DATA target, CMD_DATA cmd = null) KillAllCommand(btlsys); } } - SBattleCalculator.CalcMain(caster, target, cmd); + SBattleCalculator.CalcMain(caster, target, cmd, sfxThread); return; case BattleCommandId.SysTrans: { @@ -1656,7 +1680,7 @@ public static void ExecVfxCommand(BTL_DATA target, CMD_DATA cmd = null) case BattleCommandId.Item: case BattleCommandId.AutoPotion: default: - SBattleCalculator.CalcMain(caster, target, cmd); + SBattleCalculator.CalcMain(caster, target, cmd, sfxThread); return; } } @@ -1760,4 +1784,4 @@ private static Boolean ConsumeMp(BTL_DATA btl, Int32 mp) public const Int32 cmd_delay_max = 10; public static Int32 next_cmd_delay; -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/btl_para.cs b/Assembly-CSharp/Global/btl_para.cs index 268fa9b6a..98b5d0d4f 100644 --- a/Assembly-CSharp/Global/btl_para.cs +++ b/Assembly-CSharp/Global/btl_para.cs @@ -4,6 +4,7 @@ using Memoria; using Memoria.Data; using Object = System.Object; +using NCalc; // ReSharper disable InconsistentNaming // ReSharper disable ClassNeverInstantiated.Global @@ -199,28 +200,28 @@ public static void SetPoisonDamage(BTL_DATA btl) { if (Configuration.Mod.TranceSeek) { - damage = GetLogicalHP(btl, true) >> 5; + damage = GetLogicalHP(btl, true) >> (battleUnit.IsUnderStatus(BattleStatus.EasyKill) ? 8 : 5); if (battleUnit.IsUnderStatus(BattleStatus.Venom)) - damage = GetLogicalHP(btl, true) >> 4; + damage = GetLogicalHP(btl, true) >> (battleUnit.IsUnderStatus(BattleStatus.EasyKill) ? 7 : 4); } else { damage = GetLogicalHP(btl, true) >> 4; + if (btl_stat.CheckStatus(btl, BattleStatus.EasyKill)) + damage >>= 2; } - if (btl_stat.CheckStatus(btl, BattleStatus.EasyKill)) - damage >>= 2; if (!FF9StateSystem.Battle.isDebug) { if (Configuration.Mod.TranceSeek && battleUnit.IsZombie) { - if (battleUnit.IsUnderStatus(BattleStatus.Poison)) + if (battleUnit.IsUnderStatus(BattleStatus.Poison)) // [DV] Zombie get healed by Poison in Trance Seek. { btl.cur.hp += damage; btl.fig_stat_info |= Param.FIG_STAT_INFO_REGENE_HP; btl.fig_regene_hp = (Int32)damage; return; } - if (battleUnit.IsUnderStatus(BattleStatus.Venom)) + if (battleUnit.IsUnderStatus(BattleStatus.Venom)) // [DV] Zombie get half damage by Venom in Trance Seek. { damage /= 2U; btl.cur.hp -= damage; @@ -250,7 +251,7 @@ public static void SetRegeneRecover(BTL_DATA btl) UInt32 recover = 0; if (!btl_stat.CheckStatus(btl, BattleStatus.Petrify)) { - recover = GetLogicalHP(btl, true) >> (Configuration.Mod.TranceSeek ? 5 : 4); + recover = GetLogicalHP(btl, true) >> (Configuration.Mod.TranceSeek ? (btl_stat.CheckStatus(btl, BattleStatus.EasyKill) ? 7 : 5) : 4); if (btl_stat.CheckStatus(btl, BattleStatus.Zombie) || btl_util.CheckEnemyCategory(btl, 16)) { btl.fig_stat_info |= Param.FIG_STAT_INFO_REGENE_DMG; @@ -275,6 +276,8 @@ public static void SetRegeneRecover(BTL_DATA btl) public static void SetPoisonMpDamage(BTL_DATA btl) { + if (Configuration.Mod.TranceSeek && btl_stat.CheckStatus(btl, BattleStatus.EasyKill)) // TRANCE SEEK - Venom didn't remove MP on bosses. + return; UInt32 damage = 0; if (!btl_stat.CheckStatus(btl, BattleStatus.Petrify)) { @@ -319,7 +322,7 @@ public static void SwitchPlayerRow(BTL_DATA btl, Boolean updatePos = true) public static Boolean IsNonDyingVanillaBoss(BTL_DATA btl) { - if (Configuration.Battle.CustomBattleFlagsMeaning != 0 || btl.bi.player != 0) + if (Configuration.Battle.CustomBattleFlagsMeaning != 0 || btl.bi.player != 0 || btl_util.getEnemyPtr(btl).info.die_unused3 == 1) // [DV & Tirlititi] - TODO => Replace it with CustomBattleFlagsMeaning return false; if (NonDyingBossBattles.Contains(FF9StateSystem.Battle.battleMapIndex)) { @@ -374,4 +377,4 @@ public static Boolean IsNonDyingVanillaBoss(BTL_DATA btl) 216, 217, 652, 664, 668, 670, 751, // Friendly Yeti 627, 634, 753, 755, 941, 942, 943, 944 // Ragtime Mouse + True + False }; -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Global/btl_scrp.cs b/Assembly-CSharp/Global/btl_scrp.cs index c2247c946..d0cf1fafe 100644 --- a/Assembly-CSharp/Global/btl_scrp.cs +++ b/Assembly-CSharp/Global/btl_scrp.cs @@ -4,6 +4,7 @@ using Memoria; using Memoria.Data; using Memoria.Speedrun; +using static Memoria.Prime.PsdFile.ResolutionInfo; public class btl_scrp { @@ -395,8 +396,20 @@ public static Int32 GetCharacterData(BTL_DATA btl, UInt32 id) case 145: result = (Int32)btl.rot.eulerAngles.z; break; - } - return result; + case 146: + if (btl.bi.player == 0) + { + result = (Int32)btl_util.getEnemyPtr(btl).bonus_exp; + } + break; + case 147: + if (btl.bi.player == 0) + { + result = (Int32)btl_util.getEnemyPtr(btl).bonus_gil; + } + break; + } + return result; } public static void SetCharacterData(BTL_DATA btl, UInt32 id, Int32 val) @@ -647,11 +660,11 @@ public static void SetCharacterData(BTL_DATA btl, UInt32 id, Int32 val) case 130u: // Note: Very crafty. Creates elemental orbs (special SPS) rotating around the BTL_DATA... if (val == 3) { - UnityEngine.Vector3 btl_pos = btl.gameObject.transform.GetChildByName("bone000").position; - HonoluluBattleMain.battleSPS.AddSpecialSPSObj(0, 12, btl_pos, 4.0f); - HonoluluBattleMain.battleSPS.AddSpecialSPSObj(1, 13, btl_pos, 4.0f); - HonoluluBattleMain.battleSPS.AddSpecialSPSObj(2, 14, btl_pos, 4.0f); - } + // UnityEngine.Vector3 btl_pos = btl.gameObject.transform.GetChildByName("bone000").position; + HonoluluBattleMain.battleSPS.AddSpecialSPSObj(0, 12, btl, 0, 4.0f, out _, true); + HonoluluBattleMain.battleSPS.AddSpecialSPSObj(1, 13, btl, 0, 4.0f, out _, true); + HonoluluBattleMain.battleSPS.AddSpecialSPSObj(2, 14, btl, 0, 4.0f, out _, true); + } else if (val == 2) // ... and remove them 1 by 1 HonoluluBattleMain.battleSPS.RemoveSpecialSPSObj(2); else if (val == 1) @@ -686,7 +699,15 @@ public static void SetCharacterData(BTL_DATA btl, UInt32 id, Int32 val) btl.rot.eulerAngles = new UnityEngine.Vector3(btl.rot.eulerAngles.x, btl.rot.eulerAngles.y, val); btl.evt.rotBattle.eulerAngles = new UnityEngine.Vector3(btl.rot.eulerAngles.x, btl.rot.eulerAngles.y, val); break; - } + case 146: + if (btl.bi.player == 0) + btl_util.getEnemyPtr(btl).bonus_exp = (uint)val; + break; + case 147: + if (btl.bi.player == 0) + btl_util.getEnemyPtr(btl).bonus_gil = (uint)val; + break; + } } public static UInt32 GetBattleData(Int32 id) @@ -747,7 +768,10 @@ public static UInt32 GetBattleData(Int32 id) case 43: result = curCmd != null ? (UInt32)curCmd.info.effect_counter : 0; // The number of times the effect point has been reached for the current attack, for multi-hit pattern changes break; - } + case 44: + result = battle.btl_bonus.ap; + break; + } return result; } @@ -840,6 +864,9 @@ public static void SetBattleData(UInt32 id, Int32 val) if (curCmd != null) curCmd.info.effect_counter = val; break; - } + case 44u: + battle.btl_bonus.ap = (ushort)val; + break; + } } } diff --git a/Assembly-CSharp/Global/btl_stat.cs b/Assembly-CSharp/Global/btl_stat.cs index 1367343df..8199788c4 100644 --- a/Assembly-CSharp/Global/btl_stat.cs +++ b/Assembly-CSharp/Global/btl_stat.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using FF9; +using FF9; using Memoria; using Memoria.Data; using NCalc; +using System; +using System.Collections.Generic; +using UnityEngine; // ReSharper disable ClassNeverInstantiated.Global // ReSharper disable EmptyConstructor @@ -29,6 +29,8 @@ public static void InitCountDownStatus(BTL_DATA btl) public static void StatusCommandCancel(BTL_DATA btl, BattleStatus status) { + if (Configuration.Mod.TranceSeek && CheckStatus(btl, BattleStatus.EasyKill) && (status & BattleStatus.Sleep) != 0) // [DV] Prevent command cancel for boss. + return; if (btl.bi.player != 0) UIManager.Battle.RemovePlayerFromAction(btl.btl_id, true); if (!btl_cmd.KillCommand2(btl)) @@ -221,7 +223,7 @@ public static UInt32 AlterStatus(BTL_DATA btl, BattleStatus status, BTL_DATA inf btl.stat.cnt.conti[statusIndex] = (Int16)(btl.stat_duration_factor[status] * btl.stat.cnt.conti[statusIndex]); if ((status & (BattleStatus.Doom | BattleStatus.GradualPetrify)) != 0u) { - if (Configuration.Mod.TranceSeek && unit.HasSupportAbility(SupportAbility1.AutoRegen)) + if (Configuration.Mod.TranceSeek && unit.HasSupportAbility(SupportAbility1.AutoRegen)) // [DV] - SA Resilience { btl.stat.cnt.conti[statusIndex] = (Int16)(statusData[statusIndex].conti_cnt * defaultFactor * 2); btl.stat.cnt.cdown_max = (Int16)Math.Max(1, btl.stat.cnt.conti[statusIndex] / 2); @@ -403,17 +405,17 @@ public static void SetOprStatusCount(BTL_DATA btl, Int32 statTblNo) { UInt16 oprIndex; UInt16 defaultFactor; - if (statTblNo == 1) + if (statTblNo == 1) // Venom { oprIndex = 0; defaultFactor = (UInt16)((UInt32)btl.elem.wpr << 2); } - else if (statTblNo == 16) + else if (statTblNo == 16) // Poison { oprIndex = 1; defaultFactor = (UInt16)((UInt32)btl.elem.wpr << 2); } - else + else // Regen { oprIndex = 2; defaultFactor = (UInt16)(60 - btl.elem.wpr << 2); @@ -505,13 +507,7 @@ public static Boolean CheckStatus(BTL_DATA btl, BattleStatus status) return (btl.stat.permanent & status) != 0 || (btl.stat.cur & status) != 0; } - public static void CheckStatusLoop(BTL_DATA btl, Boolean ignoreAtb) - { - CheckStatuses(btl, ignoreAtb); - RotateAfterCheckStatusLoop(btl); - } - - private static void CheckStatuses(BTL_DATA btl, Boolean ignoreAtb) + public static void CheckStatusLoop(BTL_DATA btl) { FF9StateBattleSystem ff9Battle = FF9StateSystem.Battle.FF9Battle; STAT_INFO stat = btl.stat; @@ -521,26 +517,9 @@ private static void CheckStatuses(BTL_DATA btl, Boolean ignoreAtb) if (unit.IsUnderStatus(BattleStatus.Death)) { - if (Configuration.Mod.TranceSeek && unit.IsPlayer) - { - // TRANCE SEEK - Refresh stats on Death - btl.elem.str = unit.Player.Data.elem.str; - btl.elem.wpr = unit.Player.Data.elem.wpr; - btl.elem.mgc = unit.Player.Data.elem.mgc; - btl.defence.PhysicalDefence = unit.Player.Data.defence.PhysicalDefence; - btl.defence.PhysicalEvade = unit.Player.Data.defence.PhysicalEvade; - btl.defence.MagicalDefence = unit.Player.Data.defence.MagicalDefence; - btl.defence.MagicalEvade = unit.Player.Data.defence.MagicalEvade; - } btl_mot.DieSequence(btl); return; } - if (Configuration.Mod.TranceSeek && !unit.IsUnderStatus(BattleStatus.Death | BattleStatus.Trance) && unit.Trance == 255) - { - unit.RemoveStatus(BattleStatus.Petrify); - unit.AlterStatus(BattleStatus.Trance); - return; - } if (unit.IsUnderAnyStatus(BattleStatus.Petrify)) return; @@ -548,7 +527,7 @@ private static void CheckStatuses(BTL_DATA btl, Boolean ignoreAtb) if (!unit.IsUnderAnyStatus(BattleStatus.Stop | BattleStatus.Jump)) btl.bi.atb = 1; - if (!ignoreAtb && !UIManager.Battle.FF9BMenu_IsEnableAtb()) + if (!UIManager.Battle.FF9BMenu_IsEnableAtb()) return; if (btl.bi.atb == 0) @@ -604,7 +583,7 @@ private static void CheckStatuses(BTL_DATA btl, Boolean ignoreAtb) else { stat.cnt.opr[2] -= btl.cur.at_coef; - } + } } if (Configuration.Mod.TranceSeek) { @@ -631,7 +610,7 @@ private static void CheckStatuses(BTL_DATA btl, Boolean ignoreAtb) ActiveTimeStatus(btl); } - private static void RotateAfterCheckStatusLoop(BTL_DATA btl) + public static void RotateAfterCheckStatusLoop(BTL_DATA btl) { if (CheckStatus(btl, BattleStatus.Confuse) && !btl_util.IsBtlUsingCommand(btl) @@ -660,9 +639,19 @@ public static void SetStatusVfx(BattleUnit unit) if (data.weapon_geo) btl_util.GeoSetColor2DrawPacket(data.weapon_geo, data.add_col[0], data.add_col[1], data.add_col[2], Byte.MaxValue); } - else if (data.special_status_old) + else if (data.special_status_old) // [DV] - Add a glow effect { - btl_util.GeoSetColor2DrawPacket(data.gameObject, 255, 255, 255); + if (!FF9StateSystem.Battle.isFade) + btl_util.GeoSetABR(data.gameObject, "PSX/BattleMap_StatusEffect"); + Byte counter = (Byte)(ff9Battle.btl_cnt % 24); + Byte strength = (Byte)(counter >= 8 ? (counter >= 16 ? (24 - counter) : 8) : (counter + 2)); + Int32 OldGlow = -192; + Int16 r = (Int16)((bbgInfoPtr.chr_r - OldGlow) * strength >> 3); + Int16 g = (Int16)((bbgInfoPtr.chr_g - OldGlow) * strength >> 3); + Int16 b = (Int16)((bbgInfoPtr.chr_b - OldGlow) * strength >> 3); + GeoAddColor2DrawPacket(data.gameObject, r, g, b); + if (data.weapon_geo) + GeoAddColor2DrawPacket(data.weapon_geo, r, g, b); } else if (CheckStatus(data, BattleStatus.Shell | BattleStatus.Protect)) { @@ -697,27 +686,7 @@ public static void SetStatusVfx(BattleUnit unit) } else { - // TRANCE SEEK - Friendly Ladybug (Miskoxy), swap wings colors SetDefaultShader(data); - if (Configuration.Mod.TranceSeek && data.dms_geo_id == 405) - { - if (unit.Strength == 31) - { - SetupCustomEnemyPartColor(data.gameObject, 255, 0, 0, true, 3); - } - else if (unit.Strength == 32) - { - SetupCustomEnemyPartColor(data.gameObject, 0, 255, 255, true, 3); - } - else if (unit.Strength == 33) - { - SetupCustomEnemyPartColor(data.gameObject, 255, 255, 0, true, 3); - } - else if (unit.Strength == 34) - { - SetupCustomEnemyPartColor(data.gameObject, 0, 0, 255, true, 3); - } - } } } else if (CheckStatus(data, BattleStatus.Petrify)) @@ -812,88 +781,14 @@ public static void GeoAddColor2DrawPacket(GameObject go, Int16 r, Int16 g, Int16 } } - public static void SetupCustomEnemyPartColor(GameObject go, short r, short g, short b, bool skinned, int partindex, bool uselight = true) - { - if (uselight) - { - BBGINFO bBGINFO = battlebg.nf_GetBbgInfoPtr(); // On prend en compte la lumière ambiante - r += (short)bBGINFO.chr_r; - g += (short)bBGINFO.chr_g; - b += (short)bBGINFO.chr_b; - } - if (r < 0) - { - r = 0; - } - if (g < 0) - { - g = 0; - } - if (b < 0) - { - b = 0; - } - if (r > 255) - { - r = 255; - } - if (g > 255) - { - g = 255; - } - if (b > 255) - { - b = 255; - } - if (skinned) - { - SkinnedMeshRenderer[] componentsInChildren = go.GetComponentsInChildren(); - if (partindex < componentsInChildren.Length) - { - if (r == 0 && g == 0 && b == 0) - { - componentsInChildren[partindex].tag = "RGBZero"; - componentsInChildren[partindex].enabled = false; - } - else - { - if (!componentsInChildren[partindex].enabled && componentsInChildren[partindex].CompareTag("RGBZero")) - { - componentsInChildren[partindex].enabled = true; - componentsInChildren[partindex].tag = string.Empty; - } - componentsInChildren[partindex].material.SetColor("_Color", new Color32((byte)r, (byte)g, (byte)b, 255)); - } - } - } - else - { - MeshRenderer[] componentsInChildren2 = go.GetComponentsInChildren(); - if (partindex < componentsInChildren2.Length) - { - if (r == 0 && g == 0 && b == 0) - { - componentsInChildren2[partindex].enabled = false; - } - else - { - componentsInChildren2[partindex].enabled = true; - Material[] materials = componentsInChildren2[partindex].materials; - for (int i = 0; i < materials.Length; i++) - { - Material material = materials[i]; - material.SetColor("_Color", new Color32((byte)r, (byte)g, (byte)b, 255)); - } - } - } - } - } private static void ActiveTimeStatus(BTL_DATA btl) { for (Int32 index = 0; index < 32; ++index) { + if (btl.stat.cnt.conti[index] >= 0) // [DV] For Trance Seek purpose, to make some status dissapear for bosses. + btl.stat.cnt.conti[index] -= btl.cur.at_coef; BattleStatus status = (BattleStatus)(1 << index); - if ((btl.stat.cur & BattleStatusConst.ContiCount & status) != 0 && (btl.stat.cnt.conti[index] -= btl.cur.at_coef) < 0) + if ((btl.stat.cur & BattleStatusConst.ContiCount & status) != 0 && btl.stat.cnt.conti[index] < 0) { if ((status & BattleStatus.GradualPetrify) != 0) { @@ -915,23 +810,46 @@ private static void ActiveTimeStatus(BTL_DATA btl) { if (btl_stat.CheckStatus(btl, BattleStatus.EasyKill)) { - // Enemies affected by Doom but with Easy kill proof (doesn't exist in vanilla) lose 1/5 of their Max HP instead (non-capped, except for avoiding softlocks) - // Might want to add a Configuration option for that effect... - Int32 doom_damage = (Int32)btl_para.GetLogicalHP(btl, true) / 5; - if (doom_damage > Math.Max(btl.cur.hp - 1, 9999)) - doom_damage = (Int32)btl.cur.hp - 1; - if (doom_damage > 0) + if (Configuration.Mod.TranceSeek) // TRANCE SEEK - Add 2 random status at the end of countdown. { - BattleVoice.TriggerOnStatusChange(btl, "Used", BattleStatus.Doom); - btl_stat.RemoveStatus(btl, status); - btl.fig_info = Param.FIG_INFO_DISP_HP; - btl_para.SetDamage(new BattleUnit(btl), doom_damage, (Byte)(btl_mot.checkMotion(btl, btl.bi.def_idle) ? 1 : 0)); - btl2d.Btl2dReq(btl); + List statuschoosen = new List{ BattleStatus.Poison, BattleStatus.Venom, BattleStatus.Blind, BattleStatus.Silence, BattleStatus.Trouble, + BattleStatus.Sleep, BattleStatus.Freeze, BattleStatus.Heat, BattleStatus.Mini, BattleStatus.Petrify, BattleStatus.GradualPetrify, + BattleStatus.Berserk, BattleStatus.Confuse, BattleStatus.Stop, BattleStatus.Zombie, BattleStatus.Slow }; + + for (Int32 i = 0; i < (statuschoosen.Count - 1); i++) + { + if ((statuschoosen[i] & btl.stat.invalid) != 0) + { + statuschoosen.Remove(statuschoosen[i]); + } + } + + for (Int32 i = 0; i < 2; i++) + { + AlterStatus(btl, statuschoosen[GameRandom.Next16() % statuschoosen.Count]); + } + RemoveStatus(btl, status); } else { - btl.fig_info |= Param.FIG_INFO_MISS; - btl2d.Btl2dReq(btl); + // Enemies affected by Doom but with Easy kill proof (doesn't exist in vanilla) lose 1/5 of their Max HP instead (non-capped, except for avoiding softlocks) + // Might want to add a Configuration option for that effect... + Int32 doom_damage = (Int32)btl_para.GetLogicalHP(btl, true) / 5; + if (doom_damage > Math.Max(btl.cur.hp - 1, 9999)) + doom_damage = (Int32)btl.cur.hp - 1; + if (doom_damage > 0) + { + BattleVoice.TriggerOnStatusChange(btl, "Used", BattleStatus.Doom); + btl_stat.RemoveStatus(btl, status); + btl.fig_info = Param.FIG_INFO_DISP_HP; + btl_para.SetDamage(new BattleUnit(btl), doom_damage, (Byte)(btl_mot.checkMotion(btl, btl.bi.def_idle) ? 1 : 0)); + btl2d.Btl2dReq(btl); + } + else + { + btl.fig_info |= Param.FIG_INFO_MISS; + btl2d.Btl2dReq(btl); + } } } else @@ -965,4 +883,4 @@ public class StatusModifier : Memoria.Prime.Collections.EntryCollection= 1f) { btl.animFrameFrac--; - if (reverseSpeed && evt.animFrame >= 0) - evt.animFrame--; - else if (!reverseSpeed && evt.animFrame <= animLoopFrame) - evt.animFrame++; + if (reverseSpeed && btl.evt.animFrame >= 0) + btl.evt.animFrame--; + else if (!reverseSpeed && btl.evt.animFrame <= animLoopFrame) + btl.evt.animFrame++; } } else if (btl.animation != null) @@ -315,7 +315,8 @@ public static void DispCharacter(BTL_DATA btl, Boolean advanceAnim = true) btl.animation.enabled = false; } btl.animEndFrame = false; - if (btl_mot.IsAnimationFrozen(btl) || (!reverseSpeed && evt.animFrame > animLoopFrame) || (reverseSpeed && evt.animFrame < 0)) + + if (btl_mot.IsAnimationFrozen(btl) || (!reverseSpeed && btl.evt.animFrame > animLoopFrame) || (reverseSpeed && btl.evt.animFrame < 0)) { btl.endedAnimationName = btl.currentAnimationName; if (btl.bi.dmg_mot_f != 0) @@ -367,36 +368,34 @@ public static void DispCharacter(BTL_DATA btl, Boolean advanceAnim = true) } if (meshoffcnt == meshcnt) { - String modelName; btl.SetIsEnabledBattleModelRenderer(false); - if (FF9BattleDB.GEO.TryGetValue(btl.dms_geo_id, out modelName) && ModelFactory.garnetShortHairTable.Contains(modelName)) + if (FF9BattleDB.GEO.TryGetValue(btl.dms_geo_id, out String modelName) && ModelFactory.garnetShortHairTable.Contains(modelName)) { Renderer[] longHairRenderers = btl.gameObject.transform.GetChildByName("long_hair").GetComponentsInChildren(); - for (Int32 i = 0; i < longHairRenderers.Length; i++) - longHairRenderers[i].enabled = false; + foreach (Renderer renderer in longHairRenderers) + renderer.enabled = false; Renderer[] shortHairRenderers = btl.gameObject.transform.GetChildByName("short_hair").GetComponentsInChildren(); - for (Int32 i = 0; i < shortHairRenderers.Length; i++) - shortHairRenderers[i].enabled = false; + foreach (Renderer renderer in shortHairRenderers) + renderer.enabled = false; } } if (meshoncnt == meshcnt) { - String modelName; btl.SetIsEnabledBattleModelRenderer(true); CharacterSerialNumber serialNumber = btl_util.getSerialNumber(btl); - if (FF9BattleDB.GEO.TryGetValue(btl.dms_geo_id, out modelName) && ModelFactory.garnetShortHairTable.Contains(modelName)) + if (FF9BattleDB.GEO.TryGetValue(btl.dms_geo_id, out String modelName) && ModelFactory.garnetShortHairTable.Contains(modelName)) { if (Configuration.Graphics.GarnetHair != 2 && (serialNumber == CharacterSerialNumber.GARNET_LH_ROD || serialNumber == CharacterSerialNumber.GARNET_LH_KNIFE || Configuration.Graphics.GarnetHair == 1)) { Renderer[] longHairRenderers = btl.gameObject.transform.GetChildByName("long_hair").GetComponentsInChildren(); - for (Int32 i = 0; i < longHairRenderers.Length; i++) - longHairRenderers[i].enabled = true; + foreach (Renderer renderer in longHairRenderers) + renderer.enabled = true; } else { Renderer[] shortHairRenderers = btl.gameObject.transform.GetChildByName("short_hair").GetComponentsInChildren(); - for (Int32 i = 0; i < shortHairRenderers.Length; i++) - shortHairRenderers[i].enabled = true; + foreach (Renderer renderer in shortHairRenderers) + renderer.enabled = true; } } else if (btl.bi.player != 0 && btl.bi.slot_no == (Byte)CharacterId.Zidane && serialNumber == CharacterSerialNumber.ZIDANE_SWORD) diff --git a/Assembly-CSharp/Global/ff9/Snd/FF9Snd.cs b/Assembly-CSharp/Global/ff9/Snd/FF9Snd.cs index 27a938a12..636b8ef73 100644 --- a/Assembly-CSharp/Global/ff9/Snd/FF9Snd.cs +++ b/Assembly-CSharp/Global/ff9/Snd/FF9Snd.cs @@ -215,9 +215,9 @@ public static void ParameterChanger(ref Int32 ParmType, ref Int32 ObjNo, ref Int ObjNo = 1748; else if (ObjNo == 293) ObjNo = 633; - else if (ObjNo == 1545) - ObjNo = 58; - else if (ObjNo == 679) +// else if (ObjNo == 1545) [DV] => When Vivi cast fire on Garnet's hood in CD1 (field n°67) +// ObjNo = 58; => Third sound file of SFX Fire_Sword (se020006) + else if (ObjNo == 679) ObjNo = 9010197; else if (ObjNo == 1230 || ObjNo == 1231) { @@ -229,9 +229,9 @@ public static void ParameterChanger(ref Int32 ParmType, ref Int32 ObjNo, ref Int ObjNo = 3092; else if (ObjNo == 672) ObjNo = 9010138; - else if (ObjNo == 678) - ObjNo = 725; - else if (ObjNo == 3084) +// else if (ObjNo == 678) // [DV] => Battle Sound Slam (ex : Edge from Tantarian) +// ObjNo = 725; => Battle Sound Slap (ex : Strike from Zombie) + else if (ObjNo == 3084) ObjNo = 370; } } diff --git a/Assembly-CSharp/Global/ff9/ff9.cs b/Assembly-CSharp/Global/ff9/ff9.cs index 7cfbf8a9f..887ec4e46 100644 --- a/Assembly-CSharp/Global/ff9/ff9.cs +++ b/Assembly-CSharp/Global/ff9/ff9.cs @@ -6372,6 +6372,8 @@ private static void w_movementHumanOperation() ff9.w_moveCHRControl_LR = true; ff9.w_cameraSysDataCamera.rotation += ff9.PsxRot(32); } + var RightStick = UnityXInput.XInputManager.Instance.CurrentState.ThumbSticks.Right; + ff9.w_cameraSysDataCamera.rotation += RightStick.X * 6.0f; ff9.w_cameraSysDataCamera.rotation %= 360f; if (num4 != 0 || ff9.w_movePadLR) { @@ -6473,6 +6475,8 @@ private static void w_movementShipOperation() ff9.w_cameraSysDataCamera.rotation += ff9.PsxRot(32); ff9.w_moveCHRControl_LR = true; } + var RightStick = UnityXInput.XInputManager.Instance.CurrentState.ThumbSticks.Right; + ff9.w_cameraSysDataCamera.rotation += RightStick.X * 6.0f; ff9.w_cameraSysDataCamera.rotation %= 360f; ff9.w_cameraSysDataCamera.rotationRev = 0f; Single num4 = ff9.S(ff9.w_moveCHRControlPtr.speed_move * num3 / ff9.p1); @@ -6568,6 +6572,9 @@ private static void w_movementPlaneOperation() ff9.w_moveCHRControl_LR = true; } } + var RightStick = UnityXInput.XInputManager.Instance.CurrentState.ThumbSticks.Right; + ff9.w_cameraSysDataCamera.rotation += RightStick.X * 6.0f; + ff9.w_cameraSysDataCamera.rotation %= 360f; ff9.w_cameraSysDataCamera.rotationRev = 0f; ff9.w_moveCHRControl_RotSpeed = ff9.PsxRot(ff9.w_moveCHRControlPtr.speed_rotation * leftStickX >> 7); Single verticalMovementSpeed = ff9.S(-(Int32)ff9.w_moveCHRControlPtr.speed_updown * leftStickY / ff9.p1); diff --git a/Assembly-CSharp/Memoria/Application/FPSManager.cs b/Assembly-CSharp/Memoria/Application/FPSManager.cs index 098235301..28c9c3f2f 100644 --- a/Assembly-CSharp/Memoria/Application/FPSManager.cs +++ b/Assembly-CSharp/Memoria/Application/FPSManager.cs @@ -31,7 +31,7 @@ public static Boolean IsDelayedInputTrigger(UInt32 eventInputCode) // A smooth effect runs during frames at which the main loop doesn't run, for smoothing visual effects without updating the states of objects public static void AddSmoothEffect(UpdaterDelegate eff) { - FPSManager._activeSmooth.Add(eff); + FPSManager._activeSmooth = eff; } public static void DelayMainLoop(Single timeSkip) @@ -106,13 +106,13 @@ private static void AdvanceUpdateCounter() private static void RunSmoothUpdaters() { - foreach (UpdaterDelegate updater in FPSManager._activeSmooth) - updater(FPSManager._smoothUpdateFactor); + if (FPSManager._activeSmooth != null) + FPSManager._activeSmooth(FPSManager._smoothUpdateFactor); } private static void FlushSmoothUpdaters() { - FPSManager._activeSmooth.Clear(); + FPSManager._activeSmooth = null; } private static void CollectDelayedInputs() @@ -138,7 +138,7 @@ private static void FlushDelayedInputs() private static Int32 _currentTick = 0; private static Int32 _currentLoopCount = 0; private static Single _smoothUpdateFactor = 0f; - private static List _activeSmooth = new List(); + private static UpdaterDelegate _activeSmooth; private static UInt32 _delayedInputs = 0; private static UInt32 _delayedInputsOn = 0; private static UInt32 _delayedInputsOff = 0; diff --git a/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Battle.cs b/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Battle.cs index 601ed3dd0..5f476dfb8 100644 --- a/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Battle.cs +++ b/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Battle.cs @@ -1,21 +1,18 @@ using System; -using System.Collections.Generic; using UnityEngine; using FF9; +using Memoria.Prime; namespace Memoria { static class SmoothFrameUpdater_Battle { // Max (squared) distance per frame to be considered as a smooth movement for battle units - private const Single ActorSmoothMovementMaxSqr = 600f * 600f; + private const Single ActorSmoothMovementMaxSqr = 2000f * 2000f; // Max degree turn per frame to be considered as a smooth movement for field actors - private const Single ActorSmoothTurnMaxDeg = 30f; - // Max scaling factor per frame to be considered as a smooth movement for field actors - private const Single ActorSmoothScaleMaxChange = 1.3f; - private const Single ActorSmoothScaleMinChange = 1f / 1.3f; + private const Single ActorSmoothTurnMaxDeg = 45f; // Max (squared) distance per frame to be considered as a smooth movement for the camera - private const Single CameraSmoothMovementMaxSqr = 450f * 450f; + private const Single CameraSmoothMovementMaxSqr = 1000f * 1000f; // Max degree turn per frame to be considered as a smooth movement for the camera private const Single CameraSmoothTurnMaxDeg = 15f; @@ -31,10 +28,15 @@ public static Int32 Skip _cameraRegistered = false; for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next) { - if (next.bi.slave == 0 && next.gameObject != null && next.gameObject.activeInHierarchy && !HonoluluBattleMain.IsAttachedModel(next)) + next._smoothUpdateRegistered = false; + } + if (HonoluluBattleMain.battleSPS?.SpsList != null) + { + foreach (BattleSPS battleSPS in HonoluluBattleMain.battleSPS.SpsList) { - next._smoothUpdateRegistered = false; - next._smoothUpdatePlayingAnim = false; + if (battleSPS == null) + continue; + battleSPS._smoothUpdateRegistered = false; } } } @@ -45,26 +47,132 @@ public static void RegisterState() { for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next) { - if (next.bi.slave == 0 && next.gameObject != null && next.gameObject.activeInHierarchy && !HonoluluBattleMain.IsAttachedModel(next)) + if (next.bi.slave != 0 || next.gameObject == null || !next.gameObject.activeInHierarchy || HonoluluBattleMain.IsAttachedModel(next)) + continue; + + String curAnim = next.currentAnimationName; + Animation anim = next.gameObject.GetComponent(); + AnimationState animState = anim[curAnim]; + next._smoothUpdateBoneDelta = Vector3.zero; + + foreach (AnimationState state in anim) + { + if (state != null && state.enabled) + { + curAnim = state.name; + animState = state; + break; + } + } + + if (next._smoothUpdateRegistered) { - if (next._smoothUpdateRegistered) + next._smoothUpdatePosPrevious = next._smoothUpdatePosActual; + next._smoothUpdateRotPrevious = next._smoothUpdateRotActual; + next._smoothUpdateScalePrevious = next._smoothUpdateScaleActual; + + next._smoothUpdateAnimNamePrevious = next._smoothUpdateAnimNameActual; + next._smoothUpdateAnimTimePrevious = next._smoothUpdateAnimTimeActual; + + if (next._smoothUpdateAnimNamePrevious == curAnim) { - next._smoothUpdatePosPrevious = next._smoothUpdatePosActual; - next._smoothUpdateRotPrevious = next._smoothUpdateRotActual; - next._smoothUpdateScalePrevious = next._smoothUpdateScaleActual; + if (next._smoothUpdateAnimNameNext == null) + { + Single speed = animState.time - next._smoothUpdateAnimTimePrevious; + Single direction = next._smoothUpdateAnimSpeed; + Boolean hasLooped = + (direction < 0 && speed > 0f) || + (direction > 0 && speed < 0f); + if (!hasLooped) + next._smoothUpdateAnimSpeed = speed; + } + else + { + anim.Play(next._smoothUpdateAnimNameNext); + next._smoothUpdateAnimSpeed = animState.time - next._smoothUpdateAnimTimePrevious; + next._smoothUpdateAnimNameNext = null; + } } else { - next._smoothUpdatePosPrevious = next.gameObject.transform.position; - next._smoothUpdateRotPrevious = next.gameObject.transform.rotation; - next._smoothUpdateScalePrevious = next.gameObject.transform.localScale; + if (!anim.IsPlaying(next._smoothUpdateAnimNamePrevious)) + { + Vector3 nextBonePos = next.gameObject.transform.GetChildByName("bone000").localToWorldMatrix.GetColumn(3); + anim.Play(next._smoothUpdateAnimNamePrevious); + AnimationState prevState = anim[next._smoothUpdateAnimNamePrevious]; + prevState.time = next._smoothUpdateAnimTimePrevious + next._smoothUpdateAnimSpeed; + anim.Sample(); + Vector3 curBonePos = next.gameObject.transform.GetChildByName("bone000").localToWorldMatrix.GetColumn(3); + + next._smoothUpdateBoneDelta = nextBonePos - curBonePos; + next._smoothUpdateAnimNameNext = next.currentAnimationName; + } } - next._smoothUpdatePosActual = next.gameObject.transform.position; - next._smoothUpdateRotActual = next.gameObject.transform.rotation; - next._smoothUpdateScaleActual = next.gameObject.transform.localScale; - next._smoothUpdateRegistered = true; } + else + { + next._smoothUpdatePosPrevious = next.gameObject.transform.position; + next._smoothUpdateRotPrevious = next.gameObject.transform.rotation; + next._smoothUpdateScalePrevious = next.gameObject.transform.localScale; + + next._smoothUpdateAnimNamePrevious = curAnim; + next._smoothUpdateAnimTimePrevious = animState.time; + next._smoothUpdateAnimSpeed = 0f; + } + next._smoothUpdatePosActual = next.gameObject.transform.position; + next._smoothUpdateRotActual = next.gameObject.transform.rotation; + next._smoothUpdateScaleActual = next.gameObject.transform.localScale; + + next._smoothUpdateAnimNameActual = curAnim; + next._smoothUpdateAnimTimeActual = animState.time; + + next._smoothUpdateRegistered = true; + geo.geoScaleUpdate(next, true); } + // SPS + foreach (BattleSPS battleSPS in HonoluluBattleMain.battleSPS.SpsList) + { + if (battleSPS == null || !battleSPS.enabled) + continue; + + if (battleSPS._smoothUpdateRegistered) + { + battleSPS._smoothUpdatePosPrevious = battleSPS._smoothUpdatePosActual; + battleSPS._smoothUpdateRotPrevious = battleSPS._smoothUpdateRotActual; + battleSPS._smoothUpdateScalePrevious = battleSPS._smoothUpdateScaleActual; + } + else + { + battleSPS._smoothUpdatePosPrevious = battleSPS.pos; + battleSPS._smoothUpdateRotPrevious = Quaternion.Euler(battleSPS.rot.x, battleSPS.rot.y, battleSPS.rot.z); + battleSPS._smoothUpdateScalePrevious = battleSPS.scale; + } + battleSPS._smoothUpdatePosActual = battleSPS.pos; + battleSPS._smoothUpdateRotActual = Quaternion.Euler(battleSPS.rot.x, battleSPS.rot.y, battleSPS.rot.z); + battleSPS._smoothUpdateScaleActual = battleSPS.scale; + + battleSPS._smoothUpdateRegistered = true; + } + // Sky + if (_bg == null && !_cameraRegistered) + { + foreach (Transform transform in FF9StateSystem.Battle.FF9Battle.map.btlBGPtr.gameObject.transform) + { + if (battlebg.getBbgAttr(transform.name) == 8 && battlebg.nf_BbgSkyRotation != 0) + { + _bg = transform; + _bgRotPrevious = _bg.localRotation; + _bgRotActual = _bg.localRotation; + break; + } + } + } + if (_bg != null) + { + _bgRotPrevious = _bgRotActual; + _bgRotActual = _bg.localRotation; + } + // Camera Camera camera = Camera.main ? Camera.main : GameObject.Find("Battle Camera").GetComponent().GetComponent(); if (camera != null) { @@ -82,6 +190,7 @@ public static void RegisterState() _cameraProjMatrixActual = camera.projectionMatrix; _cameraRegistered = true; } + Apply(0f); } public static void Apply(Single smoothFactor) @@ -89,65 +198,57 @@ public static void Apply(Single smoothFactor) if (_skipCount > 0) return; SFXData.LoadLoop(); - Single unclampedFactor = 1f + smoothFactor; for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next) { - if (next.bi.slave == 0 && next.gameObject != null && next.gameObject.activeInHierarchy && !HonoluluBattleMain.IsAttachedModel(next)) + if (next.gameObject == null || !next._smoothUpdateRegistered) + continue; + + //var pos = next.gameObject.transform.position; + Vector3 frameMove = next._smoothUpdatePosActual + next._smoothUpdateBoneDelta - next._smoothUpdatePosPrevious; + if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < ActorSmoothMovementMaxSqr) + next.gameObject.transform.position = Vector3.Lerp(next._smoothUpdatePosPrevious, next._smoothUpdatePosActual + next._smoothUpdateBoneDelta, smoothFactor); + + //var mag = (next.gameObject.transform.position - pos).magnitude; + //var ang = Vector3.Angle(pos, next.gameObject.transform.position); + //if (next.btl_id == 1) Log.Message($"[DEBUG {Time.frameCount} magnitude {mag} boneDelta {next._smoothUpdateBoneDelta} bone {next.gameObject.transform.GetChildByName("bone000").localToWorldMatrix.GetColumn(3)} pos {next.gameObject.transform.position} prev {next._smoothUpdatePosPrevious} actual {next._smoothUpdatePosActual + next._smoothUpdateBoneDelta} t {smoothFactor}"); + + if (Quaternion.Angle(next._smoothUpdateRotPrevious, next._smoothUpdateRotActual) < ActorSmoothTurnMaxDeg) + next.gameObject.transform.rotation = Quaternion.Lerp(next._smoothUpdateRotPrevious, next._smoothUpdateRotActual, smoothFactor); + + next.gameObject.transform.localScale = Vector3.Lerp(next._smoothUpdateScalePrevious, next._smoothUpdateScaleActual, smoothFactor); + + Animation anim = next.gameObject.GetComponent(); + AnimationState animState = anim[next._smoothUpdateAnimNamePrevious]; + if (animState != null && next.bi.stop_anim == 0) { - Vector3 frameMove = next._smoothUpdatePosActual - next._smoothUpdatePosPrevious; - if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < ActorSmoothMovementMaxSqr) - next.gameObject.transform.position = next._smoothUpdatePosActual + smoothFactor * frameMove; - if (Quaternion.Angle(next._smoothUpdateRotPrevious, next._smoothUpdateRotActual) < ActorSmoothTurnMaxDeg) - next.gameObject.transform.rotation = Quaternion.LerpUnclamped(next._smoothUpdateRotPrevious, next._smoothUpdateRotActual, unclampedFactor); - Single minScaleFactor, maxScaleFactor; - if (next._smoothUpdateScalePrevious.x != 0f) - { - minScaleFactor = next._smoothUpdateScaleActual.x / next._smoothUpdateScalePrevious.x; - maxScaleFactor = minScaleFactor; - } - else - { - minScaleFactor = ActorSmoothScaleMinChange; - maxScaleFactor = ActorSmoothScaleMaxChange; - } - if (next._smoothUpdateScalePrevious.y != 0f) - { - Single ratio = next._smoothUpdateScaleActual.y / next._smoothUpdateScalePrevious.y; - minScaleFactor = Mathf.Min(minScaleFactor, ratio); - maxScaleFactor = Mathf.Max(maxScaleFactor, ratio); - } - else - { - minScaleFactor = ActorSmoothScaleMinChange; - maxScaleFactor = ActorSmoothScaleMaxChange; - } - if (next._smoothUpdateScalePrevious.z != 0f) - { - Single ratio = next._smoothUpdateScaleActual.z / next._smoothUpdateScalePrevious.z; - minScaleFactor = Mathf.Min(minScaleFactor, ratio); - maxScaleFactor = Mathf.Max(maxScaleFactor, ratio); - } - else - { - minScaleFactor = ActorSmoothScaleMinChange; - maxScaleFactor = ActorSmoothScaleMaxChange; - } - if (minScaleFactor > ActorSmoothScaleMinChange && maxScaleFactor < ActorSmoothScaleMaxChange) - next.gameObject.transform.localScale = unclampedFactor * next._smoothUpdateScaleActual - smoothFactor * next._smoothUpdateScalePrevious; - if (next._smoothUpdatePlayingAnim) - { - GameObject go = next.gameObject; - AnimationState anim = go.GetComponent()[next.currentAnimationName]; - if (anim != null) - { - Single animTime = Mathf.LerpUnclamped(next._smoothUpdateAnimTimePrevious, next._smoothUpdateAnimTimeActual, unclampedFactor); - animTime = Mathf.Max(0f, Mathf.Min(anim.length, animTime)); - anim.time = animTime; - go.GetComponent().Sample(); - } - } + animState.time = Mathf.Lerp(next._smoothUpdateAnimTimePrevious, next._smoothUpdateAnimTimePrevious + next._smoothUpdateAnimSpeed, smoothFactor); + + if (animState.time > animState.length) + animState.time -= animState.length; + else if (animState.time < 0f) + animState.time += animState.length; + + anim.Sample(); + // if (next.btl_id == 1) Log.Message($"[DEBUG {Time.frameCount} curName {next.currentAnimationName} actualName {next._smoothUpdateAnimNameActual} prevName {next._smoothUpdateAnimNamePrevious} nextName {next._smoothUpdateAnimNameNext} speed {next._smoothUpdateAnimSpeed} {animState.enabled} animTime {animState.time} animLength {animState.length} t {smoothFactor} prev {next._smoothUpdateAnimTimePrevious} actual {next._smoothUpdateAnimTimeActual}"); } } + // SPS + foreach (BattleSPS battleSPS in HonoluluBattleMain.battleSPS.SpsList) + { + if (battleSPS == null || !battleSPS.enabled || !battleSPS._smoothUpdateRegistered) + continue; + + battleSPS.pos = Vector3.Lerp(battleSPS._smoothUpdatePosPrevious, battleSPS._smoothUpdatePosActual, smoothFactor); + battleSPS.rot = Quaternion.Lerp(battleSPS._smoothUpdateRotPrevious, battleSPS._smoothUpdateRotActual, smoothFactor).eulerAngles; + battleSPS.scale = (Int32)Mathf.Lerp(battleSPS._smoothUpdateScalePrevious, battleSPS._smoothUpdateScaleActual, smoothFactor); + } + // Sky + if(_bg != null) + { + _bg.localRotation = Quaternion.Lerp(_bgRotPrevious, _bgRotActual, smoothFactor); + // Log.Message($"[DEBUG {Time.frameCount} cur {_bg.localRotation.eulerAngles} prev {_bgRotPrevious.eulerAngles} actual {_bgRotActual.eulerAngles} t {smoothFactor}"); + } + // Camera Camera camera = Camera.main ? Camera.main : GameObject.Find("Battle Camera").GetComponent().GetComponent(); if (_cameraRegistered && camera != null) { @@ -157,8 +258,8 @@ public static void Apply(Single smoothFactor) //Single cameraAngle = Quaternion.Angle(MatrixGetRotation(_cameraW2CMatrixActual), MatrixGetRotation(_cameraW2CMatrixPrevious)); //if (cameraAngle >= CameraSmoothTurnMaxDeg) // return; - camera.worldToCameraMatrix = MatrixLerpUnclamped(_cameraW2CMatrixPrevious, _cameraW2CMatrixActual, unclampedFactor); - camera.projectionMatrix = MatrixLerpUnclamped(_cameraProjMatrixPrevious, _cameraProjMatrixActual, unclampedFactor); + camera.worldToCameraMatrix = MatrixLerpUnclamped(_cameraW2CMatrixPrevious, _cameraW2CMatrixActual, smoothFactor); + camera.projectionMatrix = MatrixLerpUnclamped(_cameraProjMatrixPrevious, _cameraProjMatrixActual, smoothFactor); } } @@ -168,22 +269,40 @@ public static void ResetState() _skipCount--; for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next) { - if (next.bi.slave == 0 && next.gameObject != null && next.gameObject.activeInHierarchy && !HonoluluBattleMain.IsAttachedModel(next)) + if (next.gameObject == null || !next._smoothUpdateRegistered) + continue; + + next.gameObject.transform.position = next._smoothUpdatePosActual; + next.gameObject.transform.rotation = next._smoothUpdateRotActual; + next.gameObject.transform.localScale = next._smoothUpdateScaleActual; + + AnimationState animState = next.gameObject.GetComponent()[next._smoothUpdateAnimNameActual]; + if (animState != null) { - if (next._smoothUpdateRegistered) - { - next.gameObject.transform.position = next._smoothUpdatePosActual; - next.gameObject.transform.rotation = next._smoothUpdateRotActual; - next.gameObject.transform.localScale = next._smoothUpdateScaleActual; - } - if (next._smoothUpdatePlayingAnim) - { - AnimationState anim = next.gameObject.GetComponent()[next.currentAnimationName]; - if (anim != null) - anim.time = next._smoothUpdateAnimTimeActual; - } + animState.time = next._smoothUpdateAnimTimeActual; + + if (animState.time > animState.length) + animState.time -= animState.length; + else if (animState.time < 0f) + animState.time += animState.length; } } + if (HonoluluBattleMain.battleSPS?.SpsList != null) + { + foreach (BattleSPS battleSPS in HonoluluBattleMain.battleSPS.SpsList) + { + if (battleSPS == null || !battleSPS._smoothUpdateRegistered) + continue; + + battleSPS.pos = battleSPS._smoothUpdatePosActual; + battleSPS.rot = battleSPS._smoothUpdateRotActual.eulerAngles; + battleSPS.scale = battleSPS._smoothUpdateScaleActual; + } + } + if (_bg != null) + { + _bg.localRotation = _bgRotActual; + } Camera camera = Camera.main ? Camera.main : GameObject.Find("Battle Camera").GetComponent().GetComponent(); if (_cameraRegistered && camera != null) { @@ -226,9 +345,23 @@ private static Matrix4x4 MatrixLerpUnclamped(Matrix4x4 from, Matrix4x4 to, Singl private static Matrix4x4 _cameraW2CMatrixActual; private static Matrix4x4 _cameraProjMatrixPrevious; private static Matrix4x4 _cameraProjMatrixActual; + + private static Transform _bg; + private static Quaternion _bgRotPrevious; + private static Quaternion _bgRotActual; } } +partial class BattleSPS +{ + public Boolean _smoothUpdateRegistered = false; + public Vector3 _smoothUpdatePosPrevious; + public Vector3 _smoothUpdatePosActual; + public Quaternion _smoothUpdateRotPrevious; + public Quaternion _smoothUpdateRotActual; + public Int32 _smoothUpdateScalePrevious; + public Int32 _smoothUpdateScaleActual; +} partial class BTL_DATA { public Boolean _smoothUpdateRegistered = false; @@ -238,7 +371,11 @@ partial class BTL_DATA public Quaternion _smoothUpdateRotActual; public Vector3 _smoothUpdateScalePrevious; public Vector3 _smoothUpdateScaleActual; - public Boolean _smoothUpdatePlayingAnim = false; + public String _smoothUpdateAnimNamePrevious; + public String _smoothUpdateAnimNameActual; + public String _smoothUpdateAnimNameNext; public Single _smoothUpdateAnimTimePrevious; public Single _smoothUpdateAnimTimeActual; + public Single _smoothUpdateAnimSpeed; + public Vector3 _smoothUpdateBoneDelta; } diff --git a/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Field.cs b/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Field.cs index ce06c4ee4..1c2d0ff3e 100644 --- a/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Field.cs +++ b/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_Field.cs @@ -1,5 +1,5 @@ -using System; -using System.Collections.Generic; +using Memoria.Prime; +using System; using UnityEngine; namespace Memoria @@ -7,13 +7,15 @@ namespace Memoria static class SmoothFrameUpdater_Field { // TODO: add a smooth effect for field SPS (FieldSPSSystem._spsList[].pos etc) + // [SamsamTS] SPS interpolation doesn't work great for things like rain drops in Brumecia + // SPSs have low frame rate to begin with, they'll look low frame rate regardless // Max (squared) distance per frame to be considered as a smooth movement for field actors - private const Single ActorSmoothMovementMaxSqr = 100f * 100f; + private const Single ActorSmoothMovementMaxSqr = 400f * 400f; // Iifa tree leaf spiral moves at ~350 // Max degree turn per frame to be considered as a smooth movement for field actors - private const Single ActorSmoothTurnMaxDeg = 20f; + private const Single ActorSmoothTurnMaxDeg = 45f; // Max (squared) distance per frame to be considered as a smooth movement for EBG overlays - private const Single OverlaySmoothMovementMaxSqr = 20f * 20f; + //private const Single OverlaySmoothMovementMaxSqr = 20f * 20f; // Max (squared) distance per frame to be considered as a smooth movement for the camera private const Single CameraSmoothMovementMaxSqr = 450f * 450f; @@ -36,7 +38,6 @@ public static Int32 Skip if (actor != null) { actor._smoothUpdateRegistered = false; - actor._smoothUpdatePlayingAnim = false; } } } @@ -48,35 +49,73 @@ public static void RegisterState() { FieldMap fieldmap = PersistenSingleton.Instance.fieldmap; EventEngine eEngine = PersistenSingleton.Instance; + // Actors for (ObjList objList = eEngine?.GetActiveObjList(); objList != null; objList = objList.next) { - if (objList.obj != null && eEngine.objIsVisible(objList.obj) && objList.obj.cid == 4) + FieldMapActorController actor = (objList.obj as Actor)?.fieldMapActorController; + if (objList.obj == null || !eEngine.objIsVisible(objList.obj) || objList.obj.cid != 4 || actor?.originalActor?.go == null) + continue; + + GameObject go = actor.originalActor.go; + String curAnim = FF9DBAll.AnimationDB.GetValue(actor.originalActor.anim); + Animation anim = actor.gameObject.GetComponent(); + AnimationState animState = anim[curAnim]; + Transform shadow = (objList.obj as Actor).fieldMapActor?.shadowTran; + + if (actor._smoothUpdateRegistered) { - FieldMapActorController actor = (objList.obj as Actor)?.fieldMapActorController; - if (actor?.originalActor.go != null) - { - GameObject go = actor.originalActor.go; - if (actor._smoothUpdateRegistered) - { - actor._smoothUpdatePosPrevious = actor._smoothUpdatePosActual; - actor._smoothUpdateRotPrevious = actor._smoothUpdateRotActual; - } - else - { - actor._smoothUpdatePosPrevious = go.transform.position; - actor._smoothUpdateRotPrevious = go.transform.rotation; - } - actor._smoothUpdatePosActual = go.transform.position; - actor._smoothUpdateRotActual = go.transform.rotation; - actor._smoothUpdateRegistered = true; - } + actor._smoothUpdatePosPrevious = actor._smoothUpdatePosActual; + actor._smoothUpdateShadowPrevious = actor._smoothUpdateShadowActual; + actor._smoothUpdateRotPrevious = actor._smoothUpdateRotActual; + + actor._smoothUpdateAnimNamePrevious = actor._smoothUpdateAnimNameActual; + actor._smoothUpdateAnimTimePrevious = actor._smoothUpdateAnimTimeActual; + } + else + { + actor._smoothUpdatePosPrevious = go.transform.position; + actor._smoothUpdateRotPrevious = go.transform.rotation; + + if (shadow != null) + actor._smoothUpdateShadowPrevious = shadow.position; + + actor._smoothUpdateAnimNamePrevious = curAnim; + actor._smoothUpdateAnimTimePrevious = animState.time; } + actor._smoothUpdatePosActual = go.transform.position; + actor._smoothUpdateRotActual = go.transform.rotation; + + if (shadow != null) + actor._smoothUpdateShadowActual = shadow.position; + + actor._smoothUpdateAnimNameActual = curAnim; + actor._smoothUpdateAnimTimeActual = animState.time; + + if (actor._smoothUpdateRegistered && actor._smoothUpdateAnimNamePrevious == actor._smoothUpdateAnimNameActual) + { + Single speed = actor._smoothUpdateAnimTimeActual - actor._smoothUpdateAnimTimePrevious; + Int32 direction = actor.originalActor.animFrame - actor.originalActor.lastAnimFrame; + Boolean hasLooped = + (direction < 0 && actor._smoothUpdateAnimTimeActual + speed < 0f) || + (direction > 0 && actor._smoothUpdateAnimTimeActual + speed > animState.length); + if (!hasLooped) + actor._smoothUpdateAnimSpeed = speed; + } + else + { + actor._smoothUpdateAnimTimePrevious = actor._smoothUpdateAnimTimeActual; + actor._smoothUpdateAnimSpeed = 0f; + } + + actor._smoothUpdateRegistered = true; } - if (fieldmap?.scene?.overlayList != null) + // Layers + // Interfere with snouz's "Camera stabilizer" + /*if (fieldmap?.scene?.overlayList != null) { foreach (BGOVERLAY_DEF bgLayer in fieldmap.scene.overlayList) { - if (bgLayer.transform != null && !((bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.Loop) != 0) && !((bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.ScrollWithOffset) != 0) ) // && (bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.Active) != 0) + if (bgLayer.transform != null && !((bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.Loop) != 0) && !((bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.ScrollWithOffset) != 0)) // && (bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.Active) != 0) { if (bgLayer._smoothUpdateRegistered) bgLayer._smoothUpdatePosPrevious = bgLayer._smoothUpdatePosActual; @@ -86,7 +125,8 @@ public static void RegisterState() bgLayer._smoothUpdateRegistered = true; } } - } + }*/ + // Camera Camera mainCamera = fieldmap?.GetMainCamera(); if (mainCamera != null) { @@ -98,62 +138,73 @@ public static void RegisterState() _cameraPosActual = mainCamera.transform.position; _cameraRegistered = true; } + + Apply(0f); } public static void Apply(Single smoothFactor) { - if (_skipCount > 0) + if (_skipCount > 0 || smoothFactor > 1f) return; SFXData.LoadLoop(); FieldMap fieldmap = PersistenSingleton.Instance.fieldmap; EventEngine eEngine = PersistenSingleton.Instance; - Single unclampedFactor = 1f + smoothFactor; for (ObjList objList = eEngine?.GetActiveObjList(); objList != null; objList = objList.next) { if (objList.obj != null && eEngine.objIsVisible(objList.obj) && objList.obj.cid == 4) { FieldMapActorController actor = (objList.obj as Actor)?.fieldMapActorController; - if (actor?.originalActor.go != null && actor._smoothUpdateRegistered) + if (actor?.originalActor?.go == null || !actor._smoothUpdateRegistered || actor._smoothUpdateAnimNamePrevious != actor._smoothUpdateAnimNameActual) + continue; + + GameObject go = actor.originalActor.go; + Animation anim = actor.originalActor.go.GetComponent(); + AnimationState animState = anim[actor._smoothUpdateAnimNameActual]; + + Vector3 frameMove = actor._smoothUpdatePosActual - actor._smoothUpdatePosPrevious; + if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < ActorSmoothMovementMaxSqr) { - GameObject go = actor.originalActor.go; - Vector3 frameMove = actor._smoothUpdatePosActual - actor._smoothUpdatePosPrevious; - if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < ActorSmoothMovementMaxSqr) - go.transform.position = actor._smoothUpdatePosActual + smoothFactor * frameMove; - if (Quaternion.Angle(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual) < ActorSmoothTurnMaxDeg) - go.transform.rotation = Quaternion.LerpUnclamped(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual, unclampedFactor); - if (!actor._smoothUpdatePlayingAnim) - continue; - String animName = FF9DBAll.AnimationDB.GetValue(actor.originalActor.anim); - AnimationState anim = go.GetComponent()[animName]; - if (anim != null) - { - Single animTime = Mathf.LerpUnclamped(actor._smoothUpdateAnimTimePrevious, actor._smoothUpdateAnimTimeActual, unclampedFactor); - animTime = Mathf.Max(0f, Mathf.Min(anim.length, animTime)); - anim.time = animTime; - go.GetComponent().Sample(); - } + go.transform.position = Vector3.Lerp(actor._smoothUpdatePosPrevious, actor._smoothUpdatePosActual, smoothFactor); + (objList.obj as Actor).fieldMapActor.shadowTran.position = Vector3.Lerp(actor._smoothUpdateShadowPrevious, actor._smoothUpdateShadowActual, smoothFactor); } + //if (frameMove.sqrMagnitude >= ActorSmoothMovementMaxSqr) Log.Message($"[DEBUG] {Time.frameCount} {actor.name}_{actor.GetInstanceID()} {frameMove.sqrMagnitude} cur {go.transform.position} prev {actor._smoothUpdatePosPrevious} {actor._smoothUpdatePosActual} t {smoothFactor}"); + + if (Quaternion.Angle(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual) < ActorSmoothTurnMaxDeg) + go.transform.rotation = Quaternion.Lerp(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual, smoothFactor); + + if (anim != null) + { + animState.time = Mathf.Lerp(actor._smoothUpdateAnimTimePrevious, actor._smoothUpdateAnimTimePrevious + actor._smoothUpdateAnimSpeed, smoothFactor); + if (animState.time > animState.length) + animState.time -= animState.length; + else if (animState.time < 0f) + animState.time += animState.length; + anim.Sample(); + //if(actor.name == "obj15") Log.Message($"[DEBUG] {Time.frameCount} {actor.name} {animState.name} mag {frameMove.sqrMagnitude} ang {Quaternion.Angle(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual)} cur {go.transform.position} prev {actor._smoothUpdatePosPrevious} {actor._smoothUpdatePosActual} t {smoothFactor}"); + } + // if (actor.isPlayer) Log.Message($"[DEBUG] {Time.frameCount} {actor.name} framerate {animState?.clip?.frameRate} actualName {actor._smoothUpdateAnimNameActual} speed {actor._smoothUpdateAnimSpeed} {animState.enabled} animTime {animState.time} animLength {animState.length} t {smoothFactor} prev {actor._smoothUpdateAnimTimePrevious} actual {actor._smoothUpdateAnimTimePrevious + actor._smoothUpdateAnimSpeed}"); } } foreach (FF9FieldCharState charState in FF9StateSystem.Field.FF9Field.loc.map.charStateArray.Values) fldchar.updateMirrorPosAndAnim(charState.mirror); - if (fieldmap?.scene?.overlayList != null) + /*if (fieldmap?.scene?.overlayList != null) { foreach (BGOVERLAY_DEF bgLayer in fieldmap.scene.overlayList) { if (bgLayer.transform != null && bgLayer._smoothUpdateRegistered) // && (bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.Active) != 0 - { - Vector3 frameMove = bgLayer._smoothUpdatePosActual - bgLayer._smoothUpdatePosPrevious; - if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < OverlaySmoothMovementMaxSqr) - bgLayer.transform.position = bgLayer._smoothUpdatePosActual + smoothFactor * frameMove; + { + //Vector3 frameMove = bgLayer._smoothUpdatePosActual - bgLayer._smoothUpdatePosPrevious; + //if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < OverlaySmoothMovementMaxSqr) + bgLayer.transform.position = Vector3.Lerp(bgLayer._smoothUpdatePosPrevious, bgLayer._smoothUpdatePosActual, smoothFactor); + Log.Message($"[DEBUG] {Time.frameCount} {bgLayer.transform.name} mag {(bgLayer._smoothUpdatePosActual-bgLayer._smoothUpdatePosPrevious).magnitude} cur {bgLayer.transform.position} prev {bgLayer._smoothUpdatePosPrevious} {bgLayer._smoothUpdatePosActual} t {smoothFactor}"); } } - } + }*/ if (_cameraRegistered && !_cameraReverseMove) { Camera mainCamera = fieldmap?.GetMainCamera(); if (mainCamera != null && (_cameraPosActual - _cameraPosPrevious).sqrMagnitude < CameraSmoothMovementMaxSqr) - mainCamera.transform.position = Vector3.LerpUnclamped(_cameraPosPrevious, _cameraPosActual, unclampedFactor); + mainCamera.transform.position = Vector3.Lerp(_cameraPosPrevious, _cameraPosActual, smoothFactor); } } @@ -165,30 +216,26 @@ public static void ResetState() EventEngine eEngine = PersistenSingleton.Instance; for (ObjList objList = eEngine?.GetActiveObjList(); objList != null; objList = objList.next) { - if (objList.obj != null && objList.obj.cid == 4) - { - FieldMapActorController actor = (objList.obj as Actor)?.fieldMapActorController; - if (actor?.originalActor.go != null && actor._smoothUpdateRegistered) - { - GameObject go = actor.originalActor.go; - if (actor._smoothUpdateRegistered) - { - go.transform.position = actor._smoothUpdatePosActual; - go.transform.rotation = actor._smoothUpdateRotActual; - } - if (actor._smoothUpdatePlayingAnim) - { - AnimationState anim = go.GetComponent()[FF9DBAll.AnimationDB.GetValue(actor.originalActor.anim)]; - if (anim != null) - anim.time = actor._smoothUpdateAnimTimeActual; - } - } - } + FieldMapActorController actor = (objList.obj as Actor)?.fieldMapActorController; + GameObject go = actor?.originalActor?.go; + if (go == null || !actor._smoothUpdateRegistered) + continue; + + go.transform.position = actor._smoothUpdatePosActual; + go.transform.rotation = actor._smoothUpdateRotActual; + + Transform shadow = (objList.obj as Actor).fieldMapActor?.shadowTran; + if (shadow != null) + shadow.position = actor._smoothUpdateShadowActual; + + AnimationState anim = go.GetComponent()[actor._smoothUpdateAnimNameActual]; + if (anim != null) + anim.time = actor._smoothUpdateAnimTimeActual; } - if (fieldmap?.scene?.overlayList != null) + /*if (fieldmap?.scene?.overlayList != null) foreach (BGOVERLAY_DEF bgLayer in fieldmap.scene.overlayList) if (bgLayer.transform != null && bgLayer._smoothUpdateRegistered) // && (bgLayer.flags & BGOVERLAY_DEF.OVERLAY_FLAG.Active) != 0 - bgLayer.transform.position = bgLayer._smoothUpdatePosActual; + bgLayer.transform.position = bgLayer._smoothUpdatePosActual;*/ if (_cameraRegistered) { Camera mainCamera = fieldmap?.GetMainCamera(); @@ -212,13 +259,17 @@ partial class FieldMapActorController public Vector3 _smoothUpdatePosActual; public Quaternion _smoothUpdateRotPrevious; public Quaternion _smoothUpdateRotActual; - public Boolean _smoothUpdatePlayingAnim = false; + public Vector3 _smoothUpdateShadowPrevious; + public Vector3 _smoothUpdateShadowActual; + public String _smoothUpdateAnimNamePrevious; + public String _smoothUpdateAnimNameActual; public Single _smoothUpdateAnimTimePrevious; public Single _smoothUpdateAnimTimeActual; + public Single _smoothUpdateAnimSpeed; } -partial class BGOVERLAY_DEF +/*partial class BGOVERLAY_DEF { public Boolean _smoothUpdateRegistered = false; public Vector3 _smoothUpdatePosPrevious; public Vector3 _smoothUpdatePosActual; -} +}*/ diff --git a/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_World.cs b/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_World.cs index 9518b02bb..cdb6779cf 100644 --- a/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_World.cs +++ b/Assembly-CSharp/Memoria/Application/SmoothFrameUpdater_World.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; +using Memoria.Prime; +using System; using UnityEngine; namespace Memoria { static class SmoothFrameUpdater_World { - // Max (squared) distance per frame to be considered as a smooth movement for wmActors - private static readonly Single ActorSmoothMovementMaxSqr = ff9.S(800) * ff9.S(800); - // Disable smooth effects for the duration of a couple of main loop ticks public static Int32 Skip { @@ -28,10 +25,18 @@ public static Int32 Skip if (wmActor != null) { wmActor._smoothUpdateRegistered = false; - wmActor._smoothUpdatePlayingAnim = false; } } } + if (WMWorld.Instance?.Shadows != null) + { + foreach (WMShadow shadow in WMWorld.Instance.Shadows) + { + if (shadow == null) + continue; + shadow._smoothUpdateRegistered = false; + } + } } } } @@ -43,18 +48,66 @@ public static void RegisterState() Obj obj = objList.obj; if (obj.cid == 4) { - WMActor wmActor = (obj as Actor)?.wmActor; - if (wmActor != null) + WMActor actor = (obj as Actor)?.wmActor; + if (actor != null) { - if (wmActor._smoothUpdateRegistered) - wmActor._smoothUpdatePosPrevious = wmActor._smoothUpdatePosActual + ff9.world.BlockShift; + String curAnim = FF9DBAll.AnimationDB.GetValue(actor.originalActor.anim); + Animation anim = actor.Animation; + AnimationState animState = anim[curAnim]; + + if (actor._smoothUpdateRegistered) + { + actor._smoothUpdatePosPrevious = actor._smoothUpdatePosActual + ff9.world.BlockShift; + actor._smoothUpdateRotPrevious = actor._smoothUpdateRotActual; + + actor._smoothUpdateAnimNamePrevious = actor._smoothUpdateAnimNameActual; + actor._smoothUpdateAnimTimePrevious = actor._smoothUpdateAnimTimeActual; + } + else + { + actor._smoothUpdatePosPrevious = actor.transform.position; + actor._smoothUpdateRotPrevious = actor.transform.rotation; + + actor._smoothUpdateAnimNamePrevious = curAnim; + actor._smoothUpdateAnimTimePrevious = animState.time; + } + actor._smoothUpdatePosActual = actor.transform.position; + actor._smoothUpdateRotActual = actor.transform.rotation; + + actor._smoothUpdateAnimNameActual = curAnim; + actor._smoothUpdateAnimTimeActual = animState.time; + + if (actor._smoothUpdateRegistered && actor._smoothUpdateAnimNamePrevious == actor._smoothUpdateAnimNameActual) + { + Single speed = actor._smoothUpdateAnimTimeActual - actor._smoothUpdateAnimTimePrevious; + Int32 direction = actor.originalActor.animFrame - actor.originalActor.lastAnimFrame; + Boolean hasLooped = + (direction < 0 && actor._smoothUpdateAnimTimeActual + speed < 0f) || + (direction > 0 && actor._smoothUpdateAnimTimeActual + speed > animState.length); + if (!hasLooped) + actor._smoothUpdateAnimSpeed = speed; + } else - wmActor._smoothUpdatePosPrevious = wmActor.transform.position; - wmActor._smoothUpdatePosActual = wmActor.transform.position; - wmActor._smoothUpdateRegistered = true; + { + actor._smoothUpdateAnimTimePrevious = actor._smoothUpdateAnimTimeActual; + actor._smoothUpdateAnimSpeed = 0f; + } + + actor._smoothUpdateRegistered = true; } } } + foreach (WMShadow shadow in WMWorld.Instance.Shadows) + { + if (shadow == null || !shadow.enabled) + continue; + if (shadow._smoothUpdateRegistered) + shadow._smoothUpdatePosPrevious = shadow._smoothUpdatePosActual + ff9.world.BlockShift; + else + shadow._smoothUpdatePosPrevious = shadow.transform.position; + shadow._smoothUpdatePosActual = shadow.transform.position; + shadow._smoothUpdateRegistered = true; + } if (ff9.world.MainCamera != null) { if (_cameraRegistered) @@ -74,6 +127,7 @@ public static void RegisterState() _cameraRotActual = ff9.world.MainCamera.transform.rotation; _cameraRegistered = true; } + Apply(0f); } public static void Apply(Single smoothFactor) @@ -81,39 +135,48 @@ public static void Apply(Single smoothFactor) if (_skipCount > 0) return; SFXData.LoadLoop(); - Single unclampedFactor = 1f + smoothFactor; for (ObjList objList = ff9.GetActiveObjList(); objList != null; objList = objList.next) { Obj obj = objList.obj; if (obj.cid == 4) { - WMActor wmActor = (obj as Actor)?.wmActor; - if (wmActor != null && wmActor._smoothUpdateRegistered && ff9.objIsVisible(obj)) + WMActor actor = (obj as Actor)?.wmActor; + if (actor == null || !actor._smoothUpdateRegistered || actor._smoothUpdateAnimNamePrevious != actor._smoothUpdateAnimNameActual) + continue; + + Animation anim = actor.Animation; + AnimationState animState = anim[actor._smoothUpdateAnimNameActual]; + + //Vector3 frameMove = actor._smoothUpdatePosActual - actor._smoothUpdatePosPrevious; + //if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < ActorSmoothMovementMaxSqr) + actor.transform.position = Vector3.Lerp(actor._smoothUpdatePosPrevious, actor._smoothUpdatePosActual, smoothFactor); + + //if (Quaternion.Angle(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual) < ActorSmoothTurnMaxDeg) + actor.transform.rotation = Quaternion.Lerp(actor._smoothUpdateRotPrevious, actor._smoothUpdateRotActual, smoothFactor); + + if (anim != null) { - Vector3 frameMove = wmActor._smoothUpdatePosActual - wmActor._smoothUpdatePosPrevious; - if (frameMove.sqrMagnitude > 0f && frameMove.sqrMagnitude < ActorSmoothMovementMaxSqr) - wmActor.transform.position = wmActor._smoothUpdatePosActual + smoothFactor * frameMove; - if (wmActor._smoothUpdatePlayingAnim) - { - GameObject go = wmActor.originalActor.go; - String animName = FF9DBAll.AnimationDB.GetValue(wmActor.originalActor.anim); - AnimationState anim = go.GetComponent()[animName]; - if (anim != null) - { - Single animTime = Mathf.LerpUnclamped(wmActor._smoothUpdateAnimTimePrevious, wmActor._smoothUpdateAnimTimeActual, unclampedFactor); - animTime = Mathf.Max(0f, Mathf.Min(anim.length, animTime)); - anim.time = animTime; - go.GetComponent().Sample(); - } - } + animState.time = Mathf.Lerp(actor._smoothUpdateAnimTimePrevious, actor._smoothUpdateAnimTimePrevious + actor._smoothUpdateAnimSpeed, smoothFactor); + if (animState.time > animState.length) + animState.time -= animState.length; + else if (animState.time < 0f) + animState.time += animState.length; + anim.Sample(); } + //if (actor.name == "obj12_WM") Log.Message($"[DEBUG] {Time.frameCount} {actor.name} framerate {animState?.clip?.frameRate} actualName {actor._smoothUpdateAnimNameActual} speed {actor._smoothUpdateAnimSpeed} {animState.enabled} animTime {animState.time} animLength {animState.length} t {smoothFactor} prev {actor._smoothUpdateAnimTimePrevious} actual {actor._smoothUpdateAnimTimePrevious + actor._smoothUpdateAnimSpeed}"); } } + foreach (WMShadow shadow in WMWorld.Instance.Shadows) + { + if (shadow == null || !shadow._smoothUpdateRegistered) + continue; + shadow.transform.position = Vector3.Lerp(shadow._smoothUpdatePosPrevious, shadow._smoothUpdatePosActual, smoothFactor); + } if (_cameraRegistered && ff9.world.MainCamera != null) { - ff9.world.MainCamera.fieldOfView = Mathf.LerpUnclamped(_cameraFieldOfViewPrevious, _cameraFieldOfViewActual, unclampedFactor); - ff9.world.MainCamera.transform.position = Vector3.LerpUnclamped(_cameraPosPrevious, _cameraPosActual, unclampedFactor); - ff9.world.MainCamera.transform.rotation = Quaternion.LerpUnclamped(_cameraRotPrevious, _cameraRotActual, unclampedFactor); + ff9.world.MainCamera.fieldOfView = Mathf.LerpUnclamped(_cameraFieldOfViewPrevious, _cameraFieldOfViewActual, smoothFactor); + ff9.world.MainCamera.transform.position = Vector3.LerpUnclamped(_cameraPosPrevious, _cameraPosActual, smoothFactor); + ff9.world.MainCamera.transform.rotation = Quaternion.LerpUnclamped(_cameraRotPrevious, _cameraRotActual, smoothFactor); } } @@ -127,19 +190,32 @@ public static void ResetState() if (obj.cid == 4) { WMActor wmActor = (obj as Actor)?.wmActor; - if (wmActor != null) + if (wmActor == null || !wmActor._smoothUpdateRegistered) + continue; + wmActor.transform.position = wmActor._smoothUpdatePosActual; + wmActor.transform.rotation = wmActor._smoothUpdateRotActual; + + AnimationState animState = wmActor.originalActor.go.gameObject.GetComponent()[wmActor._smoothUpdateAnimNameActual]; + if (animState != null) { - if (wmActor._smoothUpdateRegistered && ff9.objIsVisible(obj)) - wmActor.transform.position = wmActor._smoothUpdatePosActual; - if (wmActor._smoothUpdatePlayingAnim) - { - AnimationState anim = wmActor.originalActor.go.GetComponent()[FF9DBAll.AnimationDB.GetValue(wmActor.originalActor.anim)]; - if (anim != null) - anim.time = wmActor._smoothUpdateAnimTimeActual; - } + animState.time = wmActor._smoothUpdateAnimTimeActual; + + if (animState.time > animState.length) + animState.time -= animState.length; + else if (animState.time < 0f) + animState.time += animState.length; } } } + if (WMWorld.Instance?.Shadows != null) + { + foreach (WMShadow shadow in WMWorld.Instance.Shadows) + { + if (shadow == null || !shadow._smoothUpdateRegistered) + continue; + shadow.transform.position = shadow._smoothUpdatePosActual; + } + } if (_cameraRegistered && ff9.world.MainCamera != null) { ff9.world.MainCamera.fieldOfView = _cameraFieldOfViewActual; @@ -164,7 +240,17 @@ partial class WMActor public Boolean _smoothUpdateRegistered = false; public Vector3 _smoothUpdatePosPrevious; public Vector3 _smoothUpdatePosActual; - public Boolean _smoothUpdatePlayingAnim = false; + public Quaternion _smoothUpdateRotPrevious; + public Quaternion _smoothUpdateRotActual; + public String _smoothUpdateAnimNamePrevious; + public String _smoothUpdateAnimNameActual; public Single _smoothUpdateAnimTimePrevious; public Single _smoothUpdateAnimTimeActual; + public Single _smoothUpdateAnimSpeed; +} +partial class WMShadow +{ + public Boolean _smoothUpdateRegistered = false; + public Vector3 _smoothUpdatePosPrevious; + public Vector3 _smoothUpdatePosActual; } diff --git a/Assembly-CSharp/Memoria/Assets/Export/Battle/BattleSceneExporter.cs b/Assembly-CSharp/Memoria/Assets/Export/Battle/BattleSceneExporter.cs index e7b745357..877614354 100644 --- a/Assembly-CSharp/Memoria/Assets/Export/Battle/BattleSceneExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Export/Battle/BattleSceneExporter.cs @@ -654,8 +654,8 @@ private static void SerializeAllEnemies() foreach (KeyValuePair> pair in localizationCsv) { - String outputPath = outputDirectory + $"Enemies.{pair.Key}.strings"; - TxtWriter.WriteStrings(outputPath, pair.Value.ToArray()); + TextResourcePath outputPath = TextResourcePath.ForExport(outputDirectory + $"Enemies.{pair.Key}"); + outputPath.WriteAll(pair.Value); } } } @@ -755,8 +755,8 @@ private static void SerializeAllActions() foreach (KeyValuePair> pair in localizationCsv) { - String outputPath = outputDirectory + $"Actions.{pair.Key}.strings"; - TxtWriter.WriteStrings(outputPath, pair.Value.ToArray()); + TextResourcePath outputPath = TextResourcePath.ForExport(outputDirectory + $"Actions.{pair.Key}.tmp"); // Don't remove .tmp or "key" will be truncated + outputPath.WriteAll(pair.Value); } } } @@ -1680,4 +1680,4 @@ public SequenceProgram(InitEvent init, ExecEvent exec) public delegate Int32 ExecEvent(btlseq.btlseqinstance btlSeq, SEQ_WORK pSeqWork, StringBuilder pMe); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldImporter.cs index 2e1231ce2..8de0f0f3d 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldImporter.cs @@ -73,7 +73,7 @@ private void Initialize() if (!ReadExternalText(out _external)) { - Log.Warning($"[{TypeName}] External file not found: [{Path.Combine(ModTextResources.Import.FieldsDirectory, _fieldFileName + ".strings")}]"); + Log.Warning($"[{TypeName}] External file not found: [{Path.Combine(ModTextResources.Import.FieldsDirectory, _fieldFileName)}]"); _cache[_fieldZoneId] = _original; continue; } @@ -98,7 +98,7 @@ private void Initialize() _watcherEvent = new AutoResetEvent(false); _watcherTask = Task.Run(DoWatch); - _watcher = new FileSystemWatcher(directory, "*.strings"); + _watcher = new FileSystemWatcher(directory, "*.*"); GameLoopManager.Quit += _watcher.Dispose; _watcher.Changed += OnChangedFileInDirectory; @@ -166,13 +166,15 @@ private void DoWatch() private void OnChangedFileInDirectory(Object sender, FileSystemEventArgs e) { - _watcherEvent.Set(); + String extension = Path.GetExtension(e.Name); + if (TextResourceFormatHelper.TryResolveFileFormat(extension, out _)) + _watcherEvent.Set(); } private static IList> LoadCustomTags() { - String inputPath = ModTextResources.Import.FieldTags; - return ReadTagReplacements(inputPath); + TextResourceReference inputReference = ModTextResources.Import.FieldTags; + return ReadTagReplacements(inputReference); } private static Dictionary>> LoadFieldTags() @@ -181,34 +183,38 @@ private static Dictionary>> if (!Directory.Exists(fieldsDirectory)) return new Dictionary>>(0); - String[] filePathes = Directory.GetFiles(fieldsDirectory, "*_Tags.strings"); - Dictionary>> fieldNames = new Dictionary>>(filePathes.Length); - foreach (String path in filePathes) + String[] filePaths = Directory.GetFiles(fieldsDirectory, "*_Tags.*"); + Dictionary>> fieldNames = new(filePaths.Length); + foreach (String path in filePaths) { - String fileName = Path.GetFileName(path); - if (fileName == null) - { - Log.Warning($"[{TypeName}] Invalid file path: [{path}]."); - continue; - } + String fileName = Path.GetFileName(path); // 0074_EVT_BATTLE_SIOTES01_Tags.strings + String extension = Path.GetExtension(fileName); // .strings - fileName = fileName.Substring(0, fileName.Length - "_Tags.strings".Length); - fieldNames[fileName] = ReadTagReplacements(path); + fileName = fileName.Substring(0, fileName.Length - "_Tags".Length - extension.Length); // 0074_EVT_BATTLE_SIOTES01 + TextResourceFormat format = TextResourceFormatHelper.ResolveFileFormat(extension); + + TextResourcePath inputPath = new(new TextResourceReference(path), format); + fieldNames[fileName] = ReadTagReplacements(inputPath); } return fieldNames; } - private static IList> ReadTagReplacements(String inputPath) + private static IList> ReadTagReplacements(TextResourceReference inputReference) { - if (!File.Exists(inputPath)) + if (!inputReference.IsExists(out TextResourcePath existingFile)) return new List>(); - TxtEntry[] generalNames = TxtReader.ReadStrings(inputPath); + return ReadTagReplacements(existingFile); + } + + private static IList> ReadTagReplacements(TextResourcePath existingFile) + { + TxtEntry[] generalNames = existingFile.ReadAll(); if (generalNames.IsNullOrEmpty()) return new List>(); - TextReplacements result = new TextReplacements(generalNames.Length); + TextReplacements result = new(generalNames.Length); foreach (TxtEntry entry in generalNames) result.Add(entry.Prefix, entry.Value); @@ -359,14 +365,14 @@ public static String GetEnding(String str) private Boolean ReadExternalText(out TxtEntry[] entries) { - String inputPath = Path.Combine(ModTextResources.Import.FieldsDirectory, _fieldFileName + ".strings"); - if (!File.Exists(inputPath)) + TextResourceReference inputReference = new(Path.Combine(ModTextResources.Import.FieldsDirectory, _fieldFileName)); + if (!inputReference.IsExists(out TextResourcePath existingFile)) { entries = null; return false; } - entries = TxtReader.ReadStrings(inputPath); + entries = existingFile.ReadAll(); return !entries.IsNullOrEmpty(); } @@ -446,4 +452,4 @@ protected override Boolean LoadExternal() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldTags.cs b/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldTags.cs index 395a465c3..c114c0d6c 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldTags.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Fields/FieldTags.cs @@ -23,7 +23,7 @@ private static TextReplacements GetSimpleTags() {"[VIVI]", "{Vivi}"}, {"[DGGR]", "{Dagger}"}, {"[STNR]", "{Steiner}"}, - {"[FRYA]", "{Fraya}"}, + {"[FRYA]", "{Freya}"}, {"[QUIN]", "{Quina}"}, {"[EIKO]", "{Eiko}"}, {"[AMRT]", "{Amarant}"}, @@ -95,4 +95,4 @@ private static TextReplacements GetSimpleTags() }; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/AbilityImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/AbilityImporter.cs index 2f7c5cd9a..45e80a030 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/AbilityImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/AbilityImporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public class AbilityImporter : SingleFileImporter { protected override String TypeName => nameof(AbilityImporter); - protected override String ImportPath => ModTextResources.Import.Abilities; + protected override TextResourceReference ImportPath => ModTextResources.Import.Abilities; protected override void ProcessEntries(TxtEntry[] entreis) { @@ -25,4 +25,4 @@ protected override Boolean LoadInternal() return true; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/BattleImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/BattleImporter.cs index 54500cce9..e771af635 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/BattleImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/BattleImporter.cs @@ -56,8 +56,8 @@ private void Initialize() private Boolean TryLoadReplacements(out Dictionary dic) { - String importPath = ModTextResources.Import.Battle; - if (!File.Exists(importPath)) + TextResourceReference importPath = ModTextResources.Import.Battle; + if (!importPath.IsExists(out TextResourcePath existingFile)) { Log.Warning($"[{TypeName}] Import was skipped bacause a file does not exist: [{importPath}]."); dic = null; @@ -66,7 +66,7 @@ private Boolean TryLoadReplacements(out Dictionary dic) Log.Message($"[{TypeName}] Loading from [{importPath}]..."); - TxtEntry[] entries = TxtReader.ReadStrings(importPath); + TxtEntry[] entries = existingFile.ReadAll(); BattleFormatter.Parse(entries, out dic); @@ -109,4 +109,4 @@ protected override Boolean LoadExternal() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/CharacterNamesImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/CharacterNamesImporter.cs index c5e6935bd..9fd8b6260 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/CharacterNamesImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/CharacterNamesImporter.cs @@ -8,7 +8,7 @@ namespace Memoria.Assets public class CharacterNamesImporter : SingleFileImporter { protected override String TypeName => nameof(CharacterNamesImporter); - protected override String ImportPath => ModTextResources.Import.CharacterNames; + protected override TextResourceReference ImportPath => ModTextResources.Import.CharacterNames; protected override void ProcessEntries(TxtEntry[] entreis) { diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/CommandLoader.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/CommandLoader.cs index 18e9bfc62..47b739ee7 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/CommandLoader.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/CommandLoader.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public class CommandImporter : SingleFileImporter { protected override String TypeName => nameof(CommandImporter); - protected override String ImportPath => ModTextResources.Import.Commands; + protected override TextResourceReference ImportPath => ModTextResources.Import.Commands; protected override void ProcessEntries(TxtEntry[] entreis) { diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/EtcImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/EtcImporter.cs index 22dcb552e..855a29ef1 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/EtcImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/EtcImporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public sealed class EtcImporter : SingleFileImporter { protected override String TypeName { get; } - protected override String ImportPath { get; } + protected override TextResourceReference ImportPath { get; } private readonly Action _setter; private readonly String _embadedPath; diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/ItemImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/ItemImporter.cs index e0f12eb7f..4b692bf14 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/ItemImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/ItemImporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public sealed class ItemImporter : SingleFileImporter { protected override String TypeName => nameof(ItemImporter); - protected override String ImportPath => ModTextResources.Import.Items; + protected override TextResourceReference ImportPath => ModTextResources.Import.Items; protected override void ProcessEntries(TxtEntry[] entreis) { diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/KeyItemImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/KeyItemImporter.cs index 4cb699575..f311073b0 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/KeyItemImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/KeyItemImporter.cs @@ -6,7 +6,7 @@ namespace Memoria.Assets public sealed class KeyItemImporter : SingleFileImporter { protected override String TypeName => nameof(KeyItemImporter); - protected override String ImportPath => ModTextResources.Import.KeyItems; + protected override TextResourceReference ImportPath => ModTextResources.Import.KeyItems; protected override void ProcessEntries(TxtEntry[] entreis) { diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/LocationNameImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/LocationNameImporter.cs index 8281962d0..6a3c9ed56 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/LocationNameImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/LocationNameImporter.cs @@ -27,7 +27,8 @@ protected override Boolean LoadExternal() Dictionary locationNames = FF9TextTool.LocationNames; foreach (String filePath in Directory.GetFiles(importDirectory, "Names of *", SearchOption.TopDirectoryOnly)) { - TxtEntry[] entries = TxtReader.ReadStrings(filePath); + TextResourcePath existingFile = TextResourcePath.ForImportExistingFile(filePath); + TxtEntry[] entries = existingFile.ReadAll(); LocationNameFormatter.Fill(filePath, entries, locationNames); } @@ -61,4 +62,4 @@ protected override Boolean LoadInternal() return true; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/SingleFileImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/SingleFileImporter.cs index f45a7e5d7..ff6b8cb0e 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/SingleFileImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/SingleFileImporter.cs @@ -7,15 +7,15 @@ namespace Memoria.Assets public abstract class SingleFileImporter : TextImporter { protected abstract String TypeName { get; } - protected abstract String ImportPath { get; } + protected abstract TextResourceReference ImportPath { get; } protected abstract void ProcessEntries(TxtEntry[] entreis); protected override Boolean LoadExternal() { try { - String importPath = ImportPath; - if (!File.Exists(importPath)) + TextResourceReference importPath = ImportPath; + if (!importPath.IsExists(out TextResourcePath existingFile)) { Log.Warning($"[{TypeName}] Import was skipped bacause a file does not exist: [{importPath}]."); return false; @@ -23,7 +23,7 @@ protected override Boolean LoadExternal() Log.Message($"[{TypeName}] Importing from [{importPath}]..."); - TxtEntry[] entries = TxtReader.ReadStrings(importPath); + TxtEntry[] entries = existingFile.ReadAll(); ProcessEntries(entries); @@ -37,4 +37,4 @@ protected override Boolean LoadExternal() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Import/Text/SkillImporter.cs b/Assembly-CSharp/Memoria/Assets/Import/Text/SkillImporter.cs index b58d91d55..73be6c477 100644 --- a/Assembly-CSharp/Memoria/Assets/Import/Text/SkillImporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Import/Text/SkillImporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public class SkillImporter : SingleFileImporter { protected override String TypeName => nameof(SkillImporter); - protected override String ImportPath => ModTextResources.Import.Skills; + protected override TextResourceReference ImportPath => ModTextResources.Import.Skills; protected override void ProcessEntries(TxtEntry[] entreis) { diff --git a/Assembly-CSharp/Memoria/Assets/Text/CharacterNamesFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/CharacterNamesFormatter.cs index c717d9cda..6ea79b3e1 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/CharacterNamesFormatter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/CharacterNamesFormatter.cs @@ -136,7 +136,7 @@ public static TxtEntry[] Build(String prefix, Dictionary ch TxtEntry[] names = new TxtEntry[characterNames.Count]; Int32 index = 0; foreach (KeyValuePair pair in characterNames) - names[index] = new TxtEntry { Index = (Int32)pair.Key, Prefix = prefix, Value = pair.Value }; + names[index++] = new TxtEntry { Index = (Int32)pair.Key, Prefix = prefix, Value = pair.Value }; return names; } @@ -148,4 +148,4 @@ public static String[] Parse(TxtEntry[] entreis) return result; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/DataResources.cs b/Assembly-CSharp/Memoria/Assets/Text/DataResources.cs index aa841d48d..466795f78 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/DataResources.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/DataResources.cs @@ -41,6 +41,7 @@ public static class Items public static String ItemEffectsFile => "ItemEffects.csv"; public static String ShopItems => "ShopItems.csv"; public static String InitialItemsFile => "InitialItems.csv"; + public static String MixItemsFile => "MixItems.csv"; public static String ItemEquipPatchFile => "ItemEquipPatch.txt"; public static String ModDirectory(String modFolder) @@ -167,4 +168,4 @@ public static String ModDirectory(String modFolder) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxConstructor.cs b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxConstructor.cs index 772295c1c..26d9b3cf9 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxConstructor.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxConstructor.cs @@ -184,6 +184,7 @@ private void PerformMemoriaTag(ref Int32 index, FFIXTextTag tag) OnCharacterName(CharacterId.Steiner); break; case FFIXTextTagCode.Freya: + case FFIXTextTagCode.Fraya: OnCharacterName(CharacterId.Freya); break; case FFIXTextTagCode.Quina: @@ -279,6 +280,12 @@ private void ParseOriginalTag(ref Int32 index, Int32 length) index += 5; return; } + if (a == "[" + NGUIText.NoTurboDialog + "]") + { + UIKeyTrigger.preventTurboKey = true; // Disable turbo dialog manually. (for Trance Seek purpose) + index += 5; + return; + } } Int32 newIndex = index; @@ -382,6 +389,7 @@ private void ParseOriginalTag(ref Int32 index, Int32 length) text3 == "[" + NGUIText.JoyStickButtonIcon || text3 == "[" + NGUIText.KeyboardButtonIcon) { + UIKeyTrigger.preventTurboKey = true; // Disable turbo dialog when a special box appear (Gysahl Greens shop from Chocobo Forest, Eiko when she's cooking, ...) newIndex = Array.IndexOf(_chars, ']', index + 4); String text6 = new String(_chars, index + 6, newIndex - index - 6); if (!FF9StateSystem.MobilePlatform || @@ -489,6 +497,7 @@ private void ParseOriginalTag(ref Int32 index, Int32 length) } else if (text3 == "[" + NGUIText.Choose) { + UIKeyTrigger.preventTurboKey = true; // Disable turbo dialog when a choice appearc Int32 startIndex = Array.IndexOf(_chars, ']', index + 4); OnChoice(startIndex); } @@ -552,7 +561,7 @@ private void OnItemName(Int32 oneParameterFromTag6) { _sb.Append("[C8B040][HSHD]"); _sb.Append(ETb.GetItemName(_textEngine.gMesValue[oneParameterFromTag6])); - _sb.Append("[C8C8C8]"); + _sb.Append("[C8C8C8][HSHD]"); } private void OnVariable(Int32 oneParameterFromTag5) @@ -943,4 +952,4 @@ public static String ProcessJapaneseChoose(String text, Int32 startIndex, Int32[ return text.Replace(sentence, sb.ToString()); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxRenderer.cs b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxRenderer.cs index d886957a0..2b8982109 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxRenderer.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogBoxRenderer.cs @@ -1,5 +1,5 @@ -using System; using Assets.Sources.Scripts.UI.Common; +using System; using UnityEngine; namespace Memoria.Assets @@ -184,6 +184,7 @@ public static Boolean ProcessMemoriaTag(Char[] toCharArray, ref Int32 index, Bet case FFIXTextTagCode.Dagger: case FFIXTextTagCode.Steiner: case FFIXTextTagCode.Freya: + case FFIXTextTagCode.Fraya: case FFIXTextTagCode.Quina: case FFIXTextTagCode.Eiko: case FFIXTextTagCode.Amarant: @@ -247,7 +248,7 @@ private static void PhraseRenderOpcodeSymbol(Char[] text, Int32 index, ref Int32 else if (tag == NGUIText.Shadow) { closingBracket = Array.IndexOf(text, ']', index + 4); - highShadow = true; + highShadow = !highShadow; // The tag seems to be used as a toggle (see issue #397) } else if (tag == NGUIText.NoShadow) { @@ -379,4 +380,4 @@ public static Boolean ProcessOriginalTag(Char[] text, ref Int32 index, ref Boole return true; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogLabelFilter.cs b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogLabelFilter.cs index 389af0ce5..5df0956f4 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogLabelFilter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/DialogLabelFilter.cs @@ -93,6 +93,7 @@ private void ProcessMemoriaTag(FFIXTextTag tag, ref Int32 index) OnCharacterName(CharacterId.Steiner); break; case FFIXTextTagCode.Freya: + case FFIXTextTagCode.Fraya: OnCharacterName(CharacterId.Freya); break; case FFIXTextTagCode.Quina: @@ -328,4 +329,4 @@ private void OnIcon(Int32 oneParameterFromTag) _currentWidth += FF9UIDataTool.GetIconSize(oneParameterFromTag).x; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTag.cs b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTag.cs index ec46851e2..87ab0bfa7 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTag.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTag.cs @@ -181,10 +181,15 @@ public override String ToString() sb.Append('{'); if (EnumCache.IsDefined(Code)) { - sb.Append(Code); + if (Code == FFIXTextTagCode.Fraya) + sb.Append(FFIXTextTagCode.Freya); + else + sb.Append(Code); } else + { sb.Append("Unknown ").Append(((Byte)Code).ToString("X2")); + } if (Param?.Length > 0) { @@ -196,4 +201,4 @@ public override String ToString() return sb.ToString(); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTagCode.cs b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTagCode.cs index 199fe3e00..f0d984c53 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTagCode.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Dialogs/FFIXTextTagCode.cs @@ -22,6 +22,7 @@ public enum FFIXTextTagCode /// [FRYA] /// Freya, + Fraya, // For retro-compatibility /// /// [QUIN] /// @@ -362,4 +363,4 @@ public enum FFIXTextTagCode /// Justified, } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/EmbadedSentenseLoader.cs b/Assembly-CSharp/Memoria/Assets/Text/EmbadedSentenseLoader.cs index 7c117684c..a2ed37d2a 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/EmbadedSentenseLoader.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/EmbadedSentenseLoader.cs @@ -18,7 +18,6 @@ public static String LoadText(String path) public static String[] ExtractSentenseEnd(String text) { String[] split = text.Split(DELIM, StringSplitOptions.None); - int oldsize = split.Length; if (split.Length > 0 && text.EndsWith(DELIM[0])) Array.Resize(ref split, split.Length - 1); return split; @@ -26,4 +25,4 @@ public static String[] ExtractSentenseEnd(String text) private static readonly String[] DELIM = new[] { "[ENDN]" }; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/AbilityExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/AbilityExporter.cs index 6bae98ceb..902d4967e 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/AbilityExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/AbilityExporter.cs @@ -7,7 +7,7 @@ public class AbilityExporter : SingleFileExporter private const String Prefix = "$ability"; protected override String TypeName => nameof(AbilityExporter); - protected override String ExportPath => ModTextResources.Export.Abilities; + protected override TextResourcePath ExportPath => ModTextResources.Export.Abilities; protected override TxtEntry[] PrepareEntries() { @@ -17,4 +17,4 @@ protected override TxtEntry[] PrepareEntries() return AbilityFormatter.Build(Prefix, abilityNames, abilityHelps); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/BattleExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/BattleExporter.cs index a6efbbbef..07e89b33b 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/BattleExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/BattleExporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public sealed class BattleExporter : SingleFileExporter { protected override String TypeName => nameof(BattleExporter); - protected override String ExportPath => ModTextResources.Export.Battle; + protected override TextResourcePath ExportPath => ModTextResources.Export.Battle; protected override TxtEntry[] PrepareEntries() { diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/CharacterNamesExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/CharacterNamesExporter.cs index bf7a5f67d..094205b5f 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/CharacterNamesExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/CharacterNamesExporter.cs @@ -9,7 +9,7 @@ public sealed class CharacterNamesExporter : SingleFileExporter private const String Prefix = "$name"; protected override String TypeName => nameof(CharacterNamesExporter); - protected override String ExportPath => ModTextResources.Export.CharacterNames; + protected override TextResourcePath ExportPath => ModTextResources.Export.CharacterNames; protected override TxtEntry[] PrepareEntries() { diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/CommandExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/CommandExporter.cs index 83a34d445..98d4a07ba 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/CommandExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/CommandExporter.cs @@ -7,7 +7,7 @@ public sealed class CommandExporter : SingleFileExporter private const String Prefix = "$command"; protected override String TypeName => nameof(CommandExporter); - protected override String ExportPath => ModTextResources.Export.Commands; + protected override TextResourcePath ExportPath => ModTextResources.Export.Commands; protected override TxtEntry[] PrepareEntries() { diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/EtcExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/EtcExporter.cs index 7b8e2349c..bdbaedfba 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/EtcExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/EtcExporter.cs @@ -5,7 +5,7 @@ namespace Memoria.Assets public sealed class EtcExporter : SingleFileExporter { protected override String TypeName { get; } - protected override String ExportPath { get; } + protected override TextResourcePath ExportPath { get; } private readonly String _prefix; private readonly String _embadedPath; diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/Fields/FieldExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/Fields/FieldExporter.cs index fd2b425bf..141013523 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/Fields/FieldExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/Fields/FieldExporter.cs @@ -42,8 +42,8 @@ public void Export() TxtEntry[] commands = formatter.Build(name, lines); Directory.CreateDirectory(directory); - String outputPath = Path.Combine(directory, name + ".strings"); - TxtWriter.WriteStrings(outputPath, commands); + TextResourcePath outputPath = TextResourcePath.ForExport(Path.Combine(directory, name)); + outputPath.WriteAll(commands); } ExportTags(directory, formatter); @@ -69,7 +69,7 @@ private static void ExportCustomTags(FieldFormatter formatter) { TxtEntry[] generalNames = formatter.Names.General; if (generalNames != null) - TxtWriter.WriteStrings(ModTextResources.Export.FieldTags, generalNames); + ModTextResources.Export.FieldTags.WriteAll(generalNames); } private static void ExportFieldTags(String directory, FieldFormatter formatter) @@ -80,8 +80,8 @@ private static void ExportFieldTags(String directory, FieldFormatter formatter) foreach (KeyValuePair pair in fieldNames) { - String fieldPath = Path.Combine(directory, pair.Key + "_Tags.strings"); - TxtWriter.WriteStrings(fieldPath, pair.Value); + TextResourcePath fieldPath = TextResourcePath.ForExport(Path.Combine(directory, pair.Key + "_Tags")); + fieldPath.WriteAll(pair.Value); } } @@ -93,4 +93,4 @@ private static String GetFieldTextFileName(Int32 fieldZoneId) return str; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/ItemExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/ItemExporter.cs index 17cde1c72..4ccfaf44f 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/ItemExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/ItemExporter.cs @@ -7,7 +7,7 @@ public sealed class ItemExporter : SingleFileExporter private const String Prefix = "$item"; protected override String TypeName => nameof(ItemExporter); - protected override String ExportPath => ModTextResources.Export.Items; + protected override TextResourcePath ExportPath => ModTextResources.Export.Items; protected override TxtEntry[] PrepareEntries() { diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/KeyItemExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/KeyItemExporter.cs index 3f72889ce..303ff9338 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/KeyItemExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/KeyItemExporter.cs @@ -7,7 +7,7 @@ public sealed class KeyItemExporter : SingleFileExporter private const String Prefix = "$key"; protected override String TypeName => nameof(KeyItemExporter); - protected override String ExportPath => ModTextResources.Export.KeyItems; + protected override TextResourcePath ExportPath => ModTextResources.Export.KeyItems; protected override TxtEntry[] PrepareEntries() { diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/LocalizationExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/LocalizationExporter.cs index 515d9f7c0..05380af79 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/LocalizationExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/LocalizationExporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public sealed class LocalizationExporter : SingleFileExporter { protected override String TypeName => nameof(LocalizationExporter); - protected override String ExportPath => ModTextResources.Export.System; + protected override TextResourcePath ExportPath => ModTextResources.Export.System; protected override TxtEntry[] PrepareEntries() { diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/LocationNameExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/LocationNameExporter.cs index b232576d9..06e1f73da 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/LocationNameExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/LocationNameExporter.cs @@ -41,14 +41,14 @@ public void Export() Char[] invalidChars = Path.GetInvalidFileNameChars(); foreach (KeyValuePair> pair in entries) { - String outputPath = Path.Combine(directory, "Names of " + pair.Key.ReplaceChars("_", invalidChars) + ".strings"); - if (File.Exists(outputPath)) + TextResourcePath outputPath = TextResourcePath.ForExport(Path.Combine(directory, "Names of " + pair.Key.ReplaceChars("_", invalidChars))); + if (File.Exists(outputPath.Value)) { skipped++; continue; } - TxtWriter.WriteStrings(outputPath, pair.Value.ToArray()); + outputPath.WriteAll(pair.Value.ToArray()); } if (skipped > 0) @@ -62,4 +62,4 @@ public void Export() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/SingleFileExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/SingleFileExporter.cs index ae593fa16..6b44795d9 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/SingleFileExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/SingleFileExporter.cs @@ -7,7 +7,7 @@ namespace Memoria.Assets public abstract class SingleFileExporter : IExporter { protected abstract String TypeName { get; } - protected abstract String ExportPath { get; } + protected abstract TextResourcePath ExportPath { get; } protected abstract TxtEntry[] PrepareEntries(); @@ -15,8 +15,8 @@ public void Export() { try { - String exportPath = ExportPath; - if (File.Exists(exportPath)) + TextResourcePath exportPath = ExportPath; + if (File.Exists(exportPath.Value)) { Log.Warning($"[{TypeName}] Export was skipped bacause a file already exists: [{exportPath}]."); return; @@ -24,10 +24,10 @@ public void Export() Log.Message($"[{TypeName}] Exporting..."); - TxtEntry[] abilities = PrepareEntries(); + TxtEntry[] entries = PrepareEntries(); - FileCommander.PrepareFileDirectory(exportPath); - TxtWriter.WriteStrings(exportPath, abilities); + FileCommander.PrepareFileDirectory(exportPath.Value); + exportPath.WriteAll(entries); Log.Message($"[{TypeName}] Exporting completed successfully."); } @@ -37,4 +37,4 @@ public void Export() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Export/SkillExporter.cs b/Assembly-CSharp/Memoria/Assets/Text/Export/SkillExporter.cs index e05fb215b..c5285eb9d 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Export/SkillExporter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Export/SkillExporter.cs @@ -7,7 +7,7 @@ public sealed class SkillExporter : SingleFileExporter private const String Prefix = "$skill"; protected override String TypeName => nameof(SkillExporter); - protected override String ExportPath => ModTextResources.Export.Skills; + protected override TextResourcePath ExportPath => ModTextResources.Export.Skills; protected override TxtEntry[] PrepareEntries() { @@ -17,4 +17,4 @@ protected override TxtEntry[] PrepareEntries() return AbilityFormatter.Build(Prefix, skillNames, skillHelps); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Formatters/BattleFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Formatters/BattleFormatter.cs index cfdb350b0..b52ff9a14 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Formatters/BattleFormatter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Formatters/BattleFormatter.cs @@ -18,7 +18,7 @@ public static class BattleFormatter {"[VIVI]", "{Vivi}"}, {"[DGGR]", "{Dagger}"}, {"[STNR]", "{Steiner}"}, - {"[FRYA]", "{Fraya}"}, + {"[FRYA]", "{Freya}"}, {"[QUIN]", "{Quina}"}, {"[EIKO]", "{Eiko}"}, {"[AMRT]", "{Amarant}"} @@ -30,7 +30,7 @@ public static class BattleFormatter {"[VIVI]", "{Vivi}"}, {"[DGGR]", "{Dagger}"}, {"[STNR]", "{Steiner}"}, - {"[FRYA]", "{Fraya}"}, + {"[FRYA]", "{Freya}"}, {"[QUIN]", "{Quina}"}, {"[EIKO]", "{Eiko}"}, {"[AMRT]", "{Amarant}"}, @@ -301,4 +301,4 @@ private static Boolean TryGetNextTag(String str, String starting, StringBuilder return true; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Formatters/FieldFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Formatters/FieldFormatter.cs index 16e09089c..3cd7d7c2d 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Formatters/FieldFormatter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Formatters/FieldFormatter.cs @@ -25,7 +25,7 @@ public TxtEntry[] Build(String name, String[] lines) } else if (!Cache.TryGetValue(line, out key)) { - key = StringsFormatter.FormatKeyIndex(postfix, entries.Count); + key = TextFormatterHelper.CreateKey(postfix, entries.Count); Cache.Add(line, key); entry.Value = FormatValue(name, line); } @@ -40,7 +40,7 @@ public TxtEntry[] Build(String name, String[] lines) private String GetLine(String[] lines, ref Int32 index) { - if (Configuration.Export.TextFormat <= 1) + if (Configuration.Export.TextContentFormat <= 1) return lines[index]; // Not supported https://github.com/Albeoris/Memoria/wiki/Different-identifiers-in-different-languages @@ -93,4 +93,4 @@ private static String RemoveInternalTags(String str) return sb.ToString(); } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Formatters/LocationNameFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Formatters/LocationNameFormatter.cs index acdef931e..b2694c8bf 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/Formatters/LocationNameFormatter.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/Formatters/LocationNameFormatter.cs @@ -36,7 +36,7 @@ private static void AddEntry(String[] parts, Int32 index, LinkedList l { if (parts.Length > 1) { - TxtEntry entry = new TxtEntry {Prefix = Prefix, Index = index, Value = parts[1]}; + TxtEntry entry = new TxtEntry { Prefix = Prefix, Index = index, Value = parts[1] }; list.AddLast(entry); } else @@ -55,7 +55,7 @@ private static LinkedList GetList(Dictionary(); dic.Add(fileName, list); - TxtEntry entry = new TxtEntry {Prefix = RootPrefix, Index = dic.Count, Value = fileName}; + TxtEntry entry = new TxtEntry { Prefix = RootPrefix, Index = dic.Count, Value = fileName }; list.AddLast(entry); return list; } @@ -88,10 +88,16 @@ public static void Fill(String filePath, TxtEntry[] entries, Dictionary not used + "$location0750": "Gate", => 750 : Burmecia/Gate + "$location0751": "Suburb", => 751 : Burmecia/Suburb + } + */ + TxtEntry header = entries[0]; - String prefix = firstEntry.Value + '/'; + String prefix = header.Value + '/'; for (Int32 i = 1; i < entries.Length; i++) { TxtEntry entry = entries[i]; @@ -100,4 +106,4 @@ public static void Fill(String filePath, TxtEntry[] entries, DictionaryFor keys not present in vanilla + public static String GetWithDefault(String key) + { + String value = Provider.Get(key); + if (!String.Equals(value, key)) + return value; + if (_defaultDictionary.TryGetValue(key, out value)) + return value; + return key; + } + + private static Dictionary _defaultDictionary = new Dictionary() + { + { "GilSymbol", "%[YSUB=1.3][sub]G" } + }; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/ModTextResources.cs b/Assembly-CSharp/Memoria/Assets/Text/ModTextResources.cs index e18d7e322..bbc37cf07 100644 --- a/Assembly-CSharp/Memoria/Assets/Text/ModTextResources.cs +++ b/Assembly-CSharp/Memoria/Assets/Text/ModTextResources.cs @@ -6,25 +6,25 @@ namespace Memoria.Assets { public static class ModTextResources { - public const String SystemPath = "/System.strings"; - private const String AbilitiesPath = "/Abilities.strings"; - private const String CommandsPath = "/Commands.strings"; - private const String SkillsPath = "/Skills.strings"; - private const String BattlePath = "/Battle.strings"; - private const String ItemsPath = "/Items.strings"; - private const String KeyItemsPath = "/KeyItems.strings"; - private const String CardLevelsPath = "/ETC/CardLevels.strings"; - private const String CardTitlesPath = "/ETC/CardTitles.strings"; - private const String BattleCommandsPath = "/ETC/BattleCommands.strings"; - private const String BattleMessagesPath = "/ETC/BattleMessages.strings"; - private const String LibraPath = "/ETC/Libra.strings"; - private const String WorldLocationsPath = "/ETC/WorldLocations.strings"; - private const String ChocoboPath = "/ETC/Chocobo.strings"; + public static TextResourceReference SystemReference => new("/System"); + private static TextResourceReference AbilitiesReference => new("/Abilities"); + private static TextResourceReference CommandsReference => new("/Commands"); + private static TextResourceReference SkillsReference => new("/Skills"); + private static TextResourceReference BattleReference => new("/Battle"); + private static TextResourceReference ItemsReference => new("/Items"); + private static TextResourceReference KeyItemsReference => new("/KeyItems"); + private static TextResourceReference CardLevelsReference => new("/ETC/CardLevels"); + private static TextResourceReference CardTitlesReference => new("/ETC/CardTitles"); + private static TextResourceReference BattleCommandsReference => new("/ETC/BattleCommands"); + private static TextResourceReference BattleMessagesReference => new("/ETC/BattleMessages"); + private static TextResourceReference LibraReference => new("/ETC/Libra"); + private static TextResourceReference WorldLocationsReference => new("/ETC/WorldLocations"); + private static TextResourceReference ChocoboReference => new("/ETC/Chocobo"); private const String LocationNamesDirectoryPath = "/Location"; private const String FieldsDirectoryPath = "/Field"; - private const String FieldTagsPath = FieldsDirectoryPath + "/FieldTags.strings"; - private const String CharacterNamesPath = "/CharacterNames.strings"; + private static TextResourceReference FieldTagsReference => new(FieldsDirectoryPath + "/FieldTags"); + private static TextResourceReference CharacterNamesReference => new("/CharacterNames"); private const String ManifestDirectoryPath = "/Manifest"; private const String CreditsAmazonPath = "/StaffCredits_Amazon.txt"; @@ -37,22 +37,22 @@ public static class ModTextResources public static class Export { public static String CurrentSymbol { get; set; } - public static String System => GetCurrentPath(SystemPath); - public static String Abilities => GetCurrentPath(AbilitiesPath); - public static String Commands => GetCurrentPath(CommandsPath); - public static String Skills => GetCurrentPath(SkillsPath); - public static String Battle => GetCurrentPath(BattlePath); - public static String Items => GetCurrentPath(ItemsPath); - public static String KeyItems => GetCurrentPath(KeyItemsPath); - public static String CardLevels => GetCurrentPath(CardLevelsPath); - public static String CardTitles => GetCurrentPath(CardTitlesPath); - public static String BattleCommands => GetCurrentPath(BattleCommandsPath); - public static String BattleMessages => GetCurrentPath(BattleMessagesPath); - public static String Libra => GetCurrentPath(LibraPath); - public static String WorldLocations => GetCurrentPath(WorldLocationsPath); - public static String Chocobo => GetCurrentPath(ChocoboPath); - public static String FieldTags => GetCurrentPath(FieldTagsPath); - public static String CharacterNames => GetCurrentPath(CharacterNamesPath); + public static TextResourcePath System => GetCurrentPath(SystemReference); + public static TextResourcePath Abilities => GetCurrentPath(AbilitiesReference); + public static TextResourcePath Commands => GetCurrentPath(CommandsReference); + public static TextResourcePath Skills => GetCurrentPath(SkillsReference); + public static TextResourcePath Battle => GetCurrentPath(BattleReference); + public static TextResourcePath Items => GetCurrentPath(ItemsReference); + public static TextResourcePath KeyItems => GetCurrentPath(KeyItemsReference); + public static TextResourcePath CardLevels => GetCurrentPath(CardLevelsReference); + public static TextResourcePath CardTitles => GetCurrentPath(CardTitlesReference); + public static TextResourcePath BattleCommands => GetCurrentPath(BattleCommandsReference); + public static TextResourcePath BattleMessages => GetCurrentPath(BattleMessagesReference); + public static TextResourcePath Libra => GetCurrentPath(LibraReference); + public static TextResourcePath WorldLocations => GetCurrentPath(WorldLocationsReference); + public static TextResourcePath Chocobo => GetCurrentPath(ChocoboReference); + public static TextResourcePath FieldTags => GetCurrentPath(FieldTagsReference); + public static TextResourcePath CharacterNames => GetCurrentPath(CharacterNamesReference); public static String LocationNamesDirectory => GetCurrentPath(LocationNamesDirectoryPath); public static String FieldsDirectory => GetCurrentPath(FieldsDirectoryPath); @@ -64,9 +64,15 @@ public static class Export public static String CreditsSteam => ManifestDirectory + CreditsSteamPath; public static String Credits => ManifestDirectory + CreditsPath; + public static TextResourcePath GetCurrentPath(TextResourceReference relativeReference) + { + String currentPath = GetCurrentPath(relativeReference.Value); + return new TextResourcePath(new TextResourceReference(currentPath), Configuration.Export.TextFileFormat); + } + public static String GetCurrentPath(String relativePath) { - StringBuilder sb = new StringBuilder(64); + StringBuilder sb = new(64); sb.Append(Configuration.Export.Path); if (sb.Length > 0 && sb[sb.Length - 1] != '/' && sb[sb.Length - 1] != '\\') sb.Append('/'); @@ -79,21 +85,21 @@ public static String GetCurrentPath(String relativePath) public static class Import { - public static String Abilities => GetCurrentPath(AbilitiesPath); - public static String Commands => GetCurrentPath(CommandsPath); - public static String Skills => GetCurrentPath(SkillsPath); - public static String Battle => GetCurrentPath(BattlePath); - public static String Items => GetCurrentPath(ItemsPath); - public static String KeyItems => GetCurrentPath(KeyItemsPath); - public static String CardLevels => GetCurrentPath(CardLevelsPath); - public static String CardTitles => GetCurrentPath(CardTitlesPath); - public static String BattleCommands => GetCurrentPath(BattleCommandsPath); - public static String BattleMessages => GetCurrentPath(BattleMessagesPath); - public static String Libra => GetCurrentPath(LibraPath); - public static String WorldLocations => GetCurrentPath(WorldLocationsPath); - public static String Chocobo => GetCurrentPath(ChocoboPath); - public static String FieldTags => GetCurrentPath(FieldTagsPath); - public static String CharacterNames => GetCurrentPath(CharacterNamesPath); + public static TextResourceReference Abilities => GetCurrentPath(AbilitiesReference); + public static TextResourceReference Commands => GetCurrentPath(CommandsReference); + public static TextResourceReference Skills => GetCurrentPath(SkillsReference); + public static TextResourceReference Battle => GetCurrentPath(BattleReference); + public static TextResourceReference Items => GetCurrentPath(ItemsReference); + public static TextResourceReference KeyItems => GetCurrentPath(KeyItemsReference); + public static TextResourceReference CardLevels => GetCurrentPath(CardLevelsReference); + public static TextResourceReference CardTitles => GetCurrentPath(CardTitlesReference); + public static TextResourceReference BattleCommands => GetCurrentPath(BattleCommandsReference); + public static TextResourceReference BattleMessages => GetCurrentPath(BattleMessagesReference); + public static TextResourceReference Libra => GetCurrentPath(LibraReference); + public static TextResourceReference WorldLocations => GetCurrentPath(WorldLocationsReference); + public static TextResourceReference Chocobo => GetCurrentPath(ChocoboReference); + public static TextResourceReference FieldTags => GetCurrentPath(FieldTagsReference); + public static TextResourceReference CharacterNames => GetCurrentPath(CharacterNamesReference); public static String LocationNamesDirectory => GetCurrentPath(LocationNamesDirectoryPath); public static String FieldsDirectory => GetCurrentPath(FieldsDirectoryPath); @@ -106,14 +112,26 @@ public static class Import public static String CreditsSteam => ManifestDirectory + CreditsSteamPath; public static String Credits => ManifestDirectory + CreditsPath; + public static TextResourceReference GetCurrentPath(TextResourceReference relativeReference) + { + String currentPath = GetCurrentPath(relativeReference.Value); + return new TextResourceReference(currentPath); + } + public static String GetCurrentPath(String relativePath) { return GetSymbolPath(Localization.GetSymbol(), relativePath); } + public static TextResourceReference GetSymbolPath(String symbol, TextResourceReference relativeReference) + { + String currentPath = GetSymbolPath(symbol, relativeReference.Value); + return new TextResourceReference(currentPath); + } + public static String GetSymbolPath(String symbol, String relativePath) { - StringBuilder sb = new StringBuilder(64); + StringBuilder sb = new(64); sb.Append(Configuration.Import.Path); if (sb.Length > 0 && sb[sb.Length - 1] != '/' && sb[sb.Length - 1] != '\\') sb.Append('/'); @@ -124,4 +142,4 @@ public static String GetSymbolPath(String symbol, String relativePath) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextFormatter.cs new file mode 100644 index 000000000..d4aa5c2b9 --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextFormatter.cs @@ -0,0 +1,10 @@ +using System.IO; + +namespace Memoria.Assets +{ + public interface ITextFormatter + { + ITextWriter GetWriter(); + ITextReader GetReader(); + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextReader.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextReader.cs new file mode 100644 index 000000000..adc07b38e --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextReader.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace Memoria.Assets +{ + public interface ITextReader + { + TxtEntry[] ReadAll(String inputPath); + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextWriter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextWriter.cs new file mode 100644 index 000000000..f27b831c6 --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITextWriter.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace Memoria.Assets +{ + public interface ITextWriter + { + void WriteAll(String outputPath, IList entries); + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/ITxtFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/ITxtFormatter.cs deleted file mode 100644 index c2c229dba..000000000 --- a/Assembly-CSharp/Memoria/Assets/Text/Strings/ITxtFormatter.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.IO; - -namespace Memoria.Assets -{ - public interface ITxtFormatter - { - void Write(StreamWriter sw, TxtEntry entry); - TxtEntry Read(StreamReader sr); - } -} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/StringsFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/StringsFormatter.cs deleted file mode 100644 index 1928686ba..000000000 --- a/Assembly-CSharp/Memoria/Assets/Text/Strings/StringsFormatter.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Text; -using Memoria.Prime.Exceptions; - -namespace Memoria.Assets -{ - public sealed class StringsFormatter : ITxtFormatter - { - private static readonly StringsFormatter LazyInstance = new StringsFormatter(); - - public static StringsFormatter Instance - { - get { return LazyInstance; } - } - - public void Write(StreamWriter sw, TxtEntry entry) - { - sw.WriteLine("\"{0}\" = \"{1}\";", - FormatKeyIndex(entry.Prefix, entry.Index), - entry.Value.Replace("\\", "\\\\").Replace("\"", "\\\"")); - } - - public static String FormatKeyIndex(String prefix, Int32 index) - { - return prefix + index.ToString("D4", CultureInfo.InvariantCulture); - } - - public TxtEntry Read(StreamReader sr) - { - Int32 index = -1; - TxtEntry result = new TxtEntry(); - - StringBuilder sb = new StringBuilder(512); - Boolean key = true; - Boolean block = false; - Boolean escape = false; - Int32 line = 0; - try - { - while (true) - { - Int32 value = sr.Read(); - if (value < 0) - { - if (sb.Length == 0) - return null; - - throw new Exception("Unexpected end of stream."); - } - - Char ch = (Char)value; - switch (ch) - { - case '\\': - { - if (!block) - continue; - - if (escape) - { - AppendLines(ref line, sb); - sb.Append('\\'); - escape = false; - } - else - { - escape = true; - } - break; - } - case '"': - { - if (escape) - { - AppendLines(ref line, sb); - sb.Append('"'); - escape = false; - } - else - { - if (block) - { - if (key) - { - if (sb.Length > 4) - result.Prefix = sb.ToString(0, sb.Length - 4); - - index = Int32.Parse(sb.ToString(sb.Length - 4, 4), CultureInfo.InvariantCulture); - key = false; - } - else - { - result.Index = index; - result.Value = sb.ToString(); - return result; - } - block = false; - sb.Length = 0; - } - else - { - block = true; - } - } - break; - } - case '\r': - { - if (!block) - continue; - - break; - } - case '\n': - { - if (!block) - continue; - - line++; - break; - } - default: - { - if (!block) - continue; - - if (escape) - { - sb.Append('\\'); - escape = false; - } - - AppendLines(ref line, sb); - sb.Append(ch); - break; - } - } - } - } - catch (Exception ex) - { - throw new Exception($"Cannot parse .strings entry.\r\n[Index: {result.Index}, Prefix: {result.Prefix}, Value: {result.Value}]\r\n[Buffer: {sb}, Line: {line} IsKey: {key}, IsBlock: {block}, IsEscape: {escape}]", ex); - } - } - - private static void AppendLines(ref Int32 line, StringBuilder sb) - { - if (line > 0) - { - for (Int32 i = 0; i < line; i++) - sb.Append('\n'); - line = 0; - } - } - } -} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextFormatterHelper.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextFormatterHelper.cs new file mode 100644 index 000000000..767c60d52 --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextFormatterHelper.cs @@ -0,0 +1,42 @@ +using System; +using System.Globalization; +using System.Text; + +namespace Memoria.Assets +{ + public static class TextFormatterHelper + { + public static String CreateKey(this TxtEntry entry) + { + return CreateKey(entry.Prefix, entry.Index); + } + + public static void SetKey(this TxtEntry entry, String key) + { + ParseKey(key, out entry.Prefix, out entry.Index); + } + + public static String CreateKey(String prefix, Int32 index) + { + return prefix + index.ToString("D4", CultureInfo.InvariantCulture); + } + + public static void ParseKey(String key, out String prefix, out Int32 index) + { + prefix = key.Length > 4 + ? key.Substring(startIndex: 0, length: key.Length - 4) + : String.Empty; + + index = Int32.Parse(key.Substring(startIndex: key.Length - 4, length: 4), CultureInfo.InvariantCulture); + } + + public static void ParseKey(StringBuilder key, out String prefix, out Int32 index) + { + prefix = key.Length > 4 + ? key.ToString(startIndex: 0, length: key.Length - 4) + : String.Empty; + + index = Int32.Parse(key.ToString(startIndex: key.Length - 4, length: 4), CultureInfo.InvariantCulture); + } + } +} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResjsonFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResjsonFormatter.cs new file mode 100644 index 000000000..5b814fd33 --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResjsonFormatter.cs @@ -0,0 +1,72 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Memoria.Assets +{ + public sealed class TextResjsonFormatter : ITextFormatter + { + public static ITextFormatter Instance { get; } = new TextResjsonFormatter(); + + public ITextWriter GetWriter() => new Writer(); + public ITextReader GetReader() => new Reader(); + + private sealed class Writer : ITextWriter + { + public void WriteAll(String outputPath, IList entries) + { + using (StreamWriter sw = File.CreateText(outputPath)) + using (JsonTextWriter writer = new(sw)) + { + writer.Formatting = Formatting.Indented; + writer.WriteStartObject(); + { + foreach (TxtEntry entry in entries) + { + writer.WritePropertyName(entry.CreateKey()); + writer.WriteValue(entry.Value); + } + } + writer.WriteEndObject(); + } + } + } + + private sealed class Reader : ITextReader + { + public TxtEntry[] ReadAll(String inputPath) + { + List entries = new(capacity: 128); + + using (StreamReader sr = File.OpenText(inputPath)) + using (JsonTextReader reader = new(sr)) + { + if (!reader.Read()) + return entries.ToArray(); // File is empty + + if (reader.TokenType != JsonToken.StartObject) + throw new FormatException("if (json.TokenType != JsonToken.StartObject)"); + + while (reader.Read()) + { + if (reader.TokenType == JsonToken.PropertyName) + { + String key = (String)reader.Value; + if (!reader.Read() || reader.TokenType != JsonToken.String) + throw new FormatException("if (!reader.Read() || reader.TokenType != JsonToken.String)"); + + String value = (String)reader.Value; + TxtEntry entry = new(); + entry.SetKey(key); + entry.Value = value; + entries.Add(entry); + } + } + } + + return entries.ToArray(); + } + } + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceFormat.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceFormat.cs new file mode 100644 index 000000000..5ded2a9c5 --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceFormat.cs @@ -0,0 +1,26 @@ +namespace Memoria.Assets +{ + public enum TextResourceFormat + { + /// + /// Apple Strings (.strings)
+ /// The standard strings file format consists of one or more key-value pairs along with optional comments. The key and value in a given pair are strings of text enclosed in double quotation marks, separated by an equals sign, and ending with a semicolon. + ///
+ /// + /// /* Comment */
+ /// "$0002_EVT_STARTUP_RYOTA_1_0041" = "{W63H2}{Widths 0,0,16,-1,0,63,16,-1}{Zidane}\n“It’s me, {Zidane}!”";
+ ///
+ Strings = 10, + + /// + /// Windows JSON (.resjson) + /// Key-value pairs are delimited with colons (:), surrounded by quotes ("), comma separated. + /// + /// + /// {
+ /// "$0002_EVT_STARTUP_RYOTA_1_0041" : "{W63H2}{Widths 0,0,16,-1,0,63,16,-1}{Zidane}\n“It’s me, {Zidane}!”",
+ /// } + ///
+ Resjson = 20, + } +} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceFormatHelper.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceFormatHelper.cs new file mode 100644 index 000000000..308cd00ef --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceFormatHelper.cs @@ -0,0 +1,39 @@ +using System; + +namespace Memoria.Assets +{ + public static class TextResourceFormatHelper + { + public static String GetFileExtension(this TextResourceFormat format) + { + return format switch + { + TextResourceFormat.Strings => ".strings", + TextResourceFormat.Resjson => ".resjson", + _ => throw new ArgumentOutOfRangeException(nameof(format), format, $"Format {format} is not supported.") + }; + } + + public static TextResourceFormat ResolveFileFormat(String fileExtension) + { + if (TryResolveFileFormat(fileExtension, out TextResourceFormat format)) + return format; + + throw new ArgumentException(fileExtension); + } + + public static Boolean TryResolveFileFormat(String fileExtension, out TextResourceFormat format) + { + String extension = fileExtension?.ToLowerInvariant(); + + format = extension switch + { + ".strings" => TextResourceFormat.Strings, + ".resjson" => TextResourceFormat.Resjson, + _ => default + }; + + return format != default; + } + } +} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourcePath.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourcePath.cs new file mode 100644 index 000000000..75f6b9933 --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourcePath.cs @@ -0,0 +1,69 @@ +using Memoria.Prime.Exceptions; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Memoria.Assets +{ + public readonly struct TextResourcePath + { + public String Value { get; } + public TextResourceFormat Format { get; } + + public TextResourcePath(TextResourceReference reference, TextResourceFormat format) + { + Exceptions.ThrowIfNullOrEmprty(reference.Value, nameof(reference)); + Exceptions.ThrowIfDefault(format, nameof(format)); + + Value = reference.Value + format.GetFileExtension(); + Format = format; + } + + public static TextResourcePath ForExport(String outputPath) + { + TextResourceReference reference = new(outputPath); + return new TextResourcePath(reference, Configuration.Export.TextFileFormat); + } + + public static TextResourcePath ForImportExistingFile(String existingPath) + { + if (!File.Exists(existingPath)) + throw new FileNotFoundException(existingPath); + + String extension = Path.GetExtension(existingPath); + TextResourceFormat format = TextResourceFormatHelper.ResolveFileFormat(extension); + TextResourceReference reference = new(existingPath); + return new TextResourcePath(reference, format); + } + + public bool Equals(TextResourcePath other) => Value == other.Value; + public override Boolean Equals(object obj) => obj is TextResourcePath other && Equals(other); + public override Int32 GetHashCode() => (Value != null ? Value.GetHashCode() : 0); + public override String ToString() => Value; + + public ITextFormatter GetFormatter() + { + return Format switch + { + TextResourceFormat.Strings => TextStringsFormatter.Instance, + TextResourceFormat.Resjson => TextResjsonFormatter.Instance, + _ => throw new NotSupportedException(Format.ToString()) + }; + } + + public void WriteAll(IList entries) + { + for (Int32 i = 0; i < entries.Count; i++) + entries[i].TryUpdateIndex(i); + + ITextFormatter formatter = GetFormatter(); + formatter.GetWriter().WriteAll(Value, entries); + } + + public TxtEntry[] ReadAll() + { + ITextFormatter formatter = GetFormatter(); + return formatter.GetReader().ReadAll(Value); + } + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceReference.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceReference.cs new file mode 100644 index 000000000..6a886106e --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextResourceReference.cs @@ -0,0 +1,39 @@ +using Memoria.Prime; +using Memoria.Prime.Exceptions; +using System; +using System.IO; + +namespace Memoria.Assets +{ + public readonly struct TextResourceReference + { + public String Value { get; } + + public TextResourceReference(String filePath) + { + Exceptions.ThrowIfNullOrEmprty(filePath, nameof(filePath)); + Value = filePath; + } + + public Boolean Equals(TextResourceReference other) => Value == other.Value; + public override Boolean Equals(object obj) => obj is TextResourceReference other && Equals(other); + public override Int32 GetHashCode() => (Value != null ? Value.GetHashCode() : 0); + public override String ToString() => Value; + + public bool IsExists(out TextResourcePath existingFile) + { + foreach (TextResourceFormat format in EnumCache.Values) + { + TextResourcePath path = new(this, format); + if (File.Exists(path.Value)) + { + existingFile = path; + return true; + } + } + + existingFile = default; + return false; + } + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TextStringsFormatter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextStringsFormatter.cs new file mode 100644 index 000000000..0f026819f --- /dev/null +++ b/Assembly-CSharp/Memoria/Assets/Text/Strings/TextStringsFormatter.cs @@ -0,0 +1,255 @@ +using Memoria.Prime; +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Collections.Generic; + +namespace Memoria.Assets +{ + public sealed class TextStringsFormatter : ITextFormatter + { + public static ITextFormatter Instance { get; } = new TextStringsFormatter(); + + public ITextWriter GetWriter() => new Writer(); + public ITextReader GetReader() => new Reader(); + + private sealed class Writer : ITextWriter + { + public void WriteAll(String outputPath, IList entries) + { + using (StreamWriter sw = File.CreateText(outputPath)) + { + sw.WriteLine("/*"); + sw.WriteLine(outputPath); + sw.WriteLine(entries.Count.ToString("D4", CultureInfo.InvariantCulture)); + sw.WriteLine("*/"); + + foreach (TxtEntry entry in entries) + { + String key = TextFormatterHelper.CreateKey(entry.Prefix, entry.Index); + String value = entry.Value + .Replace("\\", "\\\\") + .Replace("\"", "\\\""); + + sw.WriteLine($"\"{key}\" = \"{value}\";"); + } + } + } + } + + private sealed class Reader : ITextReader + { + public TxtEntry[] ReadAll(String inputPath) + { + using (StreamReader sr = File.OpenText(inputPath)) + { + String countStr = null; + + Boolean comment = false; + for (int i = 0; i < 2 || comment;) + { + String value = sr.ReadLine(); + if (value.StartsWith("/*")) + { + comment = true; + value = value.Substring(2); + } + + if (value.EndsWith("*/")) + { + comment = false; + value = value.Substring(0, value.Length - 2); + } + + value = value.Trim(); + + if (!String.IsNullOrEmpty(value)) + { + if (i == 0) + _ = value; // file path, not used + else + countStr = value; + + i++; + } + } + + Int32 count = Int32.Parse(countStr, CultureInfo.InvariantCulture); + TxtEntry[] result = new TxtEntry[count]; + + Int32 offset = 0; + for (Int32 i = 0; i < count && !sr.EndOfStream; i++) + { + TxtEntry entry; + try + { + entry = Read(sr); + } + catch (Exception ex) + { + if (i > 0) + { + TxtEntry previous = result[i - 1]; + throw new Exception($"Cannot read {i} entry from {inputPath}.\r\nPrevious: [Index: {previous.Index}, Pefix: {previous.Prefix}, Value: {previous.Value}]", ex); + } + else + { + throw new Exception($"Cannot read {i} entry from {inputPath}.", ex); + + } + } + + if (entry == null) + { + offset++; + continue; + } + + if (String.IsNullOrEmpty(entry.Prefix)) + { + Log.Warning("Invalid record [Line: {0}, Value: {1}] in the file: {2}", i, entry, inputPath); + offset++; + continue; + } + + result[i - offset] = entry; + } + + return result; + } + } + + public TxtEntry Read(StreamReader sr) + { + Int32 index = -1; + TxtEntry result = new TxtEntry(); + + StringBuilder sb = new StringBuilder(512); + Boolean key = true; + Boolean block = false; + Boolean escape = false; + Int32 line = 0; + try + { + while (true) + { + Int32 value = sr.Read(); + if (value < 0) + { + if (sb.Length == 0) + return null; + + throw new Exception("Unexpected end of stream."); + } + + Char ch = (Char)value; + switch (ch) + { + case '\\': + { + if (!block) + continue; + + if (escape) + { + AppendLines(ref line, sb); + sb.Append('\\'); + escape = false; + } + else + { + escape = true; + } + + break; + } + case '"': + { + if (escape) + { + AppendLines(ref line, sb); + sb.Append('"'); + escape = false; + } + else + { + if (block) + { + if (key) + { + if (sb.Length > 4) + result.Prefix = sb.ToString(0, sb.Length - 4); + + index = Int32.Parse(sb.ToString(sb.Length - 4, 4), CultureInfo.InvariantCulture); + key = false; + } + else + { + result.Index = index; + result.Value = sb.ToString(); + return result; + } + + block = false; + sb.Length = 0; + } + else + { + block = true; + } + } + + break; + } + case '\r': + { + if (!block) + continue; + + break; + } + case '\n': + { + if (!block) + continue; + + line++; + break; + } + default: + { + if (!block) + continue; + + if (escape) + { + sb.Append('\\'); + escape = false; + } + + AppendLines(ref line, sb); + sb.Append(ch); + break; + } + } + } + } + catch (Exception ex) + { + throw new Exception($"Cannot parse .strings entry.\r\n[Index: {result.Index}, Prefix: {result.Prefix}, Value: {result.Value}]\r\n[Buffer: {sb}, Line: {line} IsKey: {key}, IsBlock: {block}, IsEscape: {escape}]", ex); + } + } + + private static void AppendLines(ref Int32 line, StringBuilder sb) + { + if (line > 0) + { + for (Int32 i = 0; i < line; i++) + sb.Append('\n'); + line = 0; + } + } + } + } +} diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TxtReader.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TxtReader.cs deleted file mode 100644 index a9d7bcb00..000000000 --- a/Assembly-CSharp/Memoria/Assets/Text/Strings/TxtReader.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Text; -using Memoria.Prime; - -namespace Memoria.Assets -{ - public sealed class TxtReader - { - private readonly Stream _input; - private readonly ITxtFormatter _formatter; - - public TxtReader(Stream input, ITxtFormatter formatter) - { - _input = input; - _formatter = formatter; - } - - public TxtEntry[] Read(out String name) - { - name = null; - - using (StreamReader sr = new StreamReader(_input, Encoding.UTF8, true, 4096)) - { - String countStr = null; - - if (_formatter is StringsFormatter) // TEMP - { - Boolean comment = false; - for (int i = 0; i < 2 || comment;) - { - String value = sr.ReadLine(); - if (value.StartsWith("/*")) - { - comment = true; - value = value.Substring(2); - } - if (value.EndsWith("*/")) - { - comment = false; - value = value.Substring(0, value.Length - 2); - } - value = value.Trim(); - - if (!String.IsNullOrEmpty(value)) - { - if (i == 0) - name = value; - else - countStr = value; - - i++; - } - } - } - else - { - name = sr.ReadLine(); - countStr = sr.ReadLine(); - } - - Int32 count = Int32.Parse(countStr, CultureInfo.InvariantCulture); - TxtEntry[] result = new TxtEntry[count]; - - Int32 offset = 0; - for (Int32 i = 0; i < count && !sr.EndOfStream; i++) - { - TxtEntry entry; - try - { - entry = _formatter.Read(sr); - } - catch (Exception ex) - { - if (i > 0) - { - TxtEntry previous = result[i - 1]; - throw new Exception($"Cannot read {i} entry from {name}.\r\nPrevious: [Index: {previous.Index}, Pefix: {previous.Prefix}, Value: {previous.Value}]", ex); - } - else - { - throw new Exception($"Cannot read {i} entry from {name}.", ex); - - } - } - if (entry == null) - { - offset++; - continue; - } - - if (String.IsNullOrEmpty(entry.Prefix)) - { - Log.Warning("Invalid record [Line: {0}, Value: {1}] in the file: {2}", i, entry, name); - offset++; - continue; - } - - result[i - offset] = entry; - } - - return result; - } - } - - public static TxtEntry[] ReadStrings(String inputPath) - { - String name; - using (FileStream output = File.OpenRead(inputPath)) - return new TxtReader(output, StringsFormatter.Instance).Read(out name); - } - } -} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Assets/Text/Strings/TxtWriter.cs b/Assembly-CSharp/Memoria/Assets/Text/Strings/TxtWriter.cs deleted file mode 100644 index 6394a3e01..000000000 --- a/Assembly-CSharp/Memoria/Assets/Text/Strings/TxtWriter.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; - -namespace Memoria.Assets -{ - public sealed class TxtWriter - { - private readonly Stream _output; - private readonly ITxtFormatter _formatter; - - public TxtWriter(Stream output, ITxtFormatter formatter) - { - _output = output; - _formatter = formatter; - } - - public void Write(String name, IList entries) - { - using (StreamWriter sw = new StreamWriter(_output, Encoding.UTF8, 4096)) - { - if (_formatter is StringsFormatter) // TEMP - { - sw.WriteLine("/*"); - sw.WriteLine(name); - sw.WriteLine(entries.Count.ToString("D4", CultureInfo.InvariantCulture)); - sw.WriteLine("*/"); - } - else - { - sw.WriteLine(name); - sw.WriteLine(entries.Count.ToString("D4", CultureInfo.InvariantCulture)); - } - - for (Int32 i = 0; i < entries.Count; i++) - { - TxtEntry entry = entries[i]; - entry.TryUpdateIndex(i); - _formatter.Write(sw, entry); - } - } - } - - public static void WriteStrings(String outputPath, IList entries) - { - using (FileStream output = File.Create(outputPath)) - new TxtWriter(output, StringsFormatter.Instance).Write(outputPath, entries); - } - } -} \ No newline at end of file diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/BattleCalculator.cs b/Assembly-CSharp/Memoria/Battle/Calculator/BattleCalculator.cs index f205dde18..98186d82a 100644 --- a/Assembly-CSharp/Memoria/Battle/Calculator/BattleCalculator.cs +++ b/Assembly-CSharp/Memoria/Battle/Calculator/BattleCalculator.cs @@ -18,7 +18,7 @@ public static void SetBattleFollowMessage(BattleMesages message, EffectElement e public static void SetBattleFollowFormatMessage(BattleMesages message, params Object[] args) { - UIManager.Battle.SetBattleFollowMessage(message, args); + UIManager.Battle.SetBattleFollowMessage(message, args != null && args.Length > 0 ? args[0] : null); } public static void SetBattleFollowFormatMessage(Byte priority, String formatMessage, params Object[] args) @@ -87,7 +87,7 @@ public static Int32 TargetCount(Boolean isPlayer) public static Int32 BattleUnitCount(Boolean isPlayer) { Int32 count = 0; - Byte playerByte = isPlayer ? (Byte)1: (Byte)0; + Byte playerByte = isPlayer ? (Byte)1 : (Byte)0; for (BTL_DATA next = FF9StateSystem.Battle.FF9Battle.btl_list.next; next != null; next = next.next) if (next.bi.player == playerByte) count++; @@ -781,4 +781,4 @@ public void RaiseTrouble() Target.Data.fig_info |= Param.FIG_INFO_TROUBLE; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/BattleCommand.cs b/Assembly-CSharp/Memoria/Battle/Calculator/BattleCommand.cs index 25f106aad..aa38b8543 100644 --- a/Assembly-CSharp/Memoria/Battle/Calculator/BattleCommand.cs +++ b/Assembly-CSharp/Memoria/Battle/Calculator/BattleCommand.cs @@ -116,6 +116,8 @@ public Boolean IsShortSummon set => Data.info.short_summon = (Byte)(value ? 1 : 0); } public Boolean IsZeroMP => Data.info.IsZeroMP; + public Int32 CommandMPCost => Data.GetCommandMPCost(); // This takes AA features into account but not increased summon cost early on or player MP cost factor + public BattleCommandMenu CommandMenu => Data.info.cmdMenu; public Boolean IsDevided => IsManyTarget && (Int32)Data.aa.Info.Target > 2 && (Int32)Data.aa.Info.Target < 6; @@ -183,4 +185,4 @@ public Boolean HasElement(EffectElement element) return (Element & element) != 0; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/BattleTarget.cs b/Assembly-CSharp/Memoria/Battle/Calculator/BattleTarget.cs index 02bc8c640..a55067e29 100644 --- a/Assembly-CSharp/Memoria/Battle/Calculator/BattleTarget.cs +++ b/Assembly-CSharp/Memoria/Battle/Calculator/BattleTarget.cs @@ -1,19 +1,23 @@ -using System; using FF9; using Memoria.Data; +using System; namespace Memoria { public sealed class BattleTarget : BattleUnit { private readonly CalcContext _context; + private readonly BattleStatus _initialCheckPoint; public BattleTarget(BTL_DATA data, CalcContext context) : base(data) { _context = context; + _initialCheckPoint = CheckPointData(); } + public BattleStatus AddededCheckPointStatuses => CheckPointData() & ~_initialCheckPoint; + public EffectElement GuardElement { get { return (EffectElement)Data.def_attr.invalid; } @@ -268,6 +272,11 @@ public Boolean TryKillFrozen() { if (!IsUnderAnyStatus(BattleStatus.Freeze) || IsUnderAnyStatus(BattleStatus.Petrify)) return false; + if (IsUnderAnyStatus(BattleStatus.EasyKill)) // Behaviour added by Memoria with no influence on vanilla - Boss can't die when frozen + return false; + + if (Configuration.Mod.TranceSeek && IsUnderAnyStatus(BattleStatus.EasyKill)) // [DV] - Boss can't die when freeze. Can't move in Memoria.Scripts because depending with SBattleCalculator :( + return false; BattleVoice.TriggerOnStatusChange(Data, "Used", BattleStatus.Freeze); btl_cmd.KillSpecificCommand(Data, BattleCommandId.SysStone); @@ -282,5 +291,15 @@ public void GambleDefence() if (_context.DefensePower != 0 && HasSupportAbility(SupportAbility1.GambleDefence)) _context.DefensePower = (Int16)(Comn.random16() % (_context.DefensePower << 1)); } + + private BattleStatus CheckPointData() + { + BattleStatus status = 0; + if (Data.cur.hp == 0) // Using this instead of "CurrentHp" avoids considering bosses under 10 000 HP as dead here + status |= BattleStatus.Death; + else if (IsPlayer && CurrentHp * 6 <= MaximumHp) + status |= BattleStatus.LowHP; + return status; + } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/BattleUnit.cs b/Assembly-CSharp/Memoria/Battle/Calculator/BattleUnit.cs index bf52e709f..a95d9834d 100644 --- a/Assembly-CSharp/Memoria/Battle/Calculator/BattleUnit.cs +++ b/Assembly-CSharp/Memoria/Battle/Calculator/BattleUnit.cs @@ -38,7 +38,7 @@ public Boolean IsOutOfReach public Boolean CanMove => Data.bi.atb != 0; public CharacterId PlayerIndex => IsPlayer ? (CharacterId)Data.bi.slot_no : CharacterId.NONE; - public Byte Level => Data.special_status_old ? ((byte)(Data.level << 3)) : Data.level; + public Byte Level => Data.special_status_old ? (byte)Math.Max(1, Data.level >> 3) : Data.level; public Byte Position => Data.bi.line_no; public Byte Row @@ -89,49 +89,49 @@ public Int16 CurrentAtb public Int32 PhysicalDefence { - get => Data.special_status_old ? Data.defence.PhysicalDefence >> 3 : Data.defence.PhysicalDefence; + get => Data.special_status_old ? (byte)Math.Max(1, Data.defence.PhysicalDefence >> 3) : Data.defence.PhysicalDefence; set => Data.defence.PhysicalDefence = value; } public Int32 PhysicalEvade { - get => Data.special_status_old ? Data.defence.PhysicalEvade >> 3 : Data.defence.PhysicalEvade; + get => Data.special_status_old ? (byte)Math.Max(1, Data.defence.PhysicalEvade >> 3) : Data.defence.PhysicalEvade; set => Data.defence.PhysicalEvade = value; } public Int32 MagicDefence { - get => Data.special_status_old ? Data.defence.MagicalDefence >> 3 : Data.defence.MagicalDefence; + get => Data.special_status_old ? (byte)Math.Max(1, Data.defence.MagicalDefence >> 3) : Data.defence.MagicalDefence; set => Data.defence.MagicalDefence = value; } public Int32 MagicEvade { - get => Data.special_status_old ? Data.defence.MagicalEvade >> 3 : Data.defence.MagicalEvade; + get => Data.special_status_old ? (byte)Math.Max(1, Data.defence.MagicalEvade >> 3) : Data.defence.MagicalEvade; set => Data.defence.MagicalEvade = value; } public Byte Strength { - get => Data.special_status_old ? ((Byte)(Data.elem.str >> 3)) : Data.elem.str; + get => Data.special_status_old ? (byte)Math.Max(1, Data.elem.str >> 3) : Data.elem.str; set => Data.elem.str = value; } public Byte Magic { - get => Data.special_status_old ? ((Byte)(Data.elem.mgc >> 3)) : Data.elem.mgc; + get => Data.special_status_old ? (byte)Math.Max(1, Data.elem.mgc >> 3) : Data.elem.mgc; set => Data.elem.mgc = value; } public Byte Dexterity { - get => Data.special_status_old ? ((Byte)(Data.elem.dex >> 3)) : Data.elem.dex; + get => Data.special_status_old ? (byte)Math.Max(1, Data.elem.dex >> 3) : Data.elem.dex; set => Data.elem.dex = value; } public Byte Will { - get => Data.special_status_old ? ((Byte)(Data.elem.wpr >> 3)) : Data.elem.wpr; + get => Data.special_status_old ? (byte)Math.Max(1, Data.elem.wpr >> 3) : Data.elem.wpr; set => Data.elem.wpr = value; } @@ -880,4 +880,4 @@ public void ReleaseChangeToMonster() Data.is_monster_transform = false; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/CalcContext.cs b/Assembly-CSharp/Memoria/Battle/Calculator/CalcContext.cs index 24b70b667..5a5393f5d 100644 --- a/Assembly-CSharp/Memoria/Battle/Calculator/CalcContext.cs +++ b/Assembly-CSharp/Memoria/Battle/Calculator/CalcContext.cs @@ -19,11 +19,15 @@ public sealed class CalcContext public RegularItem ItemSteal = RegularItem.NoItem; // Just a variable to remember which item was stolen public HashSet DisabledSA = new HashSet(); // The support abilities that are disabled by successfully applied SA features public Boolean IsDrain = false; // Keep the Caster.Hp/MpDamage at the same value of Target.Hp/MpDamage even when modified by external effects + public EatResult EatResult = 0; + + // Current sfxthread at the moment of the effect point (from UnifiedBattleSequencer, in SFXRework mode only) + // This field may be removed and replaced by another system in the future + public BattleActionThread sfxThread = null; // Warning: can be null public Int32 PowerDifference => AttackPower - DefensePower; public Boolean IsAbsorb => (Flags & BattleCalcFlags.Absorb) != 0; - public Int32 EnsureAttack => Attack < 1 ? (Attack = 1) : Attack; public Int32 EnsurePowerDifference => PowerDifference < 1 ? 1 : PowerDifference; } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/EatResult.cs b/Assembly-CSharp/Memoria/Battle/Calculator/EatResult.cs new file mode 100644 index 000000000..ebce5cb26 --- /dev/null +++ b/Assembly-CSharp/Memoria/Battle/Calculator/EatResult.cs @@ -0,0 +1,10 @@ +namespace Memoria +{ + public enum EatResult : int + { + Failed, + CannotEat, + Yummy, + TasteBad + } +} diff --git a/Assembly-CSharp/Memoria/Battle/Calculator/SBattleCalculator.cs b/Assembly-CSharp/Memoria/Battle/Calculator/SBattleCalculator.cs index 7b0217a8f..09da98024 100644 --- a/Assembly-CSharp/Memoria/Battle/Calculator/SBattleCalculator.cs +++ b/Assembly-CSharp/Memoria/Battle/Calculator/SBattleCalculator.cs @@ -1,10 +1,9 @@ -using System; -using System.Reflection; -using System.Collections.Generic; using FF9; using Memoria.Data; using Memoria.Prime; using Memoria.Scripts; +using System; +using System.Reflection; using UnityEngine; // ReSharper disable PossibleNullReferenceException @@ -12,6 +11,7 @@ namespace Memoria { public static class SBattleCalculator { + // Note: no optional parameters in these methods, at least yet, for retro-compatibility purpose public static void CalcMain(BattleUnit caster, BattleUnit target, BattleCommand command) { CalcMain(caster.Data, target.Data, command, command.ScriptId); @@ -19,10 +19,20 @@ public static void CalcMain(BattleUnit caster, BattleUnit target, BattleCommand public static void CalcMain(BTL_DATA caster, BTL_DATA target, CMD_DATA cmd) { - CalcMain(caster, target, new BattleCommand(cmd), cmd.ScriptId); + CalcMain(caster, target, new BattleCommand(cmd), cmd.ScriptId, null); + } + + public static void CalcMain(BTL_DATA caster, BTL_DATA target, CMD_DATA cmd, BattleActionThread sfxThread) + { + CalcMain(caster, target, new BattleCommand(cmd), cmd.ScriptId, sfxThread); } public static void CalcMain(BTL_DATA caster, BTL_DATA target, BattleCommand command, Int32 scriptId) + { + CalcMain(caster, target, command, scriptId, null); + } + + public static void CalcMain(BTL_DATA caster, BTL_DATA target, BattleCommand command, Int32 scriptId, BattleActionThread sfxThread) { try { @@ -42,6 +52,7 @@ public static void CalcMain(BTL_DATA caster, BTL_DATA target, BattleCommand comm } command.ScriptId = scriptId; BattleCalculator v = new BattleCalculator(caster, target, command); + v.Context.sfxThread = sfxThread; BattleScriptFactory factory = FindScriptFactory(scriptId); foreach (SupportingAbilityFeature saFeature in ff9abil.GetEnabledSA(v.Caster)) saFeature.TriggerOnAbility(v, "BattleScriptStart", false); @@ -115,6 +126,7 @@ public static void CalcResult(BattleCalculator v) BTL_DATA target = v.Target.Data; BTL_DATA caster = v.Caster.Data; CMD_DATA cmd = v.Command.Data; + v.Context.AddedStatuses |= v.Target.AddededCheckPointStatuses; foreach (SupportingAbilityFeature saFeature in ff9abil.GetEnabledSA(caster)) saFeature.TriggerOnAbility(v, "BattleScriptEnd", false); foreach (SupportingAbilityFeature saFeature in ff9abil.GetEnabledSA(target)) @@ -294,6 +306,7 @@ public static void CalcResult(BattleCalculator v) target.cur.mp = target.max.mp; } } + v.Context.AddedStatuses |= v.Target.AddededCheckPointStatuses; foreach (SupportingAbilityFeature saFeature in ff9abil.GetEnabledSA(caster)) saFeature.TriggerOnAbility(v, "EffectDone", false); foreach (SupportingAbilityFeature saFeature in ff9abil.GetEnabledSA(target)) @@ -361,4 +374,4 @@ private static void CheckDamageReaction(BattleCalculator v) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Battle/SFX/SFXChannel.cs b/Assembly-CSharp/Memoria/Battle/SFX/SFXChannel.cs index 92a6a880e..fab669509 100644 --- a/Assembly-CSharp/Memoria/Battle/SFX/SFXChannel.cs +++ b/Assembly-CSharp/Memoria/Battle/SFX/SFXChannel.cs @@ -87,7 +87,7 @@ public static void ExecuteLoop() foreach (SFXChannel reflect in SFXChannel.CurrentPlayReflect) { if (reflect.frame == 0) - SoundLib.PlaySoundEffect(SFX.REFLECT_SOUND_ID, 5f, 0f, 1f); // DEBUG: using 5f as sound volume (same as SFX.SoundPlayChant) + SoundLib.PlaySoundEffect(SFX.REFLECT_SOUND_ID, 1f, 0f, 1f); reflect.frame++; } } diff --git a/Assembly-CSharp/Memoria/Battle/SFX/UnifiedBattleSequencer.cs b/Assembly-CSharp/Memoria/Battle/SFX/UnifiedBattleSequencer.cs index 2d0d51071..75ef8df00 100644 --- a/Assembly-CSharp/Memoria/Battle/SFX/UnifiedBattleSequencer.cs +++ b/Assembly-CSharp/Memoria/Battle/SFX/UnifiedBattleSequencer.cs @@ -910,7 +910,7 @@ public void ExecuteSingleCode(Int32 runningThreadId) c.fig_info = 0; c.fig = c.m_fig = 0; } - btl_cmd.ExecVfxCommand(btl, cmd); + btl_cmd.ExecVfxCommand(btl, cmd, runningThread); foreach (BTL_DATA c in allBtl) { if (c.fig_info != 0) diff --git a/Assembly-CSharp/Memoria/Configuration/Access/Battle.cs b/Assembly-CSharp/Memoria/Configuration/Access/Battle.cs index 338a4c44c..eb078a658 100644 --- a/Assembly-CSharp/Memoria/Configuration/Access/Battle.cs +++ b/Assembly-CSharp/Memoria/Configuration/Access/Battle.cs @@ -65,4 +65,4 @@ public static void SaveBattleSpeed() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Access/Cheats.cs b/Assembly-CSharp/Memoria/Configuration/Access/Cheats.cs index c87976fe5..abee80fa1 100644 --- a/Assembly-CSharp/Memoria/Configuration/Access/Cheats.cs +++ b/Assembly-CSharp/Memoria/Configuration/Access/Cheats.cs @@ -20,4 +20,4 @@ public static class Cheats public static Boolean GilMax => Instance._cheats.GilMax; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Access/Control.cs b/Assembly-CSharp/Memoria/Configuration/Access/Control.cs index 09f9fa797..dbd159d08 100644 --- a/Assembly-CSharp/Memoria/Configuration/Access/Control.cs +++ b/Assembly-CSharp/Memoria/Configuration/Access/Control.cs @@ -22,6 +22,8 @@ public static class Control public static Boolean DisableMouseInBattles => (DisableMouse & 4) != 0; public static String[] DialogProgressButtons => Instance._control.DialogProgressButtons; public static Boolean WrapSomeMenus => Instance._control.WrapSomeMenus; + public static Boolean BattleAutoConfirm => Instance._control.BattleAutoConfirm; + public static Boolean TurboDialog => Instance._control.TurboDialog; public static Boolean PSXScrollingMethod => Instance._control.PSXScrollingMethod; /* The PSX movement algorithm is different than the remaster's movement algorithm @@ -30,6 +32,7 @@ The PSX movement algorithm is different than the remaster's movement algorithm If that is true, it results in characters moving faster on steep slopes for the remaster version, and in characters moving either a bit slower or a bit faster on irregular walkmeshes ("irregular" = triangles are not aligned on the same plane) */ public static Boolean PSXMovementMethod => Instance._control.PSXMovementMethod; + public static Boolean AlwaysCaptureGamepad => Instance._control.AlwaysCaptureGamepad; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Access/Export.cs b/Assembly-CSharp/Memoria/Configuration/Access/Export.cs index 9e538cb94..6cc7f9902 100644 --- a/Assembly-CSharp/Memoria/Configuration/Access/Export.cs +++ b/Assembly-CSharp/Memoria/Configuration/Access/Export.cs @@ -1,3 +1,4 @@ +using Memoria.Assets; using System; namespace Memoria @@ -10,13 +11,15 @@ public static class Export public static String Path => Instance._export.Path; public static String[] Languages => Instance._export.Languages; + public static Boolean Text => Enabled && Instance._export.Text; + public static TextResourceFormat TextFileFormat => TextResourceFormatHelper.ResolveFileFormat(Instance._export.TextFileFormat); + public static Int32 TextContentFormat = 1; + public static Boolean Graphics => Enabled && Instance._export.Graphics; public static Boolean Audio => Enabled && Instance._export.Audio; public static Boolean Field => Enabled && Instance._export.Field; public static Boolean Battle => Enabled && Instance._export.Battle; - - public static Int32 TextFormat = 1; } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Access/Graphics.cs b/Assembly-CSharp/Memoria/Configuration/Access/Graphics.cs index 03bf82cc1..522cce698 100644 --- a/Assembly-CSharp/Memoria/Configuration/Access/Graphics.cs +++ b/Assembly-CSharp/Memoria/Configuration/Access/Graphics.cs @@ -17,7 +17,7 @@ public static class Graphics public static Int32 MenuFPS => Instance._graphics.MenuFPS; public static Int32 MenuTPS => Instance._graphics.MenuTPS; public static Int32 BattleSwirlFrames => Instance._graphics.BattleSwirlFrames; - public static Int32 SkipIntros = Instance._graphics.SkipIntros; + public static Int32 SkipIntros => Instance._graphics.SkipIntros; public static Int32 GarnetHair => Instance._graphics.GarnetHair; public static Int32 TileSize => Instance._graphics.TileSize; public static Int32 AntiAliasing => Instance._graphics.AntiAliasing; @@ -27,20 +27,14 @@ public static class Graphics public static Boolean InitializeWidescreenSupport() { - if (!Instance._graphics.WidescreenSupport) - return false; - if (Instance._debug.Enabled && Instance._debug.StartFieldCreator) - return false; - - if ((Math.Abs(((Double)Screen.width / (Double)Screen.height) - (16d / 9d)) < 0.01) || (Math.Abs(((Double)Screen.width / (Double)Screen.height) - (16d / 10d)) < 0.01)) + if (!Instance._graphics.WidescreenSupport || (Instance._debug.Enabled && Instance._debug.StartFieldCreator)) { - //Log.Message("WIDESCREEN | Screen.width:" + (Double)Screen.width + " Screen.height:" + (Double)Screen.height); - return true; + return false; } - - //Log.Message("Not Widescreen | Screen.width:" + (Double)Screen.width + " Screen.height:" + (Double)Screen.height); - return false; + return true; + // if ((Math.Abs(((Double)Screen.width / (Double)Screen.height) - (16d / 9d)) < 0.01) || (Math.Abs(((Double)Screen.width / (Double)Screen.height) - (16d / 10d)) < 0.01)) } + public static Boolean ScreenIs16to10() { if (Math.Abs(((Double)Screen.width / (Double)Screen.height) - (16d / 10d)) < 0.01) diff --git a/Assembly-CSharp/Memoria/Configuration/Access/Interface.cs b/Assembly-CSharp/Memoria/Configuration/Access/Interface.cs index 2b42675df..b8cd7b5be 100644 --- a/Assembly-CSharp/Memoria/Configuration/Access/Interface.cs +++ b/Assembly-CSharp/Memoria/Configuration/Access/Interface.cs @@ -97,7 +97,13 @@ public static Int32 MenuChocographRowCount set => Instance._interface.MenuChocographRowCount.Value = value; } - public static void SaveBattleValues() + public static Single FadeDuration + { + get => Mathf.Clamp(Instance._interface.FadeDuration / 1000f, 0f, 5f); + set => Instance._interface.FadeDuration.Value = (Int32)(value * 1000f); + } + + public static void SaveBattleValues() { //SaveValue(Instance._interface.Name, Instance._interface.Enabled); SaveValue(Instance._interface.Name, Instance._interface.PSXBattleMenu); @@ -124,4 +130,4 @@ public static void SaveMenuValues() } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/DataPatchers.cs b/Assembly-CSharp/Memoria/Configuration/DataPatchers.cs index c73c18f47..de3c24115 100644 --- a/Assembly-CSharp/Memoria/Configuration/DataPatchers.cs +++ b/Assembly-CSharp/Memoria/Configuration/DataPatchers.cs @@ -294,7 +294,24 @@ private static void PatchDictionaries(String[] patchCode) } } } - else if (String.Compare(entry[0], "WorldMusicList") == 0 && entry.Length >= 7) + else if (String.Compare(entry[0], "MixCommand") == 0) + { + // eg.: MixCommand Add 1000 + Boolean add = String.Compare(entry[1], "Remove") != 0; + if (String.Compare(entry[1], "Set") == 0) + BattleHUD.MixCommandSet.Clear(); + for (Int32 i = 2; i < entry.Length; i++) + { + if (entry[i].TryEnumParse(out BattleCommandId cmdId)) + { + if (add) + BattleHUD.MixCommandSet.Add(cmdId); + else + BattleHUD.MixCommandSet.Remove(cmdId); + } + } + } + else if (String.Compare(entry[0], "WorldMusicList") == 0 && entry.Length >= 7) { // eg.: WorldMusicList 69 22 112 45 95 96 61 62 if (ff9.w_musicSet == null) @@ -475,7 +492,40 @@ private static void PatchDictionaries(String[] patchCode) FF9BattleDB.Animation[ID[idindex]] = entry[entry.Length - 1]; } } - } + else if (String.Compare(entry[0], "SwapFieldModelTexture") == 0) + { + // eg.: SwapFieldModelTexture 2250 GEO_MON_B3_093 CustomTextures/OeilvertGuardian/342_0.png CustomTextures/OeilvertGuardian/342_1.png CustomTextures/OeilvertGuardian/342_2.png CustomTextures/OeilvertGuardian/342_3.png CustomTextures/OeilvertGuardian/342_4.png CustomTextures/OeilvertGuardian/342_5.png + List TexturesList = new List(); + if (!Int32.TryParse(entry[1], out Int32 FieldID)) + continue; + for (Int32 i = 3; i < entry.Length; i++) + { + TexturesList.Add(entry[i]); + } + String[] TexturesCustomModel = TexturesList.ToArray(); + ModelFactory.CustomModelField.Add(entry[1] + "#" + entry[2], TexturesCustomModel); + } + else if (String.Compare(entry[0], "SPSTexture") == 0) + { + // eg.: SPSTexture customfireorb shp 3 400 0 0 5 5 + if (!Int32.TryParse(entry[3], out Int32 numbertexture)) + continue; + if (!float.TryParse(entry[4], out float posx)) + continue; + if (!float.TryParse(entry[5], out float posy)) + continue; + if (!float.TryParse(entry[6], out float posz)) + continue; + + if (!float.TryParse(entry[7], out float SPSScale)) + SPSScale = 4; + if (!float.TryParse(entry[8], out float SPSDistance)) + SPSDistance = 5; + + Vector3 SPSpos = new Vector3(posx, posy, posz); + BattleSPSSystem.statusTextures.Add(new BattleSPSSystem.SPSTexture(entry[1], entry[2], numbertexture, SPSpos, SPSScale, SPSDistance)); + } + } if (shouldUpdateBattleStatus) BattleStatusConst.Update(); } diff --git a/Assembly-CSharp/Memoria/Configuration/Memoria.ini b/Assembly-CSharp/Memoria/Configuration/Memoria.ini index cd9ee4d07..bc5a7c4bd 100644 --- a/Assembly-CSharp/Memoria/Configuration/Memoria.ini +++ b/Assembly-CSharp/Memoria/Configuration/Memoria.ini @@ -13,20 +13,22 @@ Size = 24 [Audio] ; PriorityToOGG (default 0) When enabled, ".ogg" audio files are used instead of the ".akb.bytes" counterpart when both exist; the AKB header is then generated again at each usage + ; Backend (default 1) Choose the audio backend. 0 = SdLib, legacy backend (not recommended) / 1 = Soloud, new better sounding backend MusicVolume = 100 SoundVolume = 100 MovieVolume = 100 PriorityToOGG = 0 +Backend = 1 [Graphics] - ; BattleFPS (default 30) Controls the fluidity of battle graphics (frame per second) + ; BattleFPS (default 60) Controls the fluidity of battle graphics (frame per second) ; BattleTPS (default 15) Controls the speed of battles (tick per second) - ; FieldFPS (default 30) Controls the fluidity of field graphics + ; FieldFPS (default 60) Controls the fluidity of field graphics ; FieldTPS (default 30) Controls the speed in fields - ; WorldFPS (default 20) Controls the fluidity of world map graphics + ; WorldFPS (default 60) Controls the fluidity of world map graphics ; WorldTPS (default 20) Controls the speed in world maps ; MenuFPS (default 60) Controls the fluidity of other modules - ; BattleSwirlFrames (default 115) is the number of frames before a battle + ; BattleSwirlFrames (default 0 / PSX 115) is the number of frames "swirling" before a battle ; WidescreenSupport (default 1) activate Widescreen for 16:9 screens ; SkipIntros (default 0) 0 = Don't skip / 1 = Skip logos / 2 = Skip logos and movie / 3 = Don't loop at the title ; GarnetHair (default 0) 0 = Default / 1 = Long / 2 = Short @@ -34,15 +36,15 @@ PriorityToOGG = 0 ; AntiAliasing (default 8) Must be either 0, 2, 4 or 8: enable Unity's anti-aliasing algorithm to improve the render of 3D model edges ; CameraStabilizer (0 to 99, default 85) Adds a smooth delay on the camera following the player. Value represents "stickiness" of camera to its original position, each frame. Enabled = 0 -BattleFPS = 30 +BattleFPS = 60 BattleTPS = 15 -FieldFPS = 30 +FieldFPS = 60 FieldTPS = 30 -WorldFPS = 20 +WorldFPS = 60 WorldTPS = 20 MenuFPS = 60 MenuTPS = 60 -BattleSwirlFrames = 13 +BattleSwirlFrames = 0 WidescreenSupport = 1 SkipIntros = 0 GarnetHair = 0 @@ -54,14 +56,20 @@ CameraStabilizer = 85 ; DisableMouse (default 0) 0 = Can use the mouse to navigate in menus and move on the fields / 7 = Disable the mouse completly / 1 = Disable mouse for field menus and dialogs / 2 = Disable mouse for field movements / 4 = Disable mouse for battle menus ; DialogProgressButtons (default "Confirm") A list of buttons that can be used to progress in cutscene dialogs; the PSX version used "Confirm", "Special" ; WrapSomeMenus (default 1) 0 = Don't wrap selection in menu that don't natively wrap it / 1 = Wrap selection for easing menu navigation + ; BattleAutoConfirm (default 1) 0 = Confirm needs to be pressed repeatedly / 1 = Holding Confirm will automatically validate commands during battle and progress the battle result screen + ; TurboDialog (default 1) F9 - Toggles the automatic skipping of basic dialogs. Alternatively Holding Shift + Confirm or Right Bumper + Confirm also skips dialogs automatically. ; PSXScrollingMethod (default 1) 0 = Use the native Steam scrolling pattern / 1 = Scroll lists with the same behaviour as the PSX version - ; PSXMovementMethod (default 0) 0 = Use the native Steam move pathing method, which makes movements faster on sloping paths / 1 = Use the PSX move pathing method + ; PSXMovementMethod (default 1) 0 = Use the native Steam move pathing method, which makes movements faster on sloping paths / 1 = Use the PSX move pathing method + ; AlwaysCaptureGamepad (default 1) 0 = Gamepad inputs are ignored when the game windows doesn't have focus / 1 = Gamepad inputs are always in effect Enabled = 1 DisableMouse = 0 DialogProgressButtons = "Confirm" WrapSomeMenus = 1 +BattleAutoConfirm = 1 +TurboDialog = 1 PSXScrollingMethod = 1 -PSXMovementMethod = 0 +PSXMovementMethod = 1 +AlwaysCaptureGamepad = 1 [AnalogControl] ; StickThreshold (default 10) 0->100, threshold under which there is no movement @@ -226,6 +234,7 @@ DiscardExclusions = 56, 75, 76, 77, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, ; BattleRestoreTextFormat (default empty) Same as above for HP heal ; BattleMPDamageTextFormat (default empty) Same as above for MP damage ; BattleMPRestoreTextFormat (default empty) Same as above for MP heal + ; FadeDuration (default 40, original game 300) Duration of the fade between interface transitions in milliseconds, navigation cannot occur during transition. Setting it to 0 will allow instant navigation. BattleRowCount = 5 BattleColumnCount = 1 BattleMenuPosX = -400 @@ -247,6 +256,7 @@ MenuItemRowCount = 8 MenuAbilityRowCount = 6 MenuEquipRowCount = 5 MenuChocographRowCount = 5 +FadeDuration = 40 [Fixes] Enabled = 1 @@ -279,10 +289,12 @@ RenderWalkmeshes = 0 [Export] ; no effect in game + ; TextFileFormat: determines in what format the text resources will be exported; possible values: .strings, .resjson Enabled = 0 Path = %StreamingAssets% Languages = "US", "UK", "JP", "ES", "FR", "GR", "IT" Text = 1 +TextFileFormat = .strings Graphics = 1 Audio = 1 Field = 0 diff --git a/Assembly-CSharp/Memoria/Configuration/Structure/CheatsSection.cs b/Assembly-CSharp/Memoria/Configuration/Structure/CheatsSection.cs index 44af2cad0..6afc78aaa 100644 --- a/Assembly-CSharp/Memoria/Configuration/Structure/CheatsSection.cs +++ b/Assembly-CSharp/Memoria/Configuration/Structure/CheatsSection.cs @@ -40,4 +40,4 @@ public CheatsSection() : base(nameof(CheatsSection), false) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Structure/ControlSection.cs b/Assembly-CSharp/Memoria/Configuration/Structure/ControlSection.cs index e0d4b27bc..69837c0d2 100644 --- a/Assembly-CSharp/Memoria/Configuration/Structure/ControlSection.cs +++ b/Assembly-CSharp/Memoria/Configuration/Structure/ControlSection.cs @@ -24,17 +24,23 @@ private sealed class ControlSection : IniSection public readonly IniValue DisableMouse; public readonly IniArray DialogProgressButtons; public readonly IniValue WrapSomeMenus; + public readonly IniValue BattleAutoConfirm; + public readonly IniValue TurboDialog; public readonly IniValue PSXScrollingMethod; public readonly IniValue PSXMovementMethod; + public readonly IniValue AlwaysCaptureGamepad; public ControlSection() : base(nameof(ControlSection), true) { DisableMouse = BindInt32(nameof(DisableMouse), 0); DialogProgressButtons = BindStringArray(nameof(DialogProgressButtons), new String[1] { "Confirm" }); WrapSomeMenus = BindBoolean(nameof(WrapSomeMenus), true); + BattleAutoConfirm = BindBoolean(nameof(BattleAutoConfirm), true); + TurboDialog = BindBoolean(nameof(TurboDialog), false); PSXScrollingMethod = BindBoolean(nameof(PSXScrollingMethod), true); PSXMovementMethod = BindBoolean(nameof(PSXMovementMethod), false); + AlwaysCaptureGamepad = BindBoolean(nameof(AlwaysCaptureGamepad), false); } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Structure/ExportSection.cs b/Assembly-CSharp/Memoria/Configuration/Structure/ExportSection.cs index 9e22f3801..06b5d3c34 100644 --- a/Assembly-CSharp/Memoria/Configuration/Structure/ExportSection.cs +++ b/Assembly-CSharp/Memoria/Configuration/Structure/ExportSection.cs @@ -1,3 +1,4 @@ +using Memoria.Assets; using System; using Memoria.Prime.Ini; @@ -12,6 +13,7 @@ private sealed class ExportSection : IniSection public readonly IniValue Path; public readonly IniArray Languages; public readonly IniValue Text; + public readonly IniValue TextFileFormat; public readonly IniValue Graphics; public readonly IniValue Audio; public readonly IniValue Field; @@ -22,6 +24,7 @@ public ExportSection() : base(nameof(ExportSection), false) Path = BindPath(nameof(Path), "%StreamingAssets%"); Languages = BindStringArray(nameof(Languages), DefaultLanguages); Text = BindBoolean(nameof(Text), false); + TextFileFormat = BindString(nameof(TextFileFormat), TextResourceFormat.Strings.GetFileExtension()); Graphics = BindBoolean(nameof(Graphics), false); Audio = BindBoolean(nameof(Audio), false); Field = BindBoolean(nameof(Field), false); @@ -29,4 +32,4 @@ public ExportSection() : base(nameof(ExportSection), false) } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Configuration/Structure/InterfaceSection.cs b/Assembly-CSharp/Memoria/Configuration/Structure/InterfaceSection.cs index d192d170d..320178254 100644 --- a/Assembly-CSharp/Memoria/Configuration/Structure/InterfaceSection.cs +++ b/Assembly-CSharp/Memoria/Configuration/Structure/InterfaceSection.cs @@ -1,64 +1,67 @@ -using System; -using System.Collections.Generic; -using Memoria.Prime.Ini; +using Memoria.Prime.Ini; +using System; namespace Memoria { - public sealed partial class Configuration - { - private sealed class InterfaceSection : IniSection - { - public readonly IniValue PSXBattleMenu; - public readonly IniValue ScanDisplay; - public readonly IniValue BattleRowCount; - public readonly IniValue BattleColumnCount; - public readonly IniValue BattleMenuPosX; - public readonly IniValue BattleMenuPosY; - public readonly IniValue BattleMenuWidth; - public readonly IniValue BattleMenuHeight; - public readonly IniValue BattleDetailPosX; - public readonly IniValue BattleDetailPosY; - public readonly IniValue BattleDetailWidth; - public readonly IniValue BattleDetailHeight; - public readonly IniValue BattleDamageTextFormat; - public readonly IniValue BattleRestoreTextFormat; - public readonly IniValue BattleMPDamageTextFormat; - public readonly IniValue BattleMPRestoreTextFormat; - public readonly IniValue BattleCommandTitleFormat; + public sealed partial class Configuration + { + private sealed class InterfaceSection : IniSection + { + public readonly IniValue PSXBattleMenu; + public readonly IniValue ScanDisplay; + public readonly IniValue BattleRowCount; + public readonly IniValue BattleColumnCount; + public readonly IniValue BattleMenuPosX; + public readonly IniValue BattleMenuPosY; + public readonly IniValue BattleMenuWidth; + public readonly IniValue BattleMenuHeight; + public readonly IniValue BattleDetailPosX; + public readonly IniValue BattleDetailPosY; + public readonly IniValue BattleDetailWidth; + public readonly IniValue BattleDetailHeight; + public readonly IniValue BattleDamageTextFormat; + public readonly IniValue BattleRestoreTextFormat; + public readonly IniValue BattleMPDamageTextFormat; + public readonly IniValue BattleMPRestoreTextFormat; + public readonly IniValue BattleCommandTitleFormat; - public readonly IniValue MenuItemRowCount; - public readonly IniValue MenuAbilityRowCount; - public readonly IniValue MenuEquipRowCount; - public readonly IniValue MenuChocographRowCount; + public readonly IniValue MenuItemRowCount; + public readonly IniValue MenuAbilityRowCount; + public readonly IniValue MenuEquipRowCount; + public readonly IniValue MenuChocographRowCount; - public InterfaceSection() : base(nameof(InterfaceSection), true) - { - PSXBattleMenu = BindBoolean(nameof(PSXBattleMenu), false); - ScanDisplay = BindBoolean(nameof(ScanDisplay), true); - BattleRowCount = BindInt32(nameof(BattleRowCount), 5); - BattleColumnCount = BindInt32(nameof(BattleColumnCount), 1); - BattleMenuPosX = BindInt32(nameof(BattleMenuPosX), -400); - BattleMenuPosY = BindInt32(nameof(BattleMenuPosY), -362); - BattleMenuWidth = BindInt32(nameof(BattleMenuWidth), 630); - BattleMenuHeight = BindInt32(nameof(BattleMenuHeight), 236); - BattleDetailPosX = BindInt32(nameof(BattleDetailPosX), 345); - BattleDetailPosY = BindInt32(nameof(BattleDetailPosY), -380); - BattleDetailWidth = BindInt32(nameof(BattleDetailWidth), 796); - BattleDetailHeight = BindInt32(nameof(BattleDetailHeight), 230); - BattleDamageTextFormat = BindString(nameof(BattleDamageTextFormat), String.Empty); - BattleRestoreTextFormat = BindString(nameof(BattleRestoreTextFormat), String.Empty); - BattleMPDamageTextFormat = BindString(nameof(BattleMPDamageTextFormat), String.Empty); - BattleMPRestoreTextFormat = BindString(nameof(BattleMPRestoreTextFormat), String.Empty); - BattleCommandTitleFormat = BindString(nameof(BattleCommandTitleFormat), String.Empty); + public readonly IniValue FadeDuration; - MenuItemRowCount = BindInt32(nameof(MenuItemRowCount), 8); // Default PC: 8, PSX: 11 - MenuAbilityRowCount = BindInt32(nameof(MenuAbilityRowCount), 6); // Default PC: 6, PSX: 8 - MenuEquipRowCount = BindInt32(nameof(MenuEquipRowCount), 5); // Default PC: 5, PSX: 6 - MenuChocographRowCount = BindInt32(nameof(MenuChocographRowCount), 5); // Default PC: 5, PSX: 7 - // Shop menu -- Default PC: 5/8, PSX: 7/11 (with/without portraits) - // Status menu -- Default PC: 8, PSX: 8 - // Config menu -- Default PC: 6/8, PSX: 9 - } - } - } -} \ No newline at end of file + public InterfaceSection() : base(nameof(InterfaceSection), true) + { + PSXBattleMenu = BindBoolean(nameof(PSXBattleMenu), false); + ScanDisplay = BindBoolean(nameof(ScanDisplay), true); + BattleRowCount = BindInt32(nameof(BattleRowCount), 5); + BattleColumnCount = BindInt32(nameof(BattleColumnCount), 1); + BattleMenuPosX = BindInt32(nameof(BattleMenuPosX), -400); + BattleMenuPosY = BindInt32(nameof(BattleMenuPosY), -362); + BattleMenuWidth = BindInt32(nameof(BattleMenuWidth), 630); + BattleMenuHeight = BindInt32(nameof(BattleMenuHeight), 236); + BattleDetailPosX = BindInt32(nameof(BattleDetailPosX), 345); + BattleDetailPosY = BindInt32(nameof(BattleDetailPosY), -380); + BattleDetailWidth = BindInt32(nameof(BattleDetailWidth), 796); + BattleDetailHeight = BindInt32(nameof(BattleDetailHeight), 230); + BattleDamageTextFormat = BindString(nameof(BattleDamageTextFormat), String.Empty); + BattleRestoreTextFormat = BindString(nameof(BattleRestoreTextFormat), String.Empty); + BattleMPDamageTextFormat = BindString(nameof(BattleMPDamageTextFormat), String.Empty); + BattleMPRestoreTextFormat = BindString(nameof(BattleMPRestoreTextFormat), String.Empty); + BattleCommandTitleFormat = BindString(nameof(BattleCommandTitleFormat), String.Empty); + + MenuItemRowCount = BindInt32(nameof(MenuItemRowCount), 8); // Default PC: 8, PSX: 11 + MenuAbilityRowCount = BindInt32(nameof(MenuAbilityRowCount), 6); // Default PC: 6, PSX: 8 + MenuEquipRowCount = BindInt32(nameof(MenuEquipRowCount), 5); // Default PC: 5, PSX: 6 + MenuChocographRowCount = BindInt32(nameof(MenuChocographRowCount), 5); // Default PC: 5, PSX: 7 + // Shop menu -- Default PC: 5/8, PSX: 7/11 (with/without portraits) + // Status menu -- Default PC: 8, PSX: 8 + // Config menu -- Default PC: 6/8, PSX: 9 + + FadeDuration = BindInt32(nameof(FadeDuration), 300); + } + } + } +} diff --git a/Assembly-CSharp/Memoria/Data/Battle/BattleAbilityHelper.cs b/Assembly-CSharp/Memoria/Data/Battle/BattleAbilityHelper.cs index 01f71b610..d8f85f135 100644 --- a/Assembly-CSharp/Memoria/Data/Battle/BattleAbilityHelper.cs +++ b/Assembly-CSharp/Memoria/Data/Battle/BattleAbilityHelper.cs @@ -1,93 +1,233 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; +using FF9; +using Memoria.Database; using Memoria.Prime; using NCalc; -using FF9; +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; namespace Memoria.Data { public static class BattleAbilityHelper { - private static Dictionary AbilityPatch = new Dictionary(); - private static Dictionary AbilityPriority = new Dictionary(); - private static Dictionary AbilityPowerPatch = new Dictionary(); - private static Dictionary AbilityHitRatePatch = new Dictionary(); - private static Dictionary AbilityElementPatch = new Dictionary(); - private static Dictionary AbilityStatusPatch = new Dictionary(); - private static Dictionary AbilityTargetPatch = new Dictionary(); - private static Dictionary AbilitySpecialEffectPatch = new Dictionary(); - private static Dictionary AbilityGilCost = new Dictionary(); - private static Dictionary AbilityItemRequirement = new Dictionary(); - - public static void ParseAbilityFeature(BattleAbilityId id, String input) + public static void ParseAbilityFeature(String input) { + ParseAbilityFeature(BattleAbilityId.Void, input); + } + + public static void ParseAbilityFeature(BattleAbilityId abilId, String input) + { + FeatureSet set; + if (abilId == BattleAbilityId.Void) + { + // A feature that relies on their "Condition" to discriminate whether they apply or not + set = new FeatureSet(); + FlexibleFeatures.Add(set); + } + else + { + // A feature linked to a particular Ability ID + if (!AbilityFeatures.TryGetValue(abilId, out set)) + { + set = new FeatureSet(); + AbilityFeatures.Add(abilId, set); + } + } foreach (Match formula in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(input)) { - if (String.Compare(formula.Groups[1].Value, "Patch") == 0) - AbilityPatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "Priority") == 0) - AbilityPriority[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "Power") == 0) - AbilityPowerPatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "HitRate") == 0) - AbilityHitRatePatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "Element") == 0) - AbilityElementPatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "Status") == 0) - AbilityStatusPatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "Target") == 0) - AbilityTargetPatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "SpecialEffect") == 0) - AbilitySpecialEffectPatch[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "GilCost") == 0) - AbilityGilCost[id] = formula.Groups[2].Value; - else if (String.Compare(formula.Groups[1].Value, "ItemRequirement") == 0) - AbilityItemRequirement[id] = formula.Groups[2].Value; + if (String.Equals(formula.Groups[1].Value, "Condition")) + set.Condition = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "Patch")) + { + set.AbilityPatch = formula.Groups[2].Value; + if (abilId == BattleAbilityId.Void) + Log.Warning($"[{nameof(BattleAbilityHelper)}] \"AbilityPatch\" cannot be used as a Global AA feature"); + } + else if (String.Equals(formula.Groups[1].Value, "Priority")) + set.AbilityPriority = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "Power")) + set.AbilityPowerPatch = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "HitRate")) + set.AbilityHitRatePatch = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "Element")) + set.AbilityElementPatch = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "Status")) + set.AbilityStatusPatch = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "Target")) + set.AbilityTargetPatch = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "SpecialEffect")) + set.AbilitySpecialEffectPatch = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "GilCost")) + set.AbilityGilCost = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "MPCost")) + set.AbilityMPCost = formula.Groups[2].Value; + else if (String.Equals(formula.Groups[1].Value, "ItemRequirement")) + set.AbilityItemRequirement = formula.Groups[2].Value; } } - public static void ClearAbilityFeature(BattleAbilityId id) + public static void ClearAbilityFeature(BattleAbilityId abilId) { - AbilityPatch.Remove(id); - AbilityPriority.Remove(id); - AbilityPowerPatch.Remove(id); - AbilityHitRatePatch.Remove(id); - AbilityElementPatch.Remove(id); - AbilityStatusPatch.Remove(id); - AbilityTargetPatch.Remove(id); - AbilitySpecialEffectPatch.Remove(id); - AbilityGilCost.Remove(id); - AbilityItemRequirement.Remove(id); + AbilityFeatures.Remove(abilId); + } + + public static void ClearFlexibleAbilityFeature() + { + FlexibleFeatures.Clear(); } public static Boolean ApplySpecialCommandCondition(CMD_DATA cmd) { - BattleAbilityId abilId = btl_util.GetCommandMainActionIndex(cmd); - if (abilId == BattleAbilityId.Void) - return true; try { - String featureStr; - if (AbilityPowerPatch.TryGetValue(abilId, out featureStr)) + BattleAbilityId abilId = btl_util.GetCommandMainActionIndex(cmd); + Int64 gilCost = 0; + foreach (FeatureSet feat in GetApplicableFeatures(abilId, new BattleUnit(cmd.regist), cmd: cmd)) + { + feat.ApplyBasicModifiers(cmd); + if (!feat.ApplyCommandCondition(cmd, ref gilCost)) + return false; + } + PARTY_DATA ff9party = FF9StateSystem.Common.FF9.party; + if (gilCost > ff9party.gil) + { + UIManager.Battle.SetBattleFollowMessage(BattleMesages.NotEnoughGil); + return false; + } + ff9party.gil -= (UInt32)gilCost; + } + catch (Exception err) + { + Log.Error(err); + } + return true; + } + + public static Boolean GetPatchedMPCost(BattleAbilityId abilId, BattleUnit potentialCaster, ref Int32 mpCost, AA_DATA ability = null, CMD_DATA cmd = null, BattleCommandMenu menu = BattleCommandMenu.None) + { + Boolean changeMPCost = false; + try + { + foreach (FeatureSet feat in GetApplicableFeatures(abilId, potentialCaster, ability: ability, cmd: cmd, menu: menu)) + if (feat.ApplyMPCost(abilId, potentialCaster, ref mpCost, ability: ability, cmd: cmd, menu: menu)) + changeMPCost = true; + } + catch (Exception err) + { + Log.Error(err); + } + return changeMPCost; + } + + public static void SetCustomPriority(CMD_DATA cmd) + { + try + { + BattleAbilityId abilId = btl_util.GetCommandMainActionIndex(cmd); + foreach (FeatureSet feat in GetApplicableFeatures(abilId, new BattleUnit(cmd.regist), cmd: cmd)) + feat.ApplyPriority(cmd); + } + catch (Exception err) + { + Log.Error(err); + } + } + + public static BattleAbilityId Patch(BattleAbilityId abilId, PLAYER character) + { + try + { + // Flexible features are not taken into account, and there cannot be any condition tied to a patch + // Using a NCalc formula that conditionally returns -1 can be used instead of a condition + if (abilId != BattleAbilityId.Void && AbilityFeatures.TryGetValue(abilId, out FeatureSet abilSet)) + return abilSet.ApplyPatch(abilId, character); + } + catch (Exception err) + { + Log.Error(err); + } + return abilId; + } + + private static IEnumerable GetApplicableFeatures(BattleAbilityId abilId, BattleUnit caster, AA_DATA ability = null, CMD_DATA cmd = null, BattleCommandMenu menu = BattleCommandMenu.None) + { + foreach (FeatureSet flexiSet in FlexibleFeatures) + if (flexiSet.CheckCondition(abilId, caster, ability, cmd, menu)) + yield return flexiSet; + if (abilId != BattleAbilityId.Void && AbilityFeatures.TryGetValue(abilId, out FeatureSet abilSet) && abilSet.CheckCondition(abilId, caster, ability, cmd, menu)) + yield return abilSet; + yield break; + } + + private class FeatureSet + { + public String Condition = null; + public String AbilityPatch = null; + public String AbilityPriority = null; + public String AbilityPowerPatch = null; + public String AbilityHitRatePatch = null; + public String AbilityElementPatch = null; + public String AbilityStatusPatch = null; + public String AbilityTargetPatch = null; + public String AbilitySpecialEffectPatch = null; + public String AbilityGilCost = null; + public String AbilityMPCost = null; + public String AbilityItemRequirement = null; + + public Boolean CheckCondition(BattleAbilityId abilId, BattleUnit caster, AA_DATA ability = null, CMD_DATA cmd = null, BattleCommandMenu menu = BattleCommandMenu.None) + { + if (String.IsNullOrEmpty(Condition)) + return true; + if (cmd == null && ability == null && abilId == BattleAbilityId.Void) + return false; + Expression c = new Expression(Condition); + NCalcUtility.InitializeExpressionUnit(ref c, caster, "Caster"); + if (cmd != null) + { + NCalcUtility.InitializeExpressionCommand(ref c, new BattleCommand(cmd)); + c.Parameters["CommandId"] = (Int32)cmd.cmd_no; + c.Parameters["CommandMenu"] = (Int32)cmd.info.cmdMenu; + } + else + { + if (ability != null) + NCalcUtility.InitializeExpressionRawAbility(ref c, ability, abilId); + else + NCalcUtility.InitializeExpressionRawAbility(ref c, FF9BattleDB.CharacterActions[abilId], abilId); + if (menu == BattleCommandMenu.Ability1 && caster.IsPlayer) + c.Parameters["CommandId"] = (Int32)CharacterCommands.CommandSets[caster.Player.PresetId].Get(caster.IsUnderAnyStatus(BattleStatus.Trance), 0); + else if (menu == BattleCommandMenu.Ability2 && caster.IsPlayer) + c.Parameters["CommandId"] = (Int32)CharacterCommands.CommandSets[caster.Player.PresetId].Get(caster.IsUnderAnyStatus(BattleStatus.Trance), 1); + else + c.Parameters["CommandId"] = (Int32)BattleCommandId.None; + c.Parameters["CommandMenu"] = (Int32)menu; + } + c.EvaluateFunction += NCalcUtility.commonNCalcFunctions; + c.EvaluateParameter += NCalcUtility.commonNCalcParameters; + return NCalcUtility.EvaluateNCalcCondition(c.Evaluate()); + } + + public void ApplyBasicModifiers(CMD_DATA cmd) + { + if (!String.IsNullOrEmpty(AbilityPowerPatch)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityPowerPatch); InitCommandExpression(ref e, cmd); Int64 power = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (power >= 0) cmd.Power = (Byte)power; } - if (AbilityHitRatePatch.TryGetValue(abilId, out featureStr)) + if (!String.IsNullOrEmpty(AbilityHitRatePatch)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityHitRatePatch); InitCommandExpression(ref e, cmd); Int64 hitRate = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (hitRate >= 0) cmd.HitRate = (Byte)hitRate; } - if (AbilityElementPatch.TryGetValue(abilId, out featureStr)) + if (!String.IsNullOrEmpty(AbilityElementPatch)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityElementPatch); InitCommandExpression(ref e, cmd); Int64 element = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (element >= 0) @@ -96,25 +236,25 @@ public static Boolean ApplySpecialCommandCondition(CMD_DATA cmd) cmd.ElementForBonus = cmd.Element; } } - if (AbilityStatusPatch.TryGetValue(abilId, out featureStr)) + if (!String.IsNullOrEmpty(AbilityStatusPatch)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityStatusPatch); InitCommandExpression(ref e, cmd); Int64 status = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (status >= 0) cmd.AbilityStatus = (BattleStatus)status; } - if (AbilityTargetPatch.TryGetValue(abilId, out featureStr)) + if (!String.IsNullOrEmpty(AbilityTargetPatch)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityTargetPatch); InitCommandExpression(ref e, cmd); Int64 target = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (target >= 0) cmd.tar_id = (UInt16)target; } - if (AbilitySpecialEffectPatch.TryGetValue(abilId, out featureStr)) + if (!String.IsNullOrEmpty(AbilitySpecialEffectPatch)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilitySpecialEffectPatch); InitCommandExpression(ref e, cmd); Int64 vfx = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (vfx >= 0) @@ -124,9 +264,13 @@ public static Boolean ApplySpecialCommandCondition(CMD_DATA cmd) cmd.info.meteor_miss = 1; } } - if (AbilityItemRequirement.TryGetValue(abilId, out featureStr)) + } + + public Boolean ApplyCommandCondition(CMD_DATA cmd, ref Int64 totalGilCost) + { + if (!String.IsNullOrEmpty(AbilityItemRequirement)) { - String[] featureSplit = featureStr.Split(';'); + String[] featureSplit = AbilityItemRequirement.Split(';'); Int64 itemType = -1; Int64 itemCount = 1; for (Int32 i = 0; i < featureSplit.Length; i++) @@ -155,89 +299,105 @@ public static Boolean ApplySpecialCommandCondition(CMD_DATA cmd) return false; } } - if (AbilityGilCost.TryGetValue(abilId, out featureStr)) + if (!String.IsNullOrEmpty(AbilityGilCost)) { - PARTY_DATA partyState = FF9StateSystem.Common.FF9.party; - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityGilCost); InitCommandExpression(ref e, cmd); - Int64 gilCost = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); - if (gilCost >= 0) - { - if (gilCost > partyState.gil) - { - UIManager.Battle.SetBattleFollowMessage(BattleMesages.NotEnoughGil); - return false; - } - partyState.gil -= (UInt32)gilCost; - } + Int64 gilCost = NCalcUtility.ConvertNCalcResult(e.Evaluate(), Int64.MinValue); + if (gilCost != Int64.MinValue) + totalGilCost += gilCost; } + return true; } - catch (Exception err) + + public Boolean ApplyMPCost(BattleAbilityId abilId, BattleUnit potentialCaster, ref Int32 mpCost, AA_DATA ability = null, CMD_DATA cmd = null, BattleCommandMenu menu = BattleCommandMenu.None) { - Log.Error(err); + if (ability == null && cmd == null) + { + if (abilId == BattleAbilityId.Void) + return false; + if (!FF9BattleDB.CharacterActions.TryGetValue(abilId, out ability)) + return false; + } + if (ability == null && cmd != null) + ability = cmd.aa; + if (!String.IsNullOrEmpty(AbilityMPCost)) + { + Expression e = new Expression(AbilityMPCost); + NCalcUtility.InitializeExpressionUnit(ref e, potentialCaster, "Caster"); + NCalcUtility.InitializeExpressionRawAbility(ref e, ability, abilId); + if (cmd != null) + { + e.Parameters["CommandId"] = (Int32)cmd.cmd_no; + e.Parameters["CommandMenu"] = (Int32)cmd.info.cmdMenu; + } + else + { + if (menu == BattleCommandMenu.Ability1 && potentialCaster.IsPlayer) + e.Parameters["CommandId"] = (Int32)CharacterCommands.CommandSets[potentialCaster.Player.PresetId].Get(potentialCaster.IsUnderAnyStatus(BattleStatus.Trance), 0); + else if (menu == BattleCommandMenu.Ability2 && potentialCaster.IsPlayer) + e.Parameters["CommandId"] = (Int32)CharacterCommands.CommandSets[potentialCaster.Player.PresetId].Get(potentialCaster.IsUnderAnyStatus(BattleStatus.Trance), 1); + else + e.Parameters["CommandId"] = (Int32)BattleCommandId.None; + e.Parameters["CommandMenu"] = (Int32)menu; + } + e.Parameters["MPCost"] = (Int32)mpCost; + e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; + e.EvaluateParameter += NCalcUtility.commonNCalcParameters; + Int64 mp = NCalcUtility.ConvertNCalcResult(e.Evaluate(), Int64.MinValue); + if (mp != Int64.MinValue) + { + mpCost = (Int32)mp; + return true; + } + } + return false; } - return true; - } - public static void SetCustomPriority(CMD_DATA cmd) - { - BattleAbilityId abilId = btl_util.GetCommandMainActionIndex(cmd); - if (abilId == BattleAbilityId.Void) - return; - String featureStr; - if (AbilityPriority.TryGetValue(abilId, out featureStr)) + public void ApplyPriority(CMD_DATA cmd) { - try + if (!String.IsNullOrEmpty(AbilityPriority)) { - Expression e = new Expression(featureStr); + Expression e = new Expression(AbilityPriority); InitCommandExpression(ref e, cmd); Int64 priority = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); if (priority >= 0) cmd.info.priority = (Byte)priority; } - catch (Exception err) - { - Log.Error(err); - } } - } - private static void InitCommandExpression(ref Expression e, CMD_DATA cmd) - { - BattleUnit caster = new BattleUnit(cmd.regist); - //BattleUnit target = btl_scrp.FindBattleUnitUnlimited((UInt16)Comn.firstBitSet(cmd.tar_id)); - NCalcUtility.InitializeExpressionUnit(ref e, caster, "Caster"); - //NCalcUtility.InitializeExpressionUnit(ref e, target, "Target"); - NCalcUtility.InitializeExpressionCommand(ref e, new BattleCommand(cmd)); - e.Parameters["IsSingleTarget"] = Comn.countBits(cmd.tar_id) == 1; - e.Parameters["IsSelfTarget"] = caster.Id == cmd.tar_id; - e.Parameters["AreCasterAndTargetEnemies"] = (caster.IsPlayer && (cmd.tar_id & 0xF0) == cmd.tar_id) || (!caster.IsPlayer && (cmd.tar_id & 0xF) == cmd.tar_id); - e.Parameters["AreCasterAndTargetAllies"] = (caster.IsPlayer && (cmd.tar_id & 0xF) == cmd.tar_id) || (!caster.IsPlayer && (cmd.tar_id & 0x0F) == cmd.tar_id); - e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; - e.EvaluateParameter += NCalcUtility.commonNCalcParameters; - } - - public static BattleAbilityId Patch(BattleAbilityId id, PLAYER character) - { - String patchStr; - if (AbilityPatch.TryGetValue(id, out patchStr)) + public BattleAbilityId ApplyPatch(BattleAbilityId abilId, PLAYER character) { - try + if (!String.IsNullOrEmpty(AbilityPatch)) { - Expression e = new Expression(patchStr); + Expression e = new Expression(AbilityPatch); e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; e.EvaluateParameter += NCalcUtility.commonNCalcParameters; NCalcUtility.InitializeExpressionPlayer(ref e, character); Int64 val = NCalcUtility.ConvertNCalcResult(e.Evaluate(), -1); - if (val >= 0) + if (val >= 0 && FF9BattleDB.CharacterActions.ContainsKey((BattleAbilityId)val)) return (BattleAbilityId)val; } - catch (Exception err) - { - Log.Error(err); - } + return abilId; + } + + private static void InitCommandExpression(ref Expression e, CMD_DATA cmd) + { + BattleUnit caster = new BattleUnit(cmd.regist); + //BattleUnit target = btl_scrp.FindBattleUnitUnlimited((UInt16)Comn.firstBitSet(cmd.tar_id)); + NCalcUtility.InitializeExpressionUnit(ref e, caster, "Caster"); + //NCalcUtility.InitializeExpressionUnit(ref e, target, "Target"); + NCalcUtility.InitializeExpressionCommand(ref e, new BattleCommand(cmd)); + e.Parameters["IsSingleTarget"] = Comn.countBits(cmd.tar_id) == 1; + e.Parameters["IsSelfTarget"] = caster.Id == cmd.tar_id; + e.Parameters["AreCasterAndTargetEnemies"] = (caster.IsPlayer && (cmd.tar_id & 0xF0) == cmd.tar_id) || (!caster.IsPlayer && (cmd.tar_id & 0xF) == cmd.tar_id); + e.Parameters["AreCasterAndTargetAllies"] = (caster.IsPlayer && (cmd.tar_id & 0xF) == cmd.tar_id) || (!caster.IsPlayer && (cmd.tar_id & 0x0F) == cmd.tar_id); + e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; + e.EvaluateParameter += NCalcUtility.commonNCalcParameters; } - return id; } + + private static Dictionary AbilityFeatures = new Dictionary(); + private static List FlexibleFeatures = new List(); } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Data/Battle/BattleCommandMenu.cs b/Assembly-CSharp/Memoria/Data/Battle/BattleCommandMenu.cs new file mode 100644 index 000000000..4ae39ec1b --- /dev/null +++ b/Assembly-CSharp/Memoria/Data/Battle/BattleCommandMenu.cs @@ -0,0 +1,15 @@ +namespace Memoria.Data +{ + public enum BattleCommandMenu + { + // Only concerns commands that really emanate from a player's input (so no counter-attacks, no Berserk/Confuse attacks...) + None = -1, + Attack = 0, + Defend, + Ability1, + Ability2, + Item, + Change, + AccessMenu = 7, + } +} diff --git a/Assembly-CSharp/Memoria/Data/Characters/CharacterAbilityGems.cs b/Assembly-CSharp/Memoria/Data/Characters/CharacterAbilityGems.cs index bd7cd3f48..09ac7b9cc 100644 --- a/Assembly-CSharp/Memoria/Data/Characters/CharacterAbilityGems.cs +++ b/Assembly-CSharp/Memoria/Data/Characters/CharacterAbilityGems.cs @@ -116,23 +116,23 @@ public void TriggerOnEnable(PLAYER play) NCalcUtility.InitializeExpressionPlayer(ref e, play); e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; e.EvaluateParameter += NCalcUtility.commonNCalcParameters; - if (String.Compare(formula.Key, "MaxHP") == 0) play.max.hp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.max.hp); - else if (String.Compare(formula.Key, "MaxMP") == 0) play.max.mp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.max.mp); - else if (String.Compare(formula.Key, "Speed") == 0) play.basis.dex = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.dex); - else if (String.Compare(formula.Key, "Strength") == 0) play.basis.str = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.str); - else if (String.Compare(formula.Key, "Magic") == 0) play.basis.mgc = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.mgc); - else if (String.Compare(formula.Key, "Spirit") == 0) play.basis.wpr = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.wpr); - else if (String.Compare(formula.Key, "Defence") == 0) play.defence.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.PhysicalDefence); - else if (String.Compare(formula.Key, "Evade") == 0) play.defence.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.PhysicalEvade); - else if (String.Compare(formula.Key, "MagicDefence") == 0) play.defence.MagicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.MagicalDefence); - else if (String.Compare(formula.Key, "MagicEvade") == 0) play.defence.MagicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.MagicalEvade); - else if (String.Compare(formula.Key, "PlayerCategory") == 0) play.category = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.category); - else if (String.Compare(formula.Key, "MPCostFactor") == 0) play.mpCostFactor = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.mpCostFactor); - else if (String.Compare(formula.Key, "MaxHPLimit") == 0) play.maxHpLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxHpLimit); - else if (String.Compare(formula.Key, "MaxMPLimit") == 0) play.maxMpLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxMpLimit); - else if (String.Compare(formula.Key, "MaxDamageLimit") == 0) play.maxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxDamageLimit); - else if (String.Compare(formula.Key, "MaxMPDamageLimit") == 0) play.maxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxMpDamageLimit); - else if (String.Compare(formula.Key, "PlayerPermanentStatus") == 0) play.SetPermanentStatus((BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)play.permanent_status)); + if (String.Equals(formula.Key, "MaxHP")) play.max.hp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.max.hp); + else if (String.Equals(formula.Key, "MaxMP")) play.max.mp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.max.mp); + else if (String.Equals(formula.Key, "Speed")) play.basis.dex = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.dex); + else if (String.Equals(formula.Key, "Strength")) play.basis.str = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.str); + else if (String.Equals(formula.Key, "Magic")) play.basis.mgc = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.mgc); + else if (String.Equals(formula.Key, "Spirit")) play.basis.wpr = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.basis.wpr); + else if (String.Equals(formula.Key, "Defence")) play.defence.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.PhysicalDefence); + else if (String.Equals(formula.Key, "Evade")) play.defence.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.PhysicalEvade); + else if (String.Equals(formula.Key, "MagicDefence")) play.defence.MagicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.MagicalDefence); + else if (String.Equals(formula.Key, "MagicEvade")) play.defence.MagicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.defence.MagicalEvade); + else if (String.Equals(formula.Key, "PlayerCategory")) play.category = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.category); + else if (String.Equals(formula.Key, "MPCostFactor")) play.mpCostFactor = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.mpCostFactor); + else if (String.Equals(formula.Key, "MaxHPLimit")) play.maxHpLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxHpLimit); + else if (String.Equals(formula.Key, "MaxMPLimit")) play.maxMpLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxMpLimit); + else if (String.Equals(formula.Key, "MaxDamageLimit")) play.maxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxDamageLimit); + else if (String.Equals(formula.Key, "MaxMPDamageLimit")) play.maxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.maxMpDamageLimit); + else if (String.Equals(formula.Key, "PlayerPermanentStatus")) play.SetPermanentStatus((BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)play.permanent_status)); } } } @@ -161,8 +161,8 @@ public void TriggerOnBattleStart(ref Int32 backAttackChance, ref Int32 preemptiv Expression e = new Expression(formula.Value); e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; e.EvaluateParameter += NCalcUtility.commonNCalcParameters; - if (String.Compare(formula.Key, "BackAttack") == 0) backAttackChance = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), backAttackChance); - else if (String.Compare(formula.Key, "Preemptive") == 0) preemptiveChance = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), preemptiveChance); + if (String.Equals(formula.Key, "BackAttack")) backAttackChance = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), backAttackChance); + else if (String.Equals(formula.Key, "Preemptive")) preemptiveChance = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), preemptiveChance); } preemptivePriority += BattleStartEffect[i].PreemptivePriorityDelta; } @@ -180,7 +180,7 @@ public Boolean TriggerOnBattleResult(PLAYER play, BONUS bonus, List bon { for (Int32 i = 0; i < BattleResultEffect.Count; i++) { - if (String.Compare(BattleResultEffect[i].When, when) == 0) + if (String.Equals(BattleResultEffect[i].When, when)) { if (BattleResultEffect[i].Condition.Length > 0) { @@ -199,7 +199,10 @@ public Boolean TriggerOnBattleResult(PLAYER play, BONUS bonus, List bon triggeredAtLeastOnce = true; foreach (KeyValuePair formula in BattleResultEffect[i].Formula) { - Expression e = new Expression(formula.Value); + String[] formulaSplit = formula.Value.Split(';'); + if (formulaSplit.Length == 0) + continue; + Expression e = new Expression(formulaSplit[0]); NCalcUtility.InitializeExpressionPlayer(ref e, play); NCalcUtility.InitializeExpressionBonus(ref e, bonus, bonus_item); e.Parameters["IsFlee"] = FF9StateSystem.Common.FF9.btl_result == 4; @@ -208,14 +211,79 @@ public Boolean TriggerOnBattleResult(PLAYER play, BONUS bonus, List bon e.Parameters["Status"] = (UInt32)play.status; e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; e.EvaluateParameter += NCalcUtility.commonNCalcParameters; - if (String.Compare(formula.Key, "FleeGil") == 0) fleeGil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), fleeGil); - else if (String.Compare(formula.Key, "HP") == 0) play.cur.hp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.cur.hp); - else if (String.Compare(formula.Key, "MP") == 0) play.cur.mp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.cur.mp); - else if (String.Compare(formula.Key, "Status") == 0) play.status = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)play.status); - else if (String.Compare(formula.Key, "BonusAP") == 0) bonus.ap = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus.ap); - else if (String.Compare(formula.Key, "BonusCard") == 0) bonus.card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)bonus.card); - else if (String.Compare(formula.Key, "BonusExp") == 0) bonus.exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus.exp); - else if (String.Compare(formula.Key, "BonusGil") == 0) bonus.gil = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus.gil); + if (String.Equals(formula.Key, "FleeGil")) fleeGil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), fleeGil); + else if (String.Equals(formula.Key, "HP")) play.cur.hp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.cur.hp); + else if (String.Equals(formula.Key, "MP")) play.cur.mp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), play.cur.mp); + else if (String.Equals(formula.Key, "Status")) play.status = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)play.status); + else if (String.Equals(formula.Key, "BonusAP")) bonus.ap = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus.ap); + else if (String.Equals(formula.Key, "BonusCard")) bonus.card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)bonus.card); + else if (String.Equals(formula.Key, "BonusExp")) bonus.exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus.exp); + else if (String.Equals(formula.Key, "BonusGil")) bonus.gil = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus.gil); + else if (String.Equals(formula.Key, "BonusItemAdd")) + { + List allArgs = new List(formulaSplit.Length); + allArgs.Add(e); + for (Int32 argi = 1; argi < formulaSplit.Length; argi++) + { + Expression arge = new Expression(formulaSplit[argi]); + NCalcUtility.InitializeExpressionPlayer(ref arge, play); + NCalcUtility.InitializeExpressionBonus(ref arge, bonus, bonus_item); + arge.Parameters["IsFlee"] = FF9StateSystem.Common.FF9.btl_result == 4; + arge.Parameters["IsFleeByLuck"] = FF9StateSystem.Common.FF9.btl_result == 4 && (FF9StateSystem.Common.FF9.btl_flag & 4) == 0; + arge.Parameters["FleeGil"] = fleeGil; + arge.Parameters["Status"] = (UInt32)play.status; + arge.EvaluateFunction += NCalcUtility.commonNCalcFunctions; + arge.EvaluateParameter += NCalcUtility.commonNCalcParameters; + allArgs.Add(arge); + } + for (Int32 itcounter = 0; itcounter < allArgs.Count; itcounter += 2) + { + RegularItem itType = (RegularItem)NCalcUtility.ConvertNCalcResult(allArgs[itcounter].Evaluate(), (Int32)RegularItem.NoItem); + if (itType == RegularItem.NoItem) + continue; + UInt32 count = 1; + if (allArgs.Count > itcounter + 1) + count = (UInt32)NCalcUtility.ConvertNCalcResult(allArgs[itcounter + 1].Evaluate(), 1); + for (Int32 j = 0; j < BattleResultUI.ItemMax; j++) + { + if (bonus_item.Count <= j) + bonus_item.Add(new FF9ITEM(itType, 0)); + if (bonus_item[j].id == RegularItem.NoItem) + { + bonus_item[j].id = itType; + bonus_item[j].count = 0; + } + if (bonus_item[j].id == itType) + { + bonus_item[j].count = (Byte)Math.Min(bonus_item[j].count + count, Byte.MaxValue); + break; + } + } + } + } + else if (String.Equals(formula.Key, "EachBonusItem")) + { + for (Int32 j = 0; j < bonus_item.Count; j++) + { + if (bonus_item[j].id == RegularItem.NoItem) + continue; + e.Parameters["EachBonusItem"] = (Int32)bonus_item[j].id; + e.Parameters["EachBonusItemCount"] = (Int32)bonus_item[j].count; + RegularItem oldit = bonus_item[j].id; + bonus_item[j].id = (RegularItem)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)bonus_item[j].id); + } + } + else if (String.Equals(formula.Key, "EachBonusItemCount")) + { + for (Int32 j = 0; j < bonus_item.Count; j++) + { + if (bonus_item[j].id == RegularItem.NoItem || bonus_item[j].count == 0) + continue; + e.Parameters["EachBonusItem"] = (Int32)bonus_item[j].id; + e.Parameters["EachBonusItemCount"] = (Int32)bonus_item[j].count; + bonus_item[j].count = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), 0); + } + } else { for (Int32 j = 0; j < BattleResultUI.ItemMax; j++) @@ -230,7 +298,6 @@ public Boolean TriggerOnBattleResult(PLAYER play, BONUS bonus, List bon { while (bonus_item.Count <= j) bonus_item.Add(new FF9ITEM(RegularItem.NoItem, 0)); bonus_item[j].count = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), bonus_item[j].count); - if (bonus_item[j].count == 0) bonus_item[j].id = RegularItem.NoItem; } } } @@ -314,7 +381,7 @@ public void TriggerOnAbility(BattleCalculator calc, String when, Boolean asTarge Boolean canMove = asTarget ? !calc.Target.IsUnderAnyStatus(BattleStatusConst.NoReaction) : !calc.Caster.IsUnderAnyStatus(BattleStatusConst.NoReaction); for (Int32 i = 0; i < AbilityEffect.Count; i++) { - if (AbilityEffect[i].AsTarget == asTarget && (canMove || AbilityEffect[i].EvenImmobilized) && String.Compare(AbilityEffect[i].When, when) == 0) + if (AbilityEffect[i].AsTarget == asTarget && (canMove || AbilityEffect[i].EvenImmobilized) && String.Equals(AbilityEffect[i].When, when)) { BattleCaster caster = calc.Caster; BattleTarget target = calc.Target; @@ -335,126 +402,152 @@ public void TriggerOnAbility(BattleCalculator calc, String when, Boolean asTarge BattleStatus tCurStat = target.CurrentStatus, tAutoStat = target.PermanentStatus, tResistStat = target.ResistStatus; foreach (KeyValuePair formula in AbilityEffect[i].Effect) { - Expression e = new Expression(formula.Value); + String[] formulaSplit = formula.Value.Split(';'); + if (formulaSplit.Length == 0) + continue; + Expression e = new Expression(formulaSplit[0]); NCalcUtility.InitializeExpressionUnit(ref e, caster, "Caster"); NCalcUtility.InitializeExpressionUnit(ref e, target, "Target"); NCalcUtility.InitializeExpressionAbilityContext(ref e, calc); e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; e.EvaluateParameter += NCalcUtility.commonNCalcParameters; - if (String.Compare(formula.Key, "CasterHP") == 0) caster.CurrentHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CurrentHp); - else if (String.Compare(formula.Key, "CasterMP") == 0) caster.CurrentMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CurrentMp); - else if (String.Compare(formula.Key, "CasterMaxHP") == 0) caster.MaximumHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaximumHp); - else if (String.Compare(formula.Key, "CasterMaxMP") == 0) caster.MaximumMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaximumMp); - else if (String.Compare(formula.Key, "CasterATB") == 0) caster.CurrentAtb = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CurrentAtb); - else if (String.Compare(formula.Key, "CasterTrance") == 0) caster.Trance = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Trance); - else if (String.Compare(formula.Key, "CasterCurrentStatus") == 0) cCurStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)cCurStat); - else if (String.Compare(formula.Key, "CasterPermanentStatus") == 0) cAutoStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)cAutoStat); - else if (String.Compare(formula.Key, "CasterResistStatus") == 0) cResistStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)cResistStat); - else if (String.Compare(formula.Key, "CasterHalfElement") == 0) caster.HalfElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.HalfElement); - else if (String.Compare(formula.Key, "CasterGuardElement") == 0) caster.GuardElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.GuardElement); - else if (String.Compare(formula.Key, "CasterAbsorbElement") == 0) caster.AbsorbElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.AbsorbElement); - else if (String.Compare(formula.Key, "CasterWeakElement") == 0) caster.WeakElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.WeakElement); - else if (String.Compare(formula.Key, "CasterBonusElement") == 0) caster.BonusElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.BonusElement); - else if (String.Compare(formula.Key, "CasterSpeed") == 0) caster.Dexterity = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Dexterity); - else if (String.Compare(formula.Key, "CasterStrength") == 0) caster.Strength = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Strength); - else if (String.Compare(formula.Key, "CasterMagic") == 0) caster.Magic = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Magic); - else if (String.Compare(formula.Key, "CasterSpirit") == 0) caster.Will = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Will); - else if (String.Compare(formula.Key, "CasterDefence") == 0) caster.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.PhysicalDefence); - else if (String.Compare(formula.Key, "CasterEvade") == 0) caster.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.PhysicalEvade); - else if (String.Compare(formula.Key, "CasterMagicDefence") == 0) caster.MagicDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MagicDefence); - else if (String.Compare(formula.Key, "CasterMagicEvade") == 0) caster.MagicEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MagicEvade); - else if (String.Compare(formula.Key, "CasterRow") == 0) caster.Row = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Row); - else if (String.Compare(formula.Key, "CasterSummonCount") == 0) caster.SummonCount = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.SummonCount); - else if (String.Compare(formula.Key, "CasterIsStrengthModified") == 0) caster.StatModifier[0] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[0]); - else if (String.Compare(formula.Key, "CasterIsMagicModified") == 0) caster.StatModifier[1] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[1]); - else if (String.Compare(formula.Key, "CasterIsDefenceModified") == 0) caster.StatModifier[2] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[2]); - else if (String.Compare(formula.Key, "CasterIsEvadeModified") == 0) caster.StatModifier[3] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[3]); - else if (String.Compare(formula.Key, "CasterIsMagicDefenceModified") == 0) caster.StatModifier[4] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[4]); - else if (String.Compare(formula.Key, "CasterIsMagicEvadeModified") == 0) caster.StatModifier[5] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[5]); - else if (String.Compare(formula.Key, "CasterCriticalRateBonus") == 0) caster.CriticalRateBonus = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CriticalRateBonus); - else if (String.Compare(formula.Key, "CasterCriticalRateWeakening") == 0) caster.CriticalRateWeakening = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CriticalRateWeakening); - else if (String.Compare(formula.Key, "CasterMaxDamageLimit") == 0) caster.MaxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaxDamageLimit); - else if (String.Compare(formula.Key, "CasterMaxMPDamageLimit") == 0) caster.MaxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaxMpDamageLimit); - else if (String.Compare(formula.Key, "CasterBonusExp") == 0 && !caster.IsPlayer) caster.Enemy.Data.bonus_exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Enemy.Data.bonus_exp); - else if (String.Compare(formula.Key, "CasterBonusGil") == 0 && !caster.IsPlayer) caster.Enemy.Data.bonus_gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Enemy.Data.bonus_gil); - else if (String.Compare(formula.Key, "CasterBonusCard") == 0 && !caster.IsPlayer) caster.Enemy.Data.bonus_card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)caster.Enemy.Data.bonus_card); - else if (String.Compare(formula.Key, "TargetHP") == 0) target.CurrentHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CurrentHp); - else if (String.Compare(formula.Key, "TargetMP") == 0) target.CurrentMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CurrentMp); - else if (String.Compare(formula.Key, "TargetMaxHP") == 0) target.MaximumHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaximumHp); - else if (String.Compare(formula.Key, "TargetMaxMP") == 0) target.MaximumMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaximumMp); - else if (String.Compare(formula.Key, "TargetATB") == 0) target.CurrentAtb = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CurrentAtb); - else if (String.Compare(formula.Key, "TargetTrance") == 0) target.Trance = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Trance); - else if (String.Compare(formula.Key, "TargetCurrentStatus") == 0) tCurStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)tCurStat); - else if (String.Compare(formula.Key, "TargetPermanentStatus") == 0) tAutoStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)tAutoStat); - else if (String.Compare(formula.Key, "TargetResistStatus") == 0) tResistStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)tResistStat); - else if (String.Compare(formula.Key, "TargetHalfElement") == 0) target.HalfElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.HalfElement); - else if (String.Compare(formula.Key, "TargetGuardElement") == 0) target.GuardElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.GuardElement); - else if (String.Compare(formula.Key, "TargetAbsorbElement") == 0) target.AbsorbElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.AbsorbElement); - else if (String.Compare(formula.Key, "TargetWeakElement") == 0) target.WeakElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.WeakElement); - else if (String.Compare(formula.Key, "TargetBonusElement") == 0) target.BonusElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.BonusElement); - else if (String.Compare(formula.Key, "TargetSpeed") == 0) target.Dexterity = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Dexterity); - else if (String.Compare(formula.Key, "TargetStrength") == 0) target.Strength = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Strength); - else if (String.Compare(formula.Key, "TargetMagic") == 0) target.Magic = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Magic); - else if (String.Compare(formula.Key, "TargetSpirit") == 0) target.Will = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Will); - else if (String.Compare(formula.Key, "TargetDefence") == 0) target.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.PhysicalDefence); - else if (String.Compare(formula.Key, "TargetEvade") == 0) target.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.PhysicalEvade); - else if (String.Compare(formula.Key, "TargetMagicDefence") == 0) target.MagicDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MagicDefence); - else if (String.Compare(formula.Key, "TargetMagicEvade") == 0) target.MagicEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MagicEvade); - else if (String.Compare(formula.Key, "TargetRow") == 0) target.Row = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Row); - else if (String.Compare(formula.Key, "TargetSummonCount") == 0) target.SummonCount = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.SummonCount); - else if (String.Compare(formula.Key, "TargetIsStrengthModified") == 0) target.StatModifier[0] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[0]); - else if (String.Compare(formula.Key, "TargetIsMagicModified") == 0) target.StatModifier[1] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[1]); - else if (String.Compare(formula.Key, "TargetIsDefenceModified") == 0) target.StatModifier[2] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[2]); - else if (String.Compare(formula.Key, "TargetIsEvadeModified") == 0) target.StatModifier[3] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[3]); - else if (String.Compare(formula.Key, "TargetIsMagicDefenceModified") == 0) target.StatModifier[4] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[4]); - else if (String.Compare(formula.Key, "TargetIsMagicEvadeModified") == 0) target.StatModifier[5] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[5]); - else if (String.Compare(formula.Key, "TargetCriticalRateBonus") == 0) target.CriticalRateBonus = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CriticalRateBonus); - else if (String.Compare(formula.Key, "TargetCriticalRateWeakening") == 0) target.CriticalRateWeakening = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CriticalRateWeakening); - else if (String.Compare(formula.Key, "TargetMaxDamageLimit") == 0) target.MaxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaxDamageLimit); - else if (String.Compare(formula.Key, "TargetMaxMPDamageLimit") == 0) target.MaxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaxMpDamageLimit); - else if (String.Compare(formula.Key, "TargetBonusExp") == 0 && !target.IsPlayer) target.Enemy.Data.bonus_exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Enemy.Data.bonus_exp); - else if (String.Compare(formula.Key, "TargetBonusGil") == 0 && !target.IsPlayer) target.Enemy.Data.bonus_gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Enemy.Data.bonus_gil); - else if (String.Compare(formula.Key, "TargetBonusCard") == 0 && !target.IsPlayer) target.Enemy.Data.bonus_card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)target.Enemy.Data.bonus_card); - else if (String.Compare(formula.Key, "EffectCasterFlags") == 0) caster.Flags = (CalcFlag)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.Flags); - else if (String.Compare(formula.Key, "CasterHPDamage") == 0) caster.HpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.HpDamage); - else if (String.Compare(formula.Key, "CasterMPDamage") == 0) caster.MpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MpDamage); - else if (String.Compare(formula.Key, "EffectTargetFlags") == 0) target.Flags = (CalcFlag)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.Flags); - else if (String.Compare(formula.Key, "HPDamage") == 0) target.HpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.HpDamage); - else if (String.Compare(formula.Key, "MPDamage") == 0) target.MpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MpDamage); - else if (String.Compare(formula.Key, "FigureInfo") == 0) target.Data.fig_info = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Data.fig_info); - else if (String.Compare(formula.Key, "Power") == 0) command.Power = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.Power); - else if (String.Compare(formula.Key, "AbilityStatus") == 0) command.AbilityStatus = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)command.AbilityStatus); - else if (String.Compare(formula.Key, "AbilityElement") == 0) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); - else if (String.Compare(formula.Key, "AbilityElementForBonus") == 0) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); - else if (String.Compare(formula.Key, "IsShortRanged") == 0) command.IsShortRange = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsShortRange); - else if (String.Compare(formula.Key, "IsDrain") == 0) context.IsDrain = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), context.IsDrain); - else if (String.Compare(formula.Key, "AbilityCategory") == 0) command.AbilityCategory = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityCategory); - else if (String.Compare(formula.Key, "AbilityFlags") == 0) command.AbilityType = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityType); - else if (String.Compare(formula.Key, "Attack") == 0) context.Attack = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.Attack); - else if (String.Compare(formula.Key, "AttackPower") == 0) context.AttackPower = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.AttackPower); - else if (String.Compare(formula.Key, "DefencePower") == 0) context.DefensePower = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.DefensePower); - else if (String.Compare(formula.Key, "StatusRate") == 0) context.StatusRate = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.StatusRate); - else if (String.Compare(formula.Key, "HitRate") == 0) context.HitRate = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.HitRate); - else if (String.Compare(formula.Key, "Evade") == 0) context.Evade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.Evade); - else if (String.Compare(formula.Key, "EffectFlags") == 0) context.Flags = (BattleCalcFlags)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt16)context.Flags); - else if (String.Compare(formula.Key, "DamageModifierCount") == 0) context.DamageModifierCount = (SByte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.DamageModifierCount); - else if (String.Compare(formula.Key, "TranceIncrease") == 0) context.TranceIncrease = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.TranceIncrease); - else if (String.Compare(formula.Key, "ItemSteal") == 0) context.ItemSteal = (RegularItem)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)context.ItemSteal); - else if (String.Compare(formula.Key, "Gil") == 0) GameState.Gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), GameState.Gil); - else if (String.Compare(formula.Key, "BattleBonusAP") == 0) battle.btl_bonus.ap = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), battle.btl_bonus.ap); - else if (String.Compare(formula.Key, "Counter") == 0) + if (String.Equals(formula.Key, "CasterHP")) caster.CurrentHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CurrentHp); + else if (String.Equals(formula.Key, "CasterMP")) caster.CurrentMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CurrentMp); + else if (String.Equals(formula.Key, "CasterMaxHP")) caster.MaximumHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaximumHp); + else if (String.Equals(formula.Key, "CasterMaxMP")) caster.MaximumMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaximumMp); + else if (String.Equals(formula.Key, "CasterATB")) caster.CurrentAtb = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CurrentAtb); + else if (String.Equals(formula.Key, "CasterTrance")) caster.Trance = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Trance); + else if (String.Equals(formula.Key, "CasterCurrentStatus")) cCurStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)cCurStat); + else if (String.Equals(formula.Key, "CasterPermanentStatus")) cAutoStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)cAutoStat); + else if (String.Equals(formula.Key, "CasterResistStatus")) cResistStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)cResistStat); + else if (String.Equals(formula.Key, "CasterHalfElement")) caster.HalfElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.HalfElement); + else if (String.Equals(formula.Key, "CasterGuardElement")) caster.GuardElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.GuardElement); + else if (String.Equals(formula.Key, "CasterAbsorbElement")) caster.AbsorbElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.AbsorbElement); + else if (String.Equals(formula.Key, "CasterWeakElement")) caster.WeakElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.WeakElement); + else if (String.Equals(formula.Key, "CasterBonusElement")) caster.BonusElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.BonusElement); + else if (String.Equals(formula.Key, "CasterSpeed")) caster.Dexterity = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Dexterity); + else if (String.Equals(formula.Key, "CasterStrength")) caster.Strength = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Strength); + else if (String.Equals(formula.Key, "CasterMagic")) caster.Magic = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Magic); + else if (String.Equals(formula.Key, "CasterSpirit")) caster.Will = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Will); + else if (String.Equals(formula.Key, "CasterDefence")) caster.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.PhysicalDefence); + else if (String.Equals(formula.Key, "CasterEvade")) caster.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.PhysicalEvade); + else if (String.Equals(formula.Key, "CasterMagicDefence")) caster.MagicDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MagicDefence); + else if (String.Equals(formula.Key, "CasterMagicEvade")) caster.MagicEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MagicEvade); + else if (String.Equals(formula.Key, "CasterRow")) caster.Row = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Row); + else if (String.Equals(formula.Key, "CasterSummonCount")) caster.SummonCount = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.SummonCount); + else if (String.Equals(formula.Key, "CasterIsStrengthModified")) caster.StatModifier[0] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[0]); + else if (String.Equals(formula.Key, "CasterIsMagicModified")) caster.StatModifier[1] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[1]); + else if (String.Equals(formula.Key, "CasterIsDefenceModified")) caster.StatModifier[2] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[2]); + else if (String.Equals(formula.Key, "CasterIsEvadeModified")) caster.StatModifier[3] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[3]); + else if (String.Equals(formula.Key, "CasterIsMagicDefenceModified")) caster.StatModifier[4] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[4]); + else if (String.Equals(formula.Key, "CasterIsMagicEvadeModified")) caster.StatModifier[5] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), caster.StatModifier[5]); + else if (String.Equals(formula.Key, "CasterCriticalRateBonus")) caster.CriticalRateBonus = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CriticalRateBonus); + else if (String.Equals(formula.Key, "CasterCriticalRateWeakening")) caster.CriticalRateWeakening = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.CriticalRateWeakening); + else if (String.Equals(formula.Key, "CasterMaxDamageLimit")) caster.MaxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaxDamageLimit); + else if (String.Equals(formula.Key, "CasterMaxMPDamageLimit")) caster.MaxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MaxMpDamageLimit); + else if (String.Equals(formula.Key, "CasterBonusExp") && !caster.IsPlayer) caster.Enemy.Data.bonus_exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Enemy.Data.bonus_exp); + else if (String.Equals(formula.Key, "CasterBonusGil") && !caster.IsPlayer) caster.Enemy.Data.bonus_gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.Enemy.Data.bonus_gil); + else if (String.Equals(formula.Key, "CasterBonusCard") && !caster.IsPlayer) caster.Enemy.Data.bonus_card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)caster.Enemy.Data.bonus_card); + else if (String.Equals(formula.Key, "TargetHP")) target.CurrentHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CurrentHp); + else if (String.Equals(formula.Key, "TargetMP")) target.CurrentMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CurrentMp); + else if (String.Equals(formula.Key, "TargetMaxHP")) target.MaximumHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaximumHp); + else if (String.Equals(formula.Key, "TargetMaxMP")) target.MaximumMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaximumMp); + else if (String.Equals(formula.Key, "TargetATB")) target.CurrentAtb = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CurrentAtb); + else if (String.Equals(formula.Key, "TargetTrance")) target.Trance = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Trance); + else if (String.Equals(formula.Key, "TargetCurrentStatus")) tCurStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)tCurStat); + else if (String.Equals(formula.Key, "TargetPermanentStatus")) tAutoStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)tAutoStat); + else if (String.Equals(formula.Key, "TargetResistStatus")) tResistStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)tResistStat); + else if (String.Equals(formula.Key, "TargetHalfElement")) target.HalfElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.HalfElement); + else if (String.Equals(formula.Key, "TargetGuardElement")) target.GuardElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.GuardElement); + else if (String.Equals(formula.Key, "TargetAbsorbElement")) target.AbsorbElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.AbsorbElement); + else if (String.Equals(formula.Key, "TargetWeakElement")) target.WeakElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.WeakElement); + else if (String.Equals(formula.Key, "TargetBonusElement")) target.BonusElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.BonusElement); + else if (String.Equals(formula.Key, "TargetSpeed")) target.Dexterity = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Dexterity); + else if (String.Equals(formula.Key, "TargetStrength")) target.Strength = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Strength); + else if (String.Equals(formula.Key, "TargetMagic")) target.Magic = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Magic); + else if (String.Equals(formula.Key, "TargetSpirit")) target.Will = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Will); + else if (String.Equals(formula.Key, "TargetDefence")) target.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.PhysicalDefence); + else if (String.Equals(formula.Key, "TargetEvade")) target.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.PhysicalEvade); + else if (String.Equals(formula.Key, "TargetMagicDefence")) target.MagicDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MagicDefence); + else if (String.Equals(formula.Key, "TargetMagicEvade")) target.MagicEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MagicEvade); + else if (String.Equals(formula.Key, "TargetRow")) target.Row = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Row); + else if (String.Equals(formula.Key, "TargetSummonCount")) target.SummonCount = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.SummonCount); + else if (String.Equals(formula.Key, "TargetIsStrengthModified")) target.StatModifier[0] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[0]); + else if (String.Equals(formula.Key, "TargetIsMagicModified")) target.StatModifier[1] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[1]); + else if (String.Equals(formula.Key, "TargetIsDefenceModified")) target.StatModifier[2] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[2]); + else if (String.Equals(formula.Key, "TargetIsEvadeModified")) target.StatModifier[3] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[3]); + else if (String.Equals(formula.Key, "TargetIsMagicDefenceModified")) target.StatModifier[4] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[4]); + else if (String.Equals(formula.Key, "TargetIsMagicEvadeModified")) target.StatModifier[5] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), target.StatModifier[5]); + else if (String.Equals(formula.Key, "TargetCriticalRateBonus")) target.CriticalRateBonus = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CriticalRateBonus); + else if (String.Equals(formula.Key, "TargetCriticalRateWeakening")) target.CriticalRateWeakening = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.CriticalRateWeakening); + else if (String.Equals(formula.Key, "TargetMaxDamageLimit")) target.MaxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaxDamageLimit); + else if (String.Equals(formula.Key, "TargetMaxMPDamageLimit")) target.MaxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MaxMpDamageLimit); + else if (String.Equals(formula.Key, "TargetBonusExp") && !target.IsPlayer) target.Enemy.Data.bonus_exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Enemy.Data.bonus_exp); + else if (String.Equals(formula.Key, "TargetBonusGil") && !target.IsPlayer) target.Enemy.Data.bonus_gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Enemy.Data.bonus_gil); + else if (String.Equals(formula.Key, "TargetBonusCard") && !target.IsPlayer) target.Enemy.Data.bonus_card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)target.Enemy.Data.bonus_card); + else if (String.Equals(formula.Key, "EffectCasterFlags")) caster.Flags = (CalcFlag)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)caster.Flags); + else if (String.Equals(formula.Key, "CasterHPDamage")) caster.HpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.HpDamage); + else if (String.Equals(formula.Key, "CasterMPDamage")) caster.MpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), caster.MpDamage); + else if (String.Equals(formula.Key, "EffectTargetFlags")) target.Flags = (CalcFlag)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)target.Flags); + else if (String.Equals(formula.Key, "HPDamage")) target.HpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.HpDamage); + else if (String.Equals(formula.Key, "MPDamage")) target.MpDamage = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.MpDamage); + else if (String.Equals(formula.Key, "FigureInfo")) target.Data.fig_info = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), target.Data.fig_info); + else if (String.Equals(formula.Key, "Power")) command.Power = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.Power); + else if (String.Equals(formula.Key, "AbilityStatus")) command.AbilityStatus = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)command.AbilityStatus); + else if (String.Equals(formula.Key, "AbilityElement")) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); + else if (String.Equals(formula.Key, "AbilityElementForBonus")) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); + else if (String.Equals(formula.Key, "IsShortRanged")) command.IsShortRange = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsShortRange); + else if (String.Equals(formula.Key, "IsDrain")) context.IsDrain = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), context.IsDrain); + else if (String.Equals(formula.Key, "AbilityCategory")) command.AbilityCategory = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityCategory); + else if (String.Equals(formula.Key, "AbilityFlags")) command.AbilityType = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityType); + else if (String.Equals(formula.Key, "Attack")) context.Attack = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.Attack); + else if (String.Equals(formula.Key, "AttackPower")) context.AttackPower = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.AttackPower); + else if (String.Equals(formula.Key, "DefencePower")) context.DefensePower = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.DefensePower); + else if (String.Equals(formula.Key, "StatusRate")) context.StatusRate = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.StatusRate); + else if (String.Equals(formula.Key, "HitRate")) context.HitRate = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.HitRate); + else if (String.Equals(formula.Key, "Evade")) context.Evade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.Evade); + else if (String.Equals(formula.Key, "EffectFlags")) context.Flags = (BattleCalcFlags)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt16)context.Flags); + else if (String.Equals(formula.Key, "DamageModifierCount")) context.DamageModifierCount = (SByte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.DamageModifierCount); + else if (String.Equals(formula.Key, "TranceIncrease")) context.TranceIncrease = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), context.TranceIncrease); + else if (String.Equals(formula.Key, "ItemSteal")) context.ItemSteal = (RegularItem)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)context.ItemSteal); + else if (String.Equals(formula.Key, "Gil")) GameState.Gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), GameState.Gil); + else if (String.Equals(formula.Key, "BattleBonusAP")) battle.btl_bonus.ap = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), battle.btl_bonus.ap); + else if (String.Equals(formula.Key, "Counter")) { + List allArgs = new List(formulaSplit.Length); + allArgs.Add(e); + for (Int32 argi = 1; argi < formulaSplit.Length; argi++) + { + Expression arge = new Expression(formulaSplit[argi]); + NCalcUtility.InitializeExpressionUnit(ref arge, caster, "Caster"); + NCalcUtility.InitializeExpressionUnit(ref arge, target, "Target"); + NCalcUtility.InitializeExpressionAbilityContext(ref arge, calc); + arge.EvaluateFunction += NCalcUtility.commonNCalcFunctions; + arge.EvaluateParameter += NCalcUtility.commonNCalcParameters; + allArgs.Add(arge); + } Int32 attackId = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)BattleAbilityId.Attack); - if (attackId == (Int32)BattleAbilityId.Void && !EnableAsEnemy && !EnableAsMonsterTransform) + BattleCommandId counterCmd = EnableAsEnemy || EnableAsMonsterTransform ? BattleCommandId.EnemyCounter : BattleCommandId.Counter; + if (allArgs.Count > 1) + counterCmd = (BattleCommandId)NCalcUtility.ConvertNCalcResult(allArgs[1].Evaluate(), (Int32)BattleCommandId.Counter); + if (attackId == (Int32)BattleAbilityId.Void && counterCmd != BattleCommandId.EnemyCounter && counterCmd != BattleCommandId.MagicCounter) continue; BTL_DATA counterer = asTarget ? target.Data : caster.Data; UInt16 countered = asTarget ? caster.Id : target.Id; - if (EnableAsEnemy || EnableAsMonsterTransform) - btl_cmd.SetCounter(counterer, BattleCommandId.EnemyCounter, attackId, countered); - else - btl_cmd.SetCounter(counterer, BattleCommandId.Counter, attackId, countered); + if (allArgs.Count > 2) + countered = (UInt16)NCalcUtility.ConvertNCalcResult(allArgs[2].Evaluate(), 0); + if (allArgs.Count > 3) + { + UInt16 countererId = (UInt16)NCalcUtility.ConvertNCalcResult(allArgs[3].Evaluate(), 0); + if (countererId == 0) + continue; + counterer = btl_scrp.FindBattleUnit((UInt16)Comn.firstBitSet(countererId))?.Data ?? null; + if (counterer == null) + continue; + } + btl_cmd.SetCounter(counterer, counterCmd, attackId, countered); } - else if (String.Compare(formula.Key, "ReturnMagic") == 0) + else if (String.Equals(formula.Key, "ReturnMagic")) { //NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)BattleAbilityId.Attack); if (asTarget) @@ -462,7 +555,7 @@ public void TriggerOnAbility(BattleCalculator calc, String when, Boolean asTarge else btl_abil.TryReturnMagic(caster, target, command); } - else if (String.Compare(formula.Key, "AutoItem") == 0) + else if (String.Equals(formula.Key, "AutoItem")) { BTL_DATA counterer = asTarget ? target.Data : caster.Data; if (counterer.is_monster_transform && counterer.monster_transform.disable_commands.Contains(BattleCommandId.Item)) @@ -553,58 +646,58 @@ public void TriggerOnCommand(BattleUnit abilityUser, BattleCommand command, ref e.Parameters["AreCasterAndTargetAllies"] = caster != null && (caster.IsPlayer && (command.Data.tar_id & 0xF) == command.Data.tar_id || !caster.IsPlayer && (command.Data.tar_id & 0x0F) == command.Data.tar_id); e.EvaluateFunction += NCalcUtility.commonNCalcFunctions; e.EvaluateParameter += NCalcUtility.commonNCalcParameters; - if (String.Compare(formula.Key, "Power") == 0) command.Power = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.Power); - else if (String.Compare(formula.Key, "AbilityStatus") == 0) command.AbilityStatus = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)command.AbilityStatus); - else if (String.Compare(formula.Key, "AbilityElement") == 0) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); - else if (String.Compare(formula.Key, "AbilityElementForBonus") == 0) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); - else if (String.Compare(formula.Key, "IsShortRanged") == 0) command.IsShortRange = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsShortRange); - else if (String.Compare(formula.Key, "AbilityCategory") == 0) command.AbilityCategory = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityCategory); - else if (String.Compare(formula.Key, "AbilityFlags") == 0) command.AbilityType = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityType); - else if (String.Compare(formula.Key, "IsReflectNull") == 0) command.IsReflectNull = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsReflectNull); - else if (String.Compare(formula.Key, "IsMeteorMiss") == 0) command.Data.info.meteor_miss = (Byte)(NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsReflectNull) ? 1 : 0); - else if (String.Compare(formula.Key, "IsShortSummon") == 0) command.IsShortSummon = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsShortSummon); - else if (String.Compare(formula.Key, "TryCover") == 0) tryCover |= NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), false) ? abilityUser.Id : (UInt16)0; - else if (String.Compare(formula.Key, "ScriptId") == 0) command.ScriptId = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.ScriptId); - else if (String.Compare(formula.Key, "HitRate") == 0) command.HitRate = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.HitRate); - else if (String.Compare(formula.Key, "CommandTargetId") == 0) command.Data.tar_id = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.Data.tar_id); - else if (String.Compare(formula.Key, "HP") == 0) abilityUser.CurrentHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CurrentHp); - else if (String.Compare(formula.Key, "MP") == 0) abilityUser.CurrentMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CurrentMp); - else if (String.Compare(formula.Key, "MaxHP") == 0) abilityUser.MaximumHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaximumHp); - else if (String.Compare(formula.Key, "MaxMP") == 0) abilityUser.MaximumMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaximumMp); - else if (String.Compare(formula.Key, "ATB") == 0) abilityUser.CurrentAtb = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CurrentAtb); - else if (String.Compare(formula.Key, "Trance") == 0) abilityUser.Trance = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Trance); - else if (String.Compare(formula.Key, "CurrentStatus") == 0) uCurStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)uCurStat); - else if (String.Compare(formula.Key, "PermanentStatus") == 0) uAutoStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)uAutoStat); - else if (String.Compare(formula.Key, "ResistStatus") == 0) uResistStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)uResistStat); - else if (String.Compare(formula.Key, "HalfElement") == 0) abilityUser.HalfElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.HalfElement); - else if (String.Compare(formula.Key, "GuardElement") == 0) abilityUser.GuardElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.GuardElement); - else if (String.Compare(formula.Key, "AbsorbElement") == 0) abilityUser.AbsorbElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.AbsorbElement); - else if (String.Compare(formula.Key, "WeakElement") == 0) abilityUser.WeakElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.WeakElement); - else if (String.Compare(formula.Key, "BonusElement") == 0) abilityUser.BonusElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.BonusElement); - else if (String.Compare(formula.Key, "Speed") == 0) abilityUser.Dexterity = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Dexterity); - else if (String.Compare(formula.Key, "Strength") == 0) abilityUser.Strength = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Strength); - else if (String.Compare(formula.Key, "Magic") == 0) abilityUser.Magic = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Magic); - else if (String.Compare(formula.Key, "Spirit") == 0) abilityUser.Will = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Will); - else if (String.Compare(formula.Key, "Defence") == 0) abilityUser.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.PhysicalDefence); - else if (String.Compare(formula.Key, "Evade") == 0) abilityUser.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.PhysicalEvade); - else if (String.Compare(formula.Key, "MagicDefence") == 0) abilityUser.MagicDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MagicDefence); - else if (String.Compare(formula.Key, "MagicEvade") == 0) abilityUser.MagicEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MagicEvade); - else if (String.Compare(formula.Key, "Row") == 0) abilityUser.Row = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Row); - else if (String.Compare(formula.Key, "IsStrengthModified") == 0) abilityUser.StatModifier[0] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[0]); - else if (String.Compare(formula.Key, "IsMagicModified") == 0) abilityUser.StatModifier[1] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[1]); - else if (String.Compare(formula.Key, "IsDefenceModified") == 0) abilityUser.StatModifier[2] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[2]); - else if (String.Compare(formula.Key, "IsEvadeModified") == 0) abilityUser.StatModifier[3] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[3]); - else if (String.Compare(formula.Key, "IsMagicDefenceModified") == 0) abilityUser.StatModifier[4] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[4]); - else if (String.Compare(formula.Key, "IsMagicEvadeModified") == 0) abilityUser.StatModifier[5] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[5]); - else if (String.Compare(formula.Key, "CriticalRateBonus") == 0) abilityUser.CriticalRateBonus = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CriticalRateBonus); - else if (String.Compare(formula.Key, "CriticalRateWeakening") == 0) abilityUser.CriticalRateWeakening = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CriticalRateWeakening); - else if (String.Compare(formula.Key, "MaxDamageLimit") == 0) abilityUser.MaxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaxDamageLimit); - else if (String.Compare(formula.Key, "MaxMPDamageLimit") == 0) abilityUser.MaxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaxMpDamageLimit); - else if (String.Compare(formula.Key, "BonusExp") == 0 && !abilityUser.IsPlayer) abilityUser.Enemy.Data.bonus_exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Enemy.Data.bonus_exp); - else if (String.Compare(formula.Key, "BonusGil") == 0 && !abilityUser.IsPlayer) abilityUser.Enemy.Data.bonus_gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Enemy.Data.bonus_gil); - else if (String.Compare(formula.Key, "BonusCard") == 0 && !abilityUser.IsPlayer) abilityUser.Enemy.Data.bonus_card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)abilityUser.Enemy.Data.bonus_card); - else if (String.Compare(formula.Key, "BattleBonusAP") == 0) battle.btl_bonus.ap = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), battle.btl_bonus.ap); - else if (String.Compare(formula.Key, "Counter") == 0) + if (String.Equals(formula.Key, "Power")) command.Power = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.Power); + else if (String.Equals(formula.Key, "AbilityStatus")) command.AbilityStatus = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)command.AbilityStatus); + else if (String.Equals(formula.Key, "AbilityElement")) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); + else if (String.Equals(formula.Key, "AbilityElementForBonus")) command.Element = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)command.Element); + else if (String.Equals(formula.Key, "IsShortRanged")) command.IsShortRange = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsShortRange); + else if (String.Equals(formula.Key, "AbilityCategory")) command.AbilityCategory = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityCategory); + else if (String.Equals(formula.Key, "AbilityFlags")) command.AbilityType = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.AbilityType); + else if (String.Equals(formula.Key, "IsReflectNull")) command.IsReflectNull = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsReflectNull); + else if (String.Equals(formula.Key, "IsMeteorMiss")) command.Data.info.meteor_miss = (Byte)(NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsReflectNull) ? 1 : 0); + else if (String.Equals(formula.Key, "IsShortSummon")) command.IsShortSummon = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), command.IsShortSummon); + else if (String.Equals(formula.Key, "TryCover")) tryCover |= NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), false) ? abilityUser.Id : (UInt16)0; + else if (String.Equals(formula.Key, "ScriptId")) command.ScriptId = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.ScriptId); + else if (String.Equals(formula.Key, "HitRate")) command.HitRate = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.HitRate); + else if (String.Equals(formula.Key, "CommandTargetId")) command.Data.tar_id = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), command.Data.tar_id); + else if (String.Equals(formula.Key, "HP")) abilityUser.CurrentHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CurrentHp); + else if (String.Equals(formula.Key, "MP")) abilityUser.CurrentMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CurrentMp); + else if (String.Equals(formula.Key, "MaxHP")) abilityUser.MaximumHp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaximumHp); + else if (String.Equals(formula.Key, "MaxMP")) abilityUser.MaximumMp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaximumMp); + else if (String.Equals(formula.Key, "ATB")) abilityUser.CurrentAtb = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CurrentAtb); + else if (String.Equals(formula.Key, "Trance")) abilityUser.Trance = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Trance); + else if (String.Equals(formula.Key, "CurrentStatus")) uCurStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)uCurStat); + else if (String.Equals(formula.Key, "PermanentStatus")) uAutoStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)uAutoStat); + else if (String.Equals(formula.Key, "ResistStatus")) uResistStat = (BattleStatus)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (UInt32)uResistStat); + else if (String.Equals(formula.Key, "HalfElement")) abilityUser.HalfElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.HalfElement); + else if (String.Equals(formula.Key, "GuardElement")) abilityUser.GuardElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.GuardElement); + else if (String.Equals(formula.Key, "AbsorbElement")) abilityUser.AbsorbElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.AbsorbElement); + else if (String.Equals(formula.Key, "WeakElement")) abilityUser.WeakElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.WeakElement); + else if (String.Equals(formula.Key, "BonusElement")) abilityUser.BonusElement = (EffectElement)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Byte)abilityUser.BonusElement); + else if (String.Equals(formula.Key, "Speed")) abilityUser.Dexterity = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Dexterity); + else if (String.Equals(formula.Key, "Strength")) abilityUser.Strength = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Strength); + else if (String.Equals(formula.Key, "Magic")) abilityUser.Magic = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Magic); + else if (String.Equals(formula.Key, "Spirit")) abilityUser.Will = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Will); + else if (String.Equals(formula.Key, "Defence")) abilityUser.PhysicalDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.PhysicalDefence); + else if (String.Equals(formula.Key, "Evade")) abilityUser.PhysicalEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.PhysicalEvade); + else if (String.Equals(formula.Key, "MagicDefence")) abilityUser.MagicDefence = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MagicDefence); + else if (String.Equals(formula.Key, "MagicEvade")) abilityUser.MagicEvade = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MagicEvade); + else if (String.Equals(formula.Key, "Row")) abilityUser.Row = (Byte)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Row); + else if (String.Equals(formula.Key, "IsStrengthModified")) abilityUser.StatModifier[0] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[0]); + else if (String.Equals(formula.Key, "IsMagicModified")) abilityUser.StatModifier[1] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[1]); + else if (String.Equals(formula.Key, "IsDefenceModified")) abilityUser.StatModifier[2] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[2]); + else if (String.Equals(formula.Key, "IsEvadeModified")) abilityUser.StatModifier[3] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[3]); + else if (String.Equals(formula.Key, "IsMagicDefenceModified")) abilityUser.StatModifier[4] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[4]); + else if (String.Equals(formula.Key, "IsMagicEvadeModified")) abilityUser.StatModifier[5] = NCalcUtility.EvaluateNCalcCondition(e.Evaluate(), abilityUser.StatModifier[5]); + else if (String.Equals(formula.Key, "CriticalRateBonus")) abilityUser.CriticalRateBonus = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CriticalRateBonus); + else if (String.Equals(formula.Key, "CriticalRateWeakening")) abilityUser.CriticalRateWeakening = (Int16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.CriticalRateWeakening); + else if (String.Equals(formula.Key, "MaxDamageLimit")) abilityUser.MaxDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaxDamageLimit); + else if (String.Equals(formula.Key, "MaxMPDamageLimit")) abilityUser.MaxMpDamageLimit = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.MaxMpDamageLimit); + else if (String.Equals(formula.Key, "BonusExp") && !abilityUser.IsPlayer) abilityUser.Enemy.Data.bonus_exp = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Enemy.Data.bonus_exp); + else if (String.Equals(formula.Key, "BonusGil") && !abilityUser.IsPlayer) abilityUser.Enemy.Data.bonus_gil = (UInt32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), abilityUser.Enemy.Data.bonus_gil); + else if (String.Equals(formula.Key, "BonusCard") && !abilityUser.IsPlayer) abilityUser.Enemy.Data.bonus_card = (TetraMasterCardId)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)abilityUser.Enemy.Data.bonus_card); + else if (String.Equals(formula.Key, "BattleBonusAP")) battle.btl_bonus.ap = (UInt16)NCalcUtility.ConvertNCalcResult(e.Evaluate(), battle.btl_bonus.ap); + else if (String.Equals(formula.Key, "Counter")) { Int32 attackId = (Int32)NCalcUtility.ConvertNCalcResult(e.Evaluate(), (Int32)BattleAbilityId.Attack); if (attackId == (Int32)BattleAbilityId.Void && !EnableAsEnemy && !EnableAsMonsterTransform) @@ -649,19 +742,19 @@ public void ParseFeatures(SupportAbility id, String featureCode) else endPos = codeMatches[i + 1].Groups[1].Captures[0].Index; String saArgs = featureCode.Substring(startPos, endPos - startPos); - if (String.Compare(saCode, "Permanent") == 0) + if (String.Equals(saCode, "Permanent")) { SupportingAbilityEffectPermanent newEffect = new SupportingAbilityEffectPermanent(); foreach (Match formula in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(saArgs)) { - if (String.Compare(formula.Groups[1].Value, "Condition") == 0) + if (String.Equals(formula.Groups[1].Value, "Condition")) newEffect.Condition = formula.Groups[2].Value; else newEffect.Formula[formula.Groups[1].Value] = formula.Groups[2].Value; } PermanentEffect.Add(newEffect); } - else if (String.Compare(saCode, "BattleStart") == 0) + else if (String.Equals(saCode, "BattleStart")) { SupportingAbilityEffectBattleStartType newEffect = new SupportingAbilityEffectBattleStartType(); Match priorityDelta = new Regex(@"\bPreemptivePriority\s+([\+-]?\d+)").Match(saArgs); @@ -669,14 +762,14 @@ public void ParseFeatures(SupportAbility id, String featureCode) Int32.TryParse(priorityDelta.Groups[1].Value, out newEffect.PreemptivePriorityDelta); foreach (Match formula in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(saArgs)) { - if (String.Compare(formula.Groups[1].Value, "Condition") == 0) + if (String.Equals(formula.Groups[1].Value, "Condition")) newEffect.Condition = formula.Groups[2].Value; else newEffect.Formula[formula.Groups[1].Value] = formula.Groups[2].Value; } BattleStartEffect.Add(newEffect); } - else if (String.Compare(saCode, "BattleResult") == 0) + else if (String.Equals(saCode, "BattleResult")) { SupportingAbilityEffectBattleResult newEffect = new SupportingAbilityEffectBattleResult(); Match when = new Regex(@"\bWhen(\w+)\b").Match(saArgs); @@ -684,20 +777,20 @@ public void ParseFeatures(SupportAbility id, String featureCode) newEffect.When = when.Groups[1].Value; foreach (Match formula in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(saArgs)) { - if (String.Compare(formula.Groups[1].Value, "Condition") == 0) + if (String.Equals(formula.Groups[1].Value, "Condition")) newEffect.Condition = formula.Groups[2].Value; else newEffect.Formula[formula.Groups[1].Value] = formula.Groups[2].Value; } BattleResultEffect.Add(newEffect); } - else if (String.Compare(saCode, "StatusInit") == 0) + else if (String.Equals(saCode, "StatusInit")) { SupportingAbilityEffectBattleInitStatus newEffect = new SupportingAbilityEffectBattleInitStatus(); foreach (Match formula in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(saArgs)) { String codeName = formula.Groups[1].Value; - if (String.Compare(codeName, "Condition") == 0) + if (String.Equals(codeName, "Condition")) { newEffect.Condition = formula.Groups[2].Value; } @@ -714,7 +807,7 @@ public void ParseFeatures(SupportAbility id, String featureCode) } foreach (Match statusMatch in new Regex(@"\b((Auto|Initial|Resist)Status|InitialATB)\s+(\w+|\d+)\b").Matches(saArgs)) { - if (String.Compare(statusMatch.Groups[1].Value, "InitialATB") == 0) + if (String.Equals(statusMatch.Groups[1].Value, "InitialATB")) { Int32.TryParse(statusMatch.Groups[3].Value, out newEffect.InitialATB); } @@ -722,18 +815,18 @@ public void ParseFeatures(SupportAbility id, String featureCode) { if (statusMatch.Groups[3].Value.TryEnumParse(out BattleStatus status)) { - if (String.Compare(statusMatch.Groups[2].Value, "Auto") == 0) + if (String.Equals(statusMatch.Groups[2].Value, "Auto")) newEffect.PermanentStatus |= status; - else if (String.Compare(statusMatch.Groups[2].Value, "Initial") == 0) + else if (String.Equals(statusMatch.Groups[2].Value, "Initial")) newEffect.InitialStatus |= status; - else if (String.Compare(statusMatch.Groups[2].Value, "Resist") == 0) + else if (String.Equals(statusMatch.Groups[2].Value, "Resist")) newEffect.ResistStatus |= status; } } } StatusEffect.Add(newEffect); } - else if (String.Compare(saCode, "Ability") == 0) + else if (String.Equals(saCode, "Ability")) { SupportingAbilityEffectAbilityUse newEffect = new SupportingAbilityEffectAbilityUse(); Match when = new Regex(@"\bWhen(\w+)\b").Match(saArgs); @@ -741,7 +834,7 @@ public void ParseFeatures(SupportAbility id, String featureCode) newEffect.When = when.Groups[1].Value; foreach (Match effect in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(saArgs)) { - if (String.Compare(effect.Groups[1].Value, "Condition") == 0) + if (String.Equals(effect.Groups[1].Value, "Condition")) newEffect.Condition = effect.Groups[2].Value; else newEffect.Effect[effect.Groups[1].Value] = effect.Groups[2].Value; @@ -756,12 +849,12 @@ public void ParseFeatures(SupportAbility id, String featureCode) newEffect.DisableSA.Add((SupportAbility)saValue); AbilityEffect.Add(newEffect); } - else if (String.Compare(saCode, "Command") == 0) + else if (String.Equals(saCode, "Command")) { SupportingAbilityEffectCommandStart newEffect = new SupportingAbilityEffectCommandStart(); foreach (Match effect in new Regex(@"\[code=(.*?)\](.*?)\[/code\]").Matches(saArgs)) { - if (String.Compare(effect.Groups[1].Value, "Condition") == 0) + if (String.Equals(effect.Groups[1].Value, "Condition")) newEffect.Condition = effect.Groups[2].Value; else newEffect.Effect[effect.Groups[1].Value] = effect.Groups[2].Value; @@ -769,15 +862,15 @@ public void ParseFeatures(SupportAbility id, String featureCode) if (new Regex(@"\bEvenImmobilized\b").Match(saArgs).Success) newEffect.EvenImmobilized = true; CommandEffect.Add(newEffect); } - else if (String.Compare(saCode, "EnemyFeature") == 0) + else if (String.Equals(saCode, "EnemyFeature")) { EnableAsEnemy = true; } - else if (String.Compare(saCode, "MorphFeature") == 0) + else if (String.Equals(saCode, "MorphFeature")) { EnableAsMonsterTransform = true; } } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Data/Items/MixItems.cs b/Assembly-CSharp/Memoria/Data/Items/MixItems.cs new file mode 100644 index 000000000..15c8ee080 --- /dev/null +++ b/Assembly-CSharp/Memoria/Data/Items/MixItems.cs @@ -0,0 +1,71 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using Memoria.Prime.CSV; + +namespace Memoria.Data +{ + public class MixItems : ICsvEntry + { + public String Comment; + public Int32 Id; + public RegularItem Result; + public List Ingredients = new List(); + + public RegularItem this[Int32 index] => Ingredients[index]; + public Int32 Length => Ingredients.Count; + + public void ParseEntry(String[] raw, CsvMetaData metadata) + { + Comment = CsvParser.String(raw[0]); + Id = CsvParser.Int32(raw[1]); + Result = (RegularItem)CsvParser.Int32(raw[2]); + + Ingredients.Clear(); + for (Int32 i = 3; i < raw.Length; i++) + { + String value = raw[i]; + if (String.IsNullOrEmpty(value)) + continue; + + Int32[] itemArray = CsvParser.ItemArray(value); + Boolean stop = false; + foreach (Int32 itemInt in itemArray) + { + RegularItem itemId = (RegularItem)itemInt; + if (itemId == RegularItem.NoItem) + { + stop = true; + break; + } + Ingredients.Add(itemId); + } + if (stop) + break; + } + } + + public void WriteEntry(CsvWriter writer, CsvMetaData metadata) + { + writer.String(Comment); + writer.Int32(Id); + writer.Item((Int32)Result); + + writer.ItemArray(Ingredients.Select(it => (Int32)it).ToArray()); + } + + public Dictionary GetIngredientsAsDict() + { + Dictionary ingrCount = new Dictionary(); + foreach (RegularItem ingr in Ingredients) + { + if (ingr == RegularItem.NoItem) + continue; + if (!ingrCount.TryGetValue(ingr, out Int32 count)) + count = 0; + ingrCount[ingr] = ++count; + } + return ingrCount; + } + } +} diff --git a/Assembly-CSharp/Memoria/Data/ff9abil.cs b/Assembly-CSharp/Memoria/Data/ff9abil.cs index 85d1dbf82..3899835ea 100644 --- a/Assembly-CSharp/Memoria/Data/ff9abil.cs +++ b/Assembly-CSharp/Memoria/Data/ff9abil.cs @@ -421,13 +421,13 @@ public static void LoadAbilityFeatureFile(ref Dictionary= 0) + else { - if (!cumulate) - BattleAbilityHelper.ClearAbilityFeature((BattleAbilityId)abilIndex); - BattleAbilityHelper.ParseAbilityFeature((BattleAbilityId)abilIndex, input.Substring(startPos, endPos - startPos)); + if (abilIndex > 0) + { + if (!cumulate) + BattleAbilityHelper.ClearAbilityFeature((BattleAbilityId)abilIndex); + BattleAbilityHelper.ParseAbilityFeature((BattleAbilityId)abilIndex, input.Substring(startPos, endPos - startPos)); + } + else if (abilIndex == -1) + { + if (!cumulate) + BattleAbilityHelper.ClearFlexibleAbilityFeature(); + BattleAbilityHelper.ParseAbilityFeature(input.Substring(startPos, endPos - startPos)); + } } } } } -} \ No newline at end of file +} diff --git a/Assembly-CSharp/Memoria/Data/ff9item.2.cs b/Assembly-CSharp/Memoria/Data/ff9item.2.cs index c5f4f1e05..fe17cda3a 100644 --- a/Assembly-CSharp/Memoria/Data/ff9item.2.cs +++ b/Assembly-CSharp/Memoria/Data/ff9item.2.cs @@ -1,14 +1,13 @@ -using System; -using System.IO; -using System.Collections.Generic; -using Assets.SiliconSocial; +using Assets.SiliconSocial; using FF9; -using Memoria; using Memoria.Assets; using Memoria.Data; using Memoria.Prime; -using Memoria.Prime.CSV; using Memoria.Prime.Text; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; // ReSharper disable FieldCanBeMadeReadOnly.Global // ReSharper disable UnusedMember.Global @@ -194,7 +193,7 @@ public static Int32 FF9Item_Remove_Generic(Int32 id, Int32 count) if (IsItemImportant(id)) { if (count > 0 && FF9Item_IsExistImportant(GetImportantIdFromItemId(id))) - { + { FF9Item_RemoveImportant(GetImportantIdFromItemId(id)); return 1; } @@ -272,14 +271,14 @@ public static Int32 FF9Item_Remove(RegularItem id, Int32 count) public static Int32 FF9Item_GetEquipPart(RegularItem id) { FF9ITEM_DATA itemData = _FF9Item_Data[id]; - ItemType[] partMask = new ItemType[] - { - ItemType.Weapon, - ItemType.Helmet, - ItemType.Armlet, - ItemType.Armor, - ItemType.Accessory - }; + ItemType[] partMask = new ItemType[] + { + ItemType.Weapon, + ItemType.Helmet, + ItemType.Armlet, + ItemType.Armor, + ItemType.Accessory + }; for (Int32 i = 0; i < 5; ++i) if ((itemData.type & partMask[i]) != 0) return i; @@ -298,7 +297,7 @@ public static Int32 FF9Item_GetEquipCount(RegularItem id) } public static Int32 FF9Item_GetAnyCount(RegularItem id) - { + { return FF9Item_GetCount(id) + FF9Item_GetEquipCount(id); } @@ -399,7 +398,7 @@ public static Int32 DecreaseMoonStoneCount() } public static Boolean IsItemRegular(Int32 itemId) - { + { return GetItemModuledId(itemId) < 256; } @@ -523,8 +522,60 @@ private static Int32 GetItemModuledId(Int32 itemId) return itemId % 1000; } + public static Object GetItemProperty(RegularItem itemId, String propertyName) + { + if (!_FF9Item_Data.TryGetValue(itemId, out FF9ITEM_DATA item)) + return null; + Boolean hasWeapon = HasItemWeapon(itemId); + Boolean hasArmor = HasItemArmor(itemId); + Boolean hasEffect = HasItemEffect(itemId); + switch (propertyName) + { + case "Price": return item.price; + case "Shape": return (Int32)item.shape; + case "Color": return (Int32)item.color; + case "EquipLevel": return item.eq_lv; + case "SortOrder": return item.sort; + case "Type": return (Int32)item.type; + case "WeaponCategory": return hasWeapon ? (Int32)GetItemWeapon(itemId).Category : null; + case "WeaponStatus": return hasWeapon ? (UInt32)FF9BattleDB.StatusSets[GetItemWeapon(itemId).StatusIndex].Value : null; + case "WeaponModelId": return hasWeapon ? (Int32)GetItemWeapon(itemId).ModelId : null; + case "WeaponScriptId": return hasWeapon ? GetItemWeapon(itemId).Ref.ScriptId : null; + case "WeaponPower": return hasWeapon ? GetItemWeapon(itemId).Ref.Power : null; + case "WeaponElement": return hasWeapon ? (Int32)GetItemWeapon(itemId).Ref.Elements : null; + case "WeaponStatusRate": return hasWeapon ? GetItemWeapon(itemId).Ref.Rate : null; + case "WeaponOffset1": return hasWeapon ? (Int32)GetItemWeapon(itemId).Offset1 : null; + case "WeaponOffset2": return hasWeapon ? (Int32)GetItemWeapon(itemId).Offset2 : null; + case "WeaponHitSfx": return hasWeapon ? (Int32)GetItemWeapon(itemId).HitSfx : null; + case "ArmorDefence": return hasArmor ? GetItemArmor(itemId).PhysicalDefence : null; + case "ArmorEvade": return hasArmor ? GetItemArmor(itemId).PhysicalEvade : null; + case "ArmorMagicDefence": return hasArmor ? GetItemArmor(itemId).MagicalDefence : null; + case "ArmorMagicEvade": return hasArmor ? GetItemArmor(itemId).MagicalEvade : null; + case "EffectTargetType": return hasEffect ? (Int32)GetItemEffect(itemId).info.Target : null; + case "EffectDefaultAlly": return hasEffect ? GetItemEffect(itemId).info.DefaultAlly : null; + case "EffectDisplayStats": return hasEffect ? (Int32)GetItemEffect(itemId).info.DisplayStats : null; + case "EffectVfxIndex": return hasEffect ? (Int32)GetItemEffect(itemId).info.VfxIndex : null; + case "EffectForDead": return hasEffect ? GetItemEffect(itemId).info.ForDead : null; + case "EffectDefaultCamera": return hasEffect ? GetItemEffect(itemId).info.DefaultCamera : null; + case "EffectDefaultOnDead": return hasEffect ? GetItemEffect(itemId).info.DefaultOnDead : null; + case "EffectScriptId": return hasEffect ? GetItemEffect(itemId).Ref.ScriptId : null; + case "EffectPower": return hasEffect ? GetItemEffect(itemId).Ref.Power : null; + case "EffectElement": return hasEffect ? (Int32)GetItemEffect(itemId).Ref.Elements : null; + case "EffectRate": return hasEffect ? GetItemEffect(itemId).Ref.Rate : null; + case "EffectStatus": return hasEffect ? (UInt32)GetItemEffect(itemId).status : null; + } + if (propertyName.StartsWith("Ability ") && Int32.TryParse(propertyName.Substring("Ability ".Length), out Int32 index)) + return index >= 0 && index < item.ability.Length ? item.ability[index] : -1; + if (propertyName.StartsWith("HasActiveAbility ") && Int32.TryParse(propertyName.Substring("HasActiveAbility ".Length), out Int32 abilId)) + return new List(item.ability).Contains(ff9abil.GetAbilityIdFromActiveAbility((BattleAbilityId)abilId)); + if (propertyName.StartsWith("HasSupportAbility ") && Int32.TryParse(propertyName.Substring("HasSupportAbility ".Length), out Int32 supportId)) + return new List(item.ability).Contains(ff9abil.GetAbilityIdFromSupportAbility((SupportAbility)supportId)); + Log.Error($"[ff9item] Unrecognized item property \"{propertyName}\""); + return -1; + } + private static void ApplyItemEquipabilityPatchFile(Dictionary itemDatabase, String[] allLines) - { + { foreach (String line in allLines) { // eg.: Garnet Add 1 2 Remove 56 @@ -547,10 +598,10 @@ private static void ApplyItemEquipabilityPatchFile(Dictionary MixItemsData; + + static ff9mixitem() + { + MixItemsData = LoadSynthesis(); + } + + private static Dictionary LoadSynthesis() + { + try + { + String inputPath = DataResources.Items.PureDirectory + DataResources.Items.MixItemsFile; + Dictionary result = new Dictionary(); + foreach (MixItems[] mixDatabase in AssetManager.EnumerateCsvFromLowToHigh(inputPath)) + foreach (MixItems mix in mixDatabase) + result[mix.Id] = mix; + + return result; + } + catch (Exception ex) + { + Log.Error(ex, "[ff9mixitem] Load mix items failed."); + UIManager.Input.ConfirmQuit(); + return null; + } + } + } +} diff --git a/Assembly-CSharp/Memoria/Scenes/MenuHUD/MenuUIControlPanel.cs b/Assembly-CSharp/Memoria/Scenes/MenuHUD/MenuUIControlPanel.cs index 56531ceec..48000b1c9 100644 --- a/Assembly-CSharp/Memoria/Scenes/MenuHUD/MenuUIControlPanel.cs +++ b/Assembly-CSharp/Memoria/Scenes/MenuHUD/MenuUIControlPanel.cs @@ -14,13 +14,13 @@ namespace Memoria.Scenes public class MenuUIControlPanel : ControlPanel { public const Int32 ITEM_ROW_MIN = 6; - public const Int32 ITEM_ROW_MAX = 12; + public const Int32 ITEM_ROW_MAX = 16; public const Int32 ABILITY_ROW_MIN = 4; - public const Int32 ABILITY_ROW_MAX = 10; + public const Int32 ABILITY_ROW_MAX = 12; public const Int32 EQUIP_ROW_MIN = 4; - public const Int32 EQUIP_ROW_MAX = 8; + public const Int32 EQUIP_ROW_MAX = 10; public const Int32 CHOCOGRAPH_ROW_MIN = 4; - public const Int32 CHOCOGRAPH_ROW_MAX = 8; + public const Int32 CHOCOGRAPH_ROW_MAX = 10; public UIScene Scene; diff --git a/Assembly-CSharp/NCalc/NCalcUtility.cs b/Assembly-CSharp/NCalc/NCalcUtility.cs index 7e2b2c7fe..c992c9d92 100644 --- a/Assembly-CSharp/NCalc/NCalcUtility.cs +++ b/Assembly-CSharp/NCalc/NCalcUtility.cs @@ -1,11 +1,11 @@ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using FF9; +using FF9; using Memoria; using Memoria.Data; using Memoria.Prime.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; // NCalc source code embedded in Assembly-CSharp.dll for avoiding a DLL dependency // Original author of NCalc: sebastienros, https://archive.codeplex.com/?p=ncalc @@ -13,13 +13,14 @@ namespace NCalc { - public static class NCalcUtility + public static class NCalcUtility { public static readonly Type[] UsableEnumTypes = new Type[] { typeof(CharacterId), - typeof(BattleCommandId), typeof(BattleAbilityId), + typeof(BattleCommandId), + typeof(BattleCommandMenu), typeof(WeaponItem), typeof(AccessoryItem), typeof(GemItem), @@ -30,7 +31,8 @@ public static class NCalcUtility typeof(CharacterCategory), typeof(EnemyCategory), typeof(BattleCalcFlags), - typeof(CalcFlag) + typeof(CalcFlag), + typeof(EatResult) }; public static Int64 ConvertNCalcResult(Object obj, Int64 noChangeValue) @@ -89,6 +91,8 @@ public static String EvaluateNCalcString(Object obj, String defaultResult = "") args.Result = GameState.AbilityUsage((BattleAbilityId)NCalcUtility.ConvertNCalcResult(args.Parameters[0].Evaluate(), 0)); else if (name == "GetItemCount" && args.Parameters.Length == 1) args.Result = GameState.ItemCount((RegularItem)NCalcUtility.ConvertNCalcResult(args.Parameters[0].Evaluate(), (Int32)RegularItem.NoItem)); + else if (name == "GetItemProperty" && args.Parameters.Length == 2) + args.Result = ff9item.GetItemProperty((RegularItem)NCalcUtility.ConvertNCalcResult(args.Parameters[0].Evaluate(), (Int32)RegularItem.NoItem), NCalcUtility.EvaluateNCalcString(args.Parameters[1].Evaluate(), "Invalid")); else if (name == "GetPartyMemberLevel" && args.Parameters.Length == 1) args.Result = GameState.PartyLevel((Int32)NCalcUtility.ConvertNCalcResult(args.Parameters[0].Evaluate(), -1)); else if (name == "GetPartyMemberIndex" && args.Parameters.Length == 1) @@ -142,6 +146,17 @@ public static String EvaluateNCalcString(Object obj, String defaultResult = "") BattleUnit killer = killed?.GetKiller(); args.Result = killer != null && killer.Id == killerId; } + else if (name == "BattleUnitFilter" && args.Parameters.Length >= 1) + { + UInt16 filterId = 0; + foreach (BattleUnit btlUnit in FF9StateSystem.Battle.FF9Battle.EnumerateBattleUnits()) + { + NCalcUtility.InitializeExpressionUnit(ref args.Parameters[0], btlUnit, "Candidate"); + if (NCalcUtility.EvaluateNCalcCondition(args.Parameters[0].Evaluate(), false)) + filterId |= btlUnit.Id; + } + args.Result = filterId; + } else if (name == "BattleFilter" && args.Parameters.Length >= 1) { UInt16 btlId = (UInt16)NCalcUtility.ConvertNCalcResult(args.Parameters[0].Evaluate(), 0); @@ -219,6 +234,7 @@ public static String EvaluateNCalcString(Object obj, String defaultResult = "") else if (name == "CurrentPartyAverageLevel") args.Result = GameState.PartyAverageLevel; else if (name == "CurrentTargetablePartyCount") args.Result = Memoria.BattleState.TargetCount(true); else if (name == "CurrentTargetableEnemyCount") args.Result = Memoria.BattleState.TargetCount(false); + else if (name == "BattleGroupIndex") args.Result = (Int32)(FF9StateSystem.Battle?.FF9Battle?.btl_scene?.PatNum ?? -1); else if (name == "IsBattlePreemptive") args.Result = FF9StateSystem.Battle?.FF9Battle?.btl_scene?.Info != null && FF9StateSystem.Battle.FF9Battle.btl_scene.Info.StartType == battle_start_type_tags.BTL_START_FIRST_ATTACK; else if (name == "IsBattleBackAttack") args.Result = FF9StateSystem.Battle?.FF9Battle?.btl_scene?.Info != null && FF9StateSystem.Battle.FF9Battle.btl_scene.Info.StartType == battle_start_type_tags.BTL_START_BACK_ATTACK; else if (name == "ScenarioCounter") args.Result = (Int32)GameState.ScenarioCounter; @@ -317,6 +333,7 @@ public static void InitializeExpressionUnit(ref Expression expr, BattleUnit unit { ENEMY enemy = unit.IsPlayer ? null : unit.Enemy.Data; expr.Parameters[prefix + "Name"] = unit.Name; + expr.Parameters[prefix + "UnitId"] = (Int32)unit.Id; expr.Parameters[prefix + "MaxHP"] = unit.MaximumHp; expr.Parameters[prefix + "MaxMP"] = unit.MaximumMp; expr.Parameters[prefix + "MaxATB"] = (Int32)unit.MaximumAtb; @@ -402,6 +419,7 @@ public static void InitializeExpressionNullableUnit(ref Expression expr, BattleU return; } expr.Parameters[prefix + "Name"] = String.Empty; + expr.Parameters[prefix + "UnitId"] = 0; expr.Parameters[prefix + "MaxHP"] = 0; expr.Parameters[prefix + "MaxMP"] = 0; expr.Parameters[prefix + "MaxATB"] = 0; @@ -503,6 +521,7 @@ public static void InitializeExpressionAbilityContext(ref Expression expr, Battl expr.Parameters["TranceIncrease"] = (Int32)context.TranceIncrease; expr.Parameters["ItemSteal"] = (Int32)context.ItemSteal; expr.Parameters["IsDrain"] = context.IsDrain; + expr.Parameters["EatResult"] = (Int32)context.EatResult; InitializeExpressionCommand(ref expr, calc.Command); } @@ -530,11 +549,30 @@ public static void InitializeExpressionCommand(ref Expression expr, BattleComman expr.Parameters["IsMeteorMiss"] = command.IsMeteorMiss; expr.Parameters["IsCounterableCommand"] = btl_util.IsCommandDeclarable(command.Id); expr.Parameters["AbilityCategory"] = (Int32)command.AbilityCategory; - expr.Parameters["MPCost"] = (Int32)command.Data.aa.MP; + expr.Parameters["CommandMenu"] = (Int32)command.CommandMenu; + expr.Parameters["MPCost"] = (Int32)command.CommandMPCost; expr.Parameters["AbilityFlags"] = (Int32)command.AbilityType; expr.Parameters["CommandTargetId"] = (Int32)command.Data.tar_id; expr.Parameters["CommandTargetCount"] = command.TargetCount; expr.Parameters["CalcMainCounter"] = (Int32)command.Data.info.effect_counter; + expr.Parameters["CommandIsCounter"] = command.Id == BattleCommandId.EnemyCounter || command.Id == BattleCommandId.Counter || command.Id == BattleCommandId.MagicCounter; // Might check also if command.Data == command.Data.regist?.cmd[1] except for JumpAttack/JumpTrance + } + + public static void InitializeExpressionRawAbility(ref Expression expr, AA_DATA aa, BattleAbilityId abilId = BattleAbilityId.Void) + { + // These must be restricted to fields initialized with "InitializeExpressionCommand" + // It can be used when the ability is known but there is no CMD_DATA sent (yet) + expr.Parameters["AbilityId"] = (Int32)abilId; + expr.Parameters["ScriptId"] = aa.Ref.ScriptId; + expr.Parameters["Power"] = aa.Ref.Power; + expr.Parameters["AbilityStatus"] = (UInt32)(FF9BattleDB.StatusSets.TryGetValue(aa.AddStatusNo, out BattleStatusEntry stat) ? stat.Value : 0); + expr.Parameters["AbilityElement"] = (Int32)aa.Ref.Elements; + expr.Parameters["AbilityElementForBonus"] = (Int32)aa.Ref.Elements; + expr.Parameters["SpecialEffectId"] = (Int32)aa.Info.VfxIndex; + expr.Parameters["TargetType"] = (Int32)aa.Info.Target; + expr.Parameters["AbilityCategory"] = (Int32)aa.Category; + expr.Parameters["MPCost"] = (Int32)aa.MP; + expr.Parameters["AbilityFlags"] = (Int32)aa.Type; } } } diff --git a/Assembly-CSharp/UnityXInput/Input.cs b/Assembly-CSharp/UnityXInput/Input.cs index e44562897..c599e2d49 100644 --- a/Assembly-CSharp/UnityXInput/Input.cs +++ b/Assembly-CSharp/UnityXInput/Input.cs @@ -4,6 +4,7 @@ // MVID: 9E13D328-CC20-4729-BE81-A583B120F83A // Compiler-generated code is shown +using Memoria; using System; using UnityEngine; using XInputDotNetPure; @@ -51,7 +52,7 @@ public static Vector2 mousePosition private static Single GetXAxis(String axisName) { - if (!HonoInputManager.ApplicationIsActivated() || !PersistenSingleton.Instance.CurrentState.IsConnected) + if ((!Configuration.Control.AlwaysCaptureGamepad && !HonoInputManager.ApplicationIsActivated()) || !PersistenSingleton.Instance.CurrentState.IsConnected) return 0.0f; if (axisName.Contains("Horizontal")) { @@ -78,7 +79,7 @@ private static Single GetXAxis(String axisName) private static Boolean GetXButton(String keyName) { - if (!HonoInputManager.ApplicationIsActivated()) + if (!Configuration.Control.AlwaysCaptureGamepad && !HonoInputManager.ApplicationIsActivated()) return false; GamePadState currentState = PersistenSingleton.Instance.CurrentState; GamePadState previousState = PersistenSingleton.Instance.PreviousState; @@ -141,7 +142,7 @@ private static Boolean GetXButton(String keyName) private static Boolean GetXButtonUp(String keyName) { - if (!HonoInputManager.ApplicationIsActivated()) + if (!Configuration.Control.AlwaysCaptureGamepad && !HonoInputManager.ApplicationIsActivated()) return false; GamePadState currentState = PersistenSingleton.Instance.CurrentState; GamePadState previousState = PersistenSingleton.Instance.PreviousState; @@ -208,7 +209,7 @@ private static Boolean GetXButtonUp(String keyName) private static Boolean GetXButtonDown(String keyName) { - if (!HonoInputManager.ApplicationIsActivated()) + if (!Configuration.Control.AlwaysCaptureGamepad && !HonoInputManager.ApplicationIsActivated()) return false; GamePadState currentState = PersistenSingleton.Instance.CurrentState; GamePadState previousState = PersistenSingleton.Instance.PreviousState; diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..26b2d24d5 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,8 @@ + + + latest + false + false + false + + \ No newline at end of file diff --git a/Memoria.Client/App.config b/Memoria.Client/App.config index ff38f1851..b9a098221 100644 --- a/Memoria.Client/App.config +++ b/Memoria.Client/App.config @@ -1,28 +1,32 @@ - + - - + + - - + + - - + + - - + + + + + + - + diff --git a/Memoria.Client/Memoria.Client.csproj b/Memoria.Client/Memoria.Client.csproj index b67006892..97b3e80e3 100644 --- a/Memoria.Client/Memoria.Client.csproj +++ b/Memoria.Client/Memoria.Client.csproj @@ -1,5 +1,5 @@  - + Debug @@ -9,7 +9,7 @@ Properties Memoria.Client Memoria.Client - v4.6.1 + v4.7.2 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -31,7 +31,6 @@ - latest AnyCPU @@ -43,7 +42,6 @@ prompt 4 Off - false CS0067 @@ -54,7 +52,6 @@ TRACE prompt 4 - false @@ -73,30 +70,6 @@ ..\References\UnityEngine.dll True - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.DataGrid.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.Toolkit.dll - True - ..\References\XInputDotNetPure.dll False @@ -197,7 +170,6 @@ Resources.Designer.cs - SettingsSingleFileGenerator Settings.Designer.cs @@ -225,7 +197,9 @@ true - + + + + Russian Translation RussianTranslation - RGR Studio + RGR Studio Перевод игры на русский язык. Note: this mod doesn't support automatic installation yet. Download it from its website. @@ -482,6 +622,19 @@ Note: this mod doesn't support automatic installation yet. Download it from its https://ff9.ffrtt.ru/viewtopic.php?f=14&t=38 + + + Ukrainian Translation + UkrainianTranslation + Дракон Сходу (DragonOfTheEast) + Українська локалізація гри. + +Note: this mod doesn't support automatic installation yet. Download it from its website. + Translation + https://steamcommunity.com/sharedfiles/filedetails/?id=3237680302 + https://steamuserimages-a.akamaihd.net/ugc/2512522269181333788/6A0BBB6B3E86DCD437AB8F6AA159E776DF7BCEA6/ + +