Ejemplo n.º 1
0
        private void QueueRadio(FSMRunner fsmRunner, int soundId, int queueFlag, int owner)
        {
            bool endOfQueue;

            if (queueFlag == 1)
            {
                endOfQueue = false;
            }
            else if (queueFlag == 3)
            {
                endOfQueue = true;
            }
            else
            {
                endOfQueue = true;
                Debug.Log("Unknown value in cbPrior: " + queueFlag);
            }

            string soundName = fsmRunner.FSM.SoundClipTable[soundId];

            RadioManager.Instance.QueueRadioMessage(soundName, endOfQueue, owner);
        }
Ejemplo n.º 2
0
        public IEnumerator LoadLevel(string msnFilename)
        {
            _game.LevelName = msnFilename;
            string sceneName = SceneManager.GetActiveScene().name;

            if (sceneName != "Level")
            {
                AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(1, LoadSceneMode.Single);
                sceneLoad.allowSceneActivation = true;
                while (!sceneLoad.isDone)
                {
                    yield return(null);
                }

                yield break;
            }

            Terrain[,] terrainPatches = new Terrain[80, 80];
            MsnMissionParser.MissonDefinition mdef = MsnMissionParser.ReadMsnMission(msnFilename);

            _cacheManager.Palette = ActPaletteParser.ReadActPalette(mdef.PaletteFilePath);
            Texture2D surfaceTexture = TextureParser.ReadMapTexture(mdef.SurfaceTextureFilePath, _cacheManager.Palette, TextureFormat.RGB24, true, FilterMode.Point);

            GameObject.Find("Sky").GetComponent <Sky>().TextureFilename = mdef.SkyTextureFilePath;

            GameObject worldGameObject = GameObject.Find("World");

            if (worldGameObject != null)
            {
                Object.Destroy(worldGameObject);
            }

            worldGameObject = new GameObject("World");

            TerrainLayer[] terrainLayers = new[]
            {
                new TerrainLayer
                {
                    diffuseTexture = surfaceTexture,
                    tileSize       = new Vector2(surfaceTexture.width, surfaceTexture.height) / 10.0f,
                    metallic       = 0,
                    smoothness     = 0
                }
            };

            for (int z = 0; z < 80; z++)
            {
                for (int x = 0; x < 80; x++)
                {
                    if (mdef.TerrainPatches[x, z] == null)
                    {
                        continue;
                    }

                    GameObject patchGameObject = new GameObject("Ter " + x + ", " + z);
                    patchGameObject.layer = LayerMask.NameToLayer("Terrain");
                    patchGameObject.transform.position = new Vector3(x * 640, 0, z * 640);
                    patchGameObject.transform.parent   = worldGameObject.transform;

                    Terrain terrain = patchGameObject.AddComponent <Terrain>();
                    terrain.terrainData = mdef.TerrainPatches[x, z].TerrainData;
                    terrain.terrainData.terrainLayers = terrainLayers;
                    terrain.materialTemplate          = _terrainMaterial;
                    terrain.materialType = Terrain.MaterialType.Custom;

                    TerrainCollider terrainCollider = patchGameObject.AddComponent <TerrainCollider>();
                    terrainCollider.terrainData = terrain.terrainData;

                    foreach (MsnMissionParser.Odef odef in mdef.TerrainPatches[x, z].Objects)
                    {
                        GameObject go = null;
                        if (odef.ClassId == MsnMissionParser.ClassId.Car)
                        {
                            string lblUpper = odef.Label.ToUpper();

                            // Training mission uses hardcoded VCF for player.
                            string vcfName = odef.Label;
                            if (msnFilename.ToLower() == "a01.msn" && vcfName == "vppirna1")
                            {
                                vcfName = "vppa01";
                            }

                            switch (lblUpper)
                            {
                            case "SPAWN":
                                go     = Object.Instantiate(_spawnPrefab);
                                go.tag = "Spawn";
                                break;

                            case "REGEN":
                                go     = Object.Instantiate(_regenPrefab);
                                go.tag = "Regen";
                                break;

                            default:
                                go = _cacheManager.ImportVcf(vcfName + ".vcf", odef.IsPlayer, out _);
                                Car car = go.GetComponent <Car>();
                                car.TeamId   = odef.TeamId;
                                car.IsPlayer = odef.IsPlayer;
                                break;
                            }

                            go.transform.parent        = patchGameObject.transform;
                            go.transform.localPosition = odef.LocalPosition;
                            go.transform.localRotation = odef.LocalRotation;

                            if (odef.IsPlayer)
                            {
                                CameraManager.Instance.MainCamera.GetComponent <SmoothFollow>().Target = go.transform;
                                go.AddComponent <CarInput>();
                            }
                        }
                        else if (odef.ClassId != MsnMissionParser.ClassId.Special)
                        {
                            bool canWreck = odef.ClassId == MsnMissionParser.ClassId.Struct1 ||
                                            odef.ClassId == MsnMissionParser.ClassId.Ramp ||
                                            odef.ClassId == MsnMissionParser.ClassId.Struct2;

                            go = _cacheManager.ImportSdf(odef.Label + ".sdf", patchGameObject.transform, odef.LocalPosition, odef.LocalRotation, canWreck, out Sdf sdf, out GameObject wreckedPart);
                            if (odef.ClassId == MsnMissionParser.ClassId.Sign)
                            {
                                go.AddComponent <Sign>();
                            }
                            else if (canWreck)
                            {
                                Building building = go.AddComponent <Building>();
                                building.Initialise(sdf, wreckedPart);
                            }
                        }

                        if (go != null)
                        {
                            go.name = odef.Label + "_" + odef.Id;

                            if (mdef.FSM != null)
                            {
                                FSMEntity[] entities = mdef.FSM.EntityTable;
                                for (int i = 0; i < entities.Length; ++i)
                                {
                                    if (entities[i].Value == odef.Label && entities[i].Id == odef.Id)
                                    {
                                        WorldEntity worldEntity = go.GetComponent <WorldEntity>();
                                        if (worldEntity != null)
                                        {
                                            entities[i].WorldEntity = worldEntity;
                                            worldEntity.Id          = i;
                                        }

                                        entities[i].Object = go;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    terrainPatches[x, z] = terrain;
                }
            }

            RoadManager roadManager = RoadManager.Instance;

            foreach (MsnMissionParser.Road road in mdef.Roads)
            {
                roadManager.CreateRoadObject(road, mdef.Middle * 640);
            }

            foreach (MsnMissionParser.Ldef ldef in mdef.StringObjects)
            {
                GameObject sdfObj = _cacheManager.ImportSdf(ldef.Label + ".sdf", null, Vector3.zero, Quaternion.identity, false, out _, out _);

                for (int i = 0; i < ldef.StringPositions.Length; i++)
                {
                    Vector3 pos           = ldef.StringPositions[i];
                    Vector3 localPosition = new Vector3(pos.x % 640, pos.y, pos.z % 640);
                    int     patchPosX     = (int)(pos.x / 640.0f);
                    int     patchPosZ     = (int)(pos.z / 640.0f);
                    sdfObj.name                    = ldef.Label + " " + i;
                    sdfObj.transform.parent        = terrainPatches[patchPosX, patchPosZ].transform;
                    sdfObj.transform.localPosition = localPosition;
                    if (i < ldef.StringPositions.Length - 1)
                    {
                        sdfObj.transform.LookAt(ldef.StringPositions[i + 1], Vector3.up);
                    }
                    else
                    {
                        sdfObj.transform.LookAt(ldef.StringPositions[i - 1], Vector3.up);
                        sdfObj.transform.localRotation *= Quaternion.AngleAxis(180, Vector3.up);
                    }

                    if (i < ldef.StringPositions.Length - 1)
                    {
                        sdfObj = Object.Instantiate(sdfObj);
                    }
                }
            }

            worldGameObject.transform.position = new Vector3(-mdef.Middle.x * 640, 0, -mdef.Middle.y * 640);

            Object.FindObjectOfType <Light>().color = _cacheManager.Palette[176];
            UnityEngine.Camera.main.backgroundColor = _cacheManager.Palette[239];
            RenderSettings.fogColor     = _cacheManager.Palette[239];
            RenderSettings.ambientLight = _cacheManager.Palette[247];

            List <Car> cars = EntityManager.Instance.Cars;

            foreach (Car car in cars)
            {
                car.transform.parent = null;
            }

            if (mdef.FSM != null)
            {
                foreach (StackMachine machine in mdef.FSM.StackMachines)
                {
                    machine.Reset();
                    machine.Constants = new IntRef[machine.InitialArguments.Length];
                    for (int i = 0; i < machine.Constants.Length; i++)
                    {
                        int stackValue = machine.InitialArguments[i];
                        machine.Constants[i] = mdef.FSM.Constants[stackValue];
                    }
                }

                FSMRunner fsmRunner = FSMRunner.Instance;
                fsmRunner.FSM = mdef.FSM;
            }
        }
Ejemplo n.º 3
0
        public int DoAction(string actionName, StackMachine machine, FSMRunner fsmRunner)
        {
            global::System.Collections.Generic.Queue <IntRef> args = machine.ArgumentQueue;
            switch (actionName)
            {
            case "null":
                // Do nothing?
                break;

            case "true":
                return(1);

            case "inc":
            {
                IntRef arg = args.Dequeue();
                ++arg.Value;
            }
            break;

            case "dec":
            {
                IntRef arg = args.Dequeue();
                --arg.Value;
            }
            break;

            case "set":
            {
                IntRef arg = args.Dequeue();
                IntRef val = args.Dequeue();
                arg.Value = val.Value;
            }
            break;

            case "isGreater":
            {
                IntRef val    = args.Dequeue();
                IntRef number = args.Dequeue();

                bool greater = val.Value > number.Value;
                return(greater ? 1 : 0);
            }

            case "isLesser":
            {
                IntRef val    = args.Dequeue();
                IntRef number = args.Dequeue();

                bool lesser = val.Value < number.Value;
                return(lesser ? 1 : 0);
            }

            case "isEqual":
            {
                IntRef val    = args.Dequeue();
                IntRef number = args.Dequeue();

                bool equal = val.Value == number.Value;
                return(equal ? 1 : 0);
            }

            case "pushCam":
                CameraManager.Instance.PushCamera();
                break;

            case "popCam":
                CameraManager.Instance.PopCamera();
                break;

            case "timeGreater":
                IntRef timerNo = args.Dequeue();
                IntRef seconds = args.Dequeue();

                float secondsElapsed = Time.unscaledTime - fsmRunner.Timers[timerNo.Value];
                return(secondsElapsed >= seconds.Value ? 1 : 0);

            case "isKeypress":
                return(Input.GetKeyDown(KeyCode.Space) ? 1 : 0);

            case "camObjDir":
            {
                if (CameraManager.Instance.IsMainCameraActive)
                {
                    break;
                }

                var        camera      = CameraManager.Instance.ActiveCamera;
                IntRef     whichEntity = args.Dequeue();
                FSMEntity  origoEntity = fsmRunner.FSM.EntityTable[whichEntity.Value];
                GameObject entity      = origoEntity.Object;

                Vector3 relativePos = new Vector3(args.Dequeue().Value, args.Dequeue().Value, args.Dequeue().Value) / 100.0f;

                int yaw   = args.Dequeue().Value;
                int roll  = args.Dequeue().Value;
                int pitch = args.Dequeue().Value;

                Vector3 rotation = new Vector3(yaw, pitch, roll) / 100.0f;

                Vector3 newPos = entity.transform.position + (entity.transform.rotation * relativePos);

                if (newPos.y < entity.transform.position.y + 1)
                {
                    newPos.y = entity.transform.position.y + 1;
                }

                camera.transform.position = newPos;
                camera.transform.rotation = entity.transform.rotation * Quaternion.Euler(rotation);
            }
            break;

            case "camPosObj":
            {
                if (CameraManager.Instance.IsMainCameraActive)
                {
                    break;
                }

                var camera      = CameraManager.Instance.ActiveCamera;
                int pathIndex   = args.Dequeue().Value;
                int height      = args.Dequeue().Value;
                int watchTarget = args.Dequeue().Value;

                FSMPath path = fsmRunner.FSM.Paths[pathIndex];

                Vector3 nodePos = path.GetWorldPosition(0);
                nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height * 0.01f;
                camera.transform.position = nodePos;

                GameObject entity = fsmRunner.FSM.EntityTable[watchTarget].Object;
                camera.transform.LookAt(entity.transform, Vector3.up);
            }
            break;

            case "camObjObj":
            {
                if (CameraManager.Instance.IsMainCameraActive)
                {
                    break;
                }

                int   objectIndex = args.Dequeue().Value;
                float xPos        = args.Dequeue().Value;
                float yPos        = args.Dequeue().Value;
                float zPos        = args.Dequeue().Value;
                int   watchTarget = args.Dequeue().Value;

                FSMEntity anchorEntity = fsmRunner.FSM.EntityTable[objectIndex];
                FSMEntity targetEntity = fsmRunner.FSM.EntityTable[watchTarget];

                var camera = CameraManager.Instance.ActiveCamera;
                camera.transform.SetParent(anchorEntity.Object.transform);
                camera.transform.localPosition = new Vector3(xPos * 0.01f, zPos * 0.01f, yPos * 0.01f);
                camera.transform.LookAt(targetEntity.Object.transform, Vector3.up);
            }
            break;

            case "camTransObj":
            {
                if (CameraManager.Instance.IsMainCameraActive)
                {
                    break;
                }

                var   camera      = CameraManager.Instance.ActiveCamera;
                int   pathIndex   = args.Dequeue().Value;
                int   targetSpeed = args.Dequeue().Value;
                float height      = args.Dequeue().Value * 0.01f;

                FSMPath path = fsmRunner.FSM.Paths[pathIndex];

                if (args.Count == 0)
                {
                    Vector3 nodePos = path.GetWorldPosition(0);
                    nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height;
                    camera.transform.position = nodePos;
                    break;
                }

                int        watchTarget = args.Dequeue().Value;
                GameObject entity      = fsmRunner.FSM.EntityTable[watchTarget].Object;
                camera.transform.LookAt(entity.transform, Vector3.up);
                camera.SetTargetPath(path, targetSpeed, height);
            }
            break;

            case "camIsArrived":
            {
                if (CameraManager.Instance.IsMainCameraActive)
                {
                    break;
                }

                var camera = CameraManager.Instance.ActiveCamera;
                if (camera.Arrived)
                {
                    camera.Arrived = false;
                    return(1);
                }
                return(0);
            }

            case "goto":
            {
                int entityIndex = args.Dequeue().Value;
                int pathIndex   = args.Dequeue().Value;
                int targetSpeed = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];
                FSMPath   path   = fsmRunner.FSM.Paths[pathIndex];

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    car.SetTargetPath(path, targetSpeed);
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isWithinNav":
            {
                int pathIndex   = args.Dequeue().Value;
                int entityIndex = args.Dequeue().Value;
                int distance    = args.Dequeue().Value;

                FSMPath   path   = fsmRunner.FSM.Paths[pathIndex];
                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    bool within = car.IsWithinNav(path, distance);
                    return(within ? 1 : 0);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isWithinSqNav":
            {
                int pathIndex   = args.Dequeue().Value;
                int entityIndex = args.Dequeue().Value;
                int distance    = args.Dequeue().Value;

                FSMPath   path   = fsmRunner.FSM.Paths[pathIndex];
                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    bool within = car.IsWithinNav(path, (int)Mathf.Sqrt(distance));
                    return(within ? 1 : 0);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "follow":
            {
                int entityIndex = args.Dequeue().Value;
                int targetIndex = args.Dequeue().Value;
                int unk1        = args.Dequeue().Value;
                int unk2        = args.Dequeue().Value;
                int xOffset     = args.Dequeue().Value;
                int targetSpeed = args.Dequeue().Value;

                FSMEntity entity       = fsmRunner.FSM.EntityTable[entityIndex];
                FSMEntity targetEntity = fsmRunner.FSM.EntityTable[targetIndex];

                Car car       = entity.Object.GetComponent <Car>();
                Car targetCar = targetEntity.Object.GetComponent <Car>();
                if (car != null && targetCar != null)
                {
                    car.SetFollowTarget(targetCar, xOffset, targetSpeed);
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isAtFollow":
            {
                int       entityIndex = args.Dequeue().Value;
                FSMEntity entity      = fsmRunner.FSM.EntityTable[entityIndex];

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    bool atFollow = car.AtFollowTarget();
                    return(atFollow ? 1 : 0);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "teleport":
            {
                int entityIndex = args.Dequeue().Value;
                int pathIndex   = args.Dequeue().Value;
                int targetSpeed = args.Dequeue().Value;
                int height      = args.Dequeue().Value;

                FSMPath path = fsmRunner.FSM.Paths[pathIndex];

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];

                Vector3 nodePos = path.GetWorldPosition(0);
                nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height * 0.01f;
                entity.Object.transform.position = nodePos;

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    car.SetSpeed(targetSpeed);
                    car.SetTargetPath(path, targetSpeed);
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "teleportOffset":
            {
                int entityIndex = args.Dequeue().Value;
                int pathIndex   = args.Dequeue().Value;
                int targetSpeed = args.Dequeue().Value;
                int height      = args.Dequeue().Value;
                var offsetX     = args.Dequeue().Value;
                var offsetZ     = args.Dequeue().Value;

                FSMPath path = fsmRunner.FSM.Paths[pathIndex];

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];

                Vector3 nodePos = path.GetWorldPosition(0) + new Vector3(offsetX, 0, offsetZ);
                nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height * 0.01f;
                entity.Object.transform.position = nodePos;

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    car.SetSpeed(targetSpeed);
                    car.SetTargetPath(path, targetSpeed);
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isArrived":
            {
                int        entityIndex = args.Dequeue().Value;
                FSMEntity  origoEntity = fsmRunner.FSM.EntityTable[entityIndex];
                GameObject entity      = origoEntity.Object;

                Car car = entity.GetComponent <Car>();
                if (car != null)
                {
                    if (car.Arrived)
                    {
                        car.Arrived = false;
                        return(1);
                    }

                    return(0);
                }

                LogUnhandledEntity(actionName, entityIndex, origoEntity, machine);
            }
            break;

            case "sit":
            {
                int       entityIndex = args.Dequeue().Value;
                FSMEntity entity      = fsmRunner.FSM.EntityTable[entityIndex];

                Car car = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    car.Sit();
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "setAvoid":
            {
                int entityIndex = args.Dequeue().Value;
                int avoidIndex  = args.Dequeue().Value;

                FSMEntity entity      = fsmRunner.FSM.EntityTable[entityIndex];
                FSMEntity avoidEntity = fsmRunner.FSM.EntityTable[avoidIndex];

                Car         car    = entity.Object.GetComponent <Car>();
                WorldEntity target = avoidEntity.WorldEntity;
                if (car != null && target != null)
                {
                    // TODO: Figure out 'avoid' logic - don't path near object?
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "setMaxAttackers":
            {
                int entityIndex  = args.Dequeue().Value;
                int maxAttackers = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];

                if (entity.WorldEntity != null)
                {
                    entity.WorldEntity.MaxAttackers = maxAttackers;
                    break;
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "setSkill":
            {
                int entityIndex = args.Dequeue().Value;
                int skill1      = args.Dequeue().Value;
                int skill2      = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];
                Car       car    = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    car.Skill1 = skill1;
                    car.Skill2 = skill2;
                    return(0);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "setAgg":
            {
                int entityIndex     = args.Dequeue().Value;
                int aggressionValue = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];
                Car       car    = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    car.Aggressiveness = aggressionValue;
                    return(0);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isAttacked":
            {
                int entityIndex = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];
                Car       car    = entity.Object.GetComponent <Car>();
                if (car != null)
                {
                    return(car.Attacked ? 1 : 0);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isDead":
            {
                int entityIndex = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];
                if (entity.WorldEntity != null)
                {
                    return(entity.WorldEntity.Alive ? 0 : 1);
                }

                LogUnhandledEntity(actionName, entityIndex, entity, machine);
            }
            break;

            case "isWithin":
            {
                int entityIndex = args.Dequeue().Value;
                int targetIndex = args.Dequeue().Value;
                int distance    = args.Dequeue().Value;

                FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex];
                FSMEntity target = fsmRunner.FSM.EntityTable[targetIndex];

                bool within = Vector3.Distance(entity.Object.transform.position, target.Object.transform.position) < distance;
                return(within ? 1 : 0);
            }

            case "cbFromPrior":
            {
                int soundId   = args.Dequeue().Value;
                int owner     = args.Dequeue().Value;
                int queueFlag = args.Dequeue().Value;
                QueueRadio(fsmRunner, soundId, queueFlag, owner);
            }
            break;

            case "cbPrior":
            {
                int soundId   = args.Dequeue().Value;
                int queueFlag = args.Dequeue().Value;
                QueueRadio(fsmRunner, soundId, queueFlag, -1);
            }
            break;

            case "rand":
            {
                IntRef arg = args.Dequeue();
                IntRef val = args.Dequeue();
                arg.Value = Random.Range(0, val.Value);
            }
            break;

            case "stopCB":
                RadioManager.Instance.Stop();
                break;

            case "isCBEmpty":
            {
                return(RadioManager.Instance.IsQueueEmpty() ? 1 : 0);
            }

            case "startTimer":
                int timerIndex = args.Dequeue().Value;
                fsmRunner.Timers[timerIndex] = Time.unscaledTime;
                break;

            default:
                Debug.LogWarning("FSM action not implemented: " + actionName + " @ " + (machine.IP - 1));
                break;
            }

            return(0);
        }