Add custom gravity mode and replace hardcoded gravity interactions (#820)
Co-authored-by: Tamás Bálint Misius <lbphacker@gmail.com>
This commit is contained in:
parent
a0016a2b9c
commit
6aa68adbf4
@ -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);
|
||||
|
@ -95,6 +95,8 @@ public:
|
||||
bool aheatEnable;
|
||||
bool paused;
|
||||
int gravityMode;
|
||||
float customGravityX;
|
||||
float customGravityY;
|
||||
int airMode;
|
||||
float ambientAirTemp;
|
||||
int edgeMode;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
150
src/gui/interface/DirectionSelector.cpp
Normal file
150
src/gui/interface/DirectionSelector.cpp
Normal file
@ -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<ui::Point>()),
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
86
src/gui/interface/DirectionSelector.h
Normal file
86
src/gui/interface/DirectionSelector.h
Normal file
@ -0,0 +1,86 @@
|
||||
#ifndef DIRECTIONSELECTOR_H_
|
||||
#define DIRECTIONSELECTOR_H_
|
||||
|
||||
#include "Component.h"
|
||||
#include "Colour.h"
|
||||
#include "graphics/Graphics.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class DirectionSelector : public ui::Component
|
||||
{
|
||||
const float radius;
|
||||
const float maxRadius;
|
||||
|
||||
bool useSnapPoints;
|
||||
int snapPointRadius;
|
||||
|
||||
std::vector<ui::Point> snapPoints;
|
||||
|
||||
bool autoReturn;
|
||||
|
||||
ui::Colour backgroundColor;
|
||||
ui::Colour foregroundColor;
|
||||
ui::Colour borderColor;
|
||||
ui::Colour snapPointColor;
|
||||
|
||||
public:
|
||||
using DirectionSelectorCallback = std::function<void(float x, float y)>;
|
||||
|
||||
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_ */
|
@ -5,6 +5,7 @@ gui_files += files(
|
||||
'Component.cpp',
|
||||
'ContextMenu.cpp',
|
||||
'CopyTextButton.cpp',
|
||||
'DirectionSelector.cpp',
|
||||
'DropDown.cpp',
|
||||
'Engine.cpp',
|
||||
'Label.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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#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<String, int>("Vertical", 0));
|
||||
gravityMode->AddOption(std::pair<String, int>("Off", 1));
|
||||
gravityMode->AddOption(std::pair<String, int>("Radial", 2));
|
||||
gravityMode->SetActionCallback({ [this] { c->SetGravityMode(gravityMode->GetOption().second); } });
|
||||
gravityMode->AddOption(std::pair<String, int>("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());
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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<XRES/CELL-2 && y>=2 && y<YRES/CELL-2)
|
||||
{
|
||||
float convGravX, convGravY;
|
||||
sim.GetGravityField(x*CELL, y*CELL, -1.0f, -1.0f, convGravX, convGravY);
|
||||
auto weight = ((hv[y][x] - hv[y][x-1]) * convGravX + (hv[y][x] - hv[y-1][x]) * convGravY) / 5000.0f;
|
||||
if (weight > 0 && !(bmap_blockairh[y-1][x]&0x8))
|
||||
{
|
||||
vx[y][x] += weight * convGravX;
|
||||
vy[y][x] += weight * convGravY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(hv, ohv, sizeof(hv));
|
||||
|
@ -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;j<rt;j++)
|
||||
{
|
||||
// Calculate overall gravity direction
|
||||
switch (gravityMode)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
pGravX = 0.0f;
|
||||
pGravY = ptGrav;
|
||||
break;
|
||||
case 1:
|
||||
pGravX = pGravY = 0.0f;
|
||||
break;
|
||||
case 2:
|
||||
pGravD = 0.01f - hypotf(float(nx - XCNTR), float(ny - YCNTR));
|
||||
pGravX = ptGrav * ((float)(nx - XCNTR) / pGravD);
|
||||
pGravY = ptGrav * ((float)(ny - YCNTR) / pGravD);
|
||||
break;
|
||||
}
|
||||
pGravX += gravx[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
|
||||
pGravY += gravy[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
|
||||
GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY);
|
||||
// Scale gravity vector so that the largest component is 1 pixel
|
||||
if (fabsf(pGravY)>fabsf(pGravX))
|
||||
mv = fabsf(pGravY);
|
||||
@ -4622,24 +4616,7 @@ killed:
|
||||
for (j=0;j<rt;j++)
|
||||
{
|
||||
// Calculate overall gravity direction
|
||||
switch (gravityMode)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
pGravX = 0.0f;
|
||||
pGravY = ptGrav;
|
||||
break;
|
||||
case 1:
|
||||
pGravX = pGravY = 0.0f;
|
||||
break;
|
||||
case 2:
|
||||
pGravD = 0.01f - hypotf(float(nx - XCNTR), float(ny - YCNTR));
|
||||
pGravX = ptGrav * ((float)(nx - XCNTR) / pGravD);
|
||||
pGravY = ptGrav * ((float)(ny - YCNTR) / pGravD);
|
||||
break;
|
||||
}
|
||||
pGravX += gravx[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
|
||||
pGravY += gravy[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
|
||||
GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY);
|
||||
// Scale gravity vector so that the largest component is 1 pixel
|
||||
if (fabsf(pGravY)>fabsf(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),
|
||||
|
@ -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;
|
||||
|
@ -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)];
|
||||
|
Reference in New Issue
Block a user