Skip to content
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
9 changes: 8 additions & 1 deletion components/HiddenCostGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ function EventPanel({ event, healthPoints }: { event: MedicalEvent; healthPoints
<p className="mt-3 leading-7 text-slate-700">
A care decision is needed this round. Compare the point cost, the income added this round, and the health outcome before choosing.
</p>
<p className="mt-3 rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm font-medium leading-6 text-amber-950">
Lower health can reduce the points earned in later rounds.
</p>
<div className="mt-4 flex flex-wrap gap-3 text-sm font-semibold">
<span className="rounded-full bg-white px-4 py-2 text-slate-700 shadow-sm">Base round income: +{formatPoints(ROUND_INCOME_POINTS)} pts</span>
<span className="rounded-full bg-white px-4 py-2 text-slate-700 shadow-sm">Health-adjusted income: +{formatPoints(healthAdjustedIncome)} pts</span>
Expand Down Expand Up @@ -484,7 +487,7 @@ function ChoiceButton({
}

function ResultPanel({ result, mode, onContinue }: { result: RoundResult; mode: "primary" | "replay"; onContinue: () => void }) {
const continueLabel = result.isComplete ? (mode === "replay" ? "Return to results" : "Continue to visible results") : "Continue to next round";
const continueLabel = result.isComplete ? (mode === "replay" ? "Return to results" : "Continue to score table") : "Continue to next round";

return (
<section className="rounded-[2rem] border border-emerald-200 bg-emerald-50 p-5 shadow-sm md:p-6" aria-live="polite">
Expand All @@ -504,6 +507,10 @@ function ResultPanel({ result, mode, onContinue }: { result: RoundResult; mode:
<ResultChange label="Health points" before={result.round.healthBefore} after={result.round.healthAfter} icon="❤️" />
</div>

<p className="mt-4 rounded-2xl bg-white p-4 text-sm leading-6 text-slate-700 shadow-sm">
This round added +{formatPoints(result.round.roundIncome ?? ROUND_INCOME_POINTS)} health-adjusted income before subtracting -{formatPoints(result.round.paidCost)} treatment cost.
</p>

<button
type="button"
onClick={onContinue}
Expand Down
28 changes: 24 additions & 4 deletions utils/researchMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ROUND_INCOME_POINTS, STARTING_FINANCIAL_POINTS } from "@/utils/game";
import type {
ComputedResearchMetrics,
GameChoice,
GameRoundData,
GameSummary,
HiddenCostGameState,
PostRevealSurveyAnswers,
Expand All @@ -12,8 +13,8 @@ import type {
TreatmentChoiceCounts,
} from "@/types/research";

export const RESEARCH_EXPORT_VERSION = "prototype-1.2";
export const RESEARCH_SCHEMA_VERSION = "hidden-cost-game-research-schema-7";
export const RESEARCH_EXPORT_VERSION = "prototype-1.3";
export const RESEARCH_SCHEMA_VERSION = "hidden-cost-game-research-schema-8";
export const RESEARCH_CONSENT_VERSION = "pilot-consent-v1";

const choiceCountKeys: Record<GameChoice, keyof TreatmentChoiceCounts> = {
Expand All @@ -22,6 +23,18 @@ const choiceCountKeys: Record<GameChoice, keyof TreatmentChoiceCounts> = {
"skip-treatment": "skippedTreatmentChoices",
};

function withRoundIncomeFields(round: GameRoundData): GameRoundData {
const baseRoundIncome = round.baseRoundIncome ?? ROUND_INCOME_POINTS;
const roundIncome = round.roundIncome ?? roundMetric(round.scoreAfter - round.scoreBefore + round.paidCost);

return {
...round,
roundIncome,
baseRoundIncome,
healthIncomeMultiplier: round.healthIncomeMultiplier ?? roundMetric(roundIncome / Math.max(baseRoundIncome, 1)),
};
}

export function isPreRevealSurveyComplete(survey: PreRevealSurveyAnswers | undefined): survey is PreRevealSurveyAnswers {
const openLength = survey?.openExplanation.trim().length ?? 0;

Expand Down Expand Up @@ -341,8 +354,15 @@ export function buildResearchExport(session: ResearchSession, createdAt = new Da
treatmentCostMultiplier: session.game.treatmentCostMultiplier,
},
gameSummary,
gameRounds: session.game.rounds,
...(session.replayGame ? { replayGame: session.replayGame } : {}),
gameRounds: session.game.rounds.map(withRoundIncomeFields),
...(session.replayGame
? {
replayGame: {
...session.replayGame,
rounds: session.replayGame.rounds.map(withRoundIncomeFields),
},
}
: {}),
preRevealSurvey: session.preRevealSurvey,
...(session.preRevealSurveyOriginal ? { preRevealSurveyOriginal: session.preRevealSurveyOriginal } : {}),
...(session.preRevealSurveyRevisedAfterReveal ? { preRevealSurveyRevisedAfterReveal: session.preRevealSurveyRevisedAfterReveal } : {}),
Expand Down