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

Lstebner/achievement i am rich #77

Merged
merged 1 commit into from May 31, 2021
Merged

Conversation

lstebner
Copy link
Collaborator

@lstebner lstebner commented May 29, 2021

This PR implements 3 new achievements in a series referred to as "I am Rich". this closes issue #73 , and can be tested here https://farmhand-git-lstebner-achievement-i-am-rich-jeremyckahn.vercel.app/

this PR also adds a few new utils which were used to implement this feature

  • percentageString util to convert a floating percent to a string value
  • getSalePriceMultiplier looks at achievements and returns a multiplier value

completed achievements:

Screen Shot 2021-05-29 at 2 37 17 PM

incomplete achievements:

Screen Shot 2021-05-30 at 9 35 01 AM

increased price in sell view:

Screen Shot 2021-05-29 at 2 34 28 PM

unit tests:

Screen Shot 2021-05-29 at 1 32 34 PM

Screen Shot 2021-05-29 at 1 33 03 PM

@vercel
Copy link

vercel bot commented May 29, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/jeremyckahn/farmhand/CPA11Rgg7gTdCo6gWejukcUwBm3T
✅ Preview: https://farmhand-git-lstebner-achievement-i-am-rich-jeremyckahn.vercel.app

@lstebner lstebner mentioned this pull request May 29, 2021
Copy link
Owner

@jeremyckahn jeremyckahn left a comment

Choose a reason for hiding this comment

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

This is off to a great start! I added comments throughout, but let me know if anything is unclear and we can discuss further.

src/data/achievements.js Show resolved Hide resolved
src/data/achievements.js Outdated Show resolved Hide resolved
src/data/achievements.test.js Outdated Show resolved Hide resolved
src/data/achievements.test.js Outdated Show resolved Hide resolved
src/reducers.js Outdated Show resolved Hide resolved
src/reducers.js Outdated Show resolved Hide resolved
src/reducers.js Outdated
salePriceMultiplier = 1.1
} else if (state.completedAchievements['i-am-rich-3']) {
salePriceMultiplier = 1.05
}
Copy link
Owner

Choose a reason for hiding this comment

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

This comment is aimed at your question in the getItemCurrentValue util, but makes more sense to answer here.

should valueAdjustments have a "global" adjustment or something for any permanent global increases?

We should avoid using valueAdjustments to calculate sale bonuses, as that object is intended to only define market fluctuations. With that said, my intuition is to move this salePriceMultiplier calculation to a helper function in src/utils.js and use that helper both here and in getItemCurrentValue. What do you think of that approach?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i had a feeling valueAdjustments was something market specific. can we update the variable name? (is that easy? to like, marketValueAdjustments?). or add some documentation around it. i didn't see any explanation for the variable anywhere. whatever you prefer @jeremyckahn . i can also do the work if you let me know which you prefer.

onto the util...that makes sense to me! that will scale nicely later on.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

lots of unit tests, and a util or two later i think i got there!

Copy link
Owner

Choose a reason for hiding this comment

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

i had a feeling valueAdjustments was something market specific. can we update the variable name? (is that easy? to like, marketValueAdjustments?). or add some documentation around it. i didn't see any explanation for the variable anywhere. whatever you prefer @jeremyckahn . i can also do the work if you let me know which you prefer.

Whoops, I saw this after the fact! Sorry about that. I've effectively addressed this here: https://github.com/jeremyckahn/farmhand/pull/77/files#r641988878

tl;dr: Yes, we should definitely rename valueAdjustments to something like marketValueAdjustments for the relative value calculations, but we'll also need to having some sort of "grand total" value that is presented to the user as well.

Copy link
Owner

@jeremyckahn jeremyckahn left a comment

Choose a reason for hiding this comment

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

Awesome progress so far! There's a few issues that need to be addressed, but I'm really excited to see how well this is coming along!

src/constants.js Outdated
1: 0.05,
2: 0.1,
3: 0.25,
}
Copy link
Owner

Choose a reason for hiding this comment

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

I definitely prefer bundling these into a collection vs. multiple const variables, it fits well with the rest of this PR! In this case, I think it would be more straightforward to use an Array here, as the keys are just number indices and it'd be more natural for the code that works with I_AM_RICH_BONUSES to be zero-based. What do you think about changing this Object to being an Array?

)} bonus.`,
condition: state => state.revenue >= goal,
reward: state => state,
}))(),
Copy link
Owner

Choose a reason for hiding this comment

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

These are looking much better! Nice work! 👏

src/data/achievements.test.js Show resolved Hide resolved
description: `Earn ${dollarString(goal)}`,
rewardDescription: `All sales receive a ${percentageString(
I_AM_RICH_BONUSES[1],
'%'
Copy link
Owner

Choose a reason for hiding this comment

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

It doesn't look like the '%' parameter is needed here. Was that left over from an earlier iteration?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yup! a formatNumber attempt hah. thanks for noticing that

src/data/achievements.test.js Outdated Show resolved Hide resolved
src/utils.js Show resolved Hide resolved
@@ -145,6 +146,8 @@ export const Item = ({

const avatar = <img {...{ src: items[id] }} alt={name} />

adjustedValue *= getSalePriceMultiplier(completedAchievements)
Copy link
Owner

Choose a reason for hiding this comment

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

Rather than mutating adjustedValue here, I think we're going to need to add an additional number to represent adjustedValue * getSalePriceMultiplier(completedAchievements). The reason for this is that adjustedValue, at least for non-Shop items, specifically defines the value of an item adjusted for current market values. Modifying it here will break the calculations at these points deeper in the component:

<PurchaseValueIndicator
{...{ id, value: adjustedValue, valueAdjustments }}
/>

<SellValueIndicator
{...{ id, value: adjustedValue, valueAdjustments }}
/>

This is a bit confusing because #73 makes the semantics of this variable a bit unclear. It may make sense to rename adjustedValue to something like marketAdjustedValue, since the current name is too vague now. I think "adjustedValue" is good for representing "the final number that is presented to the user," in case you need some help with the variable naming here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i see now, thanks for pointing that out. i think it actually makes the most sense to add a sellPrice variable and only adjust the "Sell price" field. i would like to see adjustedValue updated as you said, but there are many other similar variables that i would also want to update like previousDatAdjustedValue and historicalValueAdjustments so I think it's best to leave those all for now. how does that sound?

Copy link
Owner

Choose a reason for hiding this comment

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

Oh yeah, those variables are functionally affected by this feature at all, and changing their name is actually quite a bit more involved because they are part of the persisted game data. They're named slightly more vaguely than I'd like right now, but it's not worth changing them in this PR.

src/utils.js Outdated
@@ -192,6 +193,12 @@ export const dollarString = number => formatNumber(number, '$0,0')
*/
export const integerString = number => formatNumber(number, '0,0')

/**
* @param {number} a float
Copy link
Owner

Choose a reason for hiding this comment

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

Per JSDoc syntax, this needs to reference the name of the variable. So, this will need to be something like:

* @param {number} number A float

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oops, number/number! good catch

src/utils.js Show resolved Hide resolved
@lstebner
Copy link
Collaborator Author

lstebner commented May 30, 2021

@jeremyckahn pushed another round of updates for all your latest comments. thanks for the detailed review!

@jeremyckahn jeremyckahn self-requested a review May 30, 2021 15:55
Copy link
Owner

@jeremyckahn jeremyckahn left a comment

Choose a reason for hiding this comment

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

Thanks for the latest iteration! This is looking great and I think we're almost there. I saw a few mostly minor regression issues to address, but I think the hard problems are solved at this point!

src/components/Item/Item.js Show resolved Hide resolved
src/constants.js Show resolved Hide resolved
src/data/achievements.js Outdated Show resolved Hide resolved
src/utils.js Outdated Show resolved Hide resolved
src/utils.js Outdated Show resolved Hide resolved
@jeremyckahn
Copy link
Owner

The code looks good to me, but I just tried to test out the new achievement rewards and they don't seem to factor in the sales bonus. 😕

Here's where I tested out the new feature: https://farmhand-git-lstebner-achievement-i-am-rich-jeremyckahn.vercel.app/

Here's the save file I used to test this out: https://gist.github.com/jeremyckahn/4dc3bd35f6e2db3c47b24dcc62a5db27

(You can save that JSON data to a local file and then import it into the game for testing.)

You'll see there that Carrots have a boosted value of $26.25, but once sold, the player only gets the non-boosted value of $25. I'll take a look to see what part of the code might need to be revisited to fix this too.

@jeremyckahn
Copy link
Owner

The code looks good to me, but I just tried to test out the new achievement rewards and they don't seem to factor in the sales bonus. 😕

Here's where I tested out the new feature: https://farmhand-git-lstebner-achievement-i-am-rich-jeremyckahn.vercel.app/

Here's the save file I used to test this out: https://gist.github.com/jeremyckahn/4dc3bd35f6e2db3c47b24dcc62a5db27

(You can save that JSON data to a local file and then import it into the game for testing.)

You'll see there that Carrots have a boosted value of $26.25, but once sold, the player only gets the non-boosted value of $25. I'll take a look to see what part of the code might need to be revisited to fix this too.

Based on some quick experimentation, it looks like this change might be all that's needed here:

diff --git a/src/reducers.js b/src/reducers.js
index a10d58a..617bc03 100644
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -1142,12 +1142,11 @@ export const sellItem = (state, { id }, howMany = 1) => {
           castToMoney(adjustedItemValue * LOAN_GARNISHMENT_RATE)
         )
       : 0
-    const garnishedProfit = adjustedItemValue - loanGarnishment
+    const garnishedProfit =
+      adjustedItemValue * getSalePriceMultiplier(completedAchievements) -
+      loanGarnishment
     loanBalance = moneyTotal(loanBalance, -loanGarnishment)
-    saleValue = moneyTotal(
-      saleValue * getSalePriceMultiplier(completedAchievements),
-      garnishedProfit
-    )
+    saleValue = moneyTotal(saleValue, garnishedProfit)
   }
 
   if (saleIsGarnished) {

The tests pass with this, and I'm seeing the correct behavior in-game with it!

  this adds a series of 3 new achievements based on farm revenue. the
  reward is a permanent increase to all sale prices. more info about
  achievements can be found in the wiki https://github.com/jeremyckahn/farmhand/wiki/Achievements
Copy link
Owner

@jeremyckahn jeremyckahn left a comment

Choose a reason for hiding this comment

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

I've QA'ed and verified this on https://farmhand-git-lstebner-achievement-i-am-rich-jeremyckahn.vercel.app/, and everything seems to be working perfectly! Thank you @lstebner for sticking with this and bringing it through to completion. This feature adds some much-needed late-game content and lays the groundwork for more interesting mechanics down the line. Awesome work! LGTM! 🚀

@lstebner lstebner merged commit 6bed24f into develop May 31, 2021
@lstebner lstebner deleted the lstebner/achievement-i-am-rich branch May 31, 2021 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants