Magical gene / phase 3

Dhampir — the recessive you can see coming

One copy gives red eyes with glowing whites and nothing else. Two give a white, sun-shy animal with three times the health of an ordinary horse, which cannot be fed by any means and heals only by biting something living.

Crossing two of them

What the homozygote is

CoatPure white, painted absolutely in phase 3 over whatever the melanin genes made — ColorField.set, not add, so a black horse, a cremello and a leopard all come out the same white. It masks, like dominant white, and the coat underneath is still in the genome for a foal to inherit.
EyesRed, at EyeColor.RANK_MAGICAL — above even a depigmented blue, because this is paint rather than pigment. The scleras glow and the iris does not.
BodyHEALTH_MULTIPLIER, SPEED_MULTIPLIER and JUMP_MULTIPLIER, all unclamped — it is genuinely a different animal, not a nudge inside the ordinary band. Size is untouched.
AppetiteDiet.NOTHING. It cannot be fed, and it does not regenerate beside hay and water either — the gated healing checks the diet.
DaylightHalf a heart every two seconds while the sky is clear above it. Not vanilla's ignite: a horse set alight burns down far too fast, and the point of the animal is that it survives the run to the treeline.
HealingOne bite of one living thing: half a heart dealt, three hearts healed, then it leaves that animal alone for a day.

Its gene carrot

Gene key
horsegenetics.dhampir
Alleles
Dhmp n
Outcomes
wild, dhampir-trace, dhampir
Shows when
Dhmp/n — the eyes; Dhmp/Dhmp — everything
Default allele
n
Priority
DhampirGene.PRIORITY — magical band, after every gene that paints
Founders
carriers only — no wild horse is ever one
Random splice
neverspliceable() is false
Model
genetics.genes.DhampirGene; neoforge/server/DhampirHandler and its two goals
Unplayed

The coat, the eyes, the body multipliers and the diet override are covered by DhampirGeneTest and by coat-golden.txt, and the coat has been eyeballed as baked sheets. None of the behaviour has been run in a game — not the burning, not the run for shade, not the hunt. See verification §0-R.

The carrier is the point of the gene

Almost every recessive in this mod is silent in the heterozygote — that is what makes the health loci worth a pedigree. This one is not, and deliberately: a carrier has the red eyes and the glowing scleras, and pays nothing for them. No sun damage, no stat change, an ordinary appetite, an ordinary coat.

That single decision is what makes the locus findable. Two red-eyed horses in a field are a promise, not a lottery ticket, and a breeder who spots one knows exactly what to do with it. A silent dhampir carrier would be a gene nobody would ever meet.

How “cannot be fed” is expressed

Not as a special case. The diet channel resolves the last DietContribution claim in Genes.codeOrder(), and this gene sorts after the diet locus, so its NOTHING simply wins — even over a horse that is also homozygous for the lava diet. DhampirGeneTest pins that, because it is the kind of thing that would be silently wrong: with the channel keeping the first claim instead, a lava-eating dhampir would have eaten lava and the whole cost of the gene would have quietly gone.

The same value carries one step further: HorseCareHandler's gated regen asks HorseDietHandler.canRegenerate, which is false for a NOTHING horse. “Cannot be fed” had to include “does not quietly heal itself standing next to a hay bale”, and it is stated once, in terms of the diet rather than of this gene, so any future gene claiming NOTHING inherits it.

The behaviour, and why it is hand-written

Burning, running for shade and hunting are three things, and none of them is an effects verb. Each would be a verb with exactly one user, and that vocabulary is meant to be things a data-driven gene would reach for. The herd, aggro and lethal-foal behaviours are all hand-written handlers for the same reason, and this follows them.

  • DhampirShadeGoal, at the top goal priority — a burning horse has nothing more urgent to do. It searches a box around itself for the nearest square that is either out of the sky or in water and runs for it, re-looking as it goes so it takes a doorway it passes rather than the tree it first saw. Water counts as shelter, which is what makes “run to water” a real answer rather than flavour.
  • Fences. There is no pathfinding-with-jumps in vanilla horse AI, so while it is running for shelter and its horizontal movement is blocked, it presses jump. A horse's jump strength is a real stat with a real range, so a strong one clears a fence and a Falabella does not — which is the right answer to “up to and including jumping fences if they can”. It is an approximation of intent, not a pathfinder.
  • DhampirHuntGoal — below full health, and only once it is out of the sun. It bites anything living and not undead: the passive animals, creepers and spiders, never a zombie or a skeleton. Two exclusions on top: players (a horse that bit its owner to heal would be a hostile mob wearing a saddle) and other horses (so a herd of them does not eat each other, and one alone in a paddock of horses genuinely has nothing to live on).
It is not a predator, and that is the balance

One bite per animal per day, half a heart, against a cow with five: the cow lives, walks off, and is bitten again tomorrow. So a dhampir kept beside a pen of livestock sustains itself without emptying the pen, and one kept alone starves slowly. The triple health is paid for by needing a herd of something else nearby.

The day is counted on the prey, in HorseCooldownsAttachment under DhampirHuntGoal.BITTEN_KEY — storing it on the horse would mean a growing map of every animal it has ever met, and storing it on the animal is one number that goes away with the animal. It also makes the rule “one bite per animal per day” rather than “per pair”, which keeps two dhampirs from double-draining one cow.

The eyes are claimed twice, on purpose

The gene implements EyeColorContribution, which is the declaration: it is what the eye channel ranks, and what the info panel reads. But the overlay phase runs after the eye channel and is explicitly allowed the last word over the iris — right for the genes it was built for (light's glowing eye, the leopard complex's white sclera rim), wrong here. A dhampir that also carried the leopard complex came out with the rim's ordinary black eye.

So the gene's own overlay paints the iris again. It sorts after every gene that paints, so that is the enforcement of the claim the eye channel makes. Then it marks only the sclera emissive: a glowing iris reads as a lamp, and a glowing white with a hole in it reads as a dhampir. CoatOverlay.markEmissiveSclera works out which texels those are from the coat, the exact complement of tintIris.

One rank was quietly wrong until this gene existed

EyeColor.depigmented() was rank >= RANK_DEPIGMENTED, which is indistinguishable from equality while nothing outranks the depigmented blue. The composer branches on it to run the spread roll — “how much of each iris did the depigmentation actually reach” — so a magical claim answering yes would have given a dhampir one red eye and one ordinary one. Plausible enough that nobody would have called it a bug. It is equality now.

Where it comes from

  • Founders carry, never express. A wild-caught horse is an adult that survived, and an animal that burns in daylight and starves unless it hunts would not have. The founder table lists the carrier and n/n and nothing else — the same rule the health loci use, for a different reason.
  • The random splice cannot roll it. SpliceSafety derives its blacklist from what a combination does to the body, and this one raises every stat it touches — so nothing there would have stopped it handing an unborn foal a horse that cannot be fed. This is exactly the "harm resolution cannot see" that Gene.spliceable() exists to override.
  • The known carrot hands over one copy, never two. The animal is the reward for breeding two carriers; a carrot that produced one outright would skip the whole gene.
Source: common/genetics/genes/DhampirGene.java, neoforge/server/DhampirHandler.java, neoforge/server/DhampirShadeGoal.java, neoforge/server/DhampirHuntGoal.java