#include #include #include #include // munged from https://github.com/simontime/Resead namespace sead { class Random { public: void init(); void init(uint32_t seed); void init(uint32_t seed1, uint32_t seed2, uint32_t seed3, uint32_t seed4); uint32_t getU32(); uint64_t getU64(); void getContext(uint32_t *seed1, uint32_t *seed2, uint32_t *seed3, uint32_t *seed4) const; private: uint32_t mContext[4]; }; void Random::init() { init(42069); } void Random::init(uint32_t seed) { mContext[0] = 0x6C078965 * (seed ^ (seed >> 30)) + 1; mContext[1] = 0x6C078965 * (mContext[0] ^ (mContext[0] >> 30)) + 2; mContext[2] = 0x6C078965 * (mContext[1] ^ (mContext[1] >> 30)) + 3; mContext[3] = 0x6C078965 * (mContext[2] ^ (mContext[2] >> 30)) + 4; } void Random::init(uint32_t seed1, uint32_t seed2, uint32_t seed3, uint32_t seed4) { if ((seed1 | seed2 | seed3 | seed4) == 0) // seeds must not be all zero. { seed1 = 1; seed2 = 0x6C078967; seed3 = 0x714ACB41; seed4 = 0x48077044; } mContext[0] = seed1; mContext[1] = seed2; mContext[2] = seed3; mContext[3] = seed4; } uint32_t Random::getU32() { uint32_t n = mContext[0] ^ (mContext[0] << 11); mContext[0] = mContext[1]; mContext[1] = mContext[2]; mContext[2] = mContext[3]; mContext[3] = n ^ (n >> 8) ^ mContext[3] ^ (mContext[3] >> 19); return mContext[3]; } uint64_t Random::getU64() { uint32_t n1 = mContext[0] ^ (mContext[0] << 11); uint32_t n2 = mContext[1]; uint32_t n3 = n1 ^ (n1 >> 8) ^ mContext[3]; mContext[0] = mContext[2]; mContext[1] = mContext[3]; mContext[2] = n3 ^ (mContext[3] >> 19); mContext[3] = n2 ^ (n2 << 11) ^ ((n2 ^ (n2 << 11)) >> 8) ^ mContext[2] ^ (n3 >> 19); return ((uint64_t)mContext[2] << 32) | mContext[3]; } void Random::getContext(uint32_t *seed1, uint32_t *seed2, uint32_t *seed3, uint32_t *seed4) const { *seed1 = mContext[0]; *seed2 = mContext[1]; *seed3 = mContext[2]; *seed4 = mContext[3]; } } // namespace sead uint32_t pf(float f) { return *((uint32_t *)&f); } struct TurnipPrices { int32_t basePrice; int32_t sellPrices[14]; uint32_t whatPattern; int32_t tmp40; void calculate(); // utility stuff for testing sead::Random rng; bool randbool() { return rng.getU32() & 0x80000000; } int randint(int min, int max) { return (((uint64_t)rng.getU32() * (uint64_t)(max - min + 1)) >> 32) + min; } float randfloat(float a, float b) { uint32_t val = 0x3F800000 | (rng.getU32() >> 9); float fval = *(float *)(&val); return a + ((fval - 1.0f) * (b - a)); } float randfloatMockedLeft(float a, float b) { uint32_t val = 0x3F800000 | (0 >> 9); float fval = *(float *)(&val); return a + ((fval - 1.0f) * (b - a)); } float randfloatMockedRight(float a, float b) { uint32_t val = 0x3F800000 | (UINT32_MAX >> 9); float fval = *(float *)(&val); return a + ((fval - 1.0f) * (b - a)); } float randfloatMockedMin(float a, float b) { return std::min(randfloatMockedLeft(a, b), randfloatMockedRight(a, b)); } float randfloatMockedMax(float a, float b) { return std::max(randfloatMockedLeft(a, b), randfloatMockedRight(a, b)); } int intceil(float val) { return (int)(val + 0.99999f); } }; void TurnipPrices::calculate() { basePrice = randint(90, 110); int chance = randint(0, 99); // select the next pattern int nextPattern; if (whatPattern >= 4) { nextPattern = 2; } else { switch (whatPattern) { case 0: if (chance < 20) { nextPattern = 0; } else if (chance < 50) { nextPattern = 1; } else if (chance < 65) { nextPattern = 2; } else { nextPattern = 3; } break; case 1: if (chance < 50) { nextPattern = 0; } else if (chance < 55) { nextPattern = 1; } else if (chance < 75) { nextPattern = 2; } else { nextPattern = 3; } break; case 2: if (chance < 25) { nextPattern = 0; } else if (chance < 70) { nextPattern = 1; } else if (chance < 75) { nextPattern = 2; } else { nextPattern = 3; } break; case 3: if (chance < 45) { nextPattern = 0; } else if (chance < 70) { nextPattern = 1; } else if (chance < 85) { nextPattern = 2; } else { nextPattern = 3; } break; } } whatPattern = nextPattern; /* if (checkGlobalFlag("FirstKabuBuy")) { if (!checkGlobalFlag("FirstKabuPattern")) { setGlobalFlag("FirstKabuPattern", true); whatPattern = 3; } } */ for (int i = 2; i < 14; i++) sellPrices[i] = 0; sellPrices[0] = basePrice; sellPrices[1] = basePrice; int work; int decPhaseLen1, decPhaseLen2, peakStart; int hiPhaseLen1, hiPhaseLen2and3, hiPhaseLen3; float rate; switch (whatPattern) { case 0: // PATTERN 0: high, decreasing, high, decreasing, high work = 2; decPhaseLen1 = randbool() ? 3 : 2; decPhaseLen2 = 5 - decPhaseLen1; hiPhaseLen1 = randint(0, 6); hiPhaseLen2and3 = 7 - hiPhaseLen1; hiPhaseLen3 = randint(0, hiPhaseLen2and3 - 1); // high phase 1 for (int i = 0; i < hiPhaseLen1; i++) { sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice); } // decreasing phase 1 rate = randfloat(0.8, 0.6); for (int i = 0; i < decPhaseLen1; i++) { sellPrices[work++] = intceil(rate * basePrice); rate -= 0.04; rate -= randfloat(0, 0.06); } // high phase 2 for (int i = 0; i < (hiPhaseLen2and3 - hiPhaseLen3); i++) { sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice); } // decreasing phase 2 rate = randfloat(0.8, 0.6); for (int i = 0; i < decPhaseLen2; i++) { sellPrices[work++] = intceil(rate * basePrice); rate -= 0.04; rate -= randfloat(0, 0.06); } // high phase 3 for (int i = 0; i < hiPhaseLen3; i++) { sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice); } break; case 1: // PATTERN 1: decreasing middle, high spike, random low peakStart = randint(3, 9); rate = randfloat(0.9, 0.85); for (work = 2; work < peakStart; work++) { sellPrices[work] = intceil(rate * basePrice); rate -= 0.03; rate -= randfloat(0, 0.02); } sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice); sellPrices[work++] = intceil(randfloat(1.4, 2.0) * basePrice); sellPrices[work++] = intceil(randfloat(2.0, 6.0) * basePrice); sellPrices[work++] = intceil(randfloat(1.4, 2.0) * basePrice); sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice); for (; work < 14; work++) { sellPrices[work] = intceil(randfloat(0.4, 0.9) * basePrice); } break; case 2: // PATTERN 2: consistently decreasing rate = 0.9; rate -= randfloat(0, 0.05); for (work = 2; work < 14; work++) { sellPrices[work] = intceil(rate * basePrice); rate -= 0.03; rate -= randfloat(0, 0.02); } break; case 3: // PATTERN 3: decreasing, spike, decreasing peakStart = randint(2, 9); // decreasing phase before the peak rate = randfloat(0.9, 0.4); for (work = 2; work < peakStart; work++) { sellPrices[work] = intceil(rate * basePrice); rate -= 0.03; rate -= randfloat(0, 0.02); } sellPrices[work++] = intceil(randfloat(0.9, 1.4) * (float)basePrice); sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice); rate = randfloat(1.4, 2.0); sellPrices[work++] = intceil(randfloat(1.4, rate) * basePrice) - 1; sellPrices[work++] = intceil(rate * basePrice); sellPrices[work++] = intceil(randfloat(1.4, rate) * basePrice) - 1; // decreasing phase after the peak if (work < 14) { rate = randfloat(0.9, 0.4); for (; work < 14; work++) { sellPrices[work] = intceil(rate * basePrice); rate -= 0.03; rate -= randfloat(0, 0.02); } } break; } sellPrices[0] = 0; sellPrices[1] = 0; } int main(int argc, char **argv) { TurnipPrices turnips; turnips.rng.init(); float checkingMin = turnips.randfloatMockedMin(1000.0, 2000.0), checkingMax = turnips.randfloatMockedMax(1000.0, 2000.0); printf("checkingMin, checkingMax are %f %f exact? %d %d\n", checkingMin, checkingMax, checkingMin == 1000.0, checkingMax == 2000.0); checkingMin = turnips.randfloatMockedMin(2000.0, 1000.0), checkingMax = turnips.randfloatMockedMax(2000.0, 1000.0); printf("checkingMin, checkingMax are %f %f exact? %d %d\n", checkingMin, checkingMax, checkingMin == 1000.0, checkingMax == 2000.0); float rateLow = turnips.randfloatMockedMin(0.9, 0.85); float rateHigh = turnips.randfloatMockedMax(0.9, 0.85); for (int work = 2; work < 6; work++) { int priceMin = 999999, priceMax = 0; int priceLow, priceHigh; for (int basePrice = 90; basePrice <= 110; basePrice++) { // could have added 20 directly priceLow = turnips.intceil(rateLow * basePrice); priceHigh = turnips.intceil(rateHigh * basePrice); priceMin = std::min(priceLow, priceMin); priceMax = std::max(priceHigh, priceMax); } printf("PRICE period %d low %d high %d\n", work, priceMin, priceMax); rateLow -= 0.03; rateHigh -= 0.03; rateLow -= turnips.randfloatMockedMax(0, 0.02); rateHigh -= turnips.randfloatMockedMin(0, 0.02); } return 0; }