105 lines
3.2 KiB
JavaScript
105 lines
3.2 KiB
JavaScript
import { REGIONS } from "../config/regions.js"
|
|
import { getState, updateBalance, unlockGate, returnBalance } from "../save/state.js"
|
|
|
|
/**
|
|
* Can this region be unlocked right now, and if not, why not?
|
|
*
|
|
* Returns an outcome object rather than a boolean so callers can explain the
|
|
* refusal to the player. `reason` is a code, not display text - whoever shows
|
|
* it is responsible for turning it into a translated message.
|
|
*
|
|
* { ok: true }
|
|
* { ok: false, reason: "unknown_region" } developer error
|
|
* { ok: false, reason: "already_unlocked" }
|
|
* { ok: false, reason: "missing_prior_region", requires: "farmland" }
|
|
* { ok: false, reason: "insufficient_funds", cost: 500, balance: 120 }
|
|
*
|
|
* @param {string} regionID - a REGIONS key, e.g. "farmland"
|
|
*/
|
|
export function canUnlock(regionID) {
|
|
|
|
/*
|
|
the region's whole config record:
|
|
{ nameKey, order, unlockedAtStart, unlockedCost}
|
|
*/
|
|
const region = REGIONS[regionID];
|
|
if (region === undefined) {
|
|
return { ok: false, reason: "unknown_region" };
|
|
}
|
|
// order number from the REGIONS section we keyed
|
|
const order = region.order;
|
|
// we return the full record.
|
|
const gates = getState().gates;
|
|
/*
|
|
if the records value for that key's order is
|
|
true: unlocked
|
|
*/
|
|
if (gates[regionID] === true) {
|
|
return { ok: false, reason: "already_unlocked" };
|
|
}
|
|
|
|
/*
|
|
WE ARE KEYING FOR THE KEY VALUE'S ORDER PRIOR TO PASSED REGION{RegionID}
|
|
the prior value has to be true for the passed region to unlock
|
|
*/
|
|
let priorRegion = null;
|
|
for (const id in REGIONS) {
|
|
// never pass lagoon otherwise all conditions fail
|
|
if (REGIONS[id].order === order - 1) {
|
|
/*
|
|
again tdlr we get the key prior to the past key
|
|
so for example command canUnlock("seaside");
|
|
we are retrieving farm land for comparison
|
|
it's sequential you can't unlock zones non
|
|
out of order
|
|
*/
|
|
priorRegion = id;
|
|
}
|
|
}
|
|
|
|
// if first region is auto unlocked we will never meet this condition
|
|
if (priorRegion === null) {
|
|
return { ok: false, reason: "missing_prior_region", requires: null };
|
|
}
|
|
|
|
/*
|
|
the prior region before this one must be open first
|
|
*/
|
|
if (gates[priorRegion] !== true) {
|
|
return { ok: false, reason: "missing_prior_region", requires: priorRegion };
|
|
}
|
|
|
|
//they have to be able to pay for it.
|
|
const cost = region.unlockedCost;
|
|
const balance = returnBalance();
|
|
if (balance < cost) {
|
|
return { ok: false, reason: "insufficient_funds", cost: cost, balance: balance };
|
|
}
|
|
|
|
return { ok: true };
|
|
}
|
|
|
|
/**
|
|
* Unlocks a region if the rules allow it, charges the cost, and saves.
|
|
* object canUnlock produced and can explain what went wrong.
|
|
*
|
|
* @param {string} regionID - a REGIONS key, e.g. "farmland"
|
|
*/
|
|
export function unlockRegion(regionID) {
|
|
|
|
const result = canUnlock(regionID);
|
|
if (!result.ok) {
|
|
return result;
|
|
}
|
|
|
|
unlockGate(regionID, true);
|
|
|
|
/*
|
|
always make sure things that cost money are passed negative,
|
|
because otherwise it would add to the balance
|
|
*/
|
|
updateBalance(-REGIONS[regionID].unlockedCost);
|
|
|
|
return { ok: true };
|
|
}
|