diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 16587fc..c0872b3 100644 Binary files a/Doc/FuncStats.xlsx and b/Doc/FuncStats.xlsx differ diff --git a/SpaceCadetPinball/TDemo.cpp b/SpaceCadetPinball/TDemo.cpp index f1d0b6c..7284cb1 100644 --- a/SpaceCadetPinball/TDemo.cpp +++ b/SpaceCadetPinball/TDemo.cpp @@ -1,10 +1,205 @@ #include "pch.h" #include "TDemo.h" + +#include "loader.h" +#include "pb.h" +#include "TEdgeSegment.h" +#include "timer.h" #include "TPinballTable.h" +#include "TBall.h" TDemo::TDemo(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false) { + visualStruct visual{}; + + RestartGameTimer = 0; + PlungerFlag = 0; + FlipLeftTimer = 0; + FlipRightTimer = 0; + MessageField = 0; + UnknownBaseFlag1 = 0; + UnknownBaseFlag2 = 0; + FlipRightFlag = 0; + FlipLeftFlag = 0; table->Demo = this; + auto floatArr1 = loader::query_float_attribute(groupIndex, 0, 407); + if (floatArr1) + { + FlipTimerTime1 = floatArr1[0]; + FlipTimerTime2 = floatArr1[1]; + UnFlipTimerTime1 = floatArr1[2]; + UnFlipTimerTime2 = floatArr1[3]; + } + else + { + FlipTimerTime1 = 0.2f; + FlipTimerTime2 = 0.1f; + UnFlipTimerTime1 = 0.2f; + UnFlipTimerTime2 = 0.1f; + } + loader::query_visual(groupIndex, 0, &visual); + auto v5 = loader::query_float_attribute(groupIndex, 0, 1400); + Edge1 = TEdgeSegment::install_wall(v5, this, &UnknownBaseFlag2, visual.Flag, 0.0, 1400); + + auto v6 = loader::query_float_attribute(groupIndex, 0, 1401); + TEdgeSegment::install_wall(v6, this, &UnknownBaseFlag2, visual.Flag, 0.0, 1401); + + auto v7 = loader::query_float_attribute(groupIndex, 0, 1402); + Edge2 = TEdgeSegment::install_wall(v7, this, &UnknownBaseFlag2, visual.Flag, 0.0, 1402); + + auto v8 = loader::query_float_attribute(groupIndex, 0, 1403); + TEdgeSegment::install_wall(v8, this, &UnknownBaseFlag2, visual.Flag, 0.0, 1403); + + auto v9 = loader::query_float_attribute(groupIndex, 0, 1404); + Edge3 = TEdgeSegment::install_wall(v9, this, &UnknownBaseFlag2, visual.Flag, table->CollisionCompOffset, 1404); +} + +int TDemo::Message(int code, float value) +{ + switch (code) + { + case 1014: + if (RestartGameTimer) + timer::kill(RestartGameTimer); + RestartGameTimer = 0; + break; + case 1022: + if (RestartGameTimer) + timer::kill(RestartGameTimer); + RestartGameTimer = 0; + if (UnknownBaseFlag2 != 0) + RestartGameTimer = timer::set(5.0, this, NewGameRestartTimer); + break; + case 1024: + if (FlipLeftTimer) + timer::kill(FlipLeftTimer); + FlipLeftTimer = 0; + if (FlipRightTimer) + timer::kill(FlipRightTimer); + FlipRightTimer = 0; + + if (FlipLeftFlag != 0) + UnFlipLeft(0, this); + if (FlipRightFlag) + UnFlipRight(0, this); + if (PlungerFlag) + PlungerRelease(0, this); + break; + default: + break; + } + return 0; +} + +void TDemo::Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, TEdgeSegment* edge) +{ + ball->not_again(edge); + ball->Position.X = nextPosition->X; + ball->Position.Y = nextPosition->Y; + ball->RayMaxDistance -= coef; + + switch (edge->WallValue) + { + case 1400: + if (!FlipLeftTimer && !FlipLeftFlag) + { + float time = FlipTimerTime1 + FlipTimerTime2 - static_cast(rand()) * + 0.00003051850947599719f * (FlipTimerTime2 + FlipTimerTime2); + FlipLeftTimer = timer::set(time, this, FlipLeft); + } + break; + case 1401: + FlipLeft(0, this); + break; + case 1402: + if (!FlipRightTimer && !FlipRightFlag) + { + float time = FlipTimerTime1 + FlipTimerTime2 - static_cast(rand()) * + 0.00003051850947599719f * (FlipTimerTime2 + FlipTimerTime2); + FlipRightTimer = timer::set(time, this, FlipRight); + } + break; + case 1403: + FlipRight(0, this); + break; + case 1404: + if (!PlungerFlag) + { + PinballTable->Message(1004, ball->TimeNow); + float time = static_cast(rand()) * 0.00003051850947599719f + 2.0f; + PlungerFlag = timer::set(time, this, PlungerRelease); + } + break; + default: + break; + } +} + +void TDemo::PlungerRelease(int timerId, void* caller) +{ + auto demo = static_cast(caller); + demo->PlungerFlag = 0; + demo->PinballTable->Message(1005, pb::time_next); +} + +void TDemo::UnFlipRight(int timerId, void* caller) +{ + auto demo = static_cast(caller); + if (demo->FlipRightFlag) + demo->PinballTable->Message(1003, pb::time_next); + demo->FlipRightFlag = 0; +} + +void TDemo::UnFlipLeft(int timerId, void* caller) +{ + auto demo = static_cast(caller); + if (demo->FlipLeftFlag) + demo->PinballTable->Message(1001, pb::time_next); + demo->FlipLeftFlag = 0; +} + +void TDemo::FlipRight(int timerId, void* caller) +{ + auto demo = static_cast(caller); + if (!demo->FlipRightFlag) + { + if (demo->FlipRightTimer) + { + timer::kill(demo->FlipRightTimer); + demo->FlipRightTimer = 0; + } + demo->PinballTable->Message(1002, pb::time_next); + demo->FlipRightFlag = 1; + float time = demo->UnFlipTimerTime1 + demo->UnFlipTimerTime2 - static_cast(rand()) * + 0.00003051850947599719f * (demo->UnFlipTimerTime2 + demo->UnFlipTimerTime2); + timer::set(time, demo, UnFlipRight); + } +} + +void TDemo::FlipLeft(int timerId, void* caller) +{ + auto demo = static_cast(caller); + if (!demo->FlipLeftFlag) + { + if (demo->FlipLeftTimer) + { + timer::kill(demo->FlipLeftTimer); + demo->FlipLeftTimer = 0; + } + demo->PinballTable->Message(1000, pb::time_next); + demo->FlipLeftFlag = 1; + float time = demo->UnFlipTimerTime1 + demo->UnFlipTimerTime2 - static_cast(rand()) * + 0.00003051850947599719f * (demo->UnFlipTimerTime2 + demo->UnFlipTimerTime2); + timer::set(time, demo, UnFlipLeft); + } +} + +void TDemo::NewGameRestartTimer(int timerId, void* caller) +{ + auto demo = static_cast(caller); + pb::replay_level(1); + demo->PinballTable->Message(1014, static_cast(demo->PinballTable->PlayerCount)); + demo->RestartGameTimer = 0; } diff --git a/SpaceCadetPinball/TDemo.h b/SpaceCadetPinball/TDemo.h index c48ba74..b289a5d 100644 --- a/SpaceCadetPinball/TDemo.h +++ b/SpaceCadetPinball/TDemo.h @@ -6,4 +6,28 @@ class TDemo : { public: TDemo(TPinballTable* table, int groupIndex); + int Message(int code, float value) override; + void Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, + TEdgeSegment* edge) override; + + static void PlungerRelease(int timerId, void* caller); + static void UnFlipRight(int timerId, void* caller); + static void UnFlipLeft(int timerId, void* caller); + static void FlipRight(int timerId, void* caller); + static void FlipLeft(int timerId, void* caller); + static void NewGameRestartTimer(int timerId, void* caller); + + float FlipTimerTime1; + float FlipTimerTime2; + float UnFlipTimerTime1; + float UnFlipTimerTime2; + int FlipLeftFlag; + int FlipRightFlag; + int FlipLeftTimer; + int FlipRightTimer; + int PlungerFlag; + int RestartGameTimer; + TEdgeSegment* Edge1; + TEdgeSegment* Edge2; + TEdgeSegment* Edge3; }; diff --git a/SpaceCadetPinball/TPinballComponent.cpp b/SpaceCadetPinball/TPinballComponent.cpp index e312144..5c5ce35 100644 --- a/SpaceCadetPinball/TPinballComponent.cpp +++ b/SpaceCadetPinball/TPinballComponent.cpp @@ -109,3 +109,13 @@ int TPinballComponent::get_scoring(int index) { return 0; } + +void* TPinballComponent::operator new(size_t Size) +{ + return calloc(1u, Size); +} + +void TPinballComponent::operator delete(void* p) +{ + free(p); /*Original does not have this*/ +} diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index 25daaa5..446526d 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -20,6 +20,9 @@ public: virtual void put_scoring(int index, int score); virtual int get_scoring(int index); + void* operator new(size_t Size); + void operator delete(void* p); + __int8 UnknownBaseFlag1; __int8 UnknownBaseFlag2; int MessageField; diff --git a/SpaceCadetPinball/TSink.cpp b/SpaceCadetPinball/TSink.cpp index 8f76394..61a6b18 100644 --- a/SpaceCadetPinball/TSink.cpp +++ b/SpaceCadetPinball/TSink.cpp @@ -1,2 +1,110 @@ #include "pch.h" #include "TSink.h" + + +#include "control.h" +#include "loader.h" +#include "objlist_class.h" +#include "render.h" +#include "TPinballTable.h" +#include "TBall.h" +#include "timer.h" + +TSink::TSink(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) +{ + visualStruct visual{}; + + MessageField = 0; + Timer = 0; + loader::query_visual(groupIndex, 0, &visual); + BallAcceleration.X = visual.Kicker.Unknown4F; + BallAcceleration.Y = visual.Kicker.Unknown5F; + BallAcceleration.Z = visual.Kicker.Unknown6F; + ThrowAngleMult = visual.Kicker.Unknown7F; + ThrowSpeedMult1 = visual.Kicker.Unknown2F; + ThrowSpeedMult2 = visual.Kicker.Unknown3F * 0.01f; + SoundIndex4 = visual.SoundIndex4; + SoundIndex3 = visual.SoundIndex3; + auto floatArr = loader::query_float_attribute(groupIndex, 0, 601); + BallPosition.X = floatArr[0]; + BallPosition.Y = floatArr[1]; + TimerTime = *loader::query_float_attribute(groupIndex, 0, 407); +} + +int TSink::Message(int code, float value) +{ + switch (code) + { + case 56: + if (value < 0.0) + value = TimerTime; + Timer = timer::set(value, this, TimerExpired); + break; + case 1020: + PlayerMessagefieldBackup[PinballTable->CurrentPlayer] = MessageField; + MessageField = PlayerMessagefieldBackup[static_cast(floor(value))]; + break; + case 1024: + { + if (Timer) + timer::kill(Timer); + Timer = 0; + MessageField = 0; + + auto playerPtr = PlayerMessagefieldBackup; + for (auto index = 0; index < PinballTable->PlayerCount; ++index) + { + *playerPtr = 0; + + ++playerPtr; + } + + break; + } + default: + break; + } + return 0; +} + +void TSink::put_scoring(int index, int score) +{ + if (index < 3) + Scores[index] = score; +} + +int TSink::get_scoring(int index) +{ + return index < 3 ? Scores[index] : 0; +} + +void TSink::Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, TEdgeSegment* edge) +{ + Timer = 0; + if (PinballTable->TiltLockFlag) + { + maths::basic_collision(ball, nextPosition, direction, UnknownC4F, UnknownC5F, 1000000000.0, 0.0); + } + else + { + ball->UnknownBaseFlag2 = 0; + render::sprite_set_bitmap(ball->RenderSprite, nullptr); + loader::play_sound(SoundIndex4); + control::handler(63, this); + } +} + +void TSink::TimerExpired(int timerId, void* caller) +{ + auto sink = static_cast(caller); + auto ball = static_cast(sink->PinballTable->BallList->Get(0)); + ball->CollisionComp = nullptr; + ball->UnknownBaseFlag2 = 1; + ball->Position.X = sink->BallPosition.X; + ball->Position.Y = sink->BallPosition.Y; + TBall::throw_ball(ball, &sink->BallAcceleration, sink->ThrowAngleMult, sink->ThrowSpeedMult1, + sink->ThrowSpeedMult2); + if (sink->SoundIndex3) + loader::play_sound(sink->SoundIndex3); + sink->Timer = 0; +} diff --git a/SpaceCadetPinball/TSink.h b/SpaceCadetPinball/TSink.h index 38fe23b..b31b6ca 100644 --- a/SpaceCadetPinball/TSink.h +++ b/SpaceCadetPinball/TSink.h @@ -1,11 +1,29 @@ #pragma once +#include "maths.h" #include "TCollisionComponent.h" class TSink : public TCollisionComponent { public: - TSink(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) - { - } + TSink(TPinballTable* table, int groupIndex); + int Message(int code, float value) override; + void put_scoring(int index, int score) override; + int get_scoring(int index) override; + void Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, + TEdgeSegment* edge) override; + + static void TimerExpired(int timerId, void* caller); + + int Timer; + float TimerTime; + vector_type BallPosition; + vector_type BallAcceleration; + float ThrowAngleMult; + float ThrowSpeedMult1; + float ThrowSpeedMult2; + int SoundIndex4; + int SoundIndex3; + int Scores[3]; + int PlayerMessagefieldBackup[4]; }; diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index b6df663..bd87add 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -787,9 +787,9 @@ void control::pbctrl_bdoor_controller(int key) void control::table_add_extra_ball(float count) { ++TableG->ExtraBalls; - dynamic_cast(control_soundwave28_tag.Component)->Play(); + static_cast(control_soundwave28_tag.Component)->Play(); auto msg = pinball::get_rc_string(9, 0); - dynamic_cast(control_info_text_box_tag.Component)->Display(msg, count); + static_cast(control_info_text_box_tag.Component)->Display(msg, count); } int control::cheat_bump_rank() @@ -799,7 +799,7 @@ int control::cheat_bump_rank() BOOL control::light_on(component_tag* tag) { - auto light = dynamic_cast(tag->Component); + auto light = static_cast(tag->Component); return light->BmpIndex1 || light->FlasherFlag2 || light->FlasherActive; } @@ -859,10 +859,10 @@ void control::DeploymentChuteToEscapeChuteOneWayControl(int code, TPinballCompon int count = control_skill_shot_lights_tag.Component->Message(37, 0.0); if (count) { - dynamic_cast(control_soundwave3_tag.Component)->Play(); + static_cast(control_soundwave3_tag.Component)->Play(); int score = TableG->AddScore(caller->get_scoring(count - 1)); sprintf_s(Buffer, pinball::get_rc_string(21, 0), score); - dynamic_cast(control_info_text_box_tag.Component)->Display(Buffer, 2.0); + static_cast(control_info_text_box_tag.Component)->Display(Buffer, 2.0); if (!light_on(&control_lite56_tag)) { control_l_trek_lights_tag.Component->Message(34, 0.0); @@ -1109,10 +1109,10 @@ void control::BallDrainControl(int code, TPinballComponent* caller) TableG->Message(1022, 0.0); if (pb::chk_highscore()) { - dynamic_cast(control_soundwave3_tag.Component)->Play(); + static_cast(control_soundwave3_tag.Component)->Play(); TableG->LightGroup->Message(16, 3.0); char* v11 = pinball::get_rc_string(177, 0); - dynamic_cast(control_mission_text_box_tag.Component)->Display(v11, -1.0); + static_cast(control_mission_text_box_tag.Component)->Display(v11, -1.0); } } else @@ -1136,25 +1136,25 @@ void control::BallDrainControl(int code, TPinballComponent* caller) } if (light_on(&control_lite200_tag)) { - dynamic_cast(control_soundwave27_tag.Component)->Play(); + static_cast(control_soundwave27_tag.Component)->Play(); control_lite200_tag.Component->Message(19, 0.0); - dynamic_cast(control_info_text_box_tag.Component)->Display( + static_cast(control_info_text_box_tag.Component)->Display( pinball::get_rc_string(96, 0), -1.0); - dynamic_cast(control_soundwave59_tag.Component)->Play(); + static_cast(control_soundwave59_tag.Component)->Play(); } else if (light_on(&control_lite199_tag)) { - dynamic_cast(control_soundwave27_tag.Component)->Play(); + static_cast(control_soundwave27_tag.Component)->Play(); control_lite199_tag.Component->Message(20, 0.0); control_lite200_tag.Component->Message(19, 0.0); - dynamic_cast(control_info_text_box_tag.Component)-> + static_cast(control_info_text_box_tag.Component)-> Display(pinball::get_rc_string(95, 0), 2.0); - dynamic_cast(control_soundwave59_tag.Component)->Play(); + static_cast(control_soundwave59_tag.Component)->Play(); --TableG->UnknownP78; } else if (TableG->UnknownP75) { - dynamic_cast(control_soundwave27_tag.Component)->Play(); + static_cast(control_soundwave27_tag.Component)->Play(); --TableG->UnknownP75; } else @@ -1163,14 +1163,14 @@ void control::BallDrainControl(int code, TPinballComponent* caller) { int time = SpecialAddScore(TableG->ScoreSpecial2); sprintf_s(Buffer, pinball::get_rc_string(94, 0), time); - dynamic_cast(control_info_text_box_tag.Component)->Display(Buffer, 2.0); + static_cast(control_info_text_box_tag.Component)->Display(Buffer, 2.0); } if (TableG->ExtraBalls) { TableG->ExtraBalls--; char* shootAgainText; - dynamic_cast(control_soundwave59_tag.Component)->Play(); + static_cast(control_soundwave59_tag.Component)->Play(); switch (TableG->CurrentPlayer) { case 0: @@ -1187,7 +1187,7 @@ void control::BallDrainControl(int code, TPinballComponent* caller) shootAgainText = pinball::get_rc_string(100, 0); break; } - dynamic_cast(control_info_text_box_tag.Component)->Display(shootAgainText, -1.0); + static_cast(control_info_text_box_tag.Component)->Display(shootAgainText, -1.0); } else { @@ -1201,7 +1201,7 @@ void control::BallDrainControl(int code, TPinballComponent* caller) { control_lite199_tag.Component->MessageField = 1; } - dynamic_cast(control_soundwave27_tag.Component)->Play(); + static_cast(control_soundwave27_tag.Component)->Play(); } control_bmpr_inc_lights_tag.Component->Message(20, 0.0); control_ramp_bmpr_inc_lights_tag.Component->Message(20, 0.0); diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp index 7df3583..43eed05 100644 --- a/SpaceCadetPinball/maths.cpp +++ b/SpaceCadetPinball/maths.cpp @@ -178,7 +178,7 @@ void maths::line_init(line_type* line, float x0, float y0, float x1, float y1) normalize_2d(&line->Direction); line->PerpendicularL.X = line->Direction.Y; line->PerpendicularL.Y = -line->Direction.X; - line->PreComp1 = -(line->Direction.Y * x0) + (line->Direction.X * y0); + line->PreComp1 = -(line->Direction.Y * x0) + line->Direction.X * y0; if (line->Direction.X >= 0.000000001 || line->Direction.X <= -0.000000001) { v9 = x1; @@ -420,3 +420,47 @@ void maths::RotateVector(vector_type* vec, float angle) * vec->X = tmp */ } + +void maths::find_closest_edge(ramp_plane_type* plane, int planeCount, wall_point_type* wall, vector_type** lineEnd, + vector_type** lineStart) +{ + vector_type wallEnd{}, wallStart{}; + + wallStart.X = wall->X0; + wallStart.Y = wall->Y0; + wallEnd.Y = wall->Y1; + wallEnd.X = wall->X1; + + float maxDistance = 1000000000.0f; + ramp_plane_type* planePtr = plane; + for (auto index = 0; index < planeCount; index++) + { + auto vec1 = reinterpret_cast(&planePtr->V1), + vec2 = reinterpret_cast(&planePtr->V2), + vec3 = reinterpret_cast(&planePtr->V3); + auto distance = Distance(&wallStart, vec1) + Distance(&wallEnd, vec2); + if (distance < maxDistance) + { + maxDistance = distance; + *lineEnd = vec1; + *lineStart = vec2; + } + + distance = Distance(&wallStart, vec2) + Distance(&wallEnd, vec3); + if (distance < maxDistance) + { + maxDistance = distance; + *lineEnd = vec2; + *lineStart = vec3; + } + + distance = Distance(&wallStart, vec3) + Distance(&wallEnd, vec1); + if (distance < maxDistance) + { + maxDistance = distance; + *lineEnd = vec3; + *lineStart = vec1; + } + ++planePtr; + } +} diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h index 82587ad..cfbf9f1 100644 --- a/SpaceCadetPinball/maths.h +++ b/SpaceCadetPinball/maths.h @@ -45,6 +45,32 @@ struct __declspec(align(4)) line_type vector_type RayIntersect; }; +struct vector_type2 +{ + int X; + int Y; +}; + +struct wall_point_type +{ + float X0; + float Y0; + float X1; + float Y1; +}; + +struct __declspec(align(4)) ramp_plane_type +{ + float Unknown12; + vector_type2 V0; + vector_type2 V1; + vector_type2 V2; + vector_type2 V3; + float GravityAngle1; + float GravityAngle2; + vector_type2 V5_Zero; +}; + class maths { @@ -69,4 +95,6 @@ public: static void RotatePt(vector_type* point, float sin, float cos, vector_type* origin); static float distance_to_flipper(ray_type* ray1, ray_type* ray2); static void RotateVector(vector_type* vec, float angle); + static void find_closest_edge(ramp_plane_type* plane, int planeCount, wall_point_type* wall, vector_type** lineEnd, + vector_type** lineStart); }; diff --git a/SpaceCadetPinball/pb.h b/SpaceCadetPinball/pb.h index 35748e7..4f6b0ed 100644 --- a/SpaceCadetPinball/pb.h +++ b/SpaceCadetPinball/pb.h @@ -9,7 +9,7 @@ class pb { public: static int time_ticks; - static float ball_speed_limit, time_now; + static float ball_speed_limit, time_now, time_next; static int cheat_mode, game_mode; static datFileStruct* record_table; static TPinballTable* MainTable; @@ -39,7 +39,6 @@ public: static float collide(float timeNow, float timeDelta, TBall* ball); private : static int demo_mode, mode_countdown_; - static float time_next; static high_score_struct highscore_table[5]; static int state; };