UNPKG

arx-level-generator

Version:
295 lines 10.1 kB
import path from 'node:path'; import { isTiled } from 'arx-convert/utils'; import { Material } from './Material.js'; import { Rotation } from './Rotation.js'; import { Script } from './Script.js'; import { Texture } from './Texture.js'; import { Vector3 } from './Vector3.js'; const instanceCatalog = {}; export class Entity { id; /** * specify the script file for the entity with `.asl` extension * * if the ASL file for the entity has the same name as it's container folder * like `items/magic/fern/fern.asl` then you can shorten it to `items/magic/fern` */ src; position; orientation; inventoryIcon; script; model; /** * stuff that I can't put elsewhere, but needs to get exported */ otherDependencies = []; constructor(props) { this.src = props.src; this.position = props.position ?? new Vector3(0, 0, 0); this.orientation = props.orientation ?? new Rotation(0, 0, 0); if (typeof props.id === 'undefined') { instanceCatalog[this.src] = instanceCatalog[this.src] ?? []; instanceCatalog[this.src].push(this); this.id = instanceCatalog[this.src].length; } else { this.id = props.id; } this.inventoryIcon = props.inventoryIcon; this.model = props.model; this.otherDependencies = props.otherDependencies ?? []; } /** * returns the name of the entity without any id, for example "marker" */ get entityName() { return path.parse(this.src).name; } hasScript() { return typeof this.script !== 'undefined'; } hasModel() { return typeof this.model !== 'undefined'; } hasInventoryIcon() { return typeof this.inventoryIcon !== 'undefined'; } needsInventoryIcon() { if (!this.src.startsWith('items')) { return false; } if (this.src.startsWith('items/movable')) { return false; } return true; } withScript() { if (this.hasScript()) { return this; } this.script = new Script({ filename: this.entityName + '.asl', }); return this; } at({ position, orientation }) { if (typeof position !== 'undefined') { this.position = position; } if (typeof orientation !== 'undefined') { this.orientation = orientation; } return this; } clone() { return new Entity({ id: this.id, src: this.src, position: this.position.clone(), orientation: this.orientation.clone(), inventoryIcon: this.inventoryIcon?.clone(), // script: TODO, model: this.model?.clone(), otherDependencies: this.otherDependencies.map((dependency) => dependency.clone()), }); } static fromArxInteractiveObject(entity) { return new Entity({ id: entity.identifier, src: entity.name, position: Vector3.fromArxVector3(entity.pos), orientation: Rotation.fromArxRotation(entity.angle), }); } toArxInteractiveObject() { return { identifier: this.id, name: this.src, pos: this.position.toArxVector3(), angle: this.orientation.toArxRotation(), }; } /** * returns the reference to the entity that can be used in scripts, * for example "marker_0001" */ get ref() { const numericId = this.id.toString().padStart(4, '0'); return `${this.entityName}_${numericId}`; } exportScriptTarget(settings) { if (!this.hasScript()) { throw new Error("trying to export an Entity which doesn't have a script"); } if (this.script.isRoot) { return path.resolve(settings.outputDir, Script.targetPath, this.src.replace(this.script.filename, ''), this.script.filename); } return path.resolve(settings.outputDir, Script.targetPath, this.src.replace(this.script.filename, ''), this.ref, this.script.filename); } async exportInventoryIcon(settings) { const files = {}; if (!this.needsInventoryIcon()) { return files; } if (this.hasInventoryIcon() && this.inventoryIcon.isNative) { return files; } let source; let target; if (!this.hasInventoryIcon()) { this.inventoryIcon = Texture.missingInventoryIcon; source = (await this.inventoryIcon.exportSourceAndTarget(settings, false))[0]; } else { try { source = (await this.inventoryIcon.exportSourceAndTarget(settings, false, true))[0]; } catch (e) { console.error(`[error] Entity: inventory icon not found: "${this.inventoryIcon.filename}", using default fallback icon`); this.inventoryIcon = Texture.missingInventoryIcon; source = (await this.inventoryIcon.exportSourceAndTarget(settings, false))[0]; } } if (this.src.endsWith('.asl')) { target = path.resolve(settings.outputDir, 'graph/obj3d/interactive', this.src.replace(/.asl$/, '[icon].bmp')); } else { target = path.resolve(settings.outputDir, 'graph/obj3d/interactive', this.src, this.entityName + `[icon].bmp`); } files[target] = source; return files; } async exportOtherDependencies(settings) { const files = {}; for (const stuff of this.otherDependencies) { if (!stuff.isNative) { if (stuff instanceof Texture) { let hasTiledMaterialFlag = false; if (stuff instanceof Material) { hasTiledMaterialFlag = isTiled(stuff); } const [source, target] = await stuff.exportSourceAndTarget(settings, hasTiledMaterialFlag); files[target] = source; } else { const [source, target] = stuff.exportSourceAndTarget(settings); files[target] = source; } } } return files; } move(offset) { this.position.add(offset); } // ---------------- static get marker() { return new Entity({ src: 'system/marker' }); } static get torch() { return new Entity({ src: 'items/provisions/torch' }); } static get fern() { return new Entity({ src: 'items/magic/fern' }); } static get mushroom() { return new Entity({ src: 'items/provisions/mushroom/food_mushroom.asl' }); } static get key() { return new Entity({ src: 'items/quest_item/key_base' }); } static get powerStonePlace() { return new Entity({ src: 'fix_inter/power_stone_place' }); } static get powerStone() { return new Entity({ src: 'items/magic/power_stone' }); } static get lock() { return new Entity({ src: 'fix_inter/lock' }); } static get rope() { return new Entity({ src: 'items/provisions/rope' }); } static get cube() { // TODO: I'm not sure about this, but this is the only way to import a class // which extends the base Entity class return (async () => { const { Cube } = await import('./prefabs/entity/Cube.js'); return new Cube(); })(); } static get bone() { return new Entity({ src: 'items/provisions/bone' }); } static get boneWeap() { return new Entity({ src: 'items/weapons/bone_weap' }); } static get skull() { return new Entity({ src: 'items/movable/skull' }); } static get boneBassin() { return new Entity({ src: 'items/movable/bones/bone_bassin.asl' }); } static get barrel() { return new Entity({ src: 'fix_inter/barrel/barrel.asl' }); } static get brokenBottle() { return new Entity({ src: 'items/movable/broken_bottle' }); } static get brokenShield() { return new Entity({ src: 'items/movable/broken_shield' }); } static get brokenStool() { return new Entity({ src: 'items/movable/broken_stool' }); } static get seatStool1() { return new Entity({ src: 'items/movable/seat_stool1' }); } static get akbaaBloodChickenHead() { return new Entity({ src: 'items/movable/akbaa_blood_chicken_head' }); } static get hangedGob() { return new Entity({ src: 'npc/hanged_gob' }); } static get lampGoblin1() { return new Entity({ src: 'fix_inter/lamp_goblin1' }); } static get lampGoblin2() { return new Entity({ src: 'fix_inter/lamp_goblin2' }); } static get lampGoblin3() { return new Entity({ src: 'fix_inter/lamp_goblin3' }); } static get lampHuman1() { return new Entity({ src: 'fix_inter/lamp_human1' }); } static get lampHuman2() { return new Entity({ src: 'fix_inter/lamp_human2' }); } static get lampHuman3() { return new Entity({ src: 'fix_inter/lamp_human3' }); } static get lampHumanPalace() { return new Entity({ src: 'fix_inter/lamp_human_palace' }); } static get lampHumanPalaceRoom() { return new Entity({ src: 'fix_inter/lamp_human_palace_room' }); } static get lampHumanSnake1() { return new Entity({ src: 'fix_inter/lamp_human_snake1' }); } static get lampHumanSnake2() { return new Entity({ src: 'fix_inter/lamp_human_snake2' }); } static get lampHumanTorch1() { return new Entity({ src: 'fix_inter/lamp_human_torch1' }); } static get lampSnake1() { return new Entity({ src: 'fix_inter/lamp_snake1' }); } static get lampSnake2() { return new Entity({ src: 'fix_inter/lamp_snake2' }); } } //# sourceMappingURL=Entity.js.map