@zerospacegg/iolin
Version:
Pure TypeScript implementation of ZeroSpace game data processing (PKL-free)
679 lines • 21.3 kB
JavaScript
"use strict";
/**
* Ability - Base ability class for ZeroSpace abilities
* Ported from ability.pkl with functional constructor pattern
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Passive = exports.Upgrade = exports.WeaponSwitch = exports.Siege = exports.DeathTrigger = exports.Spell = exports.Heal = exports.Attack = exports.FactionTalent = exports.TalentAbility = exports.Topbar = exports.FactionPassive = exports.FactionAbility = exports.Ability = void 0;
const child_js_1 = require("./child.cjs");
const core_js_1 = require("./core.cjs");
const entity_js_1 = require("./entity.cjs");
/**
* Base Ability class - extends Entity with ability-specific properties
* Usage: new AttackAbility("Sting", (ability) => { ability.range = 400; })
*/
class Ability extends child_js_1.Child {
constructor() {
super(...arguments);
// Targeting and activation
this.targets = [];
this.targetMode = "unit";
this.hotkey = "";
this.bonusDamage = [];
}
/** Public subtype getter - just for JSON serialization */
get subtype() {
return this.abilityType;
}
// Computed activation type based on ability type
get activationType() {
switch (this.subtype) {
case "attack":
case "heal":
return "auto";
case "passive":
case "faction-passive":
case "faction-talent":
return "permanent-effect";
case "death-trigger":
return "trigger";
default:
return "activated";
}
}
// Getter that returns targets in sorted order for consistent comparisons
get sortedTargets() {
return [...this.targets].sort();
}
// Automatic autocast based on activationType or forced autocast
get autocast() {
if (this._forceAutocast !== undefined) {
return this._forceAutocast;
}
return this.activationType === "auto";
}
// Allow setting forceAutocast
set forceAutocast(value) {
this._forceAutocast = value;
}
/**
* Apply this ability's effects to the parent entity
* Must be implemented by all abilities
*/
apply() {
// Default no-op implementation - override in subclasses
}
/**
* Apply this ability's effects to a target entity
* Used for cross-entity effects like buffs/debuffs
* Defaults to no-op if not needed
*/
applyTo(entity) {
// Default no-op implementation
}
get id() {
if (this.parentId) {
return `${this.parentId}/${this.slug}`;
}
return this.slug;
}
/**
* JSON.stringify() calls this automatically
*/
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
activationType: this.activationType,
parentSlug: this.parentSlug,
parentId: this.parentId,
targets: this.targets,
targetMode: this.targetMode,
requiresMode: this.requiresMode,
togglesMode: this.togglesMode,
hotkey: this.hotkey,
reverseHotKey: this.reverseHotKey,
healthCost: this.healthCost,
energyCost: this.energyCost,
energyType: this.energyType,
cooldown: this.cooldown,
cooldownBetweenShots: this.cooldownBetweenShots,
cooldownAtBuild: this.cooldownAtBuild,
duration: this.duration,
range: this.range,
delay: this.delay,
shots: this.shots,
volleys: this.volleys,
bonusDamage: this.bonusDamage,
splash: this.splash,
armorPenetration: this.armorPenetration,
closeupFirerate: this.closeupFirerate,
autocast: this.autocast,
// Internal game engine data NOT exported - accessed directly from TypeScript instances
// (internalId)
};
}
}
exports.Ability = Ability;
/**
* Base FactionAbility class - extends Ability with faction ability properties
* Usage: new FactionPassive("Resource Control", (ability) => { ability.abilityOf = "grell"; })
*/
class FactionAbility extends Ability {
constructor() {
super();
}
get activationType() {
switch (this.subtype) {
case "passive":
case "talent":
return "permanent-effect";
default:
return "activated";
}
}
toJSON() {
return {
...super.toJSON(),
abilityOf: this.abilityOf,
charges: this.charges,
teleport: this.teleport,
};
}
}
exports.FactionAbility = FactionAbility;
/**
* FactionPassive - Passive faction abilities
* Usage: new FactionPassive("Resource Control", (passive) => { passive.abilityOf = "grell"; })
*/
class FactionPassive extends FactionAbility {
constructor() {
super();
}
get slug() {
return `passives/${(0, core_js_1.slugify)(this.name)}`;
}
get id() {
return `faction/${this.abilityOf}/${this.slug}`;
}
get subtype() {
return "passive";
}
get abilityType() {
return this.subtype;
}
}
exports.FactionPassive = FactionPassive;
/**
* TopbarAbility - Topbar faction abilities
* Usage: new TopbarAbility({ name: "Orbital Strike", abilityOf: "grell" })
*/
class Topbar extends FactionAbility {
constructor(props) {
super();
if (props) {
Object.assign(this, props);
}
}
get slug() {
return `topbar/${(0, core_js_1.slugify)(this.name)}`;
}
get id() {
return `faction/${this.abilityOf}/${this.slug}`;
}
get subtype() {
return "topbar";
}
get abilityType() {
return this.subtype;
}
toJSON() {
return {
...super.toJSON(),
topbarType: this.topbarType,
slot: this.slot,
requiredLevel: this.requiredLevel,
};
}
}
exports.Topbar = Topbar;
/**
* TalentAbility - Talent faction abilities
* Usage: new TalentAbility("Enhanced Infusion", (talent) => { talent.abilityOf = "grell"; })
*/
class TalentAbility extends FactionAbility {
constructor() {
super();
}
get slug() {
return `talent-abilities/${(0, core_js_1.slugify)(this.name)}`;
}
get id() {
return `faction/${this.abilityOf}/${this.slug}`;
}
get subtype() {
return "talent";
}
get abilityType() {
return this.subtype;
}
}
exports.TalentAbility = TalentAbility;
/**
* FactionTalent - Faction-wide upgrades (not abilities)
* Usage: new FactionTalent({ name: "Enhanced Bio-Growth", tier: "T2" })
*/
class FactionTalent extends entity_js_1.Entity {
// Static defaults as readonly fields
get slug() {
return `talents/${(0, core_js_1.slugify)(this.name)}`;
}
get id() {
return `faction/${this.abilityOf}/${this.slug}`;
}
constructor(props) {
super();
// Talent-specific properties
this.tier = "";
this.level = 1;
if (props) {
Object.assign(this, props);
// Explicitly handle name assignment to ensure it works
if (props.name) {
this.name = props.name;
}
}
}
get subtype() {
return "talent";
}
apply() { }
toJSON() {
return {
...super.toJSON(),
tier: this.tier,
level: this.level,
abilityOf: this.abilityOf,
};
}
}
exports.FactionTalent = FactionTalent;
/**
* Attack Ability - Child class for attack abilities embedded in units
* Usage: new AttackAbility("Claws", parentId, (attack) => { attack.damage = 6; })
*/
class Attack extends Ability {
get type() {
return "ability";
}
get slug() {
return `attacks/${(0, core_js_1.slugify)(this.name)}`;
}
// Auto-calculated damagePerSec getter based on PKL logic
get damagePerSec() {
if (this.damageOverTime != null)
return undefined;
if (this.damage == null || this.cooldown == null)
return undefined;
const amt = this.damage;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
constructor(props = {}) {
super();
// Static defaults as readonly fields
this.abilityType = "attack";
// Default description implementation
this.description = "";
// Set default autocast for attacks
// autocast is now computed automatically from activationType
this.targetMode = "gamepiece"; // attacks target units + buildings
Object.assign(this, props);
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
damage: this.damage,
gamagePerSec: this.damagePerSec,
range: this.range,
cooldown: this.cooldown,
delay: this.delay,
targets: this.targets,
bonusDamage: this.bonusDamage,
splash: this.splash,
volleys: this.volleys,
};
}
}
exports.Attack = Attack;
/**
* Heal Ability - Child class for heal abilities embedded in units
* Usage: new HealAbility("Regeneration", parentId, (heal) => { heal.healAmount = 10; })
*/
class Heal extends Ability {
get type() {
return "ability";
}
get slug() {
return `heals/${(0, core_js_1.slugify)(this.name)}`;
}
// Auto-calculated healingPerSec getter based on PKL logic
get healingPerSec() {
const healValue = this.healing ?? this.healAmount;
if (this.healingOverTime != null)
return undefined;
if (healValue == null || this.cooldown == null)
return undefined;
const amt = healValue;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
constructor(props) {
super();
// Static defaults as readonly fields
this.abilityType = "heal";
// Default description implementation
this.description = "";
this.abilityType = "heal";
this.name = props.name;
this.description = props.description || "";
Object.assign(this, props);
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
healAmount: this.healAmount,
healPerSec: this.healingPerSec,
range: this.range,
cooldown: this.cooldown,
duration: this.duration,
targets: this.targets,
energyCost: this.energyCost,
};
}
}
exports.Heal = Heal;
/**
* Spell Ability - Child class for spell abilities embedded in units
* Usage: new Spell("Teleport", parentId, (spell) => { spell.energyCost = 50; })
*/
class Spell extends Ability {
get type() {
return "ability";
}
get slug() {
return `spells/${(0, core_js_1.slugify)(this.name)}`;
}
constructor(props) {
super();
// Static defaults as readonly fields
this.abilityType = "spell";
this.hotkey = "";
this.unlocked = true;
this.delay = undefined;
this.description = props.description;
if (props.forceAutocast !== undefined) {
this.forceAutocast = props.forceAutocast;
}
Object.assign(this, props);
}
// Auto-calculated damagePerSec getter based on PKL logic
get damagePerSec() {
if (this.damageOverTime != null)
return undefined;
if (this.damage == null || this.cooldown == null)
return undefined;
const amt = this.damage;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
// Auto-calculated healingPerSec getter based on PKL logic
get healingPerSec() {
if (this.healingOverTime != null)
return undefined;
if (this.healing == null || this.cooldown == null)
return undefined;
const amt = this.healing;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
energyCost: this.energyCost,
cooldown: this.cooldown,
range: this.range,
duration: this.duration,
targets: this.targets,
hotkey: this.hotkey,
unlocked: this.unlocked,
damage: this.damage,
delay: this.delay,
healing: this.healing,
};
}
}
exports.Spell = Spell;
/**
* Death Trigger Ability - Child class for abilities that trigger on unit death
* Usage: new DeathTrigger({ description: "Nuclear explosion", damage: 1000, delay: 1 })
*/
class DeathTrigger extends Ability {
get type() {
return "ability";
}
get slug() {
return `on-death/${(0, core_js_1.slugify)(this.name)}`;
}
// Death triggers have special activationType
get activationType() {
return "trigger";
}
constructor(props) {
super();
// Static defaults as readonly fields
this.abilityType = "spell";
this.hotkey = "";
this.unlocked = true;
this.delay = undefined;
this.bonusDamage = [];
this.description = props.description;
Object.assign(this, props);
}
// Auto-calculated damagePerSec getter based on PKL logic
get damagePerSec() {
if (this.damageOverTime != null)
return undefined;
if (this.damage == null || this.cooldown == null)
return undefined;
const amt = this.damage;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
// Auto-calculated healingPerSec getter based on PKL logic
get healingPerSec() {
if (this.healingOverTime != null)
return undefined;
if (this.healing == null || this.cooldown == null)
return undefined;
const amt = this.healing;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
get subtype() {
return "death-trigger";
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
energyCost: this.energyCost,
cooldown: this.cooldown,
range: this.range,
duration: this.duration,
targets: this.targets,
hotkey: this.hotkey,
unlocked: this.unlocked,
damage: this.damage,
delay: this.delay,
healing: this.healing,
splash: this.splash,
bonusDamage: this.bonusDamage,
};
}
}
exports.DeathTrigger = DeathTrigger;
/**
* Siege Ability - Child class for siege mode toggle abilities embedded in units
* Usage: new SiegeAbility("Siege Mode", parentId, (siege) => { siege.togglesMode = "siege"; })
*/
class Siege extends Ability {
get type() {
return "ability";
}
get slug() {
return `siege/${(0, core_js_1.slugify)(this.name)}`;
}
constructor(props) {
super();
// Static defaults as readonly fields
this.abilityType = "toggle";
// Siege/toggle properties with proper declarations
this.togglesMode = undefined;
this.hotkey = "";
this.reverseHotKey = undefined;
this.description = props.description;
Object.assign(this, props);
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
togglesMode: this.togglesMode,
duration: this.duration,
cooldown: this.cooldown,
targets: this.targets,
hotkey: this.hotkey,
reverseHotKey: this.reverseHotKey,
};
}
}
exports.Siege = Siege;
/**
* Weapon Switch Ability - Child class for weapon switching toggle abilities
* Usage: new WeaponSwitch("Weapon Switch", parentId, (switch) => { switch.switchBetween = ["sword", "blaster"]; })
*/
class WeaponSwitch extends Ability {
get type() {
return "ability";
}
get slug() {
return `weapon-switch/${(0, core_js_1.slugify)(this.name)}`;
}
constructor(props) {
super();
// Static defaults as readonly fields
this.abilityType = "toggle";
// Weapon switch properties with proper declarations
this.togglesMode = undefined;
this.hotkey = "";
this.description = props.description;
Object.assign(this, props);
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
togglesMode: this.togglesMode,
switchBetween: this.switchBetween,
cooldown: this.cooldown,
targets: this.targets,
hotkey: this.hotkey,
};
}
}
exports.WeaponSwitch = WeaponSwitch;
/**
* Upgrade Ability - Child class for upgrade abilities embedded in units
* Usage: new UpgradeAbility("Fast Legs", parentId, (upgrade) => { upgrade.fluxCost = 70; })
*/
class Upgrade extends child_js_1.Child {
get type() {
return "ability";
}
constructor(props = {}) {
super();
Object.assign(this, props);
}
/**
* Apply this upgrade's effects to the parent entity
* Must be implemented by all upgrades
*/
apply() {
// Default no-op implementation - override in subclasses
}
/**
* Apply this upgrade's effects to a target entity
* Used for cross-entity effects like auras or global buffs
* Defaults to no-op if not needed
*/
applyTo(entity) {
// Default no-op implementation
}
get subtype() {
return "upgrade";
}
toJSON() {
return {
...super.toJSON(),
description: this.description,
tier: this.tier,
fluxCost: this.fluxCost,
hexiteCost: this.hexiteCost,
researchTime: this.researchTime,
};
}
}
exports.Upgrade = Upgrade;
/**
* Passive Ability - Child class for passive abilities embedded in units
* Usage: new PassiveAbility("Regeneration", parentId, (passive) => { passive.healPerSec = 2; })
*/
class Passive extends Ability {
get type() {
return "ability";
}
get slug() {
return `passives/${(0, core_js_1.slugify)(this.name)}`;
}
// Auto-calculated damagePerSec getter based on PKL logic
get damagePerSec() {
if (this.damageOverTime != null)
return undefined;
if (this.damage == null || this.cooldown == null)
return undefined;
const amt = this.damage;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
// Auto-calculated healingPerSec getter based on PKL logic
get healingPerSec() {
const healValue = this.healing ?? this.healAmount;
if (this.healingOverTime != null)
return undefined;
if (healValue == null || this.cooldown == null)
return undefined;
const amt = healValue;
const shots = this.shots ?? 1;
const volleys = this.volleys ?? 1;
return Math.round((amt * shots * volleys) / this.cooldown);
}
constructor(props) {
super();
// Static defaults as readonly fields
this.abilityType = "passive";
this.duration = undefined;
this.range = undefined;
this.targets = [];
this.unlocked = true;
this.description = props.description;
Object.assign(this, props);
}
toJSON() {
return {
...super.toJSON(),
abilityType: this.abilityType,
description: this.description,
damage: this.damage,
healAmount: this.healAmount,
healPerSec: this.healingPerSec,
energyCost: this.energyCost,
cooldown: this.cooldown,
duration: this.duration,
range: this.range,
targets: this.targets,
unlocked: this.unlocked,
bonusDamage: this.bonusDamage,
splash: this.splash,
hotkey: this.hotkey,
};
}
}
exports.Passive = Passive;
//# sourceMappingURL=ability.js.map