diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index c6cb10b..ed22afb 100644 Binary files a/Doc/FuncStats.xlsx and b/Doc/FuncStats.xlsx differ diff --git a/SpaceCadetPinball/TBall.cpp b/SpaceCadetPinball/TBall.cpp index f866293..574873b 100644 --- a/SpaceCadetPinball/TBall.cpp +++ b/SpaceCadetPinball/TBall.cpp @@ -14,13 +14,13 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false) { visualStruct visual{}; - Unknown9F = 0.0; - Unknown7F = 0.0; + TimeNow = 0.0; + RayMaxDistance = 0.0; UnknownBaseFlag2 = 1; - Unknown16 = 0; + CollisionComp = nullptr; EdgeCollisionCount = 0; - Unknown8F = 0.0; - Unknown17 = 1; + TimeDelta = 0.0; + Unknown17F = 1; CollisionFlag = 0; Speed = 0.0; Acceleration.Y = 0.0; @@ -113,16 +113,16 @@ int TBall::Message(int code, float value) { render::ball_set(RenderSprite, nullptr, 0.0, 0, 0); Position.X = 0.0; - Unknown16 = 0; + CollisionComp = nullptr; Position.Y = 0.0; UnknownBaseFlag2 = 0; CollisionFlag = 0; - Unknown17 = 1; + Unknown17F = 1; Acceleration.Y = 0.0; Position.Z = Offset; Acceleration.X = 0.0; Speed = 0.0; - Unknown7F = 0.0; + RayMaxDistance = 0.0; } return 0; } diff --git a/SpaceCadetPinball/TBall.h b/SpaceCadetPinball/TBall.h index e3ee29e..e7ef2a3 100644 --- a/SpaceCadetPinball/TBall.h +++ b/SpaceCadetPinball/TBall.h @@ -2,6 +2,7 @@ #include "maths.h" #include "TPinballComponent.h" +class TCollisionComponent; class TEdgeSegment; class TBall : public TPinballComponent @@ -16,15 +17,15 @@ public : vector_type Position; vector_type Acceleration; float Speed; - float Unknown7F; - float Unknown8F; - float Unknown9F; + float RayMaxDistance; + float TimeDelta; + float TimeNow; vector_type InvAcceleration; int Unknown13; int Unknown14; int Unknown15; - int Unknown16; - int Unknown17; + TCollisionComponent* CollisionComp; + float Unknown17F; TEdgeSegment* Collisions[5]; int EdgeCollisionCount; vector_type CollisionOffset; diff --git a/SpaceCadetPinball/TCollisionComponent.cpp b/SpaceCadetPinball/TCollisionComponent.cpp index 5da51ae..762b136 100644 --- a/SpaceCadetPinball/TCollisionComponent.cpp +++ b/SpaceCadetPinball/TCollisionComponent.cpp @@ -46,7 +46,7 @@ TCollisionComponent::~TCollisionComponent() EdgeList->Delete(edge); delete edge; } - delete this->EdgeList; + delete EdgeList; } @@ -57,3 +57,64 @@ void TCollisionComponent::port_draw() static_cast(EdgeList->Get(index))->port_draw(); } } + +int TCollisionComponent::DefaultCollision(TBall* ball, vector_type* ballPosition, vector_type* vec2) +{ + if (PinballTable->TiltLockFlag) + { + maths::basic_collision(ball, ballPosition, vec2, UnknownC4F, UnknownC5F, 1000000000.0, 0.0); + return 0; + } + auto projSpeed = maths::basic_collision(ball, ballPosition, vec2, UnknownC4F, UnknownC5F, + UnknownC7F, + UnknownC6F); + if (projSpeed <= UnknownC7F) + { + if (projSpeed > 0.2) + { + if (SoundIndex2) + loader::play_sound(SoundIndex2); + } + return 0; + } + if (SoundIndex1) + loader::play_sound(SoundIndex1); + return 1; +} + +void TCollisionComponent::Collision(TBall* ball, struct vector_type* ballPosition, struct vector_type* vec2, + float someVal, TEdgeSegment* edge) +{ + int soundIndex; + + if (PinballTable->TiltLockFlag) + { + maths::basic_collision(ball, ballPosition, vec2, UnknownC4F, UnknownC5F, 1000000000.0, 0.0); + return; + } + double projSpeed = maths::basic_collision( + ball, + ballPosition, + vec2, + UnknownC4F, + UnknownC5F, + UnknownC7F, + UnknownC6F); + if (projSpeed <= UnknownC7F) + { + if (projSpeed <= 0.2) + return; + soundIndex = SoundIndex2; + } + else + { + soundIndex = SoundIndex1; + } + if (soundIndex) + loader::play_sound(soundIndex); +} + +int TCollisionComponent::FieldEffect(TBall* ball, vector_type* vecDst) +{ + return 0; +} diff --git a/SpaceCadetPinball/TCollisionComponent.h b/SpaceCadetPinball/TCollisionComponent.h index 738c49f..dc66cd2 100644 --- a/SpaceCadetPinball/TCollisionComponent.h +++ b/SpaceCadetPinball/TCollisionComponent.h @@ -2,6 +2,9 @@ #include "objlist_class.h" #include "TPinballComponent.h" +class TEdgeSegment; +class TBall; + class TCollisionComponent : public TPinballComponent { public: @@ -18,4 +21,8 @@ public: TCollisionComponent(TPinballTable* table, int groupIndex, bool createWall); ~TCollisionComponent(); void port_draw() override; + virtual void Collision(TBall* ball, struct vector_type* ballPosition, struct vector_type* vec2, float someVal, + TEdgeSegment* edge); + virtual int FieldEffect(TBall* ball, struct vector_type* vecDst); + int DefaultCollision(TBall* ball, struct vector_type* ballPosition, struct vector_type* vec2); }; diff --git a/SpaceCadetPinball/TEdgeManager.cpp b/SpaceCadetPinball/TEdgeManager.cpp index 65e1609..b22c884 100644 --- a/SpaceCadetPinball/TEdgeManager.cpp +++ b/SpaceCadetPinball/TEdgeManager.cpp @@ -1,6 +1,16 @@ #include "pch.h" #include "TEdgeManager.h" +int TEdgeManager::FieldEffects(TBall* ball, vector_type* vecDst) +{ + return 0; +} + void TEdgeManager::edges_insert_square(float a1, float a2, float a3, float a4, TEdgeSegment* a5, field_effect_type* a6) { } + +float TEdgeManager::FindCollisionDistance(ray_type* ray, TBall* ball, TEdgeSegment** edge) +{ + return 1000000000.0; +} diff --git a/SpaceCadetPinball/TEdgeManager.h b/SpaceCadetPinball/TEdgeManager.h index 9a92d3f..5e34342 100644 --- a/SpaceCadetPinball/TEdgeManager.h +++ b/SpaceCadetPinball/TEdgeManager.h @@ -16,5 +16,8 @@ public: { } + int FieldEffects(TBall* ball, struct vector_type* vecDst); + static void edges_insert_square(float a1, float a2, float a3, float a4, TEdgeSegment* a5, field_effect_type* a6); + float FindCollisionDistance(ray_type* ray, TBall* ball, TEdgeSegment** edge); }; diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index 7e2f713..aebcbc5 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -403,7 +403,7 @@ int TPinballTable::Message(int code, float value) } else { - UnknownP6 = 0; + CheatsUsed = 0; Message(1024, 0.0); auto ball = static_cast(BallList->Get(0)); ball->Position.Y = 0.0; diff --git a/SpaceCadetPinball/TPinballTable.h b/SpaceCadetPinball/TPinballTable.h index 31dbce7..39e7897 100644 --- a/SpaceCadetPinball/TPinballTable.h +++ b/SpaceCadetPinball/TPinballTable.h @@ -45,7 +45,7 @@ public: scoreStruct* CurScoreStruct; scoreStruct* ScoreBallcount; scoreStruct* ScorePlayerNumber1; - int UnknownP6; + int CheatsUsed; int SoundIndex1; int SoundIndex2; int SoundIndex3; diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index 5e15d4e..21d95fc 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -2,7 +2,11 @@ #include "control.h" #include "objlist_class.h" +#include "pb.h" #include "TPinballTable.h" +#include "TSound.h" + +int control::pbctrl_state; int control_bump_scores1[] = {500, 1000, 1500, 2000}; int control_roll_scores1[] = {2000}; @@ -502,7 +506,7 @@ component_tag* control::simple_components[142] &control_soundwave7_tag }; -int control::table_control_flag; +int control::table_unlimited_balls; void control::make_links(TPinballTable* table) @@ -570,6 +574,227 @@ void control::handler(int code, TPinballComponent* cmp) MissionControl(code, cmp); } +void control::pbctrl_bdoor_controller(int key) +{ + int v1; // eax + int v2; // eax + bool v3; // zf + + if (!control_lite198_tag.Component->MessageField) + { + if (key <= 'M') + { + if (key == 'M') + { + v2 = pbctrl_state; + if (pbctrl_state == 4 || pbctrl_state == 61 || pbctrl_state == 81 || pbctrl_state == 101) + goto LABEL_87; + v3 = pbctrl_state == 121; + } + else + { + if (key <= 'D') + { + if (key != 'D') + { + if (key == ' ') + { + if (pbctrl_state == 26) + { + pbctrl_state = 27; + return; + } + goto LABEL_77; + } + if (key != '1') + { + if (key != 'A') + { + if (key != 'B') + { + if (key == 'C') + { + if (!pbctrl_state) + { + pbctrl_state = 1; + return; + } + if (pbctrl_state == 11) + { + pbctrl_state = 12; + return; + } + } + goto LABEL_77; + } + v1 = pbctrl_state != 0 ? 0 : 81; + goto LABEL_88; + } + v2 = pbctrl_state; + if (pbctrl_state == 5 || pbctrl_state == 62 || pbctrl_state == 82 || pbctrl_state == 102) + goto LABEL_87; + v3 = pbctrl_state == 122; + goto LABEL_86; + } + v1 = pbctrl_state != 0 ? 0 : 61; + LABEL_88: + pbctrl_state = v1; + return; + } + if (pbctrl_state != 22 && pbctrl_state != 23) + goto LABEL_77; + LABEL_58: + ++pbctrl_state; + return; + } + if (key != 'E') + { + switch (key) + { + case 'G': + v1 = pbctrl_state != 0 ? 0 : 101; + break; + case 'H': + v1 = pbctrl_state != 0 ? 0 : 21; + break; + case 'I': + v2 = pbctrl_state; + if (pbctrl_state == 1 || pbctrl_state == 10) + goto LABEL_87; + v3 = pbctrl_state == 21; + goto LABEL_86; + default: + goto LABEL_77; + } + goto LABEL_88; + } + v2 = pbctrl_state; + if (pbctrl_state == 3 || pbctrl_state == 24 || pbctrl_state == 28) + goto LABEL_87; + v3 = pbctrl_state == 44; + } + goto LABEL_86; + } + if (key <= 'S') + { + if (key == 'S') + { + v2 = pbctrl_state; + if (pbctrl_state == 12 || pbctrl_state == 29) + goto LABEL_87; + v3 = pbctrl_state == 45; + } + else + { + if (key != 'N') + { + if (key != 'O') + { + if (key != 'Q') + { + if (key == 'R') + { + if (!pbctrl_state) + { + pbctrl_state = 121; + return; + } + if (pbctrl_state == 7) + { + pbctrl_state = 8; + return; + } + } + goto LABEL_77; + } + v1 = pbctrl_state != 0 ? 0 : 41; + goto LABEL_88; + } + if (pbctrl_state != 8 && pbctrl_state != 42) + goto LABEL_77; + goto LABEL_58; + } + v2 = pbctrl_state; + if (pbctrl_state == 2 || pbctrl_state == 9) + goto LABEL_87; + v3 = pbctrl_state == 25; + } + LABEL_86: + if (v3) + { + LABEL_87: + v1 = v2 + 1; + goto LABEL_88; + } + LABEL_77: + pbctrl_state = 0; + return; + } + switch (key) + { + case 'T': + v2 = pbctrl_state; + if (pbctrl_state != 30) + { + if (pbctrl_state == 27 || pbctrl_state == 6) + goto LABEL_87; + v3 = pbctrl_state == 43; + goto LABEL_86; + } + pb::cheat_mode = 1; + break; + case 'U': + if (pbctrl_state == 41) + { + pbctrl_state = 42; + return; + } + goto LABEL_77; + case 'X': + if (pbctrl_state == 63) + { + table_add_extra_ball(2.0); + goto LABEL_76; + } + if (pbctrl_state != 83) + { + if (pbctrl_state == 103) + { + GravityWellKickoutControl(64, nullptr); + } + else + { + if (pbctrl_state != 123) + goto LABEL_77; + cheat_bump_rank(); + } + LABEL_76: + TableG->CheatsUsed = 1; + goto LABEL_77; + } + table_unlimited_balls = 1; + break; + default: + goto LABEL_77; + } + TableG->CheatsUsed = 1; + goto LABEL_77; + } +} + +void control::table_add_extra_ball(float count) +{ + ++TableG->ExtraBalls; + static_cast(control_soundwave28_tag.Component)->Play(); + auto msg = pinball::get_rc_string(9, 0); + static_cast(control_info_text_box_tag.Component)->Display(msg, count); +} + +int control::cheat_bump_rank() +{ + return 0; +} + void control::FlipperRebounderControl1(int code, TPinballComponent* caller) { } @@ -806,7 +1031,7 @@ void control::table_control_handler(int code) { if (code == 1011) { - table_control_flag = 0; + table_unlimited_balls = 0; control_lite77_tag.Component->Message(7, 0.0); } } diff --git a/SpaceCadetPinball/control.h b/SpaceCadetPinball/control.h index fb6d8be..cf73b0b 100644 --- a/SpaceCadetPinball/control.h +++ b/SpaceCadetPinball/control.h @@ -30,11 +30,14 @@ public: static TPinballTable* TableG; static component_info score_components[88]; static component_tag* simple_components[142]; - static int table_control_flag; + static int table_unlimited_balls; static void make_links(TPinballTable* table); static TPinballComponent* make_component_link(component_tag* tag); static void handler(int code, TPinballComponent* cmp); + static void pbctrl_bdoor_controller(int key); + static void table_add_extra_ball(float count); + static int cheat_bump_rank(); static void FlipperRebounderControl1(int code, TPinballComponent* caller); static void FlipperRebounderControl2(int code, TPinballComponent* caller); @@ -95,5 +98,8 @@ public: static void MultiplierTargetControl(int code, TPinballComponent* caller); static void BallDrainControl(int code, TPinballComponent* caller); - static void table_control_handler(int code); + static void table_control_handler(int code); + +private: + static int pbctrl_state; }; diff --git a/SpaceCadetPinball/fullscrn.cpp b/SpaceCadetPinball/fullscrn.cpp index b539b45..7a858ce 100644 --- a/SpaceCadetPinball/fullscrn.cpp +++ b/SpaceCadetPinball/fullscrn.cpp @@ -320,7 +320,7 @@ void fullscrn::fillRect(int right, int bottom) } } -int fullscrn::convert_mouse_pos(unsigned int mouseXY) +unsigned fullscrn::convert_mouse_pos(unsigned int mouseXY) { unsigned __int16 x = mouseXY & 0xffFF - render::vscreen.XPosition; unsigned __int16 y = (mouseXY >> 16) - render::vscreen.YPosition; diff --git a/SpaceCadetPinball/fullscrn.h b/SpaceCadetPinball/fullscrn.h index bb1a9df..8ed0a87 100644 --- a/SpaceCadetPinball/fullscrn.h +++ b/SpaceCadetPinball/fullscrn.h @@ -25,7 +25,7 @@ public: static void center_in(HWND parent, HWND child); static int displaychange(); static void activate(int flag); - static int convert_mouse_pos(unsigned int mouseXY); + static unsigned convert_mouse_pos(unsigned int mouseXY); static void getminmaxinfo(MINMAXINFO* maxMin); static void paint(); static bool set_menu_mode(int menuEnabled); diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp index 66672ba..2532479 100644 --- a/SpaceCadetPinball/maths.cpp +++ b/SpaceCadetPinball/maths.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "maths.h" +#include "TBall.h" + void maths::enclosing_box(rectangle_type* rect1, rectangle_type* rect2, rectangle_type* dstRect) { @@ -203,23 +205,19 @@ void maths::line_init(line_type* line, float x0, float y0, float x1, float y1) float maths::ray_intersect_line(ray_type* ray, line_type* line) { - // Similar to https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/ - float perpDot; - float result; - float v4; bool v5; bool v6; - float v7; - perpDot = line->PerpendicularL.Y * ray->Direction.Y + ray->Direction.X * line->PerpendicularL.X; + float perpDot = line->PerpendicularL.Y * ray->Direction.Y + ray->Direction.X * line->PerpendicularL.X; if (perpDot < 0.0) { - result = -((ray->Origin.X * line->PerpendicularL.X + ray->Origin.Y * line->PerpendicularL.Y + line->PreComp1) + float result = -((ray->Origin.X * line->PerpendicularL.X + ray->Origin.Y * line->PerpendicularL.Y + line-> + PreComp1) / perpDot); if (result >= -ray->MinDistance && result <= ray->MaxDistance) { line->CompTmp1 = result * ray->Direction.X + ray->Origin.X; - v4 = result * ray->Direction.Y + ray->Origin.Y; + float v4 = result * ray->Direction.Y + ray->Origin.Y; line->Unknown10 = v4; if (0.0 == line->Direction.X) { @@ -234,7 +232,7 @@ float maths::ray_intersect_line(ray_type* ray, line_type* line) } else if (line->OriginX <= line->CompTmp1) { - v7 = line->CompTmp1; + float v7 = line->CompTmp1; v5 = v7 < line->OriginY; v6 = v7 == line->OriginY; if (v5 || v6) @@ -269,3 +267,35 @@ void maths::vector_add(vector_type* vec1Dst, vector_type* vec2) vec1Dst->X += vec2->X; vec1Dst->Y += vec2->Y; } + +float maths::basic_collision(TBall* ball, vector_type* ballPosition, vector_type* vec2, float a4, float a5, float a6, + float a7) +{ + ball->Position.X = ballPosition->X; + ball->Position.Y = ballPosition->Y; + float proj = -(vec2->Y * ball->Acceleration.Y + vec2->X * ball->Acceleration.X); + if (proj < 0) + { + proj = -proj; + } + else + { + float dx1 = proj * vec2->X; + float dy1 = proj * vec2->Y; + float v17 = dx1 + ball->Acceleration.X; + float v18 = dy1 + ball->Acceleration.Y; + ball->Acceleration.X = v17 * a5 + dx1 * a4; + ball->Acceleration.Y = v18 * a5 + dy1 * a4; + normalize_2d(&ball->Acceleration); + } + float projSpeed = proj * ball->Speed; + float newSpeed = ball->Speed - (1.0f - a4) * projSpeed; + ball->Speed = newSpeed; + if (projSpeed >= a6) + { + ball->Acceleration.X = newSpeed * ball->Acceleration.X + vec2->X * a7; + ball->Acceleration.Y = newSpeed * ball->Acceleration.Y + vec2->Y * a7; + ball->Speed = normalize_2d(&ball->Acceleration); + } + return projSpeed; +} diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h index b0b9b4c..3d93bff 100644 --- a/SpaceCadetPinball/maths.h +++ b/SpaceCadetPinball/maths.h @@ -1,5 +1,7 @@ #pragma once +class TBall; + struct vector_type { float X; @@ -28,6 +30,9 @@ struct __declspec(align(4)) ray_type vector_type Direction; float MaxDistance; float MinDistance; + float TimeNow; + float TimeDelta; + float Unknown2; }; struct __declspec(align(4)) line_type @@ -56,4 +61,5 @@ public: static void cross(vector_type* vec1, vector_type* vec2, vector_type* dstVec); static float magnitude(vector_type* vec); static void vector_add(vector_type* vec1Dst, vector_type* vec2); + static float basic_collision(TBall* ball, struct vector_type* ballPosition, struct vector_type* vec2, float a4, float a5, float a6, float a7); }; diff --git a/SpaceCadetPinball/nudge.cpp b/SpaceCadetPinball/nudge.cpp index 6d9e3b1..0438522 100644 --- a/SpaceCadetPinball/nudge.cpp +++ b/SpaceCadetPinball/nudge.cpp @@ -74,7 +74,7 @@ void nudge::_nudge(float xDiff, float yDiff) for (auto index = 0; index < ballList->Count(); index++) { auto ball = static_cast(ballList->Get(index)); - if (ball->UnknownBaseFlag2 && !ball->Unknown16) + if (ball->UnknownBaseFlag2 && !ball->CollisionComp) { ball->Acceleration.X = ball->Acceleration.X * ball->Speed; ball->Acceleration.Y = ball->Acceleration.Y * ball->Speed; diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index 1fbec02..ccb1798 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -37,9 +37,9 @@ winhelp_entry options::keymap_help[18] short options::vk_list[28] { - 0x8041, + -32703, 0x5A, - 0x8030, + -32720, 0x39, 0x402E, 0x402F, diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index d6a33cb..e78c12f 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "pb.h" + +#include "control.h" #include "high_score.h" #include "memory.h" #include "pinball.h" @@ -17,6 +19,7 @@ #include "TDemo.h" #include "TLightGroup.h" #include "TPlunger.h" +#include "TTableLayer.h" TPinballTable* pb::MainTable = nullptr; datFileStruct* pb::record_table = nullptr; @@ -218,7 +221,7 @@ int pb::frame(int time) if (!mode_countdown(time)) { time_next = time_now + timeMul; - //pb::timed_frame(time_now, timeMul, 1); + timed_frame(time_now, timeMul, true); time_now = time_next; time_ticks += time; if (nudge::nudged_left || nudge::nudged_right || nudge::nudged_up) @@ -248,6 +251,62 @@ int pb::frame(int time) return 1; } +void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls) +{ + vector_type vec1{}, vec2{}; + + for (int i = 0; i < MainTable->BallList->Count(); i++) + { + auto ball = static_cast(MainTable->BallList->Get(i)); + if (ball->UnknownBaseFlag2 != 0) + { + auto collComp = ball->CollisionComp; + if (collComp) + { + ball->TimeDelta = timeDelta; + collComp->FieldEffect(ball, &vec1); + } + else + { + if (MainTable->UnknownBaseFlag2) + { + vec2.X = 0.0; + vec2.Y = 0.0; + vec2.Z = 0.0; + TTableLayer::edge_manager->FieldEffects(ball, &vec2); + vec2.X = vec2.X * timeDelta; + vec2.Y = vec2.Y * timeDelta; + ball->Acceleration.X = ball->Speed * ball->Acceleration.X; + ball->Acceleration.Y = ball->Speed * ball->Acceleration.Y; + maths::vector_add(&ball->Acceleration, &vec2); + ball->Speed = maths::normalize_2d(&ball->Acceleration); + ball->InvAcceleration.X = ball->Acceleration.X == 0.0 ? 1000000000.0f : 1.0f / ball->Acceleration.X; + ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0 ? 1000000000.0f : 1.0f / ball->Acceleration.Y; + } + + auto timeDelta2 = timeDelta; + auto timeNow2 = timeNow; + for (auto index = 10; timeDelta2 > 0.000001 && index; --index) + { + auto time = collide(timeNow2, timeDelta2, ball); + timeDelta2 -= time; + timeNow2 += time; + } + } + } + } + + if (drawBalls) + { + for (int i = 0; i < MainTable->BallList->Count(); i++) + { + auto ball = static_cast(MainTable->BallList->Get(i)); + if (ball->UnknownBaseFlag2) + ball->Repaint(); + } + } +} + void pb::window_size(int* width, int* height) { *width = 600; @@ -337,7 +396,7 @@ void pb::keydown(int key) mode_countdown(-1); return; } - ctrl_bdoor_controller(key); + control::pbctrl_bdoor_controller(key); if (key == options::Options.LeftFlipperKey) { MainTable->Message(1000, time_now); @@ -417,7 +476,7 @@ void pb::keydown(int key) MessageBoxA(winmain::hwnd_frame, buffer, "Mem:", 0x2000u); break; case 'R': - cheat_bump_rank(); + control::cheat_bump_rank(); break; case VK_F11: gdrv::get_focus(); @@ -429,10 +488,6 @@ void pb::keydown(int key) } } -void pb::ctrl_bdoor_controller(int key) -{ -} - int pb::mode_countdown(int time) { if (!game_mode || game_mode <= 0) @@ -456,19 +511,57 @@ int pb::mode_countdown(int time) return 0; } -int pb::cheat_bump_rank() -{ - return 0; -} - void pb::launch_ball() { MainTable->Plunger->Message(1017, 0.0f); } -int pb::end_game() +void pb::end_game() { - return 0; + int scores[4]; + int scoreIndex[4]; + char String1[200]; + + mode_change(2); + int playerCount = MainTable->PlayerCount; + + score_struct_super* scorePtr = MainTable->PlayerScores; + for (auto index = 0; index < playerCount; ++index) + { + scores[index] = scorePtr->ScoreStruct->Score; + scoreIndex[index] = index; + ++scorePtr; + } + + for (auto i = 0; i < playerCount; ++i) + { + for (auto j = i; j < playerCount; ++j) + { + if (scores[j] > scores[i]) + { + int score = scores[j]; + scores[j] = scores[i]; + scores[i] = score; + + int index = scoreIndex[j]; + scoreIndex[j] = scoreIndex[i]; + scoreIndex[i] = index; + } + } + } + + if (!demo_mode && !MainTable->CheatsUsed) + { + for (auto i = 0; i < playerCount; ++i) + { + int position = high_score::get_score_position(highscore_table, scores[i]); + if (position >= 0) + { + lstrcpyA(String1, pinball::get_rc_string(scoreIndex[i] + 26, 0)); + high_score::show_and_set_high_score_dialog(highscore_table, scores[i], position, String1); + } + } + } } void pb::high_scores() @@ -500,3 +593,51 @@ bool pb::chk_highscore() } return true; } + +float pb::collide(float timeNow, float timeDelta, TBall* ball) +{ + ray_type ray{}; + vector_type positionMod{}; + + if (ball->UnknownBaseFlag2 && !ball->CollisionComp) + { + if (ball_speed_limit < ball->Speed) + ball->Speed = ball_speed_limit; + + auto maxDistance = timeDelta * ball->Speed; + ball->TimeDelta = timeDelta; + ball->RayMaxDistance = maxDistance; + ball->TimeNow = timeNow; + + ray.Origin.X = ball->Position.X; + ray.Origin.Y = ball->Position.Y; + ray.Origin.Z = ball->Position.Z; + ray.Direction.X = ball->Acceleration.X; + ray.Direction.Y = ball->Acceleration.Y; + ray.Direction.Z = ball->Acceleration.Z; + ray.MaxDistance = maxDistance; + ray.Unknown2 = ball->Unknown17F; + ray.TimeNow = timeNow; + ray.TimeDelta = timeDelta; + ray.MinDistance = 0.0020000001f; + + TEdgeSegment* edge = nullptr; + auto distance = TTableLayer::edge_manager->FindCollisionDistance(&ray, ball, &edge); + if (distance >= 1000000000.0) + { + maxDistance = timeDelta * ball->Speed; + ball->RayMaxDistance = maxDistance; + positionMod.X = maxDistance * ball->Acceleration.X; + positionMod.Y = maxDistance * ball->Acceleration.Y; + positionMod.Z = 0.0; + maths::vector_add(&ball->Position, &positionMod); + } + else + { + edge->EdgeCollision(ball, distance); + if (ball->Speed > 0.000000001) + return fabs(distance / ball->Speed); + } + } + return timeDelta; +} diff --git a/SpaceCadetPinball/pb.h b/SpaceCadetPinball/pb.h index 7eb730e..beae935 100644 --- a/SpaceCadetPinball/pb.h +++ b/SpaceCadetPinball/pb.h @@ -3,6 +3,8 @@ #include "partman.h" #include "TPinballTable.h" +class TBall; + class pb { public: @@ -22,19 +24,19 @@ public: static void replay_level(int demoMode); static void ballset(int x, int y); static int frame(int time); + static void timed_frame(float timeNow, float timeDelta, bool drawBalls); static void window_size(int* width, int* height); static void pause_continue(); static void loose_focus(); static void keyup(int key); static void keydown(int key); - static void ctrl_bdoor_controller(int key); static int mode_countdown(int time); - static int cheat_bump_rank(); static void launch_ball(); - static int end_game(); + static void end_game(); static void high_scores(); static void tilt_no_more(); static bool chk_highscore(); + static float collide(float timeNow, float timeDelta, TBall* ball); private : static int demo_mode, mode_countdown_; static float time_now, time_next; diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index eb4c27c..d9bcc59 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -312,7 +312,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP SetForegroundWindow(hWnd); return 0; } - + if (Msg <= WM_ACTIVATEAPP) { switch (Msg) @@ -410,250 +410,247 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP return 0; } - if (Msg <= WM_MENUSELECT) + switch (Msg) { - switch (Msg) + case WM_MENUSELECT: + if (lParam) + return DefWindowProcA(hWnd, Msg, wParam, lParam); + if (fullscrn::screen_mode) + fullscrn::set_menu_mode(0); + return 0; + case WM_SYSKEYDOWN: + no_time_loss = 1; + if (fullscrn::screen_mode) + fullscrn::set_menu_mode(1); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_GETMINMAXINFO: + fullscrn::getminmaxinfo((MINMAXINFO*)lParam); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_DISPLAYCHANGE: + if (fullscrn::displaychange()) { - case WM_MENUSELECT: - if (lParam) - return DefWindowProcA(hWnd, Msg, wParam, lParam); - if (fullscrn::screen_mode) - fullscrn::set_menu_mode(0); - return 0; - case WM_SYSKEYDOWN: - no_time_loss = 1; - if (fullscrn::screen_mode) - fullscrn::set_menu_mode(1); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_GETMINMAXINFO: - fullscrn::getminmaxinfo((MINMAXINFO*)lParam); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_DISPLAYCHANGE: - if (fullscrn::displaychange()) - { - options::Options.FullScreen = 0; - options::menu_check(Menu1_Full_Screen, 0); - } - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_KEYUP: - pb::keyup(wParam); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_KEYDOWN: - if (!(lParam & 0x40000000)) - pb::keydown(wParam); - switch (wParam) - { - case VK_ESCAPE: - if (options::Options.FullScreen) - options::toggle(0x193u); - SendMessageA(hwnd_frame, 0x112u, 0xF020u, 0); - break; - case VK_F1: - help_introduction(hinst, hWnd); - break; - case VK_F2: - new_game(); - break; - case VK_F3: - pause(); - break; - case VK_F4: + options::Options.FullScreen = 0; + options::menu_check(Menu1_Full_Screen, 0); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_KEYUP: + pb::keyup(wParam); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_KEYDOWN: + if (!(lParam & 0x40000000)) + pb::keydown(wParam); + switch (wParam) + { + case VK_ESCAPE: + if (options::Options.FullScreen) options::toggle(0x193u); - break; - case VK_F8: - if (!single_step) - pause(); - options::keyboard(); - break; - } - if (!pb::cheat_mode) - return DefWindowProcA(hWnd, Msg, wParam, lParam); - switch (wParam) - { - case 'H': - DispGRhistory = 1; - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case 'Y': - SetWindowTextA(hWnd, "Pinball"); - DispFrameRate = DispFrameRate == 0; - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case VK_F1: - pb::frame(10); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case VK_F15: - single_step = single_step == 0; - if (single_step == 0) - no_time_loss = 1; - return DefWindowProcA(hWnd, Msg, wParam, lParam); - default: - return DefWindowProcA(hWnd, Msg, wParam, lParam); - } - case WM_SYSCOMMAND: - switch (wParam & 0xFFF0) - { - case SC_MOVE: - if (fullscrn::screen_mode) - return 0; - break; - case SC_MINIMIZE: - if (!single_step) - pause(); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case SC_SCREENSAVE: - fullscrn::activate(0); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - default: break; - } - end_pause(); - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_INITMENU: - no_time_loss = 1; - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_COMMAND: - no_time_loss = 1; - switch (wParam) - { - case Menu1_Launch_Ball: - end_pause(); - pb::launch_ball(); - break; - case Menu1_Pause_Resume_Game: + SendMessageA(hwnd_frame, 0x112u, 0xF020u, 0); + break; + case VK_F1: + help_introduction(hinst, hWnd); + break; + case VK_F2: + new_game(); + break; + case VK_F3: + pause(); + break; + case VK_F4: + options::toggle(0x193u); + break; + case VK_F8: + if (!single_step) pause(); - break; - case Menu1_Demo: - end_pause(); - pb::toggle_demo(); - break; - case Menu1_Select_Table: - { - if (!single_step) - pause(); - auto tmpBuf = memory::allocate(0x1F4u); - if (tmpBuf) - { - char cmdLine[0x1F4u]; - options::get_string(nullptr, "Shell Exe", tmpBuf, pinball::WindowName, 500); - sprintf_s( - cmdLine, - "%s %s%lX %s%lX", - tmpBuf, - "select=", - (int)hwnd_frame, - "confirm=", - (int)hwnd_frame - * (int)hwnd_frame - * (int)hwnd_frame - * (int)hwnd_frame - * (int)hwnd_frame - * (int)hwnd_frame - * (int)hwnd_frame); - if (static_cast(WinExec(cmdLine, 5u)) < 32) - { - auto caption = pinball::get_rc_string(170, 0); - auto text = pinball::get_rc_string(171, 0); - MessageBoxA(hwnd_frame, text, caption, 0x2010u); - } - memory::free(tmpBuf); - } - break; - } - case Menu1_1Player: - case Menu1_2Players: - case Menu1_3Players: - case Menu1_4Players: - options::toggle(wParam); - new_game(); - break; - case Menu1_Help_Topics: - if (!single_step) - pause(); - help_introduction(hinst, hWnd); - break; - case 106: // End game button? - pb::end_game(); - break; - case Menu1_Full_Screen: - case Menu1_Sounds: - case Menu1_Music: - if (!single_step) - pause(); - options::toggle(wParam); - break; - case Menu1_Player_Controls: - case 204: // Second controls button? - if (!single_step) - pause(); - options::keyboard(); - break; - case Menu1_Exit: - PostMessageA(hWnd, WM_QUIT, 0, 0); - break; - case Menu1_New_Game: - new_game(); - break; - case Menu1_About_Pinball: - if (!single_step) - pause(); - a_dialog(hinst, hWnd); - break; - case Menu1_High_Scores: - if (!single_step) - pause(); - pb::high_scores(); - break; - case 1: // Unknown button - midi::restart_midi_seq(lParam); - break; - default: - break; - } - return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_LBUTTONDOWN: - if (pb::game_mode) - { - if (pb::cheat_mode) - { - mouse_down = 1; - mouse_hsave = SetCursor(nullptr); - auto lParam2 = fullscrn::convert_mouse_pos(lParam); - last_mouse_x = static_cast(lParam2); - last_mouse_y = static_cast(lParam2) >> 16; - SetCapture(hWnd); - } - return DefWindowProcA(hWnd, Msg, wParam, lParam); - } + options::keyboard(); break; - case WM_LBUTTONUP: - if (mouse_down) - { - mouse_down = 0; - SetCursor(mouse_hsave); - ReleaseCapture(); - } + } + if (!pb::cheat_mode) return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - if (pb::game_mode) - return DefWindowProcA(hWnd, Msg, wParam, lParam); - break; - case WM_POWERBROADCAST: - if (wParam == 4 && options::Options.FullScreen) - { - options::Options.FullScreen = 0; - options::menu_check(Menu1_Full_Screen, 0); - fullscrn::set_screen_mode(options::Options.FullScreen); - } + switch (wParam) + { + case 'H': + DispGRhistory = 1; return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_PALETTECHANGED: - InvalidateRect(hWnd, nullptr, 0); + case 'Y': + SetWindowTextA(hWnd, "Pinball"); + DispFrameRate = DispFrameRate == 0; return DefWindowProcA(hWnd, Msg, wParam, lParam); - case WM_POINTERDEVICEINRANGE | LB_ADDSTRING: - if (wParam == 1) - midi::restart_midi_seq(lParam); + case VK_F1: + pb::frame(10); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case VK_F15: + single_step = single_step == 0; + if (single_step == 0) + no_time_loss = 1; return DefWindowProcA(hWnd, Msg, wParam, lParam); default: return DefWindowProcA(hWnd, Msg, wParam, lParam); } + case WM_SYSCOMMAND: + switch (wParam & 0xFFF0) + { + case SC_MOVE: + if (fullscrn::screen_mode) + return 0; + break; + case SC_MINIMIZE: + if (!single_step) + pause(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case SC_SCREENSAVE: + fullscrn::activate(0); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + default: break; + } + end_pause(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_INITMENU: + no_time_loss = 1; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_COMMAND: + no_time_loss = 1; + switch (wParam) + { + case Menu1_Launch_Ball: + end_pause(); + pb::launch_ball(); + break; + case Menu1_Pause_Resume_Game: + pause(); + break; + case Menu1_Demo: + end_pause(); + pb::toggle_demo(); + break; + case Menu1_Select_Table: + { + if (!single_step) + pause(); + auto tmpBuf = memory::allocate(0x1F4u); + if (tmpBuf) + { + char cmdLine[0x1F4u]; + options::get_string(nullptr, "Shell Exe", tmpBuf, pinball::WindowName, 500); + sprintf_s( + cmdLine, + "%s %s%lX %s%lX", + tmpBuf, + "select=", + (int)hwnd_frame, + "confirm=", + (int)hwnd_frame + * (int)hwnd_frame + * (int)hwnd_frame + * (int)hwnd_frame + * (int)hwnd_frame + * (int)hwnd_frame + * (int)hwnd_frame); + if (static_cast(WinExec(cmdLine, 5u)) < 32) + { + auto caption = pinball::get_rc_string(170, 0); + auto text = pinball::get_rc_string(171, 0); + MessageBoxA(hwnd_frame, text, caption, 0x2010u); + } + memory::free(tmpBuf); + } + break; + } + case Menu1_1Player: + case Menu1_2Players: + case Menu1_3Players: + case Menu1_4Players: + options::toggle(wParam); + new_game(); + break; + case Menu1_Help_Topics: + if (!single_step) + pause(); + help_introduction(hinst, hWnd); + break; + case 106: // End game button? + pb::end_game(); + break; + case Menu1_Full_Screen: + case Menu1_Sounds: + case Menu1_Music: + if (!single_step) + pause(); + options::toggle(wParam); + break; + case Menu1_Player_Controls: + case 204: // Second controls button? + if (!single_step) + pause(); + options::keyboard(); + break; + case Menu1_Exit: + PostMessageA(hWnd, WM_QUIT, 0, 0); + break; + case Menu1_New_Game: + new_game(); + break; + case Menu1_About_Pinball: + if (!single_step) + pause(); + a_dialog(hinst, hWnd); + break; + case Menu1_High_Scores: + if (!single_step) + pause(); + pb::high_scores(); + break; + case 1: // Unknown button + midi::restart_midi_seq(lParam); + break; + default: + break; + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_LBUTTONDOWN: + if (pb::game_mode) + { + if (pb::cheat_mode) + { + mouse_down = 1; + mouse_hsave = SetCursor(nullptr); + auto mouseXY = fullscrn::convert_mouse_pos(lParam); + last_mouse_x = mouseXY & 0xffFFu; + last_mouse_y = mouseXY >> 16; + SetCapture(hWnd); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + break; + case WM_LBUTTONUP: + if (mouse_down) + { + mouse_down = 0; + SetCursor(mouse_hsave); + ReleaseCapture(); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + if (pb::game_mode) + return DefWindowProcA(hWnd, Msg, wParam, lParam); + break; + case WM_POWERBROADCAST: + if (wParam == 4 && options::Options.FullScreen) + { + options::Options.FullScreen = 0; + options::menu_check(Menu1_Full_Screen, 0); + fullscrn::set_screen_mode(options::Options.FullScreen); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_PALETTECHANGED: + InvalidateRect(hWnd, nullptr, 0); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_POINTERDEVICEINRANGE | LB_ADDSTRING: + if (wParam == 1) + midi::restart_midi_seq(lParam); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + default: + return DefWindowProcA(hWnd, Msg, wParam, lParam); } pb::mode_countdown(-1);