Render parts of the Yggdrasil generator (hardcoded map for now)
This commit is contained in:
parent
d3f4c21576
commit
5372579751
11
main.rkt
11
main.rkt
|
@ -13,7 +13,8 @@
|
|||
"src/pages/home.rkt"
|
||||
"src/pages/other-generators.rkt"
|
||||
"src/pages/arnytron.rkt"
|
||||
"src/pages/floraverse.rkt")
|
||||
"src/pages/floraverse.rkt"
|
||||
"src/pages/yggdrasil.rkt")
|
||||
; Website
|
||||
(define *website*
|
||||
(website
|
||||
|
@ -35,6 +36,11 @@
|
|||
("Calendar" weblet pages:floraverse-calendar)
|
||||
("Calendar/{month}/{day}" matching-weblet pages:floraverse-calendar)
|
||||
)
|
||||
; Yggdrasil generator
|
||||
("Yggdrasil" weblet pages:yggdrasil
|
||||
("About" weblet pages:yggdrasil-about)
|
||||
("Raw" weblet pages:yggdrasil-raw-image)
|
||||
)
|
||||
; Other generators
|
||||
("Generators" weblet pages:other-generators
|
||||
("ColorScheme" weblet pages:color-scheme-generator)
|
||||
|
@ -61,6 +67,9 @@
|
|||
("Calendar" "/Floraverse/Calendar" #f)
|
||||
("About the character generator" "/Floraverse/AboutCharacterGenerator" #f)
|
||||
)
|
||||
("Yggdrasil" "/Yggdrasil" #t
|
||||
("About the Yggdrasil generator" "/Yggdrasil/About" #f)
|
||||
)
|
||||
("Miscellaneous Generators" "/Generators" #f
|
||||
("Color Scheme" "/Generators/ColorScheme" #f)
|
||||
("Pictogrammic Adventurer" "/Generators/PictogrammicAdventurer" #t)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#lang racket/base
|
||||
|
||||
; Dungeon generator
|
||||
; Name from Etrian Odyssey, as the original output style was to look like Etrian Odyssey maps
|
||||
|
||||
; The generator outputs a 2d-array of cells, that should be given to a renderer
|
||||
(require
|
||||
racket/string
|
||||
"../collection/2d-array.rkt"
|
||||
"yggdrasil/cell.rkt"
|
||||
)
|
||||
|
||||
(provide
|
||||
yggdrasil-generate)
|
||||
|
||||
; Generator function
|
||||
; The constraints are a hash of parameters, with the possible values:
|
||||
; - (TODO)
|
||||
(define (yggdrasil-generate [constraints (make-hash)])
|
||||
; Fixed for now to test the rest
|
||||
(yggdrasil-hard-coded-generate
|
||||
'("################"
|
||||
"#.L.....+..<...#"
|
||||
"#.......#..#v#^#"
|
||||
"#Omhtc!?#7.>...#"
|
||||
"################")))
|
||||
|
||||
; Conversion from a hard-coded list of strings
|
||||
(define (yggdrasil-hard-coded-generate strlst)
|
||||
(define height (length strlst))
|
||||
(define width (string-length (car strlst)))
|
||||
(define charvec (string-join strlst ""))
|
||||
;
|
||||
(build-2d-array
|
||||
width
|
||||
height
|
||||
(lambda (i j)
|
||||
(character->yggdrasil-cell
|
||||
(string-ref charvec (+ i (* j width)))))))
|
|
@ -0,0 +1,101 @@
|
|||
#lang racket/base
|
||||
|
||||
(require
|
||||
racket/syntax)
|
||||
|
||||
; Cell of Yggdrasil generator
|
||||
(provide
|
||||
yggdrasil-cell-type
|
||||
yggdrasil-cell-feature
|
||||
; Accessors to premade cells
|
||||
get-yggdrasil-cell
|
||||
yggdrasil-cell-undefined
|
||||
; Conversion from/to characters, for hard-coded blocks of dungeon
|
||||
character->yggdrasil-cell
|
||||
yggdrasil-cell->character
|
||||
; Some features of the cells
|
||||
yggdrasil-cell-defined?
|
||||
yggdrasil-cell-blocker?
|
||||
)
|
||||
|
||||
; Structure
|
||||
(struct yggdrasil-cell
|
||||
(type ; Type of cell
|
||||
feature ; Feature of cell
|
||||
character ; Character representing the cell
|
||||
))
|
||||
|
||||
; Type of cell is among:
|
||||
; #f (not defined)
|
||||
; path
|
||||
; wall
|
||||
|
||||
; Feature of cell is among:
|
||||
; #f (no feature)
|
||||
; door
|
||||
; shortcut-EW
|
||||
; shortcut-WE
|
||||
; shortcut-NS
|
||||
; shortcut-SN
|
||||
; staircase-down
|
||||
; staircase-up
|
||||
; event
|
||||
; check
|
||||
; resource-mine
|
||||
; resource-take
|
||||
; resource-chop
|
||||
; resource-harvest
|
||||
; chest
|
||||
|
||||
; Collection of cells
|
||||
(define *yggdrasil-cells*
|
||||
(make-immutable-hash
|
||||
`((undefined . ,(yggdrasil-cell #f #f #\$))
|
||||
(wall . ,(yggdrasil-cell 'wall #f #\#))
|
||||
(path . ,(yggdrasil-cell 'path #f #\.))
|
||||
(staircase-down . ,(yggdrasil-cell 'path 'staircase-down #\L))
|
||||
(staircase-up . ,(yggdrasil-cell 'path 'staircase-up #\7))
|
||||
(shortcut-EW . ,(yggdrasil-cell 'wall 'shortcut-EW #\<))
|
||||
(shortcut-WE . ,(yggdrasil-cell 'wall 'shortcut-WE #\>))
|
||||
(shortcut-NS . ,(yggdrasil-cell 'wall 'shortcut-NS #\v))
|
||||
(shortcut-SN . ,(yggdrasil-cell 'wall 'shortcut-SN #\^))
|
||||
(door . ,(yggdrasil-cell 'wall 'door #\+))
|
||||
(event . ,(yggdrasil-cell 'path 'event #\!))
|
||||
(check . ,(yggdrasil-cell 'path 'check #\?))
|
||||
(chest . ,(yggdrasil-cell 'path 'chest #\O))
|
||||
(resource-mine . ,(yggdrasil-cell 'path 'resource-mine #\m))
|
||||
(resource-take . ,(yggdrasil-cell 'path 'resource-take #\t))
|
||||
(resource-chop . ,(yggdrasil-cell 'path 'resource-chop #\c))
|
||||
(resource-harvest . ,(yggdrasil-cell 'path 'resource-harvest #\h))
|
||||
)))
|
||||
; Characters to cells
|
||||
(define *char->cell*
|
||||
(make-immutable-hash
|
||||
(map
|
||||
(lambda (c)
|
||||
(cons
|
||||
(yggdrasil-cell-character c)
|
||||
c))
|
||||
(hash-values *yggdrasil-cells*))))
|
||||
|
||||
; Accessor to premade cells
|
||||
(define (get-yggdrasil-cell id)
|
||||
(hash-ref *yggdrasil-cells* id (yggdrasil-cell-undefined)))
|
||||
|
||||
(define (yggdrasil-cell-undefined)
|
||||
(hash-ref *yggdrasil-cells* 'undefined))
|
||||
|
||||
; Additional predicates
|
||||
; Indicate if a cell is defined
|
||||
(define (yggdrasil-cell-defined? cl)
|
||||
(not (not (yggdrasil-cell-type cl))))
|
||||
|
||||
; Indicate if a cell is blocking the path
|
||||
(define (yggdrasil-cell-blocker? cl)
|
||||
(eq? 'wall (yggdrasil-cell-type cl)))
|
||||
|
||||
; Conversion from/to characters
|
||||
(define (character->yggdrasil-cell chr)
|
||||
(hash-ref *char->cell* chr (yggdrasil-cell-undefined)))
|
||||
(define (yggdrasil-cell->character cl)
|
||||
(yggdrasil-cell-character cl))
|
|
@ -0,0 +1,120 @@
|
|||
#lang racket/base
|
||||
|
||||
; Renderer of a dungeon generated by Yggdrasil
|
||||
; A renderer is a function that takes a cell 2d-array and an output stream.
|
||||
;
|
||||
; Default renderer: outputs a PNG looking-like maps of Etrian Odyssey
|
||||
; Uses a tileset and a color to draw grid and walls.
|
||||
|
||||
(require
|
||||
"../../collection/2d-array.rkt"
|
||||
"cell.rkt"
|
||||
"../../graphics/color.rkt"
|
||||
"../../graphics/image.rkt"
|
||||
)
|
||||
|
||||
(provide
|
||||
make-tile-renderer)
|
||||
|
||||
; Tileset
|
||||
; From image path and tile size
|
||||
(define (make-tileset path size)
|
||||
; Function to define the tiles from their position
|
||||
; (the sprite bank allows sprites of aribtrary sizes, arbitrary positioned in the image)
|
||||
(define (resize lst)
|
||||
(map
|
||||
(lambda (x)
|
||||
(cons
|
||||
(car x)
|
||||
(append
|
||||
(map (lambda (n) (* size n)) (cdr x))
|
||||
(list size size))))
|
||||
lst))
|
||||
;
|
||||
(make-sprite-bank
|
||||
path
|
||||
(resize
|
||||
'((wall 0 0) (path 1 0) (staircase-down 2 0) (staircase-up 3 0)
|
||||
(shortcut-EW 0 1) (shortcut-WE 1 1) (shortcut-NS 2 1) (shortcut-SN 3 1)
|
||||
(event 0 2) (check 1 2) (chest 2 2) (door 3 2)
|
||||
(resource-chop 0 3) (resource-mine 1 3) (resource-take 2 3) (resource-harvest 3 3)))))
|
||||
|
||||
; Tile renderer structure
|
||||
(struct tile-renderer
|
||||
(tile-size
|
||||
tileset
|
||||
grid-color))
|
||||
|
||||
; Drawing function
|
||||
(define (draw-dungeon renderer dungeon output)
|
||||
(define pen-grid (make-pen (tile-renderer-grid-color renderer) 1))
|
||||
(define pen-wall (make-pen (tile-renderer-grid-color renderer) 3))
|
||||
(define cell-size (tile-renderer-tile-size renderer))
|
||||
(define image
|
||||
(make-image (* (2d-array-width dungeon) cell-size)
|
||||
(* (2d-array-height dungeon) cell-size)))
|
||||
; Draw cells by type: path or wall
|
||||
(2d-array-for-each/indexes
|
||||
dungeon
|
||||
(lambda (cell i j)
|
||||
(image-draw-sprite!
|
||||
image
|
||||
(* i cell-size)
|
||||
(* j cell-size)
|
||||
(tile-renderer-tileset renderer)
|
||||
(if (yggdrasil-cell-blocker? cell)
|
||||
'wall
|
||||
'path))))
|
||||
; Draw the grid
|
||||
(2d-array-for-each/indexes
|
||||
dungeon
|
||||
(lambda (cell i j)
|
||||
; separator between (i,j) and (i+1,j)
|
||||
(when (2d-array-inside? dungeon (+ i 1) j)
|
||||
(define next-cell (2d-array-ref dungeon (+ i 1) j))
|
||||
(image-draw-line!
|
||||
image
|
||||
(* (+ i 1) cell-size)
|
||||
(* j cell-size)
|
||||
(* (+ i 1) cell-size)
|
||||
(* (+ j 1) cell-size)
|
||||
(if (eq? (yggdrasil-cell-type cell) (yggdrasil-cell-type next-cell))
|
||||
pen-grid
|
||||
pen-wall)))
|
||||
; separator between (i,j) and (i,j+1)
|
||||
(when (2d-array-inside? dungeon i (+ j 1))
|
||||
(define next-cell (2d-array-ref dungeon i (+ j 1)))
|
||||
(image-draw-line!
|
||||
image
|
||||
(* i cell-size)
|
||||
(* (+ j 1) cell-size)
|
||||
(* (+ i 1) cell-size)
|
||||
(* (+ j 1) cell-size)
|
||||
(if (eq? (yggdrasil-cell-type cell) (yggdrasil-cell-type next-cell))
|
||||
pen-grid
|
||||
pen-wall)))
|
||||
))
|
||||
; Draw the features
|
||||
(2d-array-for-each/indexes
|
||||
dungeon
|
||||
(lambda (cell i j)
|
||||
(define feature (yggdrasil-cell-feature cell))
|
||||
(when feature
|
||||
(image-draw-sprite!
|
||||
image
|
||||
(* i cell-size)
|
||||
(* j cell-size)
|
||||
(tile-renderer-tileset renderer)
|
||||
feature))))
|
||||
; Save image
|
||||
(image-save image output))
|
||||
|
||||
;
|
||||
(define (make-tile-renderer tile-path tile-size grid-color)
|
||||
(define renderer
|
||||
(tile-renderer
|
||||
tile-size
|
||||
(make-tileset tile-path tile-size)
|
||||
grid-color))
|
||||
(lambda (dungeon output)
|
||||
(draw-dungeon renderer dungeon output)))
|
|
@ -0,0 +1,79 @@
|
|||
#lang racket/base
|
||||
|
||||
; Yggdrasil pages
|
||||
|
||||
(require
|
||||
racket/string
|
||||
"templates.rkt"
|
||||
"../webcontainer/weblets.rkt"
|
||||
"../generators/yggdrasil.rkt"
|
||||
"../generators/yggdrasil/tile-renderer.rkt"
|
||||
"../graphics/color.rkt")
|
||||
|
||||
(provide
|
||||
pages:yggdrasil
|
||||
pages:yggdrasil-raw-image
|
||||
pages:yggdrasil-about)
|
||||
|
||||
; Default renderer
|
||||
(define yggdrasil-default (make-tile-renderer "static/images/yggdrasil-default.png" 15 (named-color "black")))
|
||||
|
||||
; Raw page
|
||||
(define pages:yggdrasil-raw-image
|
||||
(raw-data-weblet
|
||||
#:content-type #"image/png"
|
||||
#:body
|
||||
(lambda (param)
|
||||
(define output-port (open-output-bytes))
|
||||
(yggdrasil-default
|
||||
(yggdrasil-generate param)
|
||||
output-port)
|
||||
(get-output-bytes output-port))))
|
||||
|
||||
; Yggdrasil page
|
||||
(define pages:yggdrasil
|
||||
(pages:template
|
||||
#:title "Yggdrasil Generator"
|
||||
#:author "feuforeve.fr"
|
||||
#:stylesheets '("/css/yggdrasil.css")
|
||||
#:content
|
||||
'(article
|
||||
(a ((href "/Yggdrasil")) "New level")
|
||||
(p
|
||||
(section ((style "display: inline-block;"))
|
||||
(img ((alt "Generated Maze") (src "/Yggdrasil/Raw"))))
|
||||
(section ((class "keys"))
|
||||
(h4 "Keys")
|
||||
(span ((class "yggdrasil-default")(id "wall"))) " Wall" (br)
|
||||
(span ((class "yggdrasil-default")(id "path"))) " Path" (br)
|
||||
(span ((class "yggdrasil-default")(id "staircase-down"))) " Staircase – Start point (go to previous level)" (br)
|
||||
(span ((class "yggdrasil-default")(id "staircase-up"))) " Staircase – End point (go to next level)" (br)
|
||||
(span ((class "yggdrasil-default")(id "door"))) " Door" (br)
|
||||
(span ((class "yggdrasil-default")(id "chest"))) " Chest" (br)
|
||||
(span ((class "yggdrasil-default")(id "event"))) " Event (immediate)" (br)
|
||||
(span ((class "yggdrasil-default")(id "check"))) " Event (must check)" (br)
|
||||
(span ((class "yggdrasil-default")(id "resource-chop"))) " Collect spot (Chop)" (br)
|
||||
(span ((class "yggdrasil-default")(id "resource-mine"))) " Collect spot (Mine)" (br)
|
||||
(span ((class "yggdrasil-default")(id "resource-take"))) " Collect spot (Take)" (br)
|
||||
(span ((class "yggdrasil-default")(id "resource-harvest"))) " Collect spot (Harvest)" (br)
|
||||
(span ((class "yggdrasil-default")(id "shortcut-EW"))) " Shortcut (east-west, unlocked from east)" (br)
|
||||
(span ((class "yggdrasil-default")(id "shortcut-WE"))) " Shortcut (east-west, unlocked from west)" (br)
|
||||
(span ((class "yggdrasil-default")(id "shortcut-NS"))) " Shortcut (north-south, unlocked from north)" (br)
|
||||
(span ((class "yggdrasil-default")(id "shortcut-SN"))) " Shortcut (north-south, unlocked from south)" (br)
|
||||
)))
|
||||
))
|
||||
|
||||
; Yggdrasil about page
|
||||
(define pages:yggdrasil-about
|
||||
(pages:template
|
||||
#:title "About the Yggdrasil generator"
|
||||
#:author "Feufochmar"
|
||||
#:date "2020-04-12"
|
||||
#:content
|
||||
'(article
|
||||
(p "This generator makes dungeons maps. "
|
||||
"By default, it displays them in the style of the game series " (a ((href "https://en.wikipedia.org/wiki/Etrian_Odyssey")) "Etrian Odyssey") ". " (br)
|
||||
"This generator is named after the giant tree Yggdrasil hosting the labyrinth in those games. " (br)
|
||||
"This generator was initially made for the " (a ((href "https://itch.io/jam/procjam2017/rate/193843")) "ProcJam 2017") ". " (br)
|
||||
))
|
||||
))
|
|
@ -0,0 +1,62 @@
|
|||
.keys {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.yggdrasil-default {
|
||||
width: 15;
|
||||
height: 15;
|
||||
background-image: url('/images/yggdrasil-default.png');
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#wall.yggdrasil-default {
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
#path.yggdrasil-default {
|
||||
background-position: -15px 0px;
|
||||
}
|
||||
#staircase-down.yggdrasil-default {
|
||||
background-position: -30px 0px;
|
||||
}
|
||||
#staircase-up.yggdrasil-default {
|
||||
background-position: -45px 0px;
|
||||
}
|
||||
#shortcut-EW.yggdrasil-default {
|
||||
background-position: 0px -15px;
|
||||
}
|
||||
#shortcut-WE.yggdrasil-default {
|
||||
background-position: -15px -15px;
|
||||
}
|
||||
#shortcut-NS.yggdrasil-default {
|
||||
background-position: -30px -15px;
|
||||
}
|
||||
#shortcut-SN.yggdrasil-default {
|
||||
background-position: -45px -15px;
|
||||
}
|
||||
#event.yggdrasil-default {
|
||||
background-position: 0px -30px;
|
||||
}
|
||||
#check.yggdrasil-default {
|
||||
background-position: -15px -30px;
|
||||
}
|
||||
#chest.yggdrasil-default {
|
||||
background-position: -30px -30px;
|
||||
}
|
||||
#door.yggdrasil-default {
|
||||
background-position: -45px -30px;
|
||||
}
|
||||
#resource-chop.yggdrasil-default {
|
||||
background-position: 0px -45px;
|
||||
}
|
||||
#resource-mine.yggdrasil-default {
|
||||
background-position: -15px -45px;
|
||||
}
|
||||
#resource-take.yggdrasil-default {
|
||||
background-position: -30px -45px;
|
||||
}
|
||||
#resource-harvest.yggdrasil-default {
|
||||
background-position: -45px -45px;
|
||||
}
|
Loading…
Reference in New Issue