(* please add your name/handle to the credits section here:
- velartrill
- riking27
also see grammar at line 79 for further editing opportunities
*)
let adjs = [| "gleeful"; "putrescent"; "whimsical"; "looming"; "endless"; "infinite"; "final"; "lustful";
"twilight"; "black"; "lunar"; "solar"; "whispering"; "sundered"; "lawless"; "threefold"; "sevenfold";
"tenfold"; "manifest"; "heavenly"; "somber"; "shadowed"; "wandering"; "distant"; "vengeful";
"fearful"; "mighty"; "shrieking"; "lofty"; "loathesome"; "faceless"; "silent"; "pale"; "crimson";
"fiery"; "wondrous"; "spiteful"; "weary"; "hateful"; "forsaken"; "forbidden"; "mellifluous";
"abyssal"; "innocent"; "bronzed"; "fine"; "poor"; "masterful"; "forgotten"; "lost"; "infernal";
"merciful"; "merciless"; "reckless"; "wonderful"; "beloved"; "ancient"; "decrepit"; "abstract";
"honorable"; "animated"; "bloody"; "dead"; "old"; "expired"; "new"; "fresh"; |]
let nouns = [| "orb"; "law"; "moon"; "night"; "fist"; "question"; "deceit"; "perception"; "regret";
"wonder"; "terror"; "hope"; "lust"; "inception"; "manifestation"; "whole"; "sea"; "stone"; "earth";
"door"; "gate"; "portal"; "tree"; "fear"; "might"; "egret"; "circle"; "pit"; "crevice"; "hand"; "face";
"inferno"; "spite"; "loom"; "malice"; "vial"; |]
let forces = [| "prince"; "king"; "queen"; "archon"; "god"; "demon"; "lord"; "lady"; "thing"; "wind";
"beast"; "terror"; "spirit"; "spirits"; "muse"; "sylph"; "fool"; "child"; "creature"; "drake"; |]
let kinds = [| "rite"; "ritual"; "spell"; "invocation"; "evocation"; "conjuration"; "abjuration"; "binding";
"incantation"; "appeasement"; "craft"; "alchemy"; "transmutation"; "transmogrification"; "incitement";
"debasement"; "blessing"; "consecrecation"; "desecration"; |]
(* two of these are combined to form a surname *)
let people_name_elts = [| "wind"; "horn"; "fear"; "sea"; "sun"; "sky"; "star"; "hand"; "cold"; "warm"; "sand";
"soul"; "sin"; "pale"; "dark"; "dread"; "hammer"; "lust"; "rage"; "blood"; "fire"; "flame"; "over"; "blight";
"thunder"; "time"; "space"; "void"; "light"; "mind"; "life"; "air"; "breath"; "heir"; "doom"; "stein"; "chill";
"cool"; "love"; "just"; "drake"; "hell"; "war"; "wright"; "bone"; |]
(* these precede surnames *)
let forenames = [| "abigail"; "mordred"; "morgan"; "samantha"; "rachael"; "cassandra"; "jedediah"; "zebediah";
"malachi"; "malachiah"; "charles"; "jezebel"; "simon"; "simone"; "salamandrael"; "jehosaphat"; "josiah";
"mandrake"; "jessifer"; "sophia"; "morgause"; "winfred"; "winnifred"; "jennifer"; "carlissa"; "carlotta";
"carissa"; "melissa"; "xylinda"; "samedra"; "damara"; "kurloz"; "hans"; "vladimir"; |]
(* titles prefix a name, i.e. Sir Abigail Lusthammer *)
let titles = [| "sir"; "king"; "lord"; "queen"; "empress"; "dame"; "madam"; "mistress"; "master"; "lady";
"emperor"; "archmage"; "magister"; "archmagister"; "magistress"; "magistrix"; "archmagistress";
"archmagistrix"; "knight"; "agent"; |]
type node = R of string array | B of node array | OL of node list | O of node | L of node list | S of string
let pick a = a.(Random.int(Array.length a))
let range min max = min+(Random.int(max-min))
let rec eval n : string = match n with
| R(n) -> pick n
| OL(n) -> eval (O(L n))
| B(n) -> eval (pick n)
| O(n) -> if range 0 2 = 0 then eval n else ""
| L(n) -> List.fold_left (fun a b -> a ^ (eval b)) "" n
| S(s) -> s
let people = L [ R people_name_elts; R people_name_elts; ]
let force = L [R adjs; S " "; R forces]
let attrib = L[OL[R titles; S" "]; OL[R forenames; S" "]; people; OL[S" the "; R adjs;];S"'s ";]
let ritual_name = B [|
L [O attrib; OL[R adjs; S " "]; R kinds; S " of "; O(S "the "); OL[force; S "'s "]; OL[R adjs; S " "]; R nouns; ];
L [attrib; OL[R adjs; S " "]; R nouns; ]
|]
let agents = [| "a child"; "a bird"; "an eagle"; "a thief"; "a king"; "a conqueror"; "a fool"; "a madman";
"an innocent"; "a murderer"; "a virgin"; "a queen"; "a pauper"; "a fox"; "a girl"; "a boy";
"a dying man"; "a drake"; "a beast"; "a spirit"; "a sylph"; "a seer"; "the wind"; |]
let liquids = B [| S "blood"; S "ale"; S "wine"; S "water"; S"sea-water"; S"river-water"; S"lake-water"; L[S "the blood of "; R agents]; |]
let liquid_containers = [| "chalice"; "ewer"; "goblet"; "bowl"; "waterskin"; "bottle"; "cask"; |]
let object_containers = [| "bowl"; "box"; "basket"; "chest"; |]
let surfaces = [| "plinth"; "platter"; "altar"; "plate"; |]
let objects = [| "stone"; "feather"; "orb"; "quill"; "knife"; "candle"; "bow"; "bullet";
"necklace"; "charm"; "amulet"; "biscuit"; |]
let materials = [| "crystal"; "bone"; "iron"; "steel"; "copper"; "gold"; "silver"; "sapphire"; "opal";
"jade"; "amethyst"; "quartz"; "diamond"; "emerald"; "tin"; "zinc"; "bismuth"; "sterling"; "bronze"; "blood"; |]
(* [optional[partorigin], bodyparts] *)
let bodyparts = [| "skull"; "femur"; "blood"; "tooth"; "toe"; "eye"; "eyeball"; "skin"; "hand"; "fingernail";
"claw"; "toenail"; "tail"; "vertebra"; "backbone"; "heart"; "liver"; "spleen"; "womb"; "fetus"; "fin"; |]
let partorigin = [| "human"; "virgin"; "cow"; "dog"; "horse"; "beast"; "wolf"; "alligator"; "goat"; "bird";
"crow"; "eagle"; "dove"; "pigeon"; "owl"; "elephant"; "bear"; "fox"; "buzzard";
(* posessives *)
"a beloved pet's"; "an innocent's"; "the target's"; "your"; "your"; "an intruder's"; |]
type thingkind = Liquid_container | Object_container | Surface | Object
type thing = {
kind : thingkind;
name : string;
adj : string option;
desc : string option;
}
let times = R[| "once"; "twice"; "thrice"; |]
let places = [| "in a dreadful ravine"; "in a forsaken village"; "at the bottom of the sea"; "on the moon";
"in a grave"; "in a mausoleum"; "beneath a tree"; "where it should not have been"; "in the sea";
"in a dwelling"; "in a forest"; |]
let desc =
(* kinds *) B[|
(* actions *) L[ B[|
L[S"found";
OL[S" "; R places];
OL[S" by ";
R(Array.concat [agents; [|"one who should not have found it"; |]])];
];
L[S"lost";
OL[S" ";
R(Array.concat [places;[|"to the sea";|]])];
OL[S" by ";
R(Array.concat [agents; [|"one who should not have lost it"; |]])];
];
L[S "stolen";
OL[S" by ";
R(Array.concat [agents; [|"one who should not have stolen it"; |]])];
OL[S" from ";
R(Array.concat [agents; [|"one who should not have lost it";"one who should not have stolen it";
"one who should never have held it"; "its rightful owner"; "a vault"; "a castle"; "a beast"; |]])];
];
L[S "washed";
OL[S" "; R[|
"in the sea"; "in blood"; "beneath a waterfall"; "in a fountain"; "in a lake long-dry";
"in tears"; "in tears of grief"; "in tears of joy";|]];
OL[S" by ";
R(Array.concat [agents; [|"an elderly washerwoman"; |]])];
];
|];
(* circumstances *) O(B[|
S" at night";
S" by chance";
S" long ago";
S" years ago";
S" in the distant past";
S" at noon";
S" at dawn";
S" in war";
S" at war";
S" for years";
S" by accident";
|]);
];
(* traits *) B[|
L[times; S"-blessed"];
L[times; S"-cursed"];
S "black as night";
S "red as blood";
S "white as bone";
S "blue as the sky";
S "green as grass";
S "bright as gold";
S "old as time";
|];
|]
let adj_material = L[ O(OL[R adjs; S" "]); OL[R materials; S" "]; ]
let newthing () : thing = let kind = pick [|Liquid_container; Object_container; Surface; Object;|] in {
kind = kind;
adj = pick[|None; Some(pick adjs)|];
desc = pick[|None; Some(eval desc)|];
name = match kind with
| Liquid_container -> eval (L[adj_material; R liquid_containers])
| Object_container -> eval (L[adj_material; R object_containers])
| Surface -> eval (L[adj_material; R surfaces])
| Object -> eval (B[|
L[adj_material; R objects];
L[OL[R partorigin; S" "]; R bodyparts;]
|])}
let descthing t = (match t.adj with Some(s) -> s^" " | None -> "")^
(*(String.uppercase_ascii()*) t.name^
(match t.desc with Some(s) -> ", "^s | None -> "")
let ritual () =
let name = eval ritual_name in
let foci =
let rec acc (times : int) : thing list = (newthing ()) :: (if times = 0 then [] else acc (times-1))
in acc (range 0 10)
in
(String.uppercase_ascii(name))^"\n\n"^
(pick [|"You will need:"; "Components:"; "Foci:"; "Ingredients:"; "Elements:"; "Materials:";
"You must gather:"; "Necessary offerings:"|]) ^"\n"^
(let rec enumerate_foci n f = match f with
| x :: rs -> ((string_of_int n) ^ ") " ^ (descthing x) ^ "\n") ^ (enumerate_foci (n+1) rs)
| [] -> "" in enumerate_foci 1 foci)
let () = Random.self_init (); print_string (ritual ());;