diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 92c39db..16587fc 100644 Binary files a/Doc/FuncStats.xlsx and b/Doc/FuncStats.xlsx differ diff --git a/SpaceCadetPinball/TBall.cpp b/SpaceCadetPinball/TBall.cpp index 1fda769..99dc7ba 100644 --- a/SpaceCadetPinball/TBall.cpp +++ b/SpaceCadetPinball/TBall.cpp @@ -126,3 +126,15 @@ int TBall::Message(int code, float value) } return 0; } + +void TBall::throw_ball(TBall* ball, vector_type* acceleration, float angleMult, float speedMult1, float speedMult2) +{ + ball->CollisionComp = nullptr; + ball->Acceleration = *acceleration; + float rnd = static_cast(rand()); + float angle = (1.0f - (rnd * 0.00003051850947599719f + rnd * 0.00003051850947599719f)) * angleMult; + maths::RotateVector(&ball->Acceleration, angle); + rnd = static_cast(rand()); + ball->Speed = (1.0f - (rnd * 0.00003051850947599719f + rnd * 0.00003051850947599719f)) * (speedMult1 * + speedMult2) + speedMult1; +} diff --git a/SpaceCadetPinball/TBall.h b/SpaceCadetPinball/TBall.h index f64366d..1ab6707 100644 --- a/SpaceCadetPinball/TBall.h +++ b/SpaceCadetPinball/TBall.h @@ -14,13 +14,16 @@ public : bool already_hit(TEdgeSegment* edge); int Message(int code, float value) override; + static void throw_ball(TBall* ball, struct vector_type* acceleration, float angleMult, float speedMult1, + float speedMult2); + vector_type Position; vector_type Acceleration; float Speed; float RayMaxDistance; float TimeDelta; float TimeNow; - vector_type InvAcceleration; + vector_type InvAcceleration; int Unknown13; int Unknown14; int Unknown15; @@ -32,5 +35,5 @@ public : int CollisionFlag; float Offset; int Unknown29; - float VisualZArray[50]; + float VisualZArray[50]; }; diff --git a/SpaceCadetPinball/TDrain.cpp b/SpaceCadetPinball/TDrain.cpp index 7d0207d..d78d961 100644 --- a/SpaceCadetPinball/TDrain.cpp +++ b/SpaceCadetPinball/TDrain.cpp @@ -1,2 +1,43 @@ #include "pch.h" #include "TDrain.h" + + +#include "control.h" +#include "loader.h" +#include "TBall.h" +#include "timer.h" +#include "TPinballTable.h" + +TDrain::TDrain(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) +{ + Timer = 0; + TimerTime = *loader::query_float_attribute(groupIndex, 0, 407); +} + +int TDrain::Message(int code, float value) +{ + if (code == 1024) + { + if (Timer) + { + timer::kill(Timer); + Timer = 0; + } + PinballTable->BallInSink = 0; + } + return 0; +} + +void TDrain::Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, TEdgeSegment* edge) +{ + ball->Message(1024, 0.0); + PinballTable->BallInSink = 1; + Timer = timer::set(TimerTime, this, TimerCallback); + control::handler(63, this); +} + +void TDrain::TimerCallback(int timerId, void* caller) +{ + auto drain = static_cast(caller); + control::handler(60, drain); +} diff --git a/SpaceCadetPinball/TDrain.h b/SpaceCadetPinball/TDrain.h index 5e530ee..cbfdf31 100644 --- a/SpaceCadetPinball/TDrain.h +++ b/SpaceCadetPinball/TDrain.h @@ -5,7 +5,13 @@ class TDrain : public TCollisionComponent { public: - TDrain(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) - { - } + TDrain(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 TimerCallback(int timerId, void* caller); + + float TimerTime; + int Timer; }; diff --git a/SpaceCadetPinball/TKickout.cpp b/SpaceCadetPinball/TKickout.cpp index 1900a17..5ae378c 100644 --- a/SpaceCadetPinball/TKickout.cpp +++ b/SpaceCadetPinball/TKickout.cpp @@ -1,2 +1,174 @@ #include "pch.h" #include "TKickout.h" + + +#include "control.h" +#include "loader.h" +#include "objlist_class.h" +#include "TBall.h" +#include "TCircle.h" +#include "timer.h" +#include "TPinballTable.h" +#include "TTableLayer.h" + +TKickout::TKickout(TPinballTable* table, int groupIndex, bool someFlag): TCollisionComponent( + table, groupIndex, false) +{ + visualStruct visual{}; + circle_type circle{}; + + NotSomeFlag = !someFlag; + if (!someFlag) + UnknownBaseFlag2 = 0; + TimerTime1 = 1.5; + TimerTime2 = 0.05f; + MessageField = 0; + Timer = 0; + KickFlag1 = 0; + FieldMult = *loader::query_float_attribute(groupIndex, 0, 305); + loader::query_visual(groupIndex, 0, &visual); + SoundIndex2 = visual.SoundIndex2; + SoundIndex1 = visual.Kicker.SoundIndex; + + Circle.Center.X = *visual.FloatArr; + Circle.Center.Y = visual.FloatArr[1]; + Circle.RadiusSq = *loader::query_float_attribute(groupIndex, 0, 306) * visual.FloatArr[2]; + if (Circle.RadiusSq == 0.0) + Circle.RadiusSq = 0.001f; + auto tCircle = new TCircle(this, &UnknownBaseFlag2, visual.Flag, + reinterpret_cast(visual.FloatArr), Circle.RadiusSq); + if (tCircle) + { + tCircle->place_in_grid(); + EdgeList->Add(tCircle); + } + + Circle.RadiusSq = visual.FloatArr[2] * visual.FloatArr[2]; + CollisionBallSetZ = loader::query_float_attribute(groupIndex, 0, 408)[2]; + ThrowSpeedMult2 = visual.Kicker.Unknown3F * 0.01f; + BallAcceleration.X = visual.Kicker.Unknown4F; + BallAcceleration.Y = visual.Kicker.Unknown5F; + BallAcceleration.Z = visual.Kicker.Unknown6F; + ThrowAngleMult = visual.Kicker.Unknown7F; + ThrowSpeedMult1 = visual.Kicker.Unknown2F; + + circle.RadiusSq = Circle.RadiusSq; + circle.Center.X = Circle.Center.X; + circle.Center.Y = Circle.Center.Y; + circle.Center.Z = Circle.Center.Z; + Field.Flag2Ptr = &UnknownBaseFlag2; + Field.CollisionComp = this; + Field.Mask = visual.Flag; + TTableLayer::edges_insert_circle(&circle, nullptr, &Field); +} + +int TKickout::Message(int code, float value) +{ + switch (code) + { + case 55: + if (KickFlag1) + { + if (value < 0.0) + value = TimerTime1; + Timer = timer::set(value, this, TimerExpired); + } + break; + case 1011: + if (NotSomeFlag) + UnknownBaseFlag2 = 0; + break; + case 1024: + if (KickFlag1) + { + if (Timer) + timer::kill(Timer); + TimerExpired(0, this); + } + if (NotSomeFlag) + UnknownBaseFlag2 = 0; + break; + default: + break; + } + + return 0; +} + +void TKickout::put_scoring(int index, int score) +{ + if (index < 5) + Scores[index] = score; +} + +int TKickout::get_scoring(int index) +{ + return index < 5 ? Scores[index] : 0; +} + +void TKickout::Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, TEdgeSegment* edge) +{ + if (!KickFlag1) + { + Ball = ball; + MaxCollisionSpeed = 1000000000.0; + KickFlag1 = 1; + ball->CollisionComp = this; + ball->Position.X = Circle.Center.X; + ball->Position.Y = Circle.Center.Y; + ball->Position.Z = CollisionBallSetZ; + FieldBallZSet = ball->Position.Z; + if (PinballTable->TiltLockFlag) + { + Message(55, 0.1f); + } + else + { + loader::play_sound(SoundIndex2); + control::handler(63, this); + } + } +} + +int TKickout::FieldEffect(TBall* ball, vector_type* dstVec) +{ + vector_type direction{}; + + if (KickFlag1) + return 0; + direction.X = Circle.Center.X - ball->Position.X; + direction.Y = Circle.Center.Y - ball->Position.Y; + if (direction.Y * direction.Y + direction.X * direction.X > Circle.RadiusSq) + return 0; + maths::normalize_2d(&direction); + dstVec->X = direction.X * FieldMult - ball->Acceleration.X * ball->Speed; + dstVec->Y = direction.Y * FieldMult - ball->Acceleration.Y * ball->Speed; + return 1; +} + +void TKickout::TimerExpired(int timerId, void* caller) +{ + auto kick = static_cast(caller); + if (kick->KickFlag1) + { + kick->KickFlag1 = 0; + kick->Timer = timer::set(kick->TimerTime2, kick, ResetTimerExpired); + if (kick->Ball) + { + kick->Ball->Position.Z = kick->FieldBallZSet; + TBall::throw_ball(kick->Ball, &kick->BallAcceleration, kick->ThrowAngleMult, kick->ThrowSpeedMult1, + kick->ThrowSpeedMult2); + kick->UnknownBaseFlag2 = 0; + kick->Ball = nullptr; + loader::play_sound(kick->SoundIndex1); + } + } +} + +void TKickout::ResetTimerExpired(int timerId, void* caller) +{ + auto kick = static_cast(caller); + if (!kick->NotSomeFlag) + kick->UnknownBaseFlag2 = 1; + kick->Timer = 0; +} diff --git a/SpaceCadetPinball/TKickout.h b/SpaceCadetPinball/TKickout.h index d77512b..1079041 100644 --- a/SpaceCadetPinball/TKickout.h +++ b/SpaceCadetPinball/TKickout.h @@ -1,11 +1,37 @@ #pragma once +#include "maths.h" #include "TCollisionComponent.h" +#include "TEdgeManager.h" class TKickout : public TCollisionComponent { public: - TKickout(TPinballTable* table, int groupIndex, int vectorType) : TCollisionComponent(table, groupIndex, false) - { - } + TKickout(TPinballTable* table, int groupIndex, bool someFlag); + 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; + int FieldEffect(TBall* ball, vector_type* vecDst) override; + + static void TimerExpired(int timerId, void* caller); + static void ResetTimerExpired(int timerId, void* caller); + + int KickFlag1; + int NotSomeFlag; + int Timer; + float TimerTime1; + float TimerTime2; + float CollisionBallSetZ; + TBall* Ball; + float FieldMult; + circle_type Circle; + float FieldBallZSet; + vector_type BallAcceleration; + float ThrowAngleMult; + float ThrowSpeedMult1; + float ThrowSpeedMult2; + field_effect_type Field; + int Scores[5]; }; diff --git a/SpaceCadetPinball/TLightBargraph.cpp b/SpaceCadetPinball/TLightBargraph.cpp index 5b38f87..0fe720f 100644 --- a/SpaceCadetPinball/TLightBargraph.cpp +++ b/SpaceCadetPinball/TLightBargraph.cpp @@ -1,2 +1,134 @@ #include "pch.h" #include "TLightBargraph.h" + + +#include "control.h" +#include "loader.h" +#include "memory.h" +#include "objlist_class.h" +#include "timer.h" +#include "TPinballTable.h" + +TLightBargraph::TLightBargraph(TPinballTable* table, int groupIndex) : TLightGroup(table, groupIndex) +{ + TimerTimeArray = nullptr; + TLightBargraph::Reset(); + if (groupIndex > 0) + { + float* floatArr = loader::query_float_attribute(groupIndex, 0, 904); + if (floatArr) + { + int count = 2 * List->Count(); + TimerTimeArray = reinterpret_cast(memory::allocate(count * sizeof(float))); + if (TimerTimeArray) + { + for (int i = 0; i < count; ++floatArr) + TimerTimeArray[i++] = *floatArr; + } + } + } +} + +TLightBargraph::~TLightBargraph() +{ + if (TimerTimeArray) + memory::free(TimerTimeArray); +} + +int TLightBargraph::Message(int code, float value) +{ + switch (code) + { + case 37: + return TimeIndex; + case 45: + { + if (TimerBargraph) + { + timer::kill(TimerBargraph); + TimerBargraph = 0; + } + auto timeIndex = static_cast(floor(value)); + auto maxCount = 2 * List->Count(); + if (timeIndex >= maxCount) + timeIndex = maxCount - 1; + if (timeIndex >= 0) + { + TLightGroup::Message(45, static_cast(timeIndex / 2)); + if (!(timeIndex & 1)) + TLightGroup::Message(46, 0.0); + float* timeArray = TimerTimeArray; + if (timeArray) + TimerBargraph = timer::set(timeArray[timeIndex], this, BargraphTimerExpired); + TimeIndex = timeIndex; + } + else + { + TLightGroup::Message(20, 0.0); + TimeIndex = 0; + } + break; + } + case 1011: + Reset(); + break; + case 1020: + if (TimerBargraph) + { + timer::kill(TimerBargraph); + TimerBargraph = 0; + } + PlayerTimerIndexBackup[PinballTable->CurrentPlayer] = TimeIndex; + Reset(); + TimeIndex = PlayerTimerIndexBackup[static_cast(floor(value))]; + if (TimeIndex) + { + TLightBargraph::Message(45, static_cast(TimeIndex)); + } + break; + case 1024: + { + Reset(); + int* playerPtr = PlayerTimerIndexBackup; + for (auto index = 0; index < PinballTable->PlayerCount; ++index) + { + *playerPtr = TimeIndex; + + ++playerPtr; + } + TLightGroup::Message(1024, value); + break; + } + default: + TLightGroup::Message(code, value); + break; + } + return 0; +} + +void TLightBargraph::Reset() +{ + if (TimerBargraph) + { + timer::kill(TimerBargraph); + TimerBargraph = 0; + } + TimeIndex = 0; + TLightGroup::Reset(); +} + +void TLightBargraph::BargraphTimerExpired(int timerId, void* caller) +{ + auto bar = static_cast(caller); + bar->TimerBargraph = 0; + if (bar->TimeIndex) + { + bar->Message(45, static_cast(bar->TimeIndex - 1)); + control::handler(60, bar); + } + else + { + bar->Message(20, 0.0); + control::handler(47, bar); + } +} diff --git a/SpaceCadetPinball/TLightBargraph.h b/SpaceCadetPinball/TLightBargraph.h index d8fd59a..1db136d 100644 --- a/SpaceCadetPinball/TLightBargraph.h +++ b/SpaceCadetPinball/TLightBargraph.h @@ -5,7 +5,15 @@ class TLightBargraph : public TLightGroup { public: - TLightBargraph(TPinballTable* table, int groupIndex) : TLightGroup(table, groupIndex) - { - } + TLightBargraph(TPinballTable* table, int groupIndex); + ~TLightBargraph() override; + int Message(int code, float value) override; + void Reset() override; + + static void BargraphTimerExpired(int timerId, void* caller); + + float* TimerTimeArray; + int TimerBargraph; + int TimeIndex; + int PlayerTimerIndexBackup[4]; }; diff --git a/SpaceCadetPinball/TLightGroup.h b/SpaceCadetPinball/TLightGroup.h index dc0ec8d..623c7e7 100644 --- a/SpaceCadetPinball/TLightGroup.h +++ b/SpaceCadetPinball/TLightGroup.h @@ -18,7 +18,7 @@ public: TLightGroup(TPinballTable* table, int groupIndex); ~TLightGroup() override; int Message(int code, float value) override; - void Reset(); + virtual void Reset(); void reschedule_animation(float time); void start_animation(); int next_light_up(); diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index 1805ff8..700bed1 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -53,7 +53,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) CurScoreStruct = nullptr; ScoreBallcount = nullptr; ScorePlayerNumber1 = nullptr; - UnknownP10 = 0; + BallInSink = 0; UnknownBaseFlag2 = 1; TiltLockFlag = 0; EndGameTimeoutTimer = 0; @@ -124,7 +124,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) new TBlocker(this, groupIndex); break; case 1012: - new TKickout(this, groupIndex, 1); + new TKickout(this, groupIndex, true); break; case 1013: new TGate(this, groupIndex); @@ -169,7 +169,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) new TComponentGroup(this, groupIndex); break; case 1029: - new TKickout(this, groupIndex, 0); + new TKickout(this, groupIndex, false); break; case 1030: new TLightBargraph(this, groupIndex); @@ -299,7 +299,7 @@ void TPinballTable::ChangeBallCount(int count) void TPinballTable::tilt(float time) { - if (!TiltLockFlag && !UnknownP10) + if (!TiltLockFlag && !BallInSink) { pinball::InfoTextBox->Clear(); pinball::MissTextBox->Clear(); diff --git a/SpaceCadetPinball/TPinballTable.h b/SpaceCadetPinball/TPinballTable.h index 11d4bbf..b587c27 100644 --- a/SpaceCadetPinball/TPinballTable.h +++ b/SpaceCadetPinball/TPinballTable.h @@ -49,7 +49,7 @@ public: int SoundIndex1; int SoundIndex2; int SoundIndex3; - int UnknownP10; + int BallInSink; int CurScore; int CurScoreE9; int LightShowTimer; diff --git a/SpaceCadetPinball/TPlunger.cpp b/SpaceCadetPinball/TPlunger.cpp index 209910a..0c5e98b 100644 --- a/SpaceCadetPinball/TPlunger.cpp +++ b/SpaceCadetPinball/TPlunger.cpp @@ -84,7 +84,7 @@ int TPlunger::Message(int code, float value) ball->Position.X = PinballTable->PlungerPositionX; ball->Position.Y = PinballTable->PlungerPositionY; ball->UnknownBaseFlag2 = 1; - PinballTable->UnknownP10 = 0; + PinballTable->BallInSink = 0; pb::tilt_no_more(); control::handler(code, this); return 0; diff --git a/SpaceCadetPinball/TPopupTarget.cpp b/SpaceCadetPinball/TPopupTarget.cpp index 9b250ab..5f5cc57 100644 --- a/SpaceCadetPinball/TPopupTarget.cpp +++ b/SpaceCadetPinball/TPopupTarget.cpp @@ -1,2 +1,100 @@ #include "pch.h" #include "TPopupTarget.h" + + +#include "control.h" +#include "loader.h" +#include "render.h" +#include "timer.h" +#include "TPinballTable.h" +#include "TZmapList.h" + +TPopupTarget::TPopupTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) +{ + this->Timer = 0; + this->TimerTime = *loader::query_float_attribute(groupIndex, 0, 407); +} + +int TPopupTarget::Message(int code, float value) +{ + switch (code) + { + case 49: + this->UnknownBaseFlag2 = 0; + render::sprite_set_bitmap(this->RenderSprite, nullptr); + break; + case 50: + this->Timer = timer::set(this->TimerTime, this, TimerExpired); + break; + case 1020: + this->PlayerMessagefieldBackup[this->PinballTable->CurrentPlayer] = this->MessageField; + this->MessageField = this->PlayerMessagefieldBackup[static_cast(floor(value))]; + TPopupTarget::Message(50 - (MessageField != 0), 0.0); + break; + case 1024: + { + this->MessageField = 0; + int* playerPtr = this->PlayerMessagefieldBackup; + for (auto index = 0; index < this->PinballTable->PlayerCount; ++index) + { + *playerPtr = 0; + ++playerPtr; + } + + if (this->Timer) + timer::kill(this->Timer); + TimerExpired(0, this); + break; + } + default: + break; + } + return 0; +} + +void TPopupTarget::put_scoring(int index, int score) +{ + if (index < 3) + Scores[index] = score; +} + +int TPopupTarget::get_scoring(int index) +{ + return index < 3 ? Scores[index] : 0; +} + +void TPopupTarget::Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, + TEdgeSegment* edge) +{ + if (this->PinballTable->TiltLockFlag) + { + maths::basic_collision(ball, nextPosition, direction, this->UnknownC4F, this->UnknownC5F, 1000000000.0, 0.0); + } + else if (maths::basic_collision( + ball, + nextPosition, + direction, + this->UnknownC4F, + this->UnknownC5F, + this->MaxCollisionSpeed, + this->CollisionMultiplier) > this->MaxCollisionSpeed) + { + if (this->SoundIndex1) + loader::play_sound(this->SoundIndex1); + this->Message(49, 0.0); + control::handler(63, this); + } +} + +void TPopupTarget::TimerExpired(int timerId, void* caller) +{ + auto target = static_cast(caller); + target->Timer = 0; + target->UnknownBaseFlag2 = 1; + render::sprite_set_bitmap(target->RenderSprite, static_cast(target->ListBitmap->Get(0))); + if (timerId) + { + if (target->SoundIndex2) + loader::play_sound(target->SoundIndex2); + } +} diff --git a/SpaceCadetPinball/TPopupTarget.h b/SpaceCadetPinball/TPopupTarget.h index 13f1e71..208a3f2 100644 --- a/SpaceCadetPinball/TPopupTarget.h +++ b/SpaceCadetPinball/TPopupTarget.h @@ -5,7 +5,17 @@ class TPopupTarget : public TCollisionComponent { public: - TPopupTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) - { - } + TPopupTarget(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; + int Scores[3]; + int PlayerMessagefieldBackup[4]; }; diff --git a/SpaceCadetPinball/TSoloTarget.cpp b/SpaceCadetPinball/TSoloTarget.cpp index 2c3036d..3f33dc5 100644 --- a/SpaceCadetPinball/TSoloTarget.cpp +++ b/SpaceCadetPinball/TSoloTarget.cpp @@ -1,2 +1,84 @@ #include "pch.h" #include "TSoloTarget.h" + + +#include "control.h" +#include "loader.h" +#include "render.h" +#include "timer.h" +#include "TPinballTable.h" +#include "TZmapList.h" + +TSoloTarget::TSoloTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) +{ + visualStruct visual{}; + + Timer = 0; + TimerTime = 0.1f; + loader::query_visual(groupIndex, 0, &visual); + SoundIndex4 = visual.SoundIndex4; + TSoloTarget::Message(50, 0.0); +} + +int TSoloTarget::Message(int code, float value) +{ + switch (code) + { + case 49: + case 50: + UnknownBaseFlag2 = code == 50; + break; + case 1024: + if (Timer) + timer::kill(Timer); + Timer = 0; + UnknownBaseFlag2 = 1; + break; + default: + return 0; + } + + if (ListBitmap) + { + auto index = 1 - UnknownBaseFlag2; + auto bmp = static_cast(ListBitmap->Get(index)); + auto zMap = static_cast(ListZMap->Get(index)); + render::sprite_set( + RenderSprite, + bmp, + zMap, + bmp->XPosition - PinballTable->XOffset, + bmp->YPosition - PinballTable->YOffset); + } + + return 0; +} + +void TSoloTarget::put_scoring(int index, int score) +{ + if (index < 1) + Scores[index] = score; +} + +int TSoloTarget::get_scoring(int index) +{ + return index < 1 ? Scores[index] : 0; +} + +void TSoloTarget::Collision(TBall* ball, vector_type* nextPosition, vector_type* direction, float coef, + TEdgeSegment* edge) +{ + if (DefaultCollision(ball, nextPosition, direction)) + { + Message(49, 0.0); + Timer = timer::set(TimerTime, this, TimerExpired); + control::handler(63, this); + } +} + +void TSoloTarget::TimerExpired(int timerId, void* caller) +{ + auto target = static_cast(caller); + target->Message(50, 0.0); + target->Timer = 0; +} diff --git a/SpaceCadetPinball/TSoloTarget.h b/SpaceCadetPinball/TSoloTarget.h index 07cd27e..32813f9 100644 --- a/SpaceCadetPinball/TSoloTarget.h +++ b/SpaceCadetPinball/TSoloTarget.h @@ -5,7 +5,18 @@ class TSoloTarget : public TCollisionComponent { public: - TSoloTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) - { - } + TSoloTarget(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 Unknown0; + int Timer; + float TimerTime; + int SoundIndex4; + int Scores[1]; }; diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index 26ad38d..b6df663 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -4,6 +4,7 @@ #include "objlist_class.h" #include "pb.h" #include "TLight.h" +#include "TLightGroup.h" #include "TPinballTable.h" #include "TSound.h" @@ -786,9 +787,9 @@ void control::pbctrl_bdoor_controller(int key) void control::table_add_extra_ball(float count) { ++TableG->ExtraBalls; - static_cast(control_soundwave28_tag.Component)->Play(); + dynamic_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); + dynamic_cast(control_info_text_box_tag.Component)->Display(msg, count); } int control::cheat_bump_rank() @@ -798,10 +799,26 @@ int control::cheat_bump_rank() BOOL control::light_on(component_tag* tag) { - auto light = static_cast(tag->Component); + auto light = dynamic_cast(tag->Component); return light->BmpIndex1 || light->FlasherFlag2 || light->FlasherActive; } +int control::SpecialAddScore(int score) +{ + int prevFlag1 = TableG->ScoreSpecial3Flag; + TableG->ScoreSpecial3Flag = 0; + int prevFlag2 = TableG->ScoreSpecial2Flag; + TableG->ScoreSpecial2Flag = 0; + int prevMult = TableG->ScoreMultiplier; + TableG->ScoreMultiplier = 0; + + int addedScore = TableG->AddScore(score); + TableG->ScoreSpecial2Flag = prevFlag2; + TableG->ScoreMultiplier = prevMult; + TableG->ScoreSpecial3Flag = prevFlag1; + return addedScore; +} + void control::FlipperRebounderControl1(int code, TPinballComponent* caller) { } @@ -842,10 +859,10 @@ void control::DeploymentChuteToEscapeChuteOneWayControl(int code, TPinballCompon int count = control_skill_shot_lights_tag.Component->Message(37, 0.0); if (count) { - static_cast(control_soundwave3_tag.Component)->Play(); + dynamic_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); - static_cast(control_info_text_box_tag.Component)->Display(Buffer, 2.0); + dynamic_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); @@ -1083,6 +1100,185 @@ void control::MultiplierTargetControl(int code, TPinballComponent* caller) void control::BallDrainControl(int code, TPinballComponent* caller) { + char Buffer[64]; + + if (code == 60) + { + if (control_lite199_tag.Component->MessageField) + { + TableG->Message(1022, 0.0); + if (pb::chk_highscore()) + { + dynamic_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); + } + } + else + { + control_plunger_tag.Component->Message(1016, 0.0); + } + } + else if (code == 63) + { + if (table_unlimited_balls) + { + control_drain_tag.Component->Message(1024, 0.0); + control_sink3_tag.Component->Message(56, 0.0); + } + else + { + if (TableG->TiltLockFlag) + { + control_lite200_tag.Component->Message(20, 0.0); + control_lite199_tag.Component->Message(20, 0.0); + } + if (light_on(&control_lite200_tag)) + { + dynamic_cast(control_soundwave27_tag.Component)->Play(); + control_lite200_tag.Component->Message(19, 0.0); + dynamic_cast(control_info_text_box_tag.Component)->Display( + pinball::get_rc_string(96, 0), -1.0); + dynamic_cast(control_soundwave59_tag.Component)->Play(); + } + else if (light_on(&control_lite199_tag)) + { + dynamic_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)-> + Display(pinball::get_rc_string(95, 0), 2.0); + dynamic_cast(control_soundwave59_tag.Component)->Play(); + --TableG->UnknownP78; + } + else if (TableG->UnknownP75) + { + dynamic_cast(control_soundwave27_tag.Component)->Play(); + --TableG->UnknownP75; + } + else + { + if (!TableG->TiltLockFlag) + { + 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); + } + if (TableG->ExtraBalls) + { + TableG->ExtraBalls--; + + char* shootAgainText; + dynamic_cast(control_soundwave59_tag.Component)->Play(); + switch (TableG->CurrentPlayer) + { + case 0: + shootAgainText = pinball::get_rc_string(97, 0); + break; + case 1: + shootAgainText = pinball::get_rc_string(98, 0); + break; + case 2: + shootAgainText = pinball::get_rc_string(99, 0); + break; + default: + case 3: + shootAgainText = pinball::get_rc_string(100, 0); + break; + } + dynamic_cast(control_info_text_box_tag.Component)->Display(shootAgainText, -1.0); + } + else + { + TableG->ChangeBallCount(TableG->BallCount - 1); + if (TableG->CurrentPlayer + 1 != TableG->PlayerCount || TableG->BallCount) + { + TableG->Message(1021, 0.0); + control_lite199_tag.Component->MessageField = 0; + } + else + { + control_lite199_tag.Component->MessageField = 1; + } + dynamic_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); + control_lite30_tag.Component->Message(20, 0.0); + control_lite29_tag.Component->Message(20, 0.0); + control_lite1_tag.Component->Message(20, 0.0); + control_lite54_tag.Component->Message(20, 0.0); + control_lite55_tag.Component->Message(20, 0.0); + control_lite56_tag.Component->Message(20, 0.0); + control_lite17_tag.Component->Message(20, 0.0); + control_lite18_tag.Component->Message(20, 0.0); + control_lite27_tag.Component->Message(20, 0.0); + control_lite28_tag.Component->Message(20, 0.0); + control_lite16_tag.Component->Message(20, 0.0); + control_lite20_tag.Component->Message(20, 0.0); + control_hyper_lights_tag.Component->Message(20, 0.0); + control_lite25_tag.Component->Message(20, 0.0); + control_lite26_tag.Component->Message(20, 0.0); + control_lite130_tag.Component->Message(20, 0.0); + control_lite19_tag.Component->Message(20, 0.0); + control_worm_hole_lights_tag.Component->Message(20, 0.0); + control_bsink_arrow_lights_tag.Component->Message(20, 0.0); + control_l_trek_lights_tag.Component->Message(20, 0.0); + control_r_trek_lights_tag.Component->Message(20, 0.0); + control_lite60_tag.Component->Message(20, 0.0); + control_lite59_tag.Component->Message(20, 0.0); + control_lite61_tag.Component->Message(20, 0.0); + control_bumber_target_lights_tag.Component->Message(20, 0.0); + control_top_target_lights_tag.Component->Message(20, 0.0); + control_top_circle_tgt_lights_tag.Component->Message(20, 0.0); + control_ramp_tgt_lights_tag.Component->Message(20, 0.0); + control_lchute_tgt_lights_tag.Component->Message(20, 0.0); + control_bpr_solotgt_lights_tag.Component->Message(20, 0.0); + control_lite110_tag.Component->Message(20, 0.0); + control_skill_shot_lights_tag.Component->Message(20, 0.0); + control_lite77_tag.Component->Message(20, 0.0); + control_lite198_tag.Component->Message(20, 0.0); + control_lite196_tag.Component->Message(20, 0.0); + control_lite195_tag.Component->Message(20, 0.0); + control_fuel_bargraph_tag.Component->Message(20, 0.0); + control_fuel_bargraph_tag.Component->Message(1024, 0.0); + GravityWellKickoutControl(1024, nullptr); + control_lite62_tag.Component->Message(20, 0.0); + control_lite4_tag.Component->MessageField = 0; + control_lite101_tag.Component->MessageField = 0; + control_lite102_tag.Component->MessageField = 0; + control_lite103_tag.Component->MessageField = 0; + control_ramp_tgt_lights_tag.Component->MessageField = 0; + control_outer_circle_tag.Component->Message(34, 0.0); + control_middle_circle_tag.Component->Message(34, 0.0); + control_attack_bump_tag.Component->Message(1024, 0.0); + control_launch_bump_tag.Component->Message(1024, 0.0); + control_gate1_tag.Component->Message(1024, 0.0); + control_gate2_tag.Component->Message(1024, 0.0); + control_block1_tag.Component->Message(1024, 0.0); + control_target1_tag.Component->Message(1024, 0.0); + control_target2_tag.Component->Message(1024, 0.0); + control_target3_tag.Component->Message(1024, 0.0); + control_target6_tag.Component->Message(1024, 0.0); + control_target5_tag.Component->Message(1024, 0.0); + control_target4_tag.Component->Message(1024, 0.0); + control_target9_tag.Component->Message(1024, 0.0); + control_target8_tag.Component->Message(1024, 0.0); + control_target7_tag.Component->Message(1024, 0.0); + if (control_lite199_tag.Component->MessageField) + control_lite198_tag.Component->MessageField = 32; + else + control_lite198_tag.Component->MessageField = 0; + MissionControl(66, nullptr); + TableG->Message(1012, 0.0); + if (light_on(&control_lite58_tag)) + control_lite58_tag.Component->Message(20, 0.0); + else + TableG->ScoreSpecial2 = 25000; + } + } + } } void control::table_control_handler(int code) diff --git a/SpaceCadetPinball/control.h b/SpaceCadetPinball/control.h index e4cc65f..b6f69e0 100644 --- a/SpaceCadetPinball/control.h +++ b/SpaceCadetPinball/control.h @@ -39,6 +39,7 @@ public: static void table_add_extra_ball(float count); static int cheat_bump_rank(); static BOOL light_on(struct component_tag* tag); + static int SpecialAddScore(int score); static void FlipperRebounderControl1(int code, TPinballComponent* caller); static void FlipperRebounderControl2(int code, TPinballComponent* caller); diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp index 9aaf441..7df3583 100644 --- a/SpaceCadetPinball/maths.cpp +++ b/SpaceCadetPinball/maths.cpp @@ -408,3 +408,15 @@ float maths::distance_to_flipper(ray_type* ray1, ray_type* ray2) } return 1000000000.0; } + +void maths::RotateVector(vector_type* vec, float angle) +{ + float s = sin(angle), c = cos(angle); + vec->X = c * vec->X - s * vec->Y; + vec->Y = s * vec->X + c * vec->Y; + /* Error in the original, should be: + * tmp = c * vec->X - s * vec->Y; + * vec->Y = s * vec->X + c * vec->Y; + * vec->X = tmp + */ +} diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h index 092cfdd..82587ad 100644 --- a/SpaceCadetPinball/maths.h +++ b/SpaceCadetPinball/maths.h @@ -68,4 +68,5 @@ public: static void SinCos(float angle, float* sinOut, float* cosOut); 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); };