Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/opensb/interface/optionsmenu/optionsmenu.config.patch20
-rw-r--r--source/frontend/StarOptionsMenu.cpp15
-rw-r--r--source/frontend/StarOptionsMenu.hpp2
-rw-r--r--source/game/StarHumanoid.cpp55
-rw-r--r--source/game/StarHumanoid.hpp7
-rw-r--r--source/game/StarPlayer.cpp40
6 files changed, 125 insertions, 14 deletions
diff --git a/assets/opensb/interface/optionsmenu/optionsmenu.config.patch b/assets/opensb/interface/optionsmenu/optionsmenu.config.patch
index a169bef..4755b45 100644
--- a/assets/opensb/interface/optionsmenu/optionsmenu.config.patch
+++ b/assets/opensb/interface/optionsmenu/optionsmenu.config.patch
@@ -54,6 +54,24 @@
"instrumentSlider" : { "type" : "slider", "position" : [62, 158], "gridImage" : "/interface/optionsmenu/largeselection.png" },
"instrumentLabel" : { "type" : "label", "position" : [32, 158], "value" : "Tunes" },
- "instrumentValueLabel" : { "type" : "label", "position" : [192, 158], "hAnchor" : "mid", "value" : "Replace Me" }
+ "instrumentValueLabel" : { "type" : "label", "position" : [192, 158], "hAnchor" : "mid", "value" : "Replace Me" },
+
+ "headRotationLabel" : {
+ "type" : "label",
+ "position" : [25, 51],
+ "hAnchor" : "left",
+ "value" : "HEAD ROTATION"
+ },
+ "headRotationCheckbox" : {
+ "type" : "button",
+ "pressedOffset" : [0, 0],
+ "position" : [104, 51],
+ "base" : "/interface/optionsmenu/checkboxnocheck.png",
+ "hover" : "/interface/optionsmenu/checkboxnocheckhover.png",
+ "baseImageChecked" : "/interface/optionsmenu/checkboxcheck.png",
+ "hoverImageChecked" : "/interface/optionsmenu/checkboxcheckhover.png",
+ "checkable" : true,
+ "checked" : true
+ }
}
} \ No newline at end of file
diff --git a/source/frontend/StarOptionsMenu.cpp b/source/frontend/StarOptionsMenu.cpp
index 8253f1f..28d44f6 100644
--- a/source/frontend/StarOptionsMenu.cpp
+++ b/source/frontend/StarOptionsMenu.cpp
@@ -10,6 +10,7 @@
#include "StarVoiceSettingsMenu.hpp"
#include "StarBindingsMenu.hpp"
#include "StarGraphicsMenu.hpp"
+#include "StarHumanoid.hpp"
namespace Star {
@@ -47,6 +48,9 @@ OptionsMenu::OptionsMenu(PaneManager* manager, UniverseClientPtr client)
reader.registerCallback("allowAssetsMismatchCheckbox", [=](Widget*) {
updateAllowAssetsMismatch();
});
+ reader.registerCallback("headRotationCheckbox", [=](Widget*) {
+ updateHeadRotation();
+ });
reader.registerCallback("backButton", [=](Widget*) {
dismiss();
});
@@ -77,6 +81,7 @@ OptionsMenu::OptionsMenu(PaneManager* manager, UniverseClientPtr client)
m_clientIPJoinableButton = fetchChild<ButtonWidget>("clientIPJoinableCheckbox");
m_clientP2PJoinableButton = fetchChild<ButtonWidget>("clientP2PJoinableCheckbox");
m_allowAssetsMismatchButton = fetchChild<ButtonWidget>("allowAssetsMismatchCheckbox");
+ m_headRotationButton = fetchChild<ButtonWidget>("headRotationCheckbox");
m_instrumentLabel = fetchChild<LabelWidget>("instrumentValueLabel");
m_sfxLabel = fetchChild<LabelWidget>("sfxValueLabel");
@@ -115,7 +120,8 @@ StringList const OptionsMenu::ConfigKeys = {
"tutorialMessages",
"clientIPJoinable",
"clientP2PJoinable",
- "allowAssetsMismatch"
+ "allowAssetsMismatch",
+ "humanoidHeadRotation"
};
void OptionsMenu::initConfig() {
@@ -166,6 +172,12 @@ void OptionsMenu::updateAllowAssetsMismatch() {
Root::singleton().configuration()->set("allowAssetsMismatch", m_allowAssetsMismatchButton->isChecked());
}
+void OptionsMenu::updateHeadRotation() {
+ m_localChanges.set("humanoidHeadRotation", m_headRotationButton->isChecked());
+ Root::singleton().configuration()->set("humanoidHeadRotation", m_headRotationButton->isChecked());
+ Humanoid::globalHeadRotation() = m_headRotationButton->isChecked();
+}
+
void OptionsMenu::syncGuiToConf() {
m_instrumentSlider->setVal(m_localChanges.get("instrumentVol").toInt(), false);
m_instrumentLabel->setText(toString(m_instrumentSlider->val()));
@@ -180,6 +192,7 @@ void OptionsMenu::syncGuiToConf() {
m_clientIPJoinableButton->setChecked(m_localChanges.get("clientIPJoinable").toBool());
m_clientP2PJoinableButton->setChecked(m_localChanges.get("clientP2PJoinable").toBool());
m_allowAssetsMismatchButton->setChecked(m_localChanges.get("allowAssetsMismatch").toBool());
+ m_headRotationButton->setChecked(m_localChanges.get("humanoidHeadRotation").optBool().value(true));
auto appController = GuiContext::singleton().applicationController();
if (!appController->p2pNetworkingService()) {
diff --git a/source/frontend/StarOptionsMenu.hpp b/source/frontend/StarOptionsMenu.hpp
index 9fde1ac..4a28fd0 100644
--- a/source/frontend/StarOptionsMenu.hpp
+++ b/source/frontend/StarOptionsMenu.hpp
@@ -36,6 +36,7 @@ private:
void updateClientIPJoinable();
void updateClientP2PJoinable();
void updateAllowAssetsMismatch();
+ void updateHeadRotation();
void syncGuiToConf();
@@ -52,6 +53,7 @@ private:
ButtonWidgetPtr m_clientIPJoinableButton;
ButtonWidgetPtr m_clientP2PJoinableButton;
ButtonWidgetPtr m_allowAssetsMismatchButton;
+ ButtonWidgetPtr m_headRotationButton;
LabelWidgetPtr m_instrumentLabel;
LabelWidgetPtr m_sfxLabel;
diff --git a/source/game/StarHumanoid.cpp b/source/game/StarHumanoid.cpp
index c71e161..8f39abe 100644
--- a/source/game/StarHumanoid.cpp
+++ b/source/game/StarHumanoid.cpp
@@ -242,6 +242,14 @@ EnumMap<Humanoid::State> const Humanoid::StateNames{
{Humanoid::State::Lay, "lay"},
};
+// gross, but I don't want to make config calls more than I need to
+bool& Humanoid::globalHeadRotation(Maybe<bool> default) {
+ static Maybe<bool> s_headRotation;
+ if (!s_headRotation)
+ s_headRotation = Root::singleton().configuration()->get("humanoidHeadRotation").optBool().value(true);
+ return *s_headRotation;
+};
+
Humanoid::Humanoid(Json const& config) {
loadConfig(config);
@@ -252,7 +260,7 @@ Humanoid::Humanoid(Json const& config) {
m_movingBackwards = false;
m_altHand.angle = 0;
m_facingDirection = Direction::Left;
- m_rotation = 0;
+ m_headRotationTarget = m_headRotation = m_rotation = 0;
m_scale = Vec2F::filled(1.f);
m_drawVaporTrail = false;
m_state = State::Idle;
@@ -412,6 +420,10 @@ void Humanoid::setMovingBackwards(bool movingBackwards) {
m_movingBackwards = movingBackwards;
}
+void Humanoid::setHeadRotation(float headRotation) {
+ m_headRotationTarget = headRotation;
+}
+
void Humanoid::setRotation(float rotation) {
m_rotation = rotation;
}
@@ -476,6 +488,10 @@ void Humanoid::setPrimaryHandNonRotatedDrawables(List<Drawable> drawables) {
m_primaryHand.nonRotatedDrawables = std::move(drawables);
}
+bool Humanoid::primaryHandHoldingItem() const {
+ return m_primaryHand.holdingItem;
+}
+
void Humanoid::setAltHandParameters(bool holdingItem, float angle, float itemAngle, bool recoil,
bool outsideOfHand) {
m_altHand.holdingItem = holdingItem;
@@ -498,16 +514,24 @@ void Humanoid::setAltHandNonRotatedDrawables(List<Drawable> drawables) {
m_altHand.nonRotatedDrawables = std::move(drawables);
}
+bool Humanoid::altHandHoldingItem() const {
+ return m_altHand.holdingItem;
+}
+
void Humanoid::animate(float dt) {
m_animationTimer += dt;
m_emoteAnimationTimer += dt;
m_danceTimer += dt;
+ float headRotationTarget = globalHeadRotation() ? m_headRotationTarget : 0.f;
+ float diff = angleDiff(m_headRotation, headRotationTarget);
+ m_headRotation = (headRotationTarget - (headRotationTarget - m_headRotation) * powf(.333333f, dt * 60.f));
}
void Humanoid::resetAnimation() {
m_animationTimer = 0.0f;
m_emoteAnimationTimer = 0.0f;
m_danceTimer = 0.0f;
+ m_headRotation = globalHeadRotation() ? 0.f : m_headRotationTarget;
}
List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
@@ -641,11 +665,28 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
else if (m_state == Lay)
headPosition += m_headLayOffset;
+ auto addHeadDrawable = [&](Drawable drawable, bool forceFullbright = false) {
+ if (m_facingDirection == Direction::Left)
+ drawable.scale(Vec2F(-1, 1));
+ drawable.fullbright |= forceFullbright;
+ if (m_headRotation != 0.f) {
+ float dir = numericalDirection(m_facingDirection);
+ Vec2F rotationPoint = headPosition;
+ rotationPoint[0] *= dir;
+ rotationPoint[1] -= .25f;
+ float headX = (m_headRotation / ((float)Constants::pi * 2.f));
+ drawable.rotate(m_headRotation, rotationPoint);
+ drawable.position[0] -= state() == State::Run ? (fmaxf(headX * dir, 0.f) * 2.f) * dir : headX;
+ drawable.position[1] -= fabsf(m_headRotation / ((float)Constants::pi * 4.f));
+ }
+ drawables.append(std::move(drawable));
+ };
+
if (!m_headFrameset.empty() && !m_bodyHidden) {
String image = strf("{}:normal", m_headFrameset);
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, headPosition);
drawable.imagePart().addDirectives(getBodyDirectives(), true);
- addDrawable(std::move(drawable), m_bodyFullbright);
+ addHeadDrawable(std::move(drawable), m_bodyFullbright);
}
if (!m_emoteFrameset.empty() && !m_bodyHidden) {
@@ -653,14 +694,14 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
String image = strf("{}:{}.{}{}", m_emoteFrameset, emoteFrameBase(m_emoteState), emoteStateSeq, emoteDirectives.prefix());
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, headPosition);
drawable.imagePart().addDirectives(emoteDirectives, true);
- addDrawable(std::move(drawable), m_bodyFullbright);
+ addHeadDrawable(std::move(drawable), m_bodyFullbright);
}
if (!m_hairFrameset.empty() && !m_bodyHidden) {
String image = strf("{}:normal", m_hairFrameset);
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, headPosition);
drawable.imagePart().addDirectives(getHairDirectives(), true).addDirectives(getHelmetMaskDirectives(), true);
- addDrawable(std::move(drawable), m_bodyFullbright);
+ addHeadDrawable(std::move(drawable), m_bodyFullbright);
}
if (!m_bodyFrameset.empty() && !m_bodyHidden) {
@@ -719,21 +760,21 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
String image = strf("{}:normal", m_facialHairFrameset);
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, headPosition);
drawable.imagePart().addDirectives(getFacialHairDirectives(), true).addDirectives(getHelmetMaskDirectives(), true);
- addDrawable(std::move(drawable), m_bodyFullbright);
+ addHeadDrawable(std::move(drawable), m_bodyFullbright);
}
if (!m_facialMaskFrameset.empty() && !m_bodyHidden) {
String image = strf("{}:normal", m_facialMaskFrameset);
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, headPosition);
drawable.imagePart().addDirectives(getFacialMaskDirectives(), true).addDirectives(getHelmetMaskDirectives(), true);
- addDrawable(std::move(drawable));
+ addHeadDrawable(std::move(drawable));
}
if (!m_headArmorFrameset.empty()) {
String image = strf("{}:normal{}", m_headArmorFrameset, m_headArmorDirectives.prefix());
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, headPosition);
drawable.imagePart().addDirectives(getHeadDirectives(), true);
- addDrawable(std::move(drawable));
+ addHeadDrawable(std::move(drawable));
}
auto frontArmDrawable = [&](String const& frameSet, Directives const& directives) -> Drawable {
diff --git a/source/game/StarHumanoid.hpp b/source/game/StarHumanoid.hpp
index c83ddb5..6fd1cbe 100644
--- a/source/game/StarHumanoid.hpp
+++ b/source/game/StarHumanoid.hpp
@@ -100,6 +100,8 @@ public:
};
static EnumMap<State> const StateNames;
+ static bool& globalHeadRotation(Maybe<bool> default = {});
+
Humanoid(Json const& config);
Humanoid(HumanoidIdentity const& identity);
Humanoid(Humanoid const&) = default;
@@ -163,6 +165,7 @@ public:
void setDance(Maybe<String> const& dance);
void setFacingDirection(Direction facingDirection);
void setMovingBackwards(bool movingBackwards);
+ void setHeadRotation(float headRotation);
void setRotation(float rotation);
void setScale(Vec2F scale);
@@ -183,6 +186,7 @@ public:
void setPrimaryHandFrameOverrides(String backFrameOverride, String frontFrameOverride);
void setPrimaryHandDrawables(List<Drawable> drawables);
void setPrimaryHandNonRotatedDrawables(List<Drawable> drawables);
+ bool primaryHandHoldingItem() const;
// Same as primary hand.
void setAltHandParameters(bool holdingItem, float angle, float itemAngle, bool recoil,
@@ -190,6 +194,7 @@ public:
void setAltHandFrameOverrides(String backFrameOverride, String frontFrameOverride);
void setAltHandDrawables(List<Drawable> drawables);
void setAltHandNonRotatedDrawables(List<Drawable> drawables);
+ bool altHandHoldingItem() const;
// Updates the animation based on whatever the current animation state is,
// wrapping or clamping animation time as appropriate.
@@ -355,6 +360,8 @@ private:
Maybe<String> m_dance;
Direction m_facingDirection;
bool m_movingBackwards;
+ float m_headRotation;
+ float m_headRotationTarget;
float m_rotation;
Vec2F m_scale;
bool m_drawVaporTrail;
diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp
index 2f89ff3..24a3c16 100644
--- a/source/game/StarPlayer.cpp
+++ b/source/game/StarPlayer.cpp
@@ -1021,16 +1021,16 @@ void Player::update(float dt, uint64_t) {
|| m_humanoid->danceCyclicOrEnded() || m_movementController->running())
m_humanoid->setDance({});
- bool isClient = world()->isClient();
- if (isClient)
- m_armor->setupHumanoidClothingDrawables(*m_humanoid, forceNude());
-
m_tools->suppressItems(suppressedItems);
m_tools->tick(dt, m_shifting, m_pendingMoves);
-
+
if (auto overrideFacingDirection = m_tools->setupHumanoidHandItems(*m_humanoid, position(), aimPosition()))
m_movementController->controlFace(*overrideFacingDirection);
+ bool isClient = world()->isClient();
+ if (isClient)
+ m_armor->setupHumanoidClothingDrawables(*m_humanoid, forceNude());
+
m_effectsAnimator->resetTransformationGroup("flip");
if (m_movementController->facingDirection() == Direction::Left)
m_effectsAnimator->scaleTransformationGroup("flip", Vec2F(-1, 1));
@@ -1075,6 +1075,35 @@ void Player::update(float dt, uint64_t) {
m_effectEmitter->tick(dt, *entityMode());
+ if (isClient) {
+ bool calculateHeadRotation = isMaster();
+ if (!calculateHeadRotation) {
+ auto headRotationProperty = getSecretProperty("humanoid.headRotation");
+ if (headRotationProperty.isType(Json::Type::Float)) {
+ m_humanoid->setHeadRotation(headRotationProperty.toFloat());
+ } else
+ calculateHeadRotation = true;
+ }
+ if (calculateHeadRotation) { // master or not an OpenStarbound player
+ float headRotation = 0.f;
+ if (m_humanoid->primaryHandHoldingItem() || m_humanoid->altHandHoldingItem()) {
+ auto primary = m_tools->primaryHandItem();
+ auto alt = m_tools->altHandItem();
+ String const disableFlag = "disableHeadRotation";
+ auto statusFlag = m_statusController->statusProperty(disableFlag);
+ if (!(statusFlag.isType(Json::Type::Bool) && statusFlag.toBool())
+ && !(primary && primary->instanceValue(disableFlag))
+ && !(alt && alt->instanceValue(disableFlag))) {
+ auto diff = world()->geometry().diff(aimPosition(), mouthPosition());
+ diff.setX(fabsf(diff.x()));
+ headRotation = diff.angle() * .25f * numericalDirection(m_humanoid->facingDirection());
+ }
+ }
+ m_humanoid->setHeadRotation(headRotation);
+ setSecretProperty("humanoid.headRotation", headRotation);
+ }
+ }
+
m_humanoid->setFacingDirection(m_movementController->facingDirection());
m_humanoid->setMovingBackwards(m_movementController->facingDirection() != m_movementController->movingDirection());
@@ -2610,6 +2639,7 @@ Maybe<StringView> Player::getSecretPropertyView(String const& name) const {
return {};
}
+
Json Player::getSecretProperty(String const& name, Json defaultValue) const {
if (auto tag = m_effectsAnimator->globalTagPtr(secretProprefix + name)) {
DataStreamExternalBuffer buffer(tag->utf8Ptr(), tag->utf8Size());