Доработать PvP и ранний выход из игры

Реализовать матч PvP до пяти очков и рабочую панель победы. Исправить возврат подготовленной фишки и оплаты при раннем выходе. Ограничить перемещения фишки бота осмысленными кандидатами.
This commit is contained in:
Сергей Бондарь 2026-08-27 11:04:40 +03:00
parent 28fc3c87ae
commit ebc47a80dd
9 changed files with 343 additions and 161 deletions

View File

@ -68,7 +68,10 @@ public class GameManager : MonoBehaviour
public QrPanel qrPanel;
public TakeOrRiskPanel takeOrRiskPanel;
private const int PvpWinningScore = 5;
private bool _isLeavingGameplay;
private int _paidEntryAmount;
private bool _canRefundEntry;
public void Initialize()
{
@ -90,11 +93,18 @@ public class GameManager : MonoBehaviour
public void TryEnterGame(GameMode mode)
{
int entryPrice = PaymentSystem.GetModePrice(mode);
if (!PaymentSystem.TryPayForMode(mode))
return;
_paidEntryAmount = PaymentSystem.Freeplay ? 0 : entryPrice;
_canRefundEntry = true;
SetMode(mode);
_isLeavingGameplay = false;
if (mode == GameMode.pvp)
ResetPvpScores();
if (mode == GameMode.pve)
CharactersController.I.ApplyFirstCharacterColorsToBoard();
@ -132,9 +142,11 @@ public class GameManager : MonoBehaviour
if (_isLeavingGameplay)
return;
RefundEntryIfAvailable();
_isLeavingGameplay = true;
ControlsPerformer.Instance.SetControlable(null);
VideoUtility.CrossFadeToMenu();
turnManager.CancelPlayerPreparation();
_fieldCleaner.Clear();
if (gameMode == GameMode.pve)
@ -157,7 +169,14 @@ public class GameManager : MonoBehaviour
public void SetMode(GameMode mode) => gameMode = mode;
public void DisableEarlyMenuExit() => _backToMenu.Hide();
public void EnableEarlyMenuExit() => _backToMenu.EnableExit();
public void DisableEarlyMenuExit()
{
_paidEntryAmount = 0;
_canRefundEntry = false;
_backToMenu.Hide();
}
public void PerformRevenge()
=> ContinueAfterPveLoss();
@ -193,6 +212,18 @@ public class GameManager : MonoBehaviour
public void ContinueAfterPveDraw()
=> StartPveRound(CharactersController.CharacterIndex);
public void ContinueAfterPvpRound()
{
_fieldCleaner.Clear();
StartRound();
}
public void RestartPvpMatch()
{
ResetPvpScores();
ContinueAfterPvpRound();
}
public void IncreaseScore(Team player)
{
if (player == Team.Player1)
@ -201,6 +232,9 @@ public class GameManager : MonoBehaviour
player2score += 1;
}
public bool HasPvpMatchWinner(Team player)
=> player == Team.Player1 ? player1score >= PvpWinningScore : player2score >= PvpWinningScore;
public void ProcessDifficultyCounter()//вызывается каждый раз, когда приходит COIN с платы или обновились настройки
{
string previous = PlayerPrefs.GetString("PreviousBaseBotDifficulty", "Прохождение");
@ -247,7 +281,7 @@ public class GameManager : MonoBehaviour
timerManager.SetActiveTimer(Team.Player1);
}
else if (gameMode == GameMode.pvp)
DualAvatarController.Instance.ShowCharacters();
DualAvatarController.Instance?.ShowCharacters();
VitrinaView.Instance.ActivateIfNeed();
DetermineNextTurn(switchPlayer: false);
@ -300,6 +334,22 @@ public class GameManager : MonoBehaviour
OnRoundStarted?.Invoke();
}
private void RefundEntryIfAvailable()
{
if (!_canRefundEntry)
return;
PaymentSystem.ReturnCredits(_paidEntryAmount);
_paidEntryAmount = 0;
_canRefundEntry = false;
}
private void ResetPvpScores()
{
player1score = 0;
player2score = 0;
}
public void upgradeFeeshkaDifficulty()
{

View File

@ -9,6 +9,7 @@ public class BackToMenuController : MonoBehaviour
private CanvasGroup _canvasGroup;
private Tween _fadeTween;
private bool _canExit;
private bool _isWaitingForPreparedChip;
private void Awake()
{
@ -29,6 +30,7 @@ public class BackToMenuController : MonoBehaviour
_fadeTween?.Kill();
_fadeTween = null;
_canExit = false;
_isWaitingForPreparedChip = false;
}
public void Show()
@ -36,12 +38,23 @@ public class BackToMenuController : MonoBehaviour
_fadeTween?.Kill();
_fadeTween = null;
_canvasGroup.alpha = 1f;
_canExit = false;
_isWaitingForPreparedChip = true;
}
public void EnableExit()
{
if (!_isWaitingForPreparedChip)
return;
_isWaitingForPreparedChip = false;
_canExit = true;
}
public void Hide()
{
_canExit = false;
_isWaitingForPreparedChip = false;
_fadeTween?.Kill();
_fadeTween = _canvasGroup
.DOFade(0f, _fadeDuration)

View File

@ -12,6 +12,7 @@ public class Bot : BasePlayer, IGamePlayer
[SerializeField] private DifficultyPreset difficultyPreset;
[SerializeField] private bool useDummyBots = false;
[SerializeField] private float minThinkingTime = 1f;
[SerializeField, Min(0f)] private float _candidatePauseDuration = 0.35f;
public DifficultyPreset dummyPreset;
@ -34,9 +35,10 @@ public class Bot : BasePlayer, IGamePlayer
private DifficultyPreset _activeDifficultyPreset;
private bool _useStrongSolver;
// Random movement
private float randomMoveTimer;
private float randomMoveInterval = 0.3f;
private int[] _thinkingCandidates;
private int _thinkingCandidateIndex;
private float _candidatePauseUntil;
private bool _isVisitingCandidates;
private int droppedRow, droppedColumn;
@ -94,31 +96,35 @@ public class Bot : BasePlayer, IGamePlayer
private void UpdateThinking()
{
// Случайные движения (инициируют переход в Moving)
TryRandomMovement();
if (!isThinkingComplete)
return;
// Проверяем, завершены ли вычисления и прошло ли минимальное время
if (isThinkingComplete && Time.time - thinkingStartTime >= _requiredThinkingTime)
if (!_isVisitingCandidates)
{
MoveToCalculatedColumn();
StartCandidateVisit();
return;
}
if (Time.time < _candidatePauseUntil)
return;
if (_thinkingCandidateIndex < _thinkingCandidates.Length - 1)
{
_thinkingCandidateIndex++;
MoveToCandidate(_thinkingCandidates[_thinkingCandidateIndex]);
return;
}
if (Time.time - thinkingStartTime >= _requiredThinkingTime)
PerformDrop();
}
private void UpdateMoving()
{
// Плавное горизонтальное движение к целевой позиции (Y сохраняется)
if (currentChip.MoveToLinear(stickedTargetPosition, moveSpeed))
{
// Если условия для дропа выполнены - бросаем
if (isThinkingComplete && Time.time - thinkingStartTime >= _requiredThinkingTime)
{
PerformDrop();
}
else
{
// Иначе возвращаемся в режим раздумий
SetState(PlayerState.Thinking);
}
SetState(PlayerState.Thinking);
_candidatePauseUntil = Time.time + _candidatePauseDuration;
}
}
@ -137,7 +143,10 @@ public class Bot : BasePlayer, IGamePlayer
isThinkingComplete = false;
calculatedColumn = -1;
thinkingStartTime = Time.time;
randomMoveTimer = 0f;
_thinkingCandidates = null;
_thinkingCandidateIndex = 0;
_candidatePauseUntil = 0f;
_isVisitingCandidates = false;
CacheDifficulty();
StopThinking();
@ -174,21 +183,26 @@ public class Bot : BasePlayer, IGamePlayer
}
}
private void MoveToCalculatedColumn()
private void StartCandidateVisit()
{
if (calculatedColumn == -1) return;
_thinkingCandidates = BuildThinkingCandidates();
_thinkingCandidateIndex = 0;
_isVisitingCandidates = true;
MoveToCandidate(_thinkingCandidates[_thinkingCandidateIndex]);
}
int targetIndex = System.Array.IndexOf(availableColumns, calculatedColumn);
private void MoveToCandidate(int column)
{
int targetIndex = System.Array.IndexOf(availableColumns, column);
if (targetIndex == -1)
{
Debug.LogWarning($"Column {calculatedColumn} is not available!");
Debug.LogWarning($"Column {column} is not available!");
return;
}
if (selectedColumnIndex == targetIndex)
{
PerformDrop();
_candidatePauseUntil = Time.time + _candidatePauseDuration;
return;
}
@ -197,6 +211,82 @@ public class Bot : BasePlayer, IGamePlayer
SetState(PlayerState.Moving);
}
private int[] BuildThinkingCandidates()
{
int alternativeColumn = FindAlternativeCandidate(calculatedColumn);
return alternativeColumn >= 0
? new[] { alternativeColumn, calculatedColumn }
: new[] { calculatedColumn };
}
private int FindAlternativeCandidate(int finalColumn)
{
Team[,] grid = board.GridToTeam();
Team opponent = team == Team.Player1 ? Team.Player2 : Team.Player1;
int bestColumn = -1;
float bestScore = float.NegativeInfinity;
float boardCenter = (board.Columns - 1) * 0.5f;
foreach (int column in availableColumns)
{
if (column == finalColumn)
continue;
int row = board.GetLowestEmptyRow(column);
int attackScore = EvaluatePlacement(grid, row, column, team);
int blockScore = EvaluatePlacement(grid, row, column, opponent);
float centerPenalty = Mathf.Abs(column - boardCenter);
float score = attackScore * 2f + blockScore * 1.5f - centerPenalty;
if (score > bestScore)
{
bestScore = score;
bestColumn = column;
}
}
return bestColumn;
}
private int EvaluatePlacement(Team[,] grid, int row, int column, Team evaluatedTeam)
{
grid[row, column] = evaluatedTeam;
int longestLine = Mathf.Max(
GetLineLength(grid, row, column, evaluatedTeam, 1, 0),
GetLineLength(grid, row, column, evaluatedTeam, 0, 1),
GetLineLength(grid, row, column, evaluatedTeam, 1, 1),
GetLineLength(grid, row, column, evaluatedTeam, 1, -1));
grid[row, column] = Team.None;
return longestLine >= 4 ? 100 + longestLine : longestLine * longestLine;
}
private int GetLineLength(Team[,] grid, int row, int column, Team evaluatedTeam, int rowStep, int columnStep)
{
return 1
+ CountDirection(grid, row, column, evaluatedTeam, rowStep, columnStep)
+ CountDirection(grid, row, column, evaluatedTeam, -rowStep, -columnStep);
}
private int CountDirection(Team[,] grid, int row, int column, Team evaluatedTeam, int rowStep, int columnStep)
{
int count = 0;
int currentRow = row + rowStep;
int currentColumn = column + columnStep;
while (currentRow >= 0 && currentRow < grid.GetLength(0) &&
currentColumn >= 0 && currentColumn < grid.GetLength(1) &&
grid[currentRow, currentColumn] == evaluatedTeam)
{
count++;
currentRow += rowStep;
currentColumn += columnStep;
}
return count;
}
private void PerformDrop()
{
dropTargetPosition = board.GetTargetPosition(SelectedColumn);
@ -208,27 +298,6 @@ public class Bot : BasePlayer, IGamePlayer
SetState(PlayerState.Dropping);
}
private void TryRandomMovement()
{
if (availableColumns == null || availableColumns.Length <= 1) return;
randomMoveTimer += Time.deltaTime;
if (randomMoveTimer >= randomMoveInterval)
{
randomMoveTimer = 0f;
int direction = Random.Range(0, 2) * 2 - 1;
int newIndex = Mathf.Clamp(selectedColumnIndex + direction, 0, availableColumns.Length - 1);
if (newIndex != selectedColumnIndex)
{
selectedColumnIndex = newIndex;
// Сохраняем текущий Y, меняем только X
UpdateTargetPositionX(board.GetStickedPosition(SelectedColumn).x);
SetState(PlayerState.Moving);
}
}
}
private void CacheAvailableColumns()
{
availableColumns = board.GetNonFullColumns();
@ -276,6 +345,7 @@ public class Bot : BasePlayer, IGamePlayer
{
// Начальная позиция – сверху с оффсетом
stickedTargetPosition = board.GetMiddleStickedPosition();
stickedTargetPosition.x = board.GetStickedPosition(SelectedColumn).x;
currentChip.transform.position = stickedTargetPosition + Vector2.up * 5f;
}

View File

@ -30,7 +30,13 @@ public class EndGameHandler : MonoBehaviour
}
else
{
_pvpWinPanel.Open();
GameManager gameManager = GameManager.Instance;
_pvpWinPanel.Open(
Team.None,
false,
gameManager.player1score,
gameManager.player2score,
gameManager.ContinueAfterPvpRound);
}
}
@ -54,7 +60,15 @@ public class EndGameHandler : MonoBehaviour
}
else
{
_pvpWinPanel.Open();
GameManager gameManager = GameManager.Instance;
gameManager.IncreaseScore(winner);
bool isMatchWin = gameManager.HasPvpMatchWinner(winner);
_pvpWinPanel.Open(
winner,
isMatchWin,
gameManager.player1score,
gameManager.player2score,
isMatchWin ? gameManager.RestartPvpMatch : gameManager.ContinueAfterPvpRound);
}
}

View File

@ -1,156 +1,159 @@
using DG.Tweening;
using DG.Tweening;
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class PvpWinPanel : MonoBehaviour, IControlable
{
[SerializeField] private RectTransform panel;
[SerializeField] private float startPanelX, shownPanelX, hiddenPanelX;
[SerializeField] private Transform description;
[SerializeField] private RevengeButton revengeButton;
[SerializeField] private GotoMenuButton menuButton;
[SerializeField] private Image background;
[SerializeField] private Color backgroundEnabledColor, backgroundDisabledColor;
[SerializeField, FormerlySerializedAs("panel")] private RectTransform _panel;
[SerializeField, FormerlySerializedAs("startPanelX")] private float _startPanelX;
[SerializeField, FormerlySerializedAs("shownPanelX")] private float _shownPanelX;
[SerializeField, FormerlySerializedAs("hiddenPanelX")] private float _hiddenPanelX;
[SerializeField, FormerlySerializedAs("description")] private Transform _description;
[SerializeField, FormerlySerializedAs("revengeButton")] private RevengeButton _restartButton;
[SerializeField, FormerlySerializedAs("menuButton")] private GotoMenuButton _menuButton;
[SerializeField, FormerlySerializedAs("background")] private Image _background;
[SerializeField, FormerlySerializedAs("backgroundEnabledColor")] private Color _backgroundEnabledColor;
[SerializeField, FormerlySerializedAs("backgroundDisabledColor")] private Color _backgroundDisabledColor;
[SerializeField, FormerlySerializedAs("elasticCurve")] private AnimationCurve _elasticCurve;
[SerializeField, FormerlySerializedAs("buttons")] private List<PveLossButton> _buttons;
[SerializeField] private AnimationCurve elasticCurve;
private Sequence _animation;
[Header("Работа с кнопками")]
[SerializeField] private List<PveLossButton> buttons;
private int buttonIndex;
private int _buttonIndex;
private Action _restartAction;
public bool ControlsEnabled { get; set; }
private void OnDisable()
{
_animation?.Kill();
_animation = null;
_restartAction = null;
ControlsEnabled = false;
}
public void UpdateControls()
{
int direction = In.GetAxis(JoystickSide.Both, InteractMode.Discrete).x;
int newButtonIndex = Mathf.Clamp(_buttonIndex + direction, 0, _buttons.Count - 1);
int newButtonIndex = Mathf.Clamp(buttonIndex + direction, 0, buttons.Count);
bool indexChanged = newButtonIndex != buttonIndex;
if (indexChanged)
if (newButtonIndex != _buttonIndex)
{
buttonIndex = newButtonIndex;
_buttonIndex = newButtonIndex;
RefreshButtons();
}
//interact
if (In.GetAction(JoystickSide.Both, InteractMode.Discrete))
{
var selectedButton = buttons[buttonIndex];
selectedButton.Interact();
}
Close();
}
public void Open()
public void Open(Team winner, bool isMatchWin, int player1Score, int player2Score, Action restartAction)
{
if (_animation != null)
{
_animation.Kill();
}
_animation?.Kill();
_restartAction = restartAction;
Initialize(winner, isMatchWin, player1Score, player2Score);
Initialize();
_animation = GetOpenSequence();
_animation.onComplete += () =>
_animation.OnComplete(() =>
{
ControlsEnabled = true;
RefreshButtons();
};
});
_animation.PlayForward();
}
public void Close()
{
if (_animation != null)
{
_animation.Kill();
}
ControlsEnabled = false;
ControlsPerformer.Instance.SetControlable(null);
int selectedButtonIndex = _buttonIndex;
_animation?.Kill();
_animation = GetCloseSequence();
_animation.onComplete += () =>
{
ControlsEnabled = false;
revengeButton.Select();
menuButton.Deselect();
};
_animation.OnComplete(() => CompleteClose(selectedButtonIndex));
_animation.PlayForward();
}
private Sequence GetCloseSequence()
private void Initialize(Team winner, bool isMatchWin, int player1Score, int player2Score)
{
Sequence seq = DOTween.Sequence();
ControlsEnabled = false;
gameObject.SetActive(true);
ControlsPerformer.Instance.SetControlable(this);
foreach (var button in buttons)
{
seq.Join(button.transform.DOScale(0, 0.4f).SetEase(Ease.InBack));
}
_panel.anchoredPosition = new Vector2(_startPanelX, _panel.anchoredPosition.y);
_description.localScale = Vector3.zero;
_description.localRotation = Quaternion.identity;
_description.GetComponent<TextMeshProUGUI>().text = GetDescription(winner, isMatchWin, player1Score, player2Score);
seq.Append(panel.DOAnchorPosX(hiddenPanelX, 1f).SetEase(Ease.InBack));
seq.Join(background.DOColor(backgroundDisabledColor, 2).SetEase(Ease.InCubic));
return seq;
}
private void Initialize()
{
panel.anchoredPosition = new Vector2(startPanelX, panel.anchoredPosition.y);
description.localScale = Vector3.zero;
var text = description.GetComponent<TextMeshProUGUI>();
int winner = GameManager.Instance.currentPlayer == Team.Player1 ? 1 : 2;
text.text = $"игрок {winner} победил";
revengeButton.Initialize();
revengeButton.transform.localScale = Vector3.zero;
menuButton.transform.localScale = Vector3.zero;
background.color = backgroundDisabledColor;
buttonIndex = 0;
_restartButton.InitializeForFreeRestart();
_restartButton.transform.localScale = Vector3.zero;
_menuButton.transform.localScale = Vector3.zero;
_background.color = _backgroundDisabledColor;
_buttonIndex = 0;
}
private Sequence GetOpenSequence()
{
Sequence seq = DOTween.Sequence();
Sequence sequence = DOTween.Sequence();
sequence.Append(_panel.DOAnchorPosX(_shownPanelX, 1f).SetEase(Ease.OutBack));
sequence.Join(_background.DOColor(_backgroundEnabledColor, 1f).SetEase(Ease.OutCubic));
sequence.Append(_description.DOScale(1f, 0.5f).SetEase(_elasticCurve));
sequence.AppendInterval(0.2f);
sequence.Append(_description.DOLocalRotate(new Vector3(0f, 0f, 2f), 0.2f));
sequence.Append(_description.DOLocalRotate(new Vector3(0f, 0f, -2f), 0.2f));
sequence.Append(_description.DOLocalRotate(Vector3.zero, 0.1f));
sequence.Join(_restartButton.transform.DOScale(1.05f, 0.5f).SetEase(Ease.OutBack));
sequence.Append(_menuButton.transform.DOScale(0.9f, 0.5f).SetEase(Ease.OutBack));
return sequence;
}
//приезд панели
seq.Append(panel.DOAnchorPosX(shownPanelX, 1f).SetEase(Ease.OutBack));
private Sequence GetCloseSequence()
{
Sequence sequence = DOTween.Sequence();
//фон
seq.Join(background.DOColor(backgroundEnabledColor, 1).SetEase(Ease.OutCubic));
foreach (PveLossButton button in _buttons)
sequence.Join(button.transform.DOScale(0f, 0.4f).SetEase(Ease.InBack));
//текст описания
seq.Append(description.DOScale(1, 0.5f).SetEase(elasticCurve));
seq.AppendInterval(0.2f);
sequence.Append(_panel.DOAnchorPosX(_hiddenPanelX, 1f).SetEase(Ease.InBack));
sequence.Join(_background.DOColor(_backgroundDisabledColor, 2f).SetEase(Ease.InCubic));
return sequence;
}
//вращение описания
float rotationDuration = 0.2f;
seq.Append(description.DOLocalRotate(new Vector3(0, 0, 2), rotationDuration));
seq.Append(description.DOLocalRotate(new Vector3(0, 0, -2), rotationDuration));
seq.Append(description.DOLocalRotate(new Vector3(0, 0, 0), rotationDuration / 2));
private void CompleteClose(int selectedButtonIndex)
{
ControlsEnabled = false;
Action restartAction = _restartAction;
_restartAction = null;
gameObject.SetActive(false);
//появление кнопок
seq.Join(revengeButton.transform.DOScale(1.05f, 0.5f).SetEase(Ease.OutBack));
seq.Append(menuButton.transform.DOScale(0.9f, 0.5f).SetEase(Ease.OutBack));
return seq;
if (selectedButtonIndex == 0)
restartAction?.Invoke();
else
GameManager.Instance.GotoMenu();
}
private void RefreshButtons()
{
if (buttonIndex == 0)
for (int index = 0; index < _buttons.Count; index++)
{
buttons[0].Select();
buttons[1].Deselect();
}
else if (buttonIndex == 1)
{
buttons[1].Select();
buttons[0].Deselect();
if (index == _buttonIndex)
_buttons[index].Select();
else
_buttons[index].Deselect();
}
}
private string GetDescription(Team winner, bool isMatchWin, int player1Score, int player2Score)
{
if (winner == Team.None)
return $"ничья · счёт {player1Score}:{player2Score}";
int playerNumber = winner == Team.Player1 ? 1 : 2;
return isMatchWin
? $"поздравляем! игрок {playerNumber} победил {player1Score}:{player2Score}"
: $"игрок {playerNumber} победил · счёт {player1Score}:{player2Score}";
}
}

View File

@ -33,6 +33,13 @@ public class RevengeButton : PveLossButton
saleImage.gameObject.SetActive(revengeCheaper);
}
public void InitializeForFreeRestart()
{
oldPrice.gameObject.SetActive(false);
actualPrice.gameObject.SetActive(false);
saleImage.gameObject.SetActive(false);
}
public override void Interact()
{
if (!interactable) return;

View File

@ -46,6 +46,17 @@ public class Player : BasePlayer, IGamePlayer
availableColumns = null;
}
public void ReturnPreparedChipToPool()
{
if (currentChip == null || state == PlayerState.Sleep || state == PlayerState.Dropping)
return;
ChipPool.Instance.Release(currentChip);
currentChip = null;
availableColumns = null;
SetState(PlayerState.Sleep);
}
public void UpdateControls()
{
// Always update state machine regardless of ControlsEnabled
@ -176,6 +187,7 @@ public class Player : BasePlayer, IGamePlayer
private void SetInitialChipPosition()
{
stickedTargetPosition = board.GetMiddleStickedPosition();
stickedTargetPosition.x = board.GetStickedPosition(SelectedColumn).x;
currentChip.transform.position = stickedTargetPosition + Vector2.up * chipYOffset;
}

View File

@ -24,6 +24,14 @@ public class TurnManager : MonoBehaviour
StartTurn(_currentPlayer);
}
public void CancelPlayerPreparation()
{
_player1.OnMoveCommitted -= OnPlayerMoveCommitted;
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
_player1.OnChipDropped -= OnTurnCompleted;
_player1.ReturnPreparedChipToPool();
}
private void SetupPlayers()
=> _currentPlayer = _player1;
@ -38,17 +46,14 @@ public class TurnManager : MonoBehaviour
{
_player1.OnMoveCommitted -= OnPlayerMoveCommitted;
_player1.OnMoveCommitted += OnPlayerMoveCommitted;
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
_player1.OnThinkingStarted += OnPlayerThinkingStarted;
}
if (_gameMode == GameMode.pve)
{
GameManager.Instance.turnTracker.EnableTimer(false);
if (isPlayerOneTurn)
{
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
_player1.OnThinkingStarted += OnPlayerThinkingStarted;
}
}
player.OnChipDropped -= OnTurnCompleted;
@ -127,6 +132,9 @@ public class TurnManager : MonoBehaviour
private void OnPlayerThinkingStarted()
{
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
GameManager.Instance.turnTracker.EnableTimer(true);
GameManager.Instance.EnableEarlyMenuExit();
if (_gameMode == GameMode.pve)
GameManager.Instance.turnTracker.EnableTimer(true);
}
}

View File

@ -48,8 +48,7 @@ public static class PaymentSystem
public static bool TryPayForMode(GameMode mode)
{
int price = mode == GameMode.pve ? PricePve : PricePvp;
return TryPay(price);
return TryPay(GetModePrice(mode));
}
public static void AddCredit()
@ -69,9 +68,14 @@ public static class PaymentSystem
public static void AddCreditNoCounters(int amount) => ChangeBalance(amount);
public static void ReturnCredits(GameMode gameMode)
=> ReturnCredits(Freeplay ? 0 : GetModePrice(gameMode));
public static void ReturnCredits(int amount)
{
int gamemodePrice = gameMode == GameMode.pvp ? PricePvp : PricePve;
ChangeBalance(gamemodePrice);
if (amount <= 0)
return;
ChangeBalance(amount);
}
public static void ResetBalance()
@ -82,6 +86,8 @@ public static class PaymentSystem
public static int GetRevengePrice(GameMode gameMode) => gameMode == GameMode.pve ? PriceRevengePve : PriceRevengePvP;
public static int GetModePrice(GameMode gameMode) => gameMode == GameMode.pve ? PricePve : PricePvp;
private static void ApplySettings()
{
Freeplay = SettingsManager.GetBool(SettingKey.FREEPLAY);
@ -135,10 +141,9 @@ public static class PaymentSystem
}
else
{
int price = mode == GameMode.pve ? PricePve : PricePvp;
return GetPluralizedMoney(price);
return GetPluralizedMoney(GetModePrice(mode));
}
}
public static string GetPluralizedMoney(int amount) => $"{amount} {PluralizeUtil.GetValutaPluralized(ValutaName, amount)}";
}
}