diff --git a/README.md b/README.md index 498132c..c27c1da 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,11 @@ [![Donate via LiberaPay](https://img.shields.io/liberapay/receives/rocketnine.space.svg?logo=liberapay)](https://liberapay.com/rocketnine.space) [![Donate via Patreon](https://img.shields.io/badge/dynamic/json?color=%23e85b46&label=Patreon&query=data.attributes.patron_count&suffix=%20patrons&url=https%3A%2F%2Fwww.patreon.com%2Fapi%2Fcampaigns%2F5252223)](https://www.patreon.com/rocketnine) -This game was created for the [Fuck Capitalism Jam 2023](https://itch.io/jam/fuck-capitalism-jam-2023). +This game was created for the [Fuck Capitalism Jam 2023](https://itch.io/jam/fuck-capitalism-jam-2023) +game jam. + +It is a parody of the 1973 business simulation game [Lemonade Stand](https://en.wikipedia.org/wiki/Lemonade_Stand) +by Bob Jamison. **Note:** This game has not yet been released. The following links are placeholders. diff --git a/flags_web.go b/flags_web.go index f4eeef7..f2240ea 100644 --- a/flags_web.go +++ b/flags_web.go @@ -5,6 +5,7 @@ package main import ( "code.rocketnine.space/tslocum/pretzel-tycoon/world" + "github.com/hajimehoshi/ebiten/v2" ) func parseFlags() { diff --git a/game/game.go b/game/game.go index d22f1c6..6e1a4ae 100644 --- a/game/game.go +++ b/game/game.go @@ -7,6 +7,8 @@ import ( "image/color" "log" "os" + "regexp" + "strconv" "code.rocketnine.space/tslocum/etk" "code.rocketnine.space/tslocum/messeji" @@ -24,15 +26,30 @@ type viewType int const ( viewTitle = iota viewIntro1 + viewStartDayProduction1 + viewStartDayProduction2 + viewStartDayProduction3 + viewStartDaySupplies viewFinancialReport ) +var matchNumbers = regexp.MustCompile("^[0-9]+$") + type Game struct { inputBuffer *etk.Input textBuffer *dummyTextBuffer currentView viewType viewTicks int + + day int + + inputLetters bool // Whether to allow the user to input letters. + + makePretzels int // In dozens. + makeSigns int + + pretzelPrice int // In cents. } var addedGame bool @@ -74,13 +91,11 @@ func NewGame() (*Game, error) { etk.Style.TextFont = loadFont() g := &Game{ - inputBuffer: etk.NewInput("", "", func(text string) (handled bool) { - log.Println("selected", text) - return true - }), - textBuffer: &dummyTextBuffer{ - Text: etk.NewText("Hello world!"), - }, + day: 1, + } + g.inputBuffer = etk.NewInput("", "", g.acceptInput) + g.textBuffer = &dummyTextBuffer{ + Text: etk.NewText("Hello world!"), } // Configure text buffer. @@ -109,10 +124,43 @@ func (g *Game) Layout(_, _ int) (screenWidth, screenHeight int) { return world.ScreenWidth, world.ScreenHeight } +func (g *Game) inputActive() bool { + return g.currentView == viewStartDayProduction1 || g.currentView == viewStartDayProduction2 || g.currentView == viewStartDayProduction3 +} + +func (g *Game) acceptInput(text string) (handled bool) { + log.Println("selected", text) + + i, err := strconv.Atoi(text) + if err != nil { + log.Println(err) // TODO this shouldnt happen + return false + } + + switch g.currentView { + case viewStartDayProduction1: + g.makePretzels = i + case viewStartDayProduction2: + g.makeSigns = i + case viewStartDayProduction3: + g.pretzelPrice = i + } + + g.currentView++ + partialTransition := g.currentView == viewStartDayProduction2 || g.currentView == viewStartDayProduction3 + if partialTransition { + viewBytes := viewText[g.currentView-1] + lines := bytes.Split(viewBytes, []byte("\n")) + g.viewTicks = len(lines) - 2 + } else { + g.viewTicks = 0 + } + return true +} + func (g *Game) refreshBuffer() error { // TODO only do this when the view buffer or input buffer changes - - currentDay := 1 + // TODO fix trailing newline causing scroll bar to appear pretzelsSold := 50 pretzelPrice := "$.10" @@ -133,13 +181,35 @@ func (g *Game) refreshBuffer() error { viewBytes = append(viewBytes, bytes.TrimRight(centeredText("PRESS SPACE TO START"), "\n")...) } + // Append user input. + if g.inputActive() { + viewBytes = append(viewBytes, g.inputBuffer.Text()...) + + // Append cursor icon. + if g.viewTicks%150 < 100 { + viewBytes = append(viewBytes, '|') + } + } + // Format view. var lines [][]byte switch g.currentView { - case viewTitle, viewIntro1: + case viewStartDayProduction1: + viewBytes = []byte(fmt.Sprintf(string(viewBytes), g.day)) + lines = bytes.Split(viewBytes, []byte("\n")) + case viewStartDayProduction2: + viewBytes = []byte(fmt.Sprintf(string(viewBytes), g.day, g.makePretzels)) + lines = bytes.Split(viewBytes, []byte("\n")) + case viewStartDayProduction3: + viewBytes = []byte(fmt.Sprintf(string(viewBytes), g.day, g.makePretzels, g.makeSigns)) + lines = bytes.Split(viewBytes, []byte("\n")) + case viewStartDaySupplies: + viewBytes = []byte(fmt.Sprintf(string(viewBytes), g.day)) lines = bytes.Split(viewBytes, []byte("\n")) case viewFinancialReport: - viewBytes = []byte(fmt.Sprintf(string(viewBytes), currentDay, pretzelsSold, pretzelPrice, totalIncome, pretzelsMade, signsMade, totalExpenses, profit, assets)) + viewBytes = []byte(fmt.Sprintf(string(viewBytes), g.day, pretzelsSold, pretzelPrice, totalIncome, pretzelsMade, signsMade, totalExpenses, profit, assets)) + lines = bytes.Split(viewBytes, []byte("\n")) + default: lines = bytes.Split(viewBytes, []byte("\n")) } @@ -188,12 +258,24 @@ func (g *Game) Update() error { } // Handle user input. - err := etk.Update() - if err != nil { - log.Fatal(err) - } + if g.inputActive() { + err := etk.Update() + if err != nil { + log.Fatal(err) + } - if inpututil.IsKeyJustPressed(ebiten.KeySpace) { + inputText := g.inputBuffer.Text() + if len(inputText) > 0 && !g.inputLetters && !matchNumbers.MatchString(inputText) { + var newInput string + for _, r := range inputText { + if matchNumbers.MatchString(string(r)) { + newInput += string(r) + } + } + g.inputBuffer.Clear() + g.inputBuffer.Write([]byte(newInput)) + } + } else if inpututil.IsKeyJustPressed(ebiten.KeySpace) { g.currentView++ if g.currentView > viewFinancialReport { g.currentView = viewTitle @@ -201,21 +283,16 @@ func (g *Game) Update() error { g.viewTicks = 0 } - err = g.refreshBuffer() + err := g.refreshBuffer() if err != nil { return err } g.viewTicks++ - // TODO fix trailing newline causing scroll bar to appear - - //g.textBuffer.Clear() - //g.textBuffer.Write([]byte(viewIntro1)) return nil } func (g *Game) Draw(screen *ebiten.Image) { - // Draw the text buffer over the hidden input buffer. g.textBuffer.Draw(screen) if world.Debug != 0 { diff --git a/game/view.go b/game/view.go index d70bb26..bdfede5 100644 --- a/game/view.go +++ b/game/view.go @@ -46,6 +46,50 @@ YOU WILL BEGIN WITH $4.20 CASH (ASSETS). ` + string(bytes.TrimRight(centeredText("PRESS SPACE TO CONTINUE..."), "\n"))), + // viewStartDayProduction1 + []byte(` DAY %d + +STARTING SUPPLIES + +PRODUCTION AMOUNTS + +HOW MANY BATCHES (DOZENS) OF PRETZELS +DO YOU WISH TO MAKE ?`), + + // viewStartDayProduction2 + []byte(` DAY %d + +STARTING SUPPLIES + +PRODUCTION AMOUNTS + +HOW MANY BATCHES (DOZENS) OF PRETZELS +DO YOU WISH TO MAKE ?%d + +HOW MANY ADVERTISING SIGNS ($1.25 EACH) +DO YOU WISH TO MAKE ?`), + + // viewStartDayProduction3 + []byte(` DAY %d + +STARTING SUPPLIES + +PRODUCTION AMOUNTS + +HOW MANY BATCHES (DOZENS) OF PRETZELS +DO YOU WISH TO MAKE ?%d + +HOW MANY ADVERTISING SIGNS ($1.25 EACH) +DO YOU WISH TO MAKE ?%d + +WHAT PRICE (IN CENTS) DO YOU WISH TO +CHARGE FOR PRETZELS ?`), + + // viewStartDaySupplies + []byte(` DAY %d + +TODO`), + // viewFinancialReport []byte(` $$ PRETZELSVILLE FINANCIAL REPORT $$ diff --git a/go.mod b/go.mod index 2d4564a..9b8ae04 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( code.rocketnine.space/tslocum/etk v0.0.0-20230608043113-585e23b06fff code.rocketnine.space/tslocum/messeji v1.0.3 github.com/hajimehoshi/ebiten/v2 v2.5.4 - golang.org/x/image v0.7.0 + golang.org/x/image v0.8.0 ) require ( diff --git a/go.sum b/go.sum index f69e591..63b8605 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1 h1:NxHSRPlbeyFGDc6rU7YsvxV/4bXS9XhuvUt5pP63XUs= golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0= -golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= -golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= +golang.org/x/image v0.8.0 h1:agUcRXV/+w6L9ryntYYsF2x9fQTMd4T8fiiYXAVW6Jg= +golang.org/x/image v0.8.0/go.mod h1:PwLxp3opCYg4WR2WO9P0L6ESnsD6bLTWcw8zanLMVFM= golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34= golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -46,7 +46,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=