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(); } } }
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); }
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)); } } }
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)); }
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); }
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)); }
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); } }
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]; } }
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); } } }
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); }
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); }