public int MarioFunction(SuperObject *spo, int *nodeInterp)
        {
            RaymanState state          = RaymanState.Inactive;
            byte        dsgVar16_value = 0;
            int *       idleTimer      = null;

            if (spo->PersoData->GetModelName(w) == "YLT_RaymanModel")
            {
                var dsgVars = spo->PersoData->GetDsgVarList();
                dsgVar16_value = *(byte *)dsgVars[16].valuePtrCurrent.ToPointer();
                byte dsgVar9_value = *(byte *)dsgVars[9].valuePtrCurrent.ToPointer();
                state     = (RaymanState)dsgVar9_value;
                idleTimer = (int *)dsgVars[24].valuePtrCurrent;
            }

            bool strafing = InputStructure.GetInputStructure()->GetEntryAction(EntryActionNames.Action_Strafe)->IsValidated();

            if (spo->PersoData->GetInstanceName(w) != "Rayman" || dsgVar16_value != 1 || !AllowTankControlState(state))
            {
                currentSpeed = 0;

                return(EngineFunctions.fn_p_stReadAnalogJoystickMario.Call(spo, nodeInterp));
            }

            int result = OriginalScript(spo, nodeInterp);

            DoTankControls(spo, state, strafing, idleTimer);

            return(result);
        }
 private bool AllowTankControlState(RaymanState state)
 {
     return(state == RaymanState.Idle ||
            state == RaymanState.Walking ||
            state == RaymanState.Running ||
            state == RaymanState.Strafing ||
            state == RaymanState.StrafingAndTargeting ||
            state == RaymanState.Helicoptering ||
            state == RaymanState.SuperHelicoptering ||
            state == RaymanState.JumpingUp ||
            state == RaymanState.FallingDown ||
            state == RaymanState.LedgeGrab ||
            state == RaymanState.CeilingClimbing ||
            state == RaymanState.CarryingObject ||
            state == RaymanState.ThrowingObject ||
            state == RaymanState.Swimming ||
            state == RaymanState.Sliding);
 }
        private void DoTankControls(SuperObject *spo, RaymanState state, bool strafing, int *idleTimer)
        {
            EntryAction *leftAction    = *(EntryAction **)0x4B9B90;
            EntryAction *rightAction   = *(EntryAction **)0x4B9B94;
            EntryAction *forwardAction = *(EntryAction **)0x4B9B88;
            EntryAction *backAction    = *(EntryAction **)0x4B9B8C;
            EntryAction *shiftAction   = *(EntryAction **)0x4B9B98;

            rayman = spo;
            var transformationMatrix = rayman->PersoData->dynam->DynamicsAsBigDynamics->matrixA.TransformationMatrix;
            var rotation             = Quaternion.CreateFromRotationMatrix(transformationMatrix);

            float rotationSpeedTarget = ((leftAction->IsValidated() ? 1f : 0) + (rightAction->IsValidated() ? -1f : 0)) * maxRotationSpeed * (shiftAction->IsValidated()?0.75f:1f);

            if (state == RaymanState.Swimming || state == RaymanState.Sliding)
            {
                rotationSpeedTarget *= 8.0f;
            }

            // Interpolate to target speed
            rotationSpeed += (rotationSpeedTarget - rotationSpeed) * rotationSpeedLerp;

            if (state == RaymanState.LedgeGrab)
            {
                if (forwardAction->IsValidated())
                {
                    currentSpeed = 10;
                }
                else if (backAction->IsValidated())
                {
                    currentSpeed = -10;
                }
                else
                {
                    currentSpeed = 0;
                }
            }
            else if (strafing && state != RaymanState.Swimming && state != RaymanState.Sliding)
            {
                float strafeX = ((leftAction->IsValidated() ? 1f : 0) + (rightAction->IsValidated() ? -1f : 0));
                float strafeY = ((forwardAction->IsValidated() ? 1f : 0) + (backAction->IsValidated() ? -1f : 0));

                float strafeMagnitude = (float)Math.Sqrt(strafeX * strafeX + strafeY * strafeY);

                if (strafeMagnitude == 0 || float.IsNaN(strafeMagnitude) || float.IsInfinity(strafeMagnitude))
                {
                    strafeMagnitude = 1.0f;
                }

                // Normalize and set length to 100
                strafeX *= 100.0f / strafeMagnitude;
                strafeY *= 100.0f / strafeMagnitude;

                HandleStrafing(rotation, rayman, strafeX, strafeY);

                return;
            }
            else
            {
                // Can be turning?
                if (state == RaymanState.Idle)
                {
                    var entryActions = InputStructure.GetInputStructure()->EntryActions;

                    int[] bannedActions = new int[] { (int)EntryActionNames.Action_Tirer, (int)EntryActionNames.Action_Sauter };

                    bool usingBannedAction = bannedActions.Where(a => entryActions[a]->IsValidated()).Count() > 0;

                    if (!usingBannedAction)
                    {
                        if (rightAction->IsValidated() && !leftAction->IsValidated())
                        {
                            if (rayman->PersoData->GetStateIndex() != 70)
                            {
                                rayman->PersoData->SetState(70);
                            }
                            playTurnAnimation = true;
                        }
                        else if (leftAction->IsValidated() && !rightAction->IsValidated())
                        {
                            if (rayman->PersoData->GetStateIndex() != 71)
                            {
                                rayman->PersoData->SetState(71);
                            }
                            playTurnAnimation = true;
                        }
                        else
                        {
                            playTurnAnimation = false;
                        }
                    }
                }

                rotation *= Quaternion.CreateFromYawPitchRoll(0, 0, rotationSpeed); // Add rotation

                float targetSpeed = (forwardAction->IsValidated() ? 100f : 0f) * (shiftAction->IsValidated() ? 0.5f : 1f);
                currentSpeed += (targetSpeed - currentSpeed) * 0.1f;
            }

            if (currentSpeed > 0 && currentSpeed < 0.5f)
            {
                currentSpeed = 0;
            }

            if (currentSpeed < 70 && Math.Abs(rotationSpeed) > 0.01f && state == RaymanState.Sliding)
            {
                currentSpeed = 70;
            }

            WriteVariables(rotation, rotationSpeed, transformationMatrix, rayman);
        }