Exemple #1
0
        void ResetRoomObjects()
        {
            int j = 1;

            for (int i = 0; i < roomData.Objects.Count; i++)
            {
                for (; j < _objs.Length; j++)
                {
                    if (_objs[j].FloatingObjectIndex == 0)
                    {
                        break;
                    }
                }
                _objs[j] = roomData.Objects[i];
                // HACK: This is done since an angle doesn't fit into a byte (360 > 256)
                _objs[j].ActorDir = Game.Version == 8 ? (byte)ScummMath.ToSimpleDir(true, roomData.Objects[i].ActorDir) : roomData.Objects[i].ActorDir;
                j++;
            }
            for (int i = j; i < _objs.Length; i++)
            {
                if (_objs[i].FloatingObjectIndex == 0)
                {
                    _objs[i] = new ObjectData();
                }
            }
        }
Exemple #2
0
        internal byte WalkboxFindTarget(Actor a, int destbox, Point walkdest)
        {
            var actor = (Actor0)a;

            byte nextBox = (byte)GetNextBox(a.Walkbox, (byte)destbox);

            if (nextBox != 0xFF && nextBox == destbox && AreBoxesNeighbors(a.Walkbox, nextBox))
            {
                actor.NewWalkTo = walkdest;
                return(nextBox);
            }

            if (nextBox != 0xFF && nextBox != a.Walkbox)
            {
                Point p;
                ScummMath.GetClosestPtOnBox(GetBoxCoordinates(nextBox), a.Position, out p);
                actor.NewWalkTo = p;
            }
            else
            {
                if (walkdest.X == -1)
                {
                    actor.NewWalkTo = actor.CurrentWalkTo;
                }
                else
                {
                    actor.NewWalkTo = walkdest;
                }
            }
            return(nextBox);
        }
Exemple #3
0
        void AnimateActor(int anim)
        {
            int dir = -1;

            switch (anim)
            {
            case 0x00:
            case 0x04:
                dir = 0;
                break;

            case 0x01:
            case 0x05:
                dir = 1;
                break;

            case 0x02:
            case 0x06:
                dir = 2;
                break;

            case 0x03:
            case 0x07:
                dir = 3;
                break;
            }

            if (IsInCurrentRoom)
            {
                CostCommandNew = (byte)anim;
                _scumm.CostumeLoader.CostumeDecodeData(this, 0, 0);

                if (dir == -1)
                {
                    return;
                }

                Facing = (ushort)ScummMath.NormalizeAngle(ScummHelper.OldDirToNewDir(dir));
            }
            else
            {
                if (anim > 4 && anim <= 7)
                {
                    Facing = (ushort)ScummMath.NormalizeAngle(ScummHelper.OldDirToNewDir(dir));
                }
            }
        }
Exemple #4
0
        protected int GetObjActToObjActDist(int a, int b)
        {
            Actor acta = null;
            Actor actb = null;

            if (IsActor(a))
            {
                acta = Actors[ObjToActor(a)];
            }

            if (IsActor(b))
            {
                actb = Actors[ObjToActor(b)];
            }

            if ((acta != null) && (actb != null) && (acta.Room == actb.Room) && (acta.Room != 0) && !acta.IsInCurrentRoom)
            {
                return(0);
            }

            Point pA;

            if (!GetObjectOrActorXY(a, out pA))
            {
                return(0xFF);
            }

            Point pB;

            if (!GetObjectOrActorXY(b, out pB))
            {
                return(0xFF);
            }

            // Perform adjustXYToBeInBox() *only* if the first item is an
            // actor and the second is an object. This used to not check
            // whether the second item is a non-actor, which caused bug
            // #853874).
            if (acta != null && actb == null)
            {
                var r = acta.AdjustXYToBeInBox(pB);
                pB = r.Position;
            }

            // Now compute the distance between the two points
            return(ScummMath.GetDistance(pA, pB));
        }
Exemple #5
0
        public static uint GetClosestPtOnBox(BoxCoords box, Point pIn, out Point pOut)
        {
            Point tmp;
            uint  dist;
            uint  bestdist = 0xFFFFFF;

            pOut = new Point();

            tmp  = ScummMath.ClosestPtOnLine(box.UpperLeft, box.UpperRight, pIn);
            dist = pIn.SquareDistance(tmp);
            if (dist < bestdist)
            {
                bestdist = dist;
                pOut     = tmp;
            }

            tmp  = ScummMath.ClosestPtOnLine(box.UpperRight, box.LowerRight, pIn);
            dist = pIn.SquareDistance(tmp);
            if (dist < bestdist)
            {
                bestdist = dist;
                pOut     = tmp;
            }

            tmp  = ScummMath.ClosestPtOnLine(box.LowerRight, box.LowerLeft, pIn);
            dist = pIn.SquareDistance(tmp);
            if (dist < bestdist)
            {
                bestdist = dist;
                pOut     = tmp;
            }

            tmp  = ScummMath.ClosestPtOnLine(box.LowerLeft, box.UpperLeft, pIn);
            dist = pIn.SquareDistance(tmp);
            if (dist < bestdist)
            {
                bestdist = dist;
                pOut     = tmp;
            }

            return(bestdist);
        }
Exemple #6
0
        int GetDistanceBetween(bool isObj1, int b, int c, bool isObj2, int e, int f)
        {
            int   i, j;
            Point pos1;
            Point pos2;

            j = i = 0xFF;

            if (isObj1)
            {
                if (!GetObjectOrActorXY(b, out pos1))
                {
                    return(-1);
                }
                if (b < Actors.Length)
                {
                    i = Actors[b].ScaleX;
                }
            }
            else
            {
                pos1 = new Point(b, c);
            }

            if (isObj2)
            {
                if (!GetObjectOrActorXY(e, out pos2))
                {
                    return(-1);
                }
                if (e < Actors.Length)
                {
                    j = Actors[e].ScaleX;
                }
            }
            else
            {
                pos2 = new Point(e, f);
            }

            return(ScummMath.GetDistance(pos1, pos2) * 0xFF / ((i + j) / 2));
        }
Exemple #7
0
        void FindPathTowardsOld(byte box1, byte box2, byte finalBox, out Point p2, out Point p3)
        {
            var gateA = new Point[2];
            var gateB = new Point[2];

            p2 = new Point();
            p3 = new Point();

            GetGates(_scumm.GetBoxCoordinates(box1), _scumm.GetBoxCoordinates(box2), gateA, gateB);

            p2.X = 32000;
            p3.X = 32000;

            // TODO:
            // next box (box2) = final box?
//            if (box2 == finalBox)
//            {
//                // In Indy3, the masks (= z-level) have to match, too -- needed for the
//                // 'maze' in the zeppelin (see bug #1032964).
            //                if (_scumm.Game.Id != GID_INDY3 || _vm->getMaskFromBox(box1) == _vm->getMaskFromBox(box2))
//                {
//                    // Is the actor (x,y) between both gates?
//                    if (compareSlope(_pos, _walkdata.dest, gateA[0]) !=
//                        compareSlope(_pos, _walkdata.dest, gateB[0]) &&
//                        compareSlope(_pos, _walkdata.dest, gateA[1]) !=
//                        compareSlope(_pos, _walkdata.dest, gateB[1]))
//                    {
//                        return;
//                    }
//                }
//            }

            p3 = ScummMath.ClosestPtOnLine(gateA[1], gateB[1], Position);

            if (ScummMath.CompareSlope(Position, p3, gateA[0]) == ScummMath.CompareSlope(Position, p3, gateB[0]))
            {
                p2 = ScummMath.ClosestPtOnLine(gateA[0], gateB[0], Position);
            }
        }
Exemple #8
0
        void GetGates(BoxCoords box1, BoxCoords box2, Point[] gateA, Point[] gateB)
        {
            int i, j;
            var dist = new int[8];
            var minDist = new int[3];
            var closest = new int[3];
            var box = new bool[3];
            var closestPoint = new Point[8];
            var boxCorner = new Point[8];
            int line1, line2;

            // For all corner coordinates of the first box, compute the point closest
            // to them on the second box (and also compute the distance of these points).
            boxCorner[0] = box1.UpperLeft;
            boxCorner[1] = box1.UpperRight;
            boxCorner[2] = box1.LowerRight;
            boxCorner[3] = box1.LowerLeft;
            for (i = 0; i < 4; i++)
            {
                dist[i] = (int)ScummMath.GetClosestPtOnBox(box2, boxCorner[i], out closestPoint[i]);
            }

            // Now do the same but with the roles of the first and second box swapped.
            boxCorner[4] = box2.UpperLeft;
            boxCorner[5] = box2.UpperRight;
            boxCorner[6] = box2.LowerRight;
            boxCorner[7] = box2.LowerLeft;
            for (i = 4; i < 8; i++)
            {
                dist[i] = (int)ScummMath.GetClosestPtOnBox(box1, boxCorner[i], out closestPoint[i]);
            }

            // Find the three closest "close" points between the two boxes.
            for (j = 0; j < 3; j++)
            {
                minDist[j] = 0xFFFF;
                for (i = 0; i < 8; i++)
                {
                    if (dist[i] < minDist[j])
                    {
                        minDist[j] = dist[i];
                        closest[j] = i;
                    }
                }
                dist[closest[j]] = 0xFFFF;
                minDist[j]       = (int)Math.Sqrt(minDist[j]);
                box[j]           = (closest[j] > 3); // Is the point on the first or on the second box?
            }


            // Finally, compute the actual "gate".

            if (box[0] == box[1] && Math.Abs(minDist[0] - minDist[1]) < 4)
            {
                line1 = closest[0];
                line2 = closest[1];
            }
            else if (box[0] == box[1] && minDist[0] == minDist[1])
            {  // parallel
                line1 = closest[0];
                line2 = closest[1];
            }
            else if (box[0] == box[2] && minDist[0] == minDist[2])
            {  // parallel
                line1 = closest[0];
                line2 = closest[2];
            }
            else if (box[1] == box[2] && minDist[1] == minDist[2])
            {  // parallel
                line1 = closest[1];
                line2 = closest[2];
            }
            else if (box[0] == box[2] && Math.Abs(minDist[0] - minDist[2]) < 4)
            {
                line1 = closest[0];
                line2 = closest[2];
            }
            else if (Math.Abs(minDist[0] - minDist[2]) < 4)
            {
                line1 = closest[1];
                line2 = closest[2];
            }
            else if (Math.Abs(minDist[0] - minDist[1]) < 4)
            {
                line1 = closest[0];
                line2 = closest[1];
            }
            else
            {
                line1 = closest[0];
                line2 = closest[0];
            }

            // Set the gate
            if (line1 < 4)
            {
                gateA[0] = boxCorner[line1];
                gateA[1] = closestPoint[line1];
            }
            else
            {
                gateA[1] = boxCorner[line1];
                gateA[0] = closestPoint[line1];
            }

            if (line2 < 4)
            {
                gateB[0] = boxCorner[line2];
                gateB[1] = closestPoint[line2];
            }
            else
            {
                gateB[1] = boxCorner[line2];
                gateB[0] = closestPoint[line2];
            }
        }
Exemple #9
0
        public override void Walk()
        {
            Point foundPath, tmp;
            int   new_dir, next_box;

            if (Moving.HasFlag(MoveFlags.Turn))
            {
                new_dir = UpdateActorDirection(false);
                if (Facing != new_dir)
                {
                    SetDirection(new_dir);
                }
                else
                {
                    Moving = MoveFlags.None;
                }
                return;
            }

            if (Moving == MoveFlags.None)
            {
                return;
            }

            if (Moving.HasFlag(MoveFlags.InLeg))
            {
                ActorWalkStep();
            }
            else
            {
                if (Moving.HasFlag(MoveFlags.LastLeg))
                {
                    Moving = MoveFlags.None;
                    StartAnimActor(StandFrame);
                    if (_targetFacing != _walkdata.DestDir)
                    {
                        TurnToDirection(_walkdata.DestDir);
                    }
                }
                else
                {
                    SetBox(_walkdata.CurBox);
                    if (Walkbox == _walkdata.DestBox)
                    {
                        foundPath = _walkdata.Dest;
                        Moving   |= MoveFlags.LastLeg;
                    }
                    else
                    {
                        next_box = _scumm.GetNextBox(Walkbox, _walkdata.DestBox);
                        if (next_box < 0)
                        {
                            Moving |= MoveFlags.LastLeg;
                            return;
                        }

                        // Can't walk through locked boxes
                        var flags = _scumm.GetBoxFlags((byte)next_box);
                        if ((flags.HasFlag(BoxFlags.Locked)) && !((flags.HasFlag(BoxFlags.PlayerOnly) && !IsPlayer)))
                        {
                            Moving |= MoveFlags.LastLeg;
                            //_walkdata.destdir = -1;
                        }

                        _walkdata.CurBox = (byte)next_box;

                        ScummMath.GetClosestPtOnBox(_scumm.GetBoxCoordinates(_walkdata.CurBox), RealPosition, out tmp);
                        ScummMath.GetClosestPtOnBox(_scumm.GetBoxCoordinates(Walkbox), tmp, out foundPath);
                    }
                    CalcMovementFactor(foundPath);
                }
            }
        }
Exemple #10
0
        internal bool CheckXYInBoxBounds(int boxnum, Point p)
        {
            // Since this method is called by many other methods that take params
            // from e.g. script opcodes, but do not validate the boxnum, we
            // make a check here to filter out invalid boxes.
            // See also bug #1599113.
            if (boxnum < 0 || boxnum == InvalidBox)
            {
                return(false);
            }

            var box = GetBoxCoordinates(boxnum);

            // Quick check: If the x (resp. y) coordinate of the point is
            // strictly smaller (bigger) than the x (y) coordinates of all
            // corners of the quadrangle, then it certainly is *not* contained
            // inside the quadrangle.
            if (p.X < box.UpperLeft.X && p.X < box.UpperRight.X && p.X < box.LowerRight.X && p.X < box.LowerLeft.X)
            {
                return(false);
            }

            if (p.X > box.UpperLeft.X && p.X > box.UpperRight.X && p.X > box.LowerRight.X && p.X > box.LowerLeft.X)
            {
                return(false);
            }

            if (p.Y < box.UpperLeft.Y && p.Y < box.UpperRight.Y && p.Y < box.LowerRight.Y && p.Y < box.LowerLeft.Y)
            {
                return(false);
            }

            if (p.Y > box.UpperLeft.Y && p.Y > box.UpperRight.Y && p.Y > box.LowerRight.Y && p.Y > box.LowerLeft.Y)
            {
                return(false);
            }

            // Corner case: If the box is a simple line segment, we consider the
            // point to be contained "in" (or rather, lying on) the line if it
            // is very close to its projection to the line segment.
            if ((box.UpperLeft == box.UpperRight && box.LowerRight == box.LowerLeft) ||
                (box.UpperLeft == box.LowerLeft && box.UpperRight == box.LowerRight))
            {
                Point tmp;
                tmp = ScummMath.ClosestPtOnLine(box.UpperLeft, box.LowerRight, p);
                if (p.SquareDistance(tmp) <= 4)
                {
                    return(true);
                }
            }

            // Finally, fall back to the classic algorithm to compute containment
            // in a convex polygon: For each (oriented) side of the polygon
            // (quadrangle in this case), compute whether p is "left" or "right"
            // from it.

            if (!ScummMath.CompareSlope(box.UpperLeft, box.UpperRight, p))
            {
                return(false);
            }

            if (!ScummMath.CompareSlope(box.UpperRight, box.LowerRight, p))
            {
                return(false);
            }

            if (!ScummMath.CompareSlope(box.LowerRight, box.LowerLeft, p))
            {
                return(false);
            }

            if (!ScummMath.CompareSlope(box.LowerLeft, box.UpperLeft, p))
            {
                return(false);
            }

            return(true);
        }
Exemple #11
0
        public override void Walk()
        {
            var cmd = WalkCommand.None;

            ActorSetWalkTo();

            NeedRedraw = true;
            do
            {
                switch (cmd)
                {
                case WalkCommand.None:
                {
                    if (NewWalkTo != CurrentWalkTo)
                    {
                        CurrentWalkTo = NewWalkTo;
                        cmd           = WalkCommand.L2A33;
                    }
                    else
                    {
                        cmd = WalkCommand._2A0A;
                    }
                }
                break;

                case WalkCommand._2A0A:
                {
                    if ((Moving & (MoveFlags)0x7F) != MoveFlags.NewLeg)
                    {
                        if (NewWalkTo == RealPosition)
                        {
                            return;
                        }
                    }
                    cmd = WalkCommand._2A9A;
                }
                break;

                case WalkCommand.L2A33:
                {
                    Moving   &= (MoveFlags)0xF0;
                    _tmp_Dest = RealPosition;

                    var tmp = CalcWalkDistances() ? 1 : 0;
                    Moving &= (MoveFlags)0xF0;
                    Moving |= (MoveFlags)tmp;

                    if (_walkYCountGreaterThanXCount == 0)
                    {
                        if (_walkDirX != 0)
                        {
                            _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * 1, Actor2.V12_Y_MULTIPLIER * 0, false);
                        }
                        else
                        {
                            _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * -1, Actor2.V12_Y_MULTIPLIER * 0, false);
                        }
                    }
                    else
                    {
                        if (_walkDirY != 0)
                        {
                            _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * 0, Actor2.V12_Y_MULTIPLIER * 1, false);
                        }
                        else
                        {
                            _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * 0, Actor2.V12_Y_MULTIPLIER * -1, false);
                        }
                    }

                    DirectionUpdate();

                    if ((Moving & MoveFlags.Frozen) != 0)
                    {
                        return;
                    }

                    AnimateActor(ScummHelper.NewDirToOldDir(Facing));

                    cmd = WalkCommand._2A9A;
                }
                break;

                case WalkCommand._2A9A:
                {
                    if (Moving == MoveFlags.InLeg)
                    {
                        return;
                    }

                    if ((Moving & (MoveFlags)0x0F) == MoveFlags.NewLeg)
                    {
                        StopActorMoving();
                        return;
                    }

                    // 2AAD
                    if (Moving.HasFlag(MoveFlags.Frozen))
                    {
                        DirectionUpdate();

                        if (Moving.HasFlag(MoveFlags.Frozen))
                        {
                            return;
                        }

                        AnimateActor(ScummHelper.NewDirToOldDir(Facing));
                    }

                    if ((Moving & (MoveFlags)0x0F) == (MoveFlags)3)
                    {
                        cmd = WalkCommand.L2C36;
                        break;
                    }

                    // 2ADA
                    if ((Moving & (MoveFlags)0x0F) == MoveFlags.Turn)
                    {
                        cmd = WalkCommand.L2CA3;
                        break;
                    }

                    if ((Moving & (MoveFlags)0x0F) == 0)
                    {
                        // 2AE8
                        byte A = ActorWalkX();

                        if (A == 1)
                        {
                            A = ActorWalkY();
                            if (A == 1)
                            {
                                Moving &= (MoveFlags)0xF0;
                                Moving |= (MoveFlags)A;
                            }
                            else
                            {
                                if (A == 4)
                                {
                                    StopActorMoving();
                                }
                            }

                            return;
                        }
                        else
                        {
                            // 2B0C
                            if (A == 3)
                            {
                                Moving &= (MoveFlags)0xF0;
                                Moving |= (MoveFlags)A;

                                if (_walkDirY != 0)
                                {
                                    _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * 0, Actor2.V12_Y_MULTIPLIER * 1, false);
                                }
                                else
                                {
                                    _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * 0, Actor2.V12_Y_MULTIPLIER * -1, false);
                                }

                                DirectionUpdate();
                                AnimateActor(ScummHelper.NewDirToOldDir(Facing));
                                cmd = WalkCommand.L2C36;
                                break;
                            }
                            else
                            {
                                // 2B39
                                A = ActorWalkY();
                                if (A != 4)
                                {
                                    return;
                                }

                                Moving &= (MoveFlags)0xF0;
                                Moving |= (MoveFlags)A;

                                if (_walkDirX != 0)
                                {
                                    _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * 1, Actor2.V12_Y_MULTIPLIER * 0, false);
                                }
                                else
                                {
                                    _targetFacing = (ushort)ScummMath.GetAngleFromPos(Actor2.V12_X_MULTIPLIER * -1, Actor2.V12_Y_MULTIPLIER * 0, false);
                                }

                                DirectionUpdate();
                                AnimateActor(ScummHelper.NewDirToOldDir(Facing));
                                cmd = WalkCommand.L2CA3;
                            }
                        }
                    }
                }
                break;

                case WalkCommand.L2C36:
                {
                    SetTmpFromActor();
                    if (_walkDirX == 0)
                    {
                        RealPosition = new Point(RealPosition.X - 1, RealPosition.Y);
                    }
                    else
                    {
                        RealPosition = new Point(RealPosition.X + 1, RealPosition.Y);
                    }

                    // 2C51
                    if (UpdateWalkbox() != InvalidBox)
                    {
                        SetActorFromTmp();
                        cmd = WalkCommand.L2A33;
                        break;
                    }

                    SetActorFromTmp();

                    if (CurrentWalkTo.Y == _tmp_Dest.Y)
                    {
                        StopActorMoving();
                        return;
                    }

                    if (_walkDirY == 0)
                    {
                        _tmp_Dest = new Point(_tmp_Dest.X, _tmp_Dest.Y - 1);
                    }
                    else
                    {
                        _tmp_Dest = new Point(_tmp_Dest.X, _tmp_Dest.Y + 1);
                    }

                    SetTmpFromActor();

                    byte A = (byte)UpdateWalkbox();
                    if (A == 0xFF)
                    {
                        SetActorFromTmp();
                        StopActorMoving();
                        return;
                    }
                    // 2C98: Yes, an exact copy of what just occured.. the original does this, so im doing it...
                    //       Just to keep me sane when going over it :)
                    if (A == 0xFF)
                    {
                        SetActorFromTmp();
                        StopActorMoving();
                        return;
                    }
                }
                    return;

                case WalkCommand.L2CA3:
                    SetTmpFromActor();
                    if (_walkDirY == 0)
                    {
                        RealPosition = new Point(RealPosition.X, RealPosition.Y - 1);
                    }
                    else
                    {
                        RealPosition = new Point(RealPosition.X, RealPosition.Y + 1);
                    }

                    if (UpdateWalkbox() == InvalidBox)
                    {
                        // 2CC7
                        SetActorFromTmp();
                        if (CurrentWalkTo.X == _tmp_Dest.X)
                        {
                            StopActorMoving();
                            return;
                        }

                        if (_walkDirX == 0)
                        {
                            _tmp_Dest = new Point(_tmp_Dest.X - 1, _tmp_Dest.Y);
                        }
                        else
                        {
                            _tmp_Dest = new Point(_tmp_Dest.X + 1, _tmp_Dest.Y);
                        }
                        SetTmpFromActor();

                        if (UpdateWalkbox() == InvalidBox)
                        {
                            SetActorFromTmp();
                            StopActorMoving();
                        }
                        return;
                    }
                    else
                    {
                        SetActorFromTmp();
                        cmd = WalkCommand.L2A33;
                    }
                    break;
                }
            } while(cmd != WalkCommand.None);
        }