From 6aa68adbf42cf82f7203869a25bf1d1fb1bdcc3a Mon Sep 17 00:00:00 2001 From: catsoften Date: Sun, 31 Jul 2022 02:19:16 -0400 Subject: [PATCH] Add custom gravity mode and replace hardcoded gravity interactions (#820) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tamás Bálint Misius --- src/client/GameSave.cpp | 12 ++ src/client/GameSave.h | 2 + src/gui/game/GameController.cpp | 5 +- src/gui/game/GameModel.cpp | 6 + src/gui/interface/DirectionSelector.cpp | 150 +++++++++++++++++++++++ src/gui/interface/DirectionSelector.h | 86 +++++++++++++ src/gui/interface/meson.build | 1 + src/gui/options/OptionsController.cpp | 10 ++ src/gui/options/OptionsController.h | 2 + src/gui/options/OptionsModel.cpp | 22 ++++ src/gui/options/OptionsModel.h | 4 + src/gui/options/OptionsView.cpp | 81 ++++++++++++- src/gui/options/OptionsView.h | 1 + src/lua/LuaScriptInterface.cpp | 21 ++++ src/lua/LuaScriptInterface.h | 1 + src/simulation/Air.cpp | 17 ++- src/simulation/Simulation.cpp | 153 ++++++++++-------------- src/simulation/Simulation.h | 2 + src/simulation/elements/STKM.cpp | 4 + 19 files changed, 485 insertions(+), 95 deletions(-) create mode 100644 src/gui/interface/DirectionSelector.cpp create mode 100644 src/gui/interface/DirectionSelector.h diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 469295aa5..752f52fc7 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -26,6 +26,8 @@ GameSave::GameSave(const GameSave & save): aheatEnable(save.aheatEnable), paused(save.paused), gravityMode(save.gravityMode), + customGravityX(save.customGravityX), + customGravityY(save.customGravityY), airMode(save.airMode), ambientAirTemp(save.ambientAirTemp), edgeMode(save.edgeMode), @@ -174,6 +176,8 @@ void GameSave::InitVars() aheatEnable = false; paused = false; gravityMode = 0; + customGravityX = 0.0f; + customGravityY = 0.0f; airMode = 0; ambientAirTemp = R_TEMP + 273.15f; edgeMode = 0; @@ -702,6 +706,8 @@ void GameSave::readOPS(char * data, int dataLength) CheckBsonFieldBool(iter, "waterEEnabled", &waterEEnabled); CheckBsonFieldBool(iter, "paused", &paused); CheckBsonFieldInt(iter, "gravityMode", &gravityMode); + CheckBsonFieldFloat(iter, "customGravityX", &customGravityX); + CheckBsonFieldFloat(iter, "customGravityY", &customGravityY); CheckBsonFieldInt(iter, "airMode", &airMode); CheckBsonFieldFloat(iter, "ambientAirTemp", &ambientAirTemp); CheckBsonFieldInt(iter, "edgeMode", &edgeMode); @@ -2614,6 +2620,12 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) bson_append_string(&b, "platform", IDENT_PLATFORM); bson_append_string(&b, "builtType", IDENT_BUILD); bson_append_finish_object(&b); + if (gravityMode == 3) + { + bson_append_double(&b, "customGravityX", double(customGravityX)); + bson_append_double(&b, "customGravityY", double(customGravityY)); + RESTRICTVERSION(97, 0); + } bson_append_start_object(&b, "minimumVersion"); bson_append_int(&b, "major", minimumMajorVersion); bson_append_int(&b, "minor", minimumMinorVersion); diff --git a/src/client/GameSave.h b/src/client/GameSave.h index de33073f7..67353de4f 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -95,6 +95,8 @@ public: bool aheatEnable; bool paused; int gravityMode; + float customGravityX; + float customGravityY; int airMode; float ambientAirTemp; int edgeMode; diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index 73d26f7a6..8ae520616 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -809,7 +809,7 @@ void GameController::ResetSpark() void GameController::SwitchGravity() { - gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode+1)%3; + gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode+1)%4; switch (gameModel->GetSimulation()->gravityMode) { @@ -822,6 +822,9 @@ void GameController::SwitchGravity() case 2: gameModel->SetInfoTip("Gravity: Radial"); break; + case 3: + gameModel->SetInfoTip("Gravity: Custom"); + break; } } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 137b8e049..0db85db30 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -954,6 +954,8 @@ void GameModel::SetSave(SaveInfo * newSave, bool invertIncludePressure) GameSave * saveData = currentSave->GetGameSave(); SetPaused(saveData->paused | GetPaused()); sim->gravityMode = saveData->gravityMode; + sim->customGravityX = saveData->customGravityX; + sim->customGravityY = saveData->customGravityY; sim->air->airMode = saveData->airMode; sim->air->ambientAirTemp = saveData->ambientAirTemp; sim->edgeMode = saveData->edgeMode; @@ -1016,6 +1018,8 @@ void GameModel::SetSaveFile(SaveFile * newSave, bool invertIncludePressure) GameSave * saveData = newSave->GetGameSave(); SetPaused(saveData->paused | GetPaused()); sim->gravityMode = saveData->gravityMode; + sim->customGravityX = saveData->customGravityX; + sim->customGravityY = saveData->customGravityY; sim->air->airMode = saveData->airMode; sim->air->ambientAirTemp = saveData->ambientAirTemp; sim->edgeMode = saveData->edgeMode; @@ -1329,6 +1333,8 @@ void GameModel::ClearSimulation() { //Load defaults sim->gravityMode = 0; + sim->customGravityX = 0.0f; + sim->customGravityY = 0.0f; sim->air->airMode = 0; sim->legacy_enable = false; sim->water_equal_test = false; diff --git a/src/gui/interface/DirectionSelector.cpp b/src/gui/interface/DirectionSelector.cpp new file mode 100644 index 000000000..b99e08cf5 --- /dev/null +++ b/src/gui/interface/DirectionSelector.cpp @@ -0,0 +1,150 @@ +#include "DirectionSelector.h" + +namespace ui { + +DirectionSelector::DirectionSelector(ui::Point position, float radius): + ui::Component(position, ui::Point(radius * 2, radius * 2)), + radius(radius), + maxRadius(radius - (radius / 4)), + useSnapPoints(false), + snapPointRadius(0), + snapPoints(std::vector()), + autoReturn(false), + backgroundColor(ui::Colour(0, 0, 0, 63)), + foregroundColor(ui::Colour(63, 63, 63, 127)), + borderColor(ui::Colour(255, 255, 255)), + snapPointColor(ui::Colour(63, 63, 63, 127)), + updateCallback(nullptr), + changeCallback(nullptr), + mouseDown(false), + mouseHover(false), + altDown(false), + offset(ui::Point(0, 0)) + { + + } + +void DirectionSelector::CheckHovering(int x, int y) +{ + mouseHover = std::hypot((offset.X + radius) - x, (offset.Y + radius) - y) < radius / 4; +} + +void DirectionSelector::SetSnapPoints(int newRadius, int points) +{ + snapPointRadius = newRadius; + snapPoints.clear(); + snapPoints.push_back(ui::Point(0, 0)); + for (int i = 1; i < points; i++) + { + int dist = ((float)i / (float)(points - 1)) * maxRadius; + snapPoints.push_back(ui::Point(0, dist)); + snapPoints.push_back(ui::Point(0, -1 * dist)); + snapPoints.push_back(ui::Point(-1 * dist, 0)); + snapPoints.push_back(ui::Point(dist, 0)); + } + useSnapPoints = true; +} + +void DirectionSelector::ClearSnapPoints() +{ + useSnapPoints = false; + snapPoints.clear(); +} + +float DirectionSelector::GetXValue() +{ + return offset.X / maxRadius; +} + +float DirectionSelector::GetYValue() +{ + return offset.Y / maxRadius; +} + +float DirectionSelector::GetTotalValue() +{ + return std::hypot(offset.X, offset.Y) / maxRadius; +} + +void DirectionSelector::SetPositionAbs(float absx, float absy) +{ + SetPosition(absx - radius, absy - radius); +} + +void DirectionSelector::SetPosition(float x, float y) +{ + if (std::hypot(x, y) > maxRadius) + { + offset.X = (maxRadius * x) / std::hypot(x, y); + offset.Y = (maxRadius * y) / std::hypot(x, y); + } + else + { + offset.X = x; + offset.Y = y; + } + + if (useSnapPoints && !altDown) + { + for (const ui::Point& i : snapPoints) + if (std::hypot(i.X - offset.X, i.Y - offset.Y) <= snapPointRadius) + { + offset.X = i.X; + offset.Y = i.Y; + } + } + if (updateCallback) + updateCallback(GetXValue(), GetYValue()); +} + +void DirectionSelector::SetValues(float x, float y) +{ + SetPosition(x * maxRadius, y * maxRadius); +} + +void DirectionSelector::Draw(const ui::Point& screenPos) +{ + Graphics * g = GetGraphics(); + ui::Point center = screenPos + radius; + + g->fillcircle(center.X, center.Y, radius, radius, backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, backgroundColor.Alpha); + g->drawcircle(center.X, center.Y, radius, radius, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha); + + for (const ui::Point& i : snapPoints) + g->fillrect( + (center.X + i.X) - (radius / 30), + (center.Y + i.Y) - (radius / 30), + radius / 10, radius / 10, + snapPointColor.Red, snapPointColor.Green, snapPointColor.Blue, altDown ? (int)(snapPointColor.Alpha / 2) : snapPointColor.Alpha + ); + + g->fillcircle(center.X + offset.X, center.Y + offset.Y, radius / 4, radius / 4, foregroundColor.Red, foregroundColor.Green, foregroundColor.Blue, mouseHover ? std::min((int)(foregroundColor.Alpha * 1.5f), 255) : foregroundColor.Alpha); + g->drawcircle(center.X + offset.X, center.Y + offset.Y, radius / 4, radius / 4, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha); +} + +void DirectionSelector::OnMouseMoved(int x, int y, int dx, int dy) +{ + if (mouseDown) + SetPositionAbs(x, y); + CheckHovering(x, y); +} + +void DirectionSelector::OnMouseClick(int x, int y, unsigned button) +{ + mouseDown = true; + SetPositionAbs(x, y); + CheckHovering(x, y); +} + +void DirectionSelector::OnMouseUp(int x, int y, unsigned button) +{ + mouseDown = false; + if (autoReturn) + SetPosition(0, 0); + CheckHovering(x - Position.X, y - Position.Y); + + if (changeCallback) + changeCallback(GetXValue(), GetYValue()); +} + +} diff --git a/src/gui/interface/DirectionSelector.h b/src/gui/interface/DirectionSelector.h new file mode 100644 index 000000000..7f12cdf71 --- /dev/null +++ b/src/gui/interface/DirectionSelector.h @@ -0,0 +1,86 @@ +#ifndef DIRECTIONSELECTOR_H_ +#define DIRECTIONSELECTOR_H_ + +#include "Component.h" +#include "Colour.h" +#include "graphics/Graphics.h" + +#include + +#include +#include +#include + +namespace ui { + +class DirectionSelector : public ui::Component +{ + const float radius; + const float maxRadius; + + bool useSnapPoints; + int snapPointRadius; + + std::vector snapPoints; + + bool autoReturn; + + ui::Colour backgroundColor; + ui::Colour foregroundColor; + ui::Colour borderColor; + ui::Colour snapPointColor; + +public: + using DirectionSelectorCallback = std::function; + +private: + DirectionSelectorCallback updateCallback; + DirectionSelectorCallback changeCallback; + + bool mouseDown; + bool mouseHover; + bool altDown; + + ui::Point offset; + + void CheckHovering(int x, int y); + +public: + DirectionSelector(ui::Point position, float radius); + virtual ~DirectionSelector() = default; + + void SetSnapPoints(int newRadius, int points); + void ClearSnapPoints(); + + inline void EnableSnapPoints() { useSnapPoints = true; } + inline void DisableSnapPoints() { useSnapPoints = false; } + + inline void EnableAutoReturn() { autoReturn = true; } + inline void DisableAutoReturn() { autoReturn = false; } + + inline void SetBackgroundColor(ui::Colour color) { backgroundColor = color; } + inline void SetForegroundColor(ui::Colour color) { foregroundColor = color; } + inline void SetBorderColor(ui::Colour color) { borderColor = color; } + inline void SetSnapPointColor(ui::Colour color) { snapPointColor = color; } + + float GetXValue(); + float GetYValue(); + float GetTotalValue(); + + void SetPositionAbs(float absx, float absy); + void SetPosition(float x, float y); + void SetValues(float x, float y); + + void Draw(const ui::Point& screenPos) override; + void OnMouseMoved(int x, int y, int dx, int dy) override; + void OnMouseClick(int x, int y, unsigned int button) override; + void OnMouseUp(int x, int y, unsigned button) override; + inline void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; } + inline void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; } + + inline void SetUpdateCallback(DirectionSelectorCallback callback) { updateCallback = callback; } + inline void SetChangeCallback(DirectionSelectorCallback callback) { changeCallback = callback; } +}; + +} /* namespace ui */ +#endif /* DIRECTIONSELECTOR_H_ */ diff --git a/src/gui/interface/meson.build b/src/gui/interface/meson.build index 7a4efa8ac..35997e327 100644 --- a/src/gui/interface/meson.build +++ b/src/gui/interface/meson.build @@ -5,6 +5,7 @@ gui_files += files( 'Component.cpp', 'ContextMenu.cpp', 'CopyTextButton.cpp', + 'DirectionSelector.cpp', 'DropDown.cpp', 'Engine.cpp', 'Label.cpp', diff --git a/src/gui/options/OptionsController.cpp b/src/gui/options/OptionsController.cpp index 5246242a8..cb7cd23b8 100644 --- a/src/gui/options/OptionsController.cpp +++ b/src/gui/options/OptionsController.cpp @@ -42,6 +42,16 @@ void OptionsController::SetGravityMode(int gravityMode) model->SetGravityMode(gravityMode); } +void OptionsController::SetCustomGravityX(float x) +{ + model->SetCustomGravityX(x); +} + +void OptionsController::SetCustomGravityY(float y) +{ + model->SetCustomGravityY(y); +} + void OptionsController::SetAirMode(int airMode) { model->SetAirMode(airMode); diff --git a/src/gui/options/OptionsController.h b/src/gui/options/OptionsController.h index 0c00d3fb5..b50a9fbb6 100644 --- a/src/gui/options/OptionsController.h +++ b/src/gui/options/OptionsController.h @@ -21,6 +21,8 @@ public: void SetNewtonianGravity(bool state); void SetWaterEqualisation(bool state); void SetGravityMode(int gravityMode); + void SetCustomGravityX(float x); + void SetCustomGravityY(float y); void SetAirMode(int airMode); void SetAmbientAirTemperature(float ambientAirTemp); void SetEdgeMode(int edgeMode); diff --git a/src/gui/options/OptionsModel.cpp b/src/gui/options/OptionsModel.cpp index 835978451..d3b7242fc 100644 --- a/src/gui/options/OptionsModel.cpp +++ b/src/gui/options/OptionsModel.cpp @@ -111,6 +111,28 @@ void OptionsModel::SetGravityMode(int gravityMode) notifySettingsChanged(); } +float OptionsModel::GetCustomGravityX() +{ + return sim->customGravityX; +} + +void OptionsModel::SetCustomGravityX(float x) +{ + sim->customGravityX = x; + notifySettingsChanged(); +} + +float OptionsModel::GetCustomGravityY() +{ + return sim->customGravityY; +} + +void OptionsModel::SetCustomGravityY(float y) +{ + sim->customGravityY = y; + notifySettingsChanged(); +} + int OptionsModel::GetScale() { return ui::Engine::Ref().GetScale(); diff --git a/src/gui/options/OptionsModel.h b/src/gui/options/OptionsModel.h index f520f83d7..2ac084487 100644 --- a/src/gui/options/OptionsModel.h +++ b/src/gui/options/OptionsModel.h @@ -34,6 +34,10 @@ public: void SetEdgeMode(int edgeMode); int GetGravityMode(); void SetGravityMode(int gravityMode); + float GetCustomGravityX(); + void SetCustomGravityX(float x); + float GetCustomGravityY(); + void SetCustomGravityY(float y); int GetScale(); void SetScale(int scale); bool GetResizable(); diff --git a/src/gui/options/OptionsView.cpp b/src/gui/options/OptionsView.cpp index 92e904cda..b54737405 100644 --- a/src/gui/options/OptionsView.cpp +++ b/src/gui/options/OptionsView.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "SDLCompat.h" #include "OptionsController.h" @@ -21,6 +22,7 @@ #include "gui/interface/Engine.h" #include "gui/interface/Label.h" #include "gui/interface/Textbox.h" +#include "gui/interface/DirectionSelector.h" OptionsView::OptionsView(): ui::Window(ui::Point(-1, -1), ui::Point(320, 340)) @@ -143,7 +145,82 @@ OptionsView::OptionsView(): gravityMode->AddOption(std::pair("Vertical", 0)); gravityMode->AddOption(std::pair("Off", 1)); gravityMode->AddOption(std::pair("Radial", 2)); - gravityMode->SetActionCallback({ [this] { c->SetGravityMode(gravityMode->GetOption().second); } }); + gravityMode->AddOption(std::pair("Custom", 3)); + + class GravityWindow : public ui::Window + { + void OnTryExit(ExitMethod method) + { + CloseActiveWindow(); + SelfDestruct(); + } + + void OnDraw() + { + Graphics * g = GetGraphics(); + + g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3); + g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 200, 200, 200, 255); + } + + ui::DirectionSelector * gravityDirection; + ui::Label * labelValues; + + OptionsController * c; + + public: + GravityWindow(ui::Point position, int radius, float x, float y, OptionsController * c_): + ui::Window(position, ui::Point((radius * 2) + 20, (radius * 2) + 75)), + gravityDirection(new ui::DirectionSelector(ui::Point(10, 32), radius)), + c(c_) + { + ui::Label * tempLabel = new ui::Label(ui::Point(4, 1), ui::Point(Size.X - 8, 22), "Custom Gravity"); + tempLabel->SetTextColour(style::Colour::InformationTitle); + tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; + tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; + AddComponent(tempLabel); + + Separator * tempSeparator = new Separator(ui::Point(0, 22), ui::Point(Size.X, 1)); + AddComponent(tempSeparator); + + labelValues = new ui::Label(ui::Point(0, (radius * 2) + 37), ui::Point(Size.X, 16), String::Build( "X:", std::round(x * 10.0f) / 10, + " Y:", std::round(y * 10.0f) / 10, + " Total:", std::round(std::hypot(x, y) * 10.0f) / 10)); + labelValues->Appearance.HorizontalAlign = ui::Appearance::AlignCentre; + labelValues->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; + AddComponent(labelValues); + + gravityDirection->SetValues(x / 2.0f, y / 2.0f); + gravityDirection->SetUpdateCallback([this](float x, float y) { + labelValues->SetText(String::Build( "X:", std::round(x * 20.0f) / 10, + " Y:", std::round(y * 20.0f) / 10, + " Total:", std::round(gravityDirection->GetTotalValue() * 20.0f) / 10)); + }); + gravityDirection->SetSnapPoints(5, 5); + AddComponent(gravityDirection); + + ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y - 17), ui::Point(Size.X, 17), "OK"); + okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre; + okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; + okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200); + okayButton->SetActionCallback({ [this] { + c->SetCustomGravityX(gravityDirection->GetXValue() * 2.0f); + c->SetCustomGravityY(gravityDirection->GetYValue() * 2.0f); + CloseActiveWindow(); + SelfDestruct(); + } }); + AddComponent(okayButton); + SetOkayButton(okayButton); + + MakeActiveWindow(); + } + }; + + gravityMode->SetActionCallback({ [this] { + c->SetGravityMode(gravityMode->GetOption().second); + if (gravityMode->GetOption().second == 3) + new GravityWindow(ui::Point(-1, -1), 50, customGravityX, customGravityY, c); + } }); tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Gravity Simulation Mode"); tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; @@ -432,6 +509,8 @@ void OptionsView::NotifySettingsChanged(OptionsModel * sender) ambientAirTemp->SetText(sb.Build()); } gravityMode->SetOption(sender->GetGravityMode()); + customGravityX = sender->GetCustomGravityX(); + customGravityY = sender->GetCustomGravityY(); decoSpace->SetOption(sender->GetDecoSpace()); edgeMode->SetOption(sender->GetEdgeMode()); scale->SetOption(sender->GetScale()); diff --git a/src/gui/options/OptionsView.h b/src/gui/options/OptionsView.h index fbb210dcb..20431d3f9 100644 --- a/src/gui/options/OptionsView.h +++ b/src/gui/options/OptionsView.h @@ -40,6 +40,7 @@ class OptionsView: public ui::Window ui::Checkbox * includePressure; ui::Checkbox * perfectCirclePressure; ui::ScrollPanel * scrollPanel; + float customGravityX, customGravityY; bool initializedAirTempPreview = false; void UpdateAmbientAirTempPreview(float airTemp, bool isValid); void UpdateAirTemp(String temp, bool isDefocus); diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 6f36ba16a..8b5f0de39 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -842,6 +842,7 @@ void LuaScriptInterface::initSimulationAPI() {"gravityGrid", simulation_gravityGrid}, {"edgeMode", simulation_edgeMode}, {"gravityMode", simulation_gravityMode}, + {"customGravity", simulation_customGravity}, {"airMode", simulation_airMode}, {"waterEqualisation", simulation_waterEqualisation}, {"waterEqualization", simulation_waterEqualisation}, @@ -1964,6 +1965,26 @@ int LuaScriptInterface::simulation_gravityMode(lua_State * l) return 0; } +int LuaScriptInterface::simulation_customGravity(lua_State * l) +{ + int acount = lua_gettop(l); + if (acount == 0) + { + lua_pushnumber(l, luacon_sim->customGravityX); + lua_pushnumber(l, luacon_sim->customGravityY); + return 2; + } + else if (acount == 1) + { + luacon_sim->customGravityX = 0.0f; + luacon_sim->customGravityY = luaL_optnumber(l, 1, 0.0f); + return 0; + } + luacon_sim->customGravityX = luaL_optnumber(l, 1, 0.0f); + luacon_sim->customGravityY = luaL_optnumber(l, 2, 0.0f); + return 0; +} + int LuaScriptInterface::simulation_airMode(lua_State * l) { int acount = lua_gettop(l); diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index a1839a3fe..733196d00 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -101,6 +101,7 @@ class LuaScriptInterface: public CommandInterface static int simulation_gravityGrid(lua_State * l); static int simulation_edgeMode(lua_State * l); static int simulation_gravityMode(lua_State * l); + static int simulation_customGravity(lua_State * l); static int simulation_airMode(lua_State * l); static int simulation_waterEqualisation(lua_State * l); static int simulation_ambientAirTemp(lua_State * l); diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp index f13441703..913d795ab 100644 --- a/src/simulation/Air.cpp +++ b/src/simulation/Air.cpp @@ -115,13 +115,18 @@ void Air::update_airh(void) dh += AIR_VADV*(1.0f-tx)*ty*((bmap_blockairh[j+1][i]&0x8) ? odh : hv[j+1][i]); dh += AIR_VADV*tx*ty*((bmap_blockairh[j+1][i+1]&0x8) ? odh : hv[j+1][i+1]); } - if(!sim.gravityMode) - { //Vertical gravity only for the time being - float airdiff = hv[y-1][x]-hv[y][x]; - if(airdiff>0 && !(bmap_blockairh[y-1][x]&0x8)) - vy[y][x] -= airdiff/5000.0f; - } ohv[y][x] = dh; + if (x>=2 && x=2 && y 0 && !(bmap_blockairh[y-1][x]&0x8)) + { + vx[y][x] += weight * convGravX; + vy[y][x] += weight * convGravY; + } + } } } memcpy(hv, ohv, sizeof(hv)); diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 0e92e45f0..a14a66b74 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -545,6 +545,8 @@ void Simulation::SaveSimOptions(GameSave * gameSave) if (!gameSave) return; gameSave->gravityMode = gravityMode; + gameSave->customGravityX = customGravityX; + gameSave->customGravityY = customGravityY; gameSave->airMode = air->airMode; gameSave->ambientAirTemp = air->ambientAirTemp; gameSave->edgeMode = edgeMode; @@ -2834,8 +2836,19 @@ int Simulation::try_move(int i, int x, int y, int nx, int ny) } break; case PT_CNCT: - if (y < ny && (TYP(pmap[y+1][x]) == PT_CNCT || TYP(pmap[y+1][x]) == PT_ROCK)) //check below CNCT for another CNCT or ROCK - return 0; + { + float cnctGravX, cnctGravY; // Calculate offset from gravity + GetGravityField(x, y, elements[PT_CNCT].Gravity, elements[PT_CNCT].Gravity, cnctGravX, cnctGravY); + int offsetX = 0, offsetY = 0; + if (cnctGravX > 0.0f) offsetX++; + else if (cnctGravX < 0.0f) offsetX--; + if (cnctGravY > 0.0f) offsetY++; + else if (cnctGravY < 0.0f) offsetY--; + if ((offsetX != 0) != (offsetY != 0) && // Is this a different position (avoid diagonals, doesn't work well) + ((nx - x) * offsetX > 0 || (ny - y) * offsetY > 0) && // Is the destination particle below the moving particle + (TYP(pmap[y+offsetY][x+offsetX]) == PT_CNCT || TYP(pmap[y+offsetY][x+offsetX]) == PT_ROCK)) //check below CNCT for another CNCT or ROCK + return 0; + } break; case PT_GBMB: if (parts[i].life > 0) @@ -3322,23 +3335,40 @@ int Simulation::create_part(int p, int x, int y, int t, int v) void Simulation::GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY) { - pGravX = newtonGrav*gravx[(y/CELL)*(XRES/CELL)+(x/CELL)]; - pGravY = newtonGrav*gravy[(y/CELL)*(XRES/CELL)+(x/CELL)]; switch (gravityMode) { - default: - case 0: //normal, vertical gravity - pGravY += particleGrav; - break; - case 1: //no gravity - break; - case 2: //radial gravity - if (x-XCNTR != 0 || y-YCNTR != 0) + default: + case 0: //normal, vertical gravity + pGravX = 0; + pGravY = particleGrav; + break; + case 1: //no gravity + pGravX = 0; + pGravY = 0; + break; + case 2: //radial gravity + { + pGravX = 0; + pGravY = 0; + auto dx = x-XCNTR; + auto dy = y-YCNTR; + if (dx || dy) { - float pGravMult = particleGrav/sqrtf(float((x-XCNTR)*(x-XCNTR) + (y-YCNTR)*(y-YCNTR))); - pGravX -= pGravMult * (float)(x - XCNTR); - pGravY -= pGravMult * (float)(y - YCNTR); + auto pGravD = 0.01f - hypotf(dx, dy); + pGravX = particleGrav * (dx / pGravD); + pGravY = particleGrav * (dy / pGravD); } + } + break; + case 3: //custom gravity + pGravX = particleGrav * customGravityX; + pGravY = particleGrav * customGravityY; + break; + } + if (newtonGrav) + { + pGravX += newtonGrav*gravx[(y/CELL)*(XRES/CELL)+(x/CELL)]; + pGravY += newtonGrav*gravy[(y/CELL)*(XRES/CELL)+(x/CELL)]; } } @@ -3467,7 +3497,6 @@ void Simulation::UpdateParticles(int start, int end) int h_count = 0; int surround[8]; int surround_hconduct[8]; - float pGravX, pGravY, pGravD; bool transitionOccurred; //the main particle loop function, goes over all particles. @@ -3538,35 +3567,10 @@ void Simulation::UpdateParticles(int start, int end) } } - pGravX = pGravY = 0; - if (!(elements[t].Properties & TYPE_SOLID)) + float pGravX = 0, pGravY = 0; + if (!(elements[t].Properties & TYPE_SOLID) && (elements[t].Gravity || elements[t].NewtonianGravity)) { - if (elements[t].Gravity) - { - //Gravity mode by Moach - switch (gravityMode) - { - default: - case 0: - pGravX = 0.0f; - pGravY = elements[t].Gravity; - break; - case 1: - pGravX = pGravY = 0.0f; - break; - case 2: - pGravD = 0.01f - hypotf(float(x - XCNTR), float(y - YCNTR)); - pGravX = elements[t].Gravity * ((float)(x - XCNTR) / pGravD); - pGravY = elements[t].Gravity * ((float)(y - YCNTR) / pGravD); - break; - } - } - if (elements[t].NewtonianGravity) - { - //Get some gravity from the gravity map - pGravX += elements[t].NewtonianGravity * gravx[(y/CELL)*(XRES/CELL)+(x/CELL)]; - pGravY += elements[t].NewtonianGravity * gravy[(y/CELL)*(XRES/CELL)+(x/CELL)]; - } + GetGravityField(x, y, elements[t].Gravity, elements[t].NewtonianGravity, pGravX, pGravY); } //velocity updates for the particle @@ -3613,13 +3617,20 @@ void Simulation::UpdateParticles(int start, int end) if (!legacy_enable) { - if (y-2 >= 0 && y-2 < YRES && (elements[t].Properties&TYPE_LIQUID) && (t!=PT_GEL || gel_scale > (1 + RNG::Ref().between(0, 254)))) {//some heat convection for liquids - r = pmap[y-2][x]; - if (!(!r || parts[i].type != TYP(r))) { - if (parts[i].temp>parts[ID(r)].temp) { - swappage = parts[i].temp; - parts[i].temp = parts[ID(r)].temp; - parts[ID(r)].temp = swappage; + if ((elements[t].Properties&TYPE_LIQUID) && (t!=PT_GEL || gel_scale > (1 + RNG::Ref().between(0, 254)))) + { + float convGravX, convGravY; + GetGravityField(x, y, -2.0f, -2.0f, convGravX, convGravY); + int offsetX = std::round(convGravX + x); + int offsetY = std::round(convGravY + y); + if ((offsetX != x || offsetY != y) && offsetX >= 0 && offsetX < XRES && offsetY >= 0 && offsetY < YRES) {//some heat convection for liquids + r = pmap[offsetY][offsetX]; + if (!(!r || parts[i].type != TYP(r))) { + if (parts[i].temp>parts[ID(r)].temp) { + swappage = parts[i].temp; + parts[i].temp = parts[ID(r)].temp; + parts[ID(r)].temp = swappage; + } } } } @@ -4550,24 +4561,7 @@ killed: for (j=0;jfabsf(pGravX)) mv = fabsf(pGravY); @@ -4622,24 +4616,7 @@ killed: for (j=0;jfabsf(pGravX)) mv = fabsf(pGravY); @@ -5272,6 +5249,8 @@ Simulation::Simulation(): GSPEED(1), edgeMode(0), gravityMode(0), + customGravityX(0), + customGravityY(0), legacy_enable(0), aheat_enable(0), water_equal_test(0), diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index a7c1b97d1..a1282c4ca 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -105,6 +105,8 @@ public: //Simulation Settings int edgeMode; int gravityMode; + float customGravityX; + float customGravityY; int legacy_enable; int aheat_enable; int water_equal_test; diff --git a/src/simulation/elements/STKM.cpp b/src/simulation/elements/STKM.cpp index 2b27f8859..228d75da4 100644 --- a/src/simulation/elements/STKM.cpp +++ b/src/simulation/elements/STKM.cpp @@ -155,6 +155,10 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) gvy = ((float)(parts[i].y - YCNTR) / gravd); } break; + case 3: + gvx = sim->customGravityX; + gvy = sim->customGravityY; + break; } gvx += sim->gravx[((int)parts[i].y/CELL)*(XRES/CELL)+((int)parts[i].x/CELL)];