Showing posts with label logic. Show all posts
Showing posts with label logic. Show all posts

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

Sunday, 14 June 2015

An Introduction to Boolean Logic

An introduction to Boolean logic, as used in CAOS for C3/DS.

Boolean logic is a kind of algebra used in computer programming that tests whether something is true or false.

There are three main rules with Boolean logic:

Whatever is true, is true.

Whatever is true cannot also be false.

In Boolean logic, there are no shades of gray, there is no maybe, no in-between.

From this, in CAOS, we can set up a number of true-false tests using a conditional (DOIF) statement, and using the modifiers OR, AND and NOT. Conditions can be joined together with AND and OR.

The Venn diagrams below show everything that can exist in the box - the 'universe'. The circles represent certain situations. Red represents our target, and white represents stuff that we exclude.


OR is a term we use when we want to make our true-false test very broad. You can see how it covers situations when either one of the conditions are true, and the area in-between where both situations are true.


AND is a term we use when we want to make our true-false test narrower, because both conditions have to be true for it to work. You can see that only the overlapped area where both conditions are true is highlighted. (e.g. a seed that only sprouts when there is enough soil moisture AND there are fewer than 3 adult plants nearby)


NOT is a term we use when we want to find out when our condition is false. (e.g. a fish critter NOT being in water will suffocate.)

In order for our statement to work, we need to say if this condition is equal to a certain situation, does not equal a certain situation, or if it is greater than a certain situation, or less than a certain situation. A statement which, like OR, gives us a broader definition of 'true' are the commands 'greater than or equal to' and 'less than or equal to'. The symbols below (<>, =, >=, >, <=, < ) and the letters (NE, EQ, GE, GT, LE, LT ) can be used interchangeably.


is equal toEQ=
is not equal toNE<>
is greater thanGT>
is greater than OR equal toGE>=
less thanLT<
is less than OR equal toLE<=


Conditions are read from left to right - unlike in algebra, in CAOS, round brackets don't force the engine to do those tests first. This means that you need to put the first thing first, and 'step along' with the code, doing one check after the other.

Using the ELIF command lets us make another true-false test run directly after the first one has run its course.

It's good practice to put an ELSE command in at the end of a DOIF statement, in case your agent runs up against a situation in which none of your true-false tests apply - and it gives your agent something to do if all else fails.

The last thing to do is to close your DOIF statement with an ENDI.

Further reading
*Laws of Thought - Wikipedia
*CAOS Chaos | Our Simple Object Un-Simplified!
*Nested DOIF? - Hack Shack
*Conditions - Creatures Wiki