diff --git a/crogine/include/crogine/ecs/components/Sprite.hpp b/crogine/include/crogine/ecs/components/Sprite.hpp index 0a851cd98..a20766163 100644 --- a/crogine/include/crogine/ecs/components/Sprite.hpp +++ b/crogine/include/crogine/ecs/components/Sprite.hpp @@ -1,6 +1,6 @@ /*----------------------------------------------------------------------- -Matt Marchant 2017 - 2020 +Matt Marchant 2017 - 2023 http://trederia.blogspot.com crogine - Zlib license. @@ -66,12 +66,25 @@ namespace cro class CRO_EXPORT_API Sprite final { public: + /*! + \brief Default constructor + */ Sprite(); /*! - \brief Construct a sprite with the given Texture + \brief Calls the default constructor passing in the desired initial BlendMode + By default Sprites use Material::BlendMode::Alpha. This blend mode is applied + to any Drawable2D or Model material when the Sprite is first added to the scene. + + To modify the blend mode at runtime use Drawable2D::setBlendMode() or + Model::setMaterial() depending on whether the sprite is 2D or 3D. + */ + explicit Sprite(Material::BlendMode mode); + + /*! + \brief Construct a sprite with the given Texture, and optional BlendMode */ - explicit Sprite(const Texture&); + explicit Sprite(const Texture&, Material::BlendMode = Material::BlendMode::Alpha); /*! \brief Sets the texture used to render this sprite. diff --git a/crogine/include/crogine/ecs/systems/ModelRenderer.hpp b/crogine/include/crogine/ecs/systems/ModelRenderer.hpp index 6360878ce..65efbaf2b 100644 --- a/crogine/include/crogine/ecs/systems/ModelRenderer.hpp +++ b/crogine/include/crogine/ecs/systems/ModelRenderer.hpp @@ -92,7 +92,7 @@ namespace cro \param cameraIndex The index of the camera's drawlist \param passIndex the ID of the pass to query */ - std::size_t getVisibleCount(std::size_t cameraIndex, std::int32_t passIndex) const; + std::size_t getVisibleCount(std::size_t cameraIndex, std::int32_t passIndex = 0) const; void onEntityAdded(Entity) override; diff --git a/crogine/include/crogine/graphics/Colour.hpp b/crogine/include/crogine/graphics/Colour.hpp index 4b77b029a..3dbbd580a 100644 --- a/crogine/include/crogine/graphics/Colour.hpp +++ b/crogine/include/crogine/graphics/Colour.hpp @@ -213,6 +213,10 @@ namespace cro float* asArray() { return &r; } const float* asArray() const { return &r; } + explicit operator std::uint32_t() const; + explicit operator glm::vec4() const; + explicit operator float* (); + explicit operator const float* () const; private: diff --git a/crogine/src/core/App.cpp b/crogine/src/core/App.cpp index 8b603ee8d..b1cab218f 100644 --- a/crogine/src/core/App.cpp +++ b/crogine/src/core/App.cpp @@ -68,7 +68,7 @@ void winAbort(int) #include #ifdef CRO_DEBUG_ -#define DEBUG_NO_CONTROLLER +//#define DEBUG_NO_CONTROLLER #endif // CRO_DEBUG_ using namespace cro; diff --git a/crogine/src/ecs/components/Sprite.cpp b/crogine/src/ecs/components/Sprite.cpp index 6921815ec..14b25f24e 100644 --- a/crogine/src/ecs/components/Sprite.cpp +++ b/crogine/src/ecs/components/Sprite.cpp @@ -1,6 +1,6 @@ /*----------------------------------------------------------------------- -Matt Marchant 2017 - 2020 +Matt Marchant 2017 - 2023 http://trederia.blogspot.com crogine - Zlib license. @@ -42,8 +42,18 @@ Sprite::Sprite() } -Sprite::Sprite(const Texture& texture) - : Sprite() +Sprite::Sprite(Material::BlendMode mode) + : m_texture (nullptr), + m_colour (Colour::White), + m_dirtyFlags (DirtyFlags::All), + m_overrideBlendMode (true), + m_blendMode (mode) +{ + +} + +Sprite::Sprite(const Texture& texture, Material::BlendMode mode) + : Sprite(mode) { setTexture(texture); } diff --git a/crogine/src/ecs/systems/ModelRenderer.cpp b/crogine/src/ecs/systems/ModelRenderer.cpp index 00df65adf..c1c6f0830 100644 --- a/crogine/src/ecs/systems/ModelRenderer.cpp +++ b/crogine/src/ecs/systems/ModelRenderer.cpp @@ -248,7 +248,7 @@ void ModelRenderer::render(Entity camera, const RenderTarget& rt) std::size_t ModelRenderer::getVisibleCount(std::size_t cameraIndex, std::int32_t passIndex) const { - CRO_ASSERT(m_drawLists.size() < cameraIndex, ""); + CRO_ASSERT(cameraIndex < m_drawLists.size(), ""); switch (passIndex) { default: return 0; diff --git a/crogine/src/ecs/systems/UISystem.cpp b/crogine/src/ecs/systems/UISystem.cpp index 014eb3aa1..4a7eeb063 100644 --- a/crogine/src/ecs/systems/UISystem.cpp +++ b/crogine/src/ecs/systems/UISystem.cpp @@ -358,6 +358,10 @@ void UISystem::process(float) updateGroupAssignments(); + //track this group, if a callback changes it we want to quit the + //current loop else new groups have the existing events applied to them... + auto currentGroup = m_activeGroup; + std::size_t currentIndex = 0; for (auto& e : m_groups[m_activeGroup]) { @@ -365,7 +369,7 @@ void UISystem::process(float) auto area = input.m_worldArea; bool contains = false; - if (contains = area.contains(m_eventPosition); contains && input.enabled) + if (contains = area.contains(m_eventPosition) && !cro::App::getWindow().getMouseCaptured(); contains && input.enabled) { if (!input.active) { @@ -403,16 +407,19 @@ void UISystem::process(float) } } + //only do mouse/touch events if they're within the bounds of an input if (contains && input.enabled) { for (const auto& f : m_mouseDownEvents) { m_buttonCallbacks[input.callbacks[UIInput::ButtonDown]](e, f); + if (currentGroup != m_activeGroup) goto updateEnd; } for (const auto& f : m_mouseUpEvents) { m_buttonCallbacks[input.callbacks[UIInput::ButtonUp]](e, f); + if (currentGroup != m_activeGroup) goto updateEnd; } } @@ -421,10 +428,12 @@ void UISystem::process(float) for (const auto& f : m_buttonDownEvents) { m_buttonCallbacks[input.callbacks[UIInput::ButtonDown]](e, f); + if (currentGroup != m_activeGroup) goto updateEnd; } for (const auto& f : m_buttonUpEvents) { m_buttonCallbacks[input.callbacks[UIInput::ButtonUp]](e, f); + if (currentGroup != m_activeGroup) goto updateEnd; } } @@ -433,6 +442,7 @@ void UISystem::process(float) //DPRINT("Window Pos", std::to_string(m_eventPosition.x) + ", " + std::to_string(m_eventPosition.y)); +updateEnd: m_previousEventPosition = m_eventPosition; m_mouseUpEvents.clear(); m_buttonUpEvents.clear(); @@ -555,6 +565,9 @@ glm::vec2 UISystem::toWorldCoords(float x, float y) //scale to vp auto vp = getScene()->getActiveCamera().getComponent().viewport; + x -= vp.left; + x /= vp.width; + y -= vp.bottom; y /= vp.height; diff --git a/crogine/src/graphics/Colour.cpp b/crogine/src/graphics/Colour.cpp index c5c7abb35..bd4dd47c9 100644 --- a/crogine/src/graphics/Colour.cpp +++ b/crogine/src/graphics/Colour.cpp @@ -182,6 +182,26 @@ glm::vec4 cro::Colour::getVec4() const } //operators +cro::Colour::operator std::uint32_t() const +{ + return (getRedByte() << 24 | getGreenByte() << 16 | getBlueByte() << 8 | getAlphaByte()); +} + +cro::Colour::operator glm::vec4() const +{ + return { r,g,b,a }; +} + +cro::Colour::operator float*() +{ + return &r; +} + +cro::Colour::operator const float* () const +{ + return &r; +} + bool cro::operator == (const Colour& l, const Colour& r) { return ((l.r == r.r) && diff --git a/libsocial/include/Social.hpp b/libsocial/include/Social.hpp index 6a6627005..bea2440ca 100644 --- a/libsocial/include/Social.hpp +++ b/libsocial/include/Social.hpp @@ -45,7 +45,7 @@ source distribution. //(terrain vertex data and materials changed 1100 -> 1110) //(player avatar data format changed 1110 -> 1120) static constexpr std::uint16_t CURRENT_VER = 1120; -static const std::string StringVer("1.12.3"); +static const std::string StringVer("1.12.4"); class Social final diff --git a/samples/golf/src/GolfGame.cpp b/samples/golf/src/GolfGame.cpp index 0dd6bfc92..9e952c79f 100644 --- a/samples/golf/src/GolfGame.cpp +++ b/samples/golf/src/GolfGame.cpp @@ -592,6 +592,7 @@ bool GolfGame::initialise() cro::AudioMixer::setLabel("Menu", MixerChannel::Menu); cro::AudioMixer::setLabel("Announcer", MixerChannel::Voice); cro::AudioMixer::setLabel("Vehicles", MixerChannel::Vehicles); + cro::AudioMixer::setLabel("Environment", MixerChannel::Environment); m_sharedData.clientConnection.netClient.create(ConstVal::MaxClients); m_sharedData.sharedResources = std::make_unique(); diff --git a/samples/golf/src/golf/Clubs.cpp b/samples/golf/src/golf/Clubs.cpp index 8d825df87..9de43cb8a 100644 --- a/samples/golf/src/golf/Clubs.cpp +++ b/samples/golf/src/golf/Clubs.cpp @@ -68,6 +68,11 @@ namespace ClubStat({9.11f, 10.f}, {9.11f, 10.f}, {9.11f, 10.f}) //except this which is dynamic }; + static constexpr float ToYards = 1.094f; + static constexpr float ToFeet = 3.281f; + //static constexpr float ToInches = 12.f; + + constexpr std::size_t DebugLevel = 35; } @@ -88,18 +93,14 @@ std::string Club::getName(bool imperial, float distanceToPin) const if (imperial) { - static constexpr float ToYards = 1.094f; - static constexpr float ToFeet = 3.281f; - //static constexpr float ToInches = 12.f; - - if (getPower(distanceToPin) > 10.f) + if (getPower(distanceToPin, imperial) > 10.f) { auto dist = static_cast(t * ToYards); return m_name + std::to_string(dist) + "yds"; } else { - auto dist = static_cast(t * ToFeet); + auto dist = static_cast(std::round(t * ToFeet)); return m_name + std::to_string(dist) + "ft"; } } @@ -116,11 +117,23 @@ std::string Club::getName(bool imperial, float distanceToPin) const } } -float Club::getPower(float distanceToPin) const +float Club::getPower(float distanceToPin, bool imperial) const { if (m_id == ClubID::Putter) { - return getScaledValue(ClubStats[m_id].stats[0].target, distanceToPin); + //looks like a bug, but turns out we need the extra power. + auto p = getScaledValue(ClubStats[m_id].stats[0].target, distanceToPin); + //return getScaledValue(ClubStats[m_id].stats[0].power, distanceToPin); + + //because imperial display is rounded we need to apply this to the power too + //if (imperial + // && p < 10.f) //only diplayed in feet < 10m + //{ + // p = std::round(p * ToFeet); + // p /= ToFeet; //still need to actually physic in metres + //} + + return p; } //check player level and return further distance diff --git a/samples/golf/src/golf/Clubs.hpp b/samples/golf/src/golf/Clubs.hpp index 9adc3971e..566929ff8 100644 --- a/samples/golf/src/golf/Clubs.hpp +++ b/samples/golf/src/golf/Clubs.hpp @@ -78,7 +78,7 @@ class Club final std::string getLabel() const { return m_name; } //doesn't include distance - float getPower(float distanceToPin) const; + float getPower(float distanceToPin, bool imperial) const; float getAngle() const { return m_angle; } @@ -101,7 +101,7 @@ class Club final //putter below this is rescaled static constexpr float ShortRange = 1.f / 3.f; - static constexpr float ShortRangeThreshold = ShortRange * 0.65f; + static constexpr float ShortRangeThreshold = ShortRange * 0.8f; static constexpr float TinyRange = 1.f / 10.f; static constexpr float TinyRangeThreshold = TinyRange * 0.5f; diff --git a/samples/golf/src/golf/DrivingRangeDirector.cpp b/samples/golf/src/golf/DrivingRangeDirector.cpp index 8ca74d360..16ed32492 100644 --- a/samples/golf/src/golf/DrivingRangeDirector.cpp +++ b/samples/golf/src/golf/DrivingRangeDirector.cpp @@ -67,7 +67,8 @@ void DrivingRangeDirector::handleMessage(const cro::Message& msg) case sv::MessageID::GolfMessage: { const auto& data = msg.getData(); - if (data.type == GolfBallEvent::TurnEnded) + if (data.type == GolfBallEvent::TurnEnded + || data.type == GolfBallEvent::Holed) { auto hole = getCurrentHole(); auto idx = m_totalHoleCount - m_holeCount; @@ -81,6 +82,7 @@ void DrivingRangeDirector::handleMessage(const cro::Message& msg) difficulty -= 1.f; distance += 10.f * difficulty; + distance = std::max(0.0001f, distance); float score = 1.f - std::max(0.f, std::min(1.f, glm::length(data.position - m_holeData[hole].pin) / distance)); m_scores[idx] = cro::Util::Easing::easeOutQuad(score) * 100.f; //grade on a curve @@ -108,6 +110,13 @@ void DrivingRangeDirector::setHoleCount(std::int32_t count, std::int32_t holeInd { std::shuffle(m_holeData.begin(), m_holeData.end(), cro::Util::Random::rndEngine); } + else + { + std::sort(m_holeData.begin(), m_holeData.end(), [](const HoleData& a, const HoleData& b) + { + return a.par < b.par; + }); + } std::fill(m_scores.begin(), m_scores.end(), 0.f); } diff --git a/samples/golf/src/golf/DrivingState.cpp b/samples/golf/src/golf/DrivingState.cpp index 0d56e595e..f1c88e9d0 100644 --- a/samples/golf/src/golf/DrivingState.cpp +++ b/samples/golf/src/golf/DrivingState.cpp @@ -546,7 +546,8 @@ void DrivingState::handleMessage(const cro::Message& msg) case sv::MessageID::GolfMessage: { const auto& data = msg.getData(); - if (data.type == GolfBallEvent::TurnEnded) + if (data.type == GolfBallEvent::TurnEnded + || data.type == GolfBallEvent::Holed) { //display a message with score showMessage(glm::length(PlayerPosition - data.position)); @@ -580,7 +581,7 @@ void DrivingState::handleMessage(const cro::Message& msg) cmd.action = [&](cro::Entity e, float) { //distance is zero because we should never select a putter here. - float scale = Clubs[m_inputParser.getClub()].getPower(0.f) / Clubs[ClubID::Driver].getPower(0.f); + float scale = Clubs[m_inputParser.getClub()].getPower(0.f, m_sharedData.imperialMeasurements) / Clubs[ClubID::Driver].getPower(0.f, m_sharedData.imperialMeasurements); e.getComponent().setScale({ scale, 1.f }); }; m_gameScene.getSystem()->sendCommand(cmd); @@ -1250,6 +1251,8 @@ void DrivingState::createScene() return; } + std::int32_t holeIndex = 0; + const auto& properties = cfg.getProperties(); for (const auto& p : properties) { @@ -1260,6 +1263,7 @@ void DrivingState::createScene() data.pin = p.getValue(); data.target = data.pin; data.tee = PlayerPosition; + data.par = holeIndex++; //we use this to sort the hole data back into order if it was shuffled //TODO this should be parsed from the cmt file data.modelPath = "assets/golf/models/driving_range.cmb"; //needed for ball system to load collision mesh //TODO check ball system for which properties are needed @@ -3086,7 +3090,7 @@ void DrivingState::forceRestart() m_mapTexture.display(); m_gameScene.setActiveCamera(oldCam); - m_gameScene.getDirector()->setHoleCount(0); + m_gameScene.getDirector()->setHoleCount(0, 0); //setting this to 0 makes sure the holes are returned to order if they were shuffled setActiveCamera(CameraID::Player); //reset any open messages diff --git a/samples/golf/src/golf/GameConsts.hpp b/samples/golf/src/golf/GameConsts.hpp index e3d723e2c..93f9084b8 100644 --- a/samples/golf/src/golf/GameConsts.hpp +++ b/samples/golf/src/golf/GameConsts.hpp @@ -173,7 +173,7 @@ struct MixerChannel final enum { Music, Effects, Menu, - Voice, Vehicles, + Voice, Vehicles, Environment, Count }; @@ -964,8 +964,16 @@ static inline void formatDistanceString(float distance, cro::Text& target, bool distance *= ToFeet; if (distance > 1) { - auto dist = static_cast(distance); - target.setString("Distance: " + std::to_string(dist) + "ft"); + std::stringstream ss; + ss.precision(1); + ss << "Distance: "; + ss << std::fixed << distance; + ss << "ft"; + + target.setString(ss.str()); + + /*auto dist = static_cast(distance); + target.setString("Distance: " + std::to_string(dist) + "ft");*/ } else { diff --git a/samples/golf/src/golf/GolfState.cpp b/samples/golf/src/golf/GolfState.cpp index 22e44de49..8346877e5 100644 --- a/samples/golf/src/golf/GolfState.cpp +++ b/samples/golf/src/golf/GolfState.cpp @@ -441,6 +441,9 @@ bool GolfState::handleEvent(const cro::Event& evt) case SDLK_3: toggleFreeCam(); break; + case SDLK_F6: + logCSV(); + break; #ifdef CRO_DEBUG_ case SDLK_F2: m_sharedData.clientConnection.netClient.sendPacket(PacketID::ServerCommand, std::uint8_t(ServerCommand::NextHole), net::NetFlag::Reliable); @@ -451,12 +454,12 @@ bool GolfState::handleEvent(const cro::Event& evt) case SDLK_F4: m_sharedData.clientConnection.netClient.sendPacket(PacketID::ServerCommand, std::uint8_t(ServerCommand::GotoGreen), net::NetFlag::Reliable); break; - case SDLK_F6: - m_sharedData.clientConnection.netClient.sendPacket(PacketID::ServerCommand, std::uint8_t(ServerCommand::EndGame), net::NetFlag::Reliable); -#ifdef USE_GNS - //Social::resetAchievement(AchievementStrings[AchievementID::SkinOfYourTeeth]); -#endif - break; +// case SDLK_F6: //this is used to log CSV +// m_sharedData.clientConnection.netClient.sendPacket(PacketID::ServerCommand, std::uint8_t(ServerCommand::EndGame), net::NetFlag::Reliable); +//#ifdef USE_GNS +// //Social::resetAchievement(AchievementStrings[AchievementID::SkinOfYourTeeth]); +//#endif +// break; case SDLK_F7: //m_sharedData.clientConnection.netClient.sendPacket(PacketID::SkipTurn, m_sharedData.localConnectionData.connectionID, net::NetFlag::Reliable); @@ -1015,7 +1018,7 @@ void GolfState::handleMessage(const cro::Message& msg) cmd.targetFlags = CommandID::StrokeIndicator; cmd.action = [&](cro::Entity e, float) { - float scale = std::max(0.25f, Clubs[getClub()].getPower(m_distanceToHole) / Clubs[ClubID::Driver].getPower(m_distanceToHole)); + float scale = std::max(0.25f, Clubs[getClub()].getPower(m_distanceToHole, m_sharedData.imperialMeasurements) / Clubs[ClubID::Driver].getPower(m_distanceToHole, m_sharedData.imperialMeasurements)); e.getComponent().setScale({ scale, 1.f }); }; m_gameScene.getSystem()->sendCommand(cmd); @@ -1588,12 +1591,18 @@ bool GolfState::simulate(float dt) if (m_idleTimer.elapsed() > idleTime) { m_idleTimer.restart(); - idleTime = cro::seconds(std::max(10.f, idleTime.asSeconds() / 2.f)); + idleTime = cro::seconds(std::max(20.f, idleTime.asSeconds() / 2.f)); - auto* msg = postMessage(MessageID::SceneMessage); - msg->type = SceneEvent::PlayerIdle; - gamepadNotify(GamepadNotify::NewPlayer); + //horrible hack to make the coughing less frequent + static std::int32_t coughCount = 0; + if ((coughCount++ % 8) == 0) + { + auto* msg = postMessage(MessageID::SceneMessage); + msg->type = SceneEvent::PlayerIdle; + + gamepadNotify(GamepadNotify::NewPlayer); + } auto* skel = &m_activeAvatar->model.getComponent(); auto animID = m_activeAvatar->animationIDs[AnimationID::Impatient]; @@ -4305,7 +4314,7 @@ void GolfState::buildScene() } else if (month == 6) { - if (cro::Util::Random::value(0, 5) == 0) + if (cro::Util::Random::value(0, 8) == 0) { buildBow(); } @@ -4563,6 +4572,7 @@ void GolfState::initAudio(bool loadTrees) progress = std::min(1.f, progress + dt); cro::AudioMixer::setPrefadeVolume(cro::Util::Easing::easeOutQuad(progress), MixerChannel::Effects); + cro::AudioMixer::setPrefadeVolume(cro::Util::Easing::easeOutQuad(progress), MixerChannel::Environment); if (progress == 1) { @@ -6463,6 +6473,16 @@ void GolfState::setCurrentPlayer(const ActivePlayer& player) }; m_uiScene.getSystem()->sendCommand(cmd); + //hide this if we're putting + cmd.targetFlags = CommandID::UI::WindString; + cmd.action = [&](cro::Entity e, float) + { + std::int32_t dir = getClub() == ClubID::Putter ? 0 : 1; + e.getComponent().getUserData().direction = dir; + e.getComponent().active = true; + }; + m_uiScene.getSystem()->sendCommand(cmd); + m_currentPlayer = player; @@ -6664,7 +6684,7 @@ void GolfState::predictBall(float powerPct) } auto pitch = Clubs[club].getAngle(); auto yaw = m_inputParser.getYaw(); - auto power = Clubs[club].getPower(m_distanceToHole) * powerPct; + auto power = Clubs[club].getPower(m_distanceToHole, m_sharedData.imperialMeasurements) * powerPct; glm::vec3 impulse(1.f, 0.f, 0.f); auto rotation = glm::rotate(glm::quat(1.f, 0.f, 0.f, 0.f), yaw, cro::Transform::Y_AXIS); diff --git a/samples/golf/src/golf/GolfState.hpp b/samples/golf/src/golf/GolfState.hpp index 2865e158c..375f22e3e 100644 --- a/samples/golf/src/golf/GolfState.hpp +++ b/samples/golf/src/golf/GolfState.hpp @@ -340,6 +340,7 @@ class GolfState final : public cro::State, public cro::GuiClient, public cro::Co void showCountdown(std::uint8_t); void createScoreboard(); void updateScoreboard(); + void logCSV() const; void showScoreboard(bool visible); void updateWindDisplay(glm::vec3); float estimatePuttPower(); diff --git a/samples/golf/src/golf/GolfStateUI.cpp b/samples/golf/src/golf/GolfStateUI.cpp index fc87e0c74..1c0be0d4c 100644 --- a/samples/golf/src/golf/GolfStateUI.cpp +++ b/samples/golf/src/golf/GolfStateUI.cpp @@ -53,6 +53,8 @@ source distribution. #include #include +#include +#include #include #include @@ -552,6 +554,35 @@ void GolfState::buildUI() entity.addComponent(); entity.addComponent(font).setCharacterSize(UITextSize); entity.getComponent().setFillColour(LeaderboardTextLight); + entity.addComponent().setUserData(); //happens to have the correct fields + entity.getComponent().getUserData().progress = 1.f; //but not the right default values :3 + entity.getComponent().function = + [](cro::Entity e, float dt) + { + const float Speed = dt * 3.f; + auto& [direction, progress] = e.getComponent().getUserData(); + if (direction == 0) + { + //shrink + progress = std::max(0.f, progress - Speed); + if (progress == 0) + { + e.getComponent().active = false; + } + } + else + { + //grow + progress = std::min(1.f, progress + Speed); + if (progress == 1) + { + e.getComponent().active = false; + } + } + + float scale = cro::Util::Easing::easeOutQuint(progress); + e.getComponent().setScale(glm::vec2(1.f, scale)); + }; infoEnt.getComponent().addChild(entity.getComponent()); auto windEnt = entity; @@ -2294,6 +2325,89 @@ void GolfState::updateScoreboard() m_leaderboardTexture.update(leaderboardEntries); } +void GolfState::logCSV() const +{ + //if (m_roundEnded) + { + auto courseName = m_courseTitle.toAnsiString(); + std::replace(courseName.begin(), courseName.end(), ' ', '_'); + std::replace(courseName.begin(), courseName.end(), ',', '_'); + if (m_sharedData.holeCount == 1) + { + courseName += "_front_nine"; + } + else if (m_sharedData.holeCount == 2) + { + courseName += "_back_nine"; + } + + std::string fileName = cro::SysTime::dateString() + "-" + cro::SysTime::timeString(); + std::replace(fileName.begin(), fileName.end(), '/', '-'); + std::replace(fileName.begin(), fileName.end(), ':', '-'); + fileName += "_" + courseName + ".csv"; + + cro::RaiiRWops out; + out.file = SDL_RWFromFile(fileName.c_str(), "w"); + if (out.file) + { + std::stringstream ss; + ss << "name,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13,h14,h15,h16,h17,h18,total\r\n"; + + std::int32_t totalPar = 0; + ss << "par,"; + for (auto hole : m_holeData) + { + ss << hole.par << ","; + totalPar += hole.par; + } + if (m_holeData.size() < 18u) + { + for (auto i = m_holeData.size(); i < 18u; ++i) + { + ss << "0,"; + } + } + ss << totalPar << "\r\n"; + + for (auto i = 0u; i < m_sharedData.connectionData.size(); ++i) + { + for (auto j = 0u; j < m_sharedData.connectionData[i].playerCount; ++j) + { + auto scoreCount = m_sharedData.connectionData[i].playerData[j].holeScores.size(); + + ss << m_sharedData.connectionData[i].playerData[j].name.toAnsiString() << ","; + std::int32_t total = 0; + for (auto score : m_sharedData.connectionData[i].playerData[j].holeScores) + { + ss << (int)score << ","; + total += score; + } + if (scoreCount < 18) + { + for (auto k = scoreCount; k < 18u; ++k) + { + ss << "0,"; + } + } + ss << total << "\r\n"; + } + } + + auto str = ss.str(); + SDL_RWwrite(out.file, str.data(), str.size(), 1); + LogI << "Saved " << fileName << std::endl; + } + else + { + LogE << "failed to open CSV file for writing: " << fileName << std::endl; + } + } + /*else + { + LogI << "Can't save CSV - Round not ended." << std::endl; + }*/ +} + void GolfState::showScoreboard(bool visible) { for (auto e : m_netStrengthIcons) diff --git a/samples/golf/src/golf/InputParser.cpp b/samples/golf/src/golf/InputParser.cpp index ecf9163ba..bf49d3a47 100644 --- a/samples/golf/src/golf/InputParser.cpp +++ b/samples/golf/src/golf/InputParser.cpp @@ -592,7 +592,7 @@ InputParser::StrokeResult InputParser::getStroke(std::int32_t club, std::int32_t { auto pitch = Clubs[club].getAngle(); auto yaw = getYaw(); - auto power = Clubs[club].getPower(distanceToHole); + auto power = Clubs[club].getPower(distanceToHole, m_sharedData.imperialMeasurements); //add hook/slice to yaw auto hook = getHook(); @@ -676,7 +676,7 @@ void InputParser::updateDistanceEstimation() //really we should be sourcing this the same as getStroke() auto pitch = Clubs[m_currentClub].getAngle(); - auto power = Clubs[m_currentClub].getPower(0.f); + auto power = Clubs[m_currentClub].getPower(0.f, m_sharedData.imperialMeasurements); auto spin = getSpin(); spin.y *= Clubs[m_currentClub].getTopSpinMultiplier(); pitch -= (4.f * cro::Util::Const::degToRad) * spin.y; @@ -806,7 +806,8 @@ void InputParser::updateStroke(float dt) break; case State::Power: { - if ((m_inputFlags & InputFlag::Cancel) && ((m_prevFlags & InputFlag::Cancel) == 0)) + if (((m_inputFlags & InputFlag::Cancel) && ((m_prevFlags & InputFlag::Cancel) == 0)) + || (m_power == 0 && m_powerbarDirection < 0)) { m_state = State::Aim; resetPower(); @@ -835,8 +836,8 @@ void InputParser::updateStroke(float dt) m_powerbarDirection = -1.f; } - if (m_power == 0 - || ((m_inputFlags & InputFlag::Action) && ((m_prevFlags & InputFlag::Action) == 0))) + if (/*m_power == 0 //this just resets the shot now - see above. + ||*/ ((m_inputFlags & InputFlag::Action) && ((m_prevFlags & InputFlag::Action) == 0))) { if (m_doubleTapClock.elapsed() > DoubleTapTime) { diff --git a/samples/golf/src/golf/MenuState.cpp b/samples/golf/src/golf/MenuState.cpp index 9d2729d6e..3fdeccc93 100644 --- a/samples/golf/src/golf/MenuState.cpp +++ b/samples/golf/src/golf/MenuState.cpp @@ -1069,6 +1069,7 @@ void MenuState::createScene() { cro::AudioMixer::setPrefadeVolume(0.f, MixerChannel::Music); cro::AudioMixer::setPrefadeVolume(0.f, MixerChannel::Effects); + cro::AudioMixer::setPrefadeVolume(0.f, MixerChannel::Environment); //fade in entity auto audioEnt = m_backgroundScene.createEntity(); @@ -1085,6 +1086,7 @@ void MenuState::createScene() float progress = currTime / MaxTime; cro::AudioMixer::setPrefadeVolume(progress, MixerChannel::Music); cro::AudioMixer::setPrefadeVolume(progress, MixerChannel::Effects); + cro::AudioMixer::setPrefadeVolume(progress, MixerChannel::Environment); if(currTime == MaxTime) { diff --git a/samples/golf/src/golf/OptionsState.cpp b/samples/golf/src/golf/OptionsState.cpp index eb44fc3b8..a96935425 100644 --- a/samples/golf/src/golf/OptionsState.cpp +++ b/samples/golf/src/golf/OptionsState.cpp @@ -113,7 +113,8 @@ namespace "Effects Volume", "Menu Volume", "Voice Volume", - "Vehicle Volume" + "Vehicle Volume", + "Environment" }; //generally static vars would be a bad idea, but in this case //a static index value will remember the last channel between @@ -504,6 +505,14 @@ bool OptionsState::handleEvent(const cro::Event& evt) void OptionsState::handleMessage(const cro::Message& msg) { + if (msg.id == MessageID::SystemMessage) + { + const auto& data = msg.getData(); + if (data.type == SystemEvent::PostProcessToggled) + { + m_scene.getActiveCamera().getComponent().active = true; + } + } m_scene.forwardMessage(msg); } @@ -1631,6 +1640,7 @@ void OptionsState::buildAVMenu(cro::Entity parent, const cro::SpriteSheet& sprit { togglePixelScale(m_sharedData, !m_sharedData.pixelScale); m_audioEnts[AudioID::Accept].getComponent().play(); + m_scene.getActiveCamera().getComponent().active = true; } }); @@ -1696,6 +1706,7 @@ void OptionsState::buildAVMenu(cro::Entity parent, const cro::SpriteSheet& sprit { m_videoSettings.fullScreen = !m_videoSettings.fullScreen; m_audioEnts[AudioID::Accept].getComponent().play(); + m_scene.getActiveCamera().getComponent().active = true; } }); @@ -1836,6 +1847,7 @@ void OptionsState::buildAVMenu(cro::Entity parent, const cro::SpriteSheet& sprit { m_sharedData.showBallTrail = !m_sharedData.showBallTrail; m_audioEnts[AudioID::Accept].getComponent().play(); + m_scene.getActiveCamera().getComponent().active = true; } }); @@ -1936,6 +1948,7 @@ void OptionsState::buildAVMenu(cro::Entity parent, const cro::SpriteSheet& sprit msg->type = SystemEvent::PostProcessToggled; m_audioEnts[AudioID::Accept].getComponent().play(); + m_scene.getActiveCamera().getComponent().active = true; } }); @@ -2006,6 +2019,7 @@ void OptionsState::buildAVMenu(cro::Entity parent, const cro::SpriteSheet& sprit { m_sharedData.imperialMeasurements = !m_sharedData.imperialMeasurements; m_audioEnts[AudioID::Accept].getComponent().play(); + m_scene.getActiveCamera().getComponent().active = true; } }); diff --git a/samples/golf/src/golf/ProfileState.cpp b/samples/golf/src/golf/ProfileState.cpp index 49ffa95bb..2f3fbdeeb 100644 --- a/samples/golf/src/golf/ProfileState.cpp +++ b/samples/golf/src/golf/ProfileState.cpp @@ -668,15 +668,14 @@ void ProfileState::buildScene() refreshSwatch(); auto fetchUIIndexFromColour = - [&](std::uint8_t colourIndex) + [&](std::uint8_t colourIndex, std::int32_t paletteIndex) { - //TODO this doesn't actually ensure colourIndex is within the range... const auto rowCount = m_uiScene.getSystem()->getGroupSize() / PaletteColumnCount; const auto x = colourIndex % PaletteColumnCount; auto y = colourIndex / PaletteColumnCount; y = (rowCount - 1) - y; - return y * PaletteColumnCount + x; + return (y * PaletteColumnCount + x) % pc::PairCounts[paletteIndex]; }; //colour buttons @@ -694,7 +693,7 @@ void ProfileState::buildScene() //set column/row count for menu m_uiScene.getSystem()->setActiveGroup(MenuID::Hair); m_uiScene.getSystem()->setColumnCount(PaletteColumnCount); - m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[0])); + m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[0], pc::ColourKey::Hair)); m_audioEnts[AudioID::Accept].getComponent().play(); @@ -714,14 +713,14 @@ void ProfileState::buildScene() m_uiScene.getSystem()->setActiveGroup(MenuID::Skin); m_uiScene.getSystem()->setColumnCount(PaletteColumnCount); - m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[1])); + m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[1], pc::ColourKey::Skin)); m_audioEnts[AudioID::Accept].getComponent().play(); m_lastSelected = e.getComponent().getSelectionIndex(); } }); - + auto topLightColour = createButton("colour_highlight", glm::vec2(17.f, 103.f)); topLightColour.getComponent().callbacks[cro::UIInput::ButtonUp] = uiSystem.addCallback([&, fetchUIIndexFromColour](cro::Entity e, const cro::ButtonEvent& evt) @@ -734,7 +733,7 @@ void ProfileState::buildScene() m_uiScene.getSystem()->setActiveGroup(MenuID::TopL); m_uiScene.getSystem()->setColumnCount(PaletteColumnCount); - m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[2])); + m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[2], pc::ColourKey::TopLight)); m_audioEnts[AudioID::Accept].getComponent().play(); @@ -754,7 +753,7 @@ void ProfileState::buildScene() m_uiScene.getSystem()->setActiveGroup(MenuID::TopD); m_uiScene.getSystem()->setColumnCount(PaletteColumnCount); - m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[3])); + m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[3], pc::ColourKey::TopDark)); m_audioEnts[AudioID::Accept].getComponent().play(); @@ -774,7 +773,7 @@ void ProfileState::buildScene() m_uiScene.getSystem()->setActiveGroup(MenuID::BottomL); m_uiScene.getSystem()->setColumnCount(PaletteColumnCount); - m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[4])); + m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[4], pc::ColourKey::BottomLight)); m_audioEnts[AudioID::Accept].getComponent().play(); @@ -794,7 +793,7 @@ void ProfileState::buildScene() m_uiScene.getSystem()->setActiveGroup(MenuID::BottomD); m_uiScene.getSystem()->setColumnCount(PaletteColumnCount); - m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[5])); + m_uiScene.getSystem()->selectAt(fetchUIIndexFromColour(m_activeProfile.avatarFlags[5], pc::ColourKey::BottomDark)); m_audioEnts[AudioID::Accept].getComponent().play(); diff --git a/samples/golf/src/golf/TerrainBuilder.cpp b/samples/golf/src/golf/TerrainBuilder.cpp index b2e07c2a0..d8ccdb117 100644 --- a/samples/golf/src/golf/TerrainBuilder.cpp +++ b/samples/golf/src/golf/TerrainBuilder.cpp @@ -573,7 +573,7 @@ void TerrainBuilder::create(cro::ResourceCollection& resources, cro::Scene& scen } glCheck(glUseProgram(m_slopeProperties.shader)); glCheck(glUniform1f(m_slopeProperties.alphaUniform, alpha)); - m_slopeProperties.currentAlpha = alpha / m_sharedData.gridTransparency; + m_slopeProperties.currentAlpha = m_sharedData.gridTransparency == 0 ? 0.f : alpha / m_sharedData.gridTransparency; }; m_slopeProperties.meshData = &entity.getComponent().getMeshData(); diff --git a/samples/golf/src/golf/TerrainShader.inl b/samples/golf/src/golf/TerrainShader.inl index 4e422f5a0..c468021d1 100644 --- a/samples/golf/src/golf/TerrainShader.inl +++ b/samples/golf/src/golf/TerrainShader.inl @@ -183,7 +183,7 @@ R"( vec4 colour = vec4(c, v_heightData.x); colour.a *= u_alpha; - colour = mix(vec4(DotColour, (0.5 + (0.5 * u_alpha)) * v_heightData.x), colour, alpha); + colour = mix(vec4(DotColour, (0.5 + (0.5 * u_alpha)) * v_heightData.x * step(0.001, alpha)), colour, alpha); FRAG_OUT = colour; }