1.0.14:
fixed some stray blocks

TODO:


a-04
a-03c
a-07
a-06

~260

* achievement for getting to chasm berry without 2dash
* achievement for getting skyfish berry without using the pufferfish

2.5 hours to thunderhead
1.5 hours to monolith

* a map that has multiple days where the map is slightly different each day
    * but they are all wednesday


distance = math.sqrt(345**2+r**2)

distances:
32 is a tight bubble around the player
120 fills a small pocket
240 fills a large area
320 fills a small room but not a large room
600 fills a large room

new
small = 0 - 60   -> 345 - 350
medium = 0 - 120 -> 345 - 365
large = 16 - 160 -> 345.5 - 380
vast = 16 - 320 -> 345.5 - 470

small   0-59
medium  0-119
large   19-159
vast    19-319
vaster  19-491

* maybe find something with a better ending for finalcave 1
    take the 3 parts of title7 and splace them at different sources
* also pick something for final room of final cave
  * trancquiescene

* tas route
* select music for:
  * powerups (3)
    dash: https://techtech.technology/en/audio/6/
    2dash: https://techtech.technology/en/audio/40/
    double jump: just the jingle (possible conflict with final cave)
  * final cave segments (4)
X    https://techtech.technology/en/audio/9/
    https://techtech.technology/en/audio/19/
    https://techtech.technology/en/audio/21/
    https://techtech.technology/en/audio/20/
    https://techtech.technology/en/audio/27/
    https://soundcloud.com/roots-of-unity/prom2test2
    https://soundcloud.com/roots-of-unity/tranquiescence
  * power off (1)
    https://soundcloud.com/roots-of-unity/crows
  * sw caves (1)
    https://techtech.technology/en/audio/23/

* achievements
 * lightning room special
    * d-04b_done
 * no jelly room
    * c_10_no_jelly
 * downclimb streamfall
    * streamfall_downclimb_complete
 * blue key without dash refill
 * get to the back of the 2dash room without getting 2dash
    * 2dash_backside
    * reach streamfall without getting any keys (and come back)
 * put fish back in water
    * fish_done
 * escape the self-destruct a different way
    * hero_achievement

* trigger/entity to activate extra sounds mode
    * sets save data enable, adds hooks
    * similar to self destruct but simpler
    * map sounds to various actions
    * mouth pop on doublejump super
    * click on doublejump

* music
    twm: song of the wanderer (helen humes, neil moret)
    streamfall: spleen
    stonerot: trembling giant
* sounds effects
* sound placement
  * trigger sounds on contact with ground or entities

Music:
Song of the wanderer
Spleen, https://soundcloud.com/roots-of-unity/prometheus2test1
https://soundcloud.com/roots-of-unity/vortex-flow-of-strength-k
trembling giant

It has been Wednesday for nearly four years now. Would you like to know why?

Map includes the following
* up to 110-ish rooms
* 20 wednesday berries
* -6 1 2- 7? birds
* 7 acheviements (might add more)
* -2 3 4 9 3- multiple -endings- end states
* 3 or more caves
* 1 jellyfish (don't let anything happen to it)
* 1 mandatory heart
* 1 optional heart
* 1 car
* beginner and intermediate routes
* some original audio
* some original assets
* some original code
* various small secrets

Influences:

* Descent
blue, yellow, and red area/keys
red zone decals
forcefields and the switch that disables them (and a wall) when you destroy it
badeline boss qua reactor, and the self-destruct sequence that follows

* Myst
blue, red, and white paper

* Chrono trigger
a black wind stirs
you jumped off this mortal coil

* Mondo Medicals
when you fight with a wednesday
you have to think like a star

everyone is the same on the insides
but bizarre on the outsides

* BEACON
A distant light | salvation?

* Immortal defense, runman: race around the world
song

* Cave story
you were never seen again
final cave

* the metroidvania genre
area intro cutscenes
backtracking
powerups

* the adventure game genre
if you don't see why then count yourself fortunate

* An Untitled Story
ending zone color scheme
fun fact about crts

* Flavors of pi
final cave mapping, how to intermediate tech spam

* star trek and the original series
guardian of forever, mod titles

* the northern caves
the southwestern caves

* polybius
everything is fine

* braid, [journalist name]
time stood still

* mondo medicals (cactus)
when you fight with a wednesday
you have to think like a star

everyone is the same on in the outsides
but bizarre on the insides

* do i even have to say it?
i told you dog, numbers

* tamer the friendly spambot
how care aout the graphic

* you have to complete the square (secondlawgames)
a 3-room pygame joke platformer drawn on graph paper. had secrets, a stupid math joke, and referenced current events in video games. spritual predecessor to this map.

* the myth of sisyphus
am i a cool kid now?

* mostly walking,sean plott
absurdist mantra this is the game
platformer pacing concepts that i was aware of and sometimes applied when i felt that a segment of gameplay should be less strenuous.

* celeste's biggest mod (patricia taxxon)
discussion of forms of difficulty and hazard usage that i did not necessarily apply but was aware of, because i also sometimes enjoy functionally scripted techspam gameplay where the hazards are just decoration.


Development Notes

[I am tired.]

No more. I'm done. All that's left is to go home, get my money, and sleep for the next two years.

This map was intended as a short demo/prototype to try out a way of translating some aspects of the metroidvania genre to Celeste. 

Software

Some of the scripts used in the development of this map are available in the github repo at https://github.com/wlaub/twoteof under the scripts directory. This includes lonn scripts written in lua, various utility scripts written in python, and some relevant input and output data.

I also used the game state recording mod at https://github.com/wlaub/tuw along with supporting python scripts to render and process gameplay paths while designing rooms. Later I found out about Aurora's Lonn Plugin (https://gamebanana.com/tools/12572), which is much more convenient and useful for player route visualization.

Cavegen

Sky Cave and The Southwestern Caves

The tiles in Sky Cave and The Southerwestern Caves were generated using a variation on an algorithm described by chevyray on tigsource in 2009 (https://forums.tigsource.com/index.php?topic=5174.0, https://web.archive.org/web/20090705003938/http://properundead.com/2009/03/cave-generator.html). It's a fast algorithm that generates aesthetically pleasing structures that are readily recognizable as representative of caves, but it also doesn't give a lot of control over the resulting structures.

The variation of the chevyray algorithm used in this map allows for some biasing of expansion probability based on direction and perhaps some other minor tweaks I forgot about. Source is available in the repo under scripts/chevycave.py.

The algorithm is fast enough that it's feasible to generate a large number of caves in order to select a small number of unlikely results containing a limited set of specific characteristics. For the purposes of this map, results were selected to join together smoothly and follow and overall left-moving path with some allowances for room-to-room directional variation. There was also a minor preference for more aesthetically pleasing results. Background tiles were added by hand according to vibes.

In the case of Sky Cave, hazards were added by hand semi-algorithmically to produce a particular aesthetic and impose some intentionality on the gameplay. Spinners were added to non-functional comf in order to spare the player the need to check every nook and cranny for secrets.

The Southwestern Caves are not meant to be explored, and so do nopt contain any additional gameplay elements beyond what the scripts generated. The foregrounds were generated in roughly the same way as Sky Cave, but were not as carefully curated. The backgrounds were hastily scribbled by hand. 

Final Cave

One of the most obvious ways of creating a cave generator is to just simulate the way caves form in nature - by gradually removing material from a substrate. There are lots of easy and simple ways of applying the concept to 2-dimensional cave generation. One option is to create a landscape with some randomly varying density, select a starting point, and then repeatedly roll to remove adjacent coordinates based on their density. You could also just reduce their density by random amounts (or even fixed amounts) on each timestep and then just remove any point that falls below 0 density.

An even simpler approach is to start with some set of initially open points, and randomly remove adjacent non-empty points for many timesteps. This causes the shape of the initial set of points (for example a rasterized set of thin lines and curves, perhaps the set of tiles occupied by a player in the course of traversing a room) to expand outward and form rough boundaries around a smooth shape vaguely like a cave. This is a vastly simpler model than actual cave formation and so doesn't really resemble a cave except abstractly as we recognize it's supposed to look like some natural enclosed structure. It is readily apparent that the simple synthetic cave is symbolic of a cave, though it may not be aesthetically satisfying.

The chevyray cavegen algorithm is fast and generates more satisfying caves than the simple erosion algorithm, but it can't be directed. The caves it generates follow random paths and so the qualities of the algorithm over-specify the gameplay. There is very little room for intentionality. You can curate these caves, but really evaluating the gameplay potential of a random room takes more time and effort than is reasonable given the low likelihood that the chevyray algorithm has of producing specific features.

The erosion model is extremely easy to implement, but it's also very slow and doesn't produce interesting features. If, instead of making erosion decisions at random, you instead made decisions by considering the surrounding geometry, then maybe you could guide the erosion process to produce some characteristic non-uniform features. For example, you might start by considering a rectangular grid around a point, multiply the on/off values (e.g. 0,1 or -1,1) of those points by a matching grid of weights, and sum the results to compute a probability of expanding. You may notice that this sort of thing is kind of like a very simple neural network, and so it stands to reason that you might be able to train a neural network to make erosion decisions and hope that it can make even better decisions.

The 15 rooms of Sky Cave, generated by the chevyray algorithm with light curation for shape and connectivity, were used to produce a training set where a network was asked to predict the on/off state of tiles given the states of surrounding tiles for every interior tile in the Sky Cave rooms. The trained model is then used to determine the probability of expansion of every tile adjacent to an open tile in an initial set constructed from gameplay recordings of the rooms in Final Cave. There was also metadata describing additional regions of tiles that must be open (e.g. room transitions) and must be solid (e.g. surfaces you touch).

A simple UI allows the erosion process to be run in real time (each step typically takes a perceptible duration), paused, and reversed. It usually takes around 500 steps for a room to get wide enough for the player to comfortably pass, but it's useful to be able to overshoot, backtrack, and try again from an earlier state to sort of tune features. To generate the background, you can just back up a few hundred steps and run again for fewer steps so that you get something similar to, but not concentric to, the boundary of the foreground. You might also fill in some regions where you want to direct the player's attention or indicate a rough positioning so that the background has bridges and lumps that can make it look nicer and communicate routing.

It's not immediately clear that the neural network does anything. Several training attempts yielded networks that would just always expand in one or more directions, and I think there are several problems with the model and the way it's used. I've tried comparing the model to random chance on the same initial conditions, and it seems kind of like the model is better at preserving long thin branching shapes than random chance, but it's subtle, and uniform random chance gives more heterogeneous results than I would expect.

The end result looks good enough to me, though.

I had somewhat more success training a model to predict a single point's value given surrounding points (the original erosion model tries to predict the 4 points around a point for historical reasons), though it's still often wrong about boundary points, which is kind of where it needs to be right. I haven't tried running an erosion model with it. I need to be done with this map, and what I've got gets the job done. It might also be interesting to allow points to un-erode. Basically just have the model predict the state of every boundary point over and over again and hope that it expands into something like the training sets. It might be the case that since it is relatively good at predicting interior and exterior points, that once it starts getting into a vaguely correct shape, the boundary will sort of stabilize in that it will stop expanding or contracting while the exact details shift continuously. In that case, it might still produce some key characteristics of the training set as long as exact boundary shape isn't critical.

Also the training set was randomly generated. There may have been no clear patterns for it to glean, at least in the 15-room training set. It is sort of unreasonable to expect it to work very well at all. I can tell that the chevyray caves have characteristic features, but it's not easy to describe them from what I've seen, and I'm not even really qualified to tell whether a cave is plausibly from chevyray cavegen. I don't have a good way to judge whether it's working, and there's no reason the forward-only random erosion model should be good at producing specific shapes.

The quest for the perfect cavegen algorithm is as endless as it is pointless, but it's fun to try. The struggle itself etc. I am an absurd hero now.


Software Used

wine
Celeste
Lonn
Celeste Studio
Olympus
FMOD Studio
Audacity
GIMP
Firefox
Chrome
Vim
Python 3
tmux
git-bash
git
gnome-terminal
notepad
windows explorer
7-zip
Nautilus
Microsoft Windows
Ubuntu Linux
xmonad
KiCAD 5
Arduino IDE
SSH
dotnet
ps, kill, pgrep, pkill
grep


This map contains a number of quotes from other works (spoilers for many small secrets).

From Mondo Medicals by Cactus:
"EVERYONE IS THE SAME ON THE OUTSIDES
BUT BIZARRE ON THE INSIDES"
"WHEN YOU FIGHT WITH A CANCER
YOU HAVE TO THINK LIKE A STAR"

From Descent by Parallax Software:
"Self destruct sequence activated"
"Self destruct in t-minus 10 9 8 7 6 5 4 3 2 1 0"

From Chrono Trigger by Square:
"But you're still hungry..."
"You jumped off this mortal coil" is based on "Supid frog! It's time you jumped off this mortal coil!"
"A black wind stirs" is a based on "the black wind howls" (with a taste of Cave Story)

From Cave Story by Studio Pixel:
"You were never seen again."

From BEACON by ChevyRay Johnston and Maddie Thorson:
Not a direct quote, but "A DISTANT LIGHT | SALVATION?" is based on "A SHARP PAIN | BLOOD?" and the other death quotes from the game.

From the soundtrack for An Untitled Story by Maddie Thorson:
"God was inside us all along."

From journalist William Laurence (by way of braid):
"On that moment hung enterity. Time stood still."

From Mostly Walking by Sean Plott, Leigh Graner, and Sean Bouchard:
The absurdist mantra "this is the game."

From Sweet Bro and Hella Jeff by Andrew Hussie:
"I warned you dog"

From The Northern Caves by nostalgebraist:
"Don't go into the caves"

From Detective Pony by sonnetstuck:
"<X> is a pharmakon."

From Polybius:
"everything is fine."

From TAMER the friendly spam bot:
"how care aout the graphic"

From The Other Guys (2010) (by way of meme):
"You thinking what I'm thinking?"
"Aim for the bushes."
"There goes my hero."

From everyone's dad:
"Shade!"



