807 lines
26 KiB
C#
807 lines
26 KiB
C#
using NUnit.Framework.Internal;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
public class ScriptVM : MonoBehaviour
|
|
{
|
|
private Script _currentScript;
|
|
private ExecutionContext _mainContext;
|
|
private Dictionary<int, ExecutionContext> _activeSubroutines = new Dictionary<int, ExecutionContext>();
|
|
private Dictionary<int, GameObject> _modelTempRegistry = new Dictionary<int, GameObject>();
|
|
private Dictionary<int, GameObject> _objectRegistry = new Dictionary<int, GameObject>();
|
|
|
|
private int selectionVariable;
|
|
|
|
// Jump Table îáðàáîò÷èêîâ êîìàíä
|
|
private Dictionary<uint, Action<ExecutionContext, ScriptCommand>> _opCodeHandlers;
|
|
|
|
public bool IsRunning => _mainContext != null && !_mainContext.IsFinished;
|
|
|
|
//SCRIPT LOGGING
|
|
void OnGUI()
|
|
{
|
|
GUILayout.BeginArea(new Rect(10, 10, 400, 600));
|
|
|
|
if (_mainContext != null)
|
|
{
|
|
GUILayout.Label($"MAIN: PC={_mainContext.ProgramCounter:X4} CMD=0x{GetCurrentCommand(_mainContext)?.OpCode:X4}");
|
|
GUILayout.Label($"Status: {(IsRunning ? "Running" : "Stopped")}");
|
|
GUILayout.Label($"Paused: {(_mainContext.IsPaused ? "+" : "-")} RemSec: -{_mainContext.PauseTimeRemaining}");
|
|
|
|
// Òåêóùèå ïàðàìåòðû êîìàíäû
|
|
var currentCmd = GetCurrentCommand(_mainContext);
|
|
if (currentCmd != null)
|
|
{
|
|
GUILayout.Label($"Params: {string.Join(", ", currentCmd.Params)}");
|
|
}
|
|
}
|
|
|
|
// Ïîäïðîãðàììû
|
|
GUILayout.Label($"Subroutines: {_activeSubroutines.Count}");
|
|
foreach (var kvp in _activeSubroutines)
|
|
{
|
|
var context = kvp.Value;
|
|
GUILayout.Label($"SUB[{kvp.Key:X2}] {context.ContextName}: PC={context.ProgramCounter:X4} CMD=0x{GetCurrentCommand(context)?.OpCode:X4}");
|
|
GUILayout.Label($" Paused: {(context.IsPaused ? "+" : "-")} RemSec: -{context.PauseTimeRemaining}");
|
|
}
|
|
|
|
GUILayout.EndArea();
|
|
}
|
|
|
|
void Awake()
|
|
{
|
|
InitializeJumpTable();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (_mainContext == null) return;
|
|
|
|
if (_mainContext.IsPaused && _mainContext.PauseTimeRemaining > 0)
|
|
{
|
|
_mainContext.PauseTimeRemaining -= Time.deltaTime;
|
|
if (_mainContext.PauseTimeRemaining <= 0)
|
|
{
|
|
_mainContext.PauseTimeRemaining = 0;
|
|
_mainContext.IsPaused = false;
|
|
_mainContext.ProgramCounter++;
|
|
MarkCurrentCommandCompleted(_mainContext); // Ïîìå÷àåì òåêóùóþ êîìàíäó êàê âûïîëíåííóþ
|
|
}
|
|
}
|
|
|
|
// Âûïîëíÿåì îñíîâíîé êîíòåêñò
|
|
if (!_mainContext.IsWaiting && !_mainContext.IsPaused)
|
|
{
|
|
ExecuteStep(_mainContext);
|
|
}
|
|
|
|
// Îáðàáàòûâàåì ïàóçó â ïîäïðîãðàììàõ
|
|
foreach (var context in _activeSubroutines.Values)
|
|
{
|
|
if (context.IsPaused && context.PauseTimeRemaining > 0)
|
|
{
|
|
context.PauseTimeRemaining -= Time.deltaTime;
|
|
if (context.PauseTimeRemaining <= 0)
|
|
{
|
|
context.PauseTimeRemaining = 0;
|
|
context.IsPaused = false;
|
|
context.ProgramCounter++;
|
|
MarkCurrentCommandCompleted(context);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Âûïîëíÿåì âñå àêòèâíûå ïîäïðîãðàììû
|
|
foreach (var context in _activeSubroutines.Values)
|
|
{
|
|
if (!context.IsWaiting && !context.IsPaused)
|
|
{
|
|
ExecuteStep(context);
|
|
}
|
|
}
|
|
|
|
// Óäàëÿåì çàâåðøåííûå ïîäïðîãðàììû
|
|
_activeSubroutines = _activeSubroutines.Where(kvp => !kvp.Value.IsFinished).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
}
|
|
|
|
public void LoadAndRunScript(Script script)
|
|
{
|
|
_currentScript = script;
|
|
_mainContext = new ExecutionContext(0, "MAIN", null);
|
|
_activeSubroutines.Clear();
|
|
_objectRegistry.Clear();
|
|
|
|
Debug.Log($"Script loaded with {script.Commands.Count} commands");
|
|
}
|
|
|
|
public void StartSubroutine(ushort subId)
|
|
{
|
|
if (_currentScript != null && _currentScript.SubroutineTable.TryGetValue(subId, out Subroutine sub))
|
|
{
|
|
var newContext = new ExecutionContext(sub.Address, sub.Name, new ScriptCommand {OpCode = 999});
|
|
_activeSubroutines[subId] = newContext;
|
|
Debug.Log($"Started independent subroutine {subId} at address {sub.Address:X4}");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Cannot start subroutine {subId}: script not loaded or subroutine not found");
|
|
}
|
|
}
|
|
|
|
private bool IsCommandCompleted(uint commandId)
|
|
{
|
|
if (commandId < _currentScript.Commands.Count)
|
|
{
|
|
return _currentScript.Commands[(int)commandId].executedStatus == 3;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// WaitTo - stops thread and check command status at address
|
|
private void Handle_WaitTo(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
uint targetCommandId = (uint)GetParam(cmd, 0);
|
|
|
|
if (IsCommandCompleted(targetCommandId))
|
|
{
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
}
|
|
|
|
private void ExecuteStep(ExecutionContext context)
|
|
{
|
|
if (context.ProgramCounter >= _currentScript.Commands.Count)
|
|
{
|
|
context.IsFinished = true;
|
|
if (context == _mainContext) Debug.Log("Main script finished");
|
|
return;
|
|
}
|
|
|
|
ScriptCommand cmd = _currentScript.Commands[(int)context.ProgramCounter];
|
|
cmd.executedStatus = 0; //cleaning status for command restart and proper wait
|
|
if (_opCodeHandlers.TryGetValue(cmd.OpCode, out var handler))
|
|
{
|
|
try
|
|
{
|
|
handler(context, cmd);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogError($"Error executing command 0x{cmd.OpCode:X8}: {ex.Message}");
|
|
// Ïðè îøèáêå âñå ðàâíî ïîìå÷àåì êàê âûïîëíåííóþ, ÷òîáû íå çàâèñíóòü
|
|
cmd.executedStatus = 3;
|
|
context.ProgramCounter++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Unknown OpCode: 0x{cmd.OpCode:X8} at PC={context.ProgramCounter:X4}");
|
|
// Íåèçâåñòíûå êîìàíäû ïðîñòî ïðîïóñêàåì
|
|
cmd.executedStatus = 3;
|
|
context.ProgramCounter++;
|
|
}
|
|
}
|
|
|
|
private void InitializeJumpTable()
|
|
{
|
|
_opCodeHandlers = new Dictionary<uint, Action<ExecutionContext, ScriptCommand>>
|
|
{
|
|
// Óïðàâëåíèå ïîòîêîì
|
|
{ 0x00000007, Handle_JumpTo },
|
|
{ 0x00000001, Handle_If1Go },
|
|
{ 0x00000002, Handle_If0Go },
|
|
{ 0x00000004, Handle_IfNotEqualGo },
|
|
{ 0x0000000D, Handle_GoSub },
|
|
{ 0x0000000E, Handle_Return },
|
|
{ 0x00000012, Handle_WaitTo },
|
|
|
|
{ 0x0000001A, Handle_GetInput },
|
|
|
|
{ 0x0000002C, Handle_SetCamXY }, // Set Camera
|
|
|
|
//Characters commands
|
|
{ 0x00000030, Handle_CharLoad }, // CharLoad
|
|
{ 0x00000031, Handle_CharInit }, // CharInit
|
|
{ 0x000000D0, Handle_CharInit }, // Another CharInit???
|
|
{ 0x00000034, Handle_CharMoveTo }, // CanWait
|
|
{ 0x00000037, Handle_CharAnimate }, // CanWait
|
|
{ 0x00000038, Handle_CharAnimate2 }, // CanWait
|
|
|
|
{ 0x00000041, Handle_PlayerInit }, // Create player char at camera set
|
|
|
|
{ 0x000000D2, Handle_CharGlowShow }, // CharInitWithGlow
|
|
|
|
{ 0x0000003E, Handle_WaitCharAnimEnd }, // Wait by char id
|
|
|
|
{ 0x00000046, Handle_CharSetSubroutine }, // Set blockcharacter subroutine
|
|
|
|
|
|
//Pause
|
|
{ 0x0000005C, Handle_PausInit }, // PausInit
|
|
{ 0x0000005D, Handle_PauseFr }, // PauseFr_
|
|
|
|
// Ðàáîòà ñ ïåðåìåííûìè
|
|
{ 0x00000008, Handle_SetTemp },
|
|
{ 0x00000009, Handle_CopyVar },
|
|
{ 0x00000060, Handle_GetVar },
|
|
{ 0x0000005E, Handle_VarTrue },
|
|
{ 0x0000005F, Handle_VarFlse },
|
|
{ 0x00000073, Handle_VarDec },
|
|
{ 0x00000074, Handle_VarSet },
|
|
|
|
// Óïðàâëåíèå
|
|
{ 0x00000043, Handle_CtrlLock },
|
|
{ 0x00000044, Handle_CtrUnlck },
|
|
|
|
// Çàãðóçêà ìîäóëåé
|
|
{ 0x00000051, Handle_DungLoad },
|
|
{ 0x00000052, Handle_EventLoad },
|
|
{ 0x00000053, Handle_CityLoad },
|
|
{ 0x000000ED, Handle_BattleLoad },
|
|
|
|
|
|
// Âèäåî
|
|
{ 0x00000059, Handle_VideoPly },
|
|
|
|
// Ýôôåêòû
|
|
{ 0x00000092, Handle_ScrnFade },
|
|
|
|
// Òåêñò
|
|
|
|
{ 0x00000024, Handle_WindOpen },
|
|
{ 0x00000013, Handle_TextShow },
|
|
{ 0x00000025, Handle_WindClose }
|
|
};
|
|
}
|
|
|
|
// ========== ÎÁÐÀÁÎÒ×ÈÊÈ ÊÎÌÀÍÄ ==========
|
|
|
|
private void Handle_JumpTo(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
uint jumpAddress = (uint)GetParam(cmd, 0);
|
|
ctx.ProgramCounter = jumpAddress;
|
|
cmd.executedStatus = 3; // Íåìåäëåííîå âûïîëíåíèå
|
|
}
|
|
|
|
private void Handle_If1Go(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int varAddress = GetParam(cmd, 0);
|
|
uint jumpAddress = (uint)GetParam(cmd, 1);
|
|
|
|
if (GetLocalVariable(ctx, varAddress) == 1)
|
|
ctx.ProgramCounter = jumpAddress;
|
|
else
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_If0Go(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int varAddress = GetParam(cmd, 0);
|
|
uint jumpAddress = (uint)GetParam(cmd, 1);
|
|
|
|
if (GetLocalVariable(ctx, varAddress) == 0)
|
|
ctx.ProgramCounter = jumpAddress;
|
|
else
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_IfNotEqualGo(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int varAddress = GetParam(cmd, 0);
|
|
int compareValue = GetParam(cmd, 1);
|
|
uint jumpAddress = (uint)GetParam(cmd, 2);
|
|
|
|
if (GetLocalVariable(ctx, varAddress) != compareValue)
|
|
ctx.ProgramCounter = jumpAddress;
|
|
else
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_GoSub(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
ushort subId = (ushort)GetParam(cmd, 0);
|
|
|
|
if (_currentScript.SubroutineTable.TryGetValue(subId, out Subroutine sub))
|
|
{
|
|
var newContext = new ExecutionContext(sub.Address, sub.Name, cmd);
|
|
_activeSubroutines[subId] = newContext;
|
|
}
|
|
ctx.ProgramCounter++;
|
|
}
|
|
|
|
private void Handle_Return(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
if (ctx.ExecutedByCmd != null) //main thread has ExecutedByCmd = null
|
|
{
|
|
// Äëÿ ïîäïðîãðàìì, âûçâàííûõ èç îñíîâíîãî ïîòîêà
|
|
ctx.ExecutedByCmd.executedStatus = 3;
|
|
ctx.IsFinished = true;
|
|
}
|
|
|
|
}
|
|
private void Handle_GetInput(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int varAddress = GetParam(cmd, 0);
|
|
SetLocalVariable(ctx, varAddress, selectionVariable);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
|
|
// Îáðàáîò÷èêè êîìàíä ïàóçû:
|
|
private void Handle_PausInit(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
// Ïðîñòî ñáðàñûâàåì ñ÷¸ò÷èê ïàóçû â êîíòåêñòå
|
|
ctx.PauseTimeRemaining = 0;
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_PauseFr(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int framesToPause = GetParam(cmd, 0);
|
|
|
|
ctx.PauseTimeRemaining = ctx.PauseTimeRemaining = framesToPause * (1f / App.Ps1FPS); //Ps1 FPS Compability
|
|
ctx.IsPaused = true; // Ñòàâèì êîíòåêñò íà ïàóçó
|
|
}
|
|
|
|
private void Handle_SetTemp(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int varAddress = GetParam(cmd, 0);
|
|
int value = GetParam(cmd, 1);
|
|
SetLocalVariable(ctx, varAddress, value);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CopyVar(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int srcAddress = GetParam(cmd, 0);
|
|
int dstAddress = GetParam(cmd, 1);
|
|
int value = GetLocalVariable(ctx, srcAddress);
|
|
SetLocalVariable(ctx, dstAddress, value);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_GetVar(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int localVarAddress = GetParam(cmd, 0);
|
|
int globalVarAddress = GetParam(cmd, 1);
|
|
int value = App.GameState.GetGlobalVariable(globalVarAddress);
|
|
SetLocalVariable(ctx, localVarAddress, value);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_VarTrue(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int globalVarAddress = GetParam(cmd, 0);
|
|
App.GameState.SetGlobalVariable(globalVarAddress, 1);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_VarFlse(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int globalVarAddress = GetParam(cmd, 0);
|
|
App.GameState.SetGlobalVariable(globalVarAddress, 0);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_VarSet(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int globalVarAddress = GetParam(cmd, 0);
|
|
int value = GetParam(cmd, 1);
|
|
App.GameState.SetGlobalVariable(globalVarAddress, value);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_VarDec(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int globalVarAddress = GetParam(cmd, 0);
|
|
int currentValue = App.GameState.GetGlobalVariable(globalVarAddress);
|
|
App.GameState.SetGlobalVariable(globalVarAddress, currentValue - 1);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CtrlLock(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
Debug.Log("Controls Locked");
|
|
App.GameState.IsPlayerControlLocked = true;
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CtrUnlck(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
Debug.Log("Controls Unlocked");
|
|
App.GameState.IsPlayerControlLocked = false;
|
|
|
|
if (_objectRegistry.TryGetValue(1, out GameObject playerObj))
|
|
{
|
|
ControlsController.Instance?.SetControlledObject(playerObj);
|
|
}
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_SetCamXY(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
uint rot = (uint)GetParam(cmd, 0);
|
|
uint x = (uint)GetParam(cmd, 1);
|
|
uint y = (uint)GetParam(cmd, 2);
|
|
uint z = (uint)GetParam(cmd, 3);
|
|
|
|
App.CameraController.SetCamTargetXY(rot, x, y, z);
|
|
Debug.Log($"Camera position set {x}.{y}.{z}. Rot - {rot}");
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_TextShow(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int textOffset = GetParam(cmd, 0);
|
|
|
|
var textTokens = TextUtils.ParseText(_currentScript.TextData, textOffset);
|
|
|
|
// Ïåðåäàåì êîìàíäó â UI ìåíåäæåð
|
|
App.TextManager.ShowText(textTokens, cmd);
|
|
|
|
ctx.ProgramCounter++;
|
|
}
|
|
|
|
private void Handle_WindOpen(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
App.UI.ShowMessageWindow();
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_WindClose(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
App.UI.HideMessageWindow(ctx);
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
//CHARACTERS SECTION
|
|
|
|
private void Handle_CharLoad(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
//Old PS1 method for loading sprite sheet in VRAM
|
|
//Now we simply creating disabled char model on scene
|
|
int modelId = GetParam(cmd, 0);
|
|
if (!_modelTempRegistry.ContainsKey(modelId))
|
|
{
|
|
GameObject model = App.ResourceManager.CharLoad(modelId);
|
|
_modelTempRegistry[modelId] = model;
|
|
}
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CharInit(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
// Ïàðàìåòðû: id, model_id, x, y, z, turn, dummy
|
|
int objectId = GetParam(cmd, 0);
|
|
int modelId = GetParam(cmd, 1);
|
|
uint posX = (uint)GetParam(cmd, 2);
|
|
uint posY = (uint)GetParam(cmd, 3);
|
|
uint posZ = (uint)GetParam(cmd, 4);
|
|
uint rotation = (uint)GetParam(cmd, 5);
|
|
int dummy = GetParam(cmd, 6); // Íåèñïîëüçóåìûé ïàðàìåòð
|
|
|
|
if (!_modelTempRegistry.TryGetValue(modelId, out GameObject templateModel))
|
|
{
|
|
Debug.LogWarning($"Model {modelId} not loaded, creating...");
|
|
templateModel = App.ResourceManager.CharLoad(modelId);
|
|
_modelTempRegistry[modelId] = templateModel;
|
|
}
|
|
|
|
if (_objectRegistry.TryGetValue(objectId, out GameObject existingModel))
|
|
{
|
|
Destroy(existingModel);
|
|
_objectRegistry.Remove(objectId);
|
|
}
|
|
|
|
GameObject characterInstance = App.ResourceManager.CharInit(templateModel, objectId, posX, posY, posZ, rotation);
|
|
|
|
_objectRegistry[objectId] = characterInstance;
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
// Activate player object at camera spot position and link controls
|
|
private void Handle_PlayerInit(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int rotation = GetParam(cmd, 0);
|
|
|
|
if (!_modelTempRegistry.TryGetValue(1, out GameObject templateModel))
|
|
{
|
|
Debug.LogWarning($"Player Model not loaded, creating...");
|
|
templateModel = App.ResourceManager.CharLoad(1);
|
|
_modelTempRegistry[1] = templateModel;
|
|
}
|
|
|
|
if (_objectRegistry.TryGetValue(1, out GameObject existingModel))
|
|
{
|
|
Destroy(existingModel);
|
|
_objectRegistry.Remove(1);
|
|
}
|
|
|
|
CameraController sceneCamera = App.CameraController;
|
|
GameObject character = App.ResourceManager.CharInit(templateModel, 1, sceneCamera.sourceX, sceneCamera.sourceY, sceneCamera.sourceZ, (uint)rotation);
|
|
|
|
_objectRegistry[1] = character;
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CharGlowShow(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
// Ïàðàìåòðû: id, x, y, z, glow, dummy
|
|
int charId = GetParam(cmd, 0);
|
|
uint posX = (uint)GetParam(cmd, 1);
|
|
uint posY = (uint)GetParam(cmd, 2);
|
|
uint posZ = (uint)GetParam(cmd, 3);
|
|
uint glow = (uint)GetParam(cmd, 4);
|
|
int dummy = GetParam(cmd, 5);
|
|
|
|
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj))
|
|
{
|
|
|
|
App.ResourceManager.CharInit(characterObj, charId, posX, posY, posZ, glow); //TODO: Async GLOW
|
|
}
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CharMoveTo(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int charId = GetParam(cmd, 0);
|
|
uint destX = (uint)GetParam(cmd, 1);
|
|
uint destZ = (uint)GetParam(cmd, 2);
|
|
uint endAction = (uint)GetParam(cmd, 3);
|
|
uint speed = (uint)GetParam(cmd, 4);
|
|
|
|
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj) && characterObj is GameObject character)
|
|
{
|
|
var controller = character.GetComponent<CharacterController>();
|
|
if (controller != null)
|
|
{
|
|
//async move
|
|
controller.MoveToGameCoordinates(destX, destZ, endAction, speed);
|
|
}
|
|
}
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CharAnimate(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int charId = GetParam(cmd, 0);
|
|
uint animationId = (uint)GetParam(cmd, 1);
|
|
uint repeatNum = (uint)GetParam(cmd, 2);
|
|
|
|
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj) && characterObj is GameObject character)
|
|
{
|
|
var controller = character.GetComponent<CharacterController>();
|
|
if (controller != null)
|
|
{
|
|
controller.PlayAnimation((int)animationId, (int)Mathf.Max(1, repeatNum));
|
|
}
|
|
}
|
|
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
private void Handle_CharAnimate2(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
Handle_CharAnimate(ctx, cmd);
|
|
}
|
|
|
|
private void Handle_WaitCharAnimEnd(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int charId = GetParam(cmd, 0);
|
|
|
|
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj) && characterObj is GameObject character)
|
|
{
|
|
var controller = character.GetComponent<CharacterController>();
|
|
if (controller != null && !controller.IsMoving)
|
|
{
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
}
|
|
|
|
private void Handle_CharSetSubroutine(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int charId = GetParam(cmd, 0);
|
|
int subId = GetParam(cmd, 1);
|
|
|
|
_objectRegistry.TryGetValue(charId, out GameObject characterObj);
|
|
characterObj.GetComponent<CharacterController>().blockSubroutine = subId;
|
|
Debug.Log($"Sub {subId} set to char {charId}");
|
|
ctx.ProgramCounter++;
|
|
cmd.executedStatus = 3;
|
|
}
|
|
|
|
|
|
// SCENERY LOADERS
|
|
private void Handle_CityLoad(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int districtId = GetParam(cmd, 0);
|
|
int y = GetParam(cmd, 1);
|
|
int x = GetParam(cmd, 2);
|
|
App.SceneLoader.LoadCity(districtId, y, x);
|
|
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
|
|
}
|
|
private void Handle_BattleLoad(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int battleId = GetParam(cmd, 0);
|
|
App.SceneLoader.LoadBattle(battleId);
|
|
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
|
|
}
|
|
private void Handle_DungLoad(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int dungeonId = GetParam(cmd, 0);
|
|
App.SceneLoader.LoadDungeon(dungeonId);
|
|
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
|
|
}
|
|
private void Handle_EventLoad(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int hzId = GetParam(cmd, 0);
|
|
int eventId = GetParam(cmd, 1);
|
|
App.SceneLoader.LoadEvent(eventId, hzId);
|
|
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
|
|
}
|
|
|
|
private void Handle_VideoPly(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int videoId = GetParam(cmd, 0);
|
|
App.VideoPlayer.PlayVideo(videoId, cmd);
|
|
PauseContext(cmd);
|
|
}
|
|
|
|
private void Handle_ScrnFade(ExecutionContext ctx, ScriptCommand cmd)
|
|
{
|
|
int fadeType = GetParam(cmd, 0);
|
|
int duration = GetParam(cmd, 1);
|
|
//App.UI.ScreenFade(fadeType, duration, () => {
|
|
// ctx.ProgramCounter++;
|
|
//});
|
|
ctx.ProgramCounter++;
|
|
}
|
|
|
|
public void PauseContext(ScriptCommand cmd)
|
|
{
|
|
// Íàõîäèì êîíòåêñò, êîòîðûé âûïîëíÿåò ýòó êîìàíäó
|
|
if (_mainContext != null && GetCurrentCommand(_mainContext) == cmd)
|
|
{
|
|
_mainContext.IsPaused = true;
|
|
return;
|
|
}
|
|
|
|
foreach (var context in _activeSubroutines.Values)
|
|
{
|
|
if (GetCurrentCommand(context) == cmd)
|
|
{
|
|
context.IsPaused = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ResumeContext(ScriptCommand cmd)
|
|
{
|
|
// Íàõîäèì êîíòåêñò è ñíèìàåì ïàóçó
|
|
if (_mainContext != null && GetCurrentCommand(_mainContext) == cmd)
|
|
{
|
|
_mainContext.IsPaused = false;
|
|
_mainContext.ProgramCounter++; // Ïåðåõîäèì ê ñëåäóþùåé êîìàíäå
|
|
return;
|
|
}
|
|
|
|
foreach (var context in _activeSubroutines.Values)
|
|
{
|
|
if (GetCurrentCommand(context) == cmd)
|
|
{
|
|
context.IsPaused = false;
|
|
context.ProgramCounter++; // Ïåðåõîäèì ê ñëåäóþùåé êîìàíäå
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========== ÂÑÏÎÌÎÃÀÒÅËÜÍÛÅ ÌÅÒÎÄÛ ==========
|
|
|
|
private ScriptCommand GetCurrentCommand(ExecutionContext ctx)
|
|
{
|
|
if (ctx.ProgramCounter < _currentScript.Commands.Count)
|
|
return _currentScript.Commands[(int)ctx.ProgramCounter];
|
|
return null;
|
|
}
|
|
|
|
private int GetParam(ScriptCommand cmd, int index)
|
|
{
|
|
return index < cmd.Params.Length ? cmd.Params[index] : 0;
|
|
}
|
|
|
|
private int GetLocalVariable(ExecutionContext ctx, int address)
|
|
{
|
|
return ctx.LocalVariables.TryGetValue(address, out int value) ? value : 0;
|
|
}
|
|
|
|
private void SetLocalVariable(ExecutionContext ctx, int address, int value)
|
|
{
|
|
ctx.LocalVariables[address] = value;
|
|
}
|
|
|
|
|
|
public void SetSelectionVariable(int value) //external after selection variable set
|
|
{
|
|
selectionVariable = value;
|
|
}
|
|
|
|
public void MarkCommandCompleted(ScriptCommand cmd)
|
|
{
|
|
cmd.executedStatus = 3;
|
|
ResumeContext(cmd);
|
|
}
|
|
|
|
private void MarkCurrentCommandCompleted(ExecutionContext ctx)
|
|
{
|
|
if (ctx.ProgramCounter > 0 && ctx.ProgramCounter - 1 < _currentScript.Commands.Count)
|
|
{
|
|
ScriptCommand cmd = _currentScript.Commands[(int)(ctx.ProgramCounter - 1)];
|
|
cmd.executedStatus = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ExecutionContext
|
|
{
|
|
public ScriptCommand ExecutedByCmd { get; set; }
|
|
public string ContextName { get; set; }
|
|
public uint ProgramCounter { get; set; }
|
|
public Dictionary<int, int> LocalVariables { get; set; }
|
|
public bool IsWaiting { get; set; }
|
|
public bool IsPaused { get; set; }
|
|
public bool IsFinished { get; set; }
|
|
public float PauseTimeRemaining { get; set; }
|
|
|
|
public ExecutionContext(uint startAddress, string name, ScriptCommand cmd)
|
|
{
|
|
ContextName = name;
|
|
ExecutedByCmd = cmd;
|
|
ProgramCounter = startAddress;
|
|
LocalVariables = new Dictionary<int, int>();
|
|
PauseTimeRemaining = 0;
|
|
}
|
|
} |