1 // http://creativecommons.org/publicdomain/zero/1.0/
3 // To the extent possible under law, the person who associated CC0
4 // with this work has waived all copyright and related or neighboring
5 // rights to this work.
9 Array
.prototype.contains = function (o
) {
10 return this.indexOf(o
) >= 0;
13 Array
.prototype.lacks = function (o
) {
14 return !this.contains(o
);
17 Array
.prototype.containsSubset = function (o
) {
18 return o
.every(this.contains
, this);
21 Array
.prototype.pushUnique = function (o
) {
27 helmets
: ["hats", "accessories"],
28 wetsuits
: ["tops", "bottoms", "socks", "dresses"],
29 dresses
: ["tops", "bottoms"]
31 Object
.keys(ACNL_WEARABLES
).forEach(function (type
) {
32 BLOCKS
[type
] = (BLOCKS
[type
] || []).concat(type
);
34 Object
.keys(BLOCKS
).forEach(function (k
) {
35 BLOCKS
[k
].forEach(function (v
) {
36 BLOCKS
[v
].pushUnique(k
);
40 function choice (os
) {
41 return os
[Math
.floor(os
.length
* Math
.random())];
44 var flatten1
= Array
.prototype.concat
.apply
.bind(Array
.prototype.concat
, []);
50 var category
= get.bind(ACNL_WEARABLES_CATEGORY
);
51 var wearables
= get.bind(ACNL_WEARABLES
);
53 function isLewd (outfit
) {
54 return ![["wetsuits"], ["dresses"], ["tops", "bottoms"]].some(
55 Array
.prototype.containsSubset
, outfit
.map(category
));
58 function impossibilities (outfit
) {
59 return flatten1(outfit
.map(category
).map(get, BLOCKS
));
62 function possibilities (outfit
) {
63 return Object
.keys(ACNL_WEARABLES
).filter(
64 Array
.prototype.lacks
, impossibilities(outfit
));
70 ps
.push(choice(flatten1(possibilities(ps
).map(wearables
))));
74 function isPosessive (item
) {
75 return item
[0].toUpperCase() === item
[0] && item
.indexOf("'s") >= 0;
78 function isPlural (item
) {
79 return item
.substr(-8) === "headgear"
80 || (item
.substr(-1) === "s"
81 && item
.substr(-2) !== "ss"
82 && item
.substr(-6) !== "cosmos"); // :(
85 function article (item
) {
86 if (item
[0].toUpperCase() === item
[0] && item
.indexOf("'s") >= 0)
88 else if (isPlural(item
))
90 else if ("aeiouAEIO".indexOf(item
[0]) >= 0
91 || ("FHLMNRSX".indexOf(item
[0]) >= 0
92 && item
.split(" ")[0].toUpperCase() == item
.split(" ")[0]))
98 function dblink (name
) {
99 return ["<a target=\"_blank\" href=\"http://moridb.com/items/search?q=",
100 encodeURIComponent(name
),
101 "\">", name
.replace("&", "&"), "</a>"].join("");
104 function litanize (names
, link
) {
105 names
= names
.map(function (name
) {
106 return article(name
) + (link
? dblink(name
) : name
);
108 switch (names
.length
) {
111 names
[names
.length
- 1] = (choice(["and ", "with "])
112 + names
[names
.length
- 1]);
115 if (Math
.random() > 0.5 && names
.length
>= 4) {
116 names
[names
.length
- 2] = "and " + names
[names
.length
- 2];
117 names
[names
.length
- 1] = "with " + names
[names
.length
- 1];
119 names
[names
.length
- 1] = "and " + names
[names
.length
- 1];
124 return names
.join(names
.length
== 2 ? " " : ", ");
129 var wearing
= document
.getElementById('wearing');
130 wearing
.innerHTML
= litanize(o
, true) + "?";
131 // TODO: This often generates > 140 characters. Do I care?
132 // Maybe pick shorter prefixes if it would help.
133 var twitter
= document
.getElementById('twitter');
134 twitter
.href
= twitter
.href
.replace(
135 /&text=[^&]+/, "&text=" + encodeURIComponent(
136 choice(["Going out in ",
137 "Labelle suggested ",
138 "I'll wear "]) + litanize(o
, false) + "."));
140 buttons
= document
.getElementById("buttons");
141 buttons
.className
= "";
142 setTimeout(function () {
143 buttons
.className
= "open";