Project Special K

(Last update: 2025-04-24 11:05)

New Horizons data
Collected thoughts
Villager submission form

Project Special K

Big list of ideas

Roadmap (sketchy)

Mock-ups and such

Content Filter screen, Villager Species sublist.

Actual screenshots

Special JSON rules

First of all, we allow // and /* */ comments. This is 2024 for crying out loud, get over it.

Values meant to represent strings may be in one of three forms:

  1. just a string ("Kitty")
  2. a map of languages ("EN": "Kitty", "JPja": "ショコラ", ...)
  3. a reference string ("ac:kitty")

Namespaces

Used in reference strings like "acnl:nattytee" or "l10n:yes". Some examples:

Namespaces may be nested by using multiple :.

Any regular string without whitespace in it and at least one : is considered a namespaced reference.

Example JSON content files

Villager: lolly.json

<br />

Furniture: corkboard.json

<br />

Directory structure

With regards to mods

Say what you want about how its developers handled Starbound after it came out, but they knew a thing or two about making games mod-able. And because I (Kawa) am a creature of habit who's copied the general methodology behind Starbound in his own projects several times over, why stop here?

To that effect, the above JSON files are to be stored in one or more archive files, probably .zip by some other name, and in folders under /mods. The base game's data goes in one particular spot with a very specific file name, while the rest (in archives or folders) goes in /mods. Internally, they'll all mirror the same folder structure.

On startup, all asset sources are enumerated, sorted, and checked for dependencies. Then, a master asset list is compiled by going through this sorted list, finding each file's path relative to the asset source, listing the asset's file name, source, and if it's in a .zip archive, its location in said archive.

Here's where the magic happens.

If, during the creation of the master asset list, a file path is found that's already listed, the one that's already there is discarded. Therefore, if you have a villagers/lolly.json in the base game data and a mod provides its own villagers/lolly.json, any attempt to load Lolly will pick the mod's over the base game's.

If the requested file path has a .json extension, we can add an extra bit of magic from Starbound's playbook: we run through the master asset list to find any entry that has that same path with .patch added to the end (villagers/lolly.json.patch), applying each according to RFC 7396, like so:

//This would be something like "mods/example/villagers/lolly.json.patch"
{
  "name": "Pop"
}

For the sake of speed and sanity, this patching should be done while the game itself as a whole is starting up. So when you start it up, the game loads all villager and item data in one go (excluding models, textures, and sounds which are done on demand and can't be patched only replaced), and that's when the patching happens. After all, we're supposed to see them on the title screen so why not?

Stuff like taking Kid Cat's helmet off would involve texture replacements, which are covered by simply having a mod with the proper file paths.

Proposed structure

📀 <asset source root>
├─ 📁 animations
│  └─ 🦾 Animations
├─ 📁 cinematics
│  └─ 📁 <one folder per item>
│     ├─ 📄 JSON
│     └─ 🖼 Textures
├─ 📁 hobbies
│  └─ 📄 JSON
├─ 📁 icons
│  ├─ 📁 items
│  │  └─ 🖼 Textures
│  └─ 📁 reactions
│     └─ 🖼 Textures
├─ 📁 items
│  ├─ 📁 outfits
│  │  └─ 📁 <one folder per type>
│  │     └─ 📁 <one folder per item>
│  │        ├─ 📄 JSON
│  │        ├─ 🦾 Model
│  │        └─ 🖼 Textures
│  ├─ 📁 furniture
│  │  └─ 📁 <one folder per item>
│  │     ├─ 📄 JSON
│  │     ├─ 🦾 Model
│  │     └─ 🖼 Textures
│  ├─ 📁 tools
│  │  └─ 📁 <one folder per item>
│  │     ├─ 📄 JSON
│  │     ├─ 🦾 Model
│  │     └─ 🖼 Textures
│  └─ ...
├─ 📁 music
│  ├─ 📁 bgm
│  │  ├─ 📁 interiors
│  │  │  └─ 🎵 Streams
│  │  ├─ 📁 clock
│  │  ├─ 📁 events
│  │  └─ 📜 Connective data
│  └─ 📁 kk
│     ├─ 📁 live
│     │  └─ 🎵 Streams
│     ├─ 📁 hifi, retro, cheap, phono
│     └─ 📜 Singalong data
├─ 📁 personalities
│  └─ 📄 JSON
├─ 📁 schemas
│  └─ 📄 JSON Schema files
├─ 📁 sound
│  ├─ 📁 ui
│  ├─ 📁 voices
│  ├─ 📁 effects
│  └─ 📜 Connective data
├─ 📁 species
│  └─ 📁 <one folder per item>
│     ├─ 📄 JSON
│     ├─ 🦾 Main model
│     └─ 🦾 Outfit models
├─ 📁 villagers
│  └─ 📁 <one folder per item>
│     ├─ 📄 JSON
│     ├─ 🦾 Specific model, if called for
│     └─ 🖼 Textures
└─ 📁 scripts
   └─ 📜 Lua scripts
(more to be defined)

Some big tricks:

Script example

Take one

Let's assume for a moment we'll use S-Expressions, because I'm a weirdo who likes easy parsers like that.

(say
  (react "smiling")
  "Aaaaand check it out! It's " (an #new)
  (get-reward) "!" (delay 20) #new
  "I hope you like it!"
)
(give-item #to-player the-item)

Basically a direct translation of an entry from GE_Quest_LostProperty_End.msbt.

  1. The an function returns nothing, or rather an empty string "", and sets a few flags for functions like get-reward to catch on to, in this case "we want an article in front of the next word, depending on the next word", and remembers the one argument it was given.
  2. The get-reward function and its ilk then pick up on these flags and gets to figure out in however way if the item name should be "an" or "a". The article flag was set, so the appropriate article, the remembered bit to put inbetween, and the item name are concatenated and returned. If the "capitalize first letter" or "capitalize everything" flags were set, those would be applied first, so "check it out!" (an #new) (capitalize) (get-reward) "!" would return "A new car".

Take two

The above doesn't work well with localization, which is one reason why New Horizons has all the things in that say statement be defined in a localizable MSBT list, but actually giving the item is done in the Event Flow script that invoked it. With that in mind, let's redo this in JSON.

{
  //...
  "GE_Quest_LostProperty_End_033": "<react smiling>Aaaaand check it out! It's <an>[nl]<get-reward>!<delay 20>[nl]I hope you like it!",
  //...
}

And then call it from Lua:

dialogue ("$GE_Quest_LostProperty_End_033");

Works much more like EF+MSBT would.

Silly content ideas

Villagers

ID Name Species Catchphrase Personality Hobby Notes
acnl:wol11 Wolf Link Wolf ruff ruff smug
acs:rco Tom Nook Tanuki yes yes
acs:sza Isabelle Dog
acs:szo Digby Dog
fnaf:frd Freddy Bear superstar jock music
fnaf:chk Chica Chicken party popper peppy music
fnaf:rox Roxanne Wolf rockstar snooty music
fnaf:bon Bonnie Rabbit gutterball lazy music
fps:rbt21 Daisy Rabbit k-ch-ch normal play Doom
fps:rhn09 Duke Rhino bastard jock fitness Duke Nukem via Gianni Matragrano
pnc:dga Sam Dog buddy Sam & Max
pnc:dgb Max Rabbit Sam & Max
psk:bob Bobo Elephant 'owzit cranky nature By zeemczed
psk:cal Callisto Horse
psk:kay Kawa Cat myeh flirty play
psk:bea00 Lissa Bear ya heard peppy By metaregress
psk:brd00 Hoshi Bird snooty nature By metaregress
psk:cat00 Farrah Cat peppy The Firrhna Project
psk:cat01 Jasmine Cat big sister By wyatt8740@tech.lgbt
psk:cat02 Meiki Cat I think normal play By Letrune
psk:cat03 Bea Cat hyahaha snooty education By metaregress
psk:duk00 Vinny Duck WHAT jock play By renamon
psk:elp00 Brunnhilde Elephant hojotoho snooty music By eevee-williams
psk:hrs00 Ray Horse jock By metaregress
psk:mus00 Spritely Mouse beep lazy education By ratSprite
psk:pbr00 Meredith Eagle bwak big sister music By Valoric Starlight
psk:rbt00 Patch Rabbit Joke by Foone
psk:rbt01 Jason Rabbit Joke by Kawa
psk:rbt?? Panken Rabbit Ask them in due time
psk:wol00 Retro Wolf fuzzies smug education By Retrotude

Items

ID Name Category
acs:oppaitee oppai tee tops
ag:shinycatsuit shiny catsuit dress-up
fps:ammobelt ammo belt bag (so it can be worn over a red shirt)
fps:praetorboots praetor boots shoes
fps:praetorhelm praetor helm headwear
fps:praetorsuit praetor suit dress-up

Furniture

ID Name Description
psk:trafficsigncirc Circular Traffic Sign
psk:trafficsignocta Octagonal Traffic Sign Use designs to make it a stop sign or whatever.
psk:trafficsignrect Rectangular Traffic Sign
psk:trafficsignsqua Square Traffic Sign

Namespaces

Map generation

Different Animal Crossing games have their own geographic quirks.

(Document them, dumbass.)

Acres

Acres are 16×16 tile blocks, arranged semi-randomly. (Look into waveform collapse?). In Animal Forest, the screen stops scrolling at the edge of the currently visible acre, then flips to the next when crossed.

Acres include:

In Animal Forest, the entire 5×6 acre map is built from a semi-random selection of tiles. Each acre comes in a set of two variations, three if there's supposed to be a building. Rivers and cliffs always connect. Acres meant for buildings have their buildings spawned on town generation. Since all of these acres are distinct singular 3D models, you can't meaningfully alter the landscape.

In New Horizons, a 5×4 acre map is first filled with the Blank option. A ring of Beach acres is semi-randomly selected -- again, they all connect. On the south edge, two Airport acres are placed in the middle and a Pier at either corner. One river mouth is added to the south edge, and another at either the south, west, or east edge. This will inform how the rivers will flow. Because Blank acres have no model of their own (they consist of 256 individual tiles), rivers and cliffs can have any shape. I'm not sure how this is determined, they might be pre-made.

Bugs and fish spawning

From Wild World on, bugs and fish spawn in acres outside of viewing range, one of each per acre.

Map sizes

Game Columns Rows Starting villagers Max villagers
Animal Forest 5 6 6 15
Wild World 4 4 3 8
City Folk 5 5 6 10
New Leaf 5 4 5 10
New Horizons 7 6 2 10

Map size and generation in Special K

It is suggested that the map in Special K be any size the player wants, from a minimum of 4×4 acres to let's say 16×16, generated using imitations of the various Animal Crossing systems. The maximum amount of villagers may be a function of the map's size.

Variant characters in Special K

It is technically possible for a single character to be defined twice. You could well have two different versions of Isabelle — one based on her New Leaf appearance and one based on New Horizons. This is because one of them would have the fully-qualified ID acnl:sza while the other would be acnh:sza. I suppose the content filter settings would have to prevent both from spawning, or perhaps the New Leaf map generator will place a Town Hall that includes one version of Isabelle, while the New Horizons generator will place a Resident Services with the other. In fact, Town Hall and Resident Services can share an ID too, in the same way.

Things to do each day

Be it at 5:00 AM or when you first start the game that day, in no particular order:

  1. Spawn a rock if there are less than six on the map.
  2. Pick a money rock.
  3. Reset luck effects.
  4. Move around villagers in some way.
  5. Pick loadout for Nook's Cranny and Able Sisters.
  6. Spawn special visitors.
  7. Regrow the animal tracks.
  8. Progress on building constructions.
  9. Grow flowers and trees.
  10. Place up to four fossils if less than six are already there.
  11. Place a gyroid if less than four are there.
  12. Place a small rock if there is none.
  13. Remove glowing spot if one, place a new one.
  14. Decide on weather pattern for the day.
  15. Check if it's Sunday, update the stalk market if it is.
  16. Maybe place an item in the recycle box (45% chance, only if less than ten).
  17. Reset daily flags.