Skip to content

Commit 91665de

Browse files
committed
feat: agi unlocked + buy 1%
1 parent c8f00b7 commit 91665de

10 files changed

Lines changed: 265 additions & 71 deletions

File tree

src/App.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ function App() {
2626
agencyUpgraded,
2727
pyramidUnlocked,
2828
pyramidPurchased,
29+
flipUnlocked,
30+
flipPurchased,
2931
linkedInBros,
32+
agiAchieved,
33+
agiElapsedMs,
3034
buyAgency,
3135
buyAgencyUpgrade,
3236
buyPyramidScheme,
37+
buyFlip,
3338
createWebsite,
3439
sellWebsite,
3540
hireDev,
@@ -58,6 +63,8 @@ function App() {
5863
sellWebsite={sellWebsite}
5964
createWebsite={createWebsite}
6065
isDisabled={websites < 1}
66+
agiAchieved={agiAchieved}
67+
flipPurchased={flipPurchased}
6168
/>
6269
</section>
6370
<section className="main flex flex-col gap-5">
@@ -81,6 +88,11 @@ function App() {
8188
pyramidUnlocked={pyramidUnlocked}
8289
pyramidPurchased={pyramidPurchased}
8390
buyPyramidScheme={buyPyramidScheme}
91+
flipUnlocked={flipUnlocked}
92+
flipPurchased={flipPurchased}
93+
buyFlip={buyFlip}
94+
agiAchieved={agiAchieved}
95+
agiElapsedMs={agiElapsedMs}
8496
/>
8597
</section>
8698
<Footer

src/components/AchievementsPanel.tsx

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,38 @@ import type { Achievement } from '../types';
33

44
interface AchievementsPanelProps {
55
unlockedAchievements: Set<string>;
6+
agiAchieved: boolean;
67
}
78

89
/*
910
ToDo: Add visible / hidden achievements -> guide / challenges
1011
*/
1112

12-
export default function AchievementsPanel({ unlockedAchievements }: AchievementsPanelProps) {
13+
export default function AchievementsPanel({
14+
unlockedAchievements,
15+
agiAchieved
16+
}: AchievementsPanelProps) {
1317
const progress = Math.round((unlockedAchievements.size / achievements.length) * 100);
1418
const achievementsList = achievements
15-
.filter((achievement) => unlockedAchievements.has(achievement.id))
16-
.map((achievement: Achievement) => (
17-
<li
18-
key={achievement.id}
19-
className="flex items-start gap-3 p-3 rounded-xl border border-line bg-card">
20-
<span className="text-xl leading-none mt-0.5">{achievement.icon}</span>
21-
<div className="flex-1 min-w-0">
22-
<p className="text-sm font-semibold text-ink">{achievement.title}</p>
23-
<p className="text-xs text-ink-muted mt-0.5">{achievement.description}</p>
24-
</div>
25-
<span className="text-win text-xs font-semibold shrink-0 mt-0.5"></span>
26-
</li>
27-
));
19+
// Locked achievements only become visible (greyed out) once AGI is achieved
20+
.filter((achievement) => agiAchieved || unlockedAchievements.has(achievement.id))
21+
.map((achievement: Achievement) => {
22+
const unlocked = unlockedAchievements.has(achievement.id);
23+
return (
24+
<li
25+
key={achievement.id}
26+
className={`flex items-start gap-3 p-3 rounded-xl border border-line bg-card ${
27+
unlocked ? '' : 'opacity-40 grayscale'
28+
}`}>
29+
<span className="text-xl leading-none mt-0.5">{achievement.icon}</span>
30+
<div className="flex-1 min-w-0">
31+
<p className="text-sm font-semibold text-ink">{achievement.title}</p>
32+
<p className="text-xs text-ink-muted mt-0.5">{achievement.description}</p>
33+
</div>
34+
{unlocked && <span className="text-win text-xs font-semibold shrink-0 mt-0.5"></span>}
35+
</li>
36+
);
37+
});
2838

2939
return (
3040
<div>

src/components/Actions.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@ interface ActionsProps {
44
sellWebsite: () => void;
55
createWebsite: () => void;
66
isDisabled: boolean;
7+
agiAchieved: boolean;
8+
flipPurchased: boolean;
79
}
810

9-
export default function Actions({ sellWebsite, createWebsite, isDisabled }: ActionsProps) {
11+
export default function Actions({
12+
sellWebsite,
13+
createWebsite,
14+
isDisabled,
15+
agiAchieved,
16+
flipPurchased
17+
}: ActionsProps) {
1018
const [animationBuy, setAnimationBuy] = useState(false);
1119
const [animationSell, setAnimationSell] = useState(false);
1220

@@ -20,6 +28,8 @@ export default function Actions({ sellWebsite, createWebsite, isDisabled }: Acti
2028
sellWebsite();
2129
};
2230

31+
if (agiAchieved) return null;
32+
2333
return (
2434
<div className="flex flex-col gap-2 mt-4">
2535
<button
@@ -33,7 +43,7 @@ export default function Actions({ sellWebsite, createWebsite, isDisabled }: Acti
3343
onClick={handleSell}
3444
disabled={isDisabled}
3545
onAnimationEnd={() => setAnimationSell(false)}>
36-
Sell Website
46+
{flipPurchased ? 'Sell Website (+1%)' : 'Sell Website'}
3747
</button>
3848
</div>
3949
);

src/components/BuyPanel.tsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { byCategory, buildingCost } from '../data/catalog';
22
import type { HireFunction } from '../types';
3+
import { formatDuration } from '../utils/format';
34
import SingleCandidate from './SingleCandidate';
45

56
const buildings = byCategory('building');
@@ -9,13 +10,33 @@ interface BuyProps {
910
maxMoney: number;
1011
staff: Record<string, number>;
1112
buyBuilding: HireFunction;
13+
agiAchieved: boolean;
14+
agiElapsedMs: number;
1215
}
1316

14-
const DISPLAY_COST_DIFFERENCE = 5000;
15-
16-
export default function BuyPanel({ money, maxMoney, staff, buyBuilding }: BuyProps) {
17+
export default function BuyPanel({
18+
money,
19+
maxMoney,
20+
staff,
21+
buyBuilding,
22+
agiAchieved,
23+
agiElapsedMs
24+
}: BuyProps) {
25+
if (agiAchieved) {
26+
return (
27+
<div className="rounded border border-ink-faint/30 p-6 text-center">
28+
<h4 className="text-ink font-semibold uppercase tracking-widest mb-2">
29+
AGI Achieved — no more working
30+
</h4>
31+
<p className="text-sm text-ink-muted">
32+
Time to AGI:{' '}
33+
<span className="text-ink font-semibold">{formatDuration(agiElapsedMs)}</span>
34+
</p>
35+
</div>
36+
);
37+
}
1738
const listBuildings = buildings
18-
.filter((building, index) => index === 0 || building.cost - DISPLAY_COST_DIFFERENCE <= maxMoney)
39+
.filter((building, index) => index === 0 || building.cost / 2 <= maxMoney)
1940
.map((building, index) => {
2041
const owned = staff[building.id] ?? 0;
2142
const isOwned = !building.repeatable && owned >= 1;

src/components/HirePanel.tsx

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import SingleCandidate from './SingleCandidate';
22
import type { HireFunction } from '../types';
33
import { byCategory } from '../data/catalog';
4-
import { AGENCY_COST, AGENCY_UPGRADE_COST, PYRAMID_COST } from '../hooks/useGameLogic';
5-
import { formatMoney } from '../utils/format';
4+
import { AGENCY_COST, AGENCY_UPGRADE_COST, PYRAMID_COST, FLIP_COST } from '../hooks/useGameLogic';
5+
import { formatMoney, formatDuration } from '../utils/format';
66

77
const devs = byCategory('dev');
88
// Hidden sellers (e.g. the agency-only LinkedIn Bro) never get a manual hire button
@@ -24,6 +24,11 @@ interface HireProps {
2424
pyramidUnlocked: boolean;
2525
pyramidPurchased: boolean;
2626
buyPyramidScheme: () => void;
27+
flipUnlocked: boolean;
28+
flipPurchased: boolean;
29+
buyFlip: () => void;
30+
agiAchieved: boolean;
31+
agiElapsedMs: number;
2732
}
2833

2934
const DISPLAY_COST_DIFFERENCE = 500;
@@ -43,11 +48,29 @@ export default function HirePanel({
4348
buyAgencyUpgrade,
4449
pyramidUnlocked,
4550
pyramidPurchased,
46-
buyPyramidScheme
51+
buyPyramidScheme,
52+
flipUnlocked,
53+
flipPurchased,
54+
buyFlip,
55+
agiAchieved,
56+
agiElapsedMs
4757
}: HireProps) {
58+
if (agiAchieved) {
59+
return (
60+
<div className="rounded border border-ink-faint/30 p-6 text-center">
61+
<h4 className="text-ink font-semibold uppercase tracking-widest mb-2">
62+
AGI Achieved: no more working
63+
</h4>
64+
<p className="text-sm text-ink-muted">
65+
Time to AGI:{' '}
66+
<span className="text-ink font-semibold">{formatDuration(agiElapsedMs)}</span>
67+
</p>
68+
</div>
69+
);
70+
}
4871
const teamFull = people >= maxPeople;
4972
const listDevs = devs
50-
.filter((dev) => dev.cost / 2 <= maxMoney) // TODO - esto igual renta irlo ajustando o tener alguna regla especial
73+
.filter((dev, index) => index === 0 || dev.cost / 2 <= maxMoney) // TODO - esto igual renta irlo ajustando o tener alguna regla especial
5174
.map((dev, index) => (
5275
<SingleCandidate
5376
key={index}
@@ -86,31 +109,31 @@ export default function HirePanel({
86109
{agencyPurchased ? (
87110
<>
88111
<p className="text-xs text-ink-muted">
89-
Activeauto-hires LinkedIn Bros ($10M each, sells +50M/s) every{' '}
112+
Active: auto-hires LinkedIn Bros ($10M each, sells +5M/s) every{' '}
90113
{agencyUpgraded ? '1s' : '3s'}.
91114
</p>
92115
<p className="text-xs text-ink-faint mt-1">LinkedIn Bros: {linkedInBros}</p>
93116
{agencyUpgraded ? (
94-
<p className="text-xs text-ink-faint mt-1">Upgraded hires every 1s.</p>
117+
<p className="text-xs text-ink-faint mt-1">Upgraded: hires every 1s.</p>
95118
) : (
96119
<button
97120
onClick={buyAgencyUpgrade}
98121
disabled={money < AGENCY_UPGRADE_COST}
99122
className="ghost disabled:opacity-40 disabled:cursor-not-allowed mt-2">
100-
Upgrade Agency {formatMoney(AGENCY_UPGRADE_COST)}
123+
Upgrade Agency: {formatMoney(AGENCY_UPGRADE_COST)}
101124
</button>
102125
)}
103126
</>
104127
) : (
105128
<>
106129
<p className="text-xs text-ink-muted mb-2">
107-
Buy once to auto-hire LinkedIn Bros (+50M/s).
130+
Buy once to auto-hire LinkedIn Bros (+5M/s).
108131
</p>
109132
<button
110133
onClick={buyAgency}
111134
disabled={money < AGENCY_COST}
112135
className="ghost disabled:opacity-40 disabled:cursor-not-allowed">
113-
Buy Agency ${AGENCY_COST.toLocaleString()}
136+
Buy Agency: ${AGENCY_COST.toLocaleString()}
114137
</button>
115138
</>
116139
)}
@@ -134,7 +157,31 @@ export default function HirePanel({
134157
onClick={buyPyramidScheme}
135158
disabled={money < PYRAMID_COST}
136159
className="ghost disabled:opacity-40 disabled:cursor-not-allowed">
137-
Buy Pyramid Scheme — ${PYRAMID_COST.toLocaleString()}
160+
Try Ponzi Scheme: {formatMoney(PYRAMID_COST)}
161+
</button>
162+
</>
163+
)}
164+
</div>
165+
)}
166+
{flipUnlocked && (
167+
<div className="mt-4 rounded border border-ink-faint/30 p-3">
168+
<h4 className="text-ink-muted text-xs font-semibold uppercase tracking-widest mb-1">
169+
IPO
170+
</h4>
171+
{flipPurchased ? (
172+
<p className="text-xs text-ink-muted">
173+
Active: each manual Sell now nets 1% of your money.
174+
</p>
175+
) : (
176+
<>
177+
<p className="text-xs text-ink-muted mb-2">
178+
Buy once: every manual Sell pays 1% of your money instead of quality.
179+
</p>
180+
<button
181+
onClick={buyFlip}
182+
disabled={money < FLIP_COST}
183+
className="ghost disabled:opacity-40 disabled:cursor-not-allowed">
184+
Buy IPO: {formatMoney(FLIP_COST)}
138185
</button>
139186
</>
140187
)}

src/components/Panel.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ interface PanelProps {
2828
pyramidUnlocked: boolean;
2929
pyramidPurchased: boolean;
3030
buyPyramidScheme: () => void;
31+
flipUnlocked: boolean;
32+
flipPurchased: boolean;
33+
buyFlip: () => void;
34+
agiAchieved: boolean;
35+
agiElapsedMs: number;
3136
}
3237

3338
export default function Panel({
@@ -48,7 +53,12 @@ export default function Panel({
4853
buyAgencyUpgrade,
4954
pyramidUnlocked,
5055
pyramidPurchased,
51-
buyPyramidScheme
56+
buyPyramidScheme,
57+
flipUnlocked,
58+
flipPurchased,
59+
buyFlip,
60+
agiAchieved,
61+
agiElapsedMs
5262
}: PanelProps) {
5363
return (
5464
<Tabs>
@@ -84,13 +94,28 @@ export default function Panel({
8494
pyramidUnlocked={pyramidUnlocked}
8595
pyramidPurchased={pyramidPurchased}
8696
buyPyramidScheme={buyPyramidScheme}
97+
flipUnlocked={flipUnlocked}
98+
flipPurchased={flipPurchased}
99+
buyFlip={buyFlip}
100+
agiAchieved={agiAchieved}
101+
agiElapsedMs={agiElapsedMs}
87102
/>
88103
</TabPanel>
89104
<TabPanel>
90-
<BuyPanel money={money} maxMoney={maxMoney} staff={staff} buyBuilding={buyBuilding} />
105+
<BuyPanel
106+
money={money}
107+
maxMoney={maxMoney}
108+
staff={staff}
109+
buyBuilding={buyBuilding}
110+
agiAchieved={agiAchieved}
111+
agiElapsedMs={agiElapsedMs}
112+
/>
91113
</TabPanel>
92114
<TabPanel>
93-
<AchievementsPanel unlockedAchievements={achievements.unlockedAchievements} />
115+
<AchievementsPanel
116+
unlockedAchievements={achievements.unlockedAchievements}
117+
agiAchieved={agiAchieved}
118+
/>
94119
</TabPanel>
95120
</Tabs>
96121
);

0 commit comments

Comments
 (0)