diff --git a/src/rendered-ascii.png b/rendered-ascii.png similarity index 100% rename from src/rendered-ascii.png rename to rendered-ascii.png diff --git a/rendered-ascii2.png b/rendered-ascii2.png new file mode 100644 index 0000000..60c478b Binary files /dev/null and b/rendered-ascii2.png differ diff --git a/src/.DS_Store b/src/.DS_Store index 6431dfb..a1c7aa2 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/compiled/drracket/errortrace/entities_rkt.dep b/src/compiled/drracket/errortrace/entities_rkt.dep index a38f4db..2ce8368 100644 --- a/src/compiled/drracket/errortrace/entities_rkt.dep +++ b/src/compiled/drracket/errortrace/entities_rkt.dep @@ -1 +1 @@ -("6.12" ("4485bd26ae4e19e344acdd982117a4c5aa2e6e42" . "3dfc9a4e963179a5727c8ec9b3110d0cf6a2e6e0") #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\point.rkt" (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) +("6.12" ("aac09700962317fc9e9bbaddd51bb6e9684e00e5" . "167230e4ec7634b952220c2adf6864a0ef9b6b21") #"/Users/larken/git/LispGameJam/src/point.rkt" (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) diff --git a/src/compiled/drracket/errortrace/entities_rkt.zo b/src/compiled/drracket/errortrace/entities_rkt.zo index 9eded4e..13fe5cc 100644 Binary files a/src/compiled/drracket/errortrace/entities_rkt.zo and b/src/compiled/drracket/errortrace/entities_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/game-screen_rkt.dep b/src/compiled/drracket/errortrace/game-screen_rkt.dep index 571dc1b..9b53474 100644 --- a/src/compiled/drracket/errortrace/game-screen_rkt.dep +++ b/src/compiled/drracket/errortrace/game-screen_rkt.dep @@ -1 +1 @@ -("6.12" ("0e0bd21f99411759055becd350113cbf114fab73" . "e446a7c9ae302df7ac737ca2f02f0d9916a8a07c") #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\inventory-screen.rkt" #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\point.rkt" #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\screen.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) +("6.12" ("7b13dcd8d8066fb320ca203f943d375142bffa46" . "0a676a7dac54c4d2f7042a7512b3b8fb303eac6a") #"/Users/larken/git/LispGameJam/src/inventory-screen.rkt" #"/Users/larken/git/LispGameJam/src/map-generation.rkt" #"/Users/larken/git/LispGameJam/src/point.rkt" #"/Users/larken/git/LispGameJam/src/screen.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) diff --git a/src/compiled/drracket/errortrace/game-screen_rkt.zo b/src/compiled/drracket/errortrace/game-screen_rkt.zo index db17bba..fda3b31 100644 Binary files a/src/compiled/drracket/errortrace/game-screen_rkt.zo and b/src/compiled/drracket/errortrace/game-screen_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/inventory-screen_rkt.dep b/src/compiled/drracket/errortrace/inventory-screen_rkt.dep index 241d5bc..31c9f6e 100644 --- a/src/compiled/drracket/errortrace/inventory-screen_rkt.dep +++ b/src/compiled/drracket/errortrace/inventory-screen_rkt.dep @@ -1 +1 @@ -("6.12" ("feba9cd7b68186a0c67f78dc4394699f6a6aca35" . "584c4da8d24ef21bf465d224a3fd1ca75f34a93b") #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\screen.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt")) +("6.12" ("459ac034457bb571fe2007122c9e4a6a0e19274b" . "e7bf0813a6bbace5755344a02b181f36a3bc7342") #"/Users/larken/git/LispGameJam/src/screen.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt")) diff --git a/src/compiled/drracket/errortrace/inventory-screen_rkt.zo b/src/compiled/drracket/errortrace/inventory-screen_rkt.zo index 290845f..dd02c2a 100644 Binary files a/src/compiled/drracket/errortrace/inventory-screen_rkt.zo and b/src/compiled/drracket/errortrace/inventory-screen_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/items_rkt.dep b/src/compiled/drracket/errortrace/items_rkt.dep new file mode 100644 index 0000000..c396e3a --- /dev/null +++ b/src/compiled/drracket/errortrace/items_rkt.dep @@ -0,0 +1 @@ +("6.12" ("9dba4bfc56437ae20e63187a75f5e15c5d50e1f3" . "22ba58f1a89219be91daa888857db033cd852aaa") #"/Users/larken/git/LispGameJam/src/point.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) diff --git a/src/compiled/drracket/errortrace/items_rkt.zo b/src/compiled/drracket/errortrace/items_rkt.zo new file mode 100644 index 0000000..2fd775c Binary files /dev/null and b/src/compiled/drracket/errortrace/items_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/map-generation_rkt.dep b/src/compiled/drracket/errortrace/map-generation_rkt.dep index 7429d9c..2f8273a 100644 --- a/src/compiled/drracket/errortrace/map-generation_rkt.dep +++ b/src/compiled/drracket/errortrace/map-generation_rkt.dep @@ -1 +1 @@ -("6.12" ("7b68ba0823d8004e8ef5937549897602aacbf100" . "0f0230417bbb838632ace3b636baa5b16a2a34cb") #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\point.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"noise" #"main.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) +("6.12" ("a894dfc083e01a9a9b28c4df606057f5d300ab95" . "817fa10a96d670827c38d2404b10778aa282bc29") #"/Users/larken/git/LispGameJam/src/entities.rkt" #"/Users/larken/git/LispGameJam/src/items.rkt" #"/Users/larken/git/LispGameJam/src/point.rkt" #"/Users/larken/git/LispGameJam/src/tiles.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"noise" #"main.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) diff --git a/src/compiled/drracket/errortrace/map-generation_rkt.zo b/src/compiled/drracket/errortrace/map-generation_rkt.zo index 812db04..0327d09 100644 Binary files a/src/compiled/drracket/errortrace/map-generation_rkt.zo and b/src/compiled/drracket/errortrace/map-generation_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/point_rkt.dep b/src/compiled/drracket/errortrace/point_rkt.dep index d58dbc4..40b4460 100644 --- a/src/compiled/drracket/errortrace/point_rkt.dep +++ b/src/compiled/drracket/errortrace/point_rkt.dep @@ -1 +1 @@ -("6.12" ("ca58fe6577647fa8098a13c8a0f8a0a38784fcd2" . "993e6f5264ee26984152d1638fd723311934eb44") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt")) +("6.12" ("30ca029b6ff90c7447eada78cab71df502ddbd3e" . "993e6f5264ee26984152d1638fd723311934eb44") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt")) diff --git a/src/compiled/drracket/errortrace/screen_rkt.dep b/src/compiled/drracket/errortrace/screen_rkt.dep index b6131b7..cf68d53 100644 --- a/src/compiled/drracket/errortrace/screen_rkt.dep +++ b/src/compiled/drracket/errortrace/screen_rkt.dep @@ -1 +1 @@ -("6.12" ("e616b95773a9b30530fbcd0fbc588852da5c505b" . "993e6f5264ee26984152d1638fd723311934eb44") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt")) +("6.12" ("39ec486216d56009bc06ce2bcebb4c2cdcd05bf4" . "993e6f5264ee26984152d1638fd723311934eb44") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt")) diff --git a/src/compiled/drracket/errortrace/screen_rkt.zo b/src/compiled/drracket/errortrace/screen_rkt.zo index 6615af1..946ca53 100644 Binary files a/src/compiled/drracket/errortrace/screen_rkt.zo and b/src/compiled/drracket/errortrace/screen_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/tiles_rkt.dep b/src/compiled/drracket/errortrace/tiles_rkt.dep new file mode 100644 index 0000000..e84fa8e --- /dev/null +++ b/src/compiled/drracket/errortrace/tiles_rkt.dep @@ -0,0 +1 @@ +("6.12" ("43334548c8175864f5e77fd0e7791b9862cd42eb" . "57008848262fcd417d822bbf1b32114f0ed8ac3f") (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) diff --git a/src/compiled/drracket/errortrace/tiles_rkt.zo b/src/compiled/drracket/errortrace/tiles_rkt.zo new file mode 100644 index 0000000..505de83 Binary files /dev/null and b/src/compiled/drracket/errortrace/tiles_rkt.zo differ diff --git a/src/compiled/drracket/errortrace/world_rkt.dep b/src/compiled/drracket/errortrace/world_rkt.dep index a8c091b..4650b4f 100644 --- a/src/compiled/drracket/errortrace/world_rkt.dep +++ b/src/compiled/drracket/errortrace/world_rkt.dep @@ -1 +1 @@ -("6.12" ("9c1fa0e01578390c77532a2a043a1a46dd6b7702" . "a643c1520339151ce3dc666c24ecd03c3b1ed777") #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\entities.rkt" #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\game-screen.rkt" #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\map-generation.rkt" #"C:\\Users\\Larken\\git\\LispGameJame2018\\src\\point.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) +("6.12" ("9953795aca5daf58321ff4afcd64d5c02cba9ce1" . "5af61e58a5de044ea340ead98c359f8f058f9afd") #"/Users/larken/git/LispGameJam/src/entities.rkt" #"/Users/larken/git/LispGameJam/src/game-screen.rkt" #"/Users/larken/git/LispGameJam/src/map-generation.rkt" #"/Users/larken/git/LispGameJam/src/point.rkt" (collects #"2htdp" #"image.rkt") (collects #"errortrace" #"errortrace-key.rkt") (collects #"racket" #"main.rkt") (collects #"racket" #"runtime-config.rkt") (collects #"thing" #"main.rkt")) diff --git a/src/compiled/drracket/errortrace/world_rkt.zo b/src/compiled/drracket/errortrace/world_rkt.zo index 9fe3b58..1f8c0a2 100644 Binary files a/src/compiled/drracket/errortrace/world_rkt.zo and b/src/compiled/drracket/errortrace/world_rkt.zo differ diff --git a/src/entities.rkt b/src/entities.rkt index 291330a..4c5cc34 100644 --- a/src/entities.rkt +++ b/src/entities.rkt @@ -12,6 +12,7 @@ (define-thing entity [character "x"] [color "white"] + [background-color "black"] [location (pt 0 0)] [inventory '()] [view-range 5]) @@ -28,9 +29,9 @@ [(act self world) (send world try-move self - (+ (thing-get 'location) + (+ (thing-get self 'location) (pt (- (random 3) 1) - (- (random 3) 1))))]) + (- (random 3) 1))))]) ; A seeking enemy runs towards the player (heedless of walls) 50% of the time ; The other 50% of the time they are identical to a wandering enemy diff --git a/src/entities.rkt~ b/src/entities.rkt~ new file mode 100644 index 0000000..291330a --- /dev/null +++ b/src/entities.rkt~ @@ -0,0 +1,70 @@ +#lang racket + +(provide (all-defined-out)) + +(require thing "point.rkt") + +; All entities have: +; - a location on the map +; - attack and defense strengths +; - hitpoints +; - an inventory +(define-thing entity + [character "x"] + [color "white"] + [location (pt 0 0)] + [inventory '()] + [view-range 5]) + +(define-thing enemy entity + [name "enemy"] + [color "red"] + [attack 10] + [defense 10] + [health 10] + [(act self world) (void)]) + +(define-thing wandering-enemy enemy + [(act self world) + (send world try-move + self + (+ (thing-get 'location) + (pt (- (random 3) 1) + (- (random 3) 1))))]) + +; A seeking enemy runs towards the player (heedless of walls) 50% of the time +; The other 50% of the time they are identical to a wandering enemy +(define-thing seeking-enemy wandering-enemy + [(act self world) + (cond + ; 50/50 of a seeking move + [(= 0 (random 2)) + (define player-pt (thing-get (send world get-player) 'location)) + (define self-pt (thing-get self 'location)) + (define dir (unit (- player-pt self-pt))) + (send world try-move + self + (+ self-pt + (inexact->exact (round (pt-x dir))) + (inexact->exact (round (pt-y dir)))))] + ; Otherwise, wander + [else + (thing-call wandering-enemy 'act self world)])]) + +; A fleeing enemy moves the exact opposite of a seeking enemy +(define-thing fleeing-enemy wandering-enemy + [(act self world) + (cond + ; 50/50 of a fleeing move + [(= 0 (random 2)) + (define player-pt (thing-get (send world get-player) 'location)) + (define self-pt (thing-get self 'location)) + (define dir (unit (- player-pt self-pt))) + (send world try-move + self + (- self-pt + (inexact->exact (round (pt-x dir))) + (inexact->exact (round (pt-y dir)))))] + ; Otherwise, wander + [else + (thing-call wandering-enemy 'act self world)])]) diff --git a/src/game-screen.rkt b/src/game-screen.rkt index d39eb68..28bcc2b 100644 --- a/src/game-screen.rkt +++ b/src/game-screen.rkt @@ -1,53 +1,113 @@ #lang racket -(require "point.rkt" "screen.rkt" "inventory-screen.rkt" 2htdp/image thing) -(provide game-screen%) +(require "point.rkt" "screen.rkt" "inventory-screen.rkt" "map-generation.rkt" 2htdp/image thing) +(provide game-screen% text/menlo text/menlo/small) +(define (text/menlo s color) (text/font s 28 color "Menlo" 'script 'normal 'normal #f)) +(define (text/menlo/small s color) (text/font s 20 color "Menlo" 'script 'normal 'normal #f)) (define game-screen% - (class screen% - (init-field TILE_SIZE WIDTH HEIGHT) - (define width-in-characters (quotient WIDTH TILE_SIZE)) - (define height-in-characters (quotient HEIGHT TILE_SIZE)) - (define/public (get-width-in-characters) width-in-characters) - (define/public (get-height-in-characters) height-in-characters) - - ; draw a character at a location with given colors on the given image - (define (draw-char c x y fg bg canvas) - (let ([char (overlay - (text/font c TILE_SIZE fg "Menlo" 'script 'normal 'normal #f) - (rectangle TILE_SIZE TILE_SIZE "solid" "black"))]) - (place-image/align char (* x TILE_SIZE) (* y TILE_SIZE) 'left 'top canvas))) - - (define (draw-entity e canvas) - (define p (thing-get e 'location)) - (draw-char (thing-get e 'character) (pt-x p) (pt-y p) (thing-get e 'color) "transparent" canvas)) - - - (define/override (render state) - ; basic idea for a render: - ; - render viewport of map using tile-at method on state - ; - render the player, and non-player-characters - (define canvas (rectangle WIDTH HEIGHT "solid" "black")) - (define player (send state get-player)) - (define draw-@ (recenter this (pt 0 0))) - (for* ([xi (in-range width-in-characters)] - [yi (in-range height-in-characters)]) - (define x/y (recenter this (- (thing-get player 'location) (pt xi yi)))) - (define tile (send state tile-at (pt-x x/y) (pt-y x/y))) - (set! canvas (draw-char (thing-get tile 'character) xi yi (thing-get tile 'color) "transparent" canvas))) - (draw-char (thing-get player 'character) (pt-x draw-@) (pt-y draw-@) (thing-get player 'color) "transparent" canvas)) - - ; key event handler for player input while viewing in-game display - (define/override (key-handler state key) - (define player (send state get-player)) - (define location (thing-get player 'location)) - (case key - [("numpad4" "h" "left") (send state try-move player (- location (pt -1 0)))] - [("numpad6" "l" "right") (send state try-move player (- location (pt 1 0)))] - [("numpad2" "j" "down") (send state try-move player (- location (pt 0 1)))] - [("numpad8" "k" "up") (send state try-move player (- location (pt 0 -1)))] - [("numpad7" "y") (send state try-move player (- location (pt -1 -1)))] - [("numpad9" "u") (send state try-move player (- location (pt 1 -1)))] - [("numpad1" "b") (send state try-move player (- location (pt -1 1)))] - [("numpad3" "n") (send state try-move player (- location (pt 1 1)))] - [else state])) - - (super-new))) + (class screen% + (init-field TILE_SIZE WIDTH HEIGHT) + (define width-in-characters (quotient WIDTH TILE_SIZE)) + (define height-in-characters (quotient HEIGHT TILE_SIZE)) + (define/public (get-width-in-characters) width-in-characters) + (define/public (get-height-in-characters) height-in-characters) + + ; draw a character at a location with given colors on the given image + (define (draw-char c x y fg bg canvas) + (let ([char (overlay + (text/font c 28 fg "Menlo" 'script 'normal 'normal #f) + (rectangle TILE_SIZE TILE_SIZE "solid" bg))]) + (place-image/align char (* x TILE_SIZE) (* y TILE_SIZE) 'left 'top canvas))) + + (define (draw-entity e state canvas) + (define p (thing-get e 'location)) + (define x/y (recenter this (- (thing-get (send state get-player) 'location) (pt (pt-x p) (pt-y p))))) + (define tile (send state tile-at (pt-x x/y) (pt-y x/y))) + (draw-char (thing-get e 'character) (pt-x x/y) (pt-y x/y) (thing-get e 'color) (thing-get tile 'background-color) canvas)) + + + (define/override (render state) + + (define player (send state get-player)) + (define p (thing-get player 'location)) + (define draw-@ (recenter this (pt 0 0))) + (define canvas (rectangle WIDTH HEIGHT "solid" "black")) + ; right-panel to hold stats, items held + (define separator (rectangle (* TILE_SIZE .25) HEIGHT "solid" (make-color 175 199 193))) + (define hp (string-append + "HP: " + (number->string (thing-get player 'health)) + " / " + (number->string (thing-get player 'max-health)))) + (define HUD + (let ([panel (rectangle (* TILE_SIZE 15) (- HEIGHT 180) "solid" (color 14 58 57))] + [get-gem (λ (f) (if (f (thing-get player 'gems)) "◆ " "◇ "))]) + (place-image/align + (above/align 'left + (text/menlo "Merlin" (make-color 175 199 193)) ; name of character + (text/menlo hp "white") ; hp / maxhp + (text/menlo (string-append "DEF: " (number->string (thing-get player 'defense))) "white") + (beside (text/menlo "Gems: " "white") ; gems collected + (text/menlo (get-gem first) (make-color 0 146 251)) + (text/menlo (get-gem second) "green") + (text/menlo (get-gem third) "red") + (text/menlo (get-gem fourth)"white"))) + 10 10 'left 'top panel))) + (define logs-viewer + (let ([result (rectangle (* TILE_SIZE 15) 180 "solid" (color 14 58 57))] + [logs (send state get-logs)]) + (place-image/align + (text/menlo/small (foldr (λ (log r) (string-append r "\n" log)) "" logs) "white") + 0 0 'left 'top + result))) + + (define (draw-tile x y tile c) + (let ([items (thing-get tile 'items)]) + (cond + [(not (empty? items)) (draw-char (thing-get (first items) 'character) x y (thing-get (first items) 'color) (thing-get tile 'background-color) c)] + [else (draw-char (thing-get tile 'character) x y (thing-get tile 'color) (thing-get tile 'background-color) c)]))) + + + ; render all of the tiles in the viewport + (for* ([xi (in-range width-in-characters)] + [yi (in-range height-in-characters)]) + (define x/y (recenter this (- (thing-get player 'location) (pt xi yi)))) + (define tile (send state tile-at (pt-x x/y) (pt-y x/y))) + (set! canvas (draw-tile xi yi tile canvas))) + ; render the player to the viewport + (set! canvas (draw-char (thing-get player 'character) + (pt-x draw-@) (pt-y draw-@) + (thing-get player 'color) + (thing-get (send state tile-at (pt-x p) (pt-y p)) 'background-color) + canvas)) + + + ; render all other npcs to the viewport + (for ([npc (get-npcs)]) + (set! canvas (draw-entity npc state canvas))) + + ; render a separator and panel next to the game-viewport for a HUD + (beside + canvas + separator + (above HUD logs-viewer))) + + + ; key event handler for player input while viewing in-game display + (define/override (key-handler state key) + (define player (send state get-player)) + (define location (thing-get player 'location)) + (case key + [("numpad4" "h" "left") (send state try-move player (- location (pt -1 0)))] + [("numpad6" "l" "right") (send state try-move player (- location (pt 1 0)))] + [("numpad2" "j" "down") (send state try-move player (- location (pt 0 1)))] + [("numpad8" "k" "up") (send state try-move player (- location (pt 0 -1)))] + [("numpad7" "y") (send state try-move player (- location (pt -1 -1)))] + [("numpad9" "u") (send state try-move player (- location (pt 1 -1)))] + [("numpad1" "b") (send state try-move player (- location (pt -1 1)))] + [("numpad3" "n") (send state try-move player (- location (pt 1 1)))]) + ;[("q") (send state kill-player)] + ;[("w") (send state collect-all-gems)]) + (send state update) + state) + + (super-new))) diff --git a/src/game-screen.rkt~ b/src/game-screen.rkt~ new file mode 100644 index 0000000..d39eb68 --- /dev/null +++ b/src/game-screen.rkt~ @@ -0,0 +1,53 @@ +#lang racket +(require "point.rkt" "screen.rkt" "inventory-screen.rkt" 2htdp/image thing) +(provide game-screen%) +(define game-screen% + (class screen% + (init-field TILE_SIZE WIDTH HEIGHT) + (define width-in-characters (quotient WIDTH TILE_SIZE)) + (define height-in-characters (quotient HEIGHT TILE_SIZE)) + (define/public (get-width-in-characters) width-in-characters) + (define/public (get-height-in-characters) height-in-characters) + + ; draw a character at a location with given colors on the given image + (define (draw-char c x y fg bg canvas) + (let ([char (overlay + (text/font c TILE_SIZE fg "Menlo" 'script 'normal 'normal #f) + (rectangle TILE_SIZE TILE_SIZE "solid" "black"))]) + (place-image/align char (* x TILE_SIZE) (* y TILE_SIZE) 'left 'top canvas))) + + (define (draw-entity e canvas) + (define p (thing-get e 'location)) + (draw-char (thing-get e 'character) (pt-x p) (pt-y p) (thing-get e 'color) "transparent" canvas)) + + + (define/override (render state) + ; basic idea for a render: + ; - render viewport of map using tile-at method on state + ; - render the player, and non-player-characters + (define canvas (rectangle WIDTH HEIGHT "solid" "black")) + (define player (send state get-player)) + (define draw-@ (recenter this (pt 0 0))) + (for* ([xi (in-range width-in-characters)] + [yi (in-range height-in-characters)]) + (define x/y (recenter this (- (thing-get player 'location) (pt xi yi)))) + (define tile (send state tile-at (pt-x x/y) (pt-y x/y))) + (set! canvas (draw-char (thing-get tile 'character) xi yi (thing-get tile 'color) "transparent" canvas))) + (draw-char (thing-get player 'character) (pt-x draw-@) (pt-y draw-@) (thing-get player 'color) "transparent" canvas)) + + ; key event handler for player input while viewing in-game display + (define/override (key-handler state key) + (define player (send state get-player)) + (define location (thing-get player 'location)) + (case key + [("numpad4" "h" "left") (send state try-move player (- location (pt -1 0)))] + [("numpad6" "l" "right") (send state try-move player (- location (pt 1 0)))] + [("numpad2" "j" "down") (send state try-move player (- location (pt 0 1)))] + [("numpad8" "k" "up") (send state try-move player (- location (pt 0 -1)))] + [("numpad7" "y") (send state try-move player (- location (pt -1 -1)))] + [("numpad9" "u") (send state try-move player (- location (pt 1 -1)))] + [("numpad1" "b") (send state try-move player (- location (pt -1 1)))] + [("numpad3" "n") (send state try-move player (- location (pt 1 1)))] + [else state])) + + (super-new))) diff --git a/src/items.rkt b/src/items.rkt new file mode 100644 index 0000000..78974bb --- /dev/null +++ b/src/items.rkt @@ -0,0 +1,161 @@ +#lang racket + +(provide (all-defined-out)) + +(require + thing + "point.rkt" + 2htdp/image) + +; All items have: +; - a display char/item if they're on the ground +; - if they're consumed or not (picked up) +; - if they stack or not (stackables use the 'quantity' value) +; - methods for: +; -- being picked up +; -- being dropped +; +; NOTE: stackable overrides consumable +(define-thing item + [character #\x] + [color "white"] + [consumable #f] + [stackable #f] + [quantity 1] + [category 'unknown] + [(on-pick-up item entity world) (void)] + [(on-drop item entity world) (void)]) + +(define-thing gem item + [character "◆"]) + +(define-thing player + [character "@"] + [color "yellow"] + [name "player"] + [attack 10] + [defense 10] + [health 20] + [max-health 20] + [gems (list #f #f #f #f)]) + +(define-thing sapphire gem + [name "sapphire"] + [color (make-color 0 146 251)] + [(on-pick-up item entity world) + (define original-gems (thing-get entity 'gems)) + (define sapphire (first original-gems)) + (define emerald (second original-gems)) + (define ruby (third original-gems)) + (define diamond (fourth original-gems)) + (thing-set! entity 'gems (list #t emerald ruby diamond))]) + +(define-thing emerald gem + [name "emerald"] + [color "green"] + [(on-pick-up item entity world) + (define original-gems (thing-get entity 'gems)) + (define sapphire (first original-gems)) + (define emerald (second original-gems)) + (define ruby (third original-gems)) + (define diamond (fourth original-gems)) + (thing-set! entity 'gems (list sapphire #t ruby diamond))]) + +(define-thing ruby gem + [name "ruby"] + [color "red"] + [(on-pick-up item entity world) + (define original-gems (thing-get entity 'gems)) + (define sapphire (first original-gems)) + (define emerald (second original-gems)) + (define ruby (third original-gems)) + (define diamond (fourth original-gems)) + (thing-set! entity 'gems (list sapphire emerald #t diamond))]) + +(define-thing diamond gem + [name "diamond"] + [color "white"] + [(on-pick-up item entity world) + (define original-gems (thing-get entity 'gems)) + (define sapphire (first original-gems)) + (define emerald (second original-gems)) + (define ruby (third original-gems)) + (define diamond (fourth original-gems)) + (thing-set! entity 'gems (list sapphire emerald ruby #t))]) + +; blue green red white +(define *gems* + (vector + emerald + sapphire + ruby diamond)) + +; Armor protects the wearer +(define-thing armor item + [character "\\"] + [defense 0] + [category 'armor] + [(on-pick-up item entity world) + (thing-set! entity 'defense (+ (thing-get entity 'defense) + (thing-get item 'defense)))] + [(on-drop item entity world) + (thing-set! entity 'defense (- (thing-get entity 'defense) + (thing-get item 'defense)))]) + +(define *armors* + (vector + (make-thing armor [name "leather"] [color "brown"] [defense 1]) + (make-thing armor [name "chain"] [color "gray"] [defense 2]) + (make-thing armor [name "plate"] [color "white"] [defense 3]) + (make-thing armor [name "enchanted"] [color "purple"] [defense 5]))) + +; Weapons increase attack +(define-thing weapon item + [character #\)] + [attack 0] + [category 'weapon] + [(on-pick-up item entity world) + (thing-set! entity 'attack (+ (thing-get entity 'attack) + (thing-get item 'attack)))] + [(on-drop item entity world) + (thing-set! entity 'attack (- (thing-get entity 'attack) + (thing-get item 'attack)))]) + +(define *weapons* + (vector + (make-thing weapon [name "club"] [color "brown"] [attack 1]) + (make-thing weapon [name "dagger"] [color "gray"] [attack 2]) + (make-thing weapon [name "battle axe"] [color "white"] [attack 3]) + (make-thing weapon [name "longsword"] [color "white"] [attack 3]) + (make-thing weapon [name "magic sword"] [color "purple"] [attack 5]))) + +; Potions are single use and consumed on contact +(define-thing potion item + [character #\!] + [category 'potion] + [consumable #t]) + +(define *potions* + (vector + (make-thing potion + [name "health potion"] + [color "red"] + [(on-pick-up item entity world) + (thing-set! entity 'health (+ 10 (thing-get entity 'health)))]))) + +; Coins are stackables +(define-thing coins item + [character #\*] + [category 'coin] + [stackable #t]) + +(define *coins* + (vector + (make-thing coins [name "copper coin"] [color "brown"] [quantity 0.01]) + (make-thing coins [name "silver coin"] [color "silver"] [quantity 0.1]) + (make-thing coins [name "gold coin"] [color "yellow"] [quantity 1]) + (make-thing coins [name "platinum coin"] [color "white"] [quantity 10]))) + +; All items combined +(define *all-items* + (vector *armors* *weapons* *potions* *coins*)) \ No newline at end of file diff --git a/src/items.rkt~ b/src/items.rkt~ new file mode 100644 index 0000000..d7d4ac6 --- /dev/null +++ b/src/items.rkt~ @@ -0,0 +1,96 @@ +#lang racket + +(provide (all-defined-out)) + +(require + thing + "point.rkt") + +; All items have: +; - a display char/item if they're on the ground +; - if they're consumed or not (picked up) +; - if they stack or not (stackables use the 'quantity' value) +; - methods for: +; -- being picked up +; -- being dropped +; +; NOTE: stackable overrides consumable +(define-thing item + [character #\x] + [color "white"] + [consumable #f] + [stackable #f] + [quantity 1] + [category 'unknown] + [(on-pick-up item entity world) (void)] + [(on-drop item entity world) (void)]) + +; Armor protects the wearer +(define-thing armor item + [character #\]] + [defense 0] + [category 'armor] + [(on-pick-up item entity world) + (thing-set! entity 'defense (+ (thing-get entity 'defense) + (thing-get item 'defense)))] + [(on-drop item entity world) + (thing-set! entity 'defense (- (thing-get entity 'defense) + (thing-get item 'defense)))]) + +(define *armors* + (vector + (make-thing armor [name "leather"] [color "brown"] [defense 1]) + (make-thing armor [name "chain"] [color "gray"] [defense 2]) + (make-thing armor [name "plate"] [color "white"] [defense 3]) + (make-thing armor [name "enchanted"] [color "purple"] [defense 5]))) + +; Weapons increase attack +(define-thing weapon item + [character #\)] + [attack 0] + [category 'weapon] + [(on-pick-up item entity world) + (thing-set! entity 'attack (+ (thing-get entity 'attack) + (thing-get item 'attack)))] + [(on-drop item entity world) + (thing-set! entity 'attack (- (thing-get entity 'attack) + (thing-get item 'attack)))]) + +(define *weapons* + (vector + (make-thing weapon [name "club"] [color "brown"] [attack 1]) + (make-thing weapon [name "dagger"] [color "gray"] [attack 2]) + (make-thing weapon [name "battle axe"] [color "white"] [attack 3]) + (make-thing weapon [name "longsword"] [color "white"] [attack 3]) + (make-thing weapon [name "magic sword"] [color "purple"] [attack 5]))) + +; Potions are single use and consumed on contact +(define-thing potion item + [character #\!] + [category 'potion] + [consumable #t]) + +(define *potions* + (vector + (make-thing potion + [name "health potion"] + [color "red"] + [(on-pick-up item entity world) + (thing-set! entity 'health (+ 10 (thing-get entity 'health)))]))) + +; Coins are stackables +(define-thing coins item + [character #\*] + [category 'coin] + [stackable #t]) + +(define *coins* + (vector + (make-thing coins [name "copper coin"] [color "brown"] [quantity 0.01]) + (make-thing coins [name "silver coin"] [color "silver"] [quantity 0.1]) + (make-thing coins [name "gold coin"] [color "yellow"] [quantity 1]) + (make-thing coins [name "platinum coin"] [color "white"] [quantity 10]))) + +; All items combined +(define *all-items* + (vector *armors* *weapons* *potions* *coins*)) \ No newline at end of file diff --git a/src/main.rkt b/src/main.rkt index d9f3ac3..a3ba0a5 100644 --- a/src/main.rkt +++ b/src/main.rkt @@ -4,8 +4,11 @@ (define world (new world%)) +; (send world get-render world) + (big-bang (new world%) - (name "Racket Roguelike") + (name "Merlin's Teleportation Troubles") (to-draw (λ (s) (send s get-render s))) (on-key (λ (s k) (send s get-key-handler s k))) - (stop-when (λ (s) (send s get-end-game-condition)))) + (stop-when (λ (s) (send s get-end-game-condition)) + (λ (s) (send s get-end-game-image)))) diff --git a/src/main.rkt~ b/src/main.rkt~ new file mode 100644 index 0000000..d9f3ac3 --- /dev/null +++ b/src/main.rkt~ @@ -0,0 +1,11 @@ +#lang racket +(require 2htdp/image 2htdp/universe "world.rkt") + +(define world + (new world%)) + +(big-bang (new world%) + (name "Racket Roguelike") + (to-draw (λ (s) (send s get-render s))) + (on-key (λ (s k) (send s get-key-handler s k))) + (stop-when (λ (s) (send s get-end-game-condition)))) diff --git a/src/map-generation.rkt b/src/map-generation.rkt index ee3b13a..b1e11f5 100644 --- a/src/map-generation.rkt +++ b/src/map-generation.rkt @@ -1,6 +1,6 @@ #lang racket -(require noise thing "point.rkt" ) ; 2htdp/image) -(provide get-tile) +(require noise thing "point.rkt" "tiles.rkt" "items.rkt" "entities.rkt" 2htdp/image) +(provide get-tile get-npcs update-npcs for-tile) (struct level-definition (tile-gen npcs items)) (define levels (make-hasheq)) (define current-depth (make-parameter 0)) @@ -10,7 +10,7 @@ (define level (make-hash)) (hash-set! level 'seed (random)) (hash-set! level 'npcs '()) - (hash-set! level 'gen (level-definition surface nothing nothing)) + (hash-set! level 'gen (level-definition surface bunnies-and-goblins base-items)) (hash-set! levels depth level)) (hash-ref levels depth)) @@ -25,7 +25,21 @@ (define new-tile (let ([base-tile ((level-definition-tile-gen (hash-ref current-level 'gen)) seed x y)]) (make-thing base-tile))) + + (when (thing-get new-tile 'walkable) + (define new-npc ((level-definition-npcs (hash-ref current-level 'gen)) seed x y)) + (when (and (not (void? new-npc)) new-npc) + (let ([new-npc (make-thing new-npc [location (pt x y)])]) + (hash-set! current-level 'npcs (cons new-npc (hash-ref current-level 'npcs)))))) + ; (Potentially) generate a new item for that tile + ; Do not generate an item if there already is one (generated by the tile generation routine) + (when (empty? (thing-get new-tile 'items '())) + (define new-item ((level-definition-items (hash-ref current-level 'gen)) seed x y)) + (when (and (not (void? new-item)) (thing-get new-tile 'walkable)) + (let ([new-item (make-thing new-item)]) + (thing-set! new-tile 'items (cons new-item (thing-get new-tile 'items)))))) (hash-set! current-level (pt x y) new-tile)) + ; Return the tile (newly generated or not) (hash-ref current-level (pt x y))) @@ -34,16 +48,16 @@ (define (surface seed x y) ; snowy-level sea-level beach-level forest-level size freq redistribution ; (create-3d-simplex-with-water 6 .5 .6 1.2 100 3 4)) - (define sea-level .5) - (define coast-level .7) - (define beach-level .75) - (define forest-level 2) + (define sea-level .3) + (define coast-level .5) + (define beach-level 1) + (define forest-level 6) (define jungle-level 3) (define desert-level 4) (define arctic-level 5) - (define mountain-level 6) + (define mountain-level 10) (define size 100) - (define redistribution 3) + (define redistribution 6) (define freq 3) (define (get-elevation x y) (expt (abs (- 1 @@ -60,87 +74,112 @@ (define desert? (<= e desert-level)) (define arctic? (<= e arctic-level)) (define mountain? (<= e mountain-level)) + (define (create-grass) + (let ([r (random 100)]) + (cond + [(>= 5 r) (make-thing flower1)] + [(>= 10 r) (make-thing flower2)] + [(>= 15 r) (make-thing flower3)] + [else (make-thing grass)]))) + (cond [water? (make-thing water)] [coast? (make-thing shallow-water)] [beach? (make-thing sand)] [forest? (if (>= 5 (random 100)) (make-thing forest-tree) - (make-thing grass))] - [jungle? (if (>= 5 (random 100)) - (make-thing jungle-tree) - (make-thing grass))] - [desert? (make-thing sand)] + (create-grass))] [mountain? (make-thing mountain)] - [else (make-thing empty)])) - -; ===== Basic tile definitions ===== - -(define-thing tile - [character " "] - [color "black"] - [items '()] - [lighting 'dark] ; Dark: Invisible; Fog: Only show tile, not NPC or item; Lit: Everything - [walkable #f] ; Can the player walk on this tile? - [solid #f]) ; Does this tile block light? - -(define-thing empty tile - [walkable #t]) - -(define-thing grass tile - [character "."] - [color "brown"] - [walkable #t]) - -(define-thing sand tile - [character "."] - [color "goldenrod"] - [walkable #t]) - -(define-thing flower tile - [character "\'"] - [color "green"] - [walkable #t]) - -(define-thing flower2 tile - [character ","] - [color "green"] - [walkable #t]) - -(define-thing flower3 tile - [character "`"] - [color "green"] - [walkable #t]) - -(define-thing mountain tile - [character "^"] - [color "white"] - [solid #t]) - -(define-thing wall tile - [solid #t] - [character "#"] - [color "white"]) - -(define-thing water tile - [character "~"] - [color "blue"]) - -(define-thing shallow-water tile - [character "~"] - [color "lightblue"]) - -(define-thing forest-tree tile - [solid #t] - [character "♠"] - [color "green"]) - -(define-thing jungle-tree tile - [solid #t] - [character "♠"] - [color "limegreen"]) + [else (make-thing mountain-peak)])) (define (nothing seed x y) #f) + +; Loop over all generated tiles on the current level to update them +; f : x y tile -> void +(define (for-tile f) + (for ([(pt tile) (in-hash (get-level (current-depth)))] + #:when (pt? pt)) + (f (pt-x pt) (pt-y pt) tile))) + +; Ascend or descend to a (potentially) new level +(define (ascend) (current-depth (+ (current-depth) 1))) +(define (descend) (current-depth (- (current-depth) 1))) + +; Get the NPCs on the current level +(define (get-npcs) + (hash-ref (get-level (current-depth)) 'npcs)) + +; Update npcs +(define (update-npcs world) + (define current-level (get-level (current-depth))) + (define npcs (hash-ref current-level 'npcs)) + + ; Allow each to move + (for ([npc (in-list npcs)]) + (thing-call npc 'act npc world)) + + ; Check for (and remove) any dead npcs + (hash-set! current-level 'npcs + (filter + (lambda (npc) + (when (<= (thing-get npc 'health) 0) + (send world log-message (format "~a has died" (thing-get npc 'name)))) + (> (thing-get npc 'health) 0)) + npcs))) + +; Look up a thing from a vector by 'name +(define (lookup vec name) + (let/ec return + (for ([thing vec] + #:when (equal? name (thing-get thing 'name #f))) + (return thing)) + (return #f))) + +(define *entities* + (vector + (make-thing fleeing-enemy + [name "rat"] + [character "r"] + [color "gray"]) + + (make-thing fleeing-enemy + [name "bunny"] + [character "b"] + [color "lightblue"]) + + (make-thing seeking-enemy + [name "minotaur"] + [character "M"] + [color "brown"]) + + (make-thing seeking-enemy + [name "goblin"] + [character "g"] + [color "orange"] + [attack 15] + [defense 5]))) + +; Enemy Generation routines +(define (bunnies-and-goblins seed x y) + (when (zero? (random 100)) + (if (zero? (random 4)) + (lookup *entities* "goblin") + (if (zero? (random 4)) + (lookup *entities* "bunny") + (lookup *entities* "rat"))))) + +; Item Generation routines +(define (base-items seed x y) + (when (zero? (random 500)) + (case (random 4) + [(0) (lookup *gems* "emerald")] + [(1) (lookup *gems* "ruby")] + [(2) (lookup *gems* "sapphire")] + [(3) (lookup *gems* "diamond")]))) + + +;;; code for rendering sample maps + (define (real->natural n) (define (helper n acc) (cond @@ -149,15 +188,14 @@ [else (helper n (add1 acc))])) (helper n 0)) -(require 2htdp/image) (define (render-surface size) (define TILE_SIZE 5) (define (draw-char c x y fg bg canvas) (let ([char (overlay (text/font c TILE_SIZE fg "Menlo" 'script 'normal 'normal #f) - (rectangle TILE_SIZE TILE_SIZE "solid" "black"))]) + (rectangle TILE_SIZE TILE_SIZE "solid" (color 14 58 57)))]) (place-image/align char (* x TILE_SIZE) (* y TILE_SIZE) 'left 'top canvas))) - (define img (rectangle size size "solid" "black")) + (define img (rectangle size size "solid" (color 14 58 57))) (for* ([x (in-range size)] [y (in-range size)]) (define tile (get-tile x y)) @@ -165,56 +203,14 @@ img) (define (render-surface2 size) - (define TILE_SIZE 2) - (define img (rectangle size size "solid" "black")) + (define TILE_SIZE 1) + (define img (rectangle size size "solid" (color 14 58 57))) (for* ([x (in-range size)] [y (in-range size)]) (define tile (get-tile x y)) (set! img (place-image/align - (rectangle TILE_SIZE TILE_SIZE "solid" (thing-get tile 'color)) + (text/font (thing-get tile 'character) TILE_SIZE (thing-get tile 'color) "Menlo" 'script 'normal 'normal #f) x y 'left 'top img))) img) -;(save-image (render-surface 1000) "rendered-ascii-surface.png") - -; -; -;(define (create-3d-simplex size freq) -; (plot3d -; (surface3d (λ (x y) -; (* size ; moving it from decimal to 100's -; (expt (abs (- 1 -; (+ (simplex (* freq (/ x size)) (* freq (/ y size))) -; (* 0.5 (simplex (* (* 2 freq) (/ x size))(* (* 2 freq) (/ y size)))) -; (* 0.25 (simplex (* (* 4 freq) (/ x size))(* (* 2 freq) (/ y size))))) -; )) -; 2))) 0 size 0 size #:line-style 'transparent))) -; - -;(require plot) -;(define (create-3d-simplex-with-water snowy-level sea-level beach-level forest-level size freq redistribution) -; (define seed (random 256)) -; (define (get-elevation x y) -; (expt (abs (- 1 -; (+ (simplex (* freq (/ x size)) (* freq (/ y size)) seed) -; (* 0.5 (simplex (* (* 2 freq) (/ x size))(* (* 2 freq) (/ y size)) seed)) -; (* 0.25 (simplex (* (* 4 freq) (/ x size))(* (* 2 freq) (/ y size)) seed))) -; )) redistribution)) -; (plot3d -; (list (surface3d (λ (x y) (* size (get-elevation x y))) 0 size 0 size #:color '(53 102 79) #:line-style 'transparent) ; land -; (surface3d (λ (x y) ; snow -; (let ([e (get-elevation x y)]) -; (if (> e snowy-level) (add1 (* size e)) 0))) 0 size 0 size #:line-style 'transparent) -; (surface3d (λ (x y) ; water -; (let ([e (get-elevation x y)]) -; (if (< e sea-level) (* size sea-level) 0))) 0 size 0 size #:color '(62 96 193) #:line-style 'transparent) -; (surface3d (λ (x y) ; beach -; (let ([e (get-elevation x y)]) -; (if (< e beach-level) (add1 (* size e)) 0))) 0 size 0 size #:color '(87 121 242) #:line-style 'transparent) -; (surface3d (λ (x y) ; forest -; (let ([e (get-elevation x y)]) -; (if (< e forest-level) (add1 (* size e)) 0))) 0 size 0 size #:color '(116 169 99) #:line-style 'transparent)))) -; -;(parameterize ([plot-width 1300] [plot-height 900] [plot-x-label #f] [plot-y-label #f] [plot-new-window? #t]) -; (create-3d-simplex-with-water 6 .5 .4 1.2 100 3 2)) diff --git a/src/simplex-3d-render.rkt b/src/simplex-3d-render.rkt new file mode 100644 index 0000000..c14ceed --- /dev/null +++ b/src/simplex-3d-render.rkt @@ -0,0 +1,36 @@ +#lang racket +(require plot noise) +(define sea-level .3) +(define coast-level .5) +(define beach-level 1) +(define forest-level 6) +(define jungle-level 3) +(define desert-level 4) +(define snowy-level 5) +(define mountain-level 6) +(define size 100) +(define redistribution 6) +(define freq 3) + +(define (create-3d-simplex-with-water) + (define seed (random 256)) + (define (get-elevation x y) + (expt (abs (- 1 + (+ (simplex (* freq (/ x size)) (* freq (/ y size)) seed) + (* 0.5 (simplex (* (* 2 freq) (/ x size))(* (* 2 freq) (/ y size)) seed)) + (* 0.25 (simplex (* (* 4 freq) (/ x size))(* (* 2 freq) (/ y size)) seed))) + )) redistribution)) + (plot3d + (list (surface3d (λ (x y) (* size (get-elevation x y))) 0 size 0 size #:color '(53 102 79) #:line-style 'transparent) ; land + (surface3d (λ (x y) ; snow; + (let ([e (get-elevation x y)]) + (if (> e snowy-level) (add1 (* size e)) 0))) 0 size 0 size #:line-style 'transparent) + (surface3d (λ (x y) ; water + (let ([e (get-elevation x y)]) + (if (< e sea-level) (* size sea-level) 0))) 0 size 0 size #:color '(62 96 193) #:line-style 'transparent) + (surface3d (λ (x y) ; forest + (let ([e (get-elevation x y)]) + (if (< e forest-level) (add1 (* size e)) 0))) 0 size 0 size #:color '(116 169 99) #:line-style 'transparent)))) + +(parameterize ([plot-width 1300] [plot-height 900] [plot-x-label #f] [plot-y-label #f] [plot-new-window? #t]) + (create-3d-simplex-with-water)) \ No newline at end of file diff --git a/src/tiles.rkt b/src/tiles.rkt new file mode 100644 index 0000000..f80f5a4 --- /dev/null +++ b/src/tiles.rkt @@ -0,0 +1,76 @@ +#lang racket +(require thing 2htdp/image) +(provide (all-defined-out)) + +; ===== Basic tile definitions ===== + +(define-thing tile + [character " "] + [color "black"] + [items '()] + [lighting 'dark] ; Dark: Invisible; Fog: Only show tile, not NPC or item; Lit: Everything + [walkable #f] ; Can the player walk on this tile? + [solid #f] + [background-color (color 14 58 57)]) + +(define-thing empty tile + [walkable #t]) + +(define-thing grass tile + [character "."] + [color "green"] + [walkable #t]) + +(define-thing sand tile + [character "."] + [color "goldenrod"] + [walkable #t]) + +(define-thing flower1 tile + [character ","] + [color "lightgreen"] + [walkable #t]) + +(define-thing flower2 tile + [character ";"] + [color "green"] + [walkable #t]) + +(define-thing flower3 tile + [character "'"] + [color "green"] + [walkable #t]) + +(define-thing mountain tile + [character "^"] + [color (make-color 193 171 137)] + [solid #t]) + +(define-thing mountain-peak tile + [character "^"] + [color "white"] + [solid #t]) + +(define-thing wall tile + [solid #t] + [character "#"] + [color "white"]) + +(define-thing water tile + [character "≈"] + ;[background-color (make-color 0 71 188)] + [color (make-color 0 146 251)]) + +(define-thing shallow-water water + [character "~"] + [walkable #t]) + +(define-thing forest-tree tile + [solid #t] + [character "♠"] + [color "green"]) + +(define-thing jungle-tree tile + [solid #t] + [character "♠"] + [color "limegreen"]) \ No newline at end of file diff --git a/src/tiles.rkt~ b/src/tiles.rkt~ new file mode 100644 index 0000000..34bda38 --- /dev/null +++ b/src/tiles.rkt~ @@ -0,0 +1,76 @@ +#lang racket +(require thing 2htdp/image) +(provide (all-defined-out)) + +; ===== Basic tile definitions ===== + +(define-thing tile + [character " "] + [color "black"] + [items '()] + [lighting 'dark] ; Dark: Invisible; Fog: Only show tile, not NPC or item; Lit: Everything + [walkable #f] ; Can the player walk on this tile? + [solid #f] + [background-color "transparent"]) ; Does this tile block light? + +(define-thing empty tile + [walkable #t]) + +(define-thing grass tile + [character "."] + [color "green"] + [walkable #t]) + +(define-thing sand tile + [character "."] + [color "goldenrod"] + [walkable #t]) + +(define-thing flower1 tile + [character ","] + [color "lightgreen"] + [walkable #t]) + +(define-thing flower2 tile + [character ";"] + [color "green"] + [walkable #t]) + +(define-thing flower3 tile + [character "'"] + [color "green"] + [walkable #t]) + +(define-thing mountain tile + [character "^"] + [color (make-color 193 171 137)] + [solid #t]) + +(define-thing mountain-peak tile + [character "^"] + [color "white"] + [solid #t]) + +(define-thing wall tile + [solid #t] + [character "#"] + [color "white"]) + +(define-thing water tile + [character "~"] + [color "blue"]) + +(define-thing shallow-water tile + [character "~"] + [color "lightblue"] + [walkable #t]) + +(define-thing forest-tree tile + [solid #t] + [character "♠"] + [color "green"]) + +(define-thing jungle-tree tile + [solid #t] + [character "♠"] + [color "limegreen"]) \ No newline at end of file diff --git a/src/world.rkt b/src/world.rkt index c06b1a4..c151bb3 100644 --- a/src/world.rkt +++ b/src/world.rkt @@ -5,49 +5,148 @@ (define world% (class object% (define player - (make-thing entity - [character "@"] - [color "yellow"] - [name "player"] - [attack 10] - [defense 10] - [health 100])); + (make-thing entity + [character "@"] + [color "yellow"] + [name "player"] + [attack 10] + [defense 10] + [health 20] + [max-health 20] + [gems (list #f #f #f #f)])) (define/public (get-player) player) + ; holds all the log messages (define log-messages '()) ; add a new message to the log (define/public (log-message msg) - (set! log-messages (cons log-messages msg))) - - (define/public (get-logs) log-messages) + (set! log-messages (cons msg log-messages))) + (define/public (get-logs) + (if (<= (length log-messages) 6) + log-messages + (take log-messages 6))) ; define the active screen for the big bang to render - (define active-screen (new game-screen% [WIDTH 800] [HEIGHT 600] [TILE_SIZE 32])) + (define active-screen (new game-screen% [WIDTH 800] [HEIGHT 608] [TILE_SIZE 32])) (define/public (update-screen new-screen) - (set! active-screen new-screen)) + (set! active-screen new-screen)) ; functions to assist with rendering...? (define/public (tile-at x y) - (get-tile x y)) + (get-tile x y)) ; move entity to target space ; if there is another entity on the target space, ; the entity will interact with that entity (define/public (try-move entity target) - (define tile (tile-at (pt-x target) (pt-y target))) - (cond - [(not (thing-get tile 'walkable)) (void)] - [else (thing-set! entity 'location target)]) - this) + (define tile (tile-at (pt-x target) (pt-y target))) + (define others + (filter + ; Only get ones at the target location that aren't me + (λ (thing) (and (not (eqv? thing entity)) + (= (thing-get thing 'location) target))) + ; Include the player and all npcs + (cons player (get-npcs)))) + (cond + [(not (thing-get tile 'walkable)) (void)] + [(null? others) + ; move to the new location + (thing-set! entity 'location target) + ; Pick up an item from the ground + (define (pick-up item) + (when (string=? "player" (thing-get entity 'name)) + (thing-call item 'on-pick-up item entity this) + (printf (foldr (λ (g r) (string-append (if g " true " " false ") r)) "" (thing-get entity 'gems)))) + + (send this log-message (format "~a picked up ~a" (thing-get entity 'name) (thing-get item 'name))) + (thing-set! entity 'inventory (cons item (thing-get entity 'inventory))) + (thing-set! tile 'items (remove item (thing-get tile 'items)))) + + ; Drop an item from the inventory + (define (drop item) + (send this log-message (format "~a dropped ~a" (thing-get entity 'name) (thing-get item 'name))) + (thing-set! entity 'inventory (remove item (thing-get entity 'inventory))) + (thing-set! tile 'items (cons item (thing-get tile 'items))) + (thing-call item 'on-drop item entity this)) + + ; Consume a consumable item from the ground + (define (consume item) + (send this log-message (format "~a consumed ~a" (thing-get entity 'name) (thing-get item 'name))) + (thing-set! tile 'items (remove item (thing-get tile 'items))) + (thing-call item 'on-pick-up item entity this)) + + (for ([item (in-list (thing-get tile 'items))]) + (pick-up item))] + + + [else + (for ([other (in-list others)]) + (send this attack entity other))]) + this) + + (define/public (attack entity other) + ; Do the damage + (define damage + (max 0 (- (random (max 1 (thing-get entity 'attack))) + (random (max 1 (thing-get other 'defense)))))) + (thing-set! other 'health (- (thing-get other 'health) damage)) + + ; Log a message + (send this log-message + (format "~a attacked ~a, did ~a damage" + (thing-get entity 'name) + (thing-get other 'name) + damage))) + + (define/public (update) + (update-npcs this)) + (define (collected-all-gems) + (foldr (λ (v r) (and v r)) #true (thing-get player 'gems))) + ; big bang functions - (define end-game-condition #f) ; world% -> boolean + (define (end-game-condition) + (or (<= (thing-get player 'health) 0) (collected-all-gems))) + + (define/public (kill-player) + (thing-set! player 'health 0)) + + (define/public (collect-all-gems) + (thing-set! player 'gems (list #t #t #t #t))) + + ; render last image + (define (render-death i) + (overlay + (overlay + (text/menlo "You died!" "red") + (overlay + (rectangle 400 200 "solid" (color 14 58 57)) + (rectangle 410 210 "solid" (make-color 175 199 193)))) + i)) + + (define (render-victory i) + (overlay + (overlay + ; (text/font c 28 fg "Menlo" 'script 'normal 'normal #f) + (text/menlo/small (string-append "You find the last gem and insert it into your teleporter...\n" + "You activate your teleporter and escaped the wilderness!") + (make-color 0 146 251)) + (overlay + (rectangle 730 200 "solid" (color 14 58 57)) + (rectangle 740 210 "solid" (make-color 175 199 193)))) + i)) + + ; world% -> boolean (define end-game-state void) ; -> world% (define/public (get-render s) (send active-screen render s)) (define/public (get-key-handler s k) (send active-screen key-handler s k)) - (define/public (get-end-game-condition) end-game-condition) + (define/public (get-end-game-condition) (end-game-condition)) + (define/public (get-end-game-image) + (if (and (> (thing-get player 'health) 0) (collected-all-gems)) + (render-victory (send active-screen render this)) + (render-death (send active-screen render this)))) (define/public (get-end-game-state) end-game-state) (super-new)))