LOG IN
Docs
By Opus

Units And Structures

How a tank, an infantry squad, and a power plant share the same Object framework but behave differently via KindOf flags and module loadouts.

A Crusader tank, a Ranger, and a power plant are the same kind of thing to the engine. Each is an Object stamped from a ThingTemplate, carrying a BodyModule, a KindOfMask, and a list of behavior modules. Nothing in the Object class says "I am a building" or "I am a vehicle." The differences live entirely in which kindof bits are set and which modules got attached at construction. Change the bits and the modules and a tank becomes a turret, or a barracks becomes a walking robot.

KindOf as type discriminator

The kindof mask is a bitset, not an int. A template routinely has ten or twelve bits set. ThingTemplate::isKindOf is a simple bit test:

// GeneralsMD/Code/GameEngine/Include/Common/ThingTemplate.h:401
Bool isKindOf(KindOfType t) const
{
  return TEST_KINDOFMASK(m_kindof, t);
}

The flag enum lives in KindOf.h. The important discriminators for this article sit early in the file:

  • KINDOF_STRUCTURE — a building (line 52)
  • KINDOF_IMMOBILE — never moves (line 47)
  • KINDOF_INFANTRY — soldier (line 53)
  • KINDOF_VEHICLE — tank, jeep, hovercraft (line 54)
  • KINDOF_AIRCRAFT — plane or helicopter (line 55)
  • KINDOF_MP_COUNT_FOR_VICTORY — losing all of these loses the game (line 84)

Gameplay systems ask isKindOf constantly. The AI, the pathfinder, the selection code, score-keeping, the victory check — none of them look at class types. They look at bits.

Structures

A typical production structure sets STRUCTURE, IMMOBILE, and MP_COUNT_FOR_VICTORY, attaches an ActiveBody (structures use ActiveBody too, not a special StructureBody class — the name is historical), and omits any AIUpdate module. What makes it a building is the absence of a locomotor set and the presence of structure-centric modules like ProductionUpdate, GarrisonContain, ProductionSpecialPowerModule, or PowerPlantUpdate.

Object AmericaPowerPlant
  KindOf = STRUCTURE IMMOBILE SELECTABLE CAN_ATTACK MP_COUNT_FOR_VICTORY
           SCORE CAPTURABLE FS_POWER AUTO_RALLYPOINT
  Body   = ActiveBody ModuleTag_05
    MaxHealth = 500.0
  End
  Behavior = PowerPlantUpdate ModuleTag_07
    End
  Behavior = StructureCollapseUpdate ModuleTag_09
    MinCollapseDelay = 000
    MaxCollapseDelay = 000
  End
End

No AIUpdate, no Locomotor. The pathfinder will never ask it to move.

Units

A unit replaces those structural modules with an AIUpdateInterface (or a subclass — DozerAIUpdate, TransportAIUpdate, JetAIUpdate) and picks a locomotor set. A Ranger looks roughly like this:

Object AmericaInfantryRanger
  KindOf = PRELOAD SELECTABLE CAN_ATTACK INFANTRY SCORE CAN_RAPPEL
           PARACHUTABLE ATTACK_NEEDS_LINE_OF_SIGHT
  Body   = ActiveBody ModuleTag_04
    MaxHealth = 120.0
  End
  Behavior = AIUpdateInterface ModuleTag_05
    AutoAcquireEnemiesWhenIdle = Yes
  End
  Locomotor = SET_NORMAL HumanLocomotor
End

The VEHICLE/INFANTRY/AIRCRAFT bit branches downstream: the pathfinder picks a different layer, the UI picks a different cursor, the AI picks a different target-priority table, and formation movement applies a different spacing rule. Infantry additionally unlocks CAN_RAPPEL and PARACHUTABLE paths that vehicles can't use. Aircraft takes over the flight layer entirely.

Production and construction

A structure "produces" a unit through a ProductionUpdate module that maintains a per-structure queue. When a job finishes, the module calls TheThingFactory->newObject with the queued template and places the result at the structure's rally point. The unit is born as a full Object — the factory structure doesn't know or care what it just built, and the produced unit doesn't carry a reference back.

Construction works the same way in reverse. A building under construction is itself an Object, stamped from the same template as the finished building but with an intermediate behavior module (StructureBody-derived construction updaters) throttling health and disabling production until the construction progress completes. See The Object Model for the template pipeline and Modules and Behaviors for the module system itself.

Quirks

  • Walls and power plants don't count for defeat. The victory check at VictoryConditions.cpp:351 iterates only objects with KINDOF_MP_COUNT_FOR_VICTORY. Power plants, walls, and upgrade structures are intentionally excluded. You can have a base of nothing but power plants and still technically be alive.
  • IMMOBILE is what blocks pathfinding cells, not STRUCTURE. A prop or tree that is IMMOBILE without STRUCTURE still reserves cells. A theoretical mobile structure would not.
  • An object can hold both VEHICLE and STRUCTURE. The engine allows it and a few gantry-type objects use the combo. Code that assumes the flags are exclusive will misclassify these — check explicitly for what you want.
  • Aircraft use the pathfinder's flight layer, not terrain. KINDOF_AIRCRAFT bypasses terrain obstacles but still routes through the pathfinder for collision and formation.
  • Infantry takes SET_NORMAL with a HumanLocomotor, aircraft alternates SET_TAXIING and SET_NORMAL, structures have no locomotor set at all. The absence of a set is the engine's real "is this thing mobile" check — more reliable than reading kindof bits.
  • Construction placement uses IMMOBILE to decide blocked cells, which is why correct cliff-cell classification matters when a dozer tries to put a building near a slope — see Cliff Cells.
  • Template inheritance is handled by Overridable, not by the INI parser. AmericaInfantryPathfinder inherits the base infantry template and overrides a few fields; both blocks live in INI and the engine merges them at load time. A mod that adds a new Object block can do the same.