Showing posts with label critter. Show all posts
Showing posts with label critter. Show all posts

Monday, 22 December 2025

From Agents to a Living Metaroom: a thought experiment

I think of metarooms as a tiny home for my creatures —a place where they can explore, play, and stay happy and healthy. 

Stocking a metaroom

 When I imagine a metaroom, I think about the physical needs of a creature:

I've noticed that having a variety of objects that creatures can interact with in many different ways can help creatures' personalities come out. 

When adding resources, I also think about how they will be replenished: Will objects be vended (smart vended?), or come from a plant? And if from a plant, are they "r-type" (short-lived, like grass) or "K-type" (long-lived, like a tree)? These choices can help build in a safety net for creatures.

Don't worry too much about the player 

I don't worry too much about thrilling the player - people can enjoy a variety of aspects such as beautiful art, nostalgia, finding a secret, or watching seasonal changes in a metaroom. If the norns are well-cared for by the room, hopefully anyone I share it with will enjoy it as a habitat. 

Case study: Mushroom Forest

For example, in my Mushroom Forest (2020), I had a collection of agents.

The sharmflower, which un-grew and re-grew, produced fruit.

The feature mushroom produced food

The pinecone (a toy) produced seeds, similarly to Freyla's Puzzleball, and also on a timed basis.

The snail was produced automatically by an invisible nest (vendor-style again), crawled around, was fun and edible for creatures, and eventually died. 

It's not a true ecosystem - but that's ok. Independent agents are stable, but may not appear lifelike, while interdependent agents are interesting, but risky. I found the snail and feature mushroom went a long way to making the metaroom interesting to me. I'm really proud of the fact that none of the code in the Mushroom Forest is 'black-box'.

Supporting an ecosystem 

Each item in the Mushroom Forest was designed to support life, but none of them interacted with each other in an ecosystem - none of them referenced each others' classifiers for hunting each other, supporting pollination, or even noticing each other.

Even the ecosystems that came with the game were notoriously unstable - population checks were sometimes non-existent or hunters too aggressive, which could make things go wrong quickly.

It feels like it's key to support the bottom of the food web first - in previous metaroom tweaks, I have made this easier with "mother" agents (but seed banks would also be a viable option). If food items, plants and non-predator animals are abundant, any predators shouldn't need help to maintain a population. Targeting the support to the base of the food web may help the rest take care of itself.

If I were to try to make an interactive metaroom, I might start by linking just a few agents. For example, a plant could produce seeds that herbivores eat, or a predator could hunt a herbivore. Even these small interactions can make the room feel alive and give the ecosystem a sense of flow. Starting simple would let me see what works and gradually build toward a more complex, interactive environment. 

Planning for surprises

I've learned that my metaroom will never be perfectly predictable, so I try to think of ways it can recover on its own. Norns move things, players may use the metaroom in unexpected ways, and agents can glitch or disappear. Wolfling mode can also make small problems easier to notice.

Rather than aiming for a perfectly self-balanced ecosystem, I ask myself: ‘What would happen if something went wrong?’

  • Seed banks, vendors, nests or 'mother' agents can help a room recover - if they target the base of the food web.
  • Diversity in critters, bugs and plants (having options) gives ecosystems resilience.
  • Using a variety of living strategies means not all agents fail the same way - and would allow for complex behaviours for featured/keystone critters. 

While there are more sophisticated critter tutorials these days, these strategies can be computationally expensive, and TTAR can also be used to create eating behaviours. Simpler systems can still produce interesting emergent behaviour.

Wrapping up

I don’t have all the answers, and that’s part of the fun. Designing a metaroom is as much about experimenting, noticing what happens, and enjoying the surprises as it is about planning or coding.

These are just some of the things I’ve been thinking about as I've tinkered with agents. Sometimes ideas work, sometimes they don’t—and that’s ok. The creatures, the interactions, the small emergent behaviours—that's all part of it.

For now, I’ll keep adding, observing, and seeing what emerges. Maybe someone else will try the same, or come up with something completely unexpected. That’s the beauty of these tiny worlds: they’re never finished.

Sunday, 18 May 2025

Roaming in C3 critters

 Roaming in C3 critters is almost considered an 'else' state after everything else is handled - it is a normal state that critters return to as a default behaviour.  But roaming isn’t just filler—it’s an integral part of the critter's behaviour tree that ensures believable, conflict-free, and performance-friendly actions.

The normal logic flow in the timer script

 Typically, roaming is switched on by OV00 (State) being 0, and it is considered the last step in the normal logic flow in the timer of most C3 critters - which typically follows this pattern:

  1. increase age
  2. decrease energy
  3. if old enough, increase sex drive
  4. drown in water - lose energy rapidly
  5. if low on energy (sometimes also OR if too old) flag for death
  6. if hungry flag to get food
  7. if sex drive high, flag to mate
  8. obstacle checking - sometimes also water-shyness
  9. if flagged for death go to die subroutine
  10. if flagged to get food, get food
  11. if flagged to mate, mate
  12. if flagged to roam, roam 

You’ll notice roaming comes last—it’s what a critter does when it’s not busy trying to survive, eat, mate, or die. Think of it as a "what now?" behaviour that kicks in when all else is calm.

The logic flow in the timer script being arranged around two phases - first flagging, then checking the flags - is an example of a behaviour tree. This has the benefits of avoiding conflicts in behaviour, creating a predictable flow, allowing for lifelike complexity (flagging for multiple behaviours allows the system to choose between them with DOIF logic), while being performance friendly.

Before you move

Navigating the World: How Obstacle Checking Works

In a world full of walls, slopes, water, and other creatures, critters need a way to avoid running headfirst into trouble. That’s where obstacle checking comes into the timer's logic flow—just before the critter decides what to do next, and crucially, before it performs any roaming behaviour.

Obstacle checking happens between flagging and acting. This allows the critter to alter or cancel its next intended action if something is physically in the way, preventing it from trying to move through a wall.

Direction Memory: How Critters Know Where They're Going

It's also important to understand how a critter "remembers" which direction it's trying to go in. This is usually done using two object variables:

  • OV10 – Stores the left/right movement direction

  • OV11 – Stores the up/down movement direction

These values help the critter maintain consistent direction between ticks of the timer script—even if it gets distracted or interrupted (say, by a curious Norn picking it up). They’re essential to making movement look fluid and purposeful.

Roaming: More Than Just Wandering

The roaming subroutine itself is built on a layered system of nested subroutines, creating lifelike complexity without chaos. The main roaming call includes:

  • subr roam

    • subr vect – Picks a random direction

    • subr anim – Sets the correct walking animations based on direction

    • subr move – Applies motion using direction data

By nesting logic like this, developers avoid redundancy and reduce bugs—especially those caused by copy-pasting the same code across multiple scripts.

Interestingly, even “special” behaviours like eating or mating briefly use the roaming-related nested subroutines vect anim and move. This helps reset the critter’s motion naturally, allowing it to continue behaving in a believable way after completing a focused task.

1. subr roam: The Control Hub

At the top of the roaming behaviour stack is the roam subroutine. Think of this as the orchestrator—it's the entry point that decides whether and how the critter should move.

The roam subroutine typically does three things:

  • Runs a random chance check: This is used to occasionally trigger special roaming behaviours specific to a species. For instance:

    • A hedgehog might randomly decide to burrow.

    • A grasshopper might chirp.

    • Other critters might sniff, pause, or perform ambient animations.

    These special behaviours give each critter type its own personality and make idle time feel alive.

  • Changes direction occasionally: Using another random roll, the roam routine may decide to alter the creature's current path, which keeps its motion from looking too linear or mechanical. 

  • Calls the three nested subroutines: Once direction and behaviour have been decided, roam hands off control to the nested logic for handling movement:

    • subr vect

    • subr anim

    • subr move

2. subr vect: Choosing a Direction

The vect subroutine is where direction gets set. This subroutine simply:

  • Picks a new random direction for the critter to head toward.

Because this direction change happens at the end of a completed behaviour cycle (e.g., after eating, mating, or completing a wander loop), the shift in direction feels natural and not abrupt.

The randomness is constrained enough that it avoids chaotic zig-zagging but ensures that the critter won’t pace in a straight line until it hits a wall.

3. subr anim: Choosing the Right Animation

Now that we know where the critter wants to go, it’s time to make it look like it’s going there. That’s where anim comes in.

This subroutine:

  • Selects the correct walking or movement animation based on the current direction (OV10, OV11).

  • Ensures that the visual feedback matches the movement intent—a critter moving left plays a "walk left" animation, and so on.

Animations in Creatures 3 are not just eye candy—they’re essential for readability and believability.  anim ensures the visuals reflect the internal logic.

4. subr move: Making the Critter Move

Finally, move applies the logic that turns direction and intent into actual motion.

This subroutine:

  • Adjusts the values of OV10 and OV11, moderating the direction based on the new vector chosen in vect.

  • Calculates the velocity the critter should move at.

  • Applies motion by setting the velocity directly.

Where vect decides where to go, and anim decides how it looks, move is what actually causes the critter to move on-screen.

Together, these three nested subroutines called by roam allow each creature to wander its environment convincingly, which is why they are also called in the gfod and mate subroutines.

Saturday, 10 May 2025

Mating behaviour in C3 critters

Mating in C3 critters is a special state which is typically controlled by sex drive (OV21) increasing past a threshold (when they are old enough), and by a flag being set - although food is considered more important.

The normal logic flow in the timer script

 Typically, mating is switched on by OV00 (State) being 6, and it is an intermediate step in the normal logic flow in the timer of most C3 critters - which typically follows this pattern:

  1. increase age
  2. decrease energy
  3. if old enough, increase sex drive
  4. drown in water - lose energy rapidly
  5. if low on energy (sometimes also OR if too old) flag for death
  6. if hungry flag to get food
  7. if sex drive high, flag to mate
  8. obstacle checking - sometimes also water-shyness
  9. if flagged for death go to die subroutine
  10. if flagged to get food, get food
  11. if flagged to mate, mate
  12. if flagged to roam, roam

The logic flow in the timer script being arranged around two phases - first flagging, then checking the flags - is an example of a behaviour tree. This has the benefits of avoiding conflicts in behaviour, creating a predictable flow, allowing for lifelike complexity (flagging for multiple behaviours allows the system to choose between them with DOIF logic), while being performance friendly.

Mating strategies

Interestingly, some critters have male and female types (OV06 being 0 or 1) and find an opposite sex mate to impregnate (reusing some code from the hunting food behaviour, as in the hedgehog and the dragonfly), and some simply reproduce parthenogenetically (without needing to find or hunt a mate) when their reproductive drive is past a certain threshold (and they have enough energy), such as the hoppity.  Additionally, even some critters that find mates and get pregnant only use pregnancy as a binary state (pregnant or not) rather than having a gestation period.

Reproduction Step-by-Step: a Hedgehog in Love

Let’s walk through how a hedgehog goes from carefree youth to proud parent:

1. Maturity and Sex Drive

  • The hedgehog ages via the ov01 counter.

  • Once it passes age 1000 and enters adulthood (ov05 = 2), it starts building sex drive (ov20).

  • This happens gradually, simulating the onset of reproductive maturity.

Fun detail: The "youth" hedgehog is actually removed and replaced by an adult version—a trick to avoid bounding box errors.

2. Seeking a Mate

  • When sex drive (ov20) exceeds 200, the hedgehog changes state to "Find Mate" (ov00 = 2).

  • It searches nearby using genus and species markers (ov47, ov48, ov49) for a compatible mate of the opposite sex.

3. Mating Process

  • If a suitable mate is found, the state changes to "Mate" (ov00 = 6). If a mate is not found, the hedgehog returns to roaming behaviour. An error in this logic, fixed in the Norn Woodland Fix Patch, is that ov16 should not be set to null twice before calling the find subroutine, and that hedgehogs are curiously undiscerning of their target's gender when seeking a mate.

  • The mate subroutine verifies gender compatibility and, if successful, sets the pregnancy counter (ov70 = 1) for females.

  • The sex drive (ov20) is reset to 0 after mating.

4. Pregnancy and Birth

  • The pregnancy counter (ov70) increases over time.

  • When it exceeds 10, the hedgehog enters "Give Birth" state (ov00 = 7).

  • The layg subroutine handles the birthing process, spawning new baby hoglets.

Once their part in the mating ritual is finished, the parent hedgehogs return to roaming (ov00 = 0), ready to begin the cycle again.

Key Variables for Reproduction

  • ov06 – Gender: 0 = female, 1 = male

  • ov00 – State:

    • 0 = Roam

    • 2 = Find Mate

    • 6 = Mate

    • 7 = Give Birth

    • 99 = Die

  • ov20 – Sex drive level (increases with age and plays a role in determining when a hedgehog seeks a mate).

  • ov70 – Pregnancy counter: When it’s greater than 0, the hedgehog is pregnant.

  • ov01 – Age counter: When the hedgehog reaches a certain age (1000), the script starts checking for mating behaviour.

  • ov16 – Target (food or mate): Used to track the hedgehog’s current mate.

  • ov05 – Life stage (1 = youth, 2 = adult).

  • ov02 – Energy: Used for survival but also affects mating behaviour. If low, the hedgehog seeks food.

  • ov73 – Hunger threshold: If energy drops below this, the hedgehog seeks food.

Visualizing the Process:

  • Roam (ov00 = 0) → Find Mate (ov00 = 2) → Mate (ov00 = 6) → Pregnancy (ov70 1-10) → Give Birth (ov00 = 7) → Roam (ov00 = 0)

This flow ensures that hedgehogs mature, seek mates, reproduce, and care for their young, all while adhering to a life cycle that mirrors natural behaviours. Note that this is laser-focused on only the reproductive cycle, and seeking food takes priority in the hedgehog's mind - it cannot search for a mate until it has first checked if it is hungry.

 Bugs 

One particularly odd case is the dragonfly, whose mating behaviour appears to be a bit of a bug—literally and figuratively. While it starts the process of finding a mate using the same targeting logic as other critters, it sometimes treats them as prey instead of a partner—approaching the intended mate only to eat them rather than complete the mating process. This quirky behaviour likely stems from overlapping use of the ov16 target variable, the fact that dragonflies hunt their own whole genus, the fact that dragonflies are more likely to be in contact with energy-draining water bodies, and a bug in state transitions, causing the dragonfly’s natural instincts to blur in a way that's more predatory than romantic. This bug is fixed in the Steam and GOG.com editions of Creatures Exodus.

Conclusion: Added realism and depth

While the mating logic in Creatures 3 operates entirely behind the scenes, it plays a fun and crucial role in making the ecosystem feel alive, real and self-sustaining. It’s not something players typically see directly—but it quietly governs when critters reproduce, how they prioritise needs, and how population dynamics shift over time, such as when a norn develops a taste for hedgehogs.

At the heart of this system is a behaviour tree structure: a two-phase loop where the critter first flags possible actions based on internal variables (like hunger or sex drive), and then acts based on priority. This design avoids conflicting behaviours, keeps things running efficiently, and allows complex decision-making to emerge from relatively simple rules.

This kind of background scripting, although largely hidden from view, adds realism and complexity to your creatures’ world—creating behaviours that feel organic, even when driven by simple variables and checking a list of possible states.

Sunday, 4 May 2025

Hunger and Hunting in C3 Critters

Eating in C3 critters is a special state which allows them to keep living, and is a multi-step process beginning with low energy triggering the search, searching for food, finding food and hunting for food.

The normal logic flow in the timer script

Typically, getting food is switched on by OV00 (State) being 1, and it is the first step in the normal logic flow in the timer of most C3 critters - which typically follows this pattern:

  1. increase age
  2. decrease energy
  3. if old enough, increase sex drive
  4. drown in water - lose energy rapidly
  5. if low on energy (sometimes also OR if too old) flag for death
  6. if hungry flag to get food
  7. if sex drive high, flag to mate
  8. obstacle checking - sometimes also water-shyness
  9. if flagged for death go to die subroutine
  10. if flagged to get food, get food
  11. if flagged to mate, mate
  12. if flagged to roam, roam 

The logic flow in the timer script being arranged around two phases - first flagging, then checking the flags - is an example of a behaviour tree. This has the benefits of avoiding conflicts in behaviour, creating a predictable flow, allowing for lifelike complexity (flagging for multiple behaviours allows the system to choose between them with DOIF logic), while being performance friendly.

The gfod Subroutine: Your Critter’s Inner Forager

When it’s time to eat, the gfod (get food) subroutine takes over. It’s more than a simple “go to food” instruction—gfod is a nest of smaller routines: find, hunt, vect, anim, and move, all working together to give your critter a believable foraging pattern, while avoiding the common coding error of repeating yourself.

Let’s walk through the full food-finding journey:

Step 0.5: The Critter Gets Hungry

Every time the timer runs, the critter’s energy (OV02) drops by 1. If it falls below the hunger threshold (typically stored in another variable, OV73), the critter flags itself as needing food—and gfod is called into action.

Step 1: gfod — Search Phase Begins

This is where the critter starts searching for food:

  • Temporary variables (VA47, VA48, VA49) define what kind of food it’s looking for—based on family, genus, and species. A 0 means “any”.

  • If there’s already a food target saved in OV16, the critter jumps straight to hunting it with hunt.

  • Otherwise, it calls the find subroutine to scout for the nearest edible object.

Bonus: Some critters, like hedgehogs, have varied diets—gfod can be expanded to look for secondary food types if the favourite isn’t found. (Just be careful they don’t accidentally target themselves if the critter is looking for its own genus in general.)

Step 2: find — Locating the Nearest Snack

In this subroutine, the critter:

  • First sets up a temporary variable to hold a massive number (VA99 = 99999999) and then changes that to be the shortest distance found from a target food item (VA58).

  • Scans nearby objects using esee, filtering by the desired food types.

  • Calculates the squared distance to each object with the Pythagorean theorem.

  • If something closer is found, it updates the new, closer target (VA58) and sets OV16 accordingly.

  • If nothing is found, the critter gives up—for now—and sets the target to null before changing its direction.

Step 3: hunt — Move to Target and Eat

Once a target is locked in, the critter enters hunting mode:

  • It checks that the target (OV16) is still valid and hasn't disappeared.

  • It figures out the direction to move by comparing its own coordinates with the target’s, adjusting movement vectors (OV10 and OV11) accordingly.

  • When it reaches the target—touching it—the critter switches its state to the next one in the main logic's behaviour tree and tells the food it’s been eaten (mesg writ OV16 12) and adjusts its own energy. (targ ownr subv ov02 ov72)

Ants behave a bit differently here: instead of eating on the spot, they pick up the food (OV18 tracks the carried food) and head back to the nest, with a message (mesg writ OV16 4) sent to the food to signal collection.

Step 4. Return to roaming

The critter reuses a little roaming behaviour after it has been hungry, got food, found food, and hunted food successfully to randomly change direction and start moving - and the behaviour tree will continue on with other activities.

Conclusion: A Background Mechanic With Quiet Complexity

While critters eating is a simple background function in Creatures 3, it's a surprisingly intricate part of what keeps critters behaving believably. From hunger detection to food targeting and pursuit, the eating system is built with clear logic, modular structure, and enough flexibility to support varied diets, differences between critters, and environmental challenges.

It’s not flashy, and it rarely calls attention to itself if it's done well—but it quietly supports the broader simulation and creates a vibrant world for creatures to live in. By using a behaviour tree model, flag-based decisions, and reusable subroutines, the developers created a system for critters that’s both efficient and extensible.

Understanding how critters eat offers a window into how even the “invisible” mechanics in Creatures 3 are carefully crafted. It’s a reminder that beneath the surface of every lifelike action is a system designed to keep the world moving.

Moving on

Saturday, 6 June 2015

Gnarler Water-Shyness

The following code is in the Gnarler timer script, which helps keep the Gnarler out of the Ettin Desert's pond by using the water CA. It isn't held in a subroutine.

**keep away from bodies of water
*Do this if you're in a room.
doif room targ ne -1
*Do this if you smell any water at all.
doif prop room targ 5 ge 0.00001
*Look for the room next to this one that smells less like water.
setv va00 lorp room targ 5 0
*Go towards the centre of the room that smells less like water.
setv va01 torx va00
*If the less-smelly room is on your left and you were going right, turn around.
doif va01 lt 0 and ov10 gt 0
negv ov10
*or else, if the less-smelly room is on your right and you were going left, turn around.
elif va01 gt 0 and ov10 lt 0
negv ov10
*end the turning around doif
endi
*end the 'smelling water' doif
endi
*end the 'I'm in a room' doif
endi


AquaShee's Crabs use a reversed version of this to help them seek out water sources.