Explain every condition, and write the whole script in our own voice
The instructions only ever covered the weather. They are now four pages: what you decide, how signs and spoilage work, what the sky does, and what the street does - the fair and the rival included, with each condition named and what it does to your day spelled out. Every passage that was reproduced from the original has been rewritten: the welcome, the ledger heading, the thunderstorm, the road works, the heat wave, the bankruptcy line and the cost announcements. A project released under copyleft has no business licensing words it did not write, and now it does not have to. NOTICE.md records what changed and why, and narrows the borrowed material to the town's name and the ledger's labels - neither of which is a copyright question. Shortening the ledger heading also fixes the pill that was wrapping to two lines in the remaster. Checked in both skins: all four pages fit the tube at full size, with room to spare.
This commit is contained in:
@@ -35,31 +35,30 @@ below meaningful:
|
|||||||
every note is generated by the synth in `src/audio/`. There are no imported
|
every note is generated by the synth in `src/audio/`. There are no imported
|
||||||
assets of any kind.
|
assets of any kind.
|
||||||
|
|
||||||
## The one place we are standing on someone else's work
|
## What is and is not ours
|
||||||
|
|
||||||
Some **on-screen wording** is reproduced from the original from memory, because
|
**All of it is ours, with two narrow exceptions noted below.**
|
||||||
it is the part people remember word for word:
|
|
||||||
|
|
||||||
| Where | Text |
|
Earlier drafts of this project reproduced some of the original's on-screen
|
||||||
| --- | --- |
|
wording from memory — the welcome, the report heading, the thunderstorm and
|
||||||
| `IntroScreen.tsx` | "HI! WELCOME TO LEMONSVILLE, CALIFORNIA!" and the paragraph after it |
|
road-works messages. That text was someone else's writing, and a project
|
||||||
| `ReportScreen.tsx` | "$$ LEMONSVILLE DAILY FINANCIAL REPORT $$" |
|
released under a copyleft licence has no business licensing words it did not
|
||||||
| `TradingScreen.tsx` | the thunderstorm message |
|
write. Every one of those passages has since been rewritten in our own voice.
|
||||||
| `BriefingScreen.tsx` | the street-crew and heat-wave messages |
|
Nothing quoted remains.
|
||||||
|
|
||||||
Short functional labels (`GLASSES SOLD`, `WEATHER REPORT: SUNNY`) are hard to
|
Two things are still not original, and neither is a copyright question:
|
||||||
express any other way and are not really anyone's creative property. The longer
|
|
||||||
passages are a different matter: they are someone's writing, quoted here as
|
|
||||||
homage rather than authored by us. We cannot license what we did not write, so
|
|
||||||
that wording is **not** covered by this project's licence and is used on a
|
|
||||||
fair-use/de-minimis footing.
|
|
||||||
|
|
||||||
If that footing is not comfortable for a given use, the fix is small and
|
- **The setting.** The town is still Lemonsville, California. Names and short
|
||||||
self-contained: rewrite those few strings in your own voice. Nothing else in
|
titles are not subject to copyright, and it is kept deliberately, as the one
|
||||||
the project depends on them.
|
visible nod to where the game came from.
|
||||||
|
- **The ledger's labels.** `GLASSES SOLD`, `COST OF SIGNS`, `PROFIT` and the
|
||||||
|
rest are the only sensible words for what they label, and the order they
|
||||||
|
appear in follows from the arithmetic. There is no creative expression in
|
||||||
|
them to own.
|
||||||
|
|
||||||
The name *Lemonade Stand* is descriptive and is used descriptively. It is not
|
Everything else — the simulation, the artwork, the music, the interface and
|
||||||
claimed as a mark of this project.
|
every word on screen — was written for this project and is covered by the
|
||||||
|
licence below.
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ Affero rather than plain GPL because the leaderboard is a network service:
|
|||||||
anyone running a modified copy of it for other people has to offer them the
|
anyone running a modified copy of it for other people has to offer them the
|
||||||
source. Running the game on its own imposes nothing extra.
|
source. Running the game on its own imposes nothing extra.
|
||||||
|
|
||||||
The simulation, the artwork and the music are original work. The game's *rules*
|
The simulation, the artwork, the music and every word on screen are original
|
||||||
are not anyone's property, and some of the on-screen wording is quoted from the
|
work — the game's *rules* are nobody's property, and nothing here is quoted
|
||||||
1979 original as homage rather than authored here. [NOTICE.md](NOTICE.md) sets
|
from the original. [NOTICE.md](NOTICE.md) sets out exactly what came from
|
||||||
out exactly what came from where, and credits the people who wrote it first.
|
where, and credits the people who wrote it first.
|
||||||
|
|||||||
+14
@@ -267,6 +267,20 @@ html[data-skin='modern'] .vignette { opacity: 0.35; }
|
|||||||
|
|
||||||
.center { text-align: center; }
|
.center { text-align: center; }
|
||||||
|
|
||||||
|
/* Instructions: a named condition, then what it does to your day. */
|
||||||
|
.intro-entry {
|
||||||
|
margin: 0 0 0.6em;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-term {
|
||||||
|
color: var(--accent);
|
||||||
|
font-weight: 700;
|
||||||
|
margin-right: 0.8ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-skin='modern'] .intro-term { font-weight: 900; }
|
||||||
|
|
||||||
/* Reserved space for a message that comes and goes without a jolt. */
|
/* Reserved space for a message that comes and goes without a jolt. */
|
||||||
.hint {
|
.hint {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -27,16 +27,15 @@ export function BriefingScreen({
|
|||||||
{conditions.heatWave && (
|
{conditions.heatWave && (
|
||||||
<>
|
<>
|
||||||
<Line />
|
<Line />
|
||||||
<Line className="warn">A HEAT WAVE IS PREDICTED FOR TODAY!</Line>
|
<Line className="warn">A HEAT WAVE HAS SETTLED OVER THE</Line>
|
||||||
<Line className="warn">EVERYONE IN TOWN IS THIRSTY.</Line>
|
<Line className="warn">TOWN. EVERY THROAT IN IT IS DRY.</Line>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{conditions.streetCrew && (
|
{conditions.streetCrew && (
|
||||||
<>
|
<>
|
||||||
<Line />
|
<Line />
|
||||||
<Line className="warn">THE STREET CREWS ARE WORKING TODAY.</Line>
|
<Line className="warn">THE ROAD IS DUG UP OUTSIDE. NOTHING</Line>
|
||||||
<Line className="warn">THERE WILL BE NO TRAFFIC ON YOUR</Line>
|
<Line className="warn">IS COMING DOWN YOUR STREET TODAY.</Line>
|
||||||
<Line className="warn">STREET.</Line>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{conditions.festival && (
|
{conditions.festival && (
|
||||||
|
|||||||
@@ -1,53 +1,93 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Btn, Line } from './Crt'
|
import { Btn, Line } from './Crt'
|
||||||
|
|
||||||
const PAGES: string[][] = [
|
/** A paragraph, optionally led by the name of the thing it describes. */
|
||||||
[
|
interface Entry {
|
||||||
'HI! WELCOME TO LEMONSVILLE, CALIFORNIA!',
|
term?: string
|
||||||
'',
|
text: string
|
||||||
'IN THIS SMALL TOWN YOU ARE IN CHARGE OF',
|
}
|
||||||
'RUNNING YOUR OWN LEMONADE STAND. YOU CAN',
|
|
||||||
'COMPETE WITH AS MANY OTHER PEOPLE AS YOU',
|
interface Page {
|
||||||
'WISH, BUT HOW MUCH PROFIT YOU MAKE IS UP',
|
title: string
|
||||||
'TO YOU. IF YOU MAKE THE MOST MONEY,',
|
entries: Entry[]
|
||||||
"YOU'RE THE WINNER!",
|
}
|
||||||
'',
|
|
||||||
'TO MAKE LEMONADE YOU WILL NEED LEMONS,',
|
const PAGES: Page[] = [
|
||||||
'SUGAR, ICE AND PAPER CUPS. THE COST OF A',
|
{
|
||||||
'GLASS STARTS AT 2 CENTS AND CLIMBS AS',
|
title: 'WELCOME TO LEMONSVILLE',
|
||||||
'THE SUMMER WEARS ON.',
|
entries: [
|
||||||
],
|
{
|
||||||
[
|
text: 'YOU HAVE A CARD TABLE, A PITCHER AND A CORNER OF THE STREET. WHAT YOU MAKE OF THEM IS ENTIRELY YOUR OWN AFFAIR.',
|
||||||
'EACH DAY YOU DECIDE THREE THINGS:',
|
},
|
||||||
'',
|
{
|
||||||
' 1. HOW MANY GLASSES TO MAKE',
|
text: 'LEMONS, SUGAR, ICE AND CUPS ALL COST MONEY. A GLASS STARTS AT 2 CENTS TO MAKE AND GETS DEARER AS THE SUMMER WEARS ON.',
|
||||||
' 2. HOW MANY SIGNS TO PUT UP',
|
},
|
||||||
' (15 CENTS EACH)',
|
{ text: 'YOU OPEN WITH $2.00 IN THE TIN. WHOEVER ENDS THE SUMMER RICHEST WINS.' },
|
||||||
' 3. WHAT TO CHARGE PER GLASS',
|
],
|
||||||
'',
|
},
|
||||||
'SIGNS BRING CUSTOMERS, BUT THE FOURTH',
|
{
|
||||||
'SIGN HELPS A LOT LESS THAN THE FIRST.',
|
title: 'WHAT YOU DECIDE',
|
||||||
'',
|
entries: [
|
||||||
'WATCH THE WEATHER. A HOT DAY IS WORTH',
|
{ text: 'EACH MORNING YOU SET THREE THINGS:' },
|
||||||
'MORE GLASSES AND A HIGHER PRICE. A',
|
{ term: 'GLASSES', text: 'HOW MANY TO MAKE TODAY.' },
|
||||||
'CLOUDY DAY MIGHT TURN INTO A STORM AND',
|
{ term: 'SIGNS', text: 'HOW MANY TO PUT UP, AT 15 CENTS EACH. THE FOURTH SIGN HELPS A LOT LESS THAN THE FIRST.' },
|
||||||
'RUIN EVERY GLASS YOU MADE.',
|
{ term: 'PRICE', text: 'WHAT TO CHARGE A GLASS. ASK TOO MUCH AND NOBODY STOPS.' },
|
||||||
'',
|
{
|
||||||
'YOU START WITH $2.00. GOOD LUCK!',
|
text: 'EVERY GLASS IS MADE FRESH. WHAT YOU DO NOT SELL IS POURED AWAY, SO MAKE WHAT THE DAY WILL ACTUALLY TAKE.',
|
||||||
],
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'READ THE SKY',
|
||||||
|
entries: [
|
||||||
|
{ term: 'SUNNY', text: 'STEADY TRADE AND NO SURPRISES.' },
|
||||||
|
{ term: 'HOT AND DRY', text: 'A BIGGER CROWD, AND THEY WILL PAY MORE FOR A COLD GLASS. A HEAT WAVE IS BETTER STILL.' },
|
||||||
|
{
|
||||||
|
term: 'CLOUDY',
|
||||||
|
text: 'FEWER BUYERS ABOUT, AND THE DAY MAY TURN INTO A THUNDERSTORM THAT RUINS EVERY GLASS YOU MADE.',
|
||||||
|
},
|
||||||
|
{ text: 'THE FORECAST COMES BEFORE YOU BUY. THE STORM DOES NOT.' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'READ THE STREET TOO',
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
term: 'STREET CREWS',
|
||||||
|
text: 'THE ROAD IS DUG UP AND THE TRAFFIC GOES WITH IT. THEY OFTEN STAY A SECOND DAY.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
term: 'SUMMER FAIR',
|
||||||
|
text: 'HALF THE TOWN COMES PAST YOUR STAND, AND THEY ARE OUT TO SPEND.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
term: 'RIVAL STAND',
|
||||||
|
text: 'SOMEBODY SETS UP ON THE NEXT CORNER AND TAKES A SHARE OF THE STREET UNTIL THEY MOVE ON.',
|
||||||
|
},
|
||||||
|
{ text: 'ALL OF IT IS ANNOUNCED BEFORE YOU COMMIT. GOOD LUCK!' },
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export function IntroScreen({ onDone }: { onDone: () => void }) {
|
export function IntroScreen({ onDone }: { onDone: () => void }) {
|
||||||
const [page, setPage] = useState(0)
|
const [page, setPage] = useState(0)
|
||||||
const last = page === PAGES.length - 1
|
const last = page === PAGES.length - 1
|
||||||
|
const { title, entries } = PAGES[page]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="stack">
|
<div className="stack">
|
||||||
<Line className="center inv-line">HOW TO RUN A LEMONADE STAND</Line>
|
<Line className="center inv-line">HOW TO RUN A LEMONADE STAND</Line>
|
||||||
<Line />
|
<Line />
|
||||||
{PAGES[page].map((t, i) => (
|
<Line className="center accent">{title}</Line>
|
||||||
<Line key={i}>{t}</Line>
|
<Line />
|
||||||
|
|
||||||
|
{entries.map((e, i) => (
|
||||||
|
<p className="intro-entry" key={i}>
|
||||||
|
{e.term && <span className="intro-term">{e.term}</span>}
|
||||||
|
{e.text}
|
||||||
|
</p>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Line />
|
<Line />
|
||||||
<div className="row center">
|
<div className="row center">
|
||||||
{page > 0 && <Btn onClick={() => setPage(page - 1)}>BACK</Btn>}
|
{page > 0 && <Btn onClick={() => setPage(page - 1)}>BACK</Btn>}
|
||||||
@@ -55,7 +95,7 @@ export function IntroScreen({ onDone }: { onDone: () => void }) {
|
|||||||
{last ? 'START' : 'MORE'}
|
{last ? 'START' : 'MORE'}
|
||||||
</Btn>
|
</Btn>
|
||||||
<Line className="dim">
|
<Line className="dim">
|
||||||
PAGE {page + 1} OF {PAGES.length}
|
{page + 1} OF {PAGES.length}
|
||||||
</Line>
|
</Line>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function ReportScreen({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="stack">
|
<div className="stack">
|
||||||
<Line className="center inv-line">$$ LEMONSVILLE DAILY FINANCIAL REPORT $$</Line>
|
<Line className="center inv-line">$$ THE DAY'S TAKINGS $$</Line>
|
||||||
|
|
||||||
<Scene
|
<Scene
|
||||||
conditions={conditions}
|
conditions={conditions}
|
||||||
@@ -80,8 +80,8 @@ export function ReportScreen({
|
|||||||
{player.bankrupt && (
|
{player.bankrupt && (
|
||||||
<>
|
<>
|
||||||
<Line />
|
<Line />
|
||||||
<Line className="warn">{player.name}, YOU DO NOT HAVE ENOUGH</Line>
|
<Line className="warn">{player.name}, THERE IS NOTHING LEFT IN</Line>
|
||||||
<Line className="warn">MONEY LEFT TO STAY IN BUSINESS.</Line>
|
<Line className="warn">THE TIN. YOUR STAND IS FINISHED.</Line>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ export function TradingScreen({
|
|||||||
<div className="stack">
|
<div className="stack">
|
||||||
<Line className="center inv-line">DAY {conditions.day} IN LEMONSVILLE</Line>
|
<Line className="center inv-line">DAY {conditions.day} IN LEMONSVILLE</Line>
|
||||||
<Scene conditions={conditions} traffic={0.2} />
|
<Scene conditions={conditions} traffic={0.2} />
|
||||||
<Line className="warn">A THUNDERSTORM HIT LEMONSVILLE EARLIER</Line>
|
<Line className="warn">THE SKY OPENED OVER THE TOWN THIS</Line>
|
||||||
<Line className="warn">TODAY, JUST AS THE STANDS WERE BEING</Line>
|
<Line className="warn">MORNING, RIGHT AS THE STANDS WENT UP.</Line>
|
||||||
<Line className="warn">SET UP. EVERYTHING WAS RUINED!!</Line>
|
<Line className="warn">NOT ONE GLASS SURVIVED IT.</Line>
|
||||||
<Line />
|
<Line />
|
||||||
<div className="row center">
|
<div className="row center">
|
||||||
<Btn kind="primary" onClick={onDone}>
|
<Btn kind="primary" onClick={onDone}>
|
||||||
|
|||||||
+3
-12
@@ -18,20 +18,11 @@ export function costPerGlass(day: number): number {
|
|||||||
|
|
||||||
export function costMessage(day: number): string[] | null {
|
export function costMessage(day: number): string[] | null {
|
||||||
if (day === 1)
|
if (day === 1)
|
||||||
return [
|
return ['LEMONS ARE CHEAP THIS WEEK. A GLASS', 'COSTS YOU 2 CENTS TO MAKE.']
|
||||||
'ON DAY 1 THE COST OF LEMONADE IS',
|
|
||||||
'2 CENTS PER GLASS.',
|
|
||||||
]
|
|
||||||
if (day === 3)
|
if (day === 3)
|
||||||
return [
|
return ['LEMONS HAVE GONE UP. A GLASS NOW', 'COSTS YOU 4 CENTS TO MAKE.']
|
||||||
'YOUR COST OF LEMONADE HAS GONE UP',
|
|
||||||
'TO 4 CENTS PER GLASS.',
|
|
||||||
]
|
|
||||||
if (day === 8)
|
if (day === 8)
|
||||||
return [
|
return ['LEMONS ARE DEARER AGAIN. A GLASS NOW', 'COSTS YOU 5 CENTS TO MAKE.']
|
||||||
'YOUR COST OF LEMONADE HAS GONE UP',
|
|
||||||
'TO 5 CENTS PER GLASS.',
|
|
||||||
]
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user