luvcraft/critters.lisp
The animal's own deterministic identity: every choice it makes is a hash of this seed and how many choices it has already made.
One individuated animal walking the block world.
Return a stable 0..1 reading for one small animal choice.
The same three integers always answer the same way, which is what lets a wandering animal be reproducible without carrying a random state around.
Return a stable 0..1 reading for critter's current decision and salt.
Move critter to its next decision, so its readings are all new ones.
The critter protocol proper.
Advance critter's behaviour and body by seconds in world.
This is the only part of an animal a new species really has to think about;
terrain contact is the shared body protocol and appearance is
map-critter-boxes.
Call function for each textured box of critter's model.
Each call passes the box centre and half extents in the animal's own frame -- X to its right, Y up from the ground it stands on, Z ahead of it -- and the atlas tile its faces wear: (X Y Z HALF-X HALF-Y HALF-Z TILE). The emitter turns the boxes by the critter's yaw; a model never sees world coordinates.
How many boxes map-critter-boxes emits for critter, at most
CRITTER-MODEL-BOX-LIMIT.
The keyword naming critter's species.
Return the lift and yaw a rider is swayed by, as critter moves under them.
An animal walking is not a platform gliding: whoever is sitting on it rides its gait. (VALUES LIFT YAW), both small and both zero for an animal which does not say otherwise.
Make a species animal standing on the ground at cell X,Y,Z, or NIL.
species is a keyword, so a new animal joins the world's population by adding
one EQL method here rather than by editing a spawn table. A method returns
NIL when the site does not suit it: this is where an animal says what ground
it lives on and how much room it needs.
The turtle: slow, deliberate, and unbothered. It walks a while, stops a while, turns away from what it bumps into, and never jumps.
Where a turtle's four legs stand: right of, and ahead of, its centre.
A walking turtle moves its legs in diagonal couplets, so the two legs of each diagonal share a gait phase and the other pair is half a stride behind.
How far this turtle has walked, in strides: the phase its legs swing on, kept as distance rather than time so a stopped turtle stands still.
A small, slow, deliberate animal with a domed shell.
Send turtle off on a new heading after it has walked into something.
Turning is what a turtle does slowly and visibly, so the heading is a wish and the yaw follows it at a bounded rate.
A blocky animal is a stack of slabs: a stepped carapace over a pale plastron, a head on the front, a stub of tail behind, and four legs which swing and lift on the gait phase the walk has accumulated.
The belly plate, then a carapace of three steps: the dome is made of slabs because this is a world of blocks, but each step is deep enough to read as a shell rather than as a stack of planks.
A resting turtle draws its head back toward the shell; a walking one cranes it a little further out on every stride.
How far ahead of its own yaw a rider may point a turtle, in radians.
Bounded, because a turtle turns at its own rate: without this, a held rein would run the wanted heading far past what the animal can follow and leave it turning long after the rider let go.
A ridden turtle sets its own mind aside and goes where it is pointed.
Urging renews its walking spell rather than replacing its gait, so a ridden turtle walks and stops like a turtle: slowly, and in its own time.
A walking turtle rocks its rider once a stride, and rolls a little with it.
The roll has to be read as a small yaw, because a camera pose here carries no roll: what is left of a waddle is the shell's nose swinging across the direction of travel.
Stand a turtle on grass or sand with clear air over it.
The population: the session-owned semantic object which holds the animals alive around the player, advances them, and keeps them company.
The living animals near the player, and how to find more.
Return the number of animals alive in population.
Add critter to population unless it is already full, returning it or NIL.
Advance every animal in population by seconds in world.
Drop the animals of population which have left the neighbourhood of X,Z.
Return the standing height on world's resident column at X,Z, or NIL.
A column only offers a site when it is resident: an animal must not be conjured onto terrain which has not been generated yet.
Keep population's animals living on resident terrain near X,Z.
Called once a frame beside residency: animals which have wandered out of the neighbourhood are forgotten, and a couple of deterministic candidate sites are offered to the population's species until it is as full as it wants to be.
Looking at an animal. The block world answers a ray with a lattice traversal; an animal is not on the lattice, so its body answers for itself. Its body for this purpose is the same upright box its feet walk on, not its model: what the player aims at is the animal, not its left hind leg.
Return how far along a ray it enters critter's body, or NIL if it misses.
origin and direction are vec3 values in continuous cell coordinates, and
direction is assumed to be a unit vector, as a camera basis gives it.
Return the nearest animal of population on the ray, and its distance.
The render product: one dense vertex array over the block surface pipeline. A critter's boxes are not voxel faces, so they classify none of their edges: the fragment stage leaves their silhouette alone and shapes their surface from the material's own relief.
Return the ambient shade of a critter face with world normal lane normal-y.
An animal carries no baked neighbourhood, but its underside is genuinely more occluded than its shell, and saying so is what keeps it from reading as a paper cut-out standing on the grass.
Return critter's normalized sky and block light, sampled where it stands.
How much of the world one whole critter atlas tile covers, in cells.
A terrain material tiles once per cell, so a block face can simply take the whole tile. A critter's faces are all different fractions of a cell, and stretching one tile across each of them would print scutes the size of the shell on its top and smear the same scutes into bands around its rim. Each face instead takes the centred fraction of its tile which keeps texels roughly the same size everywhere on the animal.
Return how much of face's tile the face's two in-plane extents deserve.
The in-plane axes are the ones block-face-local-uv projects onto, read from
the same face normal it reads.
Append one of critter's model boxes, turned by its yaw, to vertices.
The box arrives in the animal's own frame; the yaw rotation here is the only place a critter model meets world coordinates.
Append critter's whole model to vertices, lit where the animal stands.
Build the block-pipeline vertex stream for population's animals.
(critter world seconds)Advance CRITTER's behaviour and body by SECONDS in WORLD. This is the only part of an animal a new species really has to think about; terrain contact is the shared body protocol and appearance is MAP-CRITTER-BOXES.
(critter function)Call FUNCTION for each textured box of CRITTER's model. Each call passes the box centre and half extents in the animal's own frame -- X to its right, Y up from the ground it stands on, Z ahead of it -- and the atlas tile its faces wear: (X Y Z HALF-X HALF-Y HALF-Z TILE). The emitter turns the boxes by the critter's…
(name value &key type quantity documentation)Define an ordinary constant which publishes its represented quantity. The runtime value remains the unwrapped result of VALUE. TYPE states its Common Lisp representation independently of QUANTITY's semantic declaration; VALUE-DECLARATION-FOR retrieves the latter at definition boundaries.
How many animals may live around the player at once.
The most boxes any critter model may emit; the vertex buffer is sized for it.
Multiplication and scalar scaling.
One individuated animal walking the block world.
(x y z)A standard class whose annotated slots retain quantity declarations. Slot access and instance representation remain ordinary CLOS. The metaclass only makes definition-time meaning inspectable and inheritable. #OXBSAY
(critter)(critter)(critter)(critter)(critter)(critter)(seed index salt)Return a stable 0..1 reading for one small animal choice. The same three integers always answer the same way, which is what lets a wandering animal be reproducible without carrying a random state around.
Addition over compatible quantities.
Division of two represented quantities.
(critter salt)(critter)(critter)How many boxes MAP-CRITTER-BOXES emits for CRITTER, at most +CRITTER-MODEL-BOX-LIMIT+.
(critter forward turn seconds)Ask CRITTER to walk FORWARD and turn TURN over SECONDS, as a rider does. FORWARD and TURN are wishes in -1..1, not velocities: what the animal makes of them is the animal's business, and one which ignores its rider simply has no method here.
(critter)Return the lift and yaw a rider is swayed by, as CRITTER moves under them. An animal walking is not a platform gliding: whoever is sitting on it rides its gait. (VALUES LIFT YAW), both small and both zero for an animal which does not say otherwise.
(species world x y z seed)Make a SPECIES animal standing on the ground at cell X,Y,Z, or NIL. SPECIES is a keyword, so a new animal joins the world's population by adding one EQL method here rather than by editing a spawn table. A method returns NIL when the site does not suit it: this is where an animal says what ground it lives on and how…
How fast a turtle swings toward the heading it wants, in radians a second.
How far a turtle walks per full stride, which sets its leg cadence.
Where a turtle's four legs stand: right of, and ahead of, its centre. A walking turtle moves its legs in diagonal couplets, so the two legs of each diagonal share a gait phase and the other pair is half a stride behind.
A small, slow, deliberate animal with a domed shell.
An Org headline with its section and subheadings.
(turtle)Logical negation of one test or raw truth value.
(turtle)Test whether one compatible scalar is less than another.
(target current)The maximum of compatible quantities.
Subtraction or unary negation.
The minimum of compatible quantities.
Logical conjunction of tests and raw truth values.
Logical disjunction of tests and raw truth values.
(body world axis distance)The componentwise absolute value of a raw value.
Test whether two compatible scalars are equal.
How fast a rider may swing a turtle's heading, in radians a second.
How far ahead of its own yaw a rider may point a turtle, in radians. Bounded, because a turtle turns at its own rate: without this, a held rein would run the wanted heading far past what the animal can follow and leave it turning long after the rider let go.
(world x y z)Return one site as BLOCK and :RESIDENT, or NIL and :ABSENT. This sparse world-coordinate accessor constructs coordinate descriptors and a chunk lookup key. It is appropriate for inspectors, ray hits, collision probes, and sparse interaction. Algorithms over many cells should select a chunk/domain once and use…
(world x y z)How far from the player a new animal may appear, in cells.
How near the player an animal may never simply appear, in cells.
How far an animal may wander from the player before it is forgotten.
The living animals near the player, and how to find more.
(population)(population critter)(population world seconds)(population x z)Test whether one compatible scalar is greater than another.
(world x z)Return the standing height on WORLD's resident column at X,Z, or NIL. A column only offers a site when it is resident: an animal must not be conjured onto terrain which has not been generated yet.
(block)(population world x z)Keep POPULATION's animals living on resident terrain near X,Z. Called once a frame beside residency: animals which have wandered out of the neighbourhood are forgotten, and a couple of deterministic candidate sites are offered to the population's species until it is as full as it wants to be.
Test whether one compatible scalar is at least another.
The non-negative remainder of integer division.
(site)(site)(site)(critter origin direction max-distance)Return how far along a ray it enters CRITTER's body, or NIL if it misses. ORIGIN and DIRECTION are VEC3 values in continuous cell coordinates, and DIRECTION is assumed to be a unit vector, as a camera basis gives it.
Test whether one compatible scalar is at most another.
(population origin direction max-distance)(normal-y)Return the ambient shade of a critter face with world normal lane NORMAL-Y. An animal carries no baked neighbourhood, but its underside is genuinely more occluded than its shell, and saying so is what keeps it from reading as a paper cut-out standing on the grass.
(critter world)(world x y z)How much of the world one whole critter atlas tile covers, in cells. A terrain material tiles once per cell, so a block face can simply take the whole tile. A critter's faces are all different fractions of a cell, and stretching one tile across each of them would print scutes the size of the shell on its top and…
(face half-x half-y half-z)Return how much of FACE's tile the face's two in-plane extents deserve. The in-plane axes are the ones BLOCK-FACE-LOCAL-UV projects onto, read from the same face normal it reads.
(face corner)Project CORNER onto FACE's plane as tile-local UV coordinates. The rule is read from the face's own outward normal rather than its name: horizontal faces map world X,Z straight across the tile, and lateral faces keep the world-horizontal axis as U while flipping world Y into V so tiles hang upright.
(vertices critter box-x box-y box-z half-x half-y half-z tile
sky-level block-level)Append one of CRITTER's model boxes, turned by its yaw, to VERTICES. The box arrives in the animal's own frame; the yaw rotation here is the only place a critter model meets world coordinates.
(tile &optional (domain *block-atlas-tile-domain*))(vertices px py pz local-u local-v shade nx ny nz
sky-level block-level emission tile
edge-u-low edge-u-high edge-v-low edge-v-high)Append one interleaved vertex without constructing tuple objects. The fourth lane carries normalized raw light readings, not an art-directed bake: shader edits can change the response curve without remeshing the world. The final two scalars carry the atlas tile offset under the atlas mapping and the face's four…
(vertices critter world)(population world)
The animals of the block world, and the first of them: a turtle.
#KTRMAO is the design; this is what it turned into.
A critter is one of the genuinely individuated entities of #F6R9QA rather than a reading of a dense field. It owns a position, a heading, a small mind, and an independently inspectable lifetime, and there are few enough of them that identity costs nothing: each animal is an ordinary CLOS instance and each species is a class. What stays dense is the per-frame render product -- one interleaved vertex array over the ordinary block atlas and block surface pipeline, exactly like the smash fragments.
Three protocols meet in an animal:
advance-critteris its own behaviour, the only part a new species must really think about; the body protocol in SIMULATION.LISP is its contact with terrain -- the same one-axis-at-a-time AABB sweep the player controller walks on; andmap-critter-boxesis its body as seen, a handful of textured boxes in a local frame which the emitter here turns by the critter's yaw.Nothing an animal decides comes from a random state. A critter's choices are hashed from its seed, so a turtle wanders the same way in the same world on every machine and in every replay, the same discipline the terrain source and the fragment bursts already keep.