mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-11-01 17:20:20 +01:00
714 lines
17 KiB
C++
714 lines
17 KiB
C++
#include "pch.h"
|
|
#include "TPinballTable.h"
|
|
|
|
|
|
#include "control.h"
|
|
#include "loader.h"
|
|
#include "midi.h"
|
|
#include "pb.h"
|
|
#include "render.h"
|
|
#include "TBall.h"
|
|
#include "TBlocker.h"
|
|
#include "TBumper.h"
|
|
#include "TComponentGroup.h"
|
|
#include "TDemo.h"
|
|
#include "TFlagSpinner.h"
|
|
#include "TGate.h"
|
|
#include "THole.h"
|
|
#include "timer.h"
|
|
#include "TKickback.h"
|
|
#include "TKickout.h"
|
|
#include "TLight.h"
|
|
#include "TLightBargraph.h"
|
|
#include "TLightGroup.h"
|
|
#include "TLightRollover.h"
|
|
#include "TOneway.h"
|
|
#include "TPopupTarget.h"
|
|
#include "TRamp.h"
|
|
#include "TRollover.h"
|
|
#include "TSink.h"
|
|
#include "TSoloTarget.h"
|
|
#include "TSound.h"
|
|
#include "TTableLayer.h"
|
|
#include "TTextBox.h"
|
|
#include "TTimer.h"
|
|
#include "TTripwire.h"
|
|
#include "TWall.h"
|
|
#include "TPlunger.h"
|
|
#include "TFlipper.h"
|
|
#include "TDrain.h"
|
|
#include "translations.h"
|
|
|
|
int TPinballTable::score_multipliers[5] = {1, 2, 3, 5, 10};
|
|
|
|
|
|
TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
|
|
{
|
|
int shortArrLength;
|
|
|
|
CurScoreStruct = nullptr;
|
|
ScoreBallcount = nullptr;
|
|
ScorePlayerNumber1 = nullptr;
|
|
BallInDrainFlag = 0;
|
|
ActiveFlag = 1;
|
|
TiltLockFlag = 0;
|
|
EndGameTimeoutTimer = 0;
|
|
LightShowTimer = 0;
|
|
ReplayTimer = 0;
|
|
TiltTimeoutTimer = 0;
|
|
MultiballFlag = false;
|
|
PlayerCount = 0;
|
|
|
|
auto ball = AddBall({0.0f, 0.0f});
|
|
ball->Disable();
|
|
|
|
new TTableLayer(this);
|
|
LightGroup = new TLightGroup(this, 0);
|
|
|
|
auto score1 = score::create("score1", render::background_bitmap);
|
|
CurScoreStruct = score1;
|
|
PlayerScores[0].ScoreStruct = score1;
|
|
for (int scoreIndex = 1; scoreIndex < 4; scoreIndex++)
|
|
{
|
|
PlayerScores[scoreIndex].ScoreStruct = score::dup(CurScoreStruct, scoreIndex);
|
|
}
|
|
|
|
CurrentPlayer = 0;
|
|
MaxBallCount = 3;
|
|
ScoreBallcount = score::create("ballcount1", render::background_bitmap);
|
|
ScorePlayerNumber1 = score::create("player_number1", render::background_bitmap);
|
|
int groupIndexObjects = loader::query_handle("table_objects");
|
|
|
|
short* shortArr = loader::query_iattribute(groupIndexObjects, 1025, &shortArrLength);
|
|
if (shortArrLength > 0)
|
|
{
|
|
for (int i = 0; i < shortArrLength / 2; ++i)
|
|
{
|
|
int objectType = *shortArr;
|
|
short* shortArrPlus1 = shortArr + 1;
|
|
int groupIndex = *shortArrPlus1;
|
|
shortArr = shortArrPlus1 + 1;
|
|
switch (objectType)
|
|
{
|
|
case 1000:
|
|
case 1010:
|
|
new TWall(this, groupIndex);
|
|
break;
|
|
case 1001:
|
|
Plunger = new TPlunger(this, groupIndex);
|
|
break;
|
|
case 1002:
|
|
LightGroup->List.push_back(new TLight(this, groupIndex));
|
|
break;
|
|
case 1003:
|
|
FlipperL = new TFlipper(this, groupIndex);
|
|
break;
|
|
case 1004:
|
|
FlipperR = new TFlipper(this, groupIndex);
|
|
break;
|
|
case 1005:
|
|
new TBumper(this, groupIndex);
|
|
break;
|
|
case 1006:
|
|
new TPopupTarget(this, groupIndex);
|
|
break;
|
|
case 1007:
|
|
Drain = new TDrain(this, groupIndex);
|
|
break;
|
|
case 1011:
|
|
new TBlocker(this, groupIndex);
|
|
break;
|
|
case 1012:
|
|
new TKickout(this, groupIndex, true);
|
|
break;
|
|
case 1013:
|
|
new TGate(this, groupIndex);
|
|
break;
|
|
case 1014:
|
|
new TKickback(this, groupIndex);
|
|
break;
|
|
case 1015:
|
|
new TRollover(this, groupIndex);
|
|
break;
|
|
case 1016:
|
|
new TOneway(this, groupIndex);
|
|
break;
|
|
case 1017:
|
|
new TSink(this, groupIndex);
|
|
break;
|
|
case 1018:
|
|
new TFlagSpinner(this, groupIndex);
|
|
break;
|
|
case 1019:
|
|
new TSoloTarget(this, groupIndex);
|
|
break;
|
|
case 1020:
|
|
new TLightRollover(this, groupIndex);
|
|
break;
|
|
case 1021:
|
|
new TRamp(this, groupIndex);
|
|
break;
|
|
case 1022:
|
|
new THole(this, groupIndex);
|
|
break;
|
|
case 1023:
|
|
new TDemo(this, groupIndex);
|
|
break;
|
|
case 1024:
|
|
new TTripwire(this, groupIndex);
|
|
break;
|
|
case 1026:
|
|
new TLightGroup(this, groupIndex);
|
|
break;
|
|
case 1028:
|
|
new TComponentGroup(this, groupIndex);
|
|
break;
|
|
case 1029:
|
|
new TKickout(this, groupIndex, false);
|
|
break;
|
|
case 1030:
|
|
new TLightBargraph(this, groupIndex);
|
|
break;
|
|
case 1031:
|
|
new TSound(this, groupIndex);
|
|
break;
|
|
case 1032:
|
|
new TTimer(this, groupIndex);
|
|
break;
|
|
case 1033:
|
|
new TTextBox(this, groupIndex);
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
render::build_occlude_list();
|
|
pb::InfoTextBox = dynamic_cast<TTextBox*>(find_component("info_text_box"));
|
|
pb::MissTextBox = dynamic_cast<TTextBox*>(find_component("mission_text_box"));
|
|
control::make_links(this);
|
|
}
|
|
|
|
|
|
TPinballTable::~TPinballTable()
|
|
{
|
|
for (auto& PlayerScore : PlayerScores)
|
|
{
|
|
delete PlayerScore.ScoreStruct;
|
|
}
|
|
if (ScorePlayerNumber1)
|
|
{
|
|
delete ScorePlayerNumber1;
|
|
ScorePlayerNumber1 = nullptr;
|
|
}
|
|
if (ScoreBallcount)
|
|
{
|
|
delete ScoreBallcount;
|
|
ScoreBallcount = nullptr;
|
|
}
|
|
delete LightGroup;
|
|
while (!ComponentList.empty())
|
|
{
|
|
// Component destructor removes it from the list.
|
|
delete ComponentList[0];
|
|
}
|
|
control::ClearLinks();
|
|
pb::InfoTextBox = pb::MissTextBox = nullptr;
|
|
}
|
|
|
|
TPinballComponent* TPinballTable::find_component(LPCSTR componentName)
|
|
{
|
|
for (auto component : ComponentList)
|
|
{
|
|
const char* groupName = component->GroupName;
|
|
if (groupName && !strcmp(groupName, componentName))
|
|
{
|
|
return component;
|
|
}
|
|
}
|
|
|
|
pb::ShowMessageBox(SDL_MESSAGEBOX_WARNING, "Table cant find:", componentName);
|
|
return nullptr;
|
|
}
|
|
|
|
TPinballComponent* TPinballTable::find_component(int groupIndex)
|
|
{
|
|
char Buffer[40]{};
|
|
for (auto component : ComponentList)
|
|
{
|
|
if (component->GroupIndex == groupIndex)
|
|
return component;
|
|
}
|
|
|
|
snprintf(Buffer, sizeof Buffer, "%d", groupIndex);
|
|
pb::ShowMessageBox(SDL_MESSAGEBOX_WARNING, "Table cant find (lh):", Buffer);
|
|
return nullptr;
|
|
}
|
|
|
|
int TPinballTable::AddScore(int score)
|
|
{
|
|
if (JackpotScoreFlag)
|
|
{
|
|
JackpotScore += score;
|
|
const auto jackpotLimit = !pb::FullTiltMode ? 5000000 : 10000000;
|
|
if (JackpotScore > jackpotLimit)
|
|
JackpotScore = jackpotLimit;
|
|
}
|
|
if (BonusScoreFlag)
|
|
{
|
|
BonusScore += score;
|
|
if (BonusScore > 5000000)
|
|
BonusScore = 5000000;
|
|
}
|
|
int addedScore = ScoreAdded + score * score_multipliers[ScoreMultiplier];
|
|
CurScore += addedScore;
|
|
if (CurScore > 1000000000)
|
|
{
|
|
++CurScoreE9;
|
|
CurScore = CurScore - 1000000000;
|
|
}
|
|
score::set(CurScoreStruct, CurScore);
|
|
return addedScore;
|
|
}
|
|
|
|
void TPinballTable::ChangeBallCount(int count)
|
|
{
|
|
BallCount = count;
|
|
if (count <= 0)
|
|
{
|
|
score::erase(ScoreBallcount, 1);
|
|
}
|
|
else
|
|
{
|
|
score::set(ScoreBallcount, MaxBallCount - count + 1);
|
|
score::update(ScoreBallcount);
|
|
}
|
|
}
|
|
|
|
void TPinballTable::tilt(float time)
|
|
{
|
|
if (!TiltLockFlag && !BallInDrainFlag)
|
|
{
|
|
pb::InfoTextBox->Clear();
|
|
pb::MissTextBox->Clear();
|
|
pb::InfoTextBox->Display(pb::get_rc_string(Msg::STRING136), -1.0);
|
|
loader::play_sound(SoundIndex3, nullptr, "TPinballTable1");
|
|
TiltTimeoutTimer = timer::set(30.0, this, tilt_timeout);
|
|
|
|
for (auto component : ComponentList)
|
|
{
|
|
component->Message(MessageCode::SetTiltLock, time);
|
|
}
|
|
LightGroup->Message(MessageCode::TLightTurnOffTimed, 0);
|
|
TiltLockFlag = 1;
|
|
control::table_control_handler(MessageCode::SetTiltLock);
|
|
}
|
|
}
|
|
|
|
|
|
void TPinballTable::port_draw()
|
|
{
|
|
for (auto component : ComponentList)
|
|
{
|
|
component->port_draw();
|
|
}
|
|
}
|
|
|
|
int TPinballTable::Message(MessageCode code, float value)
|
|
{
|
|
const char* rc_text;
|
|
|
|
switch (code)
|
|
{
|
|
case MessageCode::LeftFlipperInputPressed:
|
|
if (!TiltLockFlag)
|
|
{
|
|
FlipperL->Message(MessageCode::TFlipperExtend, value);
|
|
}
|
|
break;
|
|
case MessageCode::LeftFlipperInputReleased:
|
|
if (!TiltLockFlag)
|
|
{
|
|
FlipperL->Message(MessageCode::TFlipperRetract, value);
|
|
}
|
|
break;
|
|
case MessageCode::RightFlipperInputPressed:
|
|
if (!TiltLockFlag)
|
|
{
|
|
FlipperR->Message(MessageCode::TFlipperExtend, value);
|
|
}
|
|
break;
|
|
case MessageCode::RightFlipperInputReleased:
|
|
if (!TiltLockFlag)
|
|
{
|
|
FlipperR->Message(MessageCode::TFlipperRetract, value);
|
|
}
|
|
break;
|
|
case MessageCode::PlungerInputPressed:
|
|
case MessageCode::PlungerInputReleased:
|
|
Plunger->Message(code, value);
|
|
break;
|
|
case MessageCode::Pause:
|
|
case MessageCode::Resume:
|
|
case MessageCode::LooseFocus:
|
|
for (auto component : ComponentList)
|
|
{
|
|
component->Message(code, value);
|
|
}
|
|
break;
|
|
case MessageCode::ClearTiltLock:
|
|
LightGroup->Message(MessageCode::TLightResetTimed, 0.0);
|
|
if (TiltLockFlag)
|
|
{
|
|
TiltLockFlag = 0;
|
|
if (TiltTimeoutTimer)
|
|
timer::kill(TiltTimeoutTimer);
|
|
TiltTimeoutTimer = 0;
|
|
}
|
|
break;
|
|
case MessageCode::StartGamePlayer1:
|
|
LightGroup->Message(MessageCode::TLightGroupReset, 0.0);
|
|
LightGroup->Message(MessageCode::TLightResetAndTurnOff, 0.0);
|
|
Plunger->Message(MessageCode::PlungerStartFeedTimer, 0.0);
|
|
if (Demo && Demo->ActiveFlag)
|
|
rc_text = pb::get_rc_string(Msg::STRING131);
|
|
else
|
|
rc_text = pb::get_rc_string(Msg::STRING127);
|
|
pb::InfoTextBox->Display(rc_text, -1.0);
|
|
if (Demo)
|
|
Demo->Message(MessageCode::NewGame, 0.0);
|
|
break;
|
|
case MessageCode::NewGame:
|
|
if (EndGameTimeoutTimer)
|
|
{
|
|
timer::kill(EndGameTimeoutTimer);
|
|
EndGame_timeout(0, this);
|
|
pb::mode_change(GameModes::InGame);
|
|
}
|
|
if (LightShowTimer)
|
|
{
|
|
timer::kill(LightShowTimer);
|
|
LightShowTimer = 0;
|
|
Message(MessageCode::StartGamePlayer1, 0.0);
|
|
}
|
|
else
|
|
{
|
|
// Some of the control cheats persist across games.
|
|
// Was this loose anti-cheat by design?
|
|
CheatsUsed = 0;
|
|
Message(MessageCode::Reset, 0.0);
|
|
auto ball = BallList[0];
|
|
ball->Position.Y = 0.0;
|
|
ball->Position.X = 0.0;
|
|
ball->Position.Z = -0.8f;
|
|
|
|
auto playerCount = static_cast<int>(floor(value));
|
|
PlayerCount = playerCount;
|
|
if (playerCount >= 1)
|
|
{
|
|
if (playerCount > 4)
|
|
PlayerCount = 4;
|
|
}
|
|
else
|
|
{
|
|
PlayerCount = 1;
|
|
}
|
|
|
|
auto plr1Score = PlayerScores[0].ScoreStruct;
|
|
CurrentPlayer = 0;
|
|
CurScoreStruct = plr1Score;
|
|
CurScore = 0;
|
|
score::set(plr1Score, 0);
|
|
ScoreMultiplier = 0;
|
|
|
|
for (int plrIndex = 1; plrIndex < PlayerCount; ++plrIndex)
|
|
{
|
|
auto scorePtr = &PlayerScores[plrIndex];
|
|
score::set(scorePtr->ScoreStruct, 0);
|
|
scorePtr->Score = 0;
|
|
scorePtr->ScoreE9Part = 0;
|
|
scorePtr->BallCount = MaxBallCount;
|
|
scorePtr->ExtraBalls = ExtraBalls;
|
|
scorePtr->BallLockedCounter = BallLockedCounter;
|
|
scorePtr->JackpotScore = JackpotScore;
|
|
}
|
|
|
|
BallCount = MaxBallCount;
|
|
ChangeBallCount(BallCount);
|
|
score::set(ScorePlayerNumber1, CurrentPlayer + 1);
|
|
score::update(ScorePlayerNumber1);
|
|
|
|
for (auto scoreIndex = 4 - PlayerCount; scoreIndex > 0; scoreIndex--)
|
|
{
|
|
score::set(PlayerScores[scoreIndex].ScoreStruct, -1);
|
|
}
|
|
|
|
JackpotScoreFlag = false;
|
|
BonusScoreFlag = false;
|
|
UnknownP71 = 0;
|
|
pb::InfoTextBox->Clear();
|
|
pb::MissTextBox->Clear();
|
|
LightGroup->Message(MessageCode::TLightGroupLightShowAnimation, 0.2f);
|
|
auto time = loader::play_sound(SoundIndex1, nullptr, "TPinballTable2");
|
|
if (time < 0)
|
|
time = 5.0f;
|
|
LightShowTimer = timer::set(time, this, LightShow_timeout);
|
|
}
|
|
|
|
if (pb::FullTiltMode)
|
|
{
|
|
// Multi-ball is FT exclusive feature, at least for now.
|
|
MultiballFlag = true;
|
|
JackpotScore = 500000;
|
|
}
|
|
midi::play_track(MidiTracks::Track1, true);
|
|
break;
|
|
case MessageCode::PlungerRelaunchBall:
|
|
if (ReplayTimer)
|
|
timer::kill(ReplayTimer);
|
|
ReplayTimer = timer::set(floor(value), this, replay_timer_callback);
|
|
ReplayActiveFlag = 1;
|
|
break;
|
|
case MessageCode::SwitchToNextPlayer:
|
|
{
|
|
if (PlayerCount <= 1)
|
|
{
|
|
const char* textboxText;
|
|
if (Demo->ActiveFlag)
|
|
textboxText = pb::get_rc_string(Msg::STRING131);
|
|
else
|
|
textboxText = pb::get_rc_string(Msg::STRING127);
|
|
pb::InfoTextBox->Display(textboxText, -1.0);
|
|
break;
|
|
}
|
|
|
|
auto nextPlayer = (CurrentPlayer + 1) % PlayerCount;
|
|
auto nextScorePtr = &PlayerScores[nextPlayer];
|
|
if (nextScorePtr->BallCount <= 0)
|
|
break;
|
|
|
|
PlayerScores[CurrentPlayer].Score = CurScore;
|
|
PlayerScores[CurrentPlayer].ScoreE9Part = CurScoreE9;
|
|
PlayerScores[CurrentPlayer].BallCount = BallCount;
|
|
PlayerScores[CurrentPlayer].ExtraBalls = ExtraBalls;
|
|
PlayerScores[CurrentPlayer].BallLockedCounter = BallLockedCounter;
|
|
PlayerScores[CurrentPlayer].JackpotScore = JackpotScore;
|
|
|
|
CurScore = nextScorePtr->Score;
|
|
CurScoreE9 = nextScorePtr->ScoreE9Part;
|
|
BallCount = nextScorePtr->BallCount;
|
|
ExtraBalls = nextScorePtr->ExtraBalls;
|
|
BallLockedCounter = nextScorePtr->BallLockedCounter;
|
|
JackpotScore = nextScorePtr->JackpotScore;
|
|
|
|
CurScoreStruct = nextScorePtr->ScoreStruct;
|
|
score::set(CurScoreStruct, CurScore);
|
|
CurScoreStruct->DirtyFlag = true;
|
|
|
|
ChangeBallCount(BallCount);
|
|
score::set(ScorePlayerNumber1, nextPlayer + 1);
|
|
score::update(ScorePlayerNumber1);
|
|
|
|
for (auto component : ComponentList)
|
|
{
|
|
component->Message(MessageCode::PlayerChanged, static_cast<float>(nextPlayer));
|
|
}
|
|
|
|
const char* textboxText = nullptr;
|
|
switch (nextPlayer)
|
|
{
|
|
case 0:
|
|
if (Demo->ActiveFlag)
|
|
textboxText = pb::get_rc_string(Msg::STRING131);
|
|
else
|
|
textboxText = pb::get_rc_string(Msg::STRING127);
|
|
break;
|
|
case 1:
|
|
if (Demo->ActiveFlag)
|
|
textboxText = pb::get_rc_string(Msg::STRING132);
|
|
else
|
|
textboxText = pb::get_rc_string(Msg::STRING128);
|
|
break;
|
|
case 2:
|
|
if (Demo->ActiveFlag)
|
|
textboxText = pb::get_rc_string(Msg::STRING133);
|
|
else
|
|
textboxText = pb::get_rc_string(Msg::STRING129);
|
|
break;
|
|
case 3:
|
|
if (Demo->ActiveFlag)
|
|
textboxText = pb::get_rc_string(Msg::STRING134);
|
|
else
|
|
textboxText = pb::get_rc_string(Msg::STRING130);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (textboxText != nullptr)
|
|
pb::InfoTextBox->Display(textboxText, -1);
|
|
JackpotScoreFlag = false;
|
|
BonusScoreFlag = false;
|
|
UnknownP71 = 0;
|
|
CurrentPlayer = nextPlayer;
|
|
}
|
|
break;
|
|
case MessageCode::GameOver:
|
|
loader::play_sound(SoundIndex2, nullptr, "TPinballTable3");
|
|
pb::MissTextBox->Clear();
|
|
pb::InfoTextBox->Display(pb::get_rc_string(Msg::STRING135), -1.0);
|
|
EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout);
|
|
break;
|
|
case MessageCode::Reset:
|
|
for (auto component : ComponentList)
|
|
{
|
|
component->Message(MessageCode::Reset, 0);
|
|
}
|
|
if (ReplayTimer)
|
|
timer::kill(ReplayTimer);
|
|
ReplayTimer = 0;
|
|
if (LightShowTimer)
|
|
{
|
|
timer::kill(LightShowTimer);
|
|
LightGroup->Message(MessageCode::TLightGroupReset, 0.0);
|
|
}
|
|
LightShowTimer = 0;
|
|
ScoreMultiplier = 0;
|
|
ScoreAdded = 0;
|
|
ReflexShotScore = 0;
|
|
BonusScore = 10000;
|
|
BonusScoreFlag = false;
|
|
JackpotScore = 20000;
|
|
JackpotScoreFlag = false;
|
|
UnknownP71 = 0;
|
|
ExtraBalls = 0;
|
|
MultiballCount = 0;
|
|
BallLockedCounter = 0;
|
|
MultiballFlag = false;
|
|
UnknownP78 = 0;
|
|
ReplayActiveFlag = 0;
|
|
ReplayTimer = 0;
|
|
TiltLockFlag = 0;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
control::table_control_handler(code);
|
|
return 0;
|
|
}
|
|
|
|
TBall* TPinballTable::AddBall(vector2 position)
|
|
{
|
|
TBall* ball = nullptr;
|
|
|
|
for (auto curBall : BallList)
|
|
{
|
|
if (!curBall->ActiveFlag)
|
|
{
|
|
ball = curBall;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ball != nullptr)
|
|
{
|
|
ball->ActiveFlag = 1;
|
|
ball->Position.Z = ball->Radius;
|
|
ball->Direction = {};
|
|
ball->Speed = 0;
|
|
ball->TimeDelta = 0;
|
|
ball->EdgeCollisionCount = 0;
|
|
ball->CollisionFlag = 0;
|
|
ball->CollisionMask = 1;
|
|
ball->CollisionComp = nullptr;
|
|
}
|
|
else
|
|
{
|
|
if (BallList.size() >= 20)
|
|
return nullptr;
|
|
ball = new TBall(this, -1);
|
|
BallList.push_back(ball);
|
|
}
|
|
|
|
ball->Position.X = position.X;
|
|
ball->Position.Y = position.Y;
|
|
ball->PrevPosition = ball->Position;
|
|
ball->StuckCounter = 0;
|
|
ball->LastActiveTime = pb::time_ticks;
|
|
|
|
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;
|
|
}
|
|
|
|
int TPinballTable::BallCountInRect(const vector2& pos, float margin)
|
|
{
|
|
RectF rect{};
|
|
rect.XMin = pos.X - margin;
|
|
rect.XMax = pos.X + margin;
|
|
rect.YMin = pos.Y - margin;
|
|
rect.YMax = pos.Y + margin;
|
|
return BallCountInRect(rect);
|
|
}
|
|
|
|
void TPinballTable::EndGame_timeout(int timerId, void* caller)
|
|
{
|
|
auto table = static_cast<TPinballTable*>(caller);
|
|
table->EndGameTimeoutTimer = 0;
|
|
pb::end_game();
|
|
|
|
for (auto component : table->ComponentList)
|
|
{
|
|
component->Message(MessageCode::GameOver, 0);
|
|
}
|
|
if (table->Demo)
|
|
table->Demo->Message(MessageCode::GameOver, 0.0);
|
|
control::handler(MessageCode::ControlMissionStarted, pb::MissTextBox);
|
|
pb::InfoTextBox->Display(pb::get_rc_string(Msg::STRING125), -1.0);
|
|
}
|
|
|
|
void TPinballTable::LightShow_timeout(int timerId, void* caller)
|
|
{
|
|
auto table = static_cast<TPinballTable*>(caller);
|
|
table->LightShowTimer = 0;
|
|
table->Message(MessageCode::StartGamePlayer1, 0.0);
|
|
}
|
|
|
|
void TPinballTable::replay_timer_callback(int timerId, void* caller)
|
|
{
|
|
auto table = static_cast<TPinballTable*>(caller);
|
|
table->ReplayActiveFlag = 0;
|
|
table->ReplayTimer = 0;
|
|
}
|
|
|
|
void TPinballTable::tilt_timeout(int timerId, void* caller)
|
|
{
|
|
auto table = static_cast<TPinballTable*>(caller);
|
|
vector2 vec{};
|
|
|
|
table->TiltTimeoutTimer = 0;
|
|
if (table->TiltLockFlag)
|
|
{
|
|
for (auto ball : table->BallList)
|
|
{
|
|
table->Drain->Collision(ball, &vec, &vec, 0.0, nullptr);
|
|
}
|
|
}
|
|
}
|