Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added difficulty-dependent "grace period" for crime and morale #1466

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion OPHD/States/MapViewState.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class MapViewState : public Wrapper
void updateCommercial();
void updateMaintenance();
void updateMorale();
void notifyBirthsAndDeaths();
DanRStevens marked this conversation as resolved.
Show resolved Hide resolved
void updateResidentialCapacity();
void updateBiowasteRecycling();
void updateResources();
Expand Down Expand Up @@ -299,13 +300,26 @@ class MapViewState : public Wrapper
TechnologyCatalog mTechnologyReader;

Planet::Attributes mPlanetAttributes;
Difficulty mDifficulty = Difficulty::Medium;

int mFood{0};

// DIFFICULTY
Difficulty mDifficulty = Difficulty::Medium;

// Length of "honeymoon period" of no crime/morale updates after landing, in turns
std::map<Difficulty, int> gracePeriod
{
{Difficulty::Beginner, 30},
{Difficulty::Easy, 25},
{Difficulty::Medium, 20},
{Difficulty::Hard, 15}
};

// MISCELLANEOUS
int mTurnCount = 0;

int mTurnNumberOfLanding = std::numeric_limits<int>::max(); /**< First turn that human colonists landed. If never landed, default is int max (representing the future). */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the update to use constants::ColonyShipOrbitTime as the default value during loading of saved games, perhaps we should modify this to match. That way the default value on all code paths is the same.

In a practical sense, the turn of landing will never exceed the colony ship orbit time, since if colonists aren't landed by then, they all die in a fiery crash, and it's game over.


int mCurrentMorale;
int mPreviousMorale;

Expand Down
3 changes: 3 additions & 0 deletions OPHD/States/MapViewStateIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ void MapViewState::save(const std::string& filePath)
{"prev_morale", mPreviousMorale},
{"colonist_landers", mLandersColonist},
{"cargo_landers", mLandersCargo},
{"turn_number_of_landing", mTurnNumberOfLanding},
{"children", population.child},
{"students", population.student},
{"workers", population.worker},
Expand Down Expand Up @@ -566,6 +567,8 @@ void MapViewState::readPopulation(NAS2D::Xml::XmlElement* element)
mCurrentMorale = dictionary.get<int>("morale");
mPreviousMorale = dictionary.get<int>("prev_morale");

mTurnNumberOfLanding = dictionary.get<int>("turn_number_of_landing", constants::ColonyShipOrbitTime);

const auto meanCrimeRate = dictionary.get<int>("mean_crime", 0);

const auto children = dictionary.get<int>("children");
Expand Down
29 changes: 26 additions & 3 deletions OPHD/States/MapViewStateTurn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include <vector>
#include <algorithm>


namespace
{
const std::map<std::string, IconGrid::Item> StructureItemFromString =
Expand Down Expand Up @@ -244,6 +243,13 @@ void MapViewState::updateMorale()
mPopulationPanel.addMoraleReason(moraleReason.first, moraleReason.second);
mCurrentMorale += moraleReason.second;
}
}


void MapViewState::notifyBirthsAndDeaths()
{
const int birthCount = mPopulation.birthCount();
const int deathCount = mPopulation.deathCount();

// Push notifications
if (birthCount)
Expand Down Expand Up @@ -710,7 +716,10 @@ void MapViewState::nextTurn()

updateResidentialCapacity();

if (mPopulation.getPopulations().size() > 0)
int turnsSinceLanding = mTurnCount - mTurnNumberOfLanding; // If negative, landing has not yet occurred.

// Colony will not have a crime rate until at least n turns from landing, depending on difficulty
if (turnsSinceLanding > gracePeriod[mDifficulty])
DanRStevens marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +719 to +722
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you wanted to avoid the comment about potential negative values, maybe we could still partially use the idea from the last review, and have a local variable:

moraleActiveTurn = mTurnNumberOfLanding + gracePeriod[mDifficulty]

The checks would then be:

if (mTurnCount > moraleActiveTurn)

We wouldn't need to worry about negative values in that case. Additionally, assuming the default value for mTurnNumberOfLanding is updated to constants::ColonyShipOrbitTime we wouldn't need to worry about potential overflow either.

As a small added bonus, it also means we avoid a double lookup of gracePeriod within the same method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was just thinking this suggestion could have gone further, and set a bool variable, rather than repeating a boolean expression in each if condition.

bool isMoraleEnabled = mTurnCount > mTurnNumberOfLanding + gracePeriod[mDifficulty];

{
mCrimeRateUpdate.update(mPoliceOverlays);
auto structuresCommittingCrimes = mCrimeRateUpdate.structuresCommittingCrimes();
Expand All @@ -723,7 +732,15 @@ void MapViewState::nextTurn()
updateMaintenance();
updateCommercial();
updateBiowasteRecycling();
updateMorale();

// Morale will not change until at least n turns from landing, depending on difficulty
if (turnsSinceLanding > gracePeriod[mDifficulty])
DanRStevens marked this conversation as resolved.
Show resolved Hide resolved
{
updateMorale();
}

notifyBirthsAndDeaths();

updateRobots();
updateResources();
updateStructuresAvailability();
Expand All @@ -747,6 +764,12 @@ void MapViewState::nextTurn()

mMineOperationsWindow.updateTruckAvailability();

// If this is the first turn with population, then set mTurnNumberOfLanding
if (mPopulation.getPopulations().size() > 0 && mTurnCount < mTurnNumberOfLanding)
{
mTurnNumberOfLanding = mTurnCount;
}
DanRStevens marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +767 to +771
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the comment on Discord, perhaps this should be moved to MapViewState::onDeployColonistLander.

In that case, we know for sure there are going to be colonists landed at that point, so we don't need the population size check, which was really just a way of detecting when colonists have landed.

We would still need to retain the second check, since there can be multiple landers, and we probably want to activate on the first landing, and not reset the value upon a subsequent landing.

The second check should still work correctly with a default value for mTurnNumberOfLanding of constants::ColonyShipOrbitTime.


// Check for Game Over conditions
if (mPopulation.getPopulations().size() <= 0 && mLandersColonist == 0)
{
Expand Down