Skip to main content

idAI2

An entity for AI/NPCs, usually demons.

idAI2 can be individually placed throughout a map, or more preferably, spawned with an idTarget_Spawn. The exact ai type of the idAI2 can be checked by looking at the inherit parameter.

Eternal

entity {
	layers {
		"spawn_target_layer"
	}
	entityDef example_ai_soldier_eternal {
	inherit = "ai/fodder/soldier_blaster";
	class = "idAI2";
	expandInheritance = false;
	poolCount = 0;
	poolGranularity = 2;
	networkReplicated = true;
	disableAIPooling = false;
	edit = { // See "struct idAI2 : public idActor"
		highlightDecl = "glorykill_highlight";
		clipModelInfo = {
			type = "CLIPMODEL_BOX";
			size = {
				x = 0.600000024;
				y = 0.600000024;
				z = 1.829;
			}
		}
		dormancy = {
			delay = 30;
			distance = 19.5070019;
		}
		spawn_statIncreases = { // Increase these stats on spawn
			num = 1;
			item[0] = {
				stat = "STAT_AI_SPAWNED";
				increase = 1;
			}
		}
		targetingDecl = "characters/soldier_blaster"; // Targeting Decl ( defines specific aim assist / AR target points )
		actorConstants = { // See "struct idActor::idActorConstant"
			perception = {
				eyeOffset = { // offset of eye relative to physics origin {{ units = m }}
					z = 1.71500003;
				}
				crouchedEyeOffset = { // eye offset when crouched {{ units = m }}
					z = 1.06700003;
				}
			}
			actorSounds = {
				sndFootsteps = "footsteps/hellified_soldier/hs_footstep";
				sndRagdollStart = "play_hell_soldier_death_short";
			}
			footstepEffectTable = "impacteffect/footsteps/ai_soldier";
			footstepEvents = "footstepevents/default";
			painInfo = {
				decayDelay = 1000; // delay for the decay, in game ticks.
				bucketMaxValue = 400; // the max value for the leaky bucket
				decayRate = -20; // the decay rate for the bucket
			}
			bulletPenetrationData = {
				energyCostToPenetrate = 10; // costs this much penetration energy to penetrate this actor
				damageScaleToPenetrate = 0.75; // bullet damage is scaled by this amount after penetrating
			}
			footstepEffectTable_Sprint = "impacteffect/footsteps/ai_soldier_sprint";
			footstepEffectTable_SlowWalk = "impacteffect/footsteps/ai_soldier";
			footstepEffectTable_CrouchWalk = "impacteffect/footsteps/ai_soldier";
			footstepEffectTable_Landing = "impacteffect/footsteps/ai_soldier_landing";
			footstepEffectTable_HeavyLanding = "impacteffect/footsteps/ai_soldier_landing";
			ledgeGrabEffectTable = "impacteffect/footsteps/ai_soldier";
			ledgeGrabEffectTable_Heavy = "impacteffect/footsteps/ai_soldier";
			ledgeGrabEffectTable_Friendly = "impacteffect/footsteps/ai_soldier";
			ledgeGrabEffectTable_FriendlyHeavy = "impacteffect/footsteps/ai_soldier";
		}
		actorEditable = { // See "struct idActor::idActorEditable"
			entityDamageComponent = { // names of joint groups, their associated damage scale, and armor level
				entityDamage = "entitydamage/ai/soldier_blaster/base";
			}
			injuredStates = { // defines parameters of each injured state, see "struct idInjuredState"
				num = 1;
				item[0] = {
					name = "not_injured";
					damageGroupMaxGoreLevels = {
						num = 6;
						item[0] = {
							damageGroupName = "head";
							maxGoreLevel = "GORELEVEL_TATTERED";
						}
						item[1] = {
							damageGroupName = "chest";
							maxGoreLevel = "GORELEVEL_TATTERED";
						}
						item[2] = {
							damageGroupName = "right_arm";
							maxGoreLevel = "GORELEVEL_TATTERED";
						}
						item[3] = {
							damageGroupName = "left_arm";
							maxGoreLevel = "GORELEVEL_TATTERED";
						}
						item[4] = {
							damageGroupName = "right_leg";
							maxGoreLevel = "GORELEVEL_TATTERED";
						}
						item[5] = {
							damageGroupName = "left_leg";
							maxGoreLevel = "GORELEVEL_TATTERED";
						}
					}
					allowIK = true; // true if AI uses IK in this injured state
					canUseAllTraversalsWhileInjured = true; // true if AI can use all traversals in this injured state
					canUseDownTraversalsWhileInjured = true; // true if AI can use down traversals in this injured state
				}
			}
			radiusDamageJoints = { // names of joints to trace to for radius damage tests
				num = 6;
				item[0] = "head_part01_md";
				item[1] = "spine_part01_md";
				item[2] = "arm_hand_lf";
				item[3] = "arm_hand_rt";
				item[4] = "leg_lower_lf";
				item[5] = "leg_lower_rt";
			}
		}
		factionName = "blaster";
		mass = 18.1439991; // mass of the actor {{ units = kg }}
		lootable = false;
		lootDropComponent = { // lootdrop decl for campaign
			lootDropDataDecl = "ai/default_fodder";
		}
		pvpLootDropComponent = { // lootdrop decl for Battlemode
			lootDropDataDecl = "ai/default_fodder_pvp";
		}
		aiConstants = { // See "struct idAI2::idAIConstant"
			components = {
				ptr = {
					ptr[12] = {
						componentDecl = "aicomponent/pathmanager/base";
					}
					ptr[14] = {
						componentDecl = "aicomponent/attack/base";
					}
					ptr[9] = {
						componentDecl = "aicomponent/positionawareness/soldier_blaster/base";
					}
					ptr[10] = {
						componentDecl = "aicomponent/extendedsense/soldier_blaster/base";
					}
					ptr[11] = {
						componentDecl = "aicomponent/transientfocus/soldier_blaster/base";
					}
					ptr[13] = {
						componentDecl = "aicomponent/soldier_blaster";
					}
				}
			}
			syncMelee = { // See "struct idSyncAttack"
				msAfterAttackBeforeCanSync = 250; // how long after a regular attack before a sync attack can be performed
				syncMeleeEntityDefs = { // entityDef decls for syncmelee
					num = 2;
					item[0] = "syncmelee/soldier_blaster";
					item[1] = "syncmelee/soldier_blaster_3p";
				}
				syncGroups = { // See "struct idSyncAttack"
					num = 1;
					item[0] = {
						syncGroupName = "";
						syncInteractions = { // syncInteraction decls
							num = 19;
							item[0] = "syncdeath/playervsai/soldier_blaster/right_upper";
							item[1] = "syncdeath/playervsai/soldier_blaster/left_upper";
							item[2] = "syncdeath/playervsai/soldier_blaster/front_upper";
							item[3] = "syncdeath/playervsai/soldier_blaster/front_head";
							item[4] = "syncdeath/playervsai/soldier_blaster/left_lower";
							item[5] = "syncdeath/playervsai/soldier_blaster/above_back";
							item[6] = "syncdeath/playervsai/soldier_blaster/above_front";
							item[7] = "syncdeath/playervsai/soldier_blaster/front_rightarm";
							item[8] = "syncdeath/playervsai/soldier_blaster/front_leftarm";
							item[9] = "syncdeath/playervsai/soldier_blaster/berserk/berserk_above_front";
							item[10] = "syncdeath/playervsai/soldier_blaster/chainsaw/cut_back";
							item[11] = "syncdeath/playervsai/soldier_blaster/back_lower";
							item[12] = "syncdeath/playervsai/soldier_blaster/chainsaw/cut_front";
							item[13] = "syncdeath/playervsai/soldier_blaster/berserk/berserk_front_upper";
							item[14] = "syncdeath/playervsai/soldier_blaster/right_lower";
							item[15] = "syncdeath/playervsai/soldier_blaster/back_upper";
							item[16] = "syncdeath/playervsai/soldier_blaster/crucbile/crucible_front";
							item[17] = "syncdeath/playervsai/soldier_blaster/crucbile/crucible_back";
							item[18] = "syncdeath/playervsai/soldier_blaster/front_lower";
						}
					}
				}
				alwaysAllowChainsawGloryKill = true; // if true then always allow chainsaw glory kills without needing stagger states or other such things
			}
			aiDeathStat = "STAT_HELL_MARINE_KILLED"; // what stat to increase on death of this ai
			positioningParms = { // parms used to control major positioning in behaviour finite state machine
				num = 2;
				item[0] = "soldier_blaster/plasma";
				item[1] = "soldier_blaster/plasma_object";
			}
			aiDeathCodex = "codex/hell/demon_soldier_blaster"; // what codex to give the player when this ai dies
		}
		aiEditable = { // See "struct idAIEditable"
			perception = { // See "struct idAIPerception"
				actorPerceptionRadius = 39; // max radius at which AI can perceive other actors {{ units = m }}
				obstaclePerceptionRadius = 78; // max radius at which AI can perceive obstacles {{ units = m }}
				closePerceptionRadius = 5; // max radius .... for close FOV {{ units = m }}
				eventPerceptionRadius = 39; // max radius at which AI will perceive any events {{ units = m }}
				senseUpdatesOnNonEnemies = false; // if true, AI will skip all worldstate updates for non-enemies
			}
			useTouchComponent = true;
			death = { // See "struct idAIEditable::idAIDeath"
				ignoreDamageType = "DAMAGETYPE_EMP"; // entity will not take any damage from any damage decl that ANDs with this value
				fadeOutAfterDeathDelay_Seconds = { // delay burn-away fx until at least after this much time ( 0 uses default, negative implies never )
					value = 3;
				}
				removeAfterFadeOutDelay_Seconds = { // remove the entity this long after burn away fx start
					value = 3;
				}
				canBecomeInjured = false; // if true, AI can become injured and use injured runs and idles
				explosionDecl = "ai/default";
				declTwitchPain = "twitchpain/soldier_blaster";
				deathAnim = ""; // animation to force on death
				trigger = ""; // idEntity to trigger on death
				triggerGloryKill = ""; // idEntity to trigger on death by glory kill
				triggerNonGloryKill = ""; // idEntity to trigger on death by normal kill
				onlyDieByGK = false; // true if the AI will only die as a result of receiving sync damage (glory killed)
			}
			movement = { // See "struct idAIEditable::idAIMovement"
				wanderRadius = 19.5070019; // how far an AI can randomly wander from its spawn position {{ units = m }}
				useTraversalClassA = true; // if true, can use class A traversals
			}
			cover = { // See "struct idAIEditable::idAICoverInfo"
				coverRadius = 19.5070019; // max radius at which the AI will check for cover {{ units = m }}
			}
			behaviors = { // See "struct idAIBehaviors"
				decl = "behaviors/soldier_blaster/soldier_blaster"; // the behavior typeinfo decl this behavior uses.
				declBehaviorEvents = "behaviorevents/default"; // AI events
				attackGraph = "ai/soldier_blaster"; // available attacks
			}
			vsAIDamageMask = "HEALTH"; // damageCategoryMask_t; how to process damage taken from other AI
			spawnSettings = { // Refer to "struct idAIEditable::idAISpawn"
				entranceAnimPath = "animweb/characters/monsters/soldier_blaster/spawn/teleport_entrance"; // initial animation to play specified via animref if entranceAnim not given
				spawnFXEntityDef = "fx/spawn_in_fodder"; // entity def for fx to use when spawned with AIOVERRIDE_TELEPORT
				initialState = "AIOVERRIDE_TELEPORT"; // initial valye for aiStateOverride_t; can be overwritten in the spawn target
				teleportDelayMS = 750; // How long it takes to spawn in when using AIOVERRIDE_TELEPORT
				chanceMissingArmor = { // See "struct idAIEditable::idAIMissingArmor"
					num = 0;
					item[0] = {
						damageGroup = "head"; // damage group whose armour may or may not be there
						missingChance = 100; // 0-100 % chance that armour is missing
					}
				}
			}
			demonTeamInfo = {
				canHostLostSouls = true;
			}
			staggerEnabled = true; // Set to false to disable staggering
		}
		aiHealth = { // Refer to "struct idHealthT < aiHealthComponent_t , AI_HEALTH_MAX , AI_HEALTH_HITPOINTS >"
			components = {
				components[1] = {
					max = 0; // Max regen allowed
					regenInterval = { // interval, in seconds, between regen updates.
						value = 0;
					}
				}
				components[0] = {
					max = 400; // Max HP allowed
					starting = 400; // HP when spawned
				}
			}
		}
		goreComponent = { // See "struct idGoreComponent"
			goreContainer = "ai/fodder/soldier"; // gore component decl
		}
		afProperties = { // See "struct idAnimator_AF : public idAnimator_Base"
			impactEffectTable = "impacteffect/ragdoll/ragdoll_fodder"; // impact table for sound and particles
			articulatedFigure = "characters/monsters/soldier_blaster_auto"; // the articulated figure decl to use
		}
		renderModelInfo = {
			model = "md6def/characters/monsters/soldier_blaster/base/soldier_blaster.md6"; // md6def decl to use
			lightRigDecl = "soldier_blaster/soldier_blaster_default";
			materialRemap = { // Use to replace the textures on a per entity basis
				num = 0;
			}
		}
		fxDecl = "character/hellified_soldier_blaster/hellified_soldier_blaster"; // fx decl for this entity
		startingInventory = { // See "struct idInventoryAttachmentDef"
			num = 2;
			item[0] = {
				startSlot = "EQUIPPED"; // startingSlot_t; EQUIPPED, HOLSTERED, or BACKPACK
				inventoryDecl = "weapon/ai/soldier_blaster/plasma"; // inventory decl for this attachment
			}
			item[1] = {
				showHolstered = false; // if true, attach and show the item when it's holstered
				inventoryDecl = "weapon/ai/soldier_blaster/plasma_slug";
			}
		}
		walkIKDecl = "walkik/biped_base";
		killerNames = { // What to string display when killed by this entity
			num = 1;
			item[0] = "#str_decl_demoncard_summon_fodder_blaster_soldier_name_GHOST53375";
		}
		spawnPosition = {
			x = -74.8000107;
			y = 181.34996;
			z = -1626.30005;
		}
		flags = {
			hide = true;
		}
	}
}
}
Misc. Notes

idAI2's can be edited in order to alter their properties. For example, you can swap out the lootDropComponent decl with that of the Maykr drone. The result will be a Soldier which will drop Maykr Drone lootdrops when headshot.

Custom AI

idAI2's can be edited in order to make custom AI. Values such as EntityDamage, LootDropComponent, and SpawnSettings can be swapped out between different idAI2's for a desired change, and others such as aiHealth and all the values in aiEditable can be edited to change how a demon functions. 

In this soldier idai2 for example, you can swap out the "LootDropComponent" parameter with that of the maykr drone. The result will be soldiers which will drop Maykr Drone lootdrops when headshot.