89 lines
4.6 KiB
C#
89 lines
4.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
using UnityEngine;
|
|
|
|
// 스토리(StoryLogic 26장 · StoryLocale) — 조건 충족 시 대화 장면 1회 (트리거 문자열은 원작 표 그대로 파싱)
|
|
namespace VS.Sim
|
|
{
|
|
[Serializable] public class StoryLineRow { public string key; public int characterId; public string emotion; public string lineEvent; }
|
|
[Serializable] public class StoryChapterRow { public string id; public string trigger; public string backgroundId; public bool useLiteUi; public List<StoryLineRow> lines; }
|
|
[Serializable] public class StoryLogicTable { public List<StoryChapterRow> chapters; }
|
|
[Serializable] public class StoryLocaleLine { public string key; public string speakerName; public string text; }
|
|
[Serializable] public class StoryCharName { public string id; public string name; }
|
|
[Serializable] public class StoryLocaleTable { public List<StoryLocaleLine> lines; public List<StoryCharName> characterNames; }
|
|
|
|
public partial class Game
|
|
{
|
|
public StoryLogicTable Story;
|
|
Dictionary<string, StoryLocaleLine> storyText;
|
|
static readonly Regex RxItem = new Regex(@"^ITEM_(\d+)_HOUSE_(\d+)_LEVEL_?\s*>=\s*(\d+)$", RegexOptions.IgnoreCase);
|
|
static readonly Regex RxHouseItem = new Regex(@"^ITEM_HOUSE_(\d+)_LEVEL_?\s*>=\s*(\d+)$", RegexOptions.IgnoreCase);
|
|
static readonly Regex RxUnlock = new Regex(@"^UNLOCK_ROOM_(\d+)$", RegexOptions.IgnoreCase);
|
|
static readonly Regex RxFollower = new Regex(@"^FOLLOWERS?_?\s*>=\s*(\d+)$", RegexOptions.IgnoreCase);
|
|
|
|
void InitStory()
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(T.StoryLogicJson)) Story = JsonUtility.FromJson<StoryLogicTable>(T.StoryLogicJson);
|
|
storyText = new Dictionary<string, StoryLocaleLine>();
|
|
if (!string.IsNullOrEmpty(T.StoryLocaleJson))
|
|
{
|
|
var loc = JsonUtility.FromJson<StoryLocaleTable>(T.StoryLocaleJson);
|
|
foreach (var l in loc.lines) storyText[l.key] = l;
|
|
}
|
|
}
|
|
catch (Exception e) { Say("story load failed " + e.Message); }
|
|
}
|
|
|
|
public StoryLocaleLine StoryLine(string key) => storyText != null && storyText.TryGetValue(key, out var l) ? l : null;
|
|
|
|
/// 트리거 평가 — 아이템 번호·레벨은 화면 표기(1부터 · 레벨 = 저장값+1) 기준 (추정: 시각 단계 문턱 24·49 ↔ 표 25·50)
|
|
public bool StoryTriggerMet(string trig)
|
|
{
|
|
if (string.IsNullOrEmpty(trig)) return false;
|
|
trig = trig.Trim();
|
|
if (trig.Equals("START_GAME", StringComparison.OrdinalIgnoreCase)) return true;
|
|
var m = RxItem.Match(trig);
|
|
if (m.Success)
|
|
{
|
|
int item = int.Parse(m.Groups[1].Value) - 1, house = int.Parse(m.Groups[2].Value) - 1, lv = int.Parse(m.Groups[3].Value);
|
|
return house == S.house && RoomLevel(item) + 1 >= lv || house < S.house;
|
|
}
|
|
m = RxHouseItem.Match(trig);
|
|
if (m.Success)
|
|
{
|
|
// ItemHouseLevel: 지난 집이면 즉시 · 같은 집이면 11개 모두 구매 + 최솟값(표시 레벨) ≥ L (TryGetMinHouseDisplayItemLevel RVA 0x25C434C)
|
|
int house = int.Parse(m.Groups[1].Value) - 1, lv = int.Parse(m.Groups[2].Value);
|
|
if (house < S.house) return true;
|
|
if (house > S.house) return false;
|
|
int min = int.MaxValue;
|
|
foreach (var it in Room.Items) { int l = RoomLevel(it.Index); if (l < 0) return false; min = Math.Min(min, l + 1); }
|
|
return min >= lv;
|
|
}
|
|
m = RxUnlock.Match(trig);
|
|
if (m.Success) return S.house >= int.Parse(m.Groups[1].Value) - 1;
|
|
m = RxFollower.Match(trig);
|
|
if (m.Success) return Follower >= System.Numerics.BigInteger.Parse(m.Groups[1].Value);
|
|
return false;
|
|
}
|
|
|
|
/// 다음에 보여 줄 장(원작 순서 = 표 순서 · 이미 본 장 제외)
|
|
public StoryChapterRow NextStory()
|
|
{
|
|
if (Story == null || !T.Cfg.remote.OnOffStory) return null;
|
|
foreach (var c in Story.chapters)
|
|
{
|
|
if (S.seenStories.Contains(c.id)) continue;
|
|
if (StoryTriggerMet(c.trigger)) return c;
|
|
// 앞 장을 안 봤으면 뒤 장은 보류(표 순서 유지)
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void MarkStorySeen(string id) { if (!S.seenStories.Contains(id)) S.seenStories.Add(id); }
|
|
}
|
|
}
|