备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
public class TrackedRng
{
private readonly System.Random _rng;
private readonly int _seed;
private int _stepCount;
public int Seed => _seed;
public int StepCount => _stepCount;
public TrackedRngState State => new TrackedRngState() { Seed = _seed, StepCount = _stepCount };
public TrackedRng(int seed, int stepCount = 0)
{
_rng = new System.Random(seed);
_seed = seed;
_stepCount = stepCount;
while (stepCount-- > 0)
_rng.Next();
}
public TrackedRng(TrackedRngState state)
{
_rng = new System.Random(state.Seed);
_seed = state.Seed;
_stepCount = state.StepCount;
while (state.StepCount-- > 0)
_rng.Next();
}
public int Next()
{
_stepCount++;
return _rng.Next();
}
public int Next(int maxValue)
{
_stepCount++;
return _rng.Next(maxValue);
}
public int Next(int minValue, int maxValue)
{
_stepCount++;
return _rng.Next(minValue, maxValue);
}
/* private void AdvanceBySteps(int stepCount)
{
while (stepCount-- > 0)
_rng.Next();
} */
}
public class TrackedRngState
{
public int StepCount = 0;
public int Seed;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98d806ad5f3ae3b409d2ffc761f0a93e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using TMPro;
using UnityEngine;
using System;
using UniRx;
public class BingoTimer : MonoBehaviour
{
[SerializeField] private TMP_Text textTimer;
private DateTime _expireTime;
private DateTime _startTime;
private TimeSpan RemainingTime => _expireTime - ZZTimeHelper.UtcNow();
private Action _onExpire;
private bool IsActive
{
get
{
var res = _expireTime > ZZTimeHelper.UtcNow();
if (_startTime != null)
res &= _startTime < ZZTimeHelper.UtcNow();
return res;
}
}
public void Init(ITimerContext ctx)
{
_expireTime = ctx.ExpiryTime;
_startTime = ctx.StartTime;
_onExpire = ctx.OnExpire;
UpdateTimer();
Observable.Interval(TimeSpan.FromSeconds(1)).Subscribe(UpdateTimer).AddTo(this);
}
private void UpdateTimer(long _ = 0L)
{
textTimer.text = ConvertTools.ConvertTime2(RemainingTime);
if (!IsActive)
{
_onExpire?.Invoke();
}
}
private void Reset()
{
textTimer = GetComponent<TMP_Text>();
}
}
public class TimerContext : ITimerContext
{
public DateTime ExpiryTime { get; set; }
public DateTime StartTime { get; set; }
public Action OnExpire { get; set; }
}
public interface ITimerContext
{
public DateTime ExpiryTime { get; }
public DateTime StartTime { get; }
public Action OnExpire { get; }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c3fd4c81bcb87c4ca3b5b9bef70bce5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
using asap.core;
using GameCore;
using System.Threading.Tasks;
using UnityEngine.UI;
using DG.Tweening;
using UnityEngine;
public class EventBingoAct : AGameAct
{
public static IEventAggregator EventAggregator = new EventAggregator();
public readonly static string ActAddressable = "EventBingoAct";
private CanvasScaler _canvasScaler;
private readonly float normalScale = 0.75f, actScale = 1.0f, duration = 0.75f;
private readonly Vector2 targetResolution = new Vector2(1080, 2340);
private Vector2 originalResolution;
public override async Task<bool> StartAsync()
{
GContext.container.Resolve<IDeferredRewardStashService>().Reset();
_canvasScaler = UIManager.Instance.GetComponent<CanvasScaler>();
// DOTween.To(() => _canvasScaler.matchWidthOrHeight, v => _canvasScaler.matchWidthOrHeight = v, actScale, duration).SetEase(Ease.OutQuad);
originalResolution = _canvasScaler.referenceResolution;
DOTween.To(() => _canvasScaler.referenceResolution, v => _canvasScaler.referenceResolution = v, targetResolution, duration).SetEase(Ease.OutQuad);
var panelGo = await UIManager.Instance.ShowUILoad(UITypes.EventBingoPanel);
var panel = panelGo.GetComponent<EventBingoPanel>();
panel.Init();
var bingoModel = GContext.container.Resolve<EventBingoModel>();
if (bingoModel is { IsFirstTime: true })
{
await UIManager.Instance.ShowUINotLoading(UITypes.EventBingoInfoPanel);
bingoModel.SetFirstTimeFlag();
}
return await base.StartAsync();
}
protected override void OnDestroy()
{
// DOTween.To(() => _canvasScaler.matchWidthOrHeight, v => _canvasScaler.matchWidthOrHeight = v, normalScale, duration).SetEase(Ease.OutQuad);
DOTween.To(() => _canvasScaler.referenceResolution, v => _canvasScaler.referenceResolution = v, originalResolution, duration).SetEase(Ease.OutQuad);
UIManager.Instance.DestroyUI(UITypes.EventBingoPanel);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94dcbd2776e372a4aad6e8dceb7a99dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using System.Threading.Tasks;
using UnityEngine;
public class EventBingoBaseballFly : RewardFly
{
public override async Task ShowAsync(CollectionItemFly itemFly)
{
Vector2 direction = itemFly.destPos - itemFly.sourcePos;
direction.Normalize();
transform.rotation = Quaternion.FromToRotation(Vector2.right, direction);
await base.ShowAsync(itemFly);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc430e3374283824ca9abb6606efc01a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,149 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using GameCore;
using asap.core;
using cfg;
using UniRx;
public class EventBingoBlockView : MonoBehaviour
{
[SerializeField] private TMP_Text numberWhite, numberYellow;
[SerializeField] private GameObject bingoGo;
[SerializeField] private Image rewardIcon, imgNumberItem;
[SerializeField] private CardLogoNum rewardIconCard;
[SerializeField] private Animation ani;
public Image RewardIcon => rewardIcon;
private int _number;
private EventBingoNumberItemFlyData _flyData;
private const string StandBy = "baseball_normal",
NearBingo = "baseball_flash",
Hit = "baseball_change",
Bingo = "baseball_completed",
Into = "baseball_in",
Out = "baseball_out";
public void Init(EventBingoBlockViewData viewData, EventBingoNumberItemFlyData flyData)
{
_flyData = flyData;
_number = viewData.number;
numberWhite.text = viewData.number.ToString();
numberYellow.text = viewData.number.ToString();
imgNumberItem.gameObject.SetActive(viewData.haveItem);
rewardIcon.gameObject.SetActive(false);
rewardIconCard.gameObject.SetActive(false);
EventBingoAct.EventAggregator.GetEvent<EventBingoNumberShown>().Subscribe(OnNumberShown).AddTo(this);
if (viewData.reward == null)
return;
var itemTableData = GContext.container.Resolve<Tables>().TbItem.GetOrDefault(viewData.reward.id);
if (itemTableData == null)
{
Debug.LogWarning($"[EventBingo] SetReward: Invalid id({viewData.reward.id}) in Table.");
return;
}
if (viewData.haveItem)
{
return;
}
else if (itemTableData.Type == 5)
{
rewardIconCard.Init(itemTableData);
rewardIconCard.gameObject.SetActive(true);
}
else
{
rewardIcon.gameObject.SetActive(true);
GContext.container.Resolve<IUIService>().SetImageSprite(rewardIcon, itemTableData.Icon);
}
}
public void OnHit(bool doHit)
{
imgNumberItem.gameObject.SetActive(doHit);
numberWhite.gameObject.SetActive(!doHit);
numberYellow.gameObject.SetActive(doHit);
}
private async void OnNumberShown(EventBingoNumberShown e)
{
try
{
if (e.Number != _number)
return;
var itemFlyData = new CollectionItemFly
{
iconName = GContext.container.Resolve<EventBingoModel>().Ctx.GetItemIconByIdx(0),
numStr = "",
targetIconSize = imgNumberItem.rectTransform.rect.width,
sourcePos = _flyData.StartPos,
destPos = imgNumberItem.transform.position,
isPlayOpen = false,
isPlayClose = false,
isDestinationRewardStash = false
};
var flyingItem = Instantiate(_flyData.FlyingNumberItem, transform.parent.parent);
flyingItem.gameObject.SetActive(true);
await flyingItem.ShowAsync(itemFlyData);
Destroy(flyingItem.gameObject);
OnReceiveNumberItem();
}
catch (System.Exception ex)
{
Debug.LogError(ex);
}
}
private void OnReceiveNumberItem()
{
imgNumberItem.gameObject.SetActive(true);
ani.Play(Hit);
}
public void SetNearBingo()
{
ani.Rewind();
ani.Play(NearBingo);
}
public float SetBingo()
{
ani.Play(Bingo);
return ani.GetClip(Bingo).length;
}
public void SetStandBy()
{
ani.Play(StandBy);
}
public float SetInto()
{
// Debug.Log("[EventBingo] Play into.");
ani.Play(Into);
return ani.GetClip(Into).length;
}
public float SetOut()
{
ani.Play(Out);
return ani.GetClip(Out).length;
}
}
public class EventBingoBlockViewData
{
public int number;
public ItemData reward;
public bool haveItem;
}
public class EventBingoNumberShown
{
public int Number;
}
public class EventBingoNumberItemFlyData
{
public Vector2 StartPos;
public RewardFly FlyingNumberItem;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7763d172b3de70c468cab2b3eb12e9b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,582 @@
using System.Collections.Generic;
using System.Linq;
using GameCore;
using System;
using UnityEngine;
using asap.core;
using game;
using cfg;
public class EventBingoModel
{
public readonly static int BoardSize = 5;
public readonly static int NumberCount = BoardSize * BoardSize;
public readonly static string SfxItemIn = "audio_ui_eventbingobaseball_in", SfxItemOut = "audio_ui_eventbingobaseball_out";
public const int RecordLength = 4;
public const char Splitter = '|', Comma = ',';
private int _stepInRound, _ticketCount, _roundCount, _eventId, _chainProgress, _chainTaskTokenProgress;
private EventBingoRoundData _roundData;
private EventBingoProgressTaskData _taskData;
private EventBingoTableContext _ctx;
private bool _isFirstTime;
// This is actually used as a dequeue.
public LinkedList<EventBingoNumberRollerItemData> NumberRollerDataList;
public int[] BoardNumbers => _roundData.BoardNumbers;
public EventBingoStepState StepState => _roundData[_stepInRound];
public int BoardState => StepState.BoardState;
public int TicketCount => _ticketCount;
public int RoundCount => _roundCount;
public EventBingoProgressTaskData TaskData => _taskData;
public int EventId => _eventId;
public int StepInRound => _stepInRound;
public bool IsActivated
{
get
{
if (_ctx == null)
return false;
var timeLimit = _ctx.GetTimeLimit();
return timeLimit.Item1 <= ZZTimeHelper.UtcNow() && ZZTimeHelper.UtcNow() < timeLimit.Item2;
}
}
public bool IsFirstTime => _isFirstTime;
public EventBingoTableContext Ctx => _ctx;
public int PackId => _ctx.GetPackId();
public void Init(FishingEvent e)
{
_eventId = e.ID;
RefreshTableContext();
_roundCount = 0;
var seed = _ctx.PickSeed(_roundCount);
_roundData = new EventBingoRoundData(seed);
_stepInRound = 0;
NumberRollerDataList = new LinkedList<EventBingoNumberRollerItemData>();
_taskData = _ctx.GetTaskData();
_ticketCount = 0;
AddTicket(_ctx.GetWelcomeGift());
SetUiPanel(_ctx.GetUiData());
_isFirstTime = true;
ToPlayfabData().Save();
}
public void Load(EventBingoPlayfabData pfData, EventBingoPlayerPreferenceData ppData, FishingEvent e)
{
_eventId = pfData.EventId;
RefreshTableContext();
_ticketCount = pfData.TicketCount;
_roundCount = pfData.RoundCount;
_stepInRound = pfData.StepInRound;
_roundData = new EventBingoRoundData(pfData.Seed);
if (!_roundData.ValidateStepIndex(_stepInRound))
{
Debug.LogWarning($"[EventBingo] Wrong data detected. Step count out of range. Reset round data.");
_stepInRound = 0;
var seed = _ctx.PickSeed(_roundCount);
_roundData = new EventBingoRoundData(seed);
}
_taskData = _ctx.GetTaskData(pfData.TaskId, pfData.TaskProgress);
if (ppData == null || ppData.RollerDataList == null)
NumberRollerDataList = new LinkedList<EventBingoNumberRollerItemData>();
else
NumberRollerDataList = new LinkedList<EventBingoNumberRollerItemData>(ppData.RollerDataList);
SetUiPanel(_ctx.GetUiData());
_isFirstTime = ppData == null ? true : ppData.IsFirstTime;
}
public void InitTest()
{
Debug.Log("[EventBingo] Abandon.");
}
public void NextStep()
{
_stepInRound++;
var taskUpdate = _taskData.AddProgress(1);
ToPlayfabData().Save();
// Debug.Log($"[EventBingo] Step{_stepInRound}: {StepState.Number}.");
}
public void NextRound()
{
_roundCount++;
var seed = _ctx.PickSeed(_roundCount);
_roundData = new EventBingoRoundData(seed);
_stepInRound = 0;
NumberRollerDataList.Clear();
ToPlayfabData().Save();
ToPlayerPreferenceData().Save();
}
public bool CheckIfTaken(int index)
{
var flag = 1 << index;
return (BoardState & flag) != 0;
}
public List<EventBingoBlockViewData> GetBoardInitiationData()
{
var res = new List<EventBingoBlockViewData>();
for (int i = 0; i < NumberCount; i++)
{
_roundData.MinorRewards.TryGetValue(i, out var minorReward);
res.Add(new EventBingoBlockViewData
{
number = _roundData.BoardNumbers[i],
reward = minorReward,
haveItem = CheckIfTaken(i)
});
}
return res;
}
public void AddNumberRecord(int number)
{
_ctx.GetRandomItemIcon(out int iconIdx, out string iconUrl);
NumberRollerDataList.AddLast(new EventBingoNumberRollerItemData
{
number = number,
iconIdx = iconIdx,
});
while (NumberRollerDataList.Count > RecordLength)
NumberRollerDataList.RemoveFirst();
ToPlayerPreferenceData().Save();
}
public bool AddTicket(int count)
{
_ticketCount += count;
if (_ticketCount < 0)
{
_ticketCount -= count;
return false;
}
EventBingoAct.EventAggregator.Publish(new EventBingoTicketUpdateEvent());
ToPlayfabData().Save();
GContext.container.Resolve<FishingEventData>().SaveTransitionData(_eventId, _ticketCount);
return true;
}
public bool DeliverMinorReward(int index, out ItemData reward)
{
bool haveReward = _roundData.MinorRewards.TryGetValue(index, out reward);
if (haveReward)
{
EventBingoSystem.GrantReward(reward);
}
else
{
// Debug.Log($"[EventBingo] No reward for idx {index}");
}
return haveReward;
}
public void RefreshTableContext()
{
_ctx = new EventBingoTableContext(_eventId);
}
public EventBingoPlayfabData ToPlayfabData()
{
return new EventBingoPlayfabData(
_eventId, _ticketCount, _roundCount, _stepInRound, _roundData.Seed,
TaskData.TaskId, TaskData.Progress, _chainProgress,
_chainTaskTokenProgress);
}
public EventBingoEntranceData ToEntranceData()
{
(var startTime, var expiryTime) = _ctx.GetTimeLimit();
bool needRedPoint = _ticketCount >= _ctx.GetRedPointThreshold();
return new EventBingoEntranceData
{
NeedRedPoint = needRedPoint,
ExpiryTime = expiryTime,
StartTime = startTime,
Icon = _ctx.GetEntranceIcon(),
};
}
public EventBingoPlayerPreferenceData ToPlayerPreferenceData()
{
return new EventBingoPlayerPreferenceData
{
RollerDataList = NumberRollerDataList.ToList(),
IsFirstTime = _isFirstTime
};
}
#region ChainPack
public int GetChainProgress()
{
return _chainProgress;
}
public void SetChainProgress(int p)
{
_chainProgress = p;
}
public int GetTaskProgress()
{
return _chainTaskTokenProgress;
}
public void SetTaskProgress(int p)
{
_chainTaskTokenProgress = p;
}
public void Save()
{
ToPlayfabData().Save();
}
#endregion
private void SetUiPanel(EventBingoUiData panelData)
{
UITypes.EventBingoInfoPanel.SetType(panelData.InfoPanel);
UITypes.EventBingoChainPackPanel.SetType(panelData.ChainPackPanel);
}
public bool IsHit(int number)
{
foreach (var n in BoardNumbers)
{
if (n == number)
return true;
}
return false;
}
public void SetFirstTimeFlag()
{
_isFirstTime = false;
ToPlayerPreferenceData().Save();
}
public void ActivateInstantBingo()
{
_stepInRound = _roundData.StepCount - 2;
}
}
public class EventBingoRoundData
{
private int _seed;
public int[] BoardNumbers;
private List<int> _playerNumberSequence;
private List<int> _stateSequence;
private List<int> _playerIdxSequence;
public Dictionary<int, ItemData> MinorRewards;
public int Seed => _seed;
public int StepCount => _stateSequence.Count;
public EventBingoStepState this[int idx]
{
get
{
if (idx >= _stateSequence.Count || idx >= _playerNumberSequence.Count)
{
var actualIdx = Mathf.Min(_stateSequence.Count - 2, _playerNumberSequence.Count - 2);
return new EventBingoStepState
{
Number = _playerNumberSequence[actualIdx],
BoardState = _stateSequence[actualIdx],
Index = _playerIdxSequence[actualIdx],
};
throw new IndexOutOfRangeException(
$"[EventBingo] Index {idx} out of range. Expected range: [0, {Math.Min(_stateSequence.Count, _playerNumberSequence.Count)}]");
}
return new EventBingoStepState
{
Number = _playerNumberSequence[idx],
BoardState = _stateSequence[idx],
Index = _playerIdxSequence[idx]
};
}
}
public EventBingoRoundData(int seed)
{
_playerNumberSequence = new List<int>();
_playerIdxSequence = new List<int>();
_stateSequence = new List<int>();
UpdateWithSeed(seed);
}
public void UpdateWithSeed(int seed)
{
var model = GContext.container.Resolve<EventBingoModel>();
_seed = seed;
var rng = new System.Random(_seed);
BoardNumbers = EventBingoSystem.GenerateBoardNumbers(rng).ToArray();
_playerNumberSequence.Clear();
_playerIdxSequence.Clear();
_stateSequence.Clear();
_playerNumberSequence.Add(-1);
_playerIdxSequence.Add(-1);
_stateSequence.Add(0b0);
var numberPool = Enumerable.Range(1, 99).ToList();
int state = 0b0;
var pickedIndexSet = new HashSet<int>();
while (numberPool.Count > 0 && EventBingoSystem.CheckBingo(state, out _) <= 0)
{
var pickedNumber = EventBingoSystem.PickRandomNumberFromList(numberPool, rng);
var pickedIdx = Array.IndexOf(BoardNumbers, pickedNumber);
if (pickedIdx > -1)
{
pickedIndexSet.Add(pickedIdx);
state |= 1 << pickedIdx;
}
_playerIdxSequence.Add(pickedIdx);
_playerNumberSequence.Add(pickedNumber);
_stateSequence.Add(state);
}
MinorRewards = new Dictionary<int, ItemData>();
model.Ctx.GetMinorDropData(rng, out var availableRewards, out var displayRewards);
var allIndices = Enumerable.Range(0, EventBingoModel.NumberCount).ToList();
FtMathUtils.ShuffleList(allIndices, rng);
var pickedIndices = pickedIndexSet.ToList();
FtMathUtils.ShuffleList(pickedIndices, rng);
var unpickedIndices = allIndices.Except(pickedIndexSet).ToList();
FtMathUtils.ShuffleList(unpickedIndices, rng);
// Assign rewards to picked positions
for (int i = 0; i < availableRewards.Count && i < pickedIndices.Count; i++)
{
MinorRewards[pickedIndices[i]] = availableRewards[i];
Debug.Log($"[EventBingo] Available MiniDrop: item {availableRewards[i].id} @ idx{pickedIndices[i]}");
}
// Assign display rewards to unpicked positions
for (int i = 0; i < displayRewards.Count && i < unpickedIndices.Count; i++)
{
MinorRewards[unpickedIndices[i]] = displayRewards[i];
Debug.Log($"[EventBingo] Unavailable MiniDrop: item {displayRewards[i].id} @ idx {unpickedIndices[i]}");
}
// var leftOverIndices = Enumerable.Range(0, EventBingoModel.NumberCount)
// .Where(x => !pickedIndexSet.Contains(x))
// .ToHashSet()
// .ToList()
// .OrderBy(x => rng.Next())
// .ToList();
// var pickedIndexList = pickedIndexSet.ToList().OrderBy(x => rng.Next()).ToList();
// for (int i = 0; i < availableRewards.Count && i < pickedIndexList.Count; i++)
// {
// var idx = pickedIndexList.First();
// MinorRewards[idx] = availableRewards[i];
// pickedIndexList.Remove(idx);
// }
// for (int i = 0; i < displayRewards.Count && i < leftOverIndices.Count; i++)
// {
// var idx = leftOverIndices.First();
// MinorRewards[idx] = displayRewards[i];
// leftOverIndices.Remove(idx);
// }
}
public int[] GetNumberRollerDataList(int step)
{
var startIdx = Mathf.Max(1, step - EventBingoModel.RecordLength + 1);
var count = Mathf.Min(EventBingoModel.RecordLength, step);
return _playerNumberSequence.GetRange(startIdx, count).ToArray();
}
public bool ValidateStepIndex(int idx)
{
return idx < _playerNumberSequence.Count && idx < _playerIdxSequence.Count && idx < _stateSequence.Count;
}
}
public class EventBingoStepState
{
public int BoardState;
public int Number;
public int Index;
}
public class EventBingoProgressTaskData
{
public int TaskId;
public int Progress;
public ItemData Reward;
public int TargetProgress;
public int NextTaskId;
/// <summary>
/// Increase progress and check if task is completed.
/// </summary>
/// <param name="count">Usually 1 in this event.</param>
/// <returns>True is the old task is completed.</returns>
public bool AddProgress(int count)
{
Progress += count;
if (Progress >= TargetProgress)
{
EventBingoSystem.GrantReward(Reward);
MoveToNextTask();
return true;
}
return false;
}
private void MoveToNextTask()
{
var nextTask = GContext.container.Resolve<EventBingoModel>().Ctx.GetTaskData(NextTaskId);
TaskId = NextTaskId;
Progress = 0;
Reward = nextTask.Reward;
TargetProgress = nextTask.TargetProgress;
NextTaskId = nextTask.NextTaskId;
}
}
public class EventBingoPlayfabData
{
public int EventId, TicketCount, RoundCount, StepInRound, Seed, TaskId, TaskProgress, ChainProgress, ChainTaskTokenProgress;
private const int TokenCount = 9;
private const string Key = "EventBingo";
private string Serialize()
{
var sb = new System.Text.StringBuilder();
sb.Append(EventId).Append(EventBingoModel.Splitter);
sb.Append(TicketCount).Append(EventBingoModel.Splitter);
sb.Append(RoundCount).Append(EventBingoModel.Splitter);
sb.Append(StepInRound).Append(EventBingoModel.Splitter);
sb.Append(Seed).Append(EventBingoModel.Splitter);
sb.Append(TaskId).Append(EventBingoModel.Splitter);
sb.Append(TaskProgress).Append(EventBingoModel.Splitter);
sb.Append(ChainProgress).Append(EventBingoModel.Splitter);
sb.Append(ChainTaskTokenProgress).Append(EventBingoModel.Splitter);
return sb.ToString();
}
private static EventBingoPlayfabData Deserialize(string s)
{
if (s == null || s == "")
return null;
var tokens = s.Trim(EventBingoModel.Splitter).Split(EventBingoModel.Splitter);
if (tokens.Length != TokenCount)
{
Debug.LogError($"[EventBingo]Wrong amount of parameters. Expect {TokenCount}, but got {tokens.Length} in \"{s}\".");
return null;
}
var eventId = int.Parse(tokens[0]);
var ticketCount = int.Parse(tokens[1]);
var roundCount = int.Parse(tokens[2]);
var stepInRound = int.Parse(tokens[3]);
var seed = int.Parse(tokens[4]);
var taskId = int.Parse(tokens[5]);
var taskProgress = int.Parse(tokens[6]);
var chainProgress = int.Parse(tokens[7]);
var chainTaskTokenProgress = int.Parse(tokens[8]);
return new EventBingoPlayfabData(eventId, ticketCount, roundCount,
stepInRound, seed, taskId, taskProgress, chainProgress, chainTaskTokenProgress);
}
public EventBingoPlayfabData(int eventId, int ticketCount, int roundCount, int stepInRound,
int seed, int taskId, int taskProgress, int chainProgress, int chainTaskTokenProgress)
{
EventId = eventId;
TicketCount = ticketCount;
RoundCount = roundCount;
StepInRound = stepInRound;
Seed = seed;
TaskId = taskId;
TaskProgress = taskProgress;
ChainProgress = chainProgress;
ChainTaskTokenProgress = chainTaskTokenProgress;
}
public void Save()
{
PlayFabMgr.Instance.UpdateUserDataValue(Key, Serialize());
}
public static EventBingoPlayfabData Load()
{
var s = PlayFabMgr.Instance.GetLocalData(Key);
return Deserialize(s);
}
}
public class EventBingoEntranceData
{
public bool NeedRedPoint;
public DateTime ExpiryTime;
public DateTime StartTime;
public string Icon;
}
public class EventBingoPlayerPreferenceData
{
public List<EventBingoNumberRollerItemData> RollerDataList;
public bool IsFirstTime = true;
private readonly static string Key = "EventBingo" + GContext.container.Resolve<IUserService>().UserId;
private string Serialize()
{
var sb = new System.Text.StringBuilder();
sb.Append(IsFirstTime ? "1" : "0").Append(EventBingoModel.Splitter);
foreach (var data in RollerDataList)
sb.Append(data.number).Append(EventBingoModel.Comma).Append(data.iconIdx).Append(EventBingoModel.Splitter);
return sb.ToString();
}
private static EventBingoPlayerPreferenceData Deserialize(string s)
{
var tokens = s.Trim(EventBingoModel.Splitter).Split(EventBingoModel.Splitter);
var rollerData = new List<EventBingoNumberRollerItemData>();
bool isFirstTime;
if (tokens.Length < 1)
{
throw new Exception("[EventBingo] Invalid serialized data, length < 1");
}
isFirstTime = tokens[0] == "1";
for (int i = 1; i < tokens.Length; i++)
{
var token = tokens[i];
var tokenTokens = token.Split(EventBingoModel.Comma);
if (tokenTokens.Length != 2)
throw new Exception("[EventBingo] Wrong amount of parameters in " + token);
rollerData.Add(new EventBingoNumberRollerItemData
{
number = int.Parse(tokenTokens[0]),
iconIdx = int.Parse(tokenTokens[1])
});
}
return new EventBingoPlayerPreferenceData { RollerDataList = rollerData, IsFirstTime = isFirstTime };
}
public void Save()
{
PlayerPrefs.SetString(Key, Serialize());
}
public static EventBingoPlayerPreferenceData Load()
{
var s = PlayerPrefs.GetString(Key);
if (s == null || s == "")
return null;
try
{
var res = Deserialize(s);
return res;
}
catch (Exception e)
{
Debug.LogError(e);
return null;
}
}
}
public class EventBingoTicketUpdateEvent { }
public class EventBingoUiData
{
public string InfoPanel { get; set; }
public string ChainPackPanel { get; set; }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e36873243b281e489e4d7f3bcc83f94
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using EnhancedUI.EnhancedScroller;
using UnityEngine;
public static class EventBingoEnhancedScrollViewExtension
{
public static int GetSnapDataIndexFromScrollPosition(this EnhancedScroller enhancedScroller)
{
var snapPosition = enhancedScroller.ScrollPosition + (enhancedScroller.ScrollRectSize * Mathf.Clamp01(0.5f));
var snapCellViewIndex = enhancedScroller.GetCellViewIndexAtPosition(snapPosition);
var dataIndex = snapCellViewIndex % enhancedScroller.NumberOfCells;
return dataIndex;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9979b385a52ef8947b95b4ba3243b729
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using System;
using UnityEngine.UI;
using UniRx;
using asap.core;
using game;
using GameCore;
public class EventBingoEntranceBtn : EventButtonResource
{
[SerializeField] private TMP_Text textTimer;
[SerializeField] private Button button;
[SerializeField] private Image icon;
private ILoadResourceService _loadResourceService;
private EventBingoEntranceData _data;
private TimeSpan RemainingTime => _data.ExpiryTime - ZZTimeHelper.UtcNow();
private bool IsActive => _data.ExpiryTime > ZZTimeHelper.UtcNow() && ZZTimeHelper.UtcNow() > _data.StartTime;
private const string RedPointKey = "eventbingo.entrance";
private void Awake()
{
var model = GContext.container.Resolve<EventBingoModel>();
if (model == null)
{
gameObject.SetActive(false);
return;
}
_data = model.ToEntranceData();
UpdateTimer();
Observable.Interval(TimeSpan.FromSeconds(1f)).Subscribe(UpdateTimer).AddTo(this);
_loadResourceService = GContext.container.Resolve<ILoadResourceService>();
button.onClick.AddListener(EnterActAsync);
RedPointManager.Instance.SetRedPointState(RedPointKey, _data.NeedRedPoint);
CheckResource(new List<string>() { UITypes.EventBingoPanel.Path, EventBingoAct.ActAddressable, _data.Icon });
}
private void UpdateTimer(long _ = 0L)
{
textTimer.text = ConvertTools.ConvertTime2(RemainingTime);
if (!IsActive)
gameObject.SetActive(false);
}
private async void EnterActAsync()
{
try
{
bool isReady = await _loadResourceService.Loads(
new List<string>() { UITypes.EventBingoPanel.Path, EventBingoAct.ActAddressable });
if (isReady)
{
GContext.Publish(new UnloadActToNextAct { actId = EventBingoAct.ActAddressable, TransitionPanel = UITypes.CloudTransitionPanel });
}
else
{
var panel = await UIManager.Instance.ShowUI(UITypes.CloudTransitionPanel);
panel.GetComponent<CloudTransitionPanel>()
.SetBtn(true, () => GContext.Publish(new UnloadActToNextAct(EventBingoAct.ActAddressable)));
}
}
catch (Exception e)
{
Debug.Log($"<color=#22a6f2>[EventBingo] EnterActError: {e.Message}\n{e.StackTrace}</color>");
throw;
}
}
protected override void OnLoadEventResource()
{
if (IsActive)
{
GContext.container.Resolve<IUIService>().SetImageSprite(icon, _data.Icon);
gameObject.SetActive(true);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af9011f11cfd6434aa503263f8be1cb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EventBingoInfoPanel : MonoBehaviour
{
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 110f25fda9663704a9dc16d729a3ac9f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using asap.core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class EventBingoNumberItemView : MonoBehaviour
{
[SerializeField] TMP_Text text_number;
[SerializeField] Image icon;
[SerializeField] Animation ani;
System.Action<EventBingoNumberItemView> _onPassThreshold;
private const string ItemRollAnimation = "baseball_rotate";
public void Init(EventBingoNumberRollerItemData data, GameObject parent, Vector2 anchoredPos, System.Action<EventBingoNumberItemView> onPassThreshold = null)
{
text_number.text = data.number.ToString();
var url = GContext.container.Resolve<EventBingoModel>().Ctx.GetItemIconByIdx(data.iconIdx);
GContext.container.Resolve<IUIService>().SetImageSprite(icon, url);
gameObject.transform.SetParent(parent.transform);
transform.localScale = Vector3.one;
gameObject.GetComponent<RectTransform>().anchoredPosition = anchoredPos;
gameObject.name = "NumberItem_" + data.number;
gameObject.SetActive(true);
_onPassThreshold = onPassThreshold;
}
public async void Move(float gap, float threshold)
{
try
{
var rect = transform as RectTransform;
var endValue = rect.anchoredPosition.x - gap;
var clip = ani.GetClip(ItemRollAnimation);
ani.Play(ItemRollAnimation);
await rect.DOAnchorPosX(endValue, clip.length).AsyncWaitForCompletion();
if (rect.anchoredPosition.x < threshold)
_onPassThreshold?.Invoke(this);
}
catch (System.Exception e)
{
Debug.LogError("[EventBingo] RollItemError: ");
Debug.LogError(e);
}
}
public float GetItemRollDuration()
{
var clip = ani.GetClip(ItemRollAnimation);
return clip.length;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e46c8cce78c4c2049894ab539bcebc83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.Linq;
using asap.core;
using Game;
using UnityEngine;
public class EventBingoNumberRollerView : MonoBehaviour
{
[SerializeField] private RectTransform[] numberReferenceList;
private float _numberGap, _numberThreshold;
private Vector2 pivot;
private List<EventBingoNumberItemView> _numberList;
private EventBingoNumberItemView _numberPrefab => numberReferenceList[0].GetComponent<EventBingoNumberItemView>();
public Vector2 StartPos => numberReferenceList[0].transform.position;
private void Awake()
{
foreach (var numRef in numberReferenceList)
numRef.gameObject.SetActive(false);
pivot = numberReferenceList[0].anchoredPosition;
_numberGap = Mathf.Abs((numberReferenceList.First().anchoredPosition.x - numberReferenceList.Last().anchoredPosition.x) / (numberReferenceList.Length - 1));
_numberThreshold = numberReferenceList.Last().anchoredPosition.x - _numberGap * 0.1f;
}
public void Init(List<EventBingoNumberRollerItemData> dataList)
{
var pos = pivot;
_numberList = new List<EventBingoNumberItemView>();
for (int i = dataList.Count - 1; i >= 0; i--)
{
var number = Instantiate(_numberPrefab);
number.Init(dataList[i], gameObject, pos, DestroyNumber);
_numberList.Add(number);
pos -= new Vector2(_numberGap, 0);
}
}
public async System.Threading.Tasks.Task RollIn(EventBingoNumberRollerItemData data)
{
var number = Instantiate(_numberPrefab);
var model = GContext.container.Resolve<EventBingoModel>();
GContext.Publish(new EventUISound(model.Ctx.GetNumberSfxUrl(data.number)));
number.Init(data, gameObject, pivot + new Vector2(_numberGap, 0), DestroyNumber);
_numberList.Add(number);
foreach (var item in _numberList)
item.Move(_numberGap, _numberThreshold);
await System.Threading.Tasks.Task.Delay(
System.TimeSpan.FromSeconds(_numberList[0].GetItemRollDuration()));
}
public void SetEmpty()
{
for (int i = 0; i < _numberList.Count; i++)
{
Destroy(_numberList[i].gameObject);
}
_numberList.Clear();
}
private void DestroyNumber(EventBingoNumberItemView number)
{
EventBingoNumberItemView item = null;
for (int i = 0; i < _numberList.Count; i++)
{
if (_numberList[i] == number)
{
item = _numberList[i];
_numberList.RemoveAt(i);
break;
}
}
Destroy(item.gameObject);
}
}
public class EventBingoNumberRollerItemData
{
public int number;
public int iconIdx;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d63cf494cadb334bb7946da8ca2931d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,344 @@
using asap.core;
using UnityEngine;
using UnityEngine.UI;
using game;
using System.Linq;
using TMPro;
using UniRx;
using GameCore;
using System;
using asap.core.common;
using System.Threading.Tasks;
using Game;
public class EventBingoPanel : MonoBehaviour
{
[SerializeField] private EventBingoBlockView[] blockViews;
[SerializeField] private Button btnPlay, btnClose, btnInfo;
[SerializeField] private EventBingoScrollView rewardScrollView;
[SerializeField] private EventBingoNumberRollerView numberRollerView;
[SerializeField] private RewardFly flyingNumberItem;
[SerializeField] private EventBingoTaskView taskView;
[SerializeField] private TMP_Text textTicketCount;
[SerializeField] private BingoTimer timer;
[SerializeField] private RewardFly rewardFlyPrefab;
[SerializeField] private Animator btnAni;
[SerializeField] private GameObject goClickMask;
// [SerializeField] private ChainPackBtn btnPack;
private IObjectPoolService _objectPoolService;
private const float RewardFlyDuration = 1.2f, BaseBallChangeDuration = 1f;
private const string ButtonPlayAnimation = "Pressed", ButtonNormalAnimation = "Normal";
private void Awake()
{
btnClose.onClick.AddListener(OnClickClose);
btnPlay.onClick.AddListener(OnClickPlay);
btnInfo.onClick.AddListener(OnClickInfo);
}
public void Init()
{
var model = GContext.container.Resolve<EventBingoModel>();
var blockViewDataList = model.GetBoardInitiationData();
for (int i = 0; i < blockViews.Length; i++)
blockViews[i].Init(blockViewDataList[i],
new EventBingoNumberItemFlyData
{
StartPos = numberRollerView.StartPos,
FlyingNumberItem = flyingNumberItem
});
numberRollerView.Init(model.NumberRollerDataList.ToList());
taskView.Init(model.TaskData);
UpdateTicketCount();
EventBingoAct.EventAggregator.GetEvent<EventBingoTicketUpdateEvent>()
.Subscribe(_ => UpdateTicketCount())
.AddTo(this);
var timeLimit = model.Ctx.GetTimeLimit();
var timerContext = new TimerContext
{
StartTime = timeLimit.Item1,
ExpiryTime = timeLimit.Item2,
OnExpire = OnClickClose
};
timer.Init(timerContext);
CreateRewardFlyObjectPool();
rewardScrollView.ToggleBingoGlitterFx(false);
}
public async void Start()
{
float duration = 0;
try
{
Debug.Log($"[EventBingo] Start.");
for (int i = 0; i < blockViews.Length; i++)
duration = blockViews[i].SetInto();
await Task.Delay(TimeSpan.FromSeconds(duration / 2));
GContext.Publish(new EventUISound(EventBingoModel.SfxItemIn));
await Task.Delay(TimeSpan.FromSeconds(duration / 2));
PlayNearBingoLoopFx();
}
catch (Exception ex)
{
Debug.LogError("[EventBingo] Panel start error.");
Debug.LogError(ex);
}
}
private void OnClickClose()
{
var _model = GContext.container.Resolve<EventBingoModel>();
_model.ToPlayfabData().Save();
_model.ToPlayerPreferenceData().Save();
ReleaseRewardFlyObjectPool();
GContext.Publish(new UnloadActToNextAct());
}
private async void OnClickPlay()
{
// Debug.Log($"[EventBingo] Play.");
try
{
BlockInput();
PlayButtonAnimation();
var model = GContext.container.Resolve<EventBingoModel>();
var ticketStatus = model.AddTicket(-1);
if (!ticketStatus)
{
Debug.Log($"[EventBingo] Insufficient tickets.");
var res = await OnClickPack();
if (!res)
{
ToastPanel.Show(LocalizationMgr.GetFormatTextValue("UI_ToastPanel_75", LocalizationMgr.GetText(model.Ctx.GetTicketNameKey())));
UnblockInput();
return;
}
UnblockInput();
return;
}
model.NextStep();
var stepState = model.StepState;
model.AddNumberRecord(stepState.Number);
var haveMinorReward = model.DeliverMinorReward(stepState.Index, out var minorReward);
var bingo = EventBingoSystem.CheckBingo(stepState.BoardState, out var pickedIndices);
var hit = model.IsHit(stepState.Number);
int evSuccessMultiple = bingo;
int evItemConsume = model.StepInRound;
int evIsCorrect = hit ? 1 : 0;
string evBoxReward = haveMinorReward ? $"{minorReward.id},{minorReward.count}" : "";
int evMilestoneReward = model.TaskData.TaskId != taskView.TaskId ? model.Ctx.GetTaskRewardDropId(taskView.TaskId) : 0;
// Debug.Log($"<color=red>[EventBingo] -------------------Event Tracking---------------------</color>");
// Debug.Log($"[EventBingo] success_multiple: {evSuccessMultiple}");
// Debug.Log($"[EventBingo] item_consume: {evItemConsume}");
// Debug.Log($"[EventBingo] is_correct: {evIsCorrect}");
// Debug.Log($"[EventBingo] box_reward: {evBoxReward}");
// Debug.Log($"[EventBingo] milestone_reward: {evMilestoneReward}");
// Debug.Log($"[EventBingo] -------------------End of Event Tracking---------------------");
#if AGG
using (var e = GEvent.GameEvent("event_bingo_start"))
{
e.AddContent("success_multiple", evSuccessMultiple)
.AddContent("item_consume", evItemConsume)
.AddContent("is_correct", evIsCorrect)
.AddContent("box_reward", evBoxReward)
.AddContent("milestone_reward", evMilestoneReward);
}
#endif
await numberRollerView.RollIn(model.NumberRollerDataList.Last.Value);
if (!hit)
{
await taskView.UpdateProgress();
// PlayNearBingoLoopFx();
UnblockInput();
return;
}
CancelNearBingoLoopFx();
EventBingoAct.EventAggregator.Publish(new EventBingoNumberShown { Number = stepState.Number });
await Task.Delay(TimeSpan.FromSeconds(RewardFlyDuration));
// all animation in nml
// foreach (var v in blockViews)
// {
// v.SetStandBy();
// }
// Debug.Log($"[EventBingo] Clear animation.");
await Awaiters.NextFrame;
if (haveMinorReward)
{
GContext.Publish(new EventRewardFlyStashRequest(reward: minorReward,
sourceIconRt: blockViews[stepState.Index].GetComponent<RectTransform>(),
doesPlayOpen: true));
await Task.Delay(TimeSpan.FromSeconds(RewardFlyDuration));
}
if (bingo > 0)
{
Debug.Log($"[EventBingo] Bingo * {bingo}!");
var rewards = model.Ctx.GetBingoRewards(bingo, model.RoundCount);
rewards.ForEach(EventBingoSystem.GrantReward);
model.NextRound();
rewardScrollView.ToggleBingoGlitterFx(true);
var bingoDuration = PlayBingoAnimation(pickedIndices);
await Task.Delay(TimeSpan.FromSeconds(bingoDuration));
var rewardPanel = (await UIManager.Instance.ShowUINotLoading(UITypes.EventBingoRewardPanel))
.GetComponent<EventBingoRewardPanel>();
var tcs = new TaskCompletionSource<bool>();
rewardPanel.Init(new EventBingoRewardPanelData { BingoCount = bingo, Rewards = rewards }, EventBingoAct.EventAggregator, tcs);
await tcs.Task;
rewardScrollView.ToggleBingoGlitterFx(false);
await taskView.UpdateProgress();
rewardScrollView.ReloadData(model.RoundCount);
await RefreshPanel();
UnblockInput();
}
else
{
await taskView.UpdateProgress();
PlayNearBingoLoopFx();
UnblockInput();
}
}
catch (Exception e)
{
Debug.LogError("[EventBingo] Bingo play error.");
Debug.LogError(e);
}
}
private async void PlayButtonAnimation()
{
try
{
btnAni.Play(ButtonPlayAnimation);
await Task.Delay(TimeSpan.FromSeconds(0.3f));
btnAni.Play(ButtonNormalAnimation);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
private async Task RefreshPanel()
{
var model = GContext.container.Resolve<EventBingoModel>();
var blockViewDataList = model.GetBoardInitiationData();
float duration = 0;
numberRollerView.SetEmpty();
GContext.Publish(new EventUISound(EventBingoModel.SfxItemOut));
for (int i = 0; i < blockViews.Length; i++)
duration = blockViews[i].SetOut();
await Task.Delay(TimeSpan.FromSeconds(duration));
for (int i = 0; i < blockViews.Length; i++)
{
blockViews[i].Init(blockViewDataList[i],
new EventBingoNumberItemFlyData
{
StartPos = numberRollerView.StartPos,
FlyingNumberItem = flyingNumberItem
});
}
await Awaiters.NextFrame;
for (int i = 0; i < blockViews.Length; i++)
duration = blockViews[i].SetInto();
await Task.Delay(TimeSpan.FromSeconds(duration / 2));
GContext.Publish(new EventUISound(EventBingoModel.SfxItemIn));
await Task.Delay(TimeSpan.FromSeconds(duration / 2));
}
private void PlayNearBingoLoopFx()
{
var model = GContext.container.Resolve<EventBingoModel>();
var nearBingoIndices = EventBingoSystem.CheckNearBingoIndices(model.StepState.BoardState);
for (int i = 0; i < nearBingoIndices.Length; i++)
{
var index = nearBingoIndices[i];
blockViews[index].SetNearBingo();
}
}
private float PlayBingoAnimation(int[] pickedIndices)
{
// Debug.Log("[EventBingo] Play Bingo.");
float res = 0;
foreach (var index in pickedIndices)
{
res = blockViews[index].SetBingo();
}
return res;
}
private void CancelNearBingoLoopFx()
{
Debug.Log("[EventBingo] Play cancel Bingo.");
foreach (var v in blockViews)
{
v.SetStandBy();
}
}
private void UpdateTicketCount()
{
var n = GContext.container.Resolve<EventBingoModel>().TicketCount;
textTicketCount.text = $"{n}";
textTicketCount.color = n > 0 ? Color.white : Color.red;
}
private async Task<bool> OnClickPack()
{
try
{
var chainPackData = GContext.container.Resolve<FishingEventData>().ChainPackWithProgressMigrationData;
if (chainPackData == null || chainPackData.IsChainPackDepleted)
{
Debug.Log("[EventBingo] No chain pack.");
return false;
}
var panel = (await UIManager.Instance.ShowUINotLoading(UITypes.EventBingoChainPackPanel)).GetComponent<ThanksGivingPopupPanel>();
panel.Init(chainPackData);
return true;
}
catch (Exception e)
{
Debug.Log($"[EventBingo]Open Chain Pack Error:");
Debug.LogError(e);
return false;
}
}
private async void OnClickInfo()
{
try
{
await UIManager.Instance.ShowUINotLoading(UITypes.EventBingoInfoPanel);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
private void CreateRewardFlyObjectPool()
{
_objectPoolService = GContext.container.Resolve<IObjectPoolService>();
_objectPoolService.CreatePool(rewardFlyPrefab, 0, 10);
}
private void ReleaseRewardFlyObjectPool()
{
_objectPoolService?.DestroyPool(typeof(RewardFly));
}
private void BlockInput()
{
// Debug.Log("[EventBingo] Block.");
goClickMask.SetActive(true);
}
private void UnblockInput()
{
// Debug.Log("[EventBingo] Unblock.");
goClickMask.SetActive(false);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8bbb5826b3bb7324eb9b143df9e1badf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using UnityEngine;
using cfg;
using asap.core;
using System.Linq;
namespace GameCore
{
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4cdcf6b273084f041a3904a0ecd44494
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using TMPro;
using UnityEngine;
public class EventBingoPosTracker : MonoBehaviour
{
[SerializeField] private TMP_Text text;
// Update is called once per frame
void Update()
{
text.text = transform.position.ToString();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d239870565903024dbae406aa65b8258
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
using GameCore;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using asap.core;
using UnityEngine.Assertions;
using System.Threading.Tasks;
using System;
public class EventBingoRewardPanel : MonoBehaviour
{
[SerializeField] private Button btnClose;
[SerializeField] private GameObject[] goBingoBanners;
[SerializeField] private RewardItemNew[] rewardDisplayList;
private IEventAggregator _eventAggregator1;
private ItemData[] _rewards;
private TaskCompletionSource<bool> _tcs;
private const float RewardFlyDuration = 1.2f;
private void Awake()
{
btnClose.onClick.AddListener(OnClickClose);
}
public void Init(EventBingoRewardPanelData data, IEventAggregator eventAggregator, TaskCompletionSource<bool> tcs)
{
for (int i = 0; i < goBingoBanners.Length; i++)
goBingoBanners[i].SetActive(i == data.BingoCount - 1);
_eventAggregator1 = eventAggregator;
Assert.IsTrue(rewardDisplayList.Length == data.Rewards.Count, $"Inconsistent reward count: {rewardDisplayList.Length} in UI vs {data.Rewards.Count} in data.");
for (int i = 0; i < data.Rewards.Count; i++)
rewardDisplayList[i].SetData(data.Rewards[i]);
_rewards = data.Rewards.ToArray();
_tcs = tcs;
}
private async void OnClickClose()
{
try
{
btnClose.gameObject.SetActive(false);
GContext.Publish(new EventRewardFlyStashRequest(
reward: _rewards[0],
sourceIconRt: rewardDisplayList[0].icon.GetComponent<RectTransform>(),
doesPlayOpen: true));
GContext.Publish(new EventRewardFlyStashRequest(
reward: _rewards[1],
sourceIconRt: rewardDisplayList[1].icon.GetComponent<RectTransform>(),
doesPlayOpen: true));
// _ = rewardDisplayList[0].ParticleAttractor();
// _ = rewardDisplayList[1].ParticleAttractor();
await Task.Delay(TimeSpan.FromSeconds(RewardFlyDuration - 0.2f));
_tcs.SetResult(true);
UIManager.Instance.DestroyUI(UITypes.EventBingoRewardPanel);
}
catch (Exception e)
{
Debug.LogError("[EventBingo] bingo reward panel error.");
Debug.LogError(e);
}
}
}
public class EventBingoRewardPanelData
{
public int BingoCount;
public List<ItemData> Rewards;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd6d7f46160ee7c4db39ab39be352b05
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class EventBingoScrollRect : ScrollRect
{
public override void OnBeginDrag(PointerEventData eventData) { }
public override void OnDrag(PointerEventData eventData) { }
public override void OnEndDrag(PointerEventData eventData) { }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9411c7312428f945a9e620d729cf122
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,129 @@
using UnityEngine;
using EnhancedUI.EnhancedScroller;
using System.Collections;
using asap.core;
public class EventBingoScrollView : MonoBehaviour, IEnhancedScrollerDelegate
{
[SerializeField] private EventBingoScrollViewItem scrollViewItem;
[SerializeField] private EnhancedScroller scroller;
[SerializeField] private EventBingoScrollViewPointerListener pointerListener;
[SerializeField] private GameObject fxBingoGlitter;
[SerializeField] private GameObject[] goPaginationDots;
private const int _bingoCount = 4;
private const float _interval = 5f;
private int _currentIndex, _roundCount;
// private bool _pauseAutoScroll;
private void Awake()
{
scroller.Delegate = this;
_currentIndex = 0;
UpdatePaginationDots();
StartCoroutine(AutoScroll());
pointerListener.Init(PauseAutoScroll, ContinueAutoScroll, UpdatePaginationDots);
}
private async void Start()
{
try
{
await Awaiters.NextFrame;
scroller.JumpToDataIndex(_currentIndex, tweenType: scroller.snapTweenType, tweenTime: scroller.snapTweenTime);
}
catch (System.Exception e)
{
Debug.LogError("[EventBingo] Scroll View Start: " + e.Message);
Debug.LogError(e);
}
}
#region IEnhancedScrollerDelegate
public int GetNumberOfCells(EnhancedScroller scroller)
{
return _bingoCount;
}
public float GetCellViewSize(EnhancedScroller scroller, int dataIndex)
{
return 532f;
}
public EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex)
{
var res = scroller.GetCellView(scrollViewItem) as EventBingoScrollViewItem;
res.Init(dataIndex, GContext.container.Resolve<EventBingoModel>().Ctx.GetBingoRewards(dataIndex + 1, _roundCount));
return res;
}
#endregion
public IEnumerator AutoScroll()
{
// scroller.JumpToDataIndex(_currentIndex);
do
{
yield return new WaitForSeconds(_interval);
IncCurrentIdx();
scroller.JumpToDataIndex(_currentIndex, tweenType: scroller.snapTweenType, tweenTime: scroller.snapTweenTime);
UpdatePaginationDots();
}
while (true);
}
private void IncCurrentIdx()
{
_currentIndex++;
if (_currentIndex >= _bingoCount)
_currentIndex = 0;
}
private void PauseAutoScroll()
{
StopAllCoroutines();
}
private void ContinueAutoScroll()
{
_currentIndex = scroller.GetSnapDataIndexFromScrollPosition();
scroller.JumpToDataIndex(_currentIndex, tweenType: scroller.snapTweenType, tweenTime: scroller.snapTweenTime);
StopAllCoroutines();
StartCoroutine(AutoScroll());
}
public async void ReloadData(int roundCount)
{
try
{
_roundCount = roundCount;
scroller.ReloadData();
await Awaiters.NextFrame;
scroller.JumpToDataIndex(_currentIndex, tweenType: scroller.snapTweenType, tweenTime: scroller.snapTweenTime);
}
catch (System.Exception e)
{
Debug.LogError("[EventBingo] Scroll View Start: " + e.Message);
Debug.LogError(e);
}
}
public void ToggleBingoGlitterFx(bool open)
{
fxBingoGlitter.SetActive(open);
}
private void UpdatePaginationDots()
{
for (int i = 0; i < goPaginationDots.Length; i++)
{
goPaginationDots[i].SetActive(i == _currentIndex);
}
}
#if UNITY_EDITOR
private void OnGUI()
{
GUI.Box(new Rect(20, 20, 200, 20), $"Current Index: {_currentIndex}");
GUI.Box(new Rect(20, 60, 200, 20), $"Current Pos: {scroller.ScrollPosition}");
}
#endif
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10a960900fa887d4e986eab2cad4c3bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using EnhancedUI.EnhancedScroller;
using TMPro;
using UnityEngine;
using GameCore;
using System.Collections.Generic;
public class EventBingoScrollViewItem : EnhancedScrollerCellView
{
[SerializeField] private RewardItemNew[] rewardDisplayList;
[SerializeField] private TMP_Text textBingo;
private readonly string[] _bingoTexts = new string[] {
"<size=76>BINGO</size>",
"<size=100>2x</size>\n<size=64>BINGO</size>",
"<size=100>3x</size>\n<size=64>BINGO</size>",
"<size=100>4x</size>\n<size=64>BINGO</size>" };
public void Init(int index, List<ItemData> rewards)
{
textBingo.text = _bingoTexts[index];
for (int i = 0; i < rewardDisplayList.Length && i < rewards.Count; i++)
rewardDisplayList[i].SetData(rewards[i]);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 231e9f9ec8acceb4e8b46b8e835d9e8c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System;
using UnityEngine;
using UnityEngine.EventSystems;
public class EventBingoScrollViewPointerListener : MonoBehaviour, IBeginDragHandler, IEndDragHandler/* , IPointerUpHandler */
{
public Action PauseAutoScroll, ContinueAutoScroll, UpdatePaginationDots;
public void Init(Action pauseAutoScroll, Action continueAutoScroll, Action updatePaginationDots)
{
PauseAutoScroll = pauseAutoScroll;
ContinueAutoScroll = continueAutoScroll;
UpdatePaginationDots = updatePaginationDots;
}
public void OnBeginDrag(PointerEventData e)
{
// Debug.Log("[EventBingo] ScrollView: begin drag.");
PauseAutoScroll?.Invoke();
UpdatePaginationDots?.Invoke();
}
public void OnEndDrag(PointerEventData e)
{
// Debug.Log("[EventBingo] ScrollView: end drag.");
ContinueAutoScroll?.Invoke();
UpdatePaginationDots?.Invoke();
}
// public void OnPointerUp(PointerEventData eventData)
// {
// // Debug.Log("[EventBingo] ScrollView: pointer up.");
// ContinueAutoScroll?.Invoke();
// }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 03a8f3d5a823bcd4cb8f8db93a6bd935
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,104 @@
using System.Collections.Generic;
using System.Linq;
using UniRx;
using UnityEngine.Assertions;
using GameCore;
using asap.core;
public class EventBingoSystem
{
private static readonly int[] BingoStates =
{
0b0000000000000000000011111,
0b0000000000000001111100000,
0b0000000000111110000000000,
0b0000011111000000000000000,
0b1111100000000000000000000,
0b1000010000100001000010000,
0b0100001000010000100001000,
0b0010000100001000010000100,
0b0001000010000100001000010,
0b0000100001000010000100001,
0b1000001000001000001000001,
0b0000100010001000100010000,
0b1000100000000000000010001
};
private static readonly int[] NearBingoStates =
{
0b0000000000000000000011110, 0b0000000000000000000011101, 0b0000000000000000000011011, 0b0000000000000000000010111, 0b0000000000000000000001111,
0b0000000000000001111000000, 0b0000000000000001110100000, 0b0000000000000001101100000, 0b0000000000000001011100000, 0b0000000000000000111100000,
0b0000000000111100000000000, 0b0000000000111010000000000, 0b0000000000110110000000000, 0b0000000000101110000000000, 0b0000000000011110000000000,
0b0000011110000000000000000, 0b0000011101000000000000000, 0b0000011011000000000000000, 0b0000010111000000000000000, 0b0000001111000000000000000,
0b1111000000000000000000000, 0b1110100000000000000000000, 0b1101100000000000000000000, 0b1011100000000000000000000, 0b0111100000000000000000000,
0b1000010000100001000000000, 0b1000010000100000000010000, 0b1000010000000001000010000, 0b1000000000100001000010000, 0b0000010000100001000010000,
0b0100001000010000100000000, 0b0100001000010000000001000, 0b0100001000000000100001000, 0b0100000000010000100001000, 0b0000001000010000100001000,
0b0010000100001000010000000, 0b0010000100001000000000100, 0b0010000100000000010000100, 0b0010000000001000010000100, 0b0000000100001000010000100,
0b0001000010000100001000000, 0b0001000010000100000000010, 0b0001000010000000001000010, 0b0001000000000100001000010, 0b0000000010000100001000010,
0b0000100001000010000100000, 0b0000100001000010000000001, 0b0000100001000000000100001, 0b0000100000000010000100001, 0b0000000001000010000100001,
0b1000001000001000001000000, 0b1000001000001000000000001, 0b1000001000000000001000001, 0b1000000000001000001000001, 0b0000001000001000001000001,
0b0000100010001000100000000, 0b0000100010001000000010000, 0b0000100010000000100010000, 0b0000100000001000100010000, 0b0000000010001000100010000,
0b1000100000000000000010000, 0b1000100000000000000000001, 0b1000000000000000000010001, 0b0000100000000000000010001,
};
public static List<int> GenerateBoardNumbers(System.Random rng)
{
var res = new List<int>();
var numPool = Enumerable.Range(1, 99).ToList();
for (int i = 0; i < EventBingoModel.NumberCount; i++)
{
var index = rng.Next(numPool.Count);
res.Add(numPool[index]);
numPool.RemoveAt(index);
}
return res;
}
public static int PickRandomNumberFromList(List<int> nums, System.Random rng)
{
Assert.IsTrue(nums is { Count: >= 1 }, "[EventBingo] Number list is empty.");
var idx = rng.Next(nums.Count);
var n = nums[idx];
nums.RemoveAt(idx);
return n;
}
public static int CheckBingo(int state, out int[] indices)
{
int res = 0;
var pickedIndices = new HashSet<int>();
for (int i = 0; i < BingoStates.Length; i++)
{
if ((state & BingoStates[i]) != BingoStates[i])
continue;
var bingoIndices = FtMathUtils.BitWisePositionScan(BingoStates[i]);
foreach(var idx in bingoIndices)
pickedIndices.Add(idx);
res++;
}
indices = pickedIndices.ToArray();
return res;
}
public static int[] CheckNearBingoIndices(int state)
{
var res = new HashSet<int>();
for (int i = 0; i < NearBingoStates.Length; i++)
{
if ((state & NearBingoStates[i]) != NearBingoStates[i])
continue;
var stateIndices = FtMathUtils.BitWisePositionScan(NearBingoStates[i]);
foreach (var idx in stateIndices)
res.Add(idx);
}
return res.ToArray();
}
public static void GrantReward(ItemData reward)
{
// Debug.Log($"[EventBingo] Grant Reward {reward.id} * {reward.count}.");
// if (reward.id == )
var e = new DeferredRewardStashService.EventStashItem { Item = reward };
GContext.Publish(e);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9790dd1586cc6d5438bea29c2bc6e7f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,249 @@
using System.Collections.Generic;
using cfg;
using asap.core;
using GameCore;
using System.Linq;
using UnityEngine;
using System;
using UnityEngine.Assertions;
public class EventBingoTableContext
{
private readonly EventBingoInit _tableInit;
private readonly TbEventBingoMiniDrop _tableMiniDrop;
private readonly PlayerItemData _playerItemData;
private readonly TbEventBingoMain _tableMain;
private readonly TbEventBingoCollectingTarget _tableTask;
private readonly TbEventBingoConfig _tableConfig;
private readonly FishingEvent _tableEvent;
private readonly FishingEventCycleItem _tableCycleItem;
public EventBingoTableContext(int eventId)
{
_playerItemData = GContext.container.Resolve<PlayerItemData>();
_tableEvent = GContext.container.Resolve<Tables>().TbFishingEvent[eventId];
var redirectId = _tableEvent.RedirectID;
_tableCycleItem = GContext.container.Resolve<Tables>().TbFishingEventCycleItem[redirectId];
var cycleId = _tableCycleItem.RedirectID;
_tableInit = GContext.container.Resolve<Tables>().TbEventBingoInit[cycleId];
_tableMiniDrop = GContext.container.Resolve<Tables>().TbEventBingoMiniDrop;
_tableMain = GContext.container.Resolve<Tables>().TbEventBingoMain;
_tableTask = GContext.container.Resolve<Tables>().TbEventBingoCollectingTarget;
_tableConfig = GContext.container.Resolve<Tables>().TbEventBingoConfig;
}
public void GetMinorDropData(System.Random rng, out List<ItemData> reachableRewards, out List<ItemData> unreachableRewards)
{
reachableRewards = new List<ItemData>();
unreachableRewards = new List<ItemData>();
var dropStrat = FtMathUtils.PickRandomItemWithWeight(_tableMiniDrop.DataList, rng, x => _tableMiniDrop.DataList[x].Weight);
Assert.IsTrue(dropStrat.DropCount == dropStrat.MiniDropCount1 + dropStrat.MiniDropCount2 && dropStrat.DropCount <= dropStrat.Count,
$"[EventBingo] dropStrat {dropStrat.Id} invalid.");
Debug.Log($"[EventBingo] MiniDropId: {dropStrat.Id}.");
int i = 0;
while (i < dropStrat.MiniDropCount1)
{
reachableRewards.Add(new ItemData(dropStrat.MiniItem1, 1));
i++;
}
while (i < dropStrat.DropCount)
{
reachableRewards.Add(new ItemData(dropStrat.MiniItem2, 1));
i++;
}
while (i < dropStrat.Count)
{
var reward = _playerItemData.GetRandomItemDataByDropId(rng, dropStrat.DropID);
if (reward != null)
unreachableRewards.Add(reward);
else
Debug.LogWarning($"[EventBingo] MiniDrop reward not found for drop Id {dropStrat.DropID}.");
i++;
}
}
public int PickSeed(int roundCount, int? lordOfSeeds = null, int notThisSeed = -1)
{
System.Random rng;
if (lordOfSeeds != null)
rng = new System.Random(lordOfSeeds.Value);
else
rng = new System.Random();
var initSeedPools = GContext.container.Resolve<Tables>().TbEventBingoConfig.DataMap;
roundCount += 1;
if (initSeedPools.Keys.Contains(roundCount))
{
var pool = initSeedPools[roundCount].SeedID;
var seed = pool[rng.Next(pool.Count)];
Debug.Log($"[EventBingo] Pick init seed{seed} in round {roundCount}");
return seed;
}
var seedSetup = FtMathUtils.PickRandomItemWithWeight(_tableMain.DataList, rng, idx => _tableMain.DataList[idx].Weight);
var seedList = seedSetup.SeedID.OrderBy(x => rng.Next()).ToList();
var res = seedList.FirstOrDefault(x => x != notThisSeed);
Debug.Log($"[EventBingo] Selected seed: {res}.");
return res;
}
public (int seed, int bingo) PickSeedValidation(int roundCount, int? lordOfSeeds = null)
{
System.Random rng;
if (lordOfSeeds != null)
rng = new System.Random(lordOfSeeds.Value);
else
rng = new System.Random();
var initSeedPools = GContext.container.Resolve<Tables>().TbEventBingoConfig.DataMap;
roundCount += 1;
if (initSeedPools.Keys.Contains(roundCount))
{
var pool = initSeedPools[roundCount].SeedID;
var seed = pool[rng.Next(pool.Count)];
Debug.Log($"[EventBingo] Pick init seed{seed} in round {roundCount}");
return (seed, 0);
}
var seedSetup = FtMathUtils.PickRandomItemWithWeight(_tableMain.DataList, rng, idx => _tableMain.DataList[idx].Weight);
var seedList = seedSetup.SeedID.OrderBy(x => rng.Next()).ToList();
var res = seedList.FirstOrDefault();
Debug.Log($"[EventBingo] Selected seed: {res}.");
return (res, seedSetup.BingoType);
}
public void GetRandomItemIcon(out int iconIdx, out string iconUrl)
{
var urlList = _tableInit.ItemResource;
iconIdx = UnityEngine.Random.Range(0, urlList.Count);
iconUrl = urlList[iconIdx];
}
public string GetItemIconByIdx(int iconId)
{
var urlList = _tableInit.ItemResource;
if (iconId < 0 || iconId >= urlList.Count)
return urlList[0];
return urlList[iconId];
}
public EventBingoProgressTaskData GetTaskData()
{
return GetTaskData(_tableInit.TargetID);
}
public EventBingoProgressTaskData GetTaskData(int taskId, int progress = 0)
{
var task = _tableTask.GetOrDefault(taskId);
if (task == null)
{
Debug.LogError($"[EventBingo] Task not found: {taskId}.");
return null;
}
return new EventBingoProgressTaskData
{
TaskId = taskId,
Progress = progress,
Reward = _playerItemData.GetItemDataByDropId(task.DropID)[0],
TargetProgress = task.TokenRequired,
NextTaskId = task.NextTask
};
}
public int GetTaskRewardDropId(int taskId)
{
return _tableTask.Get(taskId).DropID;
}
public List<ItemData> GetBingoRewards(int bingo, int roundCount)
{
var bingoId = _tableInit.BingoTypeID[bingo - 1];
var bingoConfig = _tableMain.GetOrDefault(bingoId);
// var initRoundCount = _tableConfig.DataList.Count;
var roundConfigCount = bingoConfig.DropID.Count;
// var bingoRewardConfigIdx = (roundCount - initRoundCount) % roundConfigCount;
var bingoRewardConfigIdx = roundCount % roundConfigCount;
bingoRewardConfigIdx = Mathf.Max(0, bingoRewardConfigIdx);
var dropId = bingoConfig.DropID[bingoRewardConfigIdx];
return _playerItemData.GetItemDataByDropId(dropId);
}
public Tuple<DateTime, DateTime> GetTimeLimit()
{
try
{
var et = DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime);
var st = DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).StartTime);
return new Tuple<DateTime, DateTime>(st, et);
}
catch (Exception e)
{
Debug.Log($"[EventBingo] Time Parse Error:");
Debug.LogError(e);
return new Tuple<DateTime, DateTime>(DateTime.MinValue, DateTime.MinValue);
}
}
public string GetEntranceIcon()
{
return _tableInit.Icon;
}
public int GetRedPointThreshold()
{
return _tableCycleItem.RedDot;
}
public int GetWelcomeGift()
{
return _tableCycleItem.WelcomeGift;
}
public EventBingoUiData GetUiData()
{
return new EventBingoUiData()
{
ChainPackPanel = _tableInit.ChainPackPanel,
InfoPanel = _tableInit.InfoPanel
};
}
public int GetPackId()
{
return _tableInit.PackId;
}
public ItemData GetProgressTaskFinalReward()
{
var firstTask = _tableInit.TargetID;
EventBingoCollectingTarget lastTask = null;
foreach (var task in _tableTask.DataList)
{
if (task.NextTask == firstTask)
{
lastTask = task;
break;
}
}
if (lastTask == null)
{
Debug.LogWarning("[EventBingo] No final reward found.");
return null;
}
return _playerItemData.GetItemDataByDropId(lastTask.DropID)[0];
}
public string GetNumberSfxUrl(int number)
{
var res = GContext.container.Resolve<Tables>().TbEventBingoVoice.DataMap.TryGetValue(number, out var s);
if (res)
return s.Count;
else
{
Debug.LogWarning($"[EventBingo] Number {number} is not included in voice resource table");
return "";
}
}
public string GetTicketNameKey()
{
var ticketId = _tableCycleItem.ItemId;
return GContext.container.Resolve<Tables>().TbItem.Get(ticketId).Name_l10n_key;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dacd7eb32706c4b4bb23b7a226df7bf1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using asap.core;
using DG.Tweening;
using GameCore;
public class EventBingoTaskView : MonoBehaviour
{
[SerializeField] private Image progressBar;
[SerializeField] private RewardItemNew reward, finalReward;
[SerializeField] private TMP_Text textProgress;
private int _taskId;
private float _progressGrowthDuration = 0.3f;
private ItemData _reward;
private const float RewardFlyDuration = 1.2f;
public int TaskId => _taskId;
public void Init(EventBingoProgressTaskData taskData)
{
progressBar.fillAmount = taskData.Progress / (float)taskData.TargetProgress;
reward.SetData(taskData.Reward);
textProgress.text = taskData.Progress + "/" + taskData.TargetProgress;
_taskId = taskData.TaskId;
_reward = taskData.Reward;
var bingoModel = GContext.container.Resolve<EventBingoModel>();
var fr = bingoModel.Ctx.GetProgressTaskFinalReward();
finalReward.SetData(fr);
}
public async System.Threading.Tasks.Task UpdateProgress()
{
var newData = GContext.container.Resolve<EventBingoModel>().TaskData;
if (newData.TaskId == _taskId)
{
var newProgress = newData.Progress / (float)newData.TargetProgress;
progressBar.DOFillAmount(newProgress, _progressGrowthDuration);
textProgress.text = newData.Progress + "/" + newData.TargetProgress;
}
else
{
var s = textProgress.text;
var tokens = s.Split('/');
textProgress.text = tokens[1] + "/" + tokens[1];
await progressBar.DOFillAmount(1, _progressGrowthDuration).AsyncWaitForCompletion();
GContext.Publish(new EventRewardFlyStashRequest(_reward, reward.icon.GetComponent<RectTransform>()));
await System.Threading.Tasks.Task.Delay(System.TimeSpan.FromSeconds(RewardFlyDuration));
Init(newData);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57e1896db652f8041805f6029aab5bd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,217 @@
// Modified from ThanksGivingPackPanel. All Rights Reserved...?
using System;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using asap.core;
using DG.Tweening;
using game;
using GameCore;
using UniRx;
public class ProgressChainPackPanel : MonoBehaviour
{
[SerializeField] private TMP_Text textTimer, textProgress, textComplete;
[SerializeField] private Image barProgress;
[SerializeField] private RewardItemNew tokenIcon, rewardProgress;
[SerializeField] private ThanksGivingChainSlot[] slots;
[SerializeField] private ThanksGivingChainSlot slot6;
[SerializeField] private Button btnClose;
[SerializeField] private Animation targetAnimation, contentAnimation;
[SerializeField] private float jiandaProgressBarIncreaseTime;
private readonly IEventAggregator _eventAggregator = new EventAggregator();
private static readonly int[] IndexFromToSlotIndex = { 0, 1, 3, 2, 4, 5 };
private IProgressChainPackData _data;
private int _visualProgress;
private const string ContentAnimationShiftKey = "item_change",
ContentAnimationIdleKey = "item_normal";
private void Start()
{
btnClose.onClick.AddListener(OnClickClose);
}
public void Init(IProgressChainPackData data)
{
_data = data;
for (int i = 0; i < IndexFromToSlotIndex.Length; i++) // The idx here is a little confusing....
slots[i].Init(IndexFromToSlotIndex[i], _data, _eventAggregator);
_eventAggregator.GetEvent<EventThanksGivingSlotClaimed>().Subscribe(OnClaim).AddTo(this);
textTimer.text = ConvertTools.ConvertTime2(_data.RemainingTime);
Observable.Interval(TimeSpan.FromSeconds(1.0f)).Subscribe(_ =>
{
textTimer.text = ConvertTools.ConvertTime2(_data.RemainingTime);
if (_data.RemainingTime.TotalSeconds <= 0) OnClickClose();
}).AddTo(this);
_visualProgress = _data.TokenProgress;
InitTargetProgress();
contentAnimation.Play(ContentAnimationIdleKey);
}
private const string BubbleKey = "bubble_task";
/// <summary>
/// Triggered when player click the claim button on the reward panel. Important.
/// </summary>
/// <param name="e">Contains the index of the slot that is being called.</param>
private void OnClaim(EventThanksGivingSlotClaimed e)
{
StopAllCoroutines();
StartCoroutine(PlayButtonChange(e));
StartCoroutine(PlayProgressBar(e));
StartCoroutine(ShiftSlots());
}
[SerializeField] private float jiandaParticleDelay;
private IEnumerator PlayParticle(EventThanksGivingSlotClaimed e)
{
yield return new WaitForSeconds(jiandaParticleDelay);
var slot = slots[IndexFromToSlotIndex[e.SlotIdx]];
slot.RewardPanelCallbackSubscription?.Dispose();
slot.PlayParticle();
}
[SerializeField] private float jiandaButtonChangeDelay;
private IEnumerator PlayButtonChange(EventThanksGivingSlotClaimed e)
{
yield return new WaitForSeconds(jiandaButtonChangeDelay);
var slot = slots[IndexFromToSlotIndex[e.SlotIdx]];
slot.RewardPanelCallbackSubscription?.Dispose();
slot.PlayButtonAnimation();
slot.PlayCanvasGroupEffect(false);
slot.SetToken(false);
if (e.SlotIdx + 1 < IndexFromToSlotIndex.Length)
{
slots[IndexFromToSlotIndex[e.SlotIdx + 1]].SetLock(false);
slots[IndexFromToSlotIndex[e.SlotIdx + 1]].PlayCanvasGroupEffect(true);
}
}
[SerializeField] private float jiandaProgressBarDelay;
private IEnumerator PlayProgressBar(EventThanksGivingSlotClaimed e)
{
yield return new WaitForSeconds(jiandaProgressBarDelay);
_data.GetTokenProgressTargetByProgress(_visualProgress, out var targetDisplay,
out var scoreDisplay);
var midtermTarget = targetDisplay - scoreDisplay + _visualProgress;
int rewardDropId;
if (_data.IsChainPackDepleted)
{
yield return DOTween.To(() => _visualProgress, p => _visualProgress = p, midtermTarget,
jiandaProgressBarIncreaseTime).OnUpdate(() =>
{
_data.GetTokenProgressTargetByProgress(_visualProgress, out targetDisplay,
out scoreDisplay);
textProgress.text = $"{scoreDisplay}/{targetDisplay}";
barProgress.fillAmount = (float)scoreDisplay / targetDisplay;
}).WaitForCompletion();
targetAnimation.Play(BubbleKey);
barProgress.fillAmount = 1;
textProgress.gameObject.SetActive(false);
textComplete.gameObject.SetActive(true);
rewardProgress.SetReceived(true);
GContext.Publish(new ShowData(GContext.container.Resolve<PlayerItemData>()
.GetItemDataByDropId(e.ProgressRewardGot[0], afterAdding: true)));
GContext.Publish(new ShowData());
yield break;
}
if (e.ProgressRewardGot.Count > 0)
{
yield return DOTween.To(() => _visualProgress, p => _visualProgress = p, midtermTarget,
jiandaProgressBarIncreaseTime)
.OnUpdate(() =>
{
_data.GetTokenProgressTargetByProgress(_visualProgress, out targetDisplay,
out scoreDisplay);
// Debug.Log($"<color=#f18c0a>{_visualProgress}: {scoreDisplay}/{targetDisplay}</color>");
textProgress.text = $"{scoreDisplay}/{targetDisplay}";
barProgress.fillAmount = (float)scoreDisplay / targetDisplay;
}).WaitForCompletion();
targetAnimation.Play(BubbleKey);
barProgress.fillAmount = 0;
textProgress.text = $"0/{targetDisplay}";
yield return new WaitForSeconds(35f / 60);
}
rewardDropId = _data.GetRewardDropByChainProgress(_visualProgress);
rewardProgress.SetData(GContext.container.Resolve<PlayerItemData>()
.GetItemDataByDropId(rewardDropId)[0]);
yield return DOTween.To(() => _visualProgress, p => _visualProgress = p,
_data.TokenProgress,
jiandaProgressBarIncreaseTime)
.OnUpdate(() =>
{
_data.GetTokenProgressTargetByProgress(_visualProgress, out targetDisplay,
out scoreDisplay);
textProgress.text = $"{scoreDisplay}/{targetDisplay}";
barProgress.fillAmount = (float)scoreDisplay / targetDisplay;
}).WaitForCompletion();
if (e.ProgressRewardGot.Count > 0)
{
GContext.Publish(
new ShowData(GContext.container.Resolve<PlayerItemData>()
.GetItemDataByDropId(e.ProgressRewardGot[0], afterAdding: true)));
GContext.Publish(new ShowData());
}
}
[SerializeField] private float jiandaSlotShiftDelay;
private IEnumerator ShiftSlots()
{
yield return new WaitForSeconds(jiandaSlotShiftDelay);
if (!_data.IsEndGame)
{
slot6.Init(6, _data, _eventAggregator);
contentAnimation.Play(ContentAnimationShiftKey);
yield return new WaitForSeconds(35f / 60);
contentAnimation.Play(ContentAnimationIdleKey);
}
for (int i = 0;
i < IndexFromToSlotIndex.Length;
i++) // The idx here is a little confusing....
{
slots[i].Init(IndexFromToSlotIndex[i], _data, _eventAggregator);
}
}
private void OnClickClose()
{
RedPointManager.Instance.SetRedPointState(_data.RedPointKey, _data.DoNeedPackRedPoint);
UIManager.Instance.DestroyUI(gameObject.name);
}
private void InitTargetProgress()
{
if (_data.IsChainPackDepleted)
{
barProgress.fillAmount = 1;
textProgress.gameObject.SetActive(false);
textComplete.gameObject.SetActive(true);
var rewardDropId = _data.GetRewardDropByChainProgress(_visualProgress);
rewardProgress.SetData(GContext.container.Resolve<PlayerItemData>()
.GetItemDataByDropId(rewardDropId)[0]);
rewardProgress.SetReceived(true);
}
else
{
_data.GetTokenProgressTargetByProgress(_visualProgress, out var targetDisplay,
out var scoreDisplay);
// Debug.Log($"<color=#f18c0a>Start {_visualProgress}-{targetDisplay} - {scoreDisplay}</color>");
barProgress.fillAmount = scoreDisplay / (float)targetDisplay;
textProgress.text = $"{scoreDisplay}/{targetDisplay}";
textComplete.gameObject.SetActive(false);
tokenIcon.SetIcon(_data.TokenIconUrl);
var rewardDropId = _data.GetRewardDropByChainProgress(_visualProgress);
rewardProgress.SetData(GContext.container.Resolve<PlayerItemData>()
.GetItemDataByDropId(rewardDropId)[0]);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e28c70608f35d0c46b1fde2e9bcc7987
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: