#include "pch.h" #include "TTableLayer.h" #include "fullscrn.h" #include "loader.h" #include "pb.h" #include "proj.h" #include "render.h" #include "TBall.h" #include "TLine.h" #include "TPinballTable.h" TEdgeManager* TTableLayer::edge_manager; TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, false) { visualStruct visual{}; rectangle_type rect{}; auto groupIndex = loader::query_handle("table"); loader::query_visual(groupIndex, 0, &visual); auto spriteData = visual.Bitmap; /*Full tilt: proj center first value is offset by resolution*/ auto projCenter = loader::query_float_attribute(groupIndex, 0, 700 + fullscrn::GetResolution()); proj::recenter(projCenter[0], projCenter[1]); render::set_background_zmap(spriteData.ZMap, 0, 0); auto bmp = spriteData.Bmp; VisBmp = bmp; rect.XPosition = 0; rect.YPosition = 0; rect.Width = bmp->Width; rect.Height = bmp->Height; new render_sprite(VisualTypes::Background, bmp, spriteData.ZMap, 0, 0, &rect); PinballTable->SoundIndex1 = visual.SoundIndex4; PinballTable->SoundIndex2 = visual.SoundIndex3; PinballTable->SoundIndex3 = visual.Kicker.HardHitSoundId; auto tableAngleArr = loader::query_float_attribute(groupIndex, 0, 305); if (tableAngleArr) { PinballTable->GravityDirVectMult = tableAngleArr[0]; PinballTable->GravityAngleX = tableAngleArr[1]; PinballTable->GravityAnglY = tableAngleArr[2]; } else { PinballTable->GravityDirVectMult = 25.0f; PinballTable->GravityAngleX = 0.5f; PinballTable->GravityAnglY = 1.570796f; } GraityDirX = cos(PinballTable->GravityAnglY) * sin(PinballTable->GravityAngleX) * PinballTable->GravityDirVectMult; GraityDirY = sin(PinballTable->GravityAnglY) * sin(PinballTable->GravityAngleX) * PinballTable->GravityDirVectMult; /*Full tilt hack - GraityMult should be 0.2*/ if (!pb::FullTiltMode && !pb::FullTiltDemoMode) { auto angleMultArr = loader::query_float_attribute(groupIndex, 0, 701); GraityMult = *angleMultArr; } else GraityMult = 0.2f; table->XOffset = bmp->XPosition; table->YOffset = bmp->YPosition; table->Width = bmp->Width; table->Height = bmp->Height; Threshold = visual.Kicker.Threshold; Boost = 15.0f; auto edgePoints = reinterpret_cast(visual.FloatArr); XMin = std::min(edgePoints[0].X, std::min(edgePoints[1].X, edgePoints[2].X)); YMin = std::min(edgePoints[0].Y, std::min(edgePoints[1].Y, edgePoints[2].Y)); XMax = std::max(edgePoints[0].X, std::max(edgePoints[1].X, edgePoints[2].X)); YMax = std::max(edgePoints[0].Y, std::max(edgePoints[1].Y, edgePoints[2].Y)); auto height = YMax - YMin; auto width = XMax - XMin; edge_manager = new TEdgeManager(XMin, YMin, width, height); for (auto i = 0; i < visual.FloatArrCount; i++) { auto line = new TLine(this, &ActiveFlag, visual.CollisionGroup, edgePoints[i + 1].X, edgePoints[i + 1].Y, edgePoints[i].X, edgePoints[i].Y); line->place_in_grid(&AABB); EdgeList.push_back(line); } Field.CollisionGroup = -1; Field.ActiveFlag = &ActiveFlag; Field.CollisionComp = this; edges_insert_square(YMin, XMin, YMax, XMax, nullptr, &Field); } TTableLayer::~TTableLayer() { if (edge_manager) delete edge_manager; } int TTableLayer::FieldEffect(TBall* ball, vector2* vecDst) { vecDst->X = GraityDirX - (0.5f - RandFloat() + ball->Direction.X) * ball->Speed * GraityMult; vecDst->Y = GraityDirY - ball->Direction.Y * ball->Speed * GraityMult; return 1; } void TTableLayer::edges_insert_square(float y0, float x0, float y1, float x1, TEdgeSegment* edge, field_effect_type* field) { float widthM = static_cast(static_cast(edge_manager->AdvanceX * 0.001f)); // Sic float heightM = static_cast(static_cast(edge_manager->AdvanceY * 0.001f)); float xMin = x0 - widthM; float xMax = x1 + widthM; float yMin = y0 - heightM; float yMax = y1 + heightM; int xMinBox = edge_manager->box_x(xMin); int yMinBox = edge_manager->box_y(yMin); int xMaxBox = edge_manager->box_x(xMax); int yMaxBox = edge_manager->box_y(yMax); float boxX = static_cast(xMinBox) * edge_manager->AdvanceX + edge_manager->MinX; for (int indexX = xMinBox; indexX <= xMaxBox; ++indexX) { float boxY = static_cast(yMinBox) * edge_manager->AdvanceY + edge_manager->MinY; for (int indexY = yMinBox; indexY <= yMaxBox; ++indexY) { if (xMax >= boxX && xMin <= boxX + edge_manager->AdvanceX && yMax >= boxY && yMin <= boxY + edge_manager->AdvanceY) { if (edge) { edge_manager->add_edge_to_box(indexX, indexY, edge); } if (field) { edge_manager->add_field_to_box(indexX, indexY, field); } } boxY += edge_manager->AdvanceY; } boxX += edge_manager->AdvanceX; } } void TTableLayer::edges_insert_circle(circle_type* circle, TEdgeSegment* edge, field_effect_type* field) { ray_type ray{}; vector2 vec1{}; auto radiusM = sqrt(circle->RadiusSq) + edge_manager->AdvanceX * 0.001f; auto radiusMSq = radiusM * radiusM; auto xMin = circle->Center.X - radiusM; auto yMin = circle->Center.Y - radiusM; auto xMax = radiusM + circle->Center.X; auto yMax = radiusM + circle->Center.Y; auto xMinBox = edge_manager->box_x(xMin); auto yMinBox = edge_manager->box_y(yMin); auto xMaxBox = edge_manager->box_x(xMax); auto yMaxBox = edge_manager->box_y(yMax); auto dirX = xMinBox - 1 <= 0 ? 0 : xMinBox - 1; auto dirY = yMinBox - 1 <= 0 ? 0 : yMinBox - 1; xMaxBox = edge_manager->increment_box_x(xMaxBox); yMaxBox = edge_manager->increment_box_y(yMaxBox); vec1.X = static_cast(dirX) * edge_manager->AdvanceX + edge_manager->MinX; for (auto indexX = dirX; indexX <= xMaxBox; ++indexX) { vec1.Y = static_cast(dirY) * edge_manager->AdvanceY + edge_manager->MinY; for (int indexY = dirY; indexY <= yMaxBox; ++indexY) { auto vec1XAdv = vec1.X + edge_manager->AdvanceX; auto vec1YAdv = vec1.Y + edge_manager->AdvanceY; if (xMax >= vec1.X && xMin <= vec1XAdv && yMax >= vec1.Y && yMin <= vec1YAdv) { bool collision = true; do { if (circle->Center.X <= vec1XAdv && circle->Center.X >= vec1.X && circle->Center.Y <= vec1YAdv && circle->Center.Y >= vec1.Y) break; auto vec2 = vec1; if (maths::Distance_Squared(vec1, circle->Center) <= radiusMSq) break; vec2.X = vec2.X + edge_manager->AdvanceX; if (maths::Distance_Squared(vec2, circle->Center) <= radiusMSq) break; vec2.Y = vec2.Y + edge_manager->AdvanceY; if (maths::Distance_Squared(vec2, circle->Center) <= radiusMSq) break; vec2.X = vec2.X - edge_manager->AdvanceX; if (maths::Distance_Squared(vec2, circle->Center) <= radiusMSq) break; ray.Origin = vec1; ray.Direction.X = 1.0; ray.Direction.Y = 0.0; ray.MaxDistance = edge_manager->AdvanceX; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.X = -1.0; ray.Origin.X = ray.Origin.X + edge_manager->AdvanceX; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.X = 0.0; ray.Direction.Y = 1.0; ray.MaxDistance = edge_manager->AdvanceY; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.Y = -1.0; ray.Origin.Y = ray.Origin.Y + edge_manager->AdvanceY; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.Y = 0.0; ray.Direction.X = -1.0; ray.MaxDistance = edge_manager->AdvanceX; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.X = 1.0; ray.Origin.X = ray.Origin.X - edge_manager->AdvanceX; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.X = 0.0; ray.Direction.Y = -1.0; ray.MaxDistance = edge_manager->AdvanceY; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; ray.Direction.Y = 1.0; ray.Origin.Y = ray.Origin.Y - edge_manager->AdvanceY; if (maths::ray_intersect_circle(ray, *circle) < 1000000000.0f) break; collision = false; } while (false); if (collision) { if (edge) { edge_manager->add_edge_to_box(indexX, indexY, edge); } if (field) { edge_manager->add_field_to_box(indexX, indexY, field); } } } vec1.Y += edge_manager->AdvanceY; } vec1.X += edge_manager->AdvanceX; } }