mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-11-17 15:20:17 +01:00
Multiball part 1: control and component changes from FT.
The result is 3DPB/FT hybrid, with control closer to 3DPB and components closer to FT.
This commit is contained in:
parent
14a8d64b67
commit
c1c74878df
15 changed files with 354 additions and 154 deletions
|
@ -141,3 +141,9 @@ vector2 TBall::get_coordinates()
|
|||
{
|
||||
return TTableLayer::edge_manager->NormalizeBox(Position);
|
||||
}
|
||||
|
||||
void TBall::Disable()
|
||||
{
|
||||
ActiveFlag = false;
|
||||
render::sprite_set_bitmap(RenderSprite, nullptr);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ public :
|
|||
bool already_hit(TEdgeSegment* edge);
|
||||
int Message(int code, float value) override;
|
||||
vector2 get_coordinates() override;
|
||||
void Disable();
|
||||
|
||||
static void throw_ball(TBall* ball, vector3* direction, float angleMult, float speedMult1,
|
||||
float speedMult2);
|
||||
|
|
|
@ -23,16 +23,21 @@ int TDrain::Message(int code, float value)
|
|||
timer::kill(Timer);
|
||||
Timer = 0;
|
||||
}
|
||||
PinballTable->BallInSink = 0;
|
||||
PinballTable->BallInDrainFlag = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TDrain::Collision(TBall* ball, vector2* nextPosition, vector2* direction, float distance, TEdgeSegment* edge)
|
||||
{
|
||||
ball->Message(1024, 0.0);
|
||||
PinballTable->BallInSink = 1;
|
||||
Timer = timer::set(TimerTime, this, TimerCallback);
|
||||
ball->Disable();
|
||||
--PinballTable->MultiballCount;
|
||||
if (PinballTable->MultiballCount <= 0)
|
||||
{
|
||||
PinballTable->MultiballCount = 0;
|
||||
PinballTable->BallInDrainFlag = 1;
|
||||
Timer = timer::set(TimerTime, this, TimerCallback);
|
||||
}
|
||||
control::handler(63, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,20 +49,19 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
|
|||
CurScoreStruct = nullptr;
|
||||
ScoreBallcount = nullptr;
|
||||
ScorePlayerNumber1 = nullptr;
|
||||
BallInSink = 0;
|
||||
BallInDrainFlag = 0;
|
||||
ActiveFlag = 1;
|
||||
TiltLockFlag = 0;
|
||||
EndGameTimeoutTimer = 0;
|
||||
LightShowTimer = 0;
|
||||
ReplayTimer = 0;
|
||||
TiltTimeoutTimer = 0;
|
||||
MultiballFlag = 0;
|
||||
MultiballFlag = false;
|
||||
PlayerCount = 0;
|
||||
|
||||
auto ballObj = new TBall(this);
|
||||
BallList.push_back(ballObj);
|
||||
if (ballObj)
|
||||
ballObj->ActiveFlag = 0;
|
||||
auto ball = AddBall(0.0f, 0.0f);
|
||||
ball->Disable();
|
||||
|
||||
new TTableLayer(this);
|
||||
LightGroup = new TLightGroup(this, 0);
|
||||
|
||||
|
@ -287,7 +286,7 @@ void TPinballTable::ChangeBallCount(int count)
|
|||
|
||||
void TPinballTable::tilt(float time)
|
||||
{
|
||||
if (!TiltLockFlag && !BallInSink)
|
||||
if (!TiltLockFlag && !BallInDrainFlag)
|
||||
{
|
||||
pinball::InfoTextBox->Clear();
|
||||
pinball::MissTextBox->Clear();
|
||||
|
@ -452,6 +451,9 @@ int TPinballTable::Message(int code, float value)
|
|||
LightShowTimer = timer::set(time, this, LightShow_timeout);
|
||||
}
|
||||
|
||||
// Multi-ball is FT exclusive feature, at least for now.
|
||||
if (pb::FullTiltMode)
|
||||
MultiballFlag = true;
|
||||
midi::play_track(MidiTracks::Track1, true);
|
||||
break;
|
||||
case 1018:
|
||||
|
@ -573,9 +575,9 @@ int TPinballTable::Message(int code, float value)
|
|||
ScoreSpecial3Flag = 0;
|
||||
UnknownP71 = 0;
|
||||
ExtraBalls = 0;
|
||||
UnknownP75 = 0;
|
||||
MultiballCount = 0;
|
||||
BallLockedCounter = 0;
|
||||
MultiballFlag = 0;
|
||||
MultiballFlag = false;
|
||||
UnknownP78 = 0;
|
||||
ReplayActiveFlag = 0;
|
||||
ReplayTimer = 0;
|
||||
|
@ -589,6 +591,63 @@ int TPinballTable::Message(int code, float value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
TBall* TPinballTable::AddBall(float x, float y)
|
||||
{
|
||||
TBall* ball = nullptr;
|
||||
|
||||
for (auto curBall : BallList)
|
||||
{
|
||||
if (!curBall->ActiveFlag)
|
||||
{
|
||||
ball = curBall;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ball != nullptr)
|
||||
{
|
||||
ball->ActiveFlag = 1;
|
||||
ball->Position.Z = ball->Offset;
|
||||
ball->Direction = {};
|
||||
ball->Speed = 0;
|
||||
ball->TimeDelta = 0;
|
||||
ball->TimeNow = 0;
|
||||
ball->EdgeCollisionCount = 0;
|
||||
ball->CollisionFlag = 0;
|
||||
ball->CollisionMask = 1;
|
||||
ball->CollisionComp = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BallList.size() >= 20)
|
||||
return nullptr;
|
||||
ball = new TBall(this);
|
||||
BallList.push_back(ball);
|
||||
}
|
||||
|
||||
ball->Position.X = x;
|
||||
ball->Position.Y = y;
|
||||
|
||||
return ball;
|
||||
}
|
||||
|
||||
int TPinballTable::BallCountInRect(const RectF& rect)
|
||||
{
|
||||
int count = 0;
|
||||
for (const auto ball : BallList)
|
||||
{
|
||||
if (ball->ActiveFlag &&
|
||||
ball->Position.X >= rect.XMin &&
|
||||
ball->Position.Y >= rect.YMin &&
|
||||
ball->Position.X <= rect.XMax &&
|
||||
ball->Position.Y <= rect.YMax)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void TPinballTable::EndGame_timeout(int timerId, void* caller)
|
||||
{
|
||||
auto table = static_cast<TPinballTable*>(caller);
|
||||
|
|
|
@ -9,6 +9,7 @@ class TPlunger;
|
|||
class TDrain;
|
||||
class TDemo;
|
||||
class TLightGroup;
|
||||
struct RectF;
|
||||
|
||||
struct score_struct_super
|
||||
{
|
||||
|
@ -34,6 +35,8 @@ public:
|
|||
void tilt(float time);
|
||||
void port_draw() override;
|
||||
int Message(int code, float value) override;
|
||||
TBall* AddBall(float x, float y);
|
||||
int BallCountInRect(const RectF& rect);
|
||||
|
||||
static void EndGame_timeout(int timerId, void* caller);
|
||||
static void LightShow_timeout(int timerId, void* caller);
|
||||
|
@ -49,7 +52,7 @@ public:
|
|||
int SoundIndex1{};
|
||||
int SoundIndex2{};
|
||||
int SoundIndex3{};
|
||||
int BallInSink;
|
||||
int BallInDrainFlag;
|
||||
int CurScore{};
|
||||
int CurScoreE9{};
|
||||
int LightShowTimer;
|
||||
|
@ -86,9 +89,9 @@ public:
|
|||
int BallCount{};
|
||||
int MaxBallCount;
|
||||
int ExtraBalls{};
|
||||
int UnknownP75{};
|
||||
int MultiballCount{};
|
||||
int BallLockedCounter{};
|
||||
int MultiballFlag;
|
||||
bool MultiballFlag;
|
||||
int UnknownP78{};
|
||||
int ReplayActiveFlag{};
|
||||
int ReplayTimer;
|
||||
|
|
|
@ -23,11 +23,17 @@ TPlunger::TPlunger(TPinballTable* table, int groupIndex) : TCollisionComponent(t
|
|||
SoundIndexP2 = visual.SoundIndex3;
|
||||
HardHitSoundId = visual.Kicker.HardHitSoundId;
|
||||
Threshold = 1000000000.0;
|
||||
MaxPullback = 100;
|
||||
|
||||
// In FT, default max pullback is 50.
|
||||
if (pb::FullTiltMode)
|
||||
MaxPullback = 50;
|
||||
else
|
||||
MaxPullback = 100;
|
||||
|
||||
Elasticity = 0.5f;
|
||||
Smoothness = 0.5f;
|
||||
PullbackIncrement = static_cast<int>(100.0 / (ListBitmap->size() * 8.0));
|
||||
Unknown4F = 0.025f;
|
||||
PullbackIncrement = MaxPullback / (ListBitmap->size() * 8.0f);
|
||||
PullbackDelay = 0.025f;
|
||||
float* floatArr = loader::query_float_attribute(groupIndex, 0, 601);
|
||||
table->PlungerPositionX = floatArr[0];
|
||||
table->PlungerPositionY = floatArr[1];
|
||||
|
@ -35,10 +41,19 @@ TPlunger::TPlunger(TPinballTable* table, int groupIndex) : TCollisionComponent(t
|
|||
|
||||
void TPlunger::Collision(TBall* ball, vector2* nextPosition, vector2* direction, float distance, TEdgeSegment* edge)
|
||||
{
|
||||
if (PinballTable->TiltLockFlag)
|
||||
Message(1017, 0.0);
|
||||
auto boost = RandFloat() * Boost * 0.1f + Boost;
|
||||
maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, Threshold, boost);
|
||||
if (PinballTable->TiltLockFlag || SomeCounter > 0)
|
||||
{
|
||||
auto boost = RandFloat() * MaxPullback * 0.1f + MaxPullback;
|
||||
maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, 0, boost);
|
||||
if (SomeCounter)
|
||||
SomeCounter--;
|
||||
Message(1005, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto boost = RandFloat() * Boost * 0.1f + Boost;
|
||||
maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, Threshold, boost);
|
||||
}
|
||||
}
|
||||
|
||||
int TPlunger::Message(int code, float value)
|
||||
|
@ -46,56 +61,76 @@ int TPlunger::Message(int code, float value)
|
|||
switch (code)
|
||||
{
|
||||
case 1004:
|
||||
if (!PullbackTimer_)
|
||||
if (!PullbackStartedFlag && PinballTable->MultiballCount > 0 && !PinballTable->TiltLockFlag)
|
||||
{
|
||||
PullbackStartedFlag = true;
|
||||
Boost = 0.0;
|
||||
Threshold = 1000000000.0;
|
||||
loader::play_sound(HardHitSoundId, this, "TPlunger1");
|
||||
PullbackTimer(0, this);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
case 1015:
|
||||
{
|
||||
auto ball = PinballTable->BallList.at(0);
|
||||
ball->Message(1024, 0.0);
|
||||
ball->Position.X = PinballTable->PlungerPositionX;
|
||||
ball->Position.Y = PinballTable->PlungerPositionY;
|
||||
ball->ActiveFlag = 1;
|
||||
PinballTable->BallInSink = 0;
|
||||
pb::tilt_no_more();
|
||||
control::handler(code, this);
|
||||
return 0;
|
||||
RectF rect{};
|
||||
rect.XMin = PinballTable->CollisionCompOffset * -1.2f + PinballTable->PlungerPositionX;
|
||||
rect.XMax = PinballTable->CollisionCompOffset * 1.2f + PinballTable->PlungerPositionX;
|
||||
rect.YMin = PinballTable->CollisionCompOffset * -1.2f + PinballTable->PlungerPositionY;
|
||||
rect.YMax = PinballTable->CollisionCompOffset * 1.2f + PinballTable->PlungerPositionY;
|
||||
if(PinballTable->BallCountInRect(rect))
|
||||
{
|
||||
timer::set(1.0f, this, BallFeedTimer);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ball = PinballTable->AddBall(PinballTable->PlungerPositionX, PinballTable->PlungerPositionY);
|
||||
assertm(ball, "Failure to create ball in plunger");
|
||||
PinballTable->MultiballCount++;
|
||||
PinballTable->BallInDrainFlag = 0;
|
||||
pb::tilt_no_more();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1016:
|
||||
if (BallFeedTimer_)
|
||||
timer::kill(BallFeedTimer_);
|
||||
BallFeedTimer_ = timer::set(0.95999998f, this, BallFeedTimer);
|
||||
timer::set(0.95999998f, this, BallFeedTimer);
|
||||
loader::play_sound(SoundIndexP1, this, "TPlunger2");
|
||||
control::handler(code, this);
|
||||
return 0;
|
||||
break;
|
||||
case 1017:
|
||||
Threshold = 0.0;
|
||||
Boost = static_cast<float>(MaxPullback);
|
||||
timer::set(0.2f, this, PlungerReleasedTimer);
|
||||
PullbackStartedFlag = true;
|
||||
Boost = MaxPullback;
|
||||
Message(1005, 0.0f);
|
||||
break;
|
||||
case 1018:
|
||||
SomeCounter++;
|
||||
timer::set(value, this, BallFeedTimer);
|
||||
loader::play_sound(SoundIndexP1, this, "TPlunger2_1");
|
||||
PullbackStartedFlag = true;
|
||||
PullbackTimer(0, this);
|
||||
break;
|
||||
case 1020:
|
||||
PullbackStartedFlag = false;
|
||||
Boost = 0.0f;
|
||||
Threshold = 1000000000.0f;
|
||||
SomeCounter = 0;
|
||||
timer::kill(BallFeedTimer);
|
||||
timer::kill(PullbackTimer);
|
||||
timer::kill(ReleasedTimer);
|
||||
break;
|
||||
case 1011:
|
||||
SomeCounter = 0;
|
||||
timer::kill(BallFeedTimer);
|
||||
break;
|
||||
case 1005:
|
||||
case 1009:
|
||||
case 1010:
|
||||
case 1024:
|
||||
if (PullbackStartedFlag && !SomeCounter)
|
||||
{
|
||||
if (code == 1024)
|
||||
{
|
||||
if (BallFeedTimer_)
|
||||
timer::kill(BallFeedTimer_);
|
||||
BallFeedTimer_ = 0;
|
||||
}
|
||||
|
||||
PullbackStartedFlag = false;
|
||||
Threshold = 0.0;
|
||||
if (PullbackTimer_)
|
||||
timer::kill(PullbackTimer_);
|
||||
PullbackTimer_ = 0;
|
||||
if (code == 1005)
|
||||
loader::play_sound(SoundIndexP2, this, "TPlunger3");
|
||||
loader::play_sound(SoundIndexP2, this, "TPlunger3");
|
||||
auto bmp = ListBitmap->at(0);
|
||||
auto zMap = ListZMap->at(0);
|
||||
render::sprite_set(
|
||||
|
@ -105,38 +140,68 @@ int TPlunger::Message(int code, float value)
|
|||
bmp->XPosition - PinballTable->XOffset,
|
||||
bmp->YPosition - PinballTable->YOffset);
|
||||
|
||||
timer::set(Unknown4F, this, PlungerReleasedTimer);
|
||||
break;
|
||||
timer::set(PullbackDelay, this, ReleasedTimer);
|
||||
}
|
||||
break;
|
||||
case 1024:
|
||||
{
|
||||
PullbackStartedFlag = false;
|
||||
Boost = 0.0f;
|
||||
Threshold = 1000000000.0f;
|
||||
SomeCounter = 0;
|
||||
|
||||
timer::kill(BallFeedTimer);
|
||||
timer::kill(PullbackTimer);
|
||||
timer::kill(ReleasedTimer);
|
||||
|
||||
auto bmp = ListBitmap->at(0);
|
||||
auto zMap = ListZMap->at(0);
|
||||
render::sprite_set(
|
||||
RenderSprite,
|
||||
bmp,
|
||||
zMap,
|
||||
bmp->XPosition - PinballTable->XOffset,
|
||||
bmp->YPosition - PinballTable->YOffset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
control::handler(code, this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TPlunger::BallFeedTimer(int timerId, void* caller)
|
||||
{
|
||||
auto plunger = static_cast<TPlunger*>(caller);
|
||||
plunger->PullbackTimer_ = 0;
|
||||
plunger->Message(1015, 0.0);
|
||||
}
|
||||
|
||||
void TPlunger::PullbackTimer(int timerId, void* caller)
|
||||
{
|
||||
auto plunger = static_cast<TPlunger*>(caller);
|
||||
plunger->Boost += static_cast<float>(plunger->PullbackIncrement);
|
||||
if (plunger->Boost <= static_cast<float>(plunger->MaxPullback))
|
||||
plunger->Boost += plunger->PullbackIncrement;
|
||||
if (plunger->Boost <= plunger->MaxPullback)
|
||||
{
|
||||
plunger->PullbackTimer_ = timer::set(plunger->Unknown4F, plunger, PullbackTimer);
|
||||
if (plunger->SomeCounter)
|
||||
{
|
||||
plunger->PullbackTimer_ = timer::set(plunger->PullbackDelay / 4.0f, plunger, PullbackTimer);
|
||||
}
|
||||
else
|
||||
{
|
||||
plunger->PullbackTimer_ = timer::set(plunger->PullbackDelay, plunger, PullbackTimer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plunger->PullbackTimer_ = 0;
|
||||
plunger->Boost = static_cast<float>(plunger->MaxPullback);
|
||||
plunger->Boost = plunger->MaxPullback;
|
||||
}
|
||||
|
||||
int index = static_cast<int>(floor(
|
||||
static_cast<float>(plunger->ListBitmap->size() - 1) *
|
||||
(plunger->Boost / static_cast<float>(plunger->MaxPullback))));
|
||||
(plunger->Boost / plunger->MaxPullback)));
|
||||
auto bmp = plunger->ListBitmap->at(index);
|
||||
auto zMap = plunger->ListZMap->at(index);
|
||||
render::sprite_set(
|
||||
|
@ -147,7 +212,7 @@ void TPlunger::PullbackTimer(int timerId, void* caller)
|
|||
bmp->YPosition - plunger->PinballTable->YOffset);
|
||||
}
|
||||
|
||||
void TPlunger::PlungerReleasedTimer(int timerId, void* caller)
|
||||
void TPlunger::ReleasedTimer(int timerId, void* caller)
|
||||
{
|
||||
auto plunger = static_cast<TPlunger*>(caller);
|
||||
plunger->Threshold = 1000000000.0;
|
||||
|
|
|
@ -13,13 +13,15 @@ public:
|
|||
|
||||
static void BallFeedTimer(int timerId, void* caller);
|
||||
static void PullbackTimer(int timerId, void* caller);
|
||||
static void PlungerReleasedTimer(int timerId, void* caller);
|
||||
static void ReleasedTimer(int timerId, void* caller);
|
||||
|
||||
int PullbackTimer_;
|
||||
int BallFeedTimer_;
|
||||
int MaxPullback;
|
||||
int PullbackIncrement;
|
||||
float Unknown4F;
|
||||
float MaxPullback;
|
||||
float PullbackIncrement;
|
||||
float PullbackDelay;
|
||||
int SoundIndexP1;
|
||||
int SoundIndexP2;
|
||||
bool PullbackStartedFlag{};
|
||||
int SomeCounter{};
|
||||
};
|
||||
|
|
|
@ -14,13 +14,12 @@ TSink::TSink(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
|
|||
visualStruct visual{};
|
||||
|
||||
MessageField = 0;
|
||||
Timer = 0;
|
||||
loader::query_visual(groupIndex, 0, &visual);
|
||||
loader::query_visual(groupIndex, 0, &visual);
|
||||
BallThrowDirection = visual.Kicker.ThrowBallDirection;
|
||||
ThrowAngleMult = visual.Kicker.ThrowBallAngleMult;
|
||||
ThrowSpeedMult1 = visual.Kicker.Boost;
|
||||
ThrowSpeedMult2 = visual.Kicker.ThrowBallMult * 0.01f;
|
||||
SoundIndex4 = visual.SoundIndex4;
|
||||
SoundIndex4 = visual.SoundIndex4;
|
||||
SoundIndex3 = visual.SoundIndex3;
|
||||
auto floatArr = loader::query_float_attribute(groupIndex, 0, 601);
|
||||
BallPosition.X = floatArr[0];
|
||||
|
@ -35,27 +34,19 @@ int TSink::Message(int code, float value)
|
|||
case 56:
|
||||
if (value < 0.0f)
|
||||
value = TimerTime;
|
||||
Timer = timer::set(value, this, TimerExpired);
|
||||
timer::set(value, this, TimerExpired);
|
||||
break;
|
||||
case 1020:
|
||||
timer::kill(TimerExpired);
|
||||
PlayerMessagefieldBackup[PinballTable->CurrentPlayer] = MessageField;
|
||||
MessageField = PlayerMessagefieldBackup[static_cast<int>(floor(value))];
|
||||
break;
|
||||
case 1024:
|
||||
{
|
||||
if (Timer)
|
||||
timer::kill(Timer);
|
||||
Timer = 0;
|
||||
timer::kill(TimerExpired);
|
||||
MessageField = 0;
|
||||
|
||||
auto playerPtr = PlayerMessagefieldBackup;
|
||||
for (auto index = 0; index < PinballTable->PlayerCount; ++index)
|
||||
{
|
||||
*playerPtr = 0;
|
||||
|
||||
++playerPtr;
|
||||
}
|
||||
|
||||
for (auto &msgBackup : PlayerMessagefieldBackup)
|
||||
msgBackup = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -66,15 +57,13 @@ int TSink::Message(int code, float value)
|
|||
|
||||
void TSink::Collision(TBall* ball, vector2* nextPosition, vector2* direction, float distance, TEdgeSegment* edge)
|
||||
{
|
||||
Timer = 0;
|
||||
if (PinballTable->TiltLockFlag)
|
||||
{
|
||||
maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, 1000000000.0, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ball->ActiveFlag = 0;
|
||||
render::sprite_set_bitmap(ball->RenderSprite, nullptr);
|
||||
ball->Disable();
|
||||
loader::play_sound(SoundIndex4, ball, "TSink1");
|
||||
control::handler(63, this);
|
||||
}
|
||||
|
@ -82,15 +71,26 @@ void TSink::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl
|
|||
|
||||
void TSink::TimerExpired(int timerId, void* caller)
|
||||
{
|
||||
RectF rect{};
|
||||
|
||||
auto sink = static_cast<TSink*>(caller);
|
||||
auto ball = sink->PinballTable->BallList.at(0);
|
||||
ball->CollisionComp = nullptr;
|
||||
ball->ActiveFlag = 1;
|
||||
ball->Position.X = sink->BallPosition.X;
|
||||
ball->Position.Y = sink->BallPosition.Y;
|
||||
TBall::throw_ball(ball, &sink->BallThrowDirection, sink->ThrowAngleMult, sink->ThrowSpeedMult1,
|
||||
sink->ThrowSpeedMult2);
|
||||
if (sink->SoundIndex3)
|
||||
loader::play_sound(sink->SoundIndex3, ball, "TSink2");
|
||||
sink->Timer = 0;
|
||||
auto table = sink->PinballTable;
|
||||
|
||||
rect.XMin = table->CollisionCompOffset * -2.0f + sink->BallPosition.X;
|
||||
rect.XMax = table->CollisionCompOffset * 2.0f + sink->BallPosition.X;
|
||||
rect.YMin = table->CollisionCompOffset * -2.0f + sink->BallPosition.Y;
|
||||
rect.YMax = table->CollisionCompOffset * 2.0f + sink->BallPosition.Y;
|
||||
if (table->BallCountInRect(rect))
|
||||
{
|
||||
timer::set(0.5f, sink, TimerExpired);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ball = table->AddBall(sink->BallPosition.X, sink->BallPosition.Y);
|
||||
assertm(ball, "Failure to create ball in sink");
|
||||
TBall::throw_ball(ball, &sink->BallThrowDirection, sink->ThrowAngleMult, sink->ThrowSpeedMult1,
|
||||
sink->ThrowSpeedMult2);
|
||||
if (sink->SoundIndex3)
|
||||
loader::play_sound(sink->SoundIndex3, ball, "TSink2");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ public:
|
|||
|
||||
static void TimerExpired(int timerId, void* caller);
|
||||
|
||||
int Timer;
|
||||
float TimerTime;
|
||||
vector2 BallPosition{};
|
||||
vector3 BallThrowDirection{};
|
||||
|
|
|
@ -108,6 +108,9 @@ component_tag<TLight> control_lite27_tag = {"lite27"};
|
|||
component_tag<TLight> control_lite28_tag = {"lite28"};
|
||||
component_tag<TLight> control_lite29_tag = {"lite29"};
|
||||
component_tag<TLight> control_lite30_tag = {"lite30"};
|
||||
component_tag<TLight> control_lite38_tag = {"lite38"};
|
||||
component_tag<TLight> control_lite39_tag = {"lite39"};
|
||||
component_tag<TLight> control_lite40_tag = {"lite40"};
|
||||
component_tag<TLight> control_lite54_tag = {"lite54"};
|
||||
component_tag<TLight> control_lite55_tag = {"lite55"};
|
||||
component_tag<TLight> control_lite56_tag = {"lite56"};
|
||||
|
@ -341,6 +344,9 @@ TLight*& lite27 = control_lite27_tag.Component;
|
|||
TLight*& lite28 = control_lite28_tag.Component;
|
||||
TLight*& lite29 = control_lite29_tag.Component;
|
||||
TLight*& lite30 = control_lite30_tag.Component;
|
||||
TLight*& lite38 = control_lite38_tag.Component;
|
||||
TLight*& lite39 = control_lite39_tag.Component;
|
||||
TLight*& lite40 = control_lite40_tag.Component;
|
||||
TLight*& lite54 = control_lite54_tag.Component;
|
||||
TLight*& lite55 = control_lite55_tag.Component;
|
||||
TLight*& lite56 = control_lite56_tag.Component;
|
||||
|
@ -615,7 +621,7 @@ component_info control::score_components[88]
|
|||
};
|
||||
|
||||
|
||||
component_tag_base* control::simple_components[142]
|
||||
component_tag_base* control::simple_components[145]
|
||||
{
|
||||
&control_lite8_tag,
|
||||
&control_lite9_tag,
|
||||
|
@ -758,7 +764,10 @@ component_tag_base* control::simple_components[142]
|
|||
&control_lite322_tag,
|
||||
&control_goal_lights_tag,
|
||||
&control_soundwave25_tag,
|
||||
&control_soundwave7_tag
|
||||
&control_soundwave7_tag,
|
||||
&control_lite38_tag,
|
||||
&control_lite39_tag,
|
||||
&control_lite40_tag,
|
||||
};
|
||||
|
||||
int control::waiting_deployment_flag;
|
||||
|
@ -953,25 +962,40 @@ void control::table_set_flag_lights()
|
|||
info_text_box->Display(pinball::get_rc_string(51, 0), 2.0);
|
||||
}
|
||||
|
||||
void control::table_set_multiball()
|
||||
void control::table_set_multiball(float time)
|
||||
{
|
||||
info_text_box->Display(pinball::get_rc_string(16, 0), 2.0);
|
||||
midi::play_track(MidiTracks::Track3, true);
|
||||
if (TableG->MultiballCount <= 1)
|
||||
{
|
||||
TableG->MultiballCount += 3;
|
||||
sink1->Message(56, time);
|
||||
sink2->Message(56, time);
|
||||
sink3->Message(56, time);
|
||||
lite38->Message(7, -1.0f);
|
||||
lite39->Message(7, -1.0f);
|
||||
lite40->Message(7, -1.0f);
|
||||
info_text_box->Display(pinball::get_rc_string(16, 0), 2.0);
|
||||
midi::play_track(MidiTracks::Track3, true);
|
||||
}
|
||||
}
|
||||
|
||||
void control::table_bump_ball_sink_lock()
|
||||
{
|
||||
if (TableG->BallLockedCounter == 2)
|
||||
if (TableG->MultiballCount <= 1)
|
||||
{
|
||||
table_set_multiball();
|
||||
TableG->BallLockedCounter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
TableG->BallLockedCounter = TableG->BallLockedCounter + 1;
|
||||
soundwave44->Play(nullptr, "table_bump_ball_sink_lock");
|
||||
info_text_box->Display(pinball::get_rc_string(1, 0), 2.0);
|
||||
TableG->Plunger->Message(1016, 0.0);
|
||||
TableG->MultiballCount--;
|
||||
if (TableG->BallLockedCounter == 2)
|
||||
{
|
||||
soundwave41->Play(nullptr, "table_bump_ball_sink_lock_set_multiball");
|
||||
table_set_multiball(2.0);
|
||||
TableG->BallLockedCounter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
TableG->BallLockedCounter = TableG->BallLockedCounter + 1;
|
||||
soundwave44->Play(nullptr, "table_bump_ball_sink_lock");
|
||||
info_text_box->Display(pinball::get_rc_string(1, 0), 2.0);
|
||||
TableG->Plunger->Message(1018, 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1630,19 +1654,30 @@ void control::WormHoleControl(int code, TPinballComponent* caller)
|
|||
{
|
||||
if (TableG->MultiballFlag)
|
||||
{
|
||||
table_bump_ball_sink_lock();
|
||||
TableG->AddScore(10000);
|
||||
if (TableG->MultiballCount == 1)
|
||||
{
|
||||
table_bump_ball_sink_lock();
|
||||
TableG->AddScore(10000);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
table_set_replay(4.0);
|
||||
TableG->AddScore(50000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info_text_box->Display(pinball::get_rc_string(49, 0), 2.0);
|
||||
|
||||
table_set_replay(4.0);
|
||||
TableG->AddScore(sink->get_scoring(1));
|
||||
wormhole_tag_array2[sinkFlag]->GetComponent()->Message(16, sink->TimerTime);
|
||||
wormhole_tag_array3[sinkFlag]->GetComponent()->Message(11, static_cast<float>(2 - sinkFlag));
|
||||
wormhole_tag_array3[sinkFlag]->GetComponent()->Message(16, sink->TimerTime);
|
||||
wormhole_tag_array1[sinkFlag]->GetComponent()->Message(56, sink->TimerTime);
|
||||
}
|
||||
|
||||
info_text_box->Display(pinball::get_rc_string(49, 0), 2.0);
|
||||
wormhole_tag_array2[sinkFlag]->GetComponent()->Message(16, sink->TimerTime);
|
||||
wormhole_tag_array3[sinkFlag]->GetComponent()->Message(11, static_cast<float>(2 - sinkFlag));
|
||||
wormhole_tag_array3[sinkFlag]->GetComponent()->Message(16, sink->TimerTime);
|
||||
wormhole_tag_array1[sinkFlag]->GetComponent()->Message(56, sink->TimerTime);
|
||||
return;
|
||||
}
|
||||
TableG->AddScore(sink->get_scoring(2));
|
||||
|
@ -2352,7 +2387,8 @@ void control::HyperspaceKickOutControl(int code, TPinballComponent* caller)
|
|||
|
||||
if (TableG->MultiballFlag)
|
||||
{
|
||||
table_set_multiball();
|
||||
auto duration = soundwave41->Play(nullptr, "HyperspaceKickOutControl_setMultiball");
|
||||
table_set_multiball(duration);
|
||||
}
|
||||
if (TableG->ScoreSpecial3 < 100000)
|
||||
TableG->ScoreSpecial3 = 100000;
|
||||
|
@ -2580,10 +2616,18 @@ void control::BallDrainControl(int code, TPinballComponent* caller)
|
|||
soundwave59->Play(nullptr, "BallDrainControl5");
|
||||
--TableG->UnknownP78;
|
||||
}
|
||||
else if (TableG->UnknownP75)
|
||||
else if (TableG->MultiballCount)
|
||||
{
|
||||
soundwave27->Play(nullptr, "BallDrainControl6");
|
||||
--TableG->UnknownP75;
|
||||
if (TableG->MultiballCount == 1)
|
||||
{
|
||||
lite38->Message(20, 0.0f);
|
||||
lite39->Message(20, 0.0f);
|
||||
midi::play_track(MidiTracks::Track1, false);
|
||||
}
|
||||
else if (TableG->MultiballCount == 2)
|
||||
{
|
||||
lite40->Message(20, 0.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ class control
|
|||
public:
|
||||
static TPinballTable* TableG;
|
||||
static component_info score_components[88];
|
||||
static component_tag_base* simple_components[142];
|
||||
static component_tag_base* simple_components[145];
|
||||
static int waiting_deployment_flag;
|
||||
static bool table_unlimited_balls;
|
||||
static int RankRcArray[9], MissionRcArray[17], mission_select_scores[17];
|
||||
|
@ -79,7 +79,7 @@ public:
|
|||
static void table_set_bonus();
|
||||
static void table_set_jackpot();
|
||||
static void table_set_flag_lights();
|
||||
static void table_set_multiball();
|
||||
static void table_set_multiball(float time);
|
||||
static void table_bump_ball_sink_lock();
|
||||
static void table_set_replay(float value);
|
||||
static void cheat_bump_rank();
|
||||
|
|
|
@ -85,6 +85,11 @@ struct ramp_plane_type
|
|||
vector2 FieldForce;
|
||||
};
|
||||
|
||||
struct RectF
|
||||
{
|
||||
float XMax, YMax, XMin, YMin;
|
||||
};
|
||||
|
||||
enum class FlipperIntersect
|
||||
{
|
||||
none = -1,
|
||||
|
|
|
@ -241,10 +241,16 @@ void pb::ballset(float dx, float dy)
|
|||
{
|
||||
// dx and dy are normalized to window, ideally in [-1, 1]
|
||||
static constexpr float sensitivity = 7000;
|
||||
TBall* ball = MainTable->BallList.at(0);
|
||||
ball->Direction.X = dx * sensitivity;
|
||||
ball->Direction.Y = dy * sensitivity;
|
||||
ball->Speed = maths::normalize_2d(ball->Direction);
|
||||
|
||||
for (auto ball : MainTable->BallList)
|
||||
{
|
||||
if (ball->ActiveFlag)
|
||||
{
|
||||
ball->Direction.X = dx * sensitivity;
|
||||
ball->Direction.Y = dy * sensitivity;
|
||||
ball->Speed = maths::normalize_2d(ball->Direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pb::frame(float dtMilliSec)
|
||||
|
@ -469,33 +475,8 @@ void pb::InputDown(GameInput input)
|
|||
switch (input.Value)
|
||||
{
|
||||
case 'b':
|
||||
TBall* ball;
|
||||
if (MainTable->BallList.empty())
|
||||
{
|
||||
ball = new TBall(MainTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto index = 0u; ;)
|
||||
{
|
||||
ball = MainTable->BallList.at(index);
|
||||
if (!ball->ActiveFlag)
|
||||
break;
|
||||
++index;
|
||||
if (index >= MainTable->BallList.size())
|
||||
{
|
||||
ball = new TBall(MainTable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ball->ActiveFlag = 1;
|
||||
ball->Position.X = 1.0;
|
||||
ball->Position.Z = ball->Offset;
|
||||
ball->Position.Y = 1.0;
|
||||
ball->Direction.Z = 0.0;
|
||||
ball->Direction.Y = 0.0;
|
||||
ball->Direction.X = 0.0;
|
||||
if (MainTable->AddBall(6.0f, 7.0f))
|
||||
MainTable->MultiballCount++;
|
||||
break;
|
||||
case 'h':
|
||||
{
|
||||
|
|
|
@ -61,6 +61,35 @@ int timer::kill(int timerId)
|
|||
return timerId;
|
||||
}
|
||||
|
||||
int timer::kill(void(* callback)(int, void*))
|
||||
{
|
||||
auto count = 0;
|
||||
timer_struct* current = ActiveList, * prev = nullptr;
|
||||
for (auto index = 0; index < Count; index++)
|
||||
{
|
||||
if (current->Callback == callback)
|
||||
{
|
||||
count++;
|
||||
if (prev)
|
||||
prev->NextTimer = current->NextTimer;
|
||||
else
|
||||
ActiveList = current->NextTimer;
|
||||
current->NextTimer = FreeList;
|
||||
FreeList = current;
|
||||
if (--Count == index)
|
||||
break;
|
||||
current = current->NextTimer;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = current;
|
||||
current = current->NextTimer;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int timer::set(float time, void* caller, void (* callback)(int, void*))
|
||||
{
|
||||
if (Count >= MaxCount)
|
||||
|
|
|
@ -15,6 +15,7 @@ public:
|
|||
static int init(int count);
|
||||
static void uninit();
|
||||
static int kill(int timerId);
|
||||
static int kill(void (*callback)(int, void*));
|
||||
static int set(float time, void* caller, void (* callback)(int, void*));
|
||||
static int check();
|
||||
|
||||
|
|
Loading…
Reference in a new issue