241 lines
8.2 KiB
C#
241 lines
8.2 KiB
C#
using System.Collections.Generic;
|
|
using GameFramework.DataTable;
|
|
using GeometryTD.CustomEvent;
|
|
using GeometryTD.DataTable;
|
|
using GeometryTD.Definition;
|
|
using GeometryTD.Factory;
|
|
using GeometryTD.Procedure;
|
|
using Newtonsoft.Json.Linq;
|
|
using GeometryTD.UI;
|
|
using UnityEngine;
|
|
using UnityGameFramework.Runtime;
|
|
|
|
namespace GeometryTD.CustomComponent
|
|
{
|
|
public class EventNodeComponent : GameFrameworkComponent
|
|
{
|
|
private RunNodeExecutionContext _activeContext;
|
|
private EventItem _activeEvent;
|
|
|
|
private readonly List<EventItem> _eventItems = new List<EventItem>();
|
|
|
|
private EventFormUseCase _eventFormUseCase;
|
|
private bool _initialized;
|
|
|
|
public void OnInit()
|
|
{
|
|
_eventItems.Clear();
|
|
|
|
IDataTable<DREvent> dtEvent = GameEntry.DataTable.GetDataTable<DREvent>();
|
|
if (dtEvent == null)
|
|
{
|
|
Log.Warning("Event data table is not loaded.");
|
|
_initialized = true;
|
|
return;
|
|
}
|
|
|
|
DREvent[] rows = dtEvent.GetAllDataRows();
|
|
foreach (var drEvent in rows)
|
|
{
|
|
EventOption[] options = ParseOptions(drEvent.OptionsRaw);
|
|
_eventItems.Add(new EventItem(drEvent.Id, drEvent.Title, drEvent.Description, options));
|
|
}
|
|
|
|
if (_eventFormUseCase == null)
|
|
{
|
|
_eventFormUseCase = new EventFormUseCase();
|
|
}
|
|
|
|
GameEntry.UIRouter.BindUIUseCase(UIFormType.EventForm, _eventFormUseCase);
|
|
|
|
_initialized = true;
|
|
Log.Info("EventNodeComponent initialized with {0} events.", _eventItems.Count);
|
|
}
|
|
|
|
public void StartEvent(RunNodeExecutionContext context = null)
|
|
{
|
|
if (!_initialized)
|
|
{
|
|
OnInit();
|
|
}
|
|
|
|
if (_eventItems.Count <= 0)
|
|
{
|
|
Log.Warning("EventNodeComponent has no event data.");
|
|
return;
|
|
}
|
|
|
|
if (_eventFormUseCase == null)
|
|
{
|
|
Log.Warning("EventNodeComponent StartEvent failed. Event form is not initialized.");
|
|
return;
|
|
}
|
|
|
|
_activeContext = context != null ? context.Clone() : null;
|
|
_activeEvent = SelectActiveEvent(_activeContext);
|
|
if (_activeEvent == null)
|
|
{
|
|
Log.Warning("EventNodeComponent StartEvent failed. No active event could be resolved.");
|
|
return;
|
|
}
|
|
|
|
_eventFormUseCase.BindEvent(_activeEvent, _activeContext);
|
|
GameEntry.UIRouter.OpenUI(UIFormType.EventForm);
|
|
GameEntry.Event.Fire(
|
|
this,
|
|
NodeEnterEventArgs.Create(
|
|
_activeContext?.RunId,
|
|
_activeContext?.NodeId ?? 0,
|
|
_activeContext?.NodeType ?? RunNodeType.None,
|
|
_activeContext?.SequenceIndex ?? -1));
|
|
}
|
|
|
|
public void EndEvent()
|
|
{
|
|
GameEntry.UIRouter.CloseUI(UIFormType.EventForm);
|
|
GameEntry.Event.Fire(
|
|
this,
|
|
NodeCompleteEventArgs.Create(
|
|
_activeContext?.RunId,
|
|
_activeContext?.NodeId ?? 0,
|
|
_activeContext?.NodeType ?? RunNodeType.None,
|
|
_activeContext?.SequenceIndex ?? -1,
|
|
RunNodeCompletionStatus.Completed,
|
|
true,
|
|
_activeContext != null
|
|
? _activeContext.CreateCompletionSnapshot(
|
|
GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null)
|
|
: null));
|
|
ClearActiveNodeContext();
|
|
}
|
|
|
|
private void ClearActiveNodeContext()
|
|
{
|
|
_activeContext = null;
|
|
_activeEvent = null;
|
|
_eventFormUseCase?.Clear();
|
|
}
|
|
|
|
private static EventOption[] ParseOptions(string optionsRaw)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(optionsRaw))
|
|
{
|
|
return System.Array.Empty<EventOption>();
|
|
}
|
|
|
|
try
|
|
{
|
|
JArray array = JArray.Parse(optionsRaw);
|
|
List<EventOption> options = new List<EventOption>(array.Count);
|
|
|
|
for (int i = 0; i < array.Count; i++)
|
|
{
|
|
if (!(array[i] is JObject optionObj))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string optionText = optionObj.Value<string>("optionText") ?? string.Empty;
|
|
float probability = optionObj.Value<float?>("probability") ?? 1f;
|
|
|
|
EventRequirementBase[] requirements = ParseRequirements(optionObj["requirements"] as JArray);
|
|
EventEffectBase[] costEffects = ParseEffects(optionObj["costEffects"] as JArray, probability);
|
|
EventEffectBase[] rewardEffects = ParseEffects(optionObj["rewardEffects"] as JArray, probability);
|
|
|
|
options.Add(new EventOption(optionText, requirements, costEffects, rewardEffects, probability));
|
|
}
|
|
|
|
return options.ToArray();
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Log.Warning("Failed to parse event options json. {0}", e.Message);
|
|
return System.Array.Empty<EventOption>();
|
|
}
|
|
}
|
|
|
|
private static EventRequirementBase[] ParseRequirements(JArray requirementsArray)
|
|
{
|
|
if (requirementsArray == null || requirementsArray.Count == 0)
|
|
{
|
|
return System.Array.Empty<EventRequirementBase>();
|
|
}
|
|
|
|
List<EventRequirementBase> requirements = new List<EventRequirementBase>(requirementsArray.Count);
|
|
for (int i = 0; i < requirementsArray.Count; i++)
|
|
{
|
|
if (!(requirementsArray[i] is JObject reqObj))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string type = reqObj.Value<string>("type");
|
|
JObject param = reqObj["param"] as JObject;
|
|
EventRequirementBase requirement = EventRequirementFactory.Create(type, param);
|
|
if (requirement != null)
|
|
{
|
|
requirements.Add(requirement);
|
|
}
|
|
}
|
|
|
|
return requirements.ToArray();
|
|
}
|
|
|
|
private static EventEffectBase[] ParseEffects(JArray effectsArray, float probability)
|
|
{
|
|
if (effectsArray == null || effectsArray.Count == 0)
|
|
{
|
|
return System.Array.Empty<EventEffectBase>();
|
|
}
|
|
|
|
List<EventEffectBase> effects = new List<EventEffectBase>(effectsArray.Count);
|
|
for (int i = 0; i < effectsArray.Count; i++)
|
|
{
|
|
if (!(effectsArray[i] is JObject effectObj))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string type = effectObj.Value<string>("type");
|
|
JObject param = effectObj["param"] as JObject;
|
|
EventEffectBase effect = EventEffectFactory.Create(type, param, probability);
|
|
if (effect != null)
|
|
{
|
|
effects.Add(effect);
|
|
}
|
|
}
|
|
|
|
return effects.ToArray();
|
|
}
|
|
|
|
private EventItem SelectActiveEvent(RunNodeExecutionContext context)
|
|
{
|
|
if (_eventItems.Count <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (context == null)
|
|
{
|
|
int randomIndex = Random.Range(0, _eventItems.Count);
|
|
return _eventItems[randomIndex];
|
|
}
|
|
|
|
System.Random random = new System.Random(BuildSelectionSeed(context));
|
|
return _eventItems[random.Next(0, _eventItems.Count)];
|
|
}
|
|
|
|
private static int BuildSelectionSeed(RunNodeExecutionContext context)
|
|
{
|
|
unchecked
|
|
{
|
|
int seed = 17;
|
|
seed = seed * 31 + context.RunSeed;
|
|
seed = seed * 31 + context.SequenceIndex;
|
|
seed = seed * 31 + context.NodeId;
|
|
return seed;
|
|
}
|
|
}
|
|
}
|
|
}
|