WOLF GAME
xax
<<display "init">>\n\n(these aren't hooked together and don't get saved)\n* [[character creation]]\n* [[dialog|top-level question prompt]]\n* [[map]]
<<set $pc to\n { eye: either ("brown", "blue", "black", "hazel")\n , eyefeat: "none"\n , haircolor: either ("black", "brown", "blond", "ginger")\n , hair: "military cut"\n , facialhair: "none"\n , bodyhair: "minimal"\n , skin: either ("pale, freckled", "pale", "tanned", "light-skinned", "dark-skinned")\n , scars: "none"\n , tattoos: "none"\n }>>\\n<<set $ccdisplay to null>>\\neye color: <<block pceye>><<print $pc.eye>> <<block customize>><<if $ccdisplay !== "eye">>\\n<<click "⭷">><<set $ccdisplay to "eye"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.eye "pceye" "brown" "brown">>\n<<toggle $pc.eye "pceye" "blue" "blue">>\n<<toggle $pc.eye "pceye" "green" "green">>\n<<toggle $pc.eye "pceye" "hazel" "hazel">>\n<<toggle $pc.eye "pceye" "red" "red">>\n<<toggle $pc.eye "pceye" "gleaming red-green" "gleaming red-green">>\n<<endif>><<endblock>><<endblock>>\neye features: <<block pceyefeat>><<print $pc.eyefeat>> <<block customize>><<if $ccdisplay !== "eyefeat">>\\n<<click "⭷">><<set $ccdisplay to "eyefeat"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.eyefeat "pceyefeat" "none" "none">>\n<<toggle $pc.eyefeat "pceyefeat" "eyepatch (left)" "eyepatch (left)">>\n<<toggle $pc.eyefeat "pceyefeat" "glasses" "glasses">>\n<<toggle $pc.eyefeat "pceyefeat" "bandage-wrapped" "bandage-wrapped">>\n<<endif>><<endblock>><<endblock>>\nhair color: <<block pchaircolor>><<print $pc.haircolor>> <<block customize>><<if $ccdisplay !== "haircolor">>\\n<<click "⭷">><<set $ccdisplay to "haircolor"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.haircolor "pchaircolor" "black" "black">>\n<<toggle $pc.haircolor "pchaircolor" "brown" "brown">>\n<<toggle $pc.haircolor "pchaircolor" "blond" "blond">>\n<<toggle $pc.haircolor "pchaircolor" "ginger" "ginger">>\n<<toggle $pc.haircolor "pchaircolor" "grey" "grey">>\n<<endif>><<endblock>><<endblock>>\nhair style: <<block pchair>><<print $pc.hair>> <<block customize>><<if $ccdisplay !== "hair">>\\n<<click "⭷">><<set $ccdisplay to "hair"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.hair "pchair" "bald" "bald">>\n<<toggle $pc.hair "pchair" "shaved to stubble" "shaved to stubble">>\n<<toggle $pc.hair "pchair" "widow's peak" "widow's peak">>\n<<toggle $pc.hair "pchair" "military cut" "military cut">>\n<<toggle $pc.hair "pchair" "shaggy curls" "shaggy curls">>\n<<toggle $pc.hair "pchair" "mid-length ponytail" "mid-length ponytail">>\n<<toggle $pc.hair "pchair" "long braid" "long braid">>\n<<toggle $pc.hair "pchair" "bowl cut" "bowl cut">>\n<<toggle $pc.hair "pchair" "pulled-back small braids" "pulled-back small braids">>\n<<toggle $pc.hair "pchair" "dreadlocks" "dreadlocks">>\n<<endif>><<endblock>><<endblock>>\nfacial hair: <<block pcfacialhair>><<print $pc.facialhair>> <<block customize>><<if $ccdisplay !== "facialhair">>\\n<<click "⭷">><<set $ccdisplay to "facialhair"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.facialhair "pcfacialhair" "none" "none">>\n<<toggle $pc.facialhair "pcfacialhair" "stubble" "stubble">>\n<<toggle $pc.facialhair "pcfacialhair" "mustache" "mustache">>\n<<toggle $pc.facialhair "pcfacialhair" "goatee" "goatee">>\n<<toggle $pc.facialhair "pcfacialhair" "chinstrap" "chinstrap">>\n<<toggle $pc.facialhair "pcfacialhair" "full beard" "full beard">>\n<<endif>><<endblock>><<endblock>>\nbody hair: <<block pcbodyhair>><<print $pc.bodyhair>> <<block customize>><<if $ccdisplay !== "bodyhair">>\\n<<click "⭷">><<set $ccdisplay to "bodyhair"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.bodyhair "pcbodyhair" "shaved" "shaved">>\n<<toggle $pc.bodyhair "pcbodyhair" "minimal" "minimal">>\n<<toggle $pc.bodyhair "pcbodyhair" "hairy chest" "hairy chest">>\n<<toggle $pc.bodyhair "pcbodyhair" "hairy forearms & calves" "hairy forearms & calves">>\n<<toggle $pc.bodyhair "pcbodyhair" "coarsely-haired" "coarsely-haired">>\n<<endif>><<endblock>><<endblock>>\nskin color: <<block pcskin>><<print $pc.skin>> <<block customize>><<if $ccdisplay !== "skin">>\\n<<click "⭷">><<set $ccdisplay to "skin"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.skin "pcskin" "pale, freckled" "pale, freckled">>\n<<toggle $pc.skin "pcskin" "pale" "pale">>\n<<toggle $pc.skin "pcskin" "tanned" "tanned">>\n<<toggle $pc.skin "pcskin" "light-skinned" "light-skinned">>\n<<toggle $pc.skin "pcskin" "dark-skinned" "dark-skinned">>\n<<endif>><<endblock>><<endblock>>\nscars: <<block pcscars>><<print $pc.scars>> <<block customize>><<if $ccdisplay !== "scars">>\\n<<click "⭷">><<set $ccdisplay to "scars"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.scars "pcscars" "none" "none">>\n<<toggle $pc.scars "pcscars" "fang marks; across neck and chest" "fang marks; across neck and chest">>\n<<toggle $pc.scars "pcscars" "claw marks; across ribs" "claw marks; across ribs">>\n<<toggle $pc.scars "pcscars" "burns; flecks across left side of body" "burns; flecks across left side of body">>\n<<toggle $pc.scars "pcscars" "cuts; across back of hands and both forearms" "cuts; across back of hands and both forearms">>\n<<toggle $pc.scars "pcscars" "cuts; across ribs and side" "cuts; across ribs and side">>\n<<toggle $pc.scars "pcscars" "cratered bullet mark; right side of stomach and back" "cratered bullet mark; right side of stomach and back">>\n<<toggle $pc.scars "pcscars" "cratered bullet mark; left shoulder" "cratered bullet mark; left shoulder">>\n<<toggle $pc.scars "pcscars" "buckshot mark; chest and right shoulder" "buckshot mark; chest and right shoulder">>\n<<toggle $pc.scars "pcscars" "facial scar; over cheek and through eyebrow" "facial scar; over cheek and through eyebrow">>\n<<toggle $pc.scars "pcscars" "facial scar; across bridge of nose" "facial scar; across bridge of nose">>\n<<toggle $pc.scars "pcscars" "facial scar; notched left ear" "facial scar; notched left ear">>\n<<toggle $pc.scars "pcscars" "prisoner brand; left deltoid" "prisoner brand; left deltoid">>\n<<endif>><<endblock>><<endblock>>\ntattoos: <<block pctattoos>><<print $pc.tattoos>> <<block customize>><<if $ccdisplay !== "tattoos">>\\n<<click "⭷">><<set $ccdisplay to "tattoos"; reshow ("customize")>><<endclick>>\\n<<else>><<click "⭸">><<set $ccdisplay to null; reshow ("customize")>><<endclick>>\n<<toggle $pc.tattoos "pctattoos" "none" "none">>\n<<toggle $pc.tattoos "pctattoos" "disordered mess of sailor tattoos covering most of both arms, chest, and back" "disordered mess of sailor tattoos covering most of both arms, chest, and back">>\n<<toggle $pc.tattoos "pctattoos" "knuckle tattoos; lettering in coils up wrists and forearms" "knuckle tattoos; lettering in coils up wrists and forearms">>\n<<toggle $pc.tattoos "pctattoos" "deer skull and antlers surrounded by thorn vines; chest piece" "deer skull and antlers surrounded by thorn vines; chest piece">>\n<<toggle $pc.tattoos "pctattoos" "ornate lemniscate double-barred cross across back from lower neck to waist" "ornate lemniscate double-barred cross across back from lower neck to waist">>\n<<toggle $pc.tattoos "pctattoos" "sharp-angled geometric knotwork in rings around both biceps" "sharp-angled geometric knotwork in rings around both biceps">>\n<<toggle $pc.tattoos "pctattoos" "zig-zagging lines down spine" "zig-zagging lines down spine">>\n<<toggle $pc.tattoos "pctattoos" "symmetrical curving lines and dots across hips and thighs" "symmetrical curving lines and dots across hips and thighs">>\n<<toggle $pc.tattoos "pctattoos" "dots and lines across eyebrows, cheeks, jawline" "dots and lines across eyebrows, cheeks, jawline">>\n<<toggle $pc.tattoos "pctattoos" "palms and soles of feet inked solid black" "palms and soles of feet inked solid black">>\n<<endif>><<endblock>><<endblock>>\n\n[[→|Start]]
<<set $_pos to Math.floor (Math.random () * mapData.length)>>\n(click & drag to rotate)\n<<citymap $_pos>>\n[[↺|map]]\n\n[[←|Start]]
function Point2d (x, y) {\n this.x = x;\n this.y = y;\n}\nPoint2d.prototype.minus = function (pt) {\n return new Point2d (this.x - pt.x, this.y - pt.y);\n}\n\nfunction Point3d (x, y, z) {\n this.x = x;\n this.y = y;\n this.z = z;\n}\nPoint3d.prototype.plus = function (pt) {\n return new Point3d (pt.x + this.x, pt.y + this.y, pt.z + this.z);\n}\nPoint3d.prototype.timesScalar = function (s) {\n return new Point3d (this.x * s, this.y * s, this.z * s);\n}\nPoint3d.prototype.rotateY = function (rad) {\n return new Point3d\n ( this.x * Math.cos (rad) + this.z * Math.sin (rad)\n , this.y\n ,-this.x * Math.sin (rad) + this.z * Math.cos (rad)\n );\n}\nfunction Matrix44 (vs) {\n var i = 0;\n this.vs =\n [ 1, 0, 0, 0\n , 0, 1, 0, 0\n , 0, 0, 1, 0\n , 0, 0, 0, 1\n ];\n if (vs) {\n for (i = 0; i < 16; i++) {\n this.vs[i] = vs[i];\n }\n }\n}\nMatrix44.prototype.scale = function (s) {\n [0,1,2,4,5,6,8,9,10].map (i => this.vs[i] *= s);\n return this;\n};\nMatrix44.prototype.rotateX = function (rad) {\n this.vs[ 5] = Math.cos (rad);\n this.vs[ 6] = -Math.sin (rad);\n this.vs[ 9] = Math.sin (rad);\n this.vs[10] = Math.cos (rad);\n return this;\n};\nMatrix44.prototype.rotateY = function (rad) {\n this.vs[ 0] = Math.cos (rad);\n this.vs[ 2] = -Math.sin (rad);\n this.vs[ 8] = Math.sin (rad);\n this.vs[10] = Math.cos (rad);\n return this;\n};\nMatrix44.prototype.rotateZ = function (rad) {\n this.vs[ 0] = Math.cos (rad);\n this.vs[ 1] = -Math.sin (rad);\n this.vs[ 4] = Math.sin (rad);\n this.vs[ 5] = Math.cos (rad);\n return this;\n};\nMatrix44.prototype.multiplyVector = function (vec3) {\n var x\n = this.vs[0] * vec3.x\n + this.vs[1] * vec3.y\n + this.vs[2] * vec3.z\n + this.vs[3] * 0;\n var y\n = this.vs[4] * vec3.x\n + this.vs[5] * vec3.y\n + this.vs[6] * vec3.z\n + this.vs[7] * 0;\n var z\n = this.vs[8] * vec3.x\n + this.vs[9] * vec3.y\n + this.vs[10] * vec3.z\n + this.vs[11] * 0;\n return new Point3d (x, y, z);\n};\nMatrix44.prototype.tvec3 = Matrix44.prototype.multiplyVector;\n\n\nfunction identity () {\n return new Matrix44 (\n [ 1, 0, 0, 0\n , 0, 1, 0, 0\n , 0, 0, 1, 0\n , 0, 0, 0, 1\n ]);\n}\nfunction rotationX (rad) {\n return identity().rotateX(rad);\n}\nfunction rotationY (rad) {\n return identity().rotateY(rad);\n}\nfunction rotationZ (rad) {\n return identity().rotateZ(rad);\n}\nfunction euler (x, y, z) {\n let a = Math.cos (x);\n let b = Math.sin (x);\n let c = Math.cos (y);\n let d = Math.sin (y);\n let e = Math.cos (z);\n let f = Math.sin (z);\n return new Matrix44 (\n [ c * e, -c * f, -d, 0\n , -b * d * e + a * f, b * d * f + a * e, -b * c, 0\n , a * d * e + b * f, -a * d * f + b * e, a * c, 0\n , 0, 0, 0, 1\n ]);\n};\n\nfunction RoomBox (offset, floor, outlines) {\n this.offset = offset;\n this.floor = floor;\n this.outlines = outlines;\n}\nRoomBox.prototype.rotate = function (rad) {\n this.floor = this.floor.map (pt => pt.rotateY (rad));\n this.outlines = this.outlines.map (loop => loop.map (pt => pt.rotateY (rad)));\n return this;\n}\nRoomBox.prototype.floorPath = function (camera) {\n let raws = this.floor\n .map (pt => camera.tvec3 (pt.plus (this.offset)))\n .map ((pt, i) => (i == 1 ? "L " : "") + pt.x + "," + pt.z)\n .reduce ((a, b) => a + " " + b);\n return "M " + raws + " Z";\n}\nRoomBox.prototype.outlinesPath = function (camera) {\n return this.outlines\n .map (line => {\n let o = "";\n o = line\n .map (pt => camera.tvec3 (pt.plus (this.offset)))\n .map ((pt, i) => (i == 1 ? "L " : "") + pt.x + "," + pt.z)\n .reduce ((a, b) => a + " " + b);\n if (line.length > 2) {\n return "M " + o + " Z";\n } else {\n return "M " + o;\n }\n }).reduce ((a, b) => a + " " + b);\n}\n\nwindow.cube = function (offset) {\n return new RoomBox\n ( offset\n , [ new Point3d ( 0.45, 0, 0.45)\n , new Point3d ( 0.45, 0,-0.45)\n , new Point3d (-0.45, 0,-0.45)\n , new Point3d (-0.45, 0, 0.45)\n ]\n ,/* invert the y axis b/c this is svg where +y is further down */\n [ [ new Point3d ( 0.45,-0.90, 0.45)\n , new Point3d ( 0.45,-0.90,-0.45)\n , new Point3d (-0.45,-0.90,-0.45)\n , new Point3d (-0.45,-0.90, 0.45)\n ]\n , [ new Point3d (0.45, 0 , 0.45)\n , new Point3d (0.45,-0.90, 0.45)\n ]\n , [ new Point3d (0.45, 0 , -0.45)\n , new Point3d (0.45,-0.90, -0.45)\n ]\n , [ new Point3d (-0.45, 0 , -0.45)\n , new Point3d (-0.45,-0.90, -0.45)\n ]\n , [ new Point3d (-0.45, 0 , 0.45)\n , new Point3d (-0.45,-0.90, 0.45)\n ]\n ]\n );\n};\nwindow.hall = function (offset, dim) {\n let xDim = dim === "X" ? 0.45 : 0.20;\n let zDim = dim === "Z" ? 0.45 : 0.20;\n let h = -0.40;\n return new RoomBox\n ( offset\n , [ new Point3d ( xDim, 0, zDim)\n , new Point3d ( xDim, 0,-zDim)\n , new Point3d (-xDim, 0,-zDim)\n , new Point3d (-xDim, 0, zDim)\n ]\n ,\n [ [ new Point3d ( xDim, h, zDim)\n , new Point3d ( xDim, h,-zDim)\n , new Point3d (-xDim, h,-zDim)\n , new Point3d (-xDim, h, zDim)\n ]\n , [ new Point3d (xDim, 0, zDim)\n , new Point3d (xDim, h, zDim)\n ]\n , [ new Point3d (xDim, 0, -zDim)\n , new Point3d (xDim, h, -zDim)\n ]\n , [ new Point3d (-xDim, 0, -zDim)\n , new Point3d (-xDim, h, -zDim)\n ]\n , [ new Point3d (-xDim, 0, zDim)\n , new Point3d (-xDim, h, zDim)\n ]\n ]\n );\n};\nwindow.stairs = function (offset, dim, slope) {\n let xDim = dim === "X" ? 0.45 : 0.20;\n let zDim = dim === "Z" ? 0.45 : 0.20;\n let xHeight = dim === "X" ? -slope : 0;\n let zHeight = dim === "Z" ? -slope : 0;\n let h = -0.40;\n return new RoomBox\n ( offset\n , [ new Point3d ( xDim, 0, zDim)\n , new Point3d ( xDim, zHeight,-zDim)\n , new Point3d (-xDim, xHeight + zHeight,-zDim)\n , new Point3d (-xDim, xHeight , zDim)\n ]\n ,\n [ [ new Point3d ( xDim, h , zDim)\n , new Point3d ( xDim, h + zHeight ,-zDim)\n , new Point3d (-xDim, h + xHeight + zHeight,-zDim)\n , new Point3d (-xDim, h + xHeight , zDim)\n ]\n , [ new Point3d (xDim, 0, zDim)\n , new Point3d (xDim, h, zDim)\n ]\n , [ new Point3d (xDim, zHeight, -zDim)\n , new Point3d (xDim, h + zHeight, -zDim)\n ]\n , [ new Point3d (-xDim, xHeight + zHeight, -zDim)\n , new Point3d (-xDim, h + xHeight + zHeight, -zDim)\n ]\n , [ new Point3d (-xDim, xHeight, zDim)\n , new Point3d (-xDim, h + xHeight, zDim)\n ]\n ]\n );\n};\nwindow.crossing = function (offset) {\n let h = -0.40;\n return new RoomBox\n ( offset\n , [ new Point3d ( 0.20, 0, 0.20) /* c */\n , new Point3d ( 0.45, 0, 0.20)\n , new Point3d ( 0.45, 0,-0.20)\n , new Point3d ( 0.20, 0,-0.20) /* c */\n , new Point3d ( 0.20, 0,-0.45)\n , new Point3d (-0.20, 0,-0.45)\n , new Point3d (-0.20, 0,-0.20) /* c */\n , new Point3d (-0.45, 0,-0.20)\n , new Point3d (-0.45, 0, 0.20)\n , new Point3d (-0.20, 0, 0.20) /* c */\n , new Point3d (-0.20, 0, 0.45)\n , new Point3d ( 0.20, 0, 0.45)\n ]\n ,\n [ [ new Point3d ( 0.20, h, 0.20) /* c */\n , new Point3d ( 0.45, h, 0.20)\n , new Point3d ( 0.45, h,-0.20)\n , new Point3d ( 0.20, h,-0.20) /* c */\n , new Point3d ( 0.20, h,-0.45)\n , new Point3d (-0.20, h,-0.45)\n , new Point3d (-0.20, h,-0.20) /* c */\n , new Point3d (-0.45, h,-0.20)\n , new Point3d (-0.45, h, 0.20)\n , new Point3d (-0.20, h, 0.20) /* c */\n , new Point3d (-0.20, h, 0.45)\n , new Point3d ( 0.20, h, 0.45)\n ]\n , [ new Point3d ( 0.20, 0, 0.20)\n , new Point3d ( 0.20, h, 0.20)\n ]\n , [ new Point3d ( 0.45, 0, 0.20)\n , new Point3d ( 0.45, h, 0.20)\n ]\n , [ new Point3d ( 0.45, 0,-0.20)\n , new Point3d ( 0.45, h,-0.20)\n ]\n , [ new Point3d ( 0.20, 0,-0.20)\n , new Point3d ( 0.20, h,-0.20)\n ]\n , [ new Point3d ( 0.20, 0,-0.45)\n , new Point3d ( 0.20, h,-0.45)\n ]\n , [ new Point3d (-0.20, 0,-0.45)\n , new Point3d (-0.20, h,-0.45)\n ]\n , [ new Point3d (-0.20, 0,-0.20)\n , new Point3d (-0.20, h,-0.20)\n ]\n , [ new Point3d (-0.45, 0,-0.20)\n , new Point3d (-0.45, h,-0.20)\n ]\n , [ new Point3d (-0.45, 0, 0.20)\n , new Point3d (-0.45, h, 0.20)\n ]\n , [ new Point3d (-0.20, 0, 0.20)\n , new Point3d (-0.20, h, 0.20)\n ]\n , [ new Point3d (-0.20, 0, 0.45)\n , new Point3d (-0.20, h, 0.45)\n ]\n , [ new Point3d ( 0.20, 0, 0.45)\n , new Point3d ( 0.20, h, 0.45)\n ]\n ]\n );\n};\n\nwindow.tjunction = function (offset, rot) {\n let h = -0.40;\n let rad = rot * Math.PI / 2; /* as in, `rot` is 0-3 */\n return new RoomBox\n ( offset\n , [ new Point3d ( 0.20, 0, 0.20) /* c */\n , new Point3d ( 0.45, 0, 0.20)\n , new Point3d ( 0.45, 0,-0.20)\n , new Point3d (-0.45, 0,-0.20)\n , new Point3d (-0.45, 0, 0.20)\n , new Point3d (-0.20, 0, 0.20) /* c */\n , new Point3d (-0.20, 0, 0.45)\n , new Point3d ( 0.20, 0, 0.45)\n ]\n , [ [ new Point3d ( 0.20, h, 0.20) /* c */\n , new Point3d ( 0.45, h, 0.20)\n , new Point3d ( 0.45, h,-0.20)\n , new Point3d (-0.45, h,-0.20)\n , new Point3d (-0.45, h, 0.20)\n , new Point3d (-0.20, h, 0.20) /* c */\n , new Point3d (-0.20, h, 0.45)\n , new Point3d ( 0.20, h, 0.45)\n ]\n , [ new Point3d ( 0.20, 0, 0.20)\n , new Point3d ( 0.20, h, 0.20) /* c */\n ]\n , [ new Point3d ( 0.45, 0, 0.20)\n , new Point3d ( 0.45, h, 0.20)\n ]\n , [ new Point3d ( 0.45, 0,-0.20)\n , new Point3d ( 0.45, h,-0.20)\n ]\n , [ new Point3d (-0.45, 0,-0.20)\n , new Point3d (-0.45, h,-0.20)\n ]\n , [ new Point3d (-0.45, 0, 0.20)\n , new Point3d (-0.45, h, 0.20)\n ]\n , [ new Point3d (-0.20, 0, 0.20)\n , new Point3d (-0.20, h, 0.20) /* c */\n ]\n , [ new Point3d (-0.20, 0, 0.45)\n , new Point3d (-0.20, h, 0.45)\n ]\n , [ new Point3d ( 0.20, 0, 0.45)\n , new Point3d ( 0.20, h, 0.45)\n ]\n ]\n ).rotate(rad);\n};\n\nwindow.corner = function (offset, rot) {\n let h = -0.40;\n let rad = rot * Math.PI / 2; /* as in, `rot` is 0-3 */\n return new RoomBox\n ( offset\n , [ new Point3d ( 0.20, 0, 0.20) /* c */\n , new Point3d ( 0.45, 0, 0.20)\n , new Point3d ( 0.45, 0,-0.20)\n , new Point3d (-0.20, 0,-0.20) /* c */\n , new Point3d (-0.20, 0, 0.45)\n , new Point3d ( 0.20, 0, 0.45)\n ]\n ,\n [ [ new Point3d ( 0.20, h, 0.20)\n , new Point3d ( 0.45, h, 0.20)\n , new Point3d ( 0.45, h,-0.20)\n , new Point3d (-0.20, h,-0.20)\n , new Point3d (-0.20, h, 0.45)\n , new Point3d ( 0.20, h, 0.45)\n ]\n , [ new Point3d ( 0.20, 0, 0.20)\n , new Point3d ( 0.20, h, 0.20)\n ]\n , [ new Point3d ( 0.45, 0, 0.20)\n , new Point3d ( 0.45, h, 0.20)\n ]\n , [ new Point3d ( 0.45, 0,-0.20)\n , new Point3d ( 0.45, h,-0.20)\n ]\n , [ new Point3d (-0.20, 0,-0.20)\n , new Point3d (-0.20, h,-0.20)\n ]\n , [ new Point3d (-0.20, 0, 0.45)\n , new Point3d (-0.20, h, 0.45)\n ]\n , [ new Point3d ( 0.20, 0, 0.45)\n , new Point3d ( 0.20, h, 0.45)\n ]\n ]\n ).rotate(rad);\n};\n\n\n\nwindow.mapData =\n [\n { room: crossing (new Point3d (0, 0, 0))\n , exits:\n [\n ]\n }\n , { room: hall (new Point3d ( 1, 0, 0), "X")\n , exits:\n [\n ]\n }\n , { room: cube (new Point3d ( 2, 0, 0))\n , exits:\n [\n ]\n }\n , { room: hall (new Point3d ( 0, 0, 1), "Z")\n , exits:\n [\n ]\n }\n , { room: cube (new Point3d ( 0, 0, 2))\n , exits:\n [\n ]\n }\n , { room: stairs (new Point3d (-1, 0, 0), "X", 0.5)\n , exits:\n [\n ]\n }\n , { room: cube (new Point3d (-2,-0.5, 0))\n , exits:\n [\n ]\n }\n , { room: hall (new Point3d ( 0, 0,-1), "Z")\n , exits:\n [\n ]\n }\n , { room: cube (new Point3d ( 0, 0,-2))\n , exits:\n [\n ]\n }\n\n , { room: corner (new Point3d ( 1, 0, 1), 0)\n , exits:\n [\n ]\n }\n , { room: tjunction (new Point3d (-1, 0, -1), 0)\n , exits:\n [\n ]\n }\n ];\n\nlet isRotating = false;\n\nwindow.addEventListener ('mouseup', e => {\n isRotating = false;\n});\n\nwindow.renderMap = function (ix) {\n let currentRoom = mapData[ix];\n let adjacentRooms = mapData.slice(0, ix).concat(mapData.slice(ix+1, mapData.length));\n\n let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");\n svg.setAttributeNS (null, 'width', 600);\n svg.setAttributeNS (null, 'height', 384);\n svg.setAttributeNS (null, 'viewBox', "0 0 600 384");\n svg.setAttribute('style', 'border: 2px solid #003100');\n\n let tilt = 60 / 180.0 * 3.1415926;\n let angle = 45 / 180.0 * 3.1415926;\n let camera = euler(tilt, angle, 0).scale(72);\n\n let start = new Point2d (0, 0);\n let offset = new Point2d (0, 0);\n let rect = null;\n\n svg.addEventListener ('mousedown', e => {\n isRotating = true;\n rect = svg.getBoundingClientRect();\n start = new Point2d (e.clientX - rect.x, e.clientY - rect.y);\n });\n svg.addEventListener ('mousemove', e => {\n if (!isRotating) {\n return;\n }\n offset = new Point2d (e.clientX - rect.x, e.clientY - rect.y);\n let t = offset;\n offset = offset.minus (start);\n start = t;\n tilt = tilt + offset.y * 0.004;\n angle = angle + offset.x * 0.004;\n\n tilt = Math.max (0, Math.min (Math.PI / 2, tilt));\n\n camera = euler(tilt, angle, 0).scale(72);\n renderRooms (svg, camera);\n });\n\n function renderRooms (svg, camera) {\n while (svg.firstChild) {\n svg.removeChild (svg.firstChild);\n }\n let centerOffset = camera.tvec3 (currentRoom.room.offset);\n let floor = document.createElementNS("http://www.w3.org/2000/svg", "path");\n floor.setAttributeNS(null, 'fill', 'rgba(0,255,125,0.25)');\n floor.setAttributeNS(null, 'stroke', 'rgba(0,126,255,0.50)');\n floor.setAttributeNS(null, 'stroke-width', '2');\n floor.setAttributeNS(null, 'd', currentRoom.room.floorPath(camera));\n let outlines = document.createElementNS("http://www.w3.org/2000/svg", "path");\n outlines.setAttributeNS(null, 'fill', 'none');\n outlines.setAttributeNS(null, 'stroke', 'rgba(0,255,125,0.18)');\n outlines.setAttributeNS(null, 'stroke-width', '2');\n outlines.setAttributeNS(null, 'd', currentRoom.room.outlinesPath(camera));\n\n let adjacentG = document.createElementNS("http://www.w3.org/2000/svg", "g");\n adjacentG.setAttributeNS(null, 'fill', 'none');\n adjacentG.setAttributeNS(null, 'stroke', 'rgba(0,126,255,0.50)');\n adjacentG.setAttributeNS(null, 'stroke-width', '2');\n adjacentRooms.map (adj => {\n let floor = document.createElementNS("http://www.w3.org/2000/svg", "path");\n floor.setAttributeNS(null, 'd', adj.room.floorPath(camera));\n adjacentG.appendChild (floor);\n });\n\n let tg = document.createElementNS("http://www.w3.org/2000/svg", "g");\n tg.setAttributeNS(null, 'transform', 'translate('\n + (300 - centerOffset.x) + " "\n + (192 - centerOffset.z) + ')');\n\n tg.appendChild (adjacentG);\n tg.appendChild (floor);\n tg.appendChild (outlines);\n\n svg.appendChild (tg);\n }\n renderRooms (svg, camera);\n return svg;\n}\n\nfunction parseArg (str) { return (str[0] == "$"? eval(Wikifier.parse(str)) : str); }\n\nmacros.citymap = {\n handler: function (place, macroName, params, parser) {\n var mapID = params[0] !== undefined ? parseArg(params[0]) : null;\n place.insertBefore(renderMap(mapID), null);\n }\n};
<<nobr>>\n\n<<set $locations =\n ["the gulch graveyard"\n ,"west lane"\n ,"the wanderer's encampment"\n ,"kane street"\n ]>>\n<<set $events =\n ["the fire on smulland street"\n ,"the lights above the city"\n ,"any unusual events recently"\n ]>>\n<<set $people =\n [ "unturned humans"\n , "incomplete beasts"\n , "beasts"\n , "ashen beasts"\n , "spark beasts"\n , "wanderers"\n , "who were bitten by a beast, and changed"\n , "who were bitten by a beast, but not changed"\n , "hunters"\n\n , "non-wolf beasts"\n ]>>\n<<set $persons =\n [ "the hunter of west lane"\n , "the sheep-skull hunter"\n , "the graveyard seer"\n ]>>\n\n<<set $rumormonger =\n { name: "rumormonger"\n , topics:\n { "do you know...":\n { "any...":\n { "non-wolf beasts": "rumormonger non-wolf"\n , "ashen beasts": "rumormonger ashen beasts"\n , "spark beasts": "rumormonger spark beasts"\n , "beasts who can hide as humans": "rumormonger beasts who hide"\n }\n }\n }\n }>>\n<<set $drunkard =\n { name: "drunkard"\n , topics:\n { "do you know...":\n { "any...":\n { "non-wolf beasts": "drunkard non-wolf"\n }\n }\n }\n }>>\n<<set $worker =\n { name: "worker"\n , topics:\n { "do you know...":\n { "any...":\n { "non-wolf beasts": "worker non-wolf"\n , "ashen beasts": "worker ashen beasts"\n }\n }\n }\n }>>\n\n<<set $goodbye_spec =\n { name: "goodbye_spec"\n , topics:\n { "goodbye": "goodbye interrupt"\n }\n }>>\n<<set $know_nothing =\n { name: "know_nothing"\n , topics:\n { "*": "know nothing"\n }\n }>>\n<<set $human =\n { name: "human"\n , topics:\n { "": "human intro"\n , "do you know...":\n { "any...":\n { "unturned humans": "human know humans"\n , "incomplete beasts": "human know altered"\n , "beasts": "human know beasts"\n }\n }\n }\n }>>\n\n\n<<set $_conversationPartner = [$rumormonger, $human, $goodbye_spec, $know_nothing]>>\n<<endnobr>>
<<set $interrupt to true>>\nblah blah, goodbye\n\n[[→|Start]]
"know nothing" fallback
<div class="npc_title">Street Drunkard</div>\\n<ul class="npc_ranks"><li>Rank II Confabulator</li>\\n<li>Rank I Rumormonger</li></ul>\\n\nyr talking to a human, etc
"human know humans" chunk
"human know altered" chunk
"human know beasts" chunk
there are rumors that some among __the wanderers__, who camp outside town, have turned into __jackal-headed beasts__.\n\n<<grantTopic "the wanderers" "people">>\n<<grantTopic "jackal-headed beasts" "people">>\n\nthey say that down in __the gulches__ there's a __ram-headed beast__ that perches among the tombstones.\n\n<<grantTopic "the gulches" "locations">>\n<<grantTopic "ram-headed beasts" "people">>
> me? not specifically, no. there are vagrants and thieves all over the city who are ashen beasts __in disguise__ though.\n\n<<grantTopic "beasts who can hide as humans" "people">>
> are there others, besides __the executioner__? i imagine __the royals__ would be very pleased to hear of one, and equally as displeased to hear anybody's been poking around looking.\n\n<<grantTopic "the executioner" "persons">>\n<<grantTopic "the royals" "persons">>
> if i did, i certainly wouldn't tell you. those who can hide, hide to hunt, and deal brutally with those who betray their confidence. i wouldn't continue prying in those corners, if i were you.
i was passing through __the sewers__ a fortnight ago and saw the great gleaming eyes of some grotesque __rat beast__ just downstream.\n\n<<grantTopic "the sewers" "locations">>\n<<grantTopic "rat beasts" "people">>
last night, there was some drunkard outside the beerhall who was screaming about how there were giant __rat-beasts__ down in __the sewers__\n\n<<grantTopic "the sewers" "locations">>\n<<grantTopic "rat beasts" "people">>
there's __the king of kane street__; he and his gang are mostly ashen beasts. i wouldn't go looking for them if i were you, though.\n\n<<grantTopic "the king of kane street" "persons">>\n<<grantTopic "the kane street gang" "persons">>\n\nmikhel the crusher spends his nights at the bar down the street, __the hind's heart__. he's not so friendly, though.\n\n<<grantTopic "mikhel the crusher" "persons">>\n<<grantTopic "the hind's hart" "locations">>
<<set $_granted to parameter(0)>>\\n<<set $_topic to parameter(1)>>\\n<<set $_check to (function (kind, topic) {\n let vartable = state.history[0].variables;\n let which = null;\n switch (kind) {\n case "locations":\n which = vartable["locations"];\n break;\n case "people":\n which = vartable["people"];\n break;\n case "persons":\n which = vartable["persons"];\n break;\n case "events":\n which = vartable["events"];\n break;\n default:\n throw new Error ("unexpected kind of \"" + kind + "\"");\n return false;\n }\n if (which.indexOf (topic) === -1) {\n which.push (topic);\n return true;\n } else {\n return false;\n }\n })($_topic, $_granted)>>\\n<<if $_check>>\\n''You can now ask about "<<print $_granted>>", under "<<print $_topic>>".''\n<<endif>>
<<if $prompt>>\\n<span class="askd"><<if $prompt !== "goodbye">><<print $prompt>><<if $what>> <<print $what>><<if $who>> <<print $who>><<endif>><<endif>>?<<else>>goodbye.<<endif>></span>\n<<endif>>
<<set $asking to false>>\\n<<set $prompt to "">>\\n<<set $what to "">>\\n<<set $who to "">>\\n/% this generates a blank statement to start, which would serve as the intro/splash text for a given encounter %/\n<<display "response">>\\n\n<<display "build ask">>\\n<<display "construction ui">>
<<block ask>><<if !$asking>><<display "current statement">> <<display "ask click">><<else>><<display "stated">>\n<<display "response">>\\n<<set $asking to false>>\\n\n<<display "build ask">>\\n<<endif>><<endblock>>
<<block base>><<block what>><<block who>><<if complete($prompt, $what, $who)>><span class="askq"><<replace "ask →">>\\n<<set $asking to true>>\\n<<set reshow("ask")>>\\n/% this strips away the outer layer of 'ask' wrapping, so that when we toggle 'ask' to render a new 'ask' inside of the old 'ask', we don't totally wipe the entire history when we _next_ toggle 'ask' etc. %/\\n<<set unroll (document.querySelector(".passage .ask"))>>\\n<<endreplace>></span><<endif>><<endblock>><<endblock>><<endblock>>
<<set $prompt to "">>\\n<<block base>><<set $what to "">><<set $who to "">>\\n<<block what>><<set $who to "">>\\n<<block who>>\\n<<if $prompt neq "">><div class="askcur"><<print $prompt>> <<print $what>> <<print $who>></div><<endif>>\\n<<endblock>><<endblock>><<endblock>>
<<nobr>>\n<<block asktable>><<if !$interrupt>><table><tbody><tr valign="top"><td><<toggle $prompt "base" "where is..." "where is...">>\n<<toggle $prompt "base" "have you heard of..." "have you heard of...">>\n<<toggle $prompt "base" "do you know..." "do you know...">>\n<<toggle $prompt "base" "goodbye" "goodbye">></td>\n<td><<block base>>\n<<if $prompt == "where is...">>/% locations, persons %/\n<<print groupList ("what",\n [ {title:"locations",content:$locations}\n , {title:"persons",content:$persons}\n ])>>\n<<else if $prompt == "have you heard of...">>/% persons, events %/\n<<print groupList ("what",\n [ {title:"persons",content:$persons}\n , {title:"events",content:$events}\n ])>>\n<<else if $prompt == "do you know...">>/% people, persons %/\n<<print groupList ("what",\n [ {title:null,content:["any..."]}\n , {title:"persons",content:$persons}\n ])>>\n<<else>>\n<<endif>>\n<<endblock>></td>\n<td><<block base>><<block what>><<if $what == "any...">>\n<<print groupList ("who",\n [ {title:"people",content:$people}\n ])>>\n<<else>>\n<<endif>><<endblock>><<endblock>></td></tr></tbody></table><<endif>>\n<<endblock>>\n<<endnobr>>
/% todo: when this gets run it should force a scroll to the latest question (currently it scrolls to the top of the page, which would get annoying on actual interactions) %/\\n<<set $_q = []>>\\n<<set $_q.push ($prompt)>>\\n<<if $what>><<set $_q.push ($what)>><<endif>>\\n<<if $who>><<set $_q.push ($who)>><<endif>>\\n/% asking about <<print ($_q\n .map(x => '"' + x + '"')\n .reduce((a, b) => a + ", " + b))>> %/\\n/% asking vs. <<print (function (p){\n return p.map (function (s){ return "'" + s.name + "'"; }).reduce(function(a,b) {return a + " -> " + b; });\n})($_p)>> %/\\n<<set $_a = lookupAnswer ($_q, $_conversationPartner)>>\\n<<set $interrupt to false>>\\n<<if $_a !== 0>>\\n/% got "<<print $_a.match>>" from "<<print $_a.archetype>>" %/\n<div class="resp"><<display $_a.match>></div>\\n<<else>>\\nERROR: null result; not even a fallback available\n<<endif>>\\n<<set reshow("asktable")>>
table { vertical-align: top; }\n.asktable {\n position: relative;\n display: block;\n clear: both;\n margin: 0 -24px;\n border: 1px solid #fe8;\n border-image-source: url("./img/construct-border.png");\n border-image-slice: 24;\n border-image-width: auto;\n margin-bottom: 10em;\n background: #1f1c08;\n}\n.asktable::before, .asktable::after {\n content: "";\n display: block;\n position: absolute;\n left: -1px;\n right: -1px;\n height: 32px;\n}\n .asktable::before {\n top: -1px;\n background: no-repeat center url("./img/construct-border-top.png");\n }\n .asktable::after {\n bottom: -2px;\n background: no-repeat center url("./img/construct-border-bottom.png");\n }\ntable, tbody { border: none; }\ntr, td { }\n.gr { background: #3f3610; padding: 2px; }\n\n.askd, .askcur { font-weight: bold; color: #ffc; border-radius: 4px; float: left; clear: both; padding: 0.25em; margin: 1em 0; }\n.askd { border: 1px solid #eee576; }\n.askcur { display: inline-block; border: 1px solid #808088; }\n.askq { display: inline-block; margin: calc(1.25em + 1px) 1.25em calc(1.25em + 1px) 0.25em; }\n.resp { clear: both; }\n\n.npc_title { font-weight: bold; font-size: 150%; color: #eb9; }\nul.npc_ranks { font-weight: bold; margin: 0; padding: 0; font-size: 125%; list-style: none; }\nul.npc_ranks li { margin-left: 1em; color: #fdb; }
input[type="radio"].toggleInput { display: none; }\ninput.toggleInput + label { padding: 2px; cursor: pointer; font-weight: bold; transition: 0.5s; }\n\ninput.toggleInput + label { background: transparent; color: #fe8; }\ninput.toggleInput + label:hover { background: #403810; color: #ffc; }\ninput.toggleInput:checked + label { background: #fe8; color: #000; }
@font-face {\n font-family: 'Libre Baskerville';\n font-style: normal;\n font-weight: 400;\n src: local('Libre Baskerville'), local('Libre-Baskerville'), url(./fonts/LibreBaskerville-Regular.ttf) format('truetype');\n}\n\nbody { margin: 1em 10px; font-family: "Libre Baskerville", serif; }\n#passages { margin: 0 5em; border: none; }\nul#sidebar { display: none; }\nhr { border: none; border-bottom: 1px solid #fe8; margin: 1.2em 4em; clear: both; }\n\na.internalLink { color: #fe8; transition: 0.5s; }\na.internalLink:hover { color: #ffc; text-shadow: 0px 0px 6px #982; text-decoration: none; }\n\n\n#notes {display: block; position: fixed; bottom: 0; right: 3em; width: 15em; height: 3em; line-height: 3em; text-align: center; background: linear-gradient(to top, #fe8, transparent);\n}\n#notes a { color: #000; }\n\ntable .toggleContainer { display: block; }
window.complete = function (p1, p2, p3) {\n console.log ("complete: " + p1 + "" + p2 + "" + p3);\n if (p1 && !(p1.substr(-3) === "...")) {\n return true;\n }\n if (p1 && p2 && !(p2.substr(-3) === "...")) {\n return true;\n }\n if (p1 && p2 && p3 && !(p3.substr(-3) === "...")) {\n return true;\n }\n return false;\n}\n\nwindow.lookupAnswer = function (question, archetypes) {\n var match = null;\n for (var i = 0; i < archetypes.length; i++) {\n match = tryAnswer (question, archetypes[i]);\n if (match !== null) {\n return {archetype: archetypes[i].name, match: match};\n }\n }\n return null;\n}\n\nfunction tryAnswer (question, archetype) {\n let topic = archetype.topics;\n let answer = null;\n let qi = 0;\n\n while (qi < question.length) {\n if (topic[question[qi]]) {\n topic = topic[question[qi]];\n qi++;\n } else if (topic["*"]) {\n return topic["*"];\n } else {\n return null;\n }\n }\n if (qi >= question.length) {\n return topic;\n }\n return null;\n}
window.closeArrows = String.fromCharCode(0x3e) + String.fromCharCode(0x3e);\n\nwindow.groupList = function (target, groups) {\n return groups.map(function (group) {\n return (group.title ? '<div class="gr">' + group.title + '</div>' : '') +\n group.content.map(function (i) {\n return '<<toggle $' + target + ' "' + target + '" "' + i + '" "' + i + '"' + closeArrows;\n }).join(String.fromCharCode(0x20));\n }).join(String.fromCharCode(0x20));\n}
function innercontent(tag, parser) {\n var\n i,\n textbegin = parser.source.indexOf(">>",parser.matchStart)+2,\n textend = -1,\n text = parser.source.slice(textbegin),\n depth = 0;\n for (i = 0; i < text.length; i++) {\n if (text.substr(i,tag.length + 5) === ("<<end" + tag)) {\n if(depth===0){\n textend=textbegin+i;\n break;\n }else{\n depth--;\n }\n } else if (text.substr(i,tag.length + 2) === ("<<" + tag)) {\n depth++;\n }\n }\n if (textend === -1) {\n throwError(place,"can't find matching end"+tag,parser.fullMatch());\n return;\n }\n return [textbegin, textend];\n}\n\nfunction parseArg (str) { return (str[0] == "$"? eval(Wikifier.parse(str)) : str); }\nfunction varArg (str) { return (str[0] == "$"? str.substr(1) : str); }\nfunction varArg2 (str) {\n let params = null;\n if (str[0] == "$") {\n params = str.substring(1).split(".");\n } else {\n params = [str];\n }\n let final = params.pop();\n return ((vartable, val) => {\n let o = vartable;\n /* console.log ("setting " + val); */\n params.map (p => { /* console.log (p); */ o = o[p]; /* console.log (o); */ });\n /* console.log (final); */\n o[final] = val;\n });\n}\n\nmacros.block = {\n handler: function (place, macroName, params, parser) {\n var class_ = params[0][0] == "$"\n ? eval(Wikifier.parse(params[0]))\n : params[0];\n var block = insertElement (null, "span", null, "blockSpan " + class_.replace(" ", "_"));\n var inner_index = innercontent ("block", parser);\n block.tweecode = parser.source.slice(inner_index[0], inner_index[1]);\n parser.nextMatch=inner_index[1];\n place.insertBefore(block,null);\n new Wikifier(block, block.tweecode);\n }\n};\nmacros.endblock = { handler: function () {}};\n\nmacros.click = {\n handler: function (place, macroName, params, parser) {\n var linkText = params[0] !== undefined ? params[0] : null;\n var click = insertElement (null, "a", null, "click internalLink", linkText);\n\n var inner_index = innercontent ("click", parser);\n click.tweecode = parser.source.slice(inner_index[0], inner_index[1]);\n parser.nextMatch=inner_index[1];\n place.insertBefore(click,null);\n\n click.addEventListener ('click', function (e) {\n reshowOne (click);\n });\n }\n};\nmacros.endclick = { handler: function () {}};\n\nmacros.toggle = {\n handler: function (place, macroName, params, parser) {\n var varSet = params[0] !== undefined ? varArg2(params[0]) : null;\n var group = params[1] !== undefined ? parseArg(params[1]) : null;\n var value = params[2] !== undefined ? parseArg(params[2]) : null;\n var display = params[3] !== undefined ? parseArg(params[3]) : null;\n var pre = params[4] !== undefined ? parseArg(params[4]) : null;\n\n var c = insertElement (null, "span", null, "toggleContainer", null);\n if (pre) {\n insertText (c, pre);\n }\n var toggleInput = insertElement (c, "input", "toggle_" + group + "_" + value, "toggleInput toggleGroup_" + group, null);\n var toggleLabel = insertElement (c, "label", null, "toggleLabel", display);\n toggleInput.type = "radio";\n toggleInput.name = group;\n toggleInput.value = value;\n toggleLabel.htmlFor = "toggle_" + group + "_" + value;\n\n var changeList = [group];\n toggleInput.addEventListener ('change', function () {\n /* console.log (params[0] + " set to \"" + toggleInput.value + "\""); */\n varSet (state.history[0].variables, toggleInput.value);\n changeList.map (function (f) { /* console.log (f); */ reshow (f); });\n });\n\n place.insertBefore(c, null);\n }\n};\n\nwindow.reshow = function (name) {\n var\n rall=document.querySelectorAll(".passage .blockSpan." + name.replace(" ", "_")),\n ret=false;\n for(var i=0;i<rall.length;i++){\n ret=reshowOne(rall[i]);\n }\n return ret;\n}\n\nwindow.unroll = function (where) {\n var p = where.parentNode;\n while (where.firstChild) {\n p.insertBefore (where.firstChild, where);\n }\n p.removeChild (where);\n}\n\nfunction reshowOne (target) {\n target.innerHTML="";\n new Wikifier(target,target.tweecode);\n target.classList.add("blockSpanIn");\n if(target.timeout){\n clearTimeout(target.timeout);\n }\n target.timeout=setTimeout(\n function(){\n target.classList.remove("blockSpanIn");\n },\n 1);\n}
(function(){\n version.extensions.replaceMacrosCombined={major:1,minor:1,revision:7};\n var nullobj={handler:function(){}};\n function showVer(n,notrans){\n if(!n){return;}n.innerHTML="";\n new Wikifier(n,n.tweecode);\n n.setAttribute("data-enabled","true");\n n.style.display="inline";\n n.classList.remove("revision-span-out");\n if(!notrans) {\n n.classList.add("revision-span-in");\n if(n.timeout){\n clearTimeout(n.timeout);\n }\n n.timeout=setTimeout(function(){n.classList.remove("revision-span-in");n=null;},20);\n }\n }\n function hideVer(n,notrans){\n if(!n){return;}\n n.setAttribute("data-enabled","false");n.classList.remove("revision-span-in");if(n.timeout){clearTimeout(n.timeout);}\n if(!notrans){\n n.classList.add("revision-span-out");\n n.timeout=setTimeout(function(){\n if(n.getAttribute("data-enabled")=="false"){\n n.classList.remove("revision-span-out");\n n.style.display="none";\n n.innerHTML="";\n }\n n=null;\n },1000);\n }else{\n n.style.display="none";n.innerHTML="";n=null;\n }\n}\n\nfunction tagcontents(b,starttags,desttags,endtags,k){var l=0,c="",tg,a,i;function tagfound(i,e,endtag){for(var j=0;\nj<e.length;j++){if(a.indexOf("<<"+e[j]+(endtag?">>":""),i)==i){return e[j];}}}a=b.source.slice(k);for(i=0;i<a.length;i++){if(tg=tagfound(i,starttags)){l++;}else{if((tg=tagfound(i,desttags,true))&&l==0){b.nextMatch=k+i+tg.length+4;\nreturn[c,tg];}else{if(tg=tagfound(i,endtags,true)){l--;if(l<0){return null;}}}}c+=a.charAt(i);}return null;}\n\nvar begintags=[];\nvar endtags=[];\nfunction revisionSpanHandler(g,e,f,b){var k=b.source.indexOf(">>",b.matchStart)+2,vsns=[],vtype=e,flen=f.length,becomes,c,cn,m, h,vsn;\nfunction mkspan(vtype){h=insertElement(m,"span",null,"revision-span "+vtype);h.setAttribute("data-enabled",false);h.style.display="none";h.tweecode="";return h;}if(this.shorthand&&flen){while(f.length>0){vsns.push([f.shift(),(this.flavour=="insert"?"gains":"becomes")]);\n}}else{if(this.flavour=="insert"||(this.flavour=="continue"&&this.trigger=="time")){vsns.push(["","becomes"]);}}if(this.flavour=="continue"&&flen){b.nextMatch=k+b.source.slice(k).length;\nvsns.push([b.source.slice(k),vtype]);}else{becomes=["becomes","gains"];c=tagcontents(b,begintags,becomes.concat(endtags),endtags,k);if(c&&endtags.indexOf(c[1])==-1){while(c){vsns.push(c);\nc=tagcontents(b,begintags,becomes,endtags,b.nextMatch);}c=tagcontents(b,begintags,["end"+e],endtags,b.nextMatch);}if(!c){throwError(g,"can't find matching end"+e);\nreturn;}vsns.push(c);if(this.flavour=="continue"){k=b.nextMatch;b.nextMatch=k+b.source.slice(k).length;vsns.push([b.source.slice(k),""]);}}if(this.flavour=="remove"){vsns.push(["","becomes"]);\n}cn=0;m=insertElement(g,"span",null,e);m.setAttribute("data-flavour",this.flavour);h=mkspan("initial");vsn=vsns.shift();h.tweecode=vsn[0];showVer(h,true);while(vsns.length>0){if(vsn){vtype=vsn[1];\n}vsn=vsns.shift();h=mkspan(vtype);h.tweecode=vsn[0];}if(typeof this.setup=="function"){this.setup(m,g,f);}}\n\nfunction quantity(m){return(m.children.length-1)+(m.getAttribute("data-flavour")=="remove");\n}\n\nfunction revisionSetup(m,g,f){m.className+=" "+f[0].replace(" ","_");}\nfunction keySetup(m,g,f){\n var key=f[0];m.setEventListener("keydown",function l(e){var done=!revise("revise",m);\n if(done){m.removeEventListener("keydown",l);}});\n}\nfunction timeSetup(m,g,f){function cssTimeUnit(s){if(typeof s=="string"){if(s.slice(-2).toLowerCase()=="ms"){return Number(s.slice(0,-2))||0;\n}else{if(s.slice(-1).toLowerCase()=="s"){return Number(s.slice(0,-1))*1000||0;}}}throwError(g,s+" isn't a CSS time unit");return 0;}var tm=cssTimeUnit(f[0]);var s=state.history[0].passage.title;\nsetTimeout(function timefn(){if(state.history[0].passage.title==s){var done=!revise("revise",m);if(!done){setTimeout(timefn,tm);}}},tm);}\n\nfunction hoverSetup(m){var fn,noMouseEnter=(document.head.onmouseenter!==null),m1=m.children[0],m2=m.children[1],gains=m2.className.indexOf("gains")>-1;\nif(!m1||!m2){return;}m1.onmouseenter=function(e){var efp=document.elementFromPoint(e.clientX,e.clientY);while(efp&&efp!==this){efp=efp.parentNode;}if(!efp){return;\n}if(this.getAttribute("data-enabled")!="false"){revise("revise",this.parentNode);}};m2.onmouseleave=function(e){var efp=document.elementFromPoint(e.clientX,e.clientY);\nwhile(efp&&efp!==this){efp=efp.parentNode;}if(efp){return;}if(this.getAttribute("data-enabled")!="false"){revise("revert",this.parentNode);}};if(gains){m1.onmouseleave=m2.onmouseleave;\n}if(noMouseEnter){fn=function(n){return function(e){if(!event.relatedTarget||(event.relatedTarget!=this&&!(this.compareDocumentPosition(event.relatedTarget)&Node.DOCUMENT_POSITION_CONTAINED_BY))){this[n]();\n}};};m1.onmouseover=fn("onmouseenter");m2.onmouseout=fn("onmouseleave");if(gains){m1.onmouseout=m2.onmouseout;}}m=null;}\n\nfunction mouseSetup(m){\n var evt=(document.head.onmouseenter===null?"onmouseenter":"onmouseover");\n m[evt]=function(){\n var done=!revise("revise",this);if(done){this[evt]=null;}\n };\n m=null;\n}\n\nfunction linkSetup(m,g,f){\n var l=Wikifier.createInternalLink(),p=m.parentNode;\n l.className="internalLink replaceLink";\n p.insertBefore(l,m);\n l.insertBefore(m,null);\n l.onclick=function(){\n var p,done=false;\n if(m&&m.parentNode==this){\n done=!revise("revise",m);\n /* console.log (m);\n scrollWindowTo(m); */\n let l = document.querySelectorAll (".askd");\n scrollWindowTo(l[l.length-1]);\n }\n if(done){\n this.parentNode.insertBefore(m,this);\n this.parentNode.removeChild(this);\n }\n };\n l=null;\n}\n\nfunction visitedSetup(m,g,f){\n var i,done,shv=state.history[0].variables,os="once seen",d=(m.firstChild&&(this.flavour=="insert"?m.firstChild.nextSibling:m.firstChild).tweecode);\n shv[os]=shv[os]||{};\n if(d&&!shv[os].hasOwnProperty(d)){shv[os][d]=1;}else{for(i=shv[os][d];i>0&&!done;i--){done=!revise("revise",m,true);}if(shv[os].hasOwnProperty(d)){shv[os][d]+=1;\n}}}\n\n[{name:"insert",flavour:"insert",trigger:"link",setup:linkSetup}\n,{name:"timedinsert",flavour:"insert",trigger:"time",setup:timeSetup}\n,{name:"insertion",flavour:"insert",trigger:"revisemacro",setup:revisionSetup}\n,{name:"later",flavour:"insert",trigger:"visited",setup:visitedSetup}\n,{name:"keyinsert",flavour:"insert",trigger:"key",setup:keySetup}\n,{name:"replace",flavour:"replace",trigger:"link",setup:linkSetup}\n,{name:"timedreplace",flavour:"replace",trigger:"time",setup:timeSetup}\n,{name:"mousereplace",flavour:"replace",trigger:"mouse",setup:mouseSetup}\n,{name:"hoverreplace",flavour:"replace",trigger:"hover",setup:hoverSetup}\n,{name:"revision",flavour:"replace",trigger:"revisemacro",setup:revisionSetup}\n,{name:"keyreplace",flavour:"replace",trigger:"key",setup:keySetup}\n,{name:"timedremove",flavour:"remove",trigger:"time",setup:timeSetup}\n,{name:"mouseremove",flavour:"remove",trigger:"mouse",setup:mouseSetup}\n,{name:"hoverremove",flavour:"remove",trigger:"hover",setup:hoverSetup}\n,{name:"removal",flavour:"remove",trigger:"revisemacro",setup:revisionSetup}\n,{name:"once",flavour:"remove",trigger:"visited",setup:visitedSetup}\n,{name:"keyremove",flavour:"remove",trigger:"key",setup:keySetup}\n,{name:"continue",flavour:"continue",trigger:"link",setup:linkSetup}\n,{name:"timedcontinue",flavour:"continue",trigger:"time",setup:timeSetup}\n,{name:"mousecontinue",flavour:"continue",trigger:"mouse",setup:mouseSetup}\n,{name:"keycontinue",flavour:"continue",trigger:"key",setup:keySetup}\n,{name:"cycle",flavour:"cycle",trigger:"revisemacro",setup:revisionSetup}\n,{name:"mousecycle",flavour:"cycle",trigger:"mouse",setup:mouseSetup}\n,{name:"timedcycle",flavour:"cycle",trigger:"time",setup:timeSetup}\n,{name:"keycycle",flavour:"replace",trigger:"key",setup:keySetup}\n].forEach(function(e){\n e.handler=revisionSpanHandler;\n e.shorthand=(["link","mouse","hover"].indexOf(e.trigger)>-1);\n macros[e.name]=e;\n macros["end"+e.name]=nullobj;\n begintags.push(e.name);\n endtags.push("end"+e.name);\n });\n\nfunction insideDepartingSpan(elem){var r=elem.parentNode;\nwhile(!r.classList.contains("passage")){if(r.classList.contains("revision-span-out")){return true;}r=r.parentNode;}}function reviseAll(rt,rname){var rall=document.querySelectorAll(".passage [data-flavour]."+rname),ret=false;\nfor(var i=0;i<rall.length;i++){if(!insideDepartingSpan(rall[i])){ret=revise(rt,rall[i])||ret;}}return ret;}function revise(rt,r,notrans){var ind2,curr,next,ind=-1,rev=(rt=="revert"),rnd=(rt.indexOf("random")>-1),fl=r.getAttribute("data-flavour"),rc=r.childNodes,cyc=(fl=="cycle"),rcl=rc.length-1;\nfunction doToGainerSpans(n,fn){for(var k=n-1;k>=0;k--){if(rc[k+1].classList.contains("gains")){fn(rc[k],notrans);}else{break;}}}for(var k=0;k<=rcl;k++){if(rc[k].getAttribute("data-enabled")=="true"){ind=k;\n}}if(rev){ind-=1;}curr=(ind>=0?rc[ind]:(cyc?rc[rcl]:null));ind2=ind;if(rnd){ind2=(ind+(Math.floor(Math.random()*rcl)))%rcl;}next=((ind2<rcl)?rc[ind2+1]:(cyc?rc[0]:null));\nvar docurr=(rev?showVer:hideVer);var donext=(rev?hideVer:showVer);var currfn=function(){if(!(next&&next.classList.contains("gains"))||rnd){docurr(curr,notrans);doToGainerSpans(ind,docurr,notrans);\n}};var nextfn=function(){donext(next,notrans);if(rnd){doToGainerSpans(ind2+1,donext,notrans);}};if(!rev){currfn();nextfn();}else{nextfn();currfn();}return(cyc?true:(rev?(ind>0):(ind2<rcl-1)));\n}macros.revert=macros.revise=macros.randomise=macros.randomize={handler:function(a,b,c){var l,rev,rname;function disableLink(l){l.style.display="none";}function enableLink(l){l.style.display="inline";\n}function updateLink(l){if(l.className.indexOf("random")>-1){enableLink(l);return;}var rall=document.querySelectorAll(".passage [data-flavour]."+rname),cannext,canprev,i,ind,r,fl;\nfor(i=0;i<rall.length;i++){r=rall[i],fl=r.getAttribute("data-flavour");if(insideDepartingSpan(r)){continue;}if(fl=="cycle"){cannext=canprev=true;}else{if(r.firstChild.getAttribute("data-enabled")==!1+""){canprev=true;\n}if(r.lastChild.getAttribute("data-enabled")==!1+""){cannext=true;}}}var can=(l.classList.contains("revert")?canprev:cannext);(can?enableLink:disableLink)(l);}function toggleText(w){w.classList.toggle(rl+"Enabled");\nw.classList.toggle(rl+"Disabled");w.style.display=((w.style.display=="none")?"inline":"none");}var rl="reviseLink";if(c.length<2){throwError(a,b+" macro needs 2 parameters");\nreturn;}rname=c.shift().replace(" ","_");l=Wikifier.createInternalLink(a,null);l.className="internalLink "+rl+" "+rl+"_"+rname+" "+b;var v="";var end=false;var out=false;\nif(c.length>1&&c[0][0]=="$"){v=c[0].slice(1);c.shift();}switch(c[c.length-1]){case"end":end=true;c.pop();break;case"out":out=true;c.pop();break;}var h=state.history[0].variables;\nfor(var i=0;i<c.length;i++){var on=(i==Math.max(c.indexOf(h[v]),0));var d=insertElement(null,"span",null,rl+((on)?"En":"Dis")+"abled");if(on){h[v]=c[i];l.setAttribute("data-cycle",i);\n}else{d.style.display="none";}insertText(d,c[i]);l.appendChild(d);}l.onclick=function(){reviseAll(b,rname);var t=this.childNodes,u=this.getAttribute("data-cycle")-0,m=t.length,n,lall,i;\nif((end||out)&&u>=m-(end?2:1)){if(end){n=this.removeChild(t[u+1]||t[u]);n.className=rl+"End";n.style.display="inline";this.parentNode.replaceChild(n,this);}else{this.parentNode.removeChild(this);\nreturn;}}else{toggleText(t[u]);u=(u+1)%m;if(v){h[v]=c[u];}toggleText(t[u]);this.setAttribute("data-cycle",u);}lall=document.getElementsByClassName(rl+"_"+rname);\nfor(i=0;i<lall.length;i++){updateLink(lall[i]);}};disableLink(l);setTimeout((function(l){return function(){updateLink(l);};}(l)),1);l=null;}};macros.mouserevise=macros.hoverrevise={handler:function(a,b,c,d){var endtags=["end"+b],evt=(window.onmouseenter===null?"onmouseenter":"onmouseover"),t=tagcontents(d,[b],endtags,endtags,d.source.indexOf(">>",d.matchStart)+2);\nif(t){var rname=c[0].replace(" ","_"), h=insertElement(a,"span",null,"hoverrevise hoverrevise_"+rname),f=function(){var done=!reviseAll("revise",rname);if(b!="hoverrevise"&&done){this[evt]=null;\n}};new Wikifier(h,t[0]);if(b=="hoverrevise"){h.onmouseover=f;h.onmouseout=function(){reviseAll("revert",rname);};}else{h[evt]=f;}h=null;}}};macros.instantrevise={handler:function(a,b,c,d){reviseAll("revise",c[0].replace(" ","_"));\n}};macros.endmouserevise=nullobj;macros.endhoverrevise=nullobj;\n}());