From a143b820afc7e1497230abd654e656f4adb40c91 Mon Sep 17 00:00:00 2001 From: oz Date: Sun, 27 Dec 2020 18:19:36 +0300 Subject: [PATCH] TBall, nudge v1, ready. render occlude list. --- Doc/FuncStats.xlsx | Bin 37607 -> 37762 bytes SpaceCadetPinball/DatParser.cpp | 150 ------------------ SpaceCadetPinball/DatParser.h | 7 - SpaceCadetPinball/SpaceCadetPinball.cpp | 1 - SpaceCadetPinball/SpaceCadetPinball.vcxproj | 2 - .../SpaceCadetPinball.vcxproj.filters | 6 - SpaceCadetPinball/TBall.cpp | 126 +++++++++++++++ SpaceCadetPinball/TBall.h | 34 +++- SpaceCadetPinball/TPinballComponent.cpp | 6 +- SpaceCadetPinball/TPinballComponent.h | 1 + SpaceCadetPinball/TPinballTable.cpp | 64 ++++---- SpaceCadetPinball/TPinballTable.h | 4 +- SpaceCadetPinball/control.cpp | 2 +- SpaceCadetPinball/fullscrn.cpp | 21 +-- SpaceCadetPinball/gdrv.cpp | 5 +- SpaceCadetPinball/loader.cpp | 44 ++--- SpaceCadetPinball/maths.cpp | 34 ++-- SpaceCadetPinball/maths.h | 3 +- SpaceCadetPinball/nudge.cpp | 79 ++++++++- SpaceCadetPinball/nudge.h | 17 +- SpaceCadetPinball/objlist_class.cpp | 1 - SpaceCadetPinball/options.cpp | 6 +- SpaceCadetPinball/partman.h | 1 - SpaceCadetPinball/pb.cpp | 120 ++++++++++---- SpaceCadetPinball/pb.h | 4 +- SpaceCadetPinball/pinball.cpp | 6 +- SpaceCadetPinball/proj.cpp | 16 +- SpaceCadetPinball/render.cpp | 55 ++++++- SpaceCadetPinball/render.h | 3 +- SpaceCadetPinball/winmain.cpp | 4 +- 30 files changed, 494 insertions(+), 328 deletions(-) delete mode 100644 SpaceCadetPinball/DatParser.cpp delete mode 100644 SpaceCadetPinball/DatParser.h diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 106d6c1ab70dfaacabf4f9780be531687641f841..c18f505795c3ecf5fcc0edcd295133d7f446d5dc 100644 GIT binary patch delta 30081 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Ð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 #include "objlist_class.h" #include "partman.h" -#include "DatParser.h" #include "gdrv.h" #include "loader.h" #include "pb.h" diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj b/SpaceCadetPinball/SpaceCadetPinball.vcxproj index f6176d6..56c65af 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj @@ -157,7 +157,6 @@ - @@ -221,7 +220,6 @@ - diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters index 88cec46..4088f83 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters @@ -42,9 +42,6 @@ Header Files - - Header Files - Header Files @@ -233,9 +230,6 @@ Source Files - - Source Files - Source Files diff --git a/SpaceCadetPinball/TBall.cpp b/SpaceCadetPinball/TBall.cpp index 356ab02..f866293 100644 --- a/SpaceCadetPinball/TBall.cpp +++ b/SpaceCadetPinball/TBall.cpp @@ -1,2 +1,128 @@ #include "pch.h" #include "TBall.h" + + +#include "loader.h" +#include "maths.h" +#include "objlist_class.h" +#include "proj.h" +#include "render.h" +#include "TPinballTable.h" +#include "TZmapList.h" + +TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false) +{ + visualStruct visual{}; + + Unknown9F = 0.0; + Unknown7F = 0.0; + UnknownBaseFlag2 = 1; + Unknown16 = 0; + EdgeCollisionCount = 0; + Unknown8F = 0.0; + Unknown17 = 1; + CollisionFlag = 0; + Speed = 0.0; + Acceleration.Y = 0.0; + Acceleration.X = 0.0; + InvAcceleration.Y = 1000000000.0; + InvAcceleration.X = 1000000000.0; + Position.X = 0.0; + Position.Y = 0.0; + + ListBitmap = new TZmapList(0, 4); + auto groupIndex = loader::query_handle("ball"); + Offset = *loader::query_float_attribute(groupIndex, 0, 500); + auto visualCount = loader::query_visual_states(groupIndex); + auto index = 0; + if (visualCount > 0) + { + auto visualZPtr = VisualZArray; + do + { + loader::query_visual(groupIndex, index, &visual); + if (ListBitmap) + ListBitmap->Add(visual.Bitmap); + auto visVec = reinterpret_cast(loader::query_float_attribute(groupIndex, index, 501)); + auto zDepth = proj::z_distance(visVec); + ++index; + *visualZPtr = zDepth; + ++visualZPtr; + } + while (index < visualCount); + } + RenderSprite = render::create_sprite(VisualType::Ball, nullptr, nullptr, 0, 0, nullptr); + PinballTable->CollisionCompOffset = Offset; + Position.Z = Offset; +} + +void TBall::Repaint() +{ + int pos2D[2]; + + if (CollisionFlag) + { + Position.Z = + CollisionOffset.X * Position.X + + CollisionOffset.Y * Position.Y + + Offset + CollisionOffset.Z; + } + + proj::xform_to_2d(&Position, pos2D); + auto zDepth = proj::z_distance(&Position); + + auto zArrPtr = VisualZArray; + int index; + for (index = 0; index < ListBitmap->Count() - 1; ++index, zArrPtr++) + { + if (*zArrPtr <= zDepth) break; + } + + auto bmp = static_cast(ListBitmap->Get(index)); + render::ball_set( + RenderSprite, + bmp, + zDepth, + bmp->Width / 2 - pos2D[0], + bmp->Height / 2 - pos2D[1]); +} + +void TBall::not_again(TEdgeSegment* edge) +{ + if (EdgeCollisionCount < 5) + { + Collisions[EdgeCollisionCount] = edge; + ++EdgeCollisionCount; + } +} + +bool TBall::already_hit(TEdgeSegment* edge) +{ + for (int i = 0; i < EdgeCollisionCount; i++) + { + if (Collisions[i] == edge) + return true; + } + + return false; +} + +int TBall::Message(int code, float value) +{ + if (code == 1024) + { + render::ball_set(RenderSprite, nullptr, 0.0, 0, 0); + Position.X = 0.0; + Unknown16 = 0; + Position.Y = 0.0; + UnknownBaseFlag2 = 0; + CollisionFlag = 0; + Unknown17 = 1; + Acceleration.Y = 0.0; + Position.Z = Offset; + Acceleration.X = 0.0; + Speed = 0.0; + Unknown7F = 0.0; + } + return 0; +} diff --git a/SpaceCadetPinball/TBall.h b/SpaceCadetPinball/TBall.h index 190750f..e3ee29e 100644 --- a/SpaceCadetPinball/TBall.h +++ b/SpaceCadetPinball/TBall.h @@ -1,11 +1,35 @@ #pragma once +#include "maths.h" #include "TPinballComponent.h" -class TBall : - public TPinballComponent +class TEdgeSegment; + +class TBall : public TPinballComponent { public : - TBall(TPinballTable* table): TPinballComponent(table, -1, false) - { - } + TBall(TPinballTable* table); + void Repaint(); + void not_again(TEdgeSegment* edge); + bool already_hit(TEdgeSegment* edge); + int Message(int code, float value) override; + + vector_type Position; + vector_type Acceleration; + float Speed; + float Unknown7F; + float Unknown8F; + float Unknown9F; + vector_type InvAcceleration; + int Unknown13; + int Unknown14; + int Unknown15; + int Unknown16; + int Unknown17; + TEdgeSegment* Collisions[5]; + int EdgeCollisionCount; + vector_type CollisionOffset; + int CollisionFlag; + float Offset; + int Unknown29; + float VisualZArray[50]; }; diff --git a/SpaceCadetPinball/TPinballComponent.cpp b/SpaceCadetPinball/TPinballComponent.cpp index 1d117bc..b0d82cb 100644 --- a/SpaceCadetPinball/TPinballComponent.cpp +++ b/SpaceCadetPinball/TPinballComponent.cpp @@ -8,7 +8,7 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool loadVisuals) { - visualStruct visual{}; // [esp+Ch] [ebp-6Ch] + visualStruct visual{}; MessageField = 0; UnknownBaseFlag1 = 0; @@ -18,7 +18,7 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool ListBitmap = nullptr; ListZMap = nullptr; if (table) - table->ListP1->Add(this); + table->ComponentList->Add(this); if (groupIndex >= 0) GroupName = loader::query_name(groupIndex); if (loadVisuals && groupIndex >= 0) @@ -80,7 +80,7 @@ TPinballComponent::~TPinballComponent() { TPinballTable* table = PinballTable; if (table) - table->ListP1->Delete(this); + table->ComponentList->Delete(this); delete ListBitmap; delete ListZMap; diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index 0ba7a17..c5db926 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -7,6 +7,7 @@ class TZmapList; enum class message_code { + Reset = 1024, }; class TPinballComponent diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index 871ca27..5efc507 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -47,8 +47,8 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) { int shortArrLength; - ListP1 = new objlist_class(32, 16); - ListP2 = new objlist_class(3, 1); + ComponentList = new objlist_class(32, 16); + BallList = new objlist_class(3, 1); CurScoreStruct = nullptr; ScoreBallcount = nullptr; ScorePlayerNumber1 = nullptr; @@ -62,7 +62,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) MultiballFlag = 0; auto ballObj = new TBall(this); - ListP2->Add(ballObj); + BallList->Add(ballObj); if (ballObj) ballObj->UnknownBaseFlag2 = 0; new TTableLayer(this); @@ -188,7 +188,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false) } } - //build_occlude_list(); + render::build_occlude_list(); pinball::InfoTextBox = dynamic_cast(find_component("info_text_box")); pinball::MissTextBox = dynamic_cast(find_component("mission_text_box")); control::make_links(this); @@ -212,22 +212,22 @@ TPinballTable::~TPinballTable() ScoreBallcount = nullptr; } delete LightGroup; - while (ListP1->Count() > 0) + while (ComponentList->Count() > 0) { - delete static_cast(ListP1->Get(0)); + delete static_cast(ComponentList->Get(0)); } - delete ListP2; - delete ListP1; + delete BallList; + delete ComponentList; } TPinballComponent* TPinballTable::find_component(LPCSTR componentName) { - int objCount = ListP1->Count(); + int objCount = ComponentList->Count(); if (objCount > 0) { for (int index = 0; index < objCount; ++index) { - TPinballComponent* obj = static_cast(ListP1->Get(index)); + TPinballComponent* obj = static_cast(ComponentList->Get(index)); const CHAR* groupName = obj->GroupName; if (groupName && !lstrcmpA(groupName, componentName)) { @@ -242,12 +242,12 @@ TPinballComponent* TPinballTable::find_component(LPCSTR componentName) TPinballComponent* TPinballTable::find_component(int groupIndex) { char Buffer[33]; - int objCount = ListP1->Count(); + int objCount = ComponentList->Count(); if (objCount > 0) { for (int index = 0; index < objCount; ++index) { - TPinballComponent* obj = static_cast(ListP1->Get(index)); + TPinballComponent* obj = static_cast(ComponentList->Get(index)); if (obj->GroupIndex == groupIndex) return obj; } @@ -305,11 +305,11 @@ void TPinballTable::tilt(float time) 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); + this2->TiltTimeoutTimer = timer::set(30.0, this2, tilt_timeout); - for (int i = 0; i < ListP1->Count(); i++) + for (int i = 0; i < ComponentList->Count(); i++) { - static_cast(ListP1->Get(i))->Message(1011, time); + static_cast(ComponentList->Get(i))->Message(1011, time); } this2->LightGroup->Message(8, 0); this2->TiltLockFlag = 1; @@ -320,9 +320,9 @@ void TPinballTable::tilt(float time) void TPinballTable::port_draw() { - for (int index = ListP1->Count() - 1; index >= 0; index--) + for (int index = ComponentList->Count() - 1; index >= 0; index--) { - static_cast(ListP1->Get(index))->port_draw(); + static_cast(ComponentList->Get(index))->port_draw(); } } @@ -362,9 +362,9 @@ int TPinballTable::Message(int code, float value) case 1008: case 1009: case 1010: - for (int i = 0; i < ListP1->Count(); i++) + for (int i = 0; i < ComponentList->Count(); i++) { - static_cast(ListP1->Get(i))->Message(code, value); + static_cast(ComponentList->Get(i))->Message(code, value); } break; case 1012: @@ -406,10 +406,10 @@ int TPinballTable::Message(int code, float value) { 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 ball = static_cast(BallList->Get(0)); + ball->Position.Y = 0.0; + ball->Position.X = 0.0; + ball->Position.Z = -0.8f; auto playerCount = static_cast(floor(value)); PlayerCount = playerCount; @@ -513,9 +513,9 @@ int TPinballTable::Message(int code, float value) score::set(ScorePlayerNumber1, nextPlayer + 1); score::update(ScorePlayerNumber1); - for (int i = 0; i < ListP1->Count(); i++) + for (int i = 0; i < ComponentList->Count(); i++) { - static_cast(ListP1->Get(i))->Message(1020, static_cast(nextPlayer)); + static_cast(ComponentList->Get(i))->Message(1020, static_cast(nextPlayer)); } char* textboxText = nullptr; @@ -564,9 +564,9 @@ int TPinballTable::Message(int code, float value) EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout); break; case 1024: - for (int i = 0; i < ListP1->Count(); i++) + for (int i = 0; i < ComponentList->Count(); i++) { - static_cast(ListP1->Get(i))->Message(1024, 0); + static_cast(ComponentList->Get(i))->Message(1024, 0); } if (ReplayTimer) timer::kill(ReplayTimer); @@ -608,9 +608,9 @@ void TPinballTable::EndGame_timeout(int timerId, void* caller) table->EndGameTimeoutTimer = 0; pb::end_game(); - for (int i = 0; i < table->ListP1->Count(); i++) + for (int i = 0; i < table->ComponentList->Count(); i++) { - static_cast(table->ListP1->Get(i))->Message(1022, 0); + static_cast(table->ComponentList->Get(i))->Message(1022, 0); } if (table->Demo) table->Demo->Message(1022, 0.0); @@ -635,12 +635,6 @@ void TPinballTable::replay_timer_callback(int timerId, void* caller) 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) { diff --git a/SpaceCadetPinball/TPinballTable.h b/SpaceCadetPinball/TPinballTable.h index dd1058a..31dbce7 100644 --- a/SpaceCadetPinball/TPinballTable.h +++ b/SpaceCadetPinball/TPinballTable.h @@ -65,8 +65,8 @@ public: int YOffset; int Width; int Height; - objlist_class* ListP1; - objlist_class* ListP2; + objlist_class* ComponentList; + objlist_class* BallList; TLightGroup* LightGroup; float TableAngleMult; float TableAngle1; diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index 1ad2622..5e15d4e 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -533,7 +533,7 @@ TPinballComponent* control::make_component_link(component_tag* tag) if (tag->Component) return tag->Component; - auto compList = TableG->ListP1; + auto compList = TableG->ComponentList; for (int index = 0; index < compList->Count(); index++) { auto comp = static_cast(compList->Get(index)); diff --git a/SpaceCadetPinball/fullscrn.cpp b/SpaceCadetPinball/fullscrn.cpp index 059ec25..d86940f 100644 --- a/SpaceCadetPinball/fullscrn.cpp +++ b/SpaceCadetPinball/fullscrn.cpp @@ -40,9 +40,10 @@ void fullscrn::init(int width, int height, int isFullscreen, HWND winHandle, HME hWnd, (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2, WindowRect2.top, - widht2 + 4, - WindowRect2.bottom - WindowRect2.top, + widht2 + 4 + 10, + WindowRect2.bottom - WindowRect2.top + 10, 0); + // Todo: WH + 10 hack: original request 640x480 window but somehow receives 650x490, even thought spyxx says it is 640x480 fullscrn_flag1 = 0; } @@ -94,8 +95,8 @@ int fullscrn::setWindowFlagsDisDlg() int fullscrn::enableFullscreen() { - tagRECT Rect{}; // [esp+Ch] [ebp-B0h] - DEVMODEA DevMode{}; // [esp+1Ch] [ebp-A0h] + tagRECT Rect{}; + DEVMODEA DevMode{}; if (ChangeDisplay && !display_changed) { @@ -153,7 +154,7 @@ int fullscrn::disableFullscreen() bool fullscrn::set_menu_mode(int menuEnabled) { - BOOL result; // eax + BOOL result; MenuEnabled = menuEnabled; GetWindowCenter(); @@ -174,8 +175,8 @@ bool fullscrn::set_menu_mode(int menuEnabled) void fullscrn::GetWindowCenter() { - int yPos; // eax - tagRECT Rect{}; // [esp+4h] [ebp-10h] + int yPos; + tagRECT Rect{}; if (screen_mode) { @@ -201,7 +202,7 @@ void fullscrn::force_redraw() void fullscrn::center_in(HWND parent, HWND child) { - LONG right; // ebx + LONG right; tagRECT childRect{}, parentRect{}, desktopRect{}; GetWindowRect(parent, &parentRect); @@ -296,8 +297,8 @@ void fullscrn::activate(int flag) void fullscrn::fillRect(int right, int bottom) { // Weird reg usage, should be zero - int v2 = 0; // ebx - int v3 = 0; // edi + int v2 = 0; + int v3 = 0; RECT rc; HGDIOBJ brush = CreateSolidBrush(0); diff --git a/SpaceCadetPinball/gdrv.cpp b/SpaceCadetPinball/gdrv.cpp index 7173603..c7a62f8 100644 --- a/SpaceCadetPinball/gdrv.cpp +++ b/SpaceCadetPinball/gdrv.cpp @@ -91,7 +91,7 @@ BITMAPINFO* gdrv::DibCreate(__int16 bpp, int width, int height) void gdrv::DibSetUsage(BITMAPINFO* dib, HPALETTE hpal, int someFlag) { - tagPALETTEENTRY pPalEntries[256]; // [esp+4h] [ebp-400h] + tagPALETTEENTRY pPalEntries[256]; if (!hpal) hpal = static_cast(GetStockObject(DEFAULT_PALETTE)); @@ -140,7 +140,7 @@ void gdrv::DibSetUsage(BITMAPINFO* dib, HPALETTE hpal, int someFlag) int gdrv::create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height) { - char* bmpBufPtr; // ecx + char* bmpBufPtr; auto dib = DibCreate(8, width, height); DibSetUsage(dib, palette_handle, 1); @@ -210,7 +210,6 @@ int gdrv::display_palette(PALETTEENTRY* plt) { if (plt) { - // Todo: verify RGB order pltDst->peRed = pltSrc->peBlue; pltDst->peGreen = pltSrc->peGreen; pltDst->peBlue = pltSrc->peRed; diff --git a/SpaceCadetPinball/loader.cpp b/SpaceCadetPinball/loader.cpp index 1fa482b..fe5130a 100644 --- a/SpaceCadetPinball/loader.cpp +++ b/SpaceCadetPinball/loader.cpp @@ -415,28 +415,28 @@ int loader::kicker(int groupIndex, visualKickerStruct* kicker) int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* visual) { - visualStruct* visual2; // edi - int groupIndexSum; // eax - int groupIndexSum2; // ebx - zmap_header_type* bitmap16; // eax - __int16* shortArr; // esi - unsigned int shortArrSize; // eax - int index; // ebx - int shortVal; // ecx - __int16* nextShortVal; // esi - int nextIndex; // ebx - int shortValSub100; // ecx - int shortValSub300; // ecx - int shortValSub304; // ecx - int shortValSub602; // ecx - int shortValSub1100; // ecx - int shortValSub1101; // ecx - float* floatArr; // eax - float* nextFloatVal; // esi - __int64 floatVal; // rax - float* floatArrPtr; // esi - int groupIndexSum3; // [esp+1Ch] [ebp+8h] - int shortArrLength; // [esp+24h] [ebp+10h] + visualStruct* visual2; + int groupIndexSum; + int groupIndexSum2; + zmap_header_type* bitmap16; + __int16* shortArr; + unsigned int shortArrSize; + int index; + int shortVal; + __int16* nextShortVal; + int nextIndex; + int shortValSub100; + int shortValSub300; + int shortValSub304; + int shortValSub602; + int shortValSub1100; + int shortValSub1101; + float* floatArr; + float* nextFloatVal; + __int64 floatVal; + float* floatArrPtr; + int groupIndexSum3; + int shortArrLength; visual2 = visual; default_vsi(visual); diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp index cd5f23c..66672ba 100644 --- a/SpaceCadetPinball/maths.cpp +++ b/SpaceCadetPinball/maths.cpp @@ -81,10 +81,10 @@ int maths::rectangle_clip(rectangle_type* rect1, rectangle_type* rect2, rectangl int maths::overlapping_box(rectangle_type* rect1, rectangle_type* rect2, rectangle_type* dstRect) { - int v3; // esi - int v4; // edi - int v6; // esi - int v7; // edi + int v3; + int v4; + int v6; + int v7; if (rect1->XPosition >= rect2->XPosition) { @@ -166,9 +166,9 @@ float maths::normalize_2d(vector_type* vec) void maths::line_init(line_type* line, float x0, float y0, float x1, float y1) { - float v9; // st7 - bool lineDirection; // pf - float v11; // eax + float v9; + bool lineDirection; + float v11; line->Direction.X = x1 - x0; line->Direction.Y = y1 - y0; @@ -204,12 +204,12 @@ void maths::line_init(line_type* line, float x0, float y0, float x1, float y1) float maths::ray_intersect_line(ray_type* ray, line_type* line) { // Similar to https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/ - float perpDot; // st7 - float result; // st7 - float v4; // st6 - bool v5; // c0 - bool v6; // c3 - float v7; // st6 + float perpDot; + float result; + float v4; + bool v5; + bool v6; + float v7; perpDot = line->PerpendicularL.Y * ray->Direction.Y + ray->Direction.X * line->PerpendicularL.X; if (perpDot < 0.0) @@ -262,4 +262,10 @@ float maths::magnitude(vector_type* vec) else result = sqrt(magSq); return result; -} \ No newline at end of file +} + +void maths::vector_add(vector_type* vec1Dst, vector_type* vec2) +{ + vec1Dst->X += vec2->X; + vec1Dst->Y += vec2->Y; +} diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h index b433246..b0b9b4c 100644 --- a/SpaceCadetPinball/maths.h +++ b/SpaceCadetPinball/maths.h @@ -18,7 +18,7 @@ struct __declspec(align(4)) rectangle_type struct circle_type { - vector_type Center; + vector_type Center; float RadiusSq; }; @@ -55,4 +55,5 @@ public: static float ray_intersect_line(ray_type* ray, line_type* line); static void cross(vector_type* vec1, vector_type* vec2, vector_type* dstVec); static float magnitude(vector_type* vec); + static void vector_add(vector_type* vec1Dst, vector_type* vec2); }; diff --git a/SpaceCadetPinball/nudge.cpp b/SpaceCadetPinball/nudge.cpp index 410202c..6d9e3b1 100644 --- a/SpaceCadetPinball/nudge.cpp +++ b/SpaceCadetPinball/nudge.cpp @@ -1,26 +1,99 @@ #include "pch.h" #include "nudge.h" -void nudge::un_nudge_right(int x, int y) + +#include "objlist_class.h" +#include "pb.h" +#include "render.h" +#include "TBall.h" +#include "timer.h" + +int nudge::nudged_left; +int nudge::nudged_right; +int nudge::nudged_up; +int nudge::timer; +float nudge::nudge_count; + +void nudge::un_nudge_right(int timerId, void* caller) { + if (nudged_right) + _nudge(-2.0, -1.0); + nudged_right = 0; } -void nudge::un_nudge_left(int x, int y) +void nudge::un_nudge_left(int timerId, void* caller) { + if (nudged_left) + _nudge(2.0, -1.0); + nudged_left = 0; } -void nudge::un_nudge_up(int x, int y) +void nudge::un_nudge_up(int timerId, void* caller) { + if (nudged_up) + _nudge(0.0, -1.0); + nudged_up = 0; } void nudge::nudge_right() { + _nudge(2.0, 1.0); + if (timer) + timer::kill(timer); + timer = timer::set(0.4f, nullptr, un_nudge_right); + nudged_right = 1; } void nudge::nudge_left() { + _nudge(-2.0, 1.0); + if (timer) + timer::kill(timer); + timer = timer::set(0.4f, nullptr, un_nudge_left); + nudged_left = 1; } void nudge::nudge_up() { + _nudge(0.0, 1.0); + if (timer) + timer::kill(timer); + timer = timer::set(0.4f, nullptr, un_nudge_up); + nudged_up = 1; +} + +void nudge::_nudge(float xDiff, float yDiff) +{ + vector_type accelMod; + float invAccelX, invAccelY; + + auto table = pb::MainTable; + auto ballList = pb::MainTable->BallList; + accelMod.X = xDiff * 0.5f; + accelMod.Y = yDiff * 0.5f; + for (auto index = 0; index < ballList->Count(); index++) + { + auto ball = static_cast(ballList->Get(index)); + if (ball->UnknownBaseFlag2 && !ball->Unknown16) + { + ball->Acceleration.X = ball->Acceleration.X * ball->Speed; + ball->Acceleration.Y = ball->Acceleration.Y * ball->Speed; + maths::vector_add(&ball->Acceleration, &accelMod); + ball->Speed = maths::normalize_2d(&ball->Acceleration); + if (0.0 == ball->Acceleration.X) + invAccelX = 1000000000.0; + else + invAccelX = 1.0f / ball->Acceleration.X; + ball->InvAcceleration.X = invAccelX; + if (0.0 == ball->Acceleration.Y) + invAccelY = 1000000000.0; + else + invAccelY = 1.0f / ball->Acceleration.Y; + ball->InvAcceleration.Y = invAccelY; + table = pb::MainTable; + } + } + + render::shift(static_cast(floor(xDiff + 0.5)), static_cast(floor(0.5 - yDiff)), 0, 0, table->Width, + table->Height); } diff --git a/SpaceCadetPinball/nudge.h b/SpaceCadetPinball/nudge.h index 7301902..fb4ca9e 100644 --- a/SpaceCadetPinball/nudge.h +++ b/SpaceCadetPinball/nudge.h @@ -1,12 +1,19 @@ #pragma once class nudge { -public : - - static void un_nudge_right(int x, int y); - static void un_nudge_left(int x, int y); - static void un_nudge_up(int x, int y); +public: + static void un_nudge_right(int timerId, void* caller); + static void un_nudge_left(int timerId, void* caller); + static void un_nudge_up(int timerId, void* caller); static void nudge_right(); static void nudge_left(); static void nudge_up(); + + static int nudged_left; + static int nudged_right; + static int nudged_up; + static float nudge_count; +private: + static void _nudge(float x, float y); + static int timer; }; diff --git a/SpaceCadetPinball/objlist_class.cpp b/SpaceCadetPinball/objlist_class.cpp index 8a4a2b4..af319d3 100644 --- a/SpaceCadetPinball/objlist_class.cpp +++ b/SpaceCadetPinball/objlist_class.cpp @@ -88,7 +88,6 @@ int objlist_class::objlist_delete_object(objlist_struct1* ptrToStruct, void* val if (--index < 0) return 0; } - //ptrToStruct->Array[index] = *(&ptrToStruct->Count + count); ptrToStruct->Array[index] = ptrToStruct->Array[count - 1]; --ptrToStruct->Count; return 1; diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index 27bf97e..1fbec02 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -187,7 +187,7 @@ void options::path_free() int options::get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue) { - DWORD dwDisposition; // [esp+4h] [ebp-8h] + DWORD dwDisposition; HKEY result = (HKEY)defaultValue, Data = (HKEY)defaultValue; if (!OptionsRegPath) @@ -205,7 +205,7 @@ int options::get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue) void options::set_int(LPCSTR optPath, LPCSTR lpValueName, int data) { - DWORD dwDisposition; // [esp+4h] [ebp-4h] + DWORD dwDisposition; if (OptionsRegPath) { @@ -240,7 +240,7 @@ void options::get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR lpString1, LP void options::set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value) { - DWORD dwDisposition; // [esp+4h] [ebp-4h] + DWORD dwDisposition; if (OptionsRegPath) { diff --git a/SpaceCadetPinball/partman.h b/SpaceCadetPinball/partman.h index 77a7ac0..d5f478a 100644 --- a/SpaceCadetPinball/partman.h +++ b/SpaceCadetPinball/partman.h @@ -77,7 +77,6 @@ struct dat8BitBmpHeader static_assert(sizeof(dat8BitBmpHeader) == 14, "Wrong size of dat8BitBmpHeader"); -//typedef const char* LPCSTR; class partman { public: diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 0105472..d6a33cb 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -13,14 +13,15 @@ #include "timer.h" #include "winmain.h" #include "resource.h" +#include "TBall.h" +#include "TDemo.h" #include "TLightGroup.h" #include "TPlunger.h" TPinballTable* pb::MainTable = nullptr; datFileStruct* pb::record_table = nullptr; -int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_, pb:: - ball_speed_limit, pb::state; -float pb::time_now, pb::time_next; +int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_, pb::state; +float pb::time_now, pb::time_next, pb::ball_speed_limit; high_score_struct pb::highscore_table[5]; int pb::init() @@ -63,7 +64,6 @@ int pb::init() } render::init(nullptr, zMin, zScaler, tableSize[0], tableSize[1]); - gdrv::fill_bitmap(&render::vscreen, render::vscreen.Width, render::vscreen.Height, 0, 0, '\xFF'); // temp gdrv::copy_bitmap( &render::vscreen, backgroundBmp->Width, @@ -89,9 +89,7 @@ int pb::init() MainTable = new TPinballTable(); high_score::read(highscore_table, &state); - //v11 = *(float*)((char*)MainTable->ListP2.ListPtr->Array[0] + 154); - //ball_speed_limit = v11 * 200.0; - + ball_speed_limit = static_cast(MainTable->BallList->Get(0))->Offset * 200.0f; --memory::critical_allocation; return 0; } @@ -142,9 +140,8 @@ void pb::mode_change(int mode) options::menu_check(Menu1_Demo, 1); if (MainTable) { - /*v2 = MainTable->UnknownP48; - if (v2) - *(_BYTE*)(v2 + 5) = 1;*/ + if (MainTable->Demo) + MainTable->Demo->UnknownBaseFlag2 = 1; } } else @@ -154,9 +151,8 @@ void pb::mode_change(int mode) options::menu_check(Menu1_Demo, 0); if (MainTable) { - /*v1 = MainTable->UnknownP48; - if (v1) - *(_BYTE*)(v1 + 5) = 0;*/ + if (MainTable->Demo) + MainTable->Demo->UnknownBaseFlag2 = 0; } } break; @@ -208,6 +204,10 @@ void pb::replay_level(int demoMode) void pb::ballset(int x, int y) { + TBall* ball = static_cast(MainTable->BallList->Get(0)); + ball->Acceleration.X = x * 30.0f; + ball->Acceleration.Y = y * 30.0f; + ball->Speed = maths::normalize_2d(&ball->Acceleration); } int pb::frame(int time) @@ -221,30 +221,29 @@ int pb::frame(int time) //pb::timed_frame(time_now, timeMul, 1); time_now = time_next; time_ticks += time; - /*if (nudged_left || nudged_right || nudged_up) + if (nudge::nudged_left || nudge::nudged_right || nudge::nudged_up) { - nudge_count = timeMul * 4.0 + nudge_count; + nudge::nudge_count = timeMul * 4.0f + nudge::nudge_count; } else { - v2 = nudge_count - timeMul; - if (v2 <= 0.0) - v2 = 0.0; - nudge_count = v2; - }*/ + auto nudgeDec = nudge::nudge_count - timeMul; + if (nudgeDec <= 0.0) + nudgeDec = 0.0; + nudge::nudge_count = nudgeDec; + } timer::check(); render::update(); - //score::update(MainTable->Score1); - /*if (!MainTable->UnknownP83) + score::update(MainTable->CurScoreStruct); + if (!MainTable->TiltLockFlag) { - if (nudge_count > 0.5) + if (nudge::nudge_count > 0.5) { - v3 = pinball:: get_rc_string(25, 0); - pinball::InfoTextBox->Display( v3, 2.0); + pinball::InfoTextBox->Display(pinball::get_rc_string(25, 0), 2.0); } - if (nudge_count > 1.0) - TPinballTable::tilt(MainTable, v1, time_now); - }*/ + if (nudge::nudge_count > 1.0) + MainTable->tilt(time_now); + } } return 1; } @@ -316,15 +315,15 @@ void pb::keyup(int key) } else if (key == options::Options.LeftTableBumpKey) { - nudge::un_nudge_right(0, 0); + nudge::un_nudge_right(0, nullptr); } else if (key == options::Options.RightTableBumpKey) { - nudge::un_nudge_left(0, 0); + nudge::un_nudge_left(0, nullptr); } else if (key == options::Options.BottomTableBumpKey) { - nudge::un_nudge_up(0, 0); + nudge::un_nudge_up(0, nullptr); } } } @@ -379,12 +378,38 @@ void pb::keydown(int key) switch (key) { case 'B': - /**/ + TBall* ball; + if (MainTable->BallList->Count() <= 0) + { + ball = new TBall(MainTable); + } + else + { + for (auto index = 0; ;) + { + ball = static_cast(MainTable->BallList->Get(index)); + if (!ball->UnknownBaseFlag2) + break; + ++index; + if (index >= MainTable->BallList->Count()) + { + ball = new TBall(MainTable); + break; + } + } + } + ball->Position.X = 1.0; + ball->UnknownBaseFlag2 = 1; + ball->Position.Z = ball->Offset; + ball->Position.Y = 1.0; + ball->Acceleration.Z = 0.0; + ball->Acceleration.Y = 0.0; + ball->Acceleration.X = 0.0; break; case 'H': - /*auto v1 = get_rc_string(26, 0); - lstrcpyA(&String1, v1); - show_and_set_high_score_dialog(highscore_table, 1000000000, 1, &String1);*/ + char String1[200]; + lstrcpyA(String1, pinball::get_rc_string(26, 0)); + high_score::show_and_set_high_score_dialog(highscore_table, 1000000000, 1, String1); break; case 'M': char buffer[20]; @@ -450,3 +475,28 @@ void pb::high_scores() { high_score::show_high_score_dialog(highscore_table); } + +void pb::tilt_no_more() +{ + if (MainTable->TiltLockFlag) + pinball::InfoTextBox->Clear(); + MainTable->TiltLockFlag = 0; + nudge::nudge_count = -2.0; +} + +bool pb::chk_highscore() +{ + if (demo_mode) + return false; + int playerIndex = MainTable->PlayerCount - 1; + if (playerIndex < 0) + return false; + for (int i = playerIndex; + high_score::get_score_position(highscore_table, MainTable->PlayerScores[i].ScoreStruct->Score) < 0; + --i) + { + if (--playerIndex < 0) + return false; + } + return true; +} diff --git a/SpaceCadetPinball/pb.h b/SpaceCadetPinball/pb.h index e2fe988..7eb730e 100644 --- a/SpaceCadetPinball/pb.h +++ b/SpaceCadetPinball/pb.h @@ -7,7 +7,7 @@ class pb { public: static int time_ticks; - static int ball_speed_limit; + static float ball_speed_limit; static int cheat_mode, game_mode; static datFileStruct* record_table; static TPinballTable* MainTable; @@ -33,6 +33,8 @@ public: static void launch_ball(); static int end_game(); static void high_scores(); + static void tilt_no_more(); + static bool chk_highscore(); private : static int demo_mode, mode_countdown_; static float time_now, time_next; diff --git a/SpaceCadetPinball/pinball.cpp b/SpaceCadetPinball/pinball.cpp index 92cf9e3..3fc4855 100644 --- a/SpaceCadetPinball/pinball.cpp +++ b/SpaceCadetPinball/pinball.cpp @@ -36,9 +36,9 @@ int pinball::get_rc_int(int uID, int* dst) void pinball::FindShiftKeys() { - signed int i; // esi - int rightShift; // eax - CHAR stringBuf[20]; // [esp+Ch] [ebp-18h] + signed int i; + int rightShift; + CHAR stringBuf[20]; RightShift = -1; LeftShift = -1; diff --git a/SpaceCadetPinball/proj.cpp b/SpaceCadetPinball/proj.cpp index 9bd33d6..dcefda9 100644 --- a/SpaceCadetPinball/proj.cpp +++ b/SpaceCadetPinball/proj.cpp @@ -6,14 +6,14 @@ float proj::d_, proj::centerx, proj::centery; void proj::init(float* mat4x3, float d, float centerX, float centerY) { - //for (auto colIndex = 0; colIndex < 4; ++colIndex) - //{ - // // Todo: out of bounds read from mat4x3? - // for (int rowIndex = colIndex, i = 4; i > 0; rowIndex += 4, --i) - // { - // ((float*)&matrix)[rowIndex] = mat4x3[rowIndex]; - // } - //} + /*for (auto colIndex = 0; colIndex < 4; ++colIndex) + { + // Todo: out of bounds read from mat4x3? + for (int rowIndex = colIndex, i = 4; i > 0; rowIndex += 4, --i) + { + ((float*)&matrix)[rowIndex] = mat4x3[rowIndex]; + } + }*/ memcpy(&matrix, mat4x3, sizeof(float) * 4 * 3); matrix.Row3.X = 0.0; diff --git a/SpaceCadetPinball/render.cpp b/SpaceCadetPinball/render.cpp index 3e098ff..97a3713 100644 --- a/SpaceCadetPinball/render.cpp +++ b/SpaceCadetPinball/render.cpp @@ -153,7 +153,7 @@ void render::update() rect->Width = dirtyRect->Width; rect->Height = dirtyRect->Height; - if (sprite->Unknown6_0 != 0) + if (sprite->UnknownFlag != 0) remove_sprite(sprite); } @@ -228,7 +228,7 @@ render_sprite_type_struct* render::create_sprite(VisualType visualType, gdrv_bit sprite->BmpRect.XPosition = xPosition; sprite->Bmp = bmp; sprite->VisualType = visualType; - sprite->Unknown6_0 = 0; + sprite->UnknownFlag = 0; sprite->SpriteArray = nullptr; sprite->SpriteCount = 0; if (rect) @@ -395,7 +395,7 @@ void render::repaint(struct render_sprite_type_struct* sprite) for (int index = 0; index < sprite->SpriteCount; index++) { render_sprite_type_struct* curSprite = sprite->SpriteArray[index]; - if (!curSprite->Unknown6_0 && curSprite->Bmp) + if (!curSprite->UnknownFlag && curSprite->Bmp) { if (maths::rectangle_clip(&curSprite->BmpRect, &sprite->DirtyRect, &clipRect)) zdrv::paint( @@ -523,3 +523,52 @@ void render::shift(int offsetX, int offsetY, int xSrc, int ySrc, int DestWidth, DestHeight); unpaint_balls(); } + +void render::build_occlude_list() +{ + ++memory::critical_allocation; + render_sprite_type_struct** spriteArr = nullptr; + auto spritePtr1 = sprite_list; + for (int index = 0; index < many_sprites; ++index, ++spritePtr1) + { + auto curSprite = *spritePtr1; + if ((*spritePtr1)->SpriteArray) + { + memory::free((*spritePtr1)->SpriteArray); + curSprite->SpriteArray = nullptr; + curSprite->SpriteCount = 0; + } + if (!curSprite->UnknownFlag && curSprite->BoundingRect.Width != -1) + { + if (!spriteArr) + spriteArr = reinterpret_cast(memory::allocate(0xFA0u)); + int occludeCount = 0; + auto spritePtr2 = sprite_list; + for (int i = 0; i < many_sprites; ++i, ++spritePtr2) + { + auto sprite = *spritePtr2; + if (!sprite->UnknownFlag + && sprite->BoundingRect.Width != -1 + && maths::rectangle_clip(&curSprite->BoundingRect, &sprite->BoundingRect, nullptr) + && spriteArr) + { + spriteArr[occludeCount++] = sprite; + } + } + if (!curSprite->UnknownFlag && curSprite->Bmp && occludeCount < 2) + occludeCount = 0; + if (occludeCount) + { + curSprite->SpriteArray = reinterpret_cast(memory::realloc( + spriteArr, 4 * occludeCount)); + curSprite->SpriteCount = occludeCount; + spriteArr = nullptr; + } + } + } + + if (spriteArr) + memory::free(spriteArr); + + --memory::critical_allocation; +} diff --git a/SpaceCadetPinball/render.h b/SpaceCadetPinball/render.h index b6a4fd3..b6427c3 100644 --- a/SpaceCadetPinball/render.h +++ b/SpaceCadetPinball/render.h @@ -15,7 +15,7 @@ struct __declspec(align(4)) render_sprite_type_struct rectangle_type BmpRect; gdrv_bitmap8* Bmp; zmap_header_type* ZMap; - char Unknown6_0; + char UnknownFlag; VisualType VisualType; __int16 Depth; rectangle_type BmpRectCopy; @@ -62,4 +62,5 @@ public: static void paint_balls(); static void unpaint_balls(); static void shift(int offsetX, int offsetY, int xSrc, int ySrc, int DestWidth, int DestHeight); + static void build_occlude_list(); }; diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 4355eda..eb4c27c 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -370,7 +370,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP SetCursor(prevCursor); auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1); auto menuHandle = GetMenu(hWnd); - fullscrn::init(width, static_cast(height), options::Options.FullScreen, hWnd, menuHandle, + fullscrn::init(width, height, options::Options.FullScreen, hWnd, menuHandle, changeDisplayFg); --memory::critical_allocation; @@ -662,7 +662,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP int winmain::ProcessWindowMessages() { - MSG Msg{}; // [esp+8h] [ebp-1Ch] + MSG Msg{}; if (has_focus && !single_step) {