From 99fba56a3431012d24d40677dee1451acd6b1396 Mon Sep 17 00:00:00 2001 From: oz Date: Fri, 25 Dec 2020 16:46:06 +0300 Subject: [PATCH] TPinballTable v2. --- .gitignore | 3 +- Doc/FuncStats.xlsx | Bin 37590 -> 37607 bytes SpaceCadetPinball/Sound.cpp | 14 + SpaceCadetPinball/Sound.h | 3 + SpaceCadetPinball/TDemo.cpp | 8 + SpaceCadetPinball/TDemo.h | 4 +- SpaceCadetPinball/TPinballComponent.h | 12 +- SpaceCadetPinball/TPinballTable.cpp | 479 +++++++++++++++++++++++--- SpaceCadetPinball/TPinballTable.h | 116 +++---- SpaceCadetPinball/TTableLayer.cpp | 1 + SpaceCadetPinball/TTableLayer.h | 8 +- SpaceCadetPinball/TTextBox.cpp | 3 + SpaceCadetPinball/control.cpp | 16 +- SpaceCadetPinball/control.h | 3 + SpaceCadetPinball/loader.cpp | 15 +- SpaceCadetPinball/loader.h | 4 +- SpaceCadetPinball/pb.cpp | 8 +- SpaceCadetPinball/score.cpp | 6 +- 18 files changed, 576 insertions(+), 127 deletions(-) diff --git a/.gitignore b/.gitignore index 3c4efe2..14619ec 100644 --- a/.gitignore +++ b/.gitignore @@ -258,4 +258,5 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc \ No newline at end of file +*.pyc +/Ida diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 8c060c7f77afc13e50027b6747cf564256ca052b..106d6c1ab70dfaacabf4f9780be531687641f841 100644 GIT binary patch delta 23606 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 diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index a3686cf..c7c3b38 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -39,3 +39,17 @@ int Sound::AddFactor(int a1, int a2) { return a1 + a2; } + +void Sound::PlaySoundA(int a1, int a2, int a3, unsigned short a4, short a5) +{ +} + +CHAR* Sound::LoadWaveFile(LPCSTR lpName) +{ + return nullptr; +} + +LPCVOID Sound::FreeSound(LPCVOID pMem) +{ + return nullptr; +} diff --git a/SpaceCadetPinball/Sound.h b/SpaceCadetPinball/Sound.h index a79b01f..00951bc 100644 --- a/SpaceCadetPinball/Sound.h +++ b/SpaceCadetPinball/Sound.h @@ -11,4 +11,7 @@ public: static void Close(); static int SubFactor(int a1, int a2); static int AddFactor(int a1, int a2); + static void PlaySound(int a1, int a2, int a3, unsigned __int16 a4, __int16 a5); + static CHAR* LoadWaveFile(LPCSTR lpName); + static LPCVOID FreeSound(LPCVOID pMem); }; diff --git a/SpaceCadetPinball/TDemo.cpp b/SpaceCadetPinball/TDemo.cpp index 2f5c9b1..f1d0b6c 100644 --- a/SpaceCadetPinball/TDemo.cpp +++ b/SpaceCadetPinball/TDemo.cpp @@ -1,2 +1,10 @@ #include "pch.h" #include "TDemo.h" + +#include "TPinballTable.h" + +TDemo::TDemo(TPinballTable* table, int groupIndex) + : TCollisionComponent(table, groupIndex, false) +{ + table->Demo = this; +} diff --git a/SpaceCadetPinball/TDemo.h b/SpaceCadetPinball/TDemo.h index d848cf0..c48ba74 100644 --- a/SpaceCadetPinball/TDemo.h +++ b/SpaceCadetPinball/TDemo.h @@ -5,7 +5,5 @@ class TDemo : public TCollisionComponent { public: - TDemo(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false) - { - } + TDemo(TPinballTable* table, int groupIndex); }; diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index ace4659..0ba7a17 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -1,10 +1,13 @@ #pragma once -#include "control.h" -#include "render.h" -#include "TZmapList.h" - +struct render_sprite_type_struct; +struct component_control; class TPinballTable; +class TZmapList; + +enum class message_code +{ +}; class TPinballComponent { @@ -16,7 +19,6 @@ public: virtual void put_scoring(int scoreId, int value); virtual int get_scoring(int score1); - int VfTable; __int8 UnknownBaseFlag1; __int8 UnknownBaseFlag2; int MessageField; diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index e9d49e1..871ca27 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -5,7 +5,10 @@ #include "control.h" #include "loader.h" #include "memory.h" +#include "pb.h" #include "pinball.h" +#include "render.h" +#include "Sound.h" #include "TBall.h" #include "TBlocker.h" #include "TBumper.h" @@ -14,6 +17,7 @@ #include "TFlagSpinner.h" #include "TGate.h" #include "THole.h" +#include "timer.h" #include "TKickback.h" #include "TKickout.h" #include "TLight.h" @@ -32,48 +36,50 @@ #include "TTimer.h" #include "TTripwire.h" #include "TWall.h" +#include "TPlunger.h" +#include "TFlipper.h" +#include "TDrain.h" + +int TPinballTable::score_multipliers[5] = {1, 2, 3, 5, 10}; + TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) { int shortArrLength; - //this->VfTable = (int)&TPinballTable::`vftable'; ListP1 = new objlist_class(32, 16); ListP2 = new objlist_class(3, 1); - this->Score1 = nullptr; - this->ScoreBallcount = nullptr; - this->ScorePlayerNumber1 = nullptr; - this->UnknownP10 = 0; - this->UnknownBaseFlag2 = 1; - this->UnknownP83 = 0; - this->UnknownP14 = 0; - this->UnknownP13 = 0; - this->UnknownP80 = 0; - this->UnknownP15 = 0; - this->UnknownP77 = 0; + CurScoreStruct = nullptr; + ScoreBallcount = nullptr; + ScorePlayerNumber1 = nullptr; + UnknownP10 = 0; + UnknownBaseFlag2 = 1; + TiltLockFlag = 0; + EndGameTimeoutTimer = 0; + LightShowTimer = 0; + ReplayTimer = 0; + TiltTimeoutTimer = 0; + MultiballFlag = 0; - TBall* ballObj = new TBall(this); + auto ballObj = new TBall(this); ListP2->Add(ballObj); if (ballObj) ballObj->UnknownBaseFlag2 = 0; new TTableLayer(this); - this->LightGroup = new TLightGroup(this, 0); + LightGroup = new TLightGroup(this, 0); auto score1 = score::create("score1", render::background_bitmap); - this->Score1 = score1; - this->Score2 = score1; - int scoreIndex = 1; - auto scorePtr = &this->Score3_x3_at7; - do + CurScoreStruct = score1; + PlayerScores[0].ScoreStruct = score1; + for (int scoreIndex = 1; scoreIndex < 4; scoreIndex++) { - *scorePtr = score::dup(this->Score1, scoreIndex++); - scorePtr += 7; + PlayerScores[scoreIndex].ScoreStruct = score::dup(CurScoreStruct, scoreIndex); } - while (scoreIndex < 4); - this->CurrentPlayer = 0; - this->UnknownP73 = 3; - this->ScoreBallcount = (int*)score::create("ballcount1", render::background_bitmap); - this->ScorePlayerNumber1 = (int*)score::create("player_number1", render::background_bitmap); + + 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); @@ -92,17 +98,17 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) new TWall(this, groupIndex); break; case 1001: - this->Plunger = new TPlunger(this, groupIndex); + Plunger = new TPlunger(this, groupIndex); break; case 1002: new TLight(this, groupIndex); - //((objlist_class*)(this->LightGroup + 42))->Add(light); + //((objlist_class*)(LightGroup + 42))->Add(light); break; case 1003: - this->FlipperL = new TFlipper(this, groupIndex); + FlipperL = new TFlipper(this, groupIndex); break; case 1004: - this->FlipperR = new TFlipper(this, groupIndex); + FlipperR = new TFlipper(this, groupIndex); break; case 1005: new TBumper(this, groupIndex); @@ -111,7 +117,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) new TPopupTarget(this, groupIndex); break; case 1007: - this->Drain = new TDrain(this, groupIndex); + Drain = new TDrain(this, groupIndex); break; case 1011: new TBlocker(this, groupIndex); @@ -191,19 +197,10 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) TPinballTable::~TPinballTable() { - scoreStruct** scorePtr = &Score2; - int index = 4; - do + for (int scoreIndex = 0; scoreIndex < 4; scoreIndex++) { - if (*scorePtr) - { - memory::free(*scorePtr); - *scorePtr = nullptr; - } - scorePtr += 7; - --index; + memory::free(PlayerScores[scoreIndex].ScoreStruct); } - while (index); if (ScorePlayerNumber1) { memory::free(ScorePlayerNumber1); @@ -260,6 +257,66 @@ TPinballComponent* TPinballTable::find_component(int groupIndex) return nullptr; } +int TPinballTable::AddScore(int score) +{ + if (this->ScoreSpecial3Flag) + { + this->ScoreSpecial3 += score; + if (this->ScoreSpecial3 > 5000000) + this->ScoreSpecial3 = 5000000; + } + if (this->ScoreSpecial2Flag) + { + this->ScoreSpecial2 += score; + if (this->ScoreSpecial2 > 5000000) + this->ScoreSpecial2 = 5000000; + } + int addedScore = this->ScoreAdded + score * score_multipliers[this->ScoreMultiplier]; + this->CurScore += addedScore; + if (this->CurScore > 1000000000) + { + ++this->CurScoreE9; + this->CurScore = this->CurScore - 1000000000; + } + score::set(this->CurScoreStruct, this->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) +{ + TPinballTable* this2 = this; + if (!this->TiltLockFlag && !this->UnknownP10) + { + pinball::InfoTextBox->Clear(); + pinball::MissTextBox->Clear(); + pinball::InfoTextBox->Display(pinball::get_rc_string(35, 0), -1.0); + loader::play_sound(this2->SoundIndex3); + this2->TiltTimeoutTimer = timer::set(30.0, this2, TPinballTable::tilt_timeout); + + for (int i = 0; i < ListP1->Count(); i++) + { + static_cast(ListP1->Get(i))->Message(1011, time); + } + this2->LightGroup->Message(8, 0); + this2->TiltLockFlag = 1; + control::table_control_handler(1011); + } +} + void TPinballTable::port_draw() { @@ -268,3 +325,341 @@ void TPinballTable::port_draw() static_cast(ListP1->Get(index))->port_draw(); } } + +int TPinballTable::Message(int code, float value) +{ + LPSTR rc_text; + switch (code) + { + case 1000: + if (!TiltLockFlag) + { + FlipperL->Message(1, value); + } + break; + case 1001: + if (!TiltLockFlag) + { + FlipperL->Message(2, value); + } + break; + case 1002: + if (!TiltLockFlag) + { + FlipperR->Message(1, value); + } + break; + case 1003: + if (!TiltLockFlag) + { + FlipperR->Message(2, value); + } + break; + case 1004: + case 1005: + Plunger->Message(code, value); + break; + case 1008: + case 1009: + case 1010: + for (int i = 0; i < ListP1->Count(); i++) + { + static_cast(ListP1->Get(i))->Message(code, value); + } + break; + case 1012: + LightGroup->Message(14, 0.0); + if (TiltLockFlag) + { + TiltLockFlag = 0; + if (TiltTimeoutTimer) + timer::kill(TiltTimeoutTimer); + TiltTimeoutTimer = 0; + } + break; + case 1013: + LightGroup->Message(34, 0.0); + LightGroup->Message(20, 0.0); + Plunger->Message(1016, 0.0); + if (Demo->UnknownBaseFlag2) + rc_text = pinball::get_rc_string(30, 0); + else + rc_text = pinball::get_rc_string(26, 0); + pinball::InfoTextBox->Display(rc_text, -1.0); + if (Demo) + Demo->Message(1014, 0.0); + break; + case 1014: + if (EndGameTimeoutTimer) + { + timer::kill(EndGameTimeoutTimer); + EndGame_timeout(0, this); + pb::mode_change(1); + } + if (LightShowTimer) + { + timer::kill(LightShowTimer); + LightShowTimer = 0; + Message(1013, 0.0); + } + else + { + UnknownP6 = 0; + Message(1024, 0.0); + /*v8 = (char*)this2->ListP2.ListPtr->Array[0]; + *(float*)(v8 + 46) = 0.0; + *(float*)(v8 + 42) = 0.0; + *(_DWORD*)(v8 + 50) = -1085485875;*/ + + auto playerCount = static_cast(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->Unknown2 = ScoreSpecial3; + } + + BallCount = MaxBallCount; + Sound::Idle(); + ChangeBallCount(BallCount); + score::set(ScorePlayerNumber1, CurrentPlayer + 1); + score::update(ScorePlayerNumber1); + Sound::Idle(); + + for (auto scoreIndex = 4 - PlayerCount; scoreIndex > 0; scoreIndex--) + { + score::set(PlayerScores[scoreIndex].ScoreStruct, -1); + } + + Sound::Idle(); + ScoreSpecial3Flag = 0; + ScoreSpecial2Flag = 0; + UnknownP71 = 0; + pinball::InfoTextBox->Clear(); + Sound::Idle(); + pinball::MissTextBox->Clear(); + Sound::Idle(); + LightGroup->Message(28, 0.2f); + auto time = loader::play_sound(SoundIndex1); + LightShowTimer = timer::set(time, this, LightShow_timeout); + } + break; + case 1018: + if (ReplayTimer) + timer::kill(ReplayTimer); + ReplayTimer = timer::set(floor(value), this, replay_timer_callback); + ReplayActiveFlag = 1; + break; + case 1021: + { + if (PlayerCount <= 1) + { + char* textboxText; + if (Demo->UnknownBaseFlag2) + textboxText = pinball::get_rc_string(30, 0); + else + textboxText = pinball::get_rc_string(26, 0); + pinball::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].Unknown2 = ScoreSpecial3; + + CurScore = nextScorePtr->Score; + CurScoreE9 = nextScorePtr->ScoreE9Part; + BallCount = nextScorePtr->BallCount; + ExtraBalls = nextScorePtr->ExtraBalls; + BallLockedCounter = nextScorePtr->BallLockedCounter; + ScoreSpecial3 = nextScorePtr->Unknown2; + + CurScoreStruct = nextScorePtr->ScoreStruct; + score::set(CurScoreStruct, CurScore); + CurScoreStruct->DirtyFlag = true; + + ChangeBallCount(BallCount); + score::set(ScorePlayerNumber1, nextPlayer + 1); + score::update(ScorePlayerNumber1); + + for (int i = 0; i < ListP1->Count(); i++) + { + static_cast(ListP1->Get(i))->Message(1020, static_cast(nextPlayer)); + } + + char* textboxText = nullptr; + switch (nextPlayer) + { + case 0: + if (Demo->UnknownBaseFlag2) + textboxText = pinball::get_rc_string(30, 0); + else + textboxText = pinball::get_rc_string(26, 0); + break; + case 1: + if (Demo->UnknownBaseFlag2) + textboxText = pinball::get_rc_string(31, 0); + else + textboxText = pinball::get_rc_string(27, 0); + break; + case 2: + if (Demo->UnknownBaseFlag2) + textboxText = pinball::get_rc_string(32, 0); + else + textboxText = pinball::get_rc_string(28, 0); + break; + case 3: + if (Demo->UnknownBaseFlag2) + textboxText = pinball::get_rc_string(33, 0); + else + textboxText = pinball::get_rc_string(29, 0); + break; + default: + break; + } + + if (textboxText != nullptr) + pinball::InfoTextBox->Display(textboxText, -1); + ScoreSpecial3Flag = 0; + ScoreSpecial2Flag = 0; + UnknownP71 = 0; + CurrentPlayer = nextPlayer; + } + break; + case 1022: + loader::play_sound(SoundIndex2); + pinball::MissTextBox->Clear(); + pinball::InfoTextBox->Display(pinball::get_rc_string(34, 0), -1.0); + EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout); + break; + case 1024: + for (int i = 0; i < ListP1->Count(); i++) + { + static_cast(ListP1->Get(i))->Message(1024, 0); + } + if (ReplayTimer) + timer::kill(ReplayTimer); + ReplayTimer = 0; + if (LightShowTimer) + { + timer::kill(LightShowTimer); + LightGroup->Message(34, 0.0); + } + LightShowTimer = 0; + ScoreMultiplier = 0; + ScoreAdded = 0; + ScoreSpecial1 = 0; + ScoreSpecial2 = 10000; + ScoreSpecial2Flag = 0; + ScoreSpecial3 = 20000; + ScoreSpecial3Flag = 0; + UnknownP71 = 0; + ExtraBalls = 0; + UnknownP75 = 0; + BallLockedCounter = 0; + MultiballFlag = 0; + UnknownP78 = 0; + ReplayActiveFlag = 0; + ReplayTimer = 0; + TiltLockFlag = 0; + break; + + default: break; + } + + control::table_control_handler(code); + return 0; +} + +void TPinballTable::EndGame_timeout(int timerId, void* caller) +{ + auto table = static_cast(caller); + table->EndGameTimeoutTimer = 0; + pb::end_game(); + + for (int i = 0; i < table->ListP1->Count(); i++) + { + static_cast(table->ListP1->Get(i))->Message(1022, 0); + } + if (table->Demo) + table->Demo->Message(1022, 0.0); + control::handler(67, pinball::MissTextBox); + pinball::InfoTextBox->Display(pinball::get_rc_string(24, 0), -1.0); +} + +void TPinballTable::LightShow_timeout(int timerId, void* caller) +{ + auto table = static_cast(caller); + table->LightShowTimer = 0; + table->Message(1013, 0.0); +} + +void TPinballTable::replay_timer_callback(int timerId, void* caller) +{ + auto table = static_cast(caller); + table->ReplayActiveFlag = 0; + table->ReplayTimer = 0; +} + +void TPinballTable::tilt_timeout(int timerId, void* caller) +{ + auto table = static_cast(caller); + + objlist_struct1* v2; // eax + void** v3; // edi + int v4; // ebx + char v5; // [esp+14h] [ebp-Ch] + + table->TiltTimeoutTimer = 0; + if (table->TiltLockFlag) + { + /*v2 = table->ListP2.ListPtr; + v3 = v2->Array; + if (v2->Count > 0) + { + v4 = v2->Count; + do + { + (*(void(__stdcall**)(void*, char*, char*, _DWORD, _DWORD))(*(_DWORD*)table->Drain + 20))( + *v3, + &v5, + &v5, + 0.0, + 0); + ++v3; + --v4; + } while (v4); + }*/ + } +} diff --git a/SpaceCadetPinball/TPinballTable.h b/SpaceCadetPinball/TPinballTable.h index 155e1e8..dd1058a 100644 --- a/SpaceCadetPinball/TPinballTable.h +++ b/SpaceCadetPinball/TPinballTable.h @@ -1,11 +1,26 @@ #pragma once -#include "objlist_class.h" -#include "score.h" -#include "TDrain.h" -#include "TFlipper.h" -#include "TLightGroup.h" + #include "TPinballComponent.h" -#include "TPlunger.h" + +struct scoreStruct; +class TFlipper; +class TPlunger; +class TDrain; +class TDemo; +class objlist_class; +class TLightGroup; + +struct score_struct_super +{ + scoreStruct* ScoreStruct; + int Score; + int ScoreE9Part; + int Unknown2; + int BallCount; + int ExtraBalls; + int BallLockedCounter; +}; + class TPinballTable : public TPinballComponent { @@ -14,56 +29,38 @@ public: ~TPinballTable(); TPinballComponent* find_component(LPCSTR componentName); TPinballComponent* find_component(int groupIndex); + int AddScore(int score); + void ChangeBallCount(int count); + void tilt(float time); void port_draw() override; + int Message(int code, float value) override; + + static void EndGame_timeout(int timerId, void* caller); + static void LightShow_timeout(int timerId, void* caller); + static void replay_timer_callback(int timerId, void* caller); + static void tilt_timeout(int timerId, void* caller); TFlipper* FlipperL; TFlipper* FlipperR; - scoreStruct* Score1; - int* ScoreBallcount; - int* ScorePlayerNumber1; + scoreStruct* CurScoreStruct; + scoreStruct* ScoreBallcount; + scoreStruct* ScorePlayerNumber1; int UnknownP6; int SoundIndex1; int SoundIndex2; int SoundIndex3; int UnknownP10; - int UnknownP11; - int UnknownP12; - int UnknownP13; - int UnknownP14; - int UnknownP15; - scoreStruct* Score2; - int UnknownP17; - int UnknownP18; - int UnknownP19; - int UnknownP20; - int UnknownP21; - int UnknownP22; - scoreStruct* Score3_x3_at7; - int UnknownP24; - int UnknownP25; - int UnknownP26; - int UnknownP27; - int UnknownP28; - int UnknownP29; - int UnknownP30; - int UnknownP31; - int UnknownP32; - int UnknownP33; - int UnknownP34; - int UnknownP35; - int UnknownP36; - int UnknownP37; - int UnknownP38; - int UnknownP39; - int UnknownP40; - int UnknownP41; - int UnknownP42; - int UnknownP43; + int CurScore; + int CurScoreE9; + int LightShowTimer; + int EndGameTimeoutTimer; + int TiltTimeoutTimer; + score_struct_super PlayerScores[4]; int PlayerCount; int CurrentPlayer; TPlunger* Plunger; TDrain* Drain; - int UnknownP48; + TDemo* Demo; int XOffset; int YOffset; int Width; @@ -77,24 +74,27 @@ public: float CollisionCompOffset; int UnknownP62; int UnknownP63; - int UnknownP64; - int UnknownP65; - int UnknownP66; - int UnknownP67; - int UnknownP68; - int UnknownP69; - int UnknownP70; + int ScoreMultiplier; + int ScoreAdded; + int ScoreSpecial1; + int ScoreSpecial2; + int ScoreSpecial2Flag; + int ScoreSpecial3; + int ScoreSpecial3Flag; int UnknownP71; - int UnknownP72; - int UnknownP73; - int UnknownP74; + int BallCount; + int MaxBallCount; + int ExtraBalls; int UnknownP75; - int UnknownP76; - int UnknownP77; + int BallLockedCounter; + int MultiballFlag; int UnknownP78; - int UnknownP79; - int UnknownP80; + int ReplayActiveFlag; + int ReplayTimer; int UnknownP81; int UnknownP82; - int UnknownP83; + int TiltLockFlag; + +private: + static int score_multipliers[5]; }; diff --git a/SpaceCadetPinball/TTableLayer.cpp b/SpaceCadetPinball/TTableLayer.cpp index 8b1d864..d100c53 100644 --- a/SpaceCadetPinball/TTableLayer.cpp +++ b/SpaceCadetPinball/TTableLayer.cpp @@ -3,6 +3,7 @@ #include "loader.h" #include "proj.h" +#include "render.h" #include "TLine.h" #include "TPinballTable.h" diff --git a/SpaceCadetPinball/TTableLayer.h b/SpaceCadetPinball/TTableLayer.h index dd9d88c..869f2b5 100644 --- a/SpaceCadetPinball/TTableLayer.h +++ b/SpaceCadetPinball/TTableLayer.h @@ -3,14 +3,16 @@ #include "TEdgeManager.h" - +class TPinballTable; +class TEdgeManager; +struct gdrv_bitmap8; class TTableLayer : public TCollisionComponent { public: - static TEdgeManager *edge_manager; - + static TEdgeManager* edge_manager; + TTableLayer(TPinballTable* table); ~TTableLayer() override; diff --git a/SpaceCadetPinball/TTextBox.cpp b/SpaceCadetPinball/TTextBox.cpp index c72b4f6..503ae19 100644 --- a/SpaceCadetPinball/TTextBox.cpp +++ b/SpaceCadetPinball/TTextBox.cpp @@ -1,6 +1,9 @@ #include "pch.h" #include "TTextBox.h" + +#include "control.h" #include "loader.h" +#include "render.h" #include "score.h" #include "timer.h" diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index eea48dc..1ad2622 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -1,5 +1,7 @@ #include "pch.h" #include "control.h" + +#include "objlist_class.h" #include "TPinballTable.h" int control_bump_scores1[] = {500, 1000, 1500, 2000}; @@ -500,6 +502,8 @@ component_tag* control::simple_components[142] &control_soundwave7_tag }; +int control::table_control_flag; + void control::make_links(TPinballTable* table) { @@ -558,7 +562,8 @@ void control::handler(int code, TPinballComponent* cmp) { cmp->put_scoring(scoreInd, control->Scores[scoreInd]); ++scoreInd; - } while (scoreInd < control->ScoreCount); + } + while (scoreInd < control->ScoreCount); } control->ControlFunc(code, cmp); } @@ -796,3 +801,12 @@ void control::MultiplierTargetControl(int code, TPinballComponent* caller) void control::BallDrainControl(int code, TPinballComponent* caller) { } + +void control::table_control_handler(int code) +{ + if (code == 1011) + { + table_control_flag = 0; + control_lite77_tag.Component->Message(7, 0.0); + } +} diff --git a/SpaceCadetPinball/control.h b/SpaceCadetPinball/control.h index 04250c9..fb6d8be 100644 --- a/SpaceCadetPinball/control.h +++ b/SpaceCadetPinball/control.h @@ -30,6 +30,7 @@ public: static TPinballTable* TableG; static component_info score_components[88]; static component_tag* simple_components[142]; + static int table_control_flag; static void make_links(TPinballTable* table); static TPinballComponent* make_component_link(component_tag* tag); @@ -93,4 +94,6 @@ public: static void MedalTargetControl(int code, TPinballComponent* caller); static void MultiplierTargetControl(int code, TPinballComponent* caller); static void BallDrainControl(int code, TPinballComponent* caller); + + static void table_control_handler(int code); }; diff --git a/SpaceCadetPinball/loader.cpp b/SpaceCadetPinball/loader.cpp index 79bf608..1fa482b 100644 --- a/SpaceCadetPinball/loader.cpp +++ b/SpaceCadetPinball/loader.cpp @@ -3,6 +3,7 @@ #include "memory.h" #include "partman.h" #include "pinball.h" +#include "Sound.h" #include "zdrv.h" @@ -132,7 +133,7 @@ void loader::unload() soundListStruct* soundListPtr = &sound_list[1]; do { - //Sound_FreeSound(soundListPtr->WavePtr); + Sound::FreeSound(soundListPtr->WavePtr); ++index; ++soundListPtr; } @@ -166,7 +167,7 @@ int loader::get_sound_id(int groupIndex) if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr) { int soundGroupId = sound_list[soundIndex].GroupIndex; - sound_list[soundIndex].Volume = 0.0; + sound_list[soundIndex].Duration = 0.0; if (soundGroupId > 0 && !pinball::quickFlag) { __int16* value = (__int16*)partman::field(loader_table, soundGroupId, datFieldTypes::ShortValue); @@ -174,9 +175,9 @@ int loader::get_sound_id(int groupIndex) { const CHAR* fileName = partman::field(loader_table, soundGroupId, datFieldTypes::String); HFILE hFile = _lopen(fileName, 0); - sound_list[soundIndex].Volume = (float)((double)(_llseek(hFile, 0, 2)) * 0.0000909090909090909); + sound_list[soundIndex].Duration = (float)((double)_llseek(hFile, 0, 2) * 0.0000909090909090909); _lclose(hFile); - //sound_list[soundIndex4].WavePtr = Sound_LoadWaveFile(lpName); + sound_list[soundIndex].WavePtr = Sound::LoadWaveFile(fileName); } } } @@ -320,12 +321,12 @@ int loader::material(int groupIndex, visualStruct* visual) } -double loader::play_sound(int soundIndex) +float loader::play_sound(int soundIndex) { if (soundIndex <= 0) return 0.0; - //Sound_PlaySound(sound_list[soundIndex].WavePtr, 0, 7, 5, 0); - return sound_list[soundIndex].Volume; + Sound::PlaySound((int)sound_list[soundIndex].WavePtr, 0, 7, 5, 0); + return sound_list[soundIndex].Duration; } int loader::state_id(int groupIndex, int groupIndexOffset) diff --git a/SpaceCadetPinball/loader.h b/SpaceCadetPinball/loader.h index ed50d8d..e7658f8 100644 --- a/SpaceCadetPinball/loader.h +++ b/SpaceCadetPinball/loader.h @@ -16,7 +16,7 @@ struct soundListStruct char* WavePtr; int GroupIndex; int Loaded; - float Volume; + float Duration; char* PtrToSmth; }; @@ -66,7 +66,7 @@ public: static char* query_name(int groupIndex); static float* query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue); static __int16* query_iattribute(int groupIndex, int firstValue, int* arraySize); - static double play_sound(int soundIndex); + static float play_sound(int soundIndex); static datFileStruct* loader_table; private: static errorMsg loader_errors[]; diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 4fa0d1b..0105472 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -13,6 +13,8 @@ #include "timer.h" #include "winmain.h" #include "resource.h" +#include "TLightGroup.h" +#include "TPlunger.h" TPinballTable* pb::MainTable = nullptr; datFileStruct* pb::record_table = nullptr; @@ -355,19 +357,19 @@ void pb::keydown(int key) } if (key == options::Options.LeftTableBumpKey) { - if (!MainTable->UnknownP83) + if (!MainTable->TiltLockFlag) nudge::nudge_right(); return; } if (key == options::Options.RightTableBumpKey) { - if (!MainTable->UnknownP83) + if (!MainTable->TiltLockFlag) nudge::nudge_left(); return; } if (key == options::Options.BottomTableBumpKey) { - if (!MainTable->UnknownP83) + if (!MainTable->TiltLockFlag) nudge::nudge_up(); return; } diff --git a/SpaceCadetPinball/score.cpp b/SpaceCadetPinball/score.cpp index 7119923..8badab3 100644 --- a/SpaceCadetPinball/score.cpp +++ b/SpaceCadetPinball/score.cpp @@ -3,6 +3,7 @@ #include "loader.h" #include "memory.h" #include "partman.h" +#include "render.h" #include "TDrain.h" #include "winmain.h" @@ -15,12 +16,13 @@ int score::init() scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp) { - scoreStruct* score = (scoreStruct*)memory::allocate(sizeof(scoreStruct)); + auto score = reinterpret_cast(memory::allocate(sizeof(scoreStruct))); if (!score) return nullptr; score->Score = -9999; score->BackgroundBmp = renderBgBmp; - __int16* shortArr = (__int16*)partman::field_labeled(loader::loader_table, fieldName, datFieldTypes::ShortArray); + auto shortArr = reinterpret_cast<__int16*>(partman::field_labeled(loader::loader_table, fieldName, + datFieldTypes::ShortArray)); if (!shortArr) { memory::free(score);