/** * Sort some stuff out at actor start-up time. */ static void InitialPathChecks(PMOVER pMover, int xpos, int ypos) { HPOLYGON hPath; int node; int z; pMover->objX = xpos; pMover->objY = ypos; /*-------------------------------------- | If Actor is in a follow nodes path, | | position it at the nearest node. | --------------------------------------*/ hPath = InPolygon(xpos, ypos, PATH); if (hPath != NOPOLY) { pMover->hCpath = hPath; if (PolySubtype(hPath) == NODE) { node = NearestNodeWithin(hPath, xpos, ypos); getNpathNode(hPath, node, &pMover->objX, &pMover->objY); pMover->hFnpath = hPath; pMover->line = node; pMover->npstatus = GOING_UP; } z = GetScale(hPath, pMover->objY); } else { pMover->bNoPath = true; z = GetScale(FirstPathPoly(), pMover->objY); } SetMoverWalkReel(pMover, FORWARD, z, false); }
/** * Run appropriate actor or polygon glitter code. * If none, and it's a WALKTO event, do a walk. */ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, PLR_EVENT be = PLR_NOEVENT) { int actor; int aniX, aniY; HPOLYGON hPoly; // Prevent activation of 2 events on the same tick if (++g_eCount != 1) return; if ((actor = GetTaggedActor()) != 0) { // Event for a tagged actor if (TinselV2) ActorEvent(Common::nullContext, actor, uEvent, false, 0); else ActorEvent(actor, uEvent, be); } else if ((hPoly = GetTaggedPoly()) != NOPOLY) { // Event for active tagged polygon if (!TinselV2) RunPolyTinselCode(hPoly, uEvent, be, false); else if (uEvent != PROV_WALKTO) PolygonEvent(Common::nullContext, hPoly, uEvent, 0, false, 0); } else { GetCursorXY(&aniX, &aniY, true); // There could be a poly involved which has no tag. if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY || (!TinselV2 && ((hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY))) { if (TinselV2 && (uEvent != PROV_WALKTO)) PolygonEvent(Common::nullContext, hPoly, uEvent, 0, false, 0); else if (!TinselV2) RunPolyTinselCode(hPoly, uEvent, be, false); } else if ((uEvent == PROV_WALKTO) || (uEvent == WALKTO)) { if (TinselV2) ProcessedProvisional(); WalkTo(aniX, aniY); } } }
void Race::HandlePlayerOnPlayerCollisions(){ for (unsigned i=0; i<Player.size()-1;i++) { for (unsigned j=i+1; j<Player.size();j++) { if (Player[i].DeathSwitch==1 || Player[j].DeathSwitch==1) continue; bool StillCorrecting=1; unsigned Attempts=0; while (StillCorrecting){ StillCorrecting=0; vector<Vector2d> Bounding1=Player[i].Bounding; for (unsigned k=0; k<Bounding1.size();k++) { Bounding1[k]=RotateVector(Bounding1[k],Player[i].Rotation); Bounding1[k]+=Player[i].Position; } vector<Vector2d> Bounding2=Player[j].Bounding; for (unsigned k=0; k<Bounding2.size();k++) { Bounding2[k]=RotateVector(Bounding2[k],Player[j].Rotation); Bounding2[k]+=Player[j].Position; } bool CornerPoly=0; Vector2u CornerSide=Vector2u(); Vector2d Direction=Vector2d(); double Overlap=0; bool DoubleFlag=0; if(InPolygon(Bounding1, Bounding2, CornerPoly, CornerSide, Direction,Overlap,DoubleFlag)) { vector<vector<Vector2d>> Bounding={Bounding1,Bounding2}; Vector2d CollisionPos=Bounding[CornerPoly][CornerSide.x]; HandleSinglePlayerCollision({&Player[i],&Player[j]},Bounding, CornerPoly,CollisionPos,Direction,Overlap,DoubleFlag,Attempts); Attempts++; StillCorrecting=1; } if(Attempts>=5) { //Player[i].DeathSwitch=1; StillCorrecting=0; } } } } }
/** * Reposition a moving actor. */ void PositionMover(PMOVER pMover, int x, int y) { int z; int node; HPOLYGON hPath; assert(pMover); // Moving null moving actor assert(pMover->actorObj); pMover->objX = x; pMover->objY = y; MultiSetAniXY(pMover->actorObj, x, y); hPath = InPolygon(x, y, PATH); if (hPath != NOPOLY) { pMover->hCpath = hPath; if (PolySubtype(hPath) == NODE) { node = NearestNodeWithin(hPath, x, y); getNpathNode(hPath, node, &pMover->objX, &pMover->objY); pMover->hFnpath = hPath; pMover->line = node; pMover->npstatus = GOING_UP; } else { pMover->hFnpath = NOPOLY; pMover->npstatus = NOT_IN; } z = GetScale(hPath, pMover->objY); pMover->scale = z; SetMoverStanding(pMover); } else { pMover->bNoPath = true; pMover->hFnpath = NOPOLY; // Ain't in one pMover->npstatus = NOT_IN; // Ensure legal reel and scale if (pMover->direction < 0 || pMover->direction > 3) pMover->direction = FORWARD; if (pMover->scale < 0 || pMover->scale > TOTAL_SCALES) pMover->scale = 1; } }
/** * Called from scroll process - Scrolls the image as appropriate. */ static void ScrollImage() { int OldLoffset = 0, OldToffset = 0; // Used when keeping cursor on a tag int Loffset, Toffset; int curX, curY; // get background offsets PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); /* * Keeping cursor on a tag? */ if (g_ScrollCursor) { GetCursorXYNoWait(&curX, &curY, true); if (InPolygon(curX, curY, TAG) != NOPOLY || InPolygon(curX, curY, EXIT) != NOPOLY) { OldLoffset = Loffset; OldToffset = Toffset; } else g_ScrollCursor = false; } /* * Horizontal scrolling */ if (g_LeftScroll > 0) { g_LeftScroll -= g_scrollPixelsX; if (g_LeftScroll < 0) { Loffset += g_LeftScroll; g_LeftScroll = 0; } Loffset += g_scrollPixelsX; // Move right if (Loffset > g_ImageW - SCREEN_WIDTH) Loffset = g_ImageW - SCREEN_WIDTH;// Now at extreme right /*** New feature to prop up rickety scroll boundaries ***/ if (TinselV2 && SysVar(SV_MaximumXoffset) && (Loffset > SysVar(SV_MaximumXoffset))) Loffset = SysVar(SV_MaximumXoffset); } else if (g_LeftScroll < 0) { g_LeftScroll += g_scrollPixelsX; if (g_LeftScroll > 0) { Loffset += g_LeftScroll; g_LeftScroll = 0; } Loffset -= g_scrollPixelsX; // Move left if (Loffset < 0) Loffset = 0; // Now at extreme left /*** New feature to prop up rickety scroll boundaries ***/ if (TinselV2 && SysVar(SV_MinimumXoffset) && (Loffset < SysVar(SV_MinimumXoffset))) Loffset = SysVar(SV_MinimumXoffset); } /* * Vertical scrolling */ if (g_DownScroll > 0) { g_DownScroll -= g_scrollPixelsY; if (g_DownScroll < 0) { Toffset += g_DownScroll; g_DownScroll = 0; } Toffset += g_scrollPixelsY; // Move down if (Toffset > g_ImageH - SCREEN_HEIGHT) Toffset = g_ImageH - SCREEN_HEIGHT;// Now at extreme bottom /*** New feature to prop up rickety scroll boundaries ***/ if (TinselV2 && SysVar(SV_MaximumYoffset) && Toffset > SysVar(SV_MaximumYoffset)) Toffset = SysVar(SV_MaximumYoffset); } else if (g_DownScroll < 0) { g_DownScroll += g_scrollPixelsY; if (g_DownScroll > 0) { Toffset += g_DownScroll; g_DownScroll = 0; } Toffset -= g_scrollPixelsY; // Move up if (Toffset < 0) Toffset = 0; // Now at extreme top /*** New feature to prop up rickety scroll boundaries ***/ if (TinselV2 && SysVar(SV_MinimumYoffset) && Toffset < SysVar(SV_MinimumYoffset)) Toffset = SysVar(SV_MinimumYoffset); } /* * Move cursor if keeping cursor on a tag. */ if (g_ScrollCursor) AdjustCursorXY(OldLoffset - Loffset, OldToffset - Toffset); PlayfieldSetPos(FIELD_WORLD, Loffset, Toffset); }
Vector2u Race::getNearestValidSquare(unsigned PlayerNumber){ Vector2u Dim=track.getDim(); vector<double> norm(Dim.x*Dim.y,0); Vector2d Position=Player[PlayerNumber].PositionBeforeDeath; for (unsigned k=0; k<Dim.x*Dim.y;++k) { unsigned k1= k % Dim.x; unsigned k2= k / Dim.x; norm[k]=sqrt(pow(k1+0.5-Position.x,2)+pow(k2+0.5-Position.y,2)); } vector<int> index(norm.size(), 0); for (unsigned i = 0 ; i != index.size() ; i++) { index[i] = i; } sort(index.begin(), index.end(),[&](const int& a, const int& b) {return (norm[a] < norm[b]);}); unsigned j=0; bool SquareValid=false; bool CarCollision=false; vector<PROPERTIES> InvalidTiles={FALL,WALL}; while (SquareValid==false || CarCollision==true) { CarCollision=false; SquareValid=true; unsigned k1=index[j]%Dim.x; unsigned k2=index[j]/Dim.x; Tile* CurrentTile=track.getTile(k1,k2); Detect Detection=CurrentTile->Detection; for (unsigned i=0; i<InvalidTiles.size(); i++) { if (Detection.x.count(InvalidTiles[i])==1) { SquareValid=0; } } if(CurrentTile->isSquare==0) { SquareValid=0; } Player[PlayerNumber].Position=Vector2d(k1+0.5, k2+0.5); for (unsigned i=0; i< Player.size();++i) { Car *Car1,*Car2; if(i==PlayerNumber) { continue; } Car1=&Player[PlayerNumber]; Car2=&Player[i]; vector<Vector2d> Bounding1=Car1->Bounding; for (unsigned k=0; k<Bounding1.size();k++) { Bounding1[k]=RotateVector(Bounding1[k],Player[PlayerNumber].Rotation); Bounding1[k]+=Player[PlayerNumber].Position; } Vector2d Center1=accumulate(Bounding1.begin(),Bounding1.end(),Vector2d(0,0))/static_cast<double>(Bounding1.size()); vector<Vector2d> Bounding2=Car2->Bounding; for (unsigned k=0; k<Bounding2.size();k++) { Bounding2[k]=RotateVector(Bounding2[k],Player[i].Rotation); Bounding2[k]+=Player[i].Position; } Vector2d Center2=accumulate(Bounding2.begin(),Bounding2.end(),Vector2d(0,0))/static_cast<double>(Bounding2.size()); if( InPolygon(Bounding1,Bounding2) || InPolygon(Center1,Bounding2) || InPolygon(Center2,Bounding1) ) { CarCollision=1; } } j++; if (j==Dim.x*Dim.y) { cerr<<"Failed to Find Valid Square!!"<<endl; } } return Vector2u(index[j-1]%Dim.x,index[j-1]/Dim.x); }
void Race::HandleWallCollisions(){ int trackwidth=track.getDim().x, trackheight=track.getDim().y; for (unsigned i=0; i<Player.size();i++) { bool StillCorrecting=1; unsigned Attempts=0; while (StillCorrecting){ StillCorrecting=0; vector<Vector2d> Bounding=Player[i].Bounding; for (unsigned j=0; j<4;j++) { Bounding[j]=RotateVector(Bounding[j],Player[i].Rotation); Bounding[j]+=Player[i].Position; } Vector2u CurrentSquare=Player[i].getGridPosition(); for (int j=0; j<9;j++) { bool TestCollision=0; vector<Vector2d> BoundingTile; int index1=(j%3)-1, index2=(j/3)-1; index1+=CurrentSquare.x; index2+=CurrentSquare.y; if (index1>=0 && index1<trackwidth && index2>=0 && index2<trackheight) { Tile* CurrentTile=track.getTile(index1,index2); Detect Detection=CurrentTile->Detection; if(CurrentTile->isSquare && Detection.x.find(WALL)!=Detection.x.end()) { BoundingTile={Vector2d(index1,index2),Vector2d(index1,index2+1), Vector2d(index1+1,index2+1),Vector2d(index1+1,index2)}; TestCollision=1; } if(CurrentTile->isSquare==0 && Detection.y.find(WALL)!=Detection.y.end()) { if(CurrentTile->Orientation==1) { BoundingTile={Vector2d(index1,index2),Vector2d(index1,index2+1),Vector2d(index1+1,index2)}; } else{ BoundingTile={Vector2d(index1,index2),Vector2d(index1+1,index2+1),Vector2d(index1+1,index2)}; } TestCollision=1; } if(CurrentTile->isSquare==0 && Detection.x.find(WALL)!=Detection.x.end()) { if(CurrentTile->Orientation==1) { BoundingTile={Vector2d(index1,index2+1),Vector2d(index1+1,index2+1),Vector2d(index1+1,index2)}; } else{ BoundingTile={Vector2d(index1,index2),Vector2d(index1,index2+1),Vector2d(index1+1,index2+1)}; } TestCollision=1; } } else{ BoundingTile={Vector2d(index1,index2),Vector2d(index1,index2+1), Vector2d(index1+1,index2+1),Vector2d(index1+1,index2)}; TestCollision=1; } if(TestCollision==1) { bool CornerPoly=0; Vector2u CornerSide=Vector2u(); Vector2d Direction=Vector2d(); double Overlap=0; bool DoubleFlag=0; if(InPolygon(BoundingTile, Bounding, CornerPoly, CornerSide, Direction,Overlap,DoubleFlag)) { if(CornerPoly==1) { Direction=Vector2d(-Direction.x,-Direction.y); } if (DoubleFlag==1) { Vector2d TileAverage=accumulate(BoundingTile.begin(),BoundingTile.end(),Vector2d(0,0)); TileAverage=TileAverage/static_cast<double>(BoundingTile.size()); Vector2d Average=accumulate(Bounding.begin(),Bounding.end(),Vector2d(0,0)); Average=Average/static_cast<double>(Bounding.size()); Vector2d AltVelocity=Average-TileAverage; AltVelocity=AltVelocity/(sqrt(DotProduct(AltVelocity,AltVelocity))); HandleSingleWallCollision(Player[i], Direction, Overlap,Attempts,AltVelocity); } else{ HandleSingleWallCollision(Player[i], Direction, Overlap,Attempts); } StillCorrecting=1; Attempts++; } } if(Attempts>=20) { Player[i].DeathSwitch=1; StillCorrecting=0; } } } } }