121 auto objectResult = definitionObject(registry,
"unit",
unit.definition()->id);
123 const auto object = std::move(objectResult).takeValue();
125 auto health =
number(
object,
"health", 1.0f, 0.0f);
126 auto speed =
number(
object,
"speed", 1.0f, 0.0f);
128 auto sight =
number(
object,
"sightRange", 0.0f, 0.0f);
129 auto detection =
number(
object,
"detectionRange", 0.0f, 0.0f);
130 auto radar =
number(
object,
"radarRange", 0.0f, 0.0f);
131 auto jamming =
number(
object,
"jammingRange", 0.0f, 0.0f);
132 auto range =
number(
object,
"attackRange", 0.0f, 0.0f);
133 auto role =
text(
object,
"role");
134 auto weaponType =
text(
object,
"weaponType");
135 auto targetTags = tags(
object,
"targetTags");
136 if (!health || !speed || !
radius || !sight || !detection || !radar || !jamming || !
range || !role ||
137 !weaponType || !targetTags)
139 "RTS unit definition contains an invalid core field",
"unit", {},
142 auto capacity =
number(
object,
"cargoCapacity", role.value() ==
"worker" ? 10.0f : 0.0f, 0.0f);
143 auto gather =
number(
object,
"gatherRate", role.value() ==
"worker" ? 5.0f : 0.0f, 0.0f);
144 auto buildRate =
number(
object,
"buildRate", 1.0f, 0.0f);
145 auto repairRate =
number(
object,
"repairRate", 0.0f, 0.0f);
146 auto captureRate =
number(
object,
"captureRate", 0.0f, 0.0f);
147 auto shield =
number(
object,
"shieldCapacity", 0.0f, 0.0f);
148 auto shieldRegen =
number(
object,
"shieldRegenRate", 0.0f, 0.0f);
149 auto shieldDelay =
number(
object,
"shieldRegenDelay", 0.0f, 0.0f);
150 auto transport = integer(
object,
"transportCapacity", 0);
151 auto airborne =
text(
object,
"targetDomain");
152 auto suppression =
number(
object,
"suppressionCapacity", 0.0f, 0.0f);
153 auto suppressionRecovery =
number(
object,
"suppressionRecoveryRate", 0.0f, 0.0f);
154 auto suppressedSpeed =
number(
object,
"suppressedSpeedFactor", 1.0f, 0.0f);
155 auto suppressedDamage =
number(
object,
"suppressedDamageFactor", 1.0f, 0.0f);
156 auto retreatEnabled =
boolean(
object,
"suppressionRetreatEnabled",
false);
157 auto retreatThreshold =
number(
object,
"suppressionRetreatThreshold", 0.8f, 0.0f);
158 auto retreatDistance =
number(
object,
"suppressionRetreatDistance", 6.0f, 0.0f);
159 auto moraleRange =
number(
object,
"moraleAuraRange", 0.0f, 0.0f);
160 auto moraleFactor =
number(
object,
"moraleAuraSuppressionFactor", 1.0f, 0.0f);
161 auto moraleRecovery =
number(
object,
"moraleAuraRecoveryBonus", 0.0f, 0.0f);
162 auto veteranThreshold =
number(
object,
"veteranThreshold", 0.0f, 0.0f);
163 auto eliteThreshold =
number(
object,
"eliteThreshold", 0.0f, 0.0f);
164 auto veteranDamage =
number(
object,
"veteranDamageFactor", 1.0f, 0.0f);
165 auto eliteDamage =
number(
object,
"eliteDamageFactor", 1.0f, 0.0f);
166 auto veteranHealth =
number(
object,
"veteranHealthFactor", 1.0f, 0.0f);
167 auto eliteHealth =
number(
object,
"eliteHealthFactor", 1.0f, 0.0f);
168 auto commandRange =
number(
object,
"commandRange", 0.0f, 0.0f);
169 auto commandCapacity = integer(
object,
"commandCapacity", 0);
170 auto commandCost = integer(
object,
"commandCost", 1);
171 auto commandPriority = integer(
object,
"commandPriority", 0);
172 auto commandJamming =
number(
object,
"commandJammingRange", 0.0f, 0.0f);
173 auto commandRequired =
boolean(
object,
"requiresCommand",
false);
174 auto relayUplink =
boolean(
object,
"commandRelayRequiresUplink",
false);
175 auto outOfCommandSpeed =
number(
object,
"outOfCommandSpeedFactor", 1.0f, 0.0f);
176 auto outOfCommandDamage =
number(
object,
"outOfCommandDamageFactor", 1.0f, 0.0f);
177 auto ammoCapacity =
number(
object,
"ammoSupplyCapacity", 0.0f, 0.0f);
178 auto ammoRange =
number(
object,
"ammoSupplyRange", 0.0f, 0.0f);
179 auto ammoRate =
number(
object,
"ammoSupplyRate", 0.0f, 0.0f);
180 auto ammoRelay =
boolean(
object,
"ammoRelayEnabled",
false);
181 auto autoResupply =
boolean(
object,
"autoResupplyEnabled",
false);
182 auto autoThreshold =
number(
object,
"autoResupplyThreshold", 0.5f, 0.0f);
183 auto reserveAmmo =
number(
object,
"reserveAmmoCapacity", 0.0f, 0.0f);
184 auto supplyPriority =
number(
object,
"supplyPriority", 1.0f, 0.0f);
185 auto firingTurnRate =
number(
object,
"turretTurnRate", 0.0f, 0.0f);
186 auto firingArc =
number(
object,
"firingArc", 0.01f, 0.0f);
187 auto firingHeight =
number(
object,
"firingHeight", 1.0f, 0.000001f);
188 auto targetHeight =
number(
object,
"targetHeight", 1.0f, 0.000001f);
189 if (!
capacity || !gather || !buildRate || !repairRate || !captureRate || !shield || !shieldRegen ||
190 !shieldDelay || !transport || !airborne || !suppression || !suppressionRecovery ||
191 !suppressedSpeed || !suppressedDamage || !retreatEnabled || !retreatThreshold || !retreatDistance ||
192 !moraleRange || !moraleFactor || !moraleRecovery || !veteranThreshold || !eliteThreshold ||
193 !veteranDamage || !eliteDamage || !veteranHealth || !eliteHealth || !commandRange ||
194 !commandCapacity || !commandCost || !commandPriority || !commandJamming || !commandRequired ||
195 !relayUplink || !outOfCommandSpeed || !outOfCommandDamage || !ammoCapacity || !ammoRange ||
196 !ammoRate || !ammoRelay || !autoResupply || !autoThreshold || !reserveAmmo || !supplyPriority ||
197 !firingTurnRate || !firingArc || !firingHeight || !targetHeight)
199 "RTS unit definition contains an invalid capability field",
200 "unit", {},
"rts.archetype"));
203 if (!weaponType.value().empty()) {
206 "RTS unit definition requires a weapon factory",
207 "unit.weaponType", {},
"rts.archetype"));
208 auto created = weaponFactory(weaponType.value(),
unit.identity()->subject.persistentId());
210 weapon = std::move(
created).takeValue();
213 unit.motion()->speed = speed.value();
214 unit.motion()->airborne = airborne.value() ==
"air";
216 unit.vision()->sightRange = sight.value();
217 unit.vision()->detectionRange = detection.value();
218 unit.vision()->radarRange = radar.value();
219 unit.vision()->jammingRange = jamming.value();
220 unit.combat()->acquisitionRange = std::max(sight.value(),
range.value());
221 unit.combat()->engagementRange =
range.value();
222 unit.combat()->leashRange = std::max(sight.value(),
range.value()) * 1.5f;
223 unit.durability()->state.subject =
unit.identity()->subject;
224 unit.durability()->state.health = health.value();
225 unit.durability()->state.maxHealth = health.value();
226 unit.durability()->alive = health.value() > 0.0f;
228 unit.worker()->gatherRate = gather.value();
229 unit.worker()->buildRate = buildRate.value();
230 unit.worker()->repairRate = repairRate.value();
231 unit.worker()->autoAssign = role.value() ==
"worker";
232 unit.capture()->rate = captureRate.value();
233 unit.shield()->capacity = shield.value();
234 unit.shield()->value = shield.value();
235 unit.shield()->regenRate = shieldRegen.value();
236 unit.shield()->regenDelay = shieldDelay.value();
237 unit.containment()->capacity =
static_cast<std::size_t
>(transport.value());
238 unit.morale()->capacity = suppression.value();
239 unit.morale()->recoveryRate = suppressionRecovery.value();
240 unit.morale()->suppressedSpeedFactor = suppressedSpeed.value();
241 unit.morale()->suppressedDamageFactor = suppressedDamage.value();
242 unit.morale()->retreatEnabled = retreatEnabled.value();
243 unit.morale()->retreatThreshold = retreatThreshold.value();
244 unit.morale()->retreatDistance = retreatDistance.value();
245 unit.morale()->auraRange = moraleRange.value();
246 unit.morale()->auraSuppressionFactor = moraleFactor.value();
247 unit.morale()->auraRecoveryBonus = moraleRecovery.value();
248 unit.veterancy()->veteranThreshold = veteranThreshold.value();
249 unit.veterancy()->eliteThreshold = eliteThreshold.value();
250 unit.veterancy()->veteranDamageFactor = veteranDamage.value();
251 unit.veterancy()->eliteDamageFactor = eliteDamage.value();
252 unit.veterancy()->veteranHealthFactor = veteranHealth.value();
253 unit.veterancy()->eliteHealthFactor = eliteHealth.value();
254 unit.command()->range = commandRange.value();
255 unit.command()->capacity = commandCapacity.value();
256 unit.command()->cost = commandCost.value();
257 unit.command()->priority = commandPriority.value();
258 unit.command()->jammingRange = commandJamming.value();
259 unit.command()->requiresCommand = commandRequired.value();
260 unit.command()->relayRequiresUplink = relayUplink.value();
261 unit.command()->outOfCommandSpeedFactor = outOfCommandSpeed.value();
262 unit.command()->outOfCommandDamageFactor = outOfCommandDamage.value();
263 unit.supply()->capacity = std::max(ammoCapacity.value(), reserveAmmo.value());
264 unit.supply()->stock = ammoCapacity.value();
265 unit.supply()->range = ammoRange.value();
266 unit.supply()->transferRate = ammoRate.value();
267 unit.supply()->relayEnabled = ammoRelay.value();
268 unit.supply()->autoDispatch = autoResupply.value();
269 unit.supply()->autoThreshold = autoThreshold.value();
270 unit.supply()->priority = supplyPriority.value();
271 unit.combat()->turnRateDegrees = firingTurnRate.value();
272 unit.combat()->aimToleranceDegrees = firingArc.value();
273 unit.combat()->firingHeight = firingHeight.value();
274 unit.combat()->targetHeight = targetHeight.value();
275 unit.tags()->values = std::move(targetTags).takeValue();
276 if (weapon !=
nullptr) {
279 unit.weapon()->link = std::move(link).takeValue();
286 auto objectResult = definitionObject(registry,
"building", building.definition()->id);
288 const auto object = std::move(objectResult).takeValue();
289 auto health =
number(
object,
"health", 1.0f, 0.0f);
291 auto buildTime =
number(
object,
"buildTime", 0.0f, 0.0f);
292 auto sight =
number(
object,
"sightRange", 0.0f, 0.0f);
293 auto weaponType =
text(
object,
"weaponType");
294 auto garrison = integer(
object,
"garrisonCapacity", 0);
295 auto capturable =
boolean(
object,
"capturable",
false);
296 auto captureTime =
number(
object,
"captureTime", 5.0f, 0.000001f);
297 auto powerProduced =
number(
object,
"powerProvided", 0.0f, 0.0f);
298 auto powerUsed =
number(
object,
"powerUsed", 0.0f, 0.0f);
299 auto powerPriority = integer(
object,
"powerPriority", 0);
300 auto influence =
number(
object,
"buildInfluenceRadius", 0.0f, 0.0f);
301 auto incomeResource =
text(
object,
"incomeResource");
302 auto incomeRate =
number(
object,
"incomeRate", 0.0f, 0.0f);
303 auto repairCost =
number(
object,
"repairCostPerHealth", 0.0f, 0.0f);
304 auto repairResource =
text(
object,
"repairResource",
"minerals");
305 auto shield =
number(
object,
"shieldCapacity", 0.0f, 0.0f);
306 auto shieldRegen =
number(
object,
"shieldRegenRate", 0.0f, 0.0f);
307 auto shieldDelay =
number(
object,
"shieldRegenDelay", 0.0f, 0.0f);
308 auto garrisonBonus =
number(
object,
"garrisonDamageBonus", 0.0f, 0.0f);
309 auto ammoCapacity =
number(
object,
"ammoSupplyCapacity", 0.0f, 0.0f);
310 auto ammoRange =
number(
object,
"ammoSupplyRange", 0.0f, 0.0f);
311 auto ammoRate =
number(
object,
"ammoSupplyRate", 0.0f, 0.0f);
312 auto ammoResource =
text(
object,
"ammoProductionResource");
313 auto ammoCost =
number(
object,
"ammoProductionCost", 0.0f, 0.0f);
314 auto ammoProduction =
number(
object,
"ammoProductionRate", 0.0f, 0.0f);
315 auto commandRange =
number(
object,
"commandRange", 0.0f, 0.0f);
316 auto commandCapacity = integer(
object,
"commandCapacity", 0);
317 auto commandJamming =
number(
object,
"commandJammingRange", 0.0f, 0.0f);
318 auto turretTurn =
number(
object,
"turretTurnRate", 0.0f, 0.0f);
319 auto firingArc =
number(
object,
"firingArc", 0.01f, 0.0f);
320 auto firingHeight =
number(
object,
"firingHeight", 2.0f, 0.000001f);
321 auto targetHeight =
number(
object,
"targetHeight", 1.5f, 0.000001f);
322 if (!health || !
radius || !buildTime || !sight || !weaponType || !garrison || !capturable || !captureTime ||
323 !powerProduced || !powerUsed || !powerPriority || !influence || !incomeResource || !incomeRate ||
324 !repairCost || !repairResource || !shield || !shieldRegen || !shieldDelay || !garrisonBonus ||
325 !ammoCapacity || !ammoRange || !ammoRate || !ammoResource || !ammoCost || !ammoProduction ||
326 !commandRange || !commandCapacity || !commandJamming || !turretTurn || !firingArc ||
327 !firingHeight || !targetHeight)
329 "RTS building definition contains an invalid field",
"building",
330 {},
"rts.archetype"));
333 if (!weaponType.value().empty()) {
336 "RTS building definition requires a weapon factory",
337 "building.weaponType", {},
"rts.archetype"));
338 auto created = weaponFactory(weaponType.value(), building.identity()->subject.persistentId());
340 weapon = std::move(
created).takeValue();
343 building.placement()->placed =
true;
344 building.construction()->buildTimeSeconds = buildTime.value();
345 building.integrity()->state.subject = building.identity()->subject;
346 building.integrity()->state.health = health.value();
347 building.integrity()->state.maxHealth = health.value();
348 building.integrity()->alive = health.value() > 0.0f;
349 building.integrity()->repairCostPerHealth = repairCost.value();
350 building.integrity()->repairResource = std::move(repairResource).takeValue();
351 building.shield()->capacity = shield.value();
352 building.shield()->value = shield.value();
353 building.shield()->regenRate = shieldRegen.value();
354 building.shield()->regenDelay = shieldDelay.value();
355 building.vision()->sightRange = sight.value();
356 building.garrison()->capacity =
static_cast<std::size_t
>(garrison.value());
357 building.garrison()->damageBonusPerOccupant = garrisonBonus.value();
358 building.capture()->capturable = capturable.value();
359 building.capture()->durationSeconds = captureTime.value();
360 building.infrastructure()->powerProduced = powerProduced.value();
361 building.infrastructure()->powerConsumed = powerUsed.value();
362 building.infrastructure()->powerPriority = powerPriority.value();
363 building.infrastructure()->buildInfluenceRadius = influence.value();
364 building.infrastructure()->incomeResource = std::move(incomeResource).takeValue();
365 building.infrastructure()->incomeRate = incomeRate.value();
366 building.supply()->capacity = ammoCapacity.value();
367 building.supply()->stock = ammoCapacity.value();
368 building.supply()->range = ammoRange.value();
369 building.supply()->transferRate = ammoRate.value();
370 building.supply()->productionResource = std::move(ammoResource).takeValue();
371 building.supply()->productionCostPerRound =
static_cast<std::int64_t
>(std::ceil(ammoCost.value()));
372 building.supply()->productionRate = ammoProduction.value();
373 building.command()->range = commandRange.value();
374 building.command()->capacity = commandCapacity.value();
375 building.command()->jammingRange = commandJamming.value();
376 building.command()->active = commandRange.value() > 0.0f;
377 building.combat()->firingHeight = firingHeight.value();
378 building.combat()->targetHeight = targetHeight.value();
379 building.dropoff()->radius =
radius.value();
380 if (
const auto dropoff =
boolean(
object,
"dropoff",
false); dropoff && dropoff.value())
381 building.dropoff()->acceptedResources.push_back(
"minerals");
382 if (weapon !=
nullptr) {
385 building.weapon()->link = std::move(link).takeValue();
386 building.combat()->acquisitionRange = sight.value();
387 building.combat()->engagementRange = sight.value();
388 building.combat()->turnRateDegrees = turretTurn.value();
389 building.combat()->aimToleranceDegrees = firingArc.value();