Repository: flowtsohg/mdx-m3-viewer Branch: master Commit: 2ff0bc00c636 Files: 496 Total size: 3.0 MB Directory structure: gitextract_a23fu6lt/ ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── Viewer.code-workspace ├── Viewer.sublime-project ├── clean.js ├── clients/ │ ├── README.md │ ├── downgrader/ │ │ ├── index.html │ │ └── index.js │ ├── example/ │ │ ├── README.md │ │ ├── index.html │ │ ├── index.js │ │ └── resources/ │ │ ├── SmileyGW_004.mdx │ │ └── Textures/ │ │ └── SmileyGW.blp │ ├── map/ │ │ ├── README.md │ │ ├── index.html │ │ └── index.js │ ├── mdlx/ │ │ ├── index.html │ │ └── index.js │ ├── mdlxoptimizer/ │ │ ├── index.html │ │ └── index.ts │ ├── melee/ │ │ ├── README.md │ │ ├── index.html │ │ └── index.js │ ├── rebuild/ │ │ ├── README.md │ │ ├── components/ │ │ │ └── rebuilder.js │ │ ├── index.html │ │ └── index.js │ ├── recorder/ │ │ ├── README.md │ │ ├── index.html │ │ └── index.js │ ├── sanitytest/ │ │ ├── README.md │ │ ├── components/ │ │ │ ├── logger.js │ │ │ ├── mdlview.js │ │ │ ├── sanitytester.js │ │ │ ├── teamcolors.js │ │ │ ├── testmeta.js │ │ │ ├── testresults.js │ │ │ ├── tooltips.js │ │ │ ├── viewer.js │ │ │ └── viewercontrols.js │ │ ├── index.css │ │ ├── index.html │ │ ├── index.js │ │ └── test.js │ ├── shared/ │ │ ├── camera.js │ │ ├── component.js │ │ ├── components/ │ │ │ └── toggle.js │ │ ├── domutils.js │ │ ├── localorhive.js │ │ └── utils.js │ ├── tests/ │ │ ├── README.md │ │ ├── components/ │ │ │ └── unittester.js │ │ ├── index.html │ │ ├── index.js │ │ ├── solvers.js │ │ ├── tests/ │ │ │ ├── base.js │ │ │ ├── m3.js │ │ │ ├── mdx.js │ │ │ └── mdxprimitives.js │ │ └── unittester.js │ ├── textureatlas/ │ │ ├── index.html │ │ └── index.js │ ├── thirdparty/ │ │ ├── filesaver.js │ │ └── resemble.js │ └── weu/ │ ├── README.md │ ├── TriggerDataCustom.txt │ ├── TriggerDataPTR129.txt │ ├── TriggerDataWEU.txt │ ├── TriggerDataYDWE.txt │ ├── components/ │ │ ├── weuchanges.js │ │ ├── weuconverter.js │ │ └── weumeta.js │ ├── index.css │ ├── index.html │ └── index.js ├── package.json ├── src/ │ ├── common/ │ │ ├── arrayunique.ts │ │ ├── audio.ts │ │ ├── binarystream.ts │ │ ├── bitstream.ts │ │ ├── bytesof.ts │ │ ├── canvas.ts │ │ ├── convertbitrange.ts │ │ ├── dxt.ts │ │ ├── fetchdatatype.ts │ │ ├── gl-matrix-addon.ts │ │ ├── index.ts │ │ ├── isformat.ts │ │ ├── math.ts │ │ ├── path.ts │ │ ├── searches.ts │ │ ├── seededrandom.ts │ │ ├── sstrhash2.ts │ │ ├── stringreverse.ts │ │ ├── typecast.ts │ │ ├── urlwithparams.ts │ │ └── utf8.ts │ ├── index.ts │ ├── parsers/ │ │ ├── blp/ │ │ │ ├── image.ts │ │ │ ├── index.ts │ │ │ ├── isformat.ts │ │ │ └── jpg.js │ │ ├── dds/ │ │ │ ├── image.ts │ │ │ ├── index.ts │ │ │ └── isformat.ts │ │ ├── index.ts │ │ ├── ini/ │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── m3/ │ │ │ ├── animationreference.ts │ │ │ ├── attachmentpoint.ts │ │ │ ├── batch.ts │ │ │ ├── bone.ts │ │ │ ├── boundingshape.ts │ │ │ ├── boundingsphere.ts │ │ │ ├── camera.ts │ │ │ ├── division.ts │ │ │ ├── event.ts │ │ │ ├── index.ts │ │ │ ├── indexentry.ts │ │ │ ├── isformat.ts │ │ │ ├── layer.ts │ │ │ ├── light.ts │ │ │ ├── materialreference.ts │ │ │ ├── md34.ts │ │ │ ├── model.ts │ │ │ ├── modelheader.ts │ │ │ ├── reference.ts │ │ │ ├── region.ts │ │ │ ├── sd.ts │ │ │ ├── sequence.ts │ │ │ ├── standardmaterial.ts │ │ │ ├── stc.ts │ │ │ ├── stg.ts │ │ │ ├── sts.ts │ │ │ └── unsupportedentry.ts │ │ ├── mdlx/ │ │ │ ├── animatedobject.ts │ │ │ ├── animationmap.ts │ │ │ ├── animations.ts │ │ │ ├── attachment.ts │ │ │ ├── bone.ts │ │ │ ├── camera.ts │ │ │ ├── collisionshape.ts │ │ │ ├── eventobject.ts │ │ │ ├── extent.ts │ │ │ ├── faceeffect.ts │ │ │ ├── genericobject.ts │ │ │ ├── geoset.ts │ │ │ ├── geosetanimation.ts │ │ │ ├── helper.ts │ │ │ ├── index.ts │ │ │ ├── isformat.ts │ │ │ ├── layer.ts │ │ │ ├── light.ts │ │ │ ├── material.ts │ │ │ ├── model.ts │ │ │ ├── particleemitter.ts │ │ │ ├── particleemitter2.ts │ │ │ ├── particleemitterpopcorn.ts │ │ │ ├── ribbonemitter.ts │ │ │ ├── sequence.ts │ │ │ ├── texture.ts │ │ │ ├── textureanimation.ts │ │ │ ├── tokenstream.ts │ │ │ └── unknownchunk.ts │ │ ├── mpq/ │ │ │ ├── adpcm.ts │ │ │ ├── archive.ts │ │ │ ├── block.ts │ │ │ ├── blocktable.ts │ │ │ ├── constants.ts │ │ │ ├── crypto.ts │ │ │ ├── explode.ts │ │ │ ├── file.ts │ │ │ ├── hash.ts │ │ │ ├── hashtable.ts │ │ │ ├── index.ts │ │ │ └── isarchive.ts │ │ ├── slk/ │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── tga/ │ │ │ ├── image.ts │ │ │ ├── index.ts │ │ │ └── isformat.ts │ │ └── w3x/ │ │ ├── doo/ │ │ │ ├── doodad.ts │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ ├── randomitem.ts │ │ │ ├── randomitemset.ts │ │ │ └── terraindoodad.ts │ │ ├── imp/ │ │ │ ├── file.ts │ │ │ ├── import.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── map.ts │ │ ├── mmp/ │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ └── minimapicon.ts │ │ ├── shd/ │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── unitsdoo/ │ │ │ ├── droppeditem.ts │ │ │ ├── droppeditemset.ts │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ ├── inventoryitem.ts │ │ │ ├── modifiedability.ts │ │ │ ├── randomunit.ts │ │ │ └── unit.ts │ │ ├── w3c/ │ │ │ ├── camera.ts │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── w3d/ │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── w3e/ │ │ │ ├── corner.ts │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── w3f/ │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ ├── maporder.ts │ │ │ └── maptitle.ts │ │ ├── w3i/ │ │ │ ├── file.ts │ │ │ ├── force.ts │ │ │ ├── index.ts │ │ │ ├── player.ts │ │ │ ├── randomitem.ts │ │ │ ├── randomitemset.ts │ │ │ ├── randomitemtable.ts │ │ │ ├── randomunit.ts │ │ │ ├── randomunittable.ts │ │ │ ├── techavailabilitychange.ts │ │ │ └── upgradeavailabilitychange.ts │ │ ├── w3o/ │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── w3r/ │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ └── region.ts │ │ ├── w3s/ │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ └── sound.ts │ │ ├── w3u/ │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ ├── modification.ts │ │ │ ├── modificationtable.ts │ │ │ └── modifiedobject.ts │ │ ├── wct/ │ │ │ ├── customtexttrigger.ts │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── wpm/ │ │ │ ├── file.ts │ │ │ └── index.ts │ │ ├── wtg/ │ │ │ ├── eca.ts │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ ├── parameter.ts │ │ │ ├── subparameters.ts │ │ │ ├── trigger.ts │ │ │ ├── triggercategory.ts │ │ │ ├── triggerdata.ts │ │ │ └── variable.ts │ │ └── wts/ │ │ ├── file.ts │ │ └── index.ts │ ├── utils/ │ │ ├── blp/ │ │ │ ├── index.ts │ │ │ └── sanitytest.ts │ │ ├── dds/ │ │ │ ├── index.ts │ │ │ └── sanitytest.ts │ │ ├── index.ts │ │ ├── jass2/ │ │ │ ├── compilenatives.ts │ │ │ ├── constanthandles.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ ├── jass2lua.ts │ │ │ ├── natives.ts │ │ │ ├── thread.ts │ │ │ ├── tokenstream.ts │ │ │ └── types/ │ │ │ ├── agent.ts │ │ │ ├── aidifficulty.ts │ │ │ ├── alliancetype.ts │ │ │ ├── animtype.ts │ │ │ ├── attacktype.ts │ │ │ ├── blendmode.ts │ │ │ ├── camerafield.ts │ │ │ ├── camerasetup.ts │ │ │ ├── damagetype.ts │ │ │ ├── dialogevent.ts │ │ │ ├── effecttype.ts │ │ │ ├── enum.ts │ │ │ ├── eventid.ts │ │ │ ├── fgamestate.ts │ │ │ ├── fogstate.ts │ │ │ ├── force.ts │ │ │ ├── gamedifficulty.ts │ │ │ ├── gameevent.ts │ │ │ ├── gamespeed.ts │ │ │ ├── gamestate.ts │ │ │ ├── gametype.ts │ │ │ ├── group.ts │ │ │ ├── handle.ts │ │ │ ├── hashtable.ts │ │ │ ├── igamestate.ts │ │ │ ├── index.ts │ │ │ ├── itemtype.ts │ │ │ ├── limitop.ts │ │ │ ├── location.ts │ │ │ ├── mapcontrol.ts │ │ │ ├── mapdensity.ts │ │ │ ├── mapflag.ts │ │ │ ├── mapsetting.ts │ │ │ ├── mapvisibility.ts │ │ │ ├── mousebuttontype.ts │ │ │ ├── pathingtype.ts │ │ │ ├── placement.ts │ │ │ ├── player.ts │ │ │ ├── playercolor.ts │ │ │ ├── playerevent.ts │ │ │ ├── playergameresult.ts │ │ │ ├── playerscore.ts │ │ │ ├── playerslotstate.ts │ │ │ ├── playerstate.ts │ │ │ ├── playerunitevent.ts │ │ │ ├── race.ts │ │ │ ├── racepreference.ts │ │ │ ├── raritycontrol.ts │ │ │ ├── rect.ts │ │ │ ├── region.ts │ │ │ ├── soundtype.ts │ │ │ ├── startlocprio.ts │ │ │ ├── subanimtype.ts │ │ │ ├── texmapflags.ts │ │ │ ├── timer.ts │ │ │ ├── trigger.ts │ │ │ ├── unit.ts │ │ │ ├── unitevent.ts │ │ │ ├── unitstate.ts │ │ │ ├── unittype.ts │ │ │ ├── version.ts │ │ │ ├── volumegroup.ts │ │ │ ├── weapontype.ts │ │ │ ├── weathereffect.ts │ │ │ ├── widget.ts │ │ │ └── widgetevent.ts │ │ ├── mappeddata.ts │ │ ├── mdlx/ │ │ │ ├── index.ts │ │ │ ├── mdlstructure.ts │ │ │ ├── primitives/ │ │ │ │ ├── createprimitive.ts │ │ │ │ └── primitives.ts │ │ │ └── sanitytest/ │ │ │ ├── data.ts │ │ │ ├── sanitytest.ts │ │ │ ├── testers.ts │ │ │ ├── tracks.ts │ │ │ └── utils.ts │ │ └── w3x/ │ │ ├── generatelistfile.ts │ │ ├── index.ts │ │ └── weu/ │ │ ├── conversions.ts │ │ ├── data.ts │ │ ├── parsewtg.ts │ │ ├── processing.ts │ │ ├── transformations/ │ │ │ ├── blz.ts │ │ │ ├── functions.ts │ │ │ ├── presets.ts │ │ │ ├── specific.ts │ │ │ └── transformer.ts │ │ ├── utils.ts │ │ └── weu.ts │ ├── version.ts │ └── viewer/ │ ├── bounds.ts │ ├── camera.ts │ ├── cell.ts │ ├── emittedobject.ts │ ├── emittedobjectupdater.ts │ ├── emitter.ts │ ├── genericresource.ts │ ├── gl/ │ │ ├── clientbuffer.ts │ │ ├── clientdatatexture.ts │ │ ├── datatexture.ts │ │ ├── gl.ts │ │ ├── index.ts │ │ └── shader.ts │ ├── grid.ts │ ├── handlerresource.ts │ ├── handlers/ │ │ ├── blp/ │ │ │ ├── handler.ts │ │ │ └── texture.ts │ │ ├── dds/ │ │ │ ├── handler.ts │ │ │ └── texture.ts │ │ ├── index.ts │ │ ├── m3/ │ │ │ ├── attachment.ts │ │ │ ├── batch.ts │ │ │ ├── bone.ts │ │ │ ├── boundingshape.ts │ │ │ ├── camera.ts │ │ │ ├── handler.ts │ │ │ ├── layer.ts │ │ │ ├── model.ts │ │ │ ├── modelinstance.ts │ │ │ ├── node.ts │ │ │ ├── region.ts │ │ │ ├── sd.ts │ │ │ ├── sequence.ts │ │ │ ├── shaders/ │ │ │ │ ├── layers.glsl.ts │ │ │ │ ├── standard.frag.ts │ │ │ │ └── standard.vert.ts │ │ │ ├── skeleton.ts │ │ │ ├── standardmaterial.ts │ │ │ ├── stc.ts │ │ │ ├── stg.ts │ │ │ ├── sts.ts │ │ │ └── texture.ts │ │ ├── mdx/ │ │ │ ├── animatedobject.ts │ │ │ ├── attachment.ts │ │ │ ├── attachmentinstance.ts │ │ │ ├── batch.ts │ │ │ ├── batchgroup.ts │ │ │ ├── bone.ts │ │ │ ├── camera.ts │ │ │ ├── collisionshape.ts │ │ │ ├── emitter.ts │ │ │ ├── emittergroup.ts │ │ │ ├── eventobjectemitter.ts │ │ │ ├── eventobjectemitterobject.ts │ │ │ ├── eventobjectsnd.ts │ │ │ ├── eventobjectsndemitter.ts │ │ │ ├── eventobjectsplemitter.ts │ │ │ ├── eventobjectsplubr.ts │ │ │ ├── eventobjectspn.ts │ │ │ ├── eventobjectspnemitter.ts │ │ │ ├── eventobjectubremitter.ts │ │ │ ├── filtermode.ts │ │ │ ├── genericobject.ts │ │ │ ├── geometryemitterfuncs.ts │ │ │ ├── geoset.ts │ │ │ ├── geosetanimation.ts │ │ │ ├── handler.ts │ │ │ ├── helper.ts │ │ │ ├── layer.ts │ │ │ ├── light.ts │ │ │ ├── material.ts │ │ │ ├── model.ts │ │ │ ├── modelinstance.ts │ │ │ ├── node.ts │ │ │ ├── particle.ts │ │ │ ├── particle2.ts │ │ │ ├── particleemitter.ts │ │ │ ├── particleemitter2.ts │ │ │ ├── particleemitter2object.ts │ │ │ ├── particleemitterobject.ts │ │ │ ├── replaceableids.ts │ │ │ ├── ribbon.ts │ │ │ ├── ribbonemitter.ts │ │ │ ├── ribbonemitterobject.ts │ │ │ ├── sd.ts │ │ │ ├── sequence.ts │ │ │ ├── setupgeosets.ts │ │ │ ├── setupgroups.ts │ │ │ ├── shaders/ │ │ │ │ ├── hd.frag.ts │ │ │ │ ├── hd.vert.ts │ │ │ │ ├── particles.frag.ts │ │ │ │ ├── particles.vert.ts │ │ │ │ ├── sd.frag.ts │ │ │ │ ├── sd.vert.ts │ │ │ │ └── transforms.glsl.ts │ │ │ ├── texture.ts │ │ │ └── textureanimation.ts │ │ ├── shaders/ │ │ │ ├── bonetexture.glsl.ts │ │ │ ├── precision.glsl.ts │ │ │ └── quattransform.glsl.ts │ │ ├── tga/ │ │ │ ├── handler.ts │ │ │ └── texture.ts │ │ └── w3x/ │ │ ├── doodad.ts │ │ ├── map.ts │ │ ├── shaders/ │ │ │ ├── cliffs.frag.ts │ │ │ ├── cliffs.vert.ts │ │ │ ├── ground.frag.ts │ │ │ ├── ground.vert.ts │ │ │ ├── water.frag.ts │ │ │ └── water.vert.ts │ │ ├── standsequence.ts │ │ ├── terraindoodad.ts │ │ ├── terrainmodel.ts │ │ ├── unit.ts │ │ ├── variations.ts │ │ ├── viewer.ts │ │ └── widget.ts │ ├── imagetexture.ts │ ├── index.ts │ ├── model.ts │ ├── modelinstance.ts │ ├── node.ts │ ├── resource.ts │ ├── scene.ts │ ├── skeletalnode.ts │ ├── texture.ts │ └── viewer.ts ├── tsconfig.json ├── types/ │ ├── fengari.d.ts │ └── tga-js.d.ts └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintignore ================================================ dist clients thirdparty webpack.config.js clean.js ================================================ FILE: .eslintrc.json ================================================ { "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 9, "sourceType": "module", "project": ["./tsconfig.json"] }, "plugins": [ "@typescript-eslint" ], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended" ], "rules": { "eol-last": "error", "@typescript-eslint/indent": [ "error", 2 ], "no-tabs": "error", "@typescript-eslint/semi": "error", "@typescript-eslint/no-extra-semi": 2, "prefer-const": "error", "@typescript-eslint/object-curly-spacing": [ "error", "always", { "arraysInObjects": false, "objectsInObjects": false }], "array-bracket-spacing": ["error", "never"], "@typescript-eslint/no-unnecessary-type-assertion": "error", "no-return-await": "error", "@typescript-eslint/explicit-function-return-type": "error", "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }], "@typescript-eslint/no-empty-function": "warn", "no-empty": "warn" } } ================================================ FILE: .gitignore ================================================ node_modules dist package-lock.json ================================================ FILE: .npmignore ================================================ .* **/tsconfig.json **/webpack.config.js node_modules Viewer.code-workspace Viewer.sublime-project src clients dist/clients clean.js ================================================ FILE: CONTRIBUTING.md ================================================ If you want to contribute, here are a few notes: 1) If the changes are related in any way to the viewer itself (parsers that are used, handlers, shaders, etc.), then the unit tests must all pass. This of course doesn't include unit tests that are directly related to the changes, and thus need to be updated. 2) If the changes are related to real-time parts of the code, they should be efficient! There are no such things as real-time heap allocations (e.g. `new`, `[]`, `{}`), typed arrays are generally preferred for data storage over arrays/objects, and so on. 3) Use `npm run dev` to start webpack in watch mode and re-build the source as you write it. 4) Have fun :) ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013-2021 Chananya Freiman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ **NO LONGER ACTIVELY MAINTAINED.** mdx-m3-viewer ============= At the core of it, a 3D model viewer for MDX and M3 models used by the games Warcraft 3 and Starcraft 2 respectively. The viewer part handles the following formats: * MDX (Warcraft 3 model): extensive support, almost everything should work. * M3 (Starcraft 2 model): partial support. * W3M/W3X (Warcraft 3 map): partial support. * BLP1 (Warcraft 3 texture): extensive support, almost everything should work. * TGA (image): extensive support, almost everything should work. * DDS (compressed texture): partial support - DXT1/DXT3/DXT5/RGTC. * PNG/JPG/GIF/WebP: supported by the browser. There are file parsers that the viewer depends on.\ These don't rely on the viewer or indeed on even running in a browser.\ They include: * MDX/MDL: read/write. * M3: read. * BLP1: read. * INI: read/write. * SLK: read/write. * MPQ1: read/write. * W3M/W3X/W3N: read/write, including all of the internal files. * DDS: read (DXT1/DXT3/DXT5/RGTC). * TGA: read. There are all sorts of utilities that were made over the years.\ These include things like... * The library's unit tester, which compares rendered results against stored images that were generated in the same way. * The MDX sanity test, which looks for errors and weird things in MDX models. * A Jass context that can...well, run Jass code. That being said, it really runs Lua code converted from Jass, on a JS Lua VM. What a tongue twiser. While it supports some Warcraft 3 natives, don't expect it run whole maps. Maybe in the future 😉 * A utility that makes it possible to open Warcraft 3 maps in the vanilla World Editor, in cases were said maps used a non-vanilla editor with extended GUI, in which case they crash upon opening in the official editor. * etc. Finally, the library also comes with a bunch of clients.\ A "client" in this context means external code that uses the library.\ Most of these clients are simple and messy, since they were made as side projects while working on the library.\ Most of these clients are also just wrappers around the viewer and the utilities, merely giving them an interface on a web page.\ These include things like... * A simple example client. * The unit tester's page, which allows to run the unit tests, and to download the results. * The MDX sanity test's page, which visually shows the results of sanity tests, and other nifty things. * etc. ------------------------ #### Building ``` npm install mdx-m3-viewer npm run build ``` This will generate the CommonJS, UMD, and the packed clients under `dist`. ------------------------ #### Examples Run the Webpack dev server with: ``` npm run serve ``` Once it compiled the code, open `http://localhost:8080/clients/example/` in the browser, and play with the client's source to see how things change. You can also check out the other available clients. ------------------------ #### Importing You can import the viewer in different ways: ```javascript // UMD export in the browser. new ModelViewer.viewer.ModelViewer(canvas); // require/import the library. const ModelViewer = require('mdx-m3-viewer'); // CommonJS. import ModelViewer from 'mdx-m3-viewer'; // ES6. new ModelViewer.viewer.ModelViewer(canvas); // require/import something directly. const ModelViewer = require('mdx-m3-viewer/src/viewer/viewer'); // CommonJS. import ModelViewer from 'mdx-m3-viewer/src/viewer/viewer'; // ES6. new ModelViewer(canvas); ``` When developing with TypeScript, nothing needs to be done to get correct typings. This is true also when importing specific files, which means a client can import only what it needs from the library. All code snippets will use the names as if you imported them directly to avoid some mess. See the examples for actual namespacing. ------------------------ #### Usage First, let's create the viewer: ```javascript let canvas = ...; // A aka HTMLCanvasElement object. let viewer = new ModelViewer(canvas); ``` If the client doesn't have the WebGL requierments to run the viewer, an exception will be thrown when trying to create it. Now that we have a viewer, a scene can be created. Each scene has its own camera and viewport, and holds a list of things to update and render. ```javascript let scene = viewer.addScene(); // Move the camera backwards a bit, so we can actually see the origin. scene.camera.move([0, 0, 500]); ``` Finally, we need to actually let the viewer update and render: ```javascript (function step() { requestAnimationFrame(step); viewer.updateAndRender(); }()); ``` --- Models and textures are loaded with the `load` function. To load models and textures with `load`, the viewer must have handlers that tell it how to load the different file formats.\ If you want to load an MDX model, the MDX handler must be added to the viewer, and so on.\ This is done with the `addHandler` function, and the different handlers are exported as a part of the library. Let's add the MDX and BLP handlers: ```javascript viewer.addHandler(handlers.mdx); viewer.addHandler(handlers.blp); ``` Now MDX (and MDL) and BLP files will be accepted by the viewer. Suppose we have the following directory structure, where `model.mdx` uses `texture.blp`: ``` ├── index.html └── Resources ├── model.mdx └── texture.blp ``` Loading the model is simple: ```javascript let modelPromise = viewer.load("Resources/model.mdx"); ``` You get back a promise, which will resolve to either the MDX model, or to undefined if any error occured. When the MDX model loads, it also loads internal resources, like its textures, so the viewer will attempt to fetch `texture.blp`.\ If the server knows this is a relative path to `Resources/` then all is fine.\ It is typically a lot easier and more dynamic to control the paths on the client though.\ This is done with "path solvers" - functions that, given a source to load from, such as a path, can modify it and return the actual source to load from.\ It will probably make more sense with code - let's load the model again, with the texture fetch asking for the correct path: `Resources/texture.blp`. ```javascript function pathSolver(path) { return "Resources/" + path; } let modelPromise = viewer.load("model.mdx", pathSolver); ``` Here's the short version of what happens: 1. `pathSolver` is called with `"model.mdx"` and returns `"Resources/model.mdx"`. 2. The viewer starts the fetch, and emits the `loadstart` event. 3. A promise is returned. 4. ...time passes until the file finishes loading... 5. The viewer detects the format as MDX based on the file data (the url is irrelevant to this process). 6. The model is constructed successfuly, or not, with a `load` or `error` event sent respectively, followed by the `loadend` event. 7. In the case of an MDX model, the previous step will also cause it to load its textures. 8. `pathSolver` is called with `"texture.blp"`, which returns `"Resources/texture.blp"`, and we loop back to step 2, but with a texture this time. Path solvers can return promises which will be waited upon, and they can return models and textures directly for injections. Generally speaking, you'll need a simple path solver that expects urls and prepends them by some base directory or API url.\ There are however times when this is not the case, such as loading models with custom textures, and handling both in-memory and fetches in the same solver as done in the map viewer. Once the promise is resolved, we have a model, however a model in this context is simply a source of data.\ The next step is to create an instance of this model.\ Instances can be rendered, moved, rotated, scaled, parented to other instances or nodes, play animations, and so on. ```javascript let instance = model.addInstance(); ``` And finally add the instance to the scene, so it's updated and rendered: ```javascript instance.setScene(scene); // Equivalent to: scene.addInstance(instance); ``` --- Other resources, such as SLK tables and INI configurations, are loaded with `loadGeneric`. ```javascript let resourcePromise = viewer.loadGeneric(path, dataType[, callback]); ``` Where: * `path` is an url string. * `dataType` is a string with one of these values: `text`, `arrayBuffer`, `blob`, `bytes`, or `image`. * `callback` is an optional function that will be called with the data once the fetch is complete, and should return the resource's data. If a callback is given, `resource.data` will be whatever the callback returns.\ If a promise is returned, the loader waits for it to resolve, and uses whatever it resolved to.\ If no callback is given, the data will be the fetch data itself, according to the given data type (`bytes` refers to a `Uint8Array`). `loadGeneric` is a simple layer above the standard `fetch` function.\ The purpose of loading other files through the viewer is to cache the results and avoid multiple loads, while also allowing the viewer itself to handle events correctly. ------------------------ #### Events and Promises As mentioned above, there are emitted events, and they can be used with the NodeJS EventEmitter API: ```javascript viewer.on(eventName, listener) viewer.off(eventName, listener) viewer.once(eventName, listener) viewer.emit(eventName[, ...args]) ``` The built-in names are: * `loadstart` - a resource started loading. * `load` - a resource successfully loaded. * `error` - something bad happened. * `loadend` - a resource finished loading, follows both `load` and `error` when loading a resource. * `idle` - all loads finished for now. For example: ```javascript viewer.on('error', (e) => console.log(e)); ``` In addition there is `viewer.whenAllLoaded([callback])`, which can be used to run code when nothing is loading. If a callback is given, it will be called, otherwise a promise is returned. If there are no resources currently being loaded, this will happen instantly. Otherwise, it will happen once the `idle` event is emitted. ```javascript viewer.whenAllLoaded((viewer) => { // Nothing is loading! }); viewer.whenAllLoaded() .then((viewer) => { // Nothing is loading! }); ``` --- And now some more specific information and tips. #### Team colors, event objects, and Reforged When loading an MDX model that uses team color/glow textures, it will tell the handler to load all of the team textures. Similarly, if an MDX model has event objects, it will tell the handler to load the needed SLK files. The handler uses `load` much like the client does, and thus the same implications apply - if the server is set for the relative paths, all is fine, otherwise a path solver should be used. A path solver can be passed when adding the handler: ```javascript viewer.addHandler(handlers.mdx, wc3PathSolver); ``` The handler also selects between TFT (16) and Reforged (28) team colors.\ These will be used regardless of whether any specific model being rendered is a TFT or Reforged model.\ The default mode is TFT, and it can be changed by passing true as the third parameter when adding the handler: ```javascript viewer.addHandler(handlers.mdx, wc3PathSolver, true); // Reforged team colors and event objects. ``` #### Interacting with model instances Model instances are nodes, and can be transformed as such: ```javascript instance.setLocation([50, 0, 0]); // Move to the given point. instance.move([50, 0, 0]); // Move by the given offset. instance.setRotation([0, 0, 0, 1]); // Set the rotation to the given quaternion. instance.rotate([0, 0, 0, 1]); // Rotate by the given quaternion. instance.setScale([2, 2, 2]); // Set the scale to the given vector. instance.scale([2, 2, 2]); // Scale by the given vector. instance.setUniformScale(2); // Set the scale to the given number. instance.uniformScale(2); // Scale by the given number. instance.face([50, 0, 0], [0, 0, 1]); // Face the given point, with the given "up" vector. instance.setParent(nodeOrInstance); // Set a parent, making all other transformations relative to it. instance.setParent(); // Remove the parent. ``` Both MDX and M3 instances can run animations, have team colors, etc.: ```javascript instance.setSequence(-1); // No animation. instance.setSequence(0); // First animation. instance.setSequenceLoopMode(0); // Never loop animations. instance.setSequenceLoopMode(1); // Loop animations based on the model. instance.setSequenceLoopMode(2); // Always loop animations. instance.setTeamColor(0); // First team color. instance.setVertexColor([1, 0, 0]); // Red vertex color. let node = instance.getAttachment(0); // Get the first attachment point. ``` MDX instances have `setTexture`, `setParticle2Texture`, and `setEventTexture`, to override textures, particle emitter textures, and event object textures: ```javascript instance.setTexture(0, myTexture); // Override texture 0. instance.setParticle2Texture(0, myTexture); // Override the texture of particle emitter 0. instance.setEventTexture(0, myTexture); // Override the texture of event emitter 0. instance.setTexture(0); // Remove the override, same with the other functions. ``` M3 instances have `setTexture`: ```javascript instance.setTexture(1, 0, myTexture); // Override texture 0 of standard material 1. ``` #### Solver Params: Reforged and the map viewer It is in fact possible to send more data to path solvers with `load`. The full signature is as follows: ```javascript let resourcePromise = viewer.load(src[, pathSolver[, solverParams]]); ``` Where `solverParams` can be anything. When `solverParams` exists, it will be sent to the path solver as the second argument: ```javascript function pathSolver(src, solverParams) { // ... } ``` The MDX handler and the map viewer use `solverParams` to select between SD/HD Reforged resources, and to select specific tileset resources. The MDX handler defines the parameters as such: `{reforged?: boolean, hd?: boolean}`.\ The map viewer defines them as such: `{reforged?: boolean, hd?: boolean, tileset: string}`. If `reforged` is falsy or doesn't exist, they want a TFT resource.\ If `reforged` is true, they want a Reforged SD resource and...\ If `hd` and `reforged` are true, they want a Reforged HD resource. For example, when a new MDX model is being loaded, and it is detected as a Reforged model (version > 800), any internal resources like its textures will be loaded with `solverParams = {reforged: true}`, and if the model is detected to be HD: `solverParams = {reforged: true, hd: true}`. You can also manually supply your own parameters.\ For example, let's suppose we want to load the Warcraft 3 Footman model, but with a twist - we want all three versions of it - RoC/TFT, Reforged SD, and Reforged HD.\ The loading code can be something along these lines: ```js let TFT = viewer.load('Units/Human/Footman/Footman.mdx', mySolver); let SD = viewer.load('Units/Human/Footman/Footman.mdx', mySolver, {reforged: true}); let HD = viewer.load('Units/Human/Footman/Footman.mdx', mySolver, {reforged: true, hd: true}); ``` So what does the path solver do with `solverParams`?\ As always, that depends on the client.\ For example, the solver may append the parameters as url parameters, and the server selects the game based on them.\ The solver can also completely ignore these parameters and return whatever resources it wants. #### Starcraft 2 models are tiny SC2 models are tiny compared to WC3 models.\ If a client needs models of both games to co-exist, it's suggested to scale SC2 models by 100.\ This can be done with something along the lines of: ```javascript let instance = model.addInstance(); if (model instanceof handlers.m3.resource) { instance.uniformScale(100); } ``` #### Loading resources from memory Resources don't have to be fetched - if you have the data, you can load it directly.\ Nothing special is needed, simply use it as you would an url: ```javascript let resourcePromise = viewer.load(buffer); ``` Say a web page wants to load MDX models from local files that are dragged into it.\ After some event handling, you end up with data such as a `string` or an `ArrayBuffer`. Practically speaking, most MDX models will attempt to load Warcraft 3 textures.\ This means that if we load the model directly, it will fail to load the textures, unless as always, the server is set for the relative paths. A path solver can again simplify the load: ```javascript function pathSolver(src) { if (src === buffer) { return src; } return wc3PathSolver(src); } viewer.load(buffer, pathSolver); ``` When the thing being loaded is the buffer, it will be used, otherwise, e.g. for the textures, the Warcraft 3 path solver will be used instead. #### Primitive shapes It is possible to construct primitive shapes with `createPrimitive`, which is available under `utils.mdlx.createPrimitive`. The function expects an object describing a primitive geometry, which can be obtained via the different functions in `utils.mdlx.primitives`. An optional material can be given, which can control the render mode between polygons and lines, the color, texture, and such. For example: ```javascript let modelPromise = createPrimitive(viewer, primitives.createUnitCube(), { color: [1, 0, 0] }); ``` Note that this loads a standard MDX model which can be used like any other MDX model. #### Sounds MDX models have sound emitters, and the viewer supports them. If sound is desired, `viewer.audioEnabled` should be set to true BEFORE loading models.\ This signals to the MDX handler that sound is desired, and it will load the neccessary sound files when loading models.\ If `audioEnabled` isn't true, the sound files aren't downloaded in the first place to reduce file fetching. To get the sounds to actually run, you must call `scene.enableAudio()`, which returns a promise that resolves to whether audio was actually enabled.\ There are two reasons for it to fail - either because the browser simply does not support audio, or because the browser did not want to enable audio.\ The latter will happen if you attempt to enable audio before the user made any interaction with the page (like clicking something). This is a browser policy and there is no control over it. If audio was enabled, you will hear familiar sounds when running animations, like attack sounds, death sounds, and so on.\ Not enough work was put into them to have the same feel as Warcraft 3, but it's sometimes a fun surprise to suddenly hear a model making sounds in the browser. #### Scene composition You can have any number of scenes you want. Each scene offers the following to control how it's composed on the canvas: * `viewport` - the position and size of the scene in pixels (defaults to the entire canvas). * `alpha` - determines whether the scene has a background, or can be seen through (defaults to false - has a background). * `color` - the background color, which is used when `alpha` is false (defaults to black). ```javascript scene.viewport[0] = 100; // X offset from the left side of the canvas. scene.viewport[1] = 100; // Y offset from the bottom side of the canvas. scene.viewport[2] = 200; // Width. scene.viewport[3] = 200; // Height. scene.alpha = false; // Opaque, i.e. has a background (and also the default). scene.color[0] = 1; // Red background. scene.color[1] = 0; scene.color[2] = 0; ``` The order in which the scenes are drawn is based on the order of creation, but you can manually move scenes around in `viewer.scenes`. For example, let's say we want to mimic how Warcraft 3 looks. This could be done with 3 scenes: 1) The game world. 2) The UI with `alpha = true` so that where the UI isn't drawn, the game world will be seen through. 3) The selected portrait, moved and sized to be on the correct portion of the UI. #### Everything is blurry WebGL uses a canvas as its back buffer, meaning it has the same amount of pixels as the canvas does. Surprising, right?\ What may actually surprise you, however, is that the canvas back buffer isn't neccassarily the size it is drawn at, due to CSS styling.\ For example, you can have a canvas that is scaled via CSS to the entire page, but if you never set its actual size, it will probably be a 100x100 pixel canvas (or whatever default size the browser uses), stretched to the page size.\ If you want to set the size of the back buffer, i.e. the real resolution of the canvas, use the `width` and `height` properties of the canvas, rather than CSS properties such as `clientWidth` and `clientHeight`. ```javascript // Could be a static size. canvas.width = 512; canvas.height = 512; // Or perhaps scaled with CSS, if you put this in a resize event listener. canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; // This however only changes the CSS size, not the canvas resolution! canvas.clientWidth = 512; canvas.clientHeight = 512; // Nor does this. canvas.style.width = '512px'; canvas.style.height = '512px'; ``` #### Variable frames per second `ModelViewer.update()` and `ModelViewer.updateAndRender()` have an optional `dt` argument. `dt` controls how much time in miliseconds to advance the animations. By default, `dt` is set for 60FPS, or `1000 / 60`. If a client runs on a >60Hz monitor, and uses `requestAnimationFrame` for its main loop as it should, animations will run faster than they should. In other cases, a client might have too many things rendering and it slows down, causing animations to go slow motion. To support a variable FPS while keeping the same animation speed, `dt` can be controlled dynamically, for example: ```javascript let lastTime = performance.now(); (function step() { requestAnimationFrame(step); let now = performance.now(); // The faster the FPS, the lower dt will be. // Twice the FPS? half the dt. // There are more frames per second, so every frame advances the animation less. // And the other way is also true. // Half the FPS? twice the dt. // There are less frames per second, so every frame advances the animation more. let dt = now - lastTime; lastTime = now; viewer.updateAndRender(dt); }()); ``` ================================================ FILE: Viewer.code-workspace ================================================ { "folders": [ { "path": "." } ], "settings": { "editor.tabSize": 2, "files.eol": "\n", "typescript.preferences.quoteStyle": "single", "typescript.validate.enable": true, "editor.formatOnSave": true, "eslint.lintTask.enable": true, "eslint.validate": [ "typescript" ], "workbench.editor.enablePreview": false, "typescript.tsdk": "node_modules\\typescript\\lib" } } ================================================ FILE: Viewer.sublime-project ================================================ { "folders": [ { "path": "." } ], "tab_size": 2, "translate_tabs_to_spaces": true, "use_tab_stops": true, } ================================================ FILE: clean.js ================================================ // See https://stackoverflow.com/a/52526549/2503048 var fs = require('fs'); function deleteFolderRecursive(path) { if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) { fs.readdirSync(path).forEach(function (file, index) { var curPath = path + "/" + file; if (fs.lstatSync(curPath).isDirectory()) { // recurse deleteFolderRecursive(curPath); } else { // delete file fs.unlinkSync(curPath); } }); console.log(`Deleting directory "${path}"...`); fs.rmdirSync(path); } } console.log("Cleaning build files..."); deleteFolderRecursive("./dist/cjs"); deleteFolderRecursive("./dist/umd"); console.log("Successfully cleaned the build files!"); console.log("Running TSC and Webpack, it might take a while..."); ================================================ FILE: clients/README.md ================================================ Over the years, many different clients were made with this library. Most of them have gone into the pages of forgotten history, but some remain. I present them as-is, in their messy state, so that they may perhaps help anyone who wants to use the library, or for anyone wanting to improve them. Note that if the web page you open doesn't point to `127.0.0.1` (e.g. you are using a remote server, or using `localhost` instead), all downloads will be redirected to the Hiveworkshop. Once upon a time Ralle, the Hive's owner, said he's ok with this. If at any point this changes, I will remove this information from the repository. Due to this, for the time being, all of the clients should run out of the box. ================================================ FILE: clients/downgrader/index.html ================================================ 
Drag & Drop a Warcraft 3 "new" map (~1.29 and onwards) to downgrade it back to an "old" map (~1.28 and backwards).
This currently handles the map information, doodads/destructibles, and units/items.
Triggers of Reforged maps (1.32) will be deleted, because my code doesn't (yet?) support Reforged triggers.
================================================ FILE: clients/downgrader/index.js ================================================ import War3Map from '../../src/parsers/w3x/map'; import War3MapW3i from '../../src/parsers/w3x/w3i/file'; import War3MapDoo from '../../src/parsers/w3x/doo/file'; import War3MapUnitsDoo from '../../src/parsers/w3x/unitsdoo/file'; document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); const file = e.dataTransfer.files[0]; const reader = new FileReader(); reader.addEventListener('loadend', (e) => { const buffer = e.target.result; const map = new War3Map(); map.load(buffer); const w3i = new War3MapW3i(); w3i.load(map.get('war3map.w3i').arrayBuffer()); if (w3i.version > 25) { console.log(`war3map.w3i version ${w3i.version} => 25`); w3i.version = 25; map.set('war3map.w3i', w3i.save()); } const buildVersion = w3i.getBuildVersion(); if (buildVersion > 131) { console.log(`war3map.doo buildVersion ${buildVersion} => 0`); const doo = new War3MapDoo(); doo.load(map.get('war3map.doo').arrayBuffer(), buildVersion); console.log(doo) map.set('war3map.doo', doo.save(0)); console.log(`war3mapUnits.doo buildVersion ${buildVersion} => 0`); const unitsDoo = new War3MapUnitsDoo(); unitsDoo.load(map.get('war3mapUnits.doo').arrayBuffer(), buildVersion); console.log(unitsDoo) map.set('war3mapUnits.doo', unitsDoo.save(0)); console.log('Deleting the triggers, because this is a Reforged map, and my code does not support Reforged triggers (yet?)'); map.delete('war3map.wtg'); } saveAs(new Blob([map.save().buffer], { type: 'application/octet-stream' }), 'downgraded_' + file.name); }); reader.readAsArrayBuffer(file); }); ================================================ FILE: clients/example/README.md ================================================ A simple example client. Thanks to Frank from the HiveWorkshop for the MDX model and BLP texture! ================================================ FILE: clients/example/index.html ================================================  MDX Example ================================================ FILE: clients/example/index.js ================================================ import * as ModelViewer from '../../src/'; import { setupCamera } from '../shared/camera'; const handlers = ModelViewer.viewer.handlers; let canvas = document.getElementById('canvas'); canvas.width = 800; canvas.height = 600; // Create the viewer! let viewer = new ModelViewer.viewer.ModelViewer(canvas); // Create a new scene. Each scene has its own camera, and a list of things to render. let scene = viewer.addScene(); // Check camera.js! setupCamera(scene); // Events. viewer.on('loadstart', (e) => console.log(e)); viewer.on('load', (e) => console.log('load', e)); viewer.on('loadend', (e) => console.log('loadend', e)); viewer.on('error', (e) => console.log('error', e)); // Add the MDX handler. // Note that this also loads all of the team colors/glows. // You can optionally supply a path solver (look below) to point the viewer to the right location of the textures. // Additionally, a boolean can be given that selects between RoC/TFT and Reforged team colors. // For example: // viewer.addHandler(handlers.mdx, pathSolver); // Roc/TFT = 14 teams. // viewer.addHandler(handlers.mdx, pathSolver, true); // Reforged = 28 teams. // In the case of this example, team colors aren't used, so it's fine for their loads to simply fail. viewer.addHandler(handlers.mdx); // Add the BLP handler. viewer.addHandler(handlers.blp); // A path solver is used for every load call. // Given a possibly relative source, it should return the actual source to load from. // This can be in the form of an URL string, or direct sources from memory (e.g. a previously loaded ArrayBuffer). function pathSolver(src) { return 'resources/' + src; } // Load our MDX model! let modelPromise = viewer.load('SmileyGW_004.mdx', pathSolver); modelPromise.then((model) => { // The promise can return undefined if something went wrong! if (model) { // Create an instance of this model. let instance = model.addInstance(); // Set the instance's scene. // Equivalent to scene.addInstance(instance) instance.setScene(scene); // Want to run the second animation. // 0 is the first animation, and -1 is no animation. instance.setSequence(1); // Tell the instance to loop animations forever. // This overrides the setting in the model itself. instance.setSequenceLoopMode(2); // Let's create another instance and do other stuff with it. let instance2 = model.addInstance(); instance2.setScene(scene); instance2.setSequence(0); instance2.setSequenceLoopMode(2); instance2.move([100, 100, 0]); instance2.uniformScale(0.5); // And a third one. let instance3 = model.addInstance(); instance3.setScene(scene); instance3.setSequence(2); instance3.setSequenceLoopMode(2); instance3.move([-100, -100, 0]); } }); // The viewer has the update(), startFrame(), render(), and updateAndRender() functions. // Generally speaking, you will want a simple never ending loop like the one that follows, but who knows. The control is in your hands. (function step() { requestAnimationFrame(step); viewer.updateAndRender(); })(); ================================================ FILE: clients/map/README.md ================================================ A Warcraft 3 map viewer client. Drag and drop a map file (W3X, W3M) into the page. ================================================ FILE: clients/map/index.html ================================================  Map | HIVE
Loading the page
================================================ FILE: clients/map/index.js ================================================ import { basename, extname } from "../../src/common/path"; import War3MapViewer from '../../src/viewer/handlers/w3x/viewer'; import { setupCamera } from "../shared/camera"; import localOrHive from "../shared/localorhive"; let statusElement = document.getElementById('status'); statusElement.textContent = 'Initializing the viewer'; let canvas = document.getElementById('canvas'); // true because the Reforged Hive API is used in localOrHive. let viewer = new War3MapViewer(canvas, localOrHive, true); let thingsLoading = []; function updateStatus() { if (thingsLoading.length) { statusElement.textContent = `Loading ${thingsLoading.join(', ')}`; } else { statusElement.textContent = ''; } } for (let key of viewer.promiseMap.keys()) { thingsLoading.push(basename(key)); } updateStatus(); viewer.on('loadstart', ({ fetchUrl }) => { thingsLoading.push(basename(fetchUrl)); updateStatus(); }); viewer.on('loadend', ({ fetchUrl }) => { let file = basename(fetchUrl); let index = thingsLoading.indexOf(file); if (index !== -1) { thingsLoading.splice(index, 1); updateStatus(); } }); let meter = new FPSMeter({ position: 'absolute', right: '10px', top: '10px', left: 'calc(100% - 130px)', theme: 'transparent', heat: 1, graph: 1 }); let cellsElement = document.getElementById('cells'); let instancesElement = document.getElementById('instances'); let particlesElement = document.getElementById('particles'); (function step() { requestAnimationFrame(step); viewer.updateAndRender(); meter.tick(); cellsElement.textContent = `Cells: ${viewer.visibleCells}`; instancesElement.textContent = `Instances: ${viewer.visibleInstances}`; particlesElement.textContent = `Particles: ${viewer.updatedParticles}`; }()); document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); if (viewer.loadedBaseFiles) { let file = e.dataTransfer.files[0]; let name = file.name; let ext = extname(name); if (ext === '.w3m' || ext === '.w3x') { let reader = new FileReader(); reader.addEventListener('loadend', e => { viewer.loadMap(e.target.result); setupCamera(viewer.map.worldScene, { distance: 3000 }); }); reader.readAsArrayBuffer(file); } } }); ================================================ FILE: clients/mdlx/index.html ================================================  MDX <-> MDL
Drop any combination of models (.mdl, .mdx) to convert them
================================================ FILE: clients/mdlx/index.js ================================================ import { extname } from "../../src/common/path"; import { version } from "../../src/version"; import Model from '../../src/parsers/mdlx/model'; console.log('Viewer version', version); document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); for (let file of e.dataTransfer.files) { let name = file.name; let ext = extname(name); if (ext === '.mdx' || ext === '.mdl') { let reader = new FileReader(); reader.addEventListener('loadend', (e) => { let model = new Model(); model.load(e.target.result); let buffer; let type; if (ext === '.mdl') { buffer = model.saveMdx().buffer; type = 'application/octet-stream'; ext = 'mdx'; } else { buffer = model.saveMdl(); type = 'text/plain'; ext = 'mdl' } saveAs(new Blob([buffer], { type }), name.slice(0, -3) + ext); }); if (ext === '.mdl') { reader.readAsText(file); } else { reader.readAsArrayBuffer(file); } } } }); ================================================ FILE: clients/mdlxoptimizer/index.html ================================================  MDLX Optimizer ================================================ FILE: clients/mdlxoptimizer/index.ts ================================================ import { extname } from "../../src/common/path"; // @ts-ignore import { getAllFileEntries, readEntry } from "../shared/utils"; import MdlxModel from '../../src/parsers/mdlx/model'; import AnimatedObject from '../../src/parsers/mdlx/animatedobject'; import { Animation } from '../../src/parsers/mdlx/animations'; import { getValuesDiff } from '../../src/utils/mdlx/sanitytest/tracks'; type Value = Uint32Array | Float32Array; type Entry = [number, Value, Value, Value]; const FRAME = 0; const VALUE = 1; const INTAN = 2; const OUTTAN = 3; function optimizeAnimation(model: MdlxModel, animation: Animation) { const sequences = model.sequences; const { interpolationType, globalSequenceId, frames, values, inTans, outTans } = animation; if (globalSequenceId !== -1) { console.error('NEED TO ADD GLOBAL ANIMATION SUPPORT'); return 0; } // Map the keyframes to entries, and remove duplicated frames while we're at it. const entryMap = new Map(); for (let i = 0, l = frames.length; i < l; i++) { entryMap.set(frames[i], [frames[i], values[i], inTans[i], outTans[i]]) } // Now back to an array. const entries: Entry[] = [...entryMap.values()]; // And sort it. entries.sort((a, b) => a[FRAME] - b[FRAME]); // Get all of the edge entries. // In other words, the frames of the current first and last entries for every sequence. const edges = new Set(); for (const sequence of sequences) { const [start, end] = sequence.interval; let startFrame = Infinity; let endFrame = Infinity; for (const entry of entries) { const frame = entry[FRAME]; if (startFrame === Infinity && frame - start >= 0) { startFrame = frame; } if (end - frame >= 0) { endFrame = frame; } } edges.add(startFrame); edges.add(endFrame); } const keptEntries: Entry[] = []; // Now we can iterate over the entries. for (let i = 0, l = entries.length; i < l; i++) { const entry = entries[i]; const frame = entry[FRAME]; // Edge entries are left as-is. if (edges.has(frame)) { keptEntries.push(entry); } else { // Otherwise, let's see if this entry is in any sequence to begin with. for (const sequence of sequences) { const [start, end] = sequence.interval; if (frame >= start && frame <= end) { keptEntries.push(entry); break; } } } } const finalEntries: Entry[] = []; // Now that all of the entries are valid in sequences, we can check for values. if (keptEntries.length >= 2) { for (let i = 0, l = keptEntries.length; i < l; i++) { const entry = keptEntries[i]; const frame = entry[FRAME]; // Once again, don't touch edges. if (edges.has(frame)) { finalEntries.push(entry); continue; } // Otherwise, if this isn't the first or last entries, check for equal values. if (i > 0 && i < keptEntries.length - 1) { const prevEntry = keptEntries[i - 1]; const nextEntry = keptEntries[i + 1]; const difference = getValuesDiff(prevEntry[VALUE], entry[VALUE], nextEntry[VALUE]); if (difference > 0.0001) { finalEntries.push(entry); } } } } const newFrames = []; const newValues = []; const newInTans = []; const newOutTans = []; for (const entry of finalEntries) { newFrames.push(entry[FRAME]); newValues.push(entry[VALUE]); if (interpolationType > 1) { newInTans.push(entry[INTAN]); newOutTans.push(entry[OUTTAN]); } } animation.frames = newFrames; animation.values = newValues; animation.inTans = newInTans; animation.outTans = newOutTans; return frames.length - newFrames.length; } function optimizeAnimations(model: MdlxModel, animations: Animation[]) { let tracks = 0; for (const animation of animations) { tracks += optimizeAnimation(model, animation); } return tracks; } function optimizeMaterials(model: MdlxModel) { let tracks = 0; for (const material of model.materials) { for (const layer of material.layers) { tracks += optimizeAnimations(model, layer.animations) } } return tracks; } function optimizeObjects(model: MdlxModel, objects: AnimatedObject[]) { let tracks = 0; for (const object of objects) { tracks += optimizeAnimations(model, object.animations); } return tracks; } function optimizeModel(name: string, buffer: ArrayBuffer) { try { const model = new MdlxModel(); model.load(buffer); let tracks = 0; tracks += optimizeMaterials(model); tracks += optimizeObjects(model, model.textureAnimations); tracks += optimizeObjects(model, model.geosetAnimations); tracks += optimizeObjects(model, model.bones); tracks += optimizeObjects(model, model.lights); tracks += optimizeObjects(model, model.helpers); tracks += optimizeObjects(model, model.attachments); tracks += optimizeObjects(model, model.particleEmitters); tracks += optimizeObjects(model, model.particleEmitters2); tracks += optimizeObjects(model, model.particleEmittersPopcorn); tracks += optimizeObjects(model, model.ribbonEmitters); tracks += optimizeObjects(model, model.cameras); tracks += optimizeObjects(model, model.collisionShapes); console.log(`Removed ${tracks} tracks`); return model.saveMdx(); } catch (e) { console.error(`Error for "${name}": ${e}`); return undefined; } } async function optimizeDataTransfer(dataTransfer: DataTransfer) { const entries = await getAllFileEntries(dataTransfer); const names = []; const promises = []; for (let entry of entries) { const name = entry.name; const ext = extname(name); if (ext === '.mdx' || ext === '.mdl') { names.push(name); promises.push(readEntry(entry, ext === '.mdl')); } } const buffers = await Promise.all(promises); const optimizedBuffers = []; for (let i = 0, l = buffers.length; i < l; i++) { optimizedBuffers.push(optimizeModel(names[i], buffers[i])); } for (let i = 0, l = buffers.length; i < l; i++) { const buffer = optimizedBuffers[i]; if (buffer) { // @ts-ignore saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'opt_' + names[i]); } } } document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); if (e.dataTransfer) { optimizeDataTransfer(e.dataTransfer); } }); ================================================ FILE: clients/melee/README.md ================================================ A small tool to fake a map as a Melee map. This changes the map's icon when it is listed in the game. I don't know of any other effects. ================================================ FILE: clients/melee/index.html ================================================  Melee

Drop a map anywhere

================================================ FILE: clients/melee/index.js ================================================ let w3x = ModelViewer.default.parsers.w3x; function onLocalLoaded(e, name) { let buffer = e.target.result; console.log('Reading the map'); let map = new w3x.Map(); map.load(buffer); console.log('Setting the map melee flag'); map.flags |= 0x4; console.log('Reading war3map.w3i'); let w3i = new w3x.w3i.File(); w3i.load(map.get('war3map.w3i').arrayBuffer()); console.log('Setting the w3i melee flag'); w3i.flags |= 0x4; console.log('Saving war3map.w3i'); map.set('war3map.w3i', w3i.save()); let newName = `${name.substr(0, name.length - 4)}_melee${name.substr(-4)}`; console.log(`Saving the map as "${newName}"`); saveAs(new Blob([map.save().buffer], { type: 'application/octet-stream' }), newName); } function onFileDrop(e) { let file = e.dataTransfer.files[0]; let name = file.name.toLowerCase(); if (file && (name.endsWith('.w3m') || name.endsWith('.w3x'))) { let reader = new FileReader(); reader.addEventListener('loadend', (e) => onLocalLoaded(e, file.name)); reader.readAsArrayBuffer(file); } } document.addEventListener('dragover', (e) => { e.preventDefault(); }); document.addEventListener('dragend', (e) => { e.preventDefault(); onFileDrop(e); }); document.addEventListener('drop', (e) => { e.preventDefault(); onFileDrop(e); }); ================================================ FILE: clients/rebuild/README.md ================================================ This is a small proof of concept of rebuilding a "protected" map. This is done by running the map's Jass script with a virtual machine, and keeping track of created objects (e.g. units and doodads). The objects are then re-created in their "un-protected" files, e.g. `war3mapUnits.doo`. Note that this is, indeed, merely a proof of concept, not a complete implementation. ================================================ FILE: clients/rebuild/components/rebuilder.js ================================================ import { extname } from "../../../src/common/path"; import War3Map from "../../../src/parsers/w3x/map"; import UnitsDooFile from "../../../src/parsers/w3x/unitsdoo/file"; import UnitsDooUnit from "../../../src/parsers/w3x/unitsdoo/unit"; import Context from '../../../src/utils/jass2/context'; import JassUnit from '../../../src/utils/jass2/types/unit'; import Component from "../../shared/component"; import { createElement } from "../../shared/domutils"; import localOrHive from "../../shared/localorhive"; import { aFrame } from "../../shared/utils"; export default class Rebuilder extends Component { constructor(parentElement) { super(); this.commonjText = ''; this.blizzardjText = ''; this.ready = false; this.load(); parentElement.appendChild(this.container); } async load() { this.text('Fetching files: "Scripts\\common.j", "Scripts\\Blizzard.j"'); this.text('Please wait...'); let [commonjResponse, blizzardjResponse] = await Promise.all([ fetch('https://www.hiveworkshop.com/data/static_assets/mpq/tft/scripts/common.j'), fetch('https://www.hiveworkshop.com/data/static_assets/mpq/tft/scripts/blizzard.j'), ]); let [commonjText, blizzardjText] = await Promise.all([ commonjResponse.text(), blizzardjResponse.text(), ]); this.commonjText = commonjText; this.blizzardjText = blizzardjText; this.text('Ready, drag and drop a map (*.w3m, *.w3x) anywhere on the page.'); } clear() { this.container.innerHTML = ''; } text(text) { createElement({ textContent: text, container: this.container }); } rebuildFile(file) { if (file) { let name = file.name; let ext = extname(name); let isMap = ext === '.w3m' || ext === '.w3x'; this.clear(); if (isMap) { this.text(`Reading ${name}`); let reader = new FileReader(); reader.addEventListener('loadend', async (e) => { let buffer = e.target.result; this.text(`Parsing ${name}`); let map = new War3Map(); try { map.load(buffer); } catch (e) { this.text(`Failed to parse: ${e}`); return; } let context = new Context(); this.text('Converting and running common.j'); await aFrame(); context.run(this.commonjText, true); this.text('Converting and running Blizzard.j'); await aFrame(); context.run(this.blizzardjText, true); this.text('Converting and running war3map.j'); await aFrame(); context.open(map); this.text('Running config()'); await aFrame(); context.call('config'); this.text('Running main()'); await aFrame(); context.call('main'); this.text('Collecting handles'); await aFrame(); let unitsFile = new UnitsDooFile(); let units = unitsFile.units; for (let handle of context.handles) { if (handle instanceof JassUnit) { let unit = new UnitsDooUnit(); unit.id = handle.unitId; unit.location[0] = handle.x; unit.location[1] = handle.y; // For z need the height of the terrain! unit.angle = handle.face / 180 * Math.PI; unit.player = handle.player.index; unit.targetAcquisition = handle.acquireRange; units.push(unit); } } this.text(`Saving war3mapUnits.doo with ${units.length} objects`); await aFrame(); map.set('war3mapUnits.doo', unitsFile.save(false)); this.text('Finished'); saveAs(new Blob([map.get('war3mapUnits.doo').arrayBuffer()], { type: 'application/octet-stream' }), 'war3mapUnits.doo'); }); reader.readAsArrayBuffer(file); } else { this.text(`${name} is not a map`); } } } } ================================================ FILE: clients/rebuild/index.html ================================================  Rebuilder ================================================ FILE: clients/rebuild/index.js ================================================ import Rebuilder from './components/rebuilder'; const rebuilder = new Rebuilder(document.body); document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); rebuilder.rebuildFile(e.dataTransfer.files[0]); }); // For debugging etc. window.rebuilder = rebuilder; ================================================ FILE: clients/recorder/README.md ================================================ This client is used to record unit animations into a collection of images, that can be downloaded in a zip file. ================================================ FILE: clients/recorder/index.html ================================================  Recorder | HIVE

================================================ FILE: clients/recorder/index.js ================================================ ModelViewer = ModelViewer.default; let common = ModelViewer.common; let quat = common.glMatrix.quat; let vec3 = common.glMatrix.vec3; let math = common.math; let geometry = common.geometry; var keyboard = {}; var mouse = { buttons: [false, false, false], x: 0, y: 0, x2: 0, y2: 0 }; var canvas = document.getElementById('canvas'); var viewer = new ModelViewer.viewer.ModelViewer(canvas, { alpha: true }); var instance; viewer.on('error', (e) => console.error(e)); viewer.addHandler(ModelViewer.viewer.handlers.mdx, localOrHive); viewer.addHandler(ModelViewer.viewer.handlers.blp); viewer.addHandler(ModelViewer.viewer.handlers.tga); viewer.addHandler(ModelViewer.viewer.handlers.dds); let backgroundOpaque = true; let turnTable = false; let turnTableSpeed = 0; let turnTableQuat = quat.create(); let isRecording = false; let recordingFrame = 0; let oneTimeRecord = false; let zip = new JSZip(); let frameCounterElement = document.getElementById('frame_counter'); let sequenceNameElement = document.getElementById('sequence_name'); (function step() { viewer.updateAndRender(); if (instance) { instance.rotate(turnTableQuat); if (isRecording || oneTimeRecord) { oneTimeRecord = false; zip.file( `${recordingFrame++}_${instance.model.name}_${Math.floor(instance.frame)}.png`, viewer.canvas.toDataURL().substring(22), { base64: true } ); frameCounterElement.textContent = recordingFrame; } } requestAnimationFrame(step); })(); let scene = viewer.addScene(); scene.alpha = true; setupCamera(scene, { distance: 500 }); console.log('Viewer version', ModelViewer.version); // Run the next sequence for the given instance at e. function runNextSequence(e) { let instance = e.target; instance.setSequence((instance.sequence + 1) % instance.model.sequences.length); } // Log load starts to the console. viewer.on('loadstart', target => { let path = target.fetchUrl; if (path) { console.log('Loading ' + target.fetchUrl); } }); // Log load ends to the console. viewer.on('load', target => { let path = target.fetchUrl; if (path) { console.log('Finished loading ' + target.fetchUrl); } }); function normalizePath(path) { return path.toLocaleLowerCase().replace(/\\/g, '/'); } // Load a local file function onLocalFileLoaded(name, buffer) { if (name.endsWith('.mdx')) { let pathSolver = src => { if (src === buffer) { return src; } else { return localOrHive(normalizePath(src)); } }; turnTableSpeed = 0; quat.identity(turnTableQuat); isRecording = false; scene.clear(); viewer.load(buffer, pathSolver) .then((model) => { instance = model.addInstance(); instance.setSequenceLoopMode(2); instance.setSequence(0); sequenceNameElement.textContent = model.sequences[0].name; scene.addInstance(instance); }); } } canvas.addEventListener('contextmenu', function (e) { e.preventDefault(); }); canvas.addEventListener('selectstart', function (e) { e.preventDefault(); }); function onFileDrop(e) { let file = e.dataTransfer.files[0]; if (file) { let name = file.name.toLowerCase(); if (name.endsWith('.mdx') || name.endsWith('.blp')) { let reader = new FileReader(); reader.addEventListener('loadend', e => onLocalFileLoaded(name, e.target.result)); reader.readAsArrayBuffer(file); } } } document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); onFileDrop(e); }); document.addEventListener('drop', e => { e.preventDefault(); onFileDrop(e); }); window.addEventListener('keydown', e => { let key = e.key; if (instance) { let model = instance.model; if (key === ' ') { isRecording = !isRecording; } else if (key === 'ArrowLeft') { if (instance.sequence === 0) { instance.setSequence(model.sequences.length - 1); } else { instance.setSequence(instance.sequence - 1); } sequenceNameElement.textContent = model.sequences[instance.sequence].name; } else if (key === 'ArrowRight') { if (instance.sequence === model.sequences.length - 1) { instance.setSequence(0); } else { instance.setSequence(instance.sequence + 1); } sequenceNameElement.textContent = model.sequences[instance.sequence].name; } else if (key === 'ArrowUp') { turnTableSpeed += 0.2; quat.setAxisAngle(turnTableQuat, [0, 0, 1], math.degToRad(turnTableSpeed)); } else if (key === 'ArrowDown') { turnTableSpeed -= 0.2; quat.setAxisAngle(turnTableQuat, [0, 0, 1], math.degToRad(turnTableSpeed)); } else if (key === 'Enter') { oneTimeRecord = true; } else if (key === 'Escape') { if (recordingFrame > 0) { zip.generateAsync({ type: 'blob' }).then(blob => { saveAs(blob, `recorded_frames_${recordingFrame}.zip`); zip = new JSZip(); recordingFrame = 0; frameCounterElement.textContent = ''; }); } } } if (key === 'b') { backgroundOpaque = !backgroundOpaque; if (backgroundOpaque) { viewer.alpha = false; sequenceNameElement.style.color = 'white'; frameCounterElement.style.color = 'white'; } else { viewer.alpha = true; sequenceNameElement.style.color = 'black'; frameCounterElement.style.color = 'black'; } } }); ================================================ FILE: clients/sanitytest/README.md ================================================ This client runs the MDX sanity tester, and shows the information in a graphical manner. It is used on the Hiveworkshop to find issues with Warcraft 3 models and textures. ================================================ FILE: clients/sanitytest/components/logger.js ================================================ import Component from "../../shared/component"; import Toggle from "../../shared/components/toggle"; import { createElement, scrolledToBottom, scrollToBottom } from "../../shared/domutils"; export default class Logger extends Component { constructor(options) { super({ ...options, className: 'console' }); this.messages = []; this.tabs = createElement({ className: 'tabs', container: this.container }); this.logsToggler = new Toggle('Hide Logs', 'Show Logs', (e) => this.filter(), { container: this.tabs }); this.infoToggler = new Toggle('Hide Info', 'Show Info', (e) => this.filter(), { container: this.tabs }); this.errorsToggler = new Toggle('Hide Errors', 'Show Errors', (e) => this.filter(), { container: this.tabs }); this.contents = createElement({ className: 'tab-contents', container: this.container }); // Default to hiding the log spam. this.logsToggler.toggle(); } message(type, message) { let loggerMessage = new LoggerMessage(type, message); loggerMessage.filter(this.logsToggler.clicked, this.infoToggler.clicked, this.errorsToggler.clicked); this.messages.push(loggerMessage); // If scrolled all the way... let scrolled = scrolledToBottom(this.contents); this.contents.appendChild(loggerMessage.container); // ...scroll back down after adding the message. if (scrolled) { scrollToBottom(this.contents); } } log(message) { this.message('log', message); } info(message) { this.message('info', message); } error(message) { this.message('error', message); } filter() { // If scrolled all the way... let scrolled = scrolledToBottom(this.contents); for (let message of this.messages) { message.filter(this.logsToggler.clicked, this.infoToggler.clicked, this.errorsToggler.clicked); } // ...scroll down after filtering. if (scrolled) { scrollToBottom(this.contents); } } } class LoggerMessage extends Component { constructor(type, message) { super({ className: type, textContent: message }); this.type = type; } matchFilters(logs, info, errors) { let type = this.type; return (type === 'log' && !logs) || (type === 'info' && !info) || (type === 'error' && !errors); } filter(logs, info, errors) { if (this.matchFilters(logs, info, errors)) { this.show(); } else { this.hide(); } } } ================================================ FILE: clients/sanitytest/components/mdlview.js ================================================ import mdlStructure from "../../../src/utils/mdlx/mdlstructure"; import Component from "../../shared/component"; import { createElement } from "../../shared/domutils"; export default class MdlView extends Component { constructor(parser) { super({ className: 'mdl-view' }); const mdlNodes = mdlStructure(parser); this.structureElement = createElement({ className: 'mdl-structure', container: this.container }); this.sourceElement = createElement({ tagName: 'pre', className: 'mdl-source', container: this.container }); this.nodes = []; this.visibleNode = null; for (let node of mdlNodes) { this.nodes.push(new MdlViewNode(this, node, this.structureElement)); } } showNode(node) { if (this.visibleNode) { this.visibleNode.normal(); } this.visibleNode = node; node.highlight(); this.sourceElement.textContent = node.node.source; } } class MdlViewNode extends Component { constructor(view, node, parentElement) { super({ className: 'clickable highlightable', textContent: node.name, container: parentElement }); this.container.addEventListener('click', () => view.showNode(this)); this.node = node; this.nodes = []; if (node.nodes && node.nodes.length) { let container = createElement({ className: 'indent' }); for (let child of node.nodes) { this.nodes.push(new MdlViewNode(view, child, container)); } parentElement.appendChild(container); } } } ================================================ FILE: clients/sanitytest/components/sanitytester.js ================================================ import { basename, extname } from "../../../src/common/path"; import War3Map from "../../../src/parsers/w3x/map"; import Component from "../../shared/component"; import Toggle from "../../shared/components/toggle"; import { createElement, hideElement, showElement } from "../../shared/domutils"; import localOrHive from "../../shared/localorhive"; import { getAllFileEntries, readFile, readEntry } from "../../shared/utils"; import Test from "../test"; import Logger from "./logger"; import Viewer from "./viewer"; export default class SanityTester extends Component { constructor(parentElement) { super({ className: 'client' }); this.tests = []; this.visibleTest = null; // Tests header let testsHeader = createElement({ className: 'tests-header', container: this.container }); createElement({ tagName: 'h1', textContent: 'Tests', container: testsHeader, container: testsHeader }); // Tests body let testsBody = createElement({ className: 'tests-body', container: this.container }); this.searchTests = createElement({ tagName: 'input', placeholder: 'Search tests', oninput: () => this.filterTests(), container: testsBody }); this.testsElement = createElement({ className: 'tests', container: testsBody }); // Results header let resultsHeader = createElement({ className: 'results-header', container: this.container }); createElement({ tagName: 'h1', textContent: 'Test Results', container: resultsHeader, container: resultsHeader }); this.unusedToggle = new Toggle('Hide Unused', 'Show Unused', () => this.filterResults(), { container: resultsHeader }); this.warningToggle = new Toggle('Hide Warnings', 'Show Warnings', () => this.filterResults(), { container: resultsHeader }); this.severeToggler = new Toggle('Hide Severe', 'Show Severe', () => this.filterResults(), { container: resultsHeader }); this.errorToggler = new Toggle('Hide Errors', 'Show Errors', () => this.filterResults(), { container: resultsHeader }); // Results body this.resultsBody = createElement({ className: 'results-body', container: this.container }); // Viewer/Logger and MDL header let viewerLoggerMdlHeader = createElement({ className: 'viewer-and-mdl-header', container: this.container }); let viewerLoggerMdlH1 = createElement({ tagName: 'h1', textContent: '3D View', container: viewerLoggerMdlHeader }); // Viewer/Logger and MDL body let viewerLoggerMdlBody = createElement({ className: 'viewer-and-mdl-body', container: this.container }); let viewerLogger = createElement({ className: 'viewer-and-console', container: viewerLoggerMdlBody }); this.mdl = createElement({ className: 'mdl hidden', container: viewerLoggerMdlBody }); // Viewer/Logger and MDL toggler new Toggle('View in MDL', 'View in 3D', (e) => { if (e.clicked) { viewerLoggerMdlH1.textContent = 'MDL View'; hideElement(viewerLogger); showElement(this.mdl); if (!this.viewer.controls.animationToggle.clicked) { this.viewer.controls.animationToggle.toggle(); } } else { viewerLoggerMdlH1.textContent = '3D View'; showElement(viewerLogger); // If the page was resized in MDL view, the camera thinks the size of the canvas is 1x1. // Need to resize now that the canvas is visible again and has a real size. this.viewer.orbitCamera.onResize(); hideElement(this.mdl); } }, { container: viewerLoggerMdlHeader }); // Actual Viewer and Logger this.logger = new Logger({ container: viewerLogger }); this.viewer = new Viewer(this, { container: viewerLogger }); // Append at the end to avoid re-renders. parentElement.appendChild(this.container); } filterTests() { let term = this.searchTests.value.toLowerCase(); for (let test of this.tests) { if (test.name.toLowerCase().includes(term)) { test.meta.show(); } else { test.meta.hide(); } } } filterResults() { if (this.visibleTest && this.visibleTest.results) { this.visibleTest.results.filter(this.unusedToggle.clicked, this.warningToggle.clicked, this.severeToggler.clicked, this.errorToggler.clicked); } } // pathSolver is used for API tests. test(name, buffer, render, pathSolver) { this.logger.info(`Parsing ${name}`); let test; try { test = new Test(this, name, buffer, pathSolver); } catch (e) { this.logger.error(`An error occured before the test could finish: ${e.stack}`) } this.tests.push(test); this.testsElement.appendChild(test.meta.container); test.meta.container.scrollIntoView(); if (test.results) { this.resultsBody.appendChild(test.results.container); } if (test.mdl) { this.mdl.appendChild(test.mdl.container); } this.viewer.load(test); if (render) { this.render(test); } else { test.hide(); } } render(test) { if (test !== this.visibleTest) { if (this.visibleTest) { this.visibleTest.hide(); } this.visibleTest = test; this.filterResults(); test.show(); this.viewer.render(test); } } loadMap(name, buffer) { this.logger.info(`Parsing ${name}`); let map = new War3Map(); try { map.load(buffer); } catch (e) { this.logger.error(`Failed to parse ${name}: ${e}`); return; } let pathSolver = (src, params) => { let file = map.get(src); if (file) { return file.bytes(); } return localOrHive(src, params); }; let render = true; for (let importName of map.getImportNames()) { let ext = extname(importName); if (ext === '.mdx' || ext === '.mdl' || ext === '.blp' || ext === '.dds' || ext === '.tga') { let file = map.get(importName); if (file) { if (ext === '.mdx') { this.test(`${name}:${importName}`, file.arrayBuffer(), render, pathSolver); } else if (ext === '.mdl') { this.test(`${name}:${importName}`, file.text(), render, pathSolver); } else if (ext === '.blp' || ext === '.dds' || ext === '.tga') { this.test(`${name}:${importName}`, file.arrayBuffer(), render); } render = false; } else { this.logger.error(`The map says it imports ${importName} but it couldn't be found`); } } } } /** * Load a file, e.g. resulting from a Drag & Drop action. */ async loadFile(file) { let name = file.name; let ext = extname(name); if (ext === '.mdx' || ext === '.mdl' || ext === '.blp' || ext === '.dds' || ext === '.tga' || ext === '.w3x' || ext === '.w3m') { this.logger.info(`Reading ${name}`); let buffer = await readFile(file, ext === '.mdl'); if (ext === '.w3m' || ext === '.w3x') { this.loadMap(name, buffer); } else { this.test(name, buffer, true); } } else { this.logger.info(`${name} is not a supported file, skipping it`); } } /** * Load all of the entries from a data transfer, e.g. resulting from a Drag & Drop action. */ async loadDataTransfer(dataTransfer) { let entries = await getAllFileEntries(dataTransfer); let names = []; let promises = []; // First start reading all of the relevant files. for (let entry of entries) { let name = entry.name; let ext = extname(name); if (ext === '.mdx' || ext === '.mdl' || ext === '.blp' || ext === '.dds' || ext === '.tga' || ext === '.w3x' || ext === '.w3m') { this.logger.info(`Reading ${name}`); names.push(name.toLowerCase()); promises.push(readEntry(entry, ext === '.mdl')); } else { this.logger.info(`${name} is not a supported file, skipping it`); } } // Finish reading... let buffers = await Promise.all(promises); // Now map from names to buffers. let overrides = new Map(); for (let i = 0, l = names.length; i < l; i++) { overrides.set(names[i], buffers[i]); } // Path solver to see if a resource that needs loading is one of the files in the data transfer. let pathSolver = (src, params) => { let override = overrides.get(basename(src).toLowerCase()); if (override) { return override; } else { return localOrHive(src, params); } }; let render = true; // Finally load the tests. for (let [name, buffer] of overrides.entries()) { if (name.endsWith('.w3m') || name.endsWith('.w3x')) { this.loadMap(name, buffer); } else { this.test(name, buffer, render, pathSolver); } render = false; } } /** * Used by the Hiveworkshop to test resources. * * file=url&file=url2&override[path]=url3 */ loadAPI(api) { if (api !== '') { let files = []; let overrides = new Map(); for (let param of api.slice(1).split('&')) { let [key, value] = param.split('='); if (value !== undefined) { // Test also overrides. files.push(value); if (key.startsWith('override')) { // Discord changes \ to / in urls, ignoring escaping, so escape manually. overrides.set(key.slice(9, -1).replace(/\//g, '\\'), value); } } } if (files.length) { let pathSolver = (src, params) => { let override = overrides.get(basename(src).toLowerCase()); if (override) { return override; } else { return localOrHive(src, params); } }; let render = true; for (let file of files) { fetch(file) .then(async (response) => { let buffer; if (file.endsWith('.mdl')) { buffer = await response.text(); } else { buffer = await response.arrayBuffer(); } this.test(file, buffer, render, pathSolver); render = false; }); } } } } } ================================================ FILE: clients/sanitytest/components/teamcolors.js ================================================ export const TEAM_COLORS = [ { name: 'Red', color: '#ff0402' }, { name: 'Blue', color: '#0042ff' }, { name: 'Teal', color: '#1be6ba' }, { name: 'Purple', color: '#540081' }, { name: 'Yellow', color: '#fffc00' }, { name: 'Orange', color: '#ff8a0d' }, { name: 'Green', color: '#20c000' }, { name: 'Pink', color: '#e45bb0' }, { name: 'Gray', color: '#949697' }, { name: 'Light Blue', color: '#7ebff1' }, { name: 'Dark Green', color: '#106247' }, { name: 'Brown', color: '#4f2a05' }, { name: 'Maroon', color: '#9c0000' }, { name: 'Navy', color: '#0000c3' }, { name: 'Turquoise', color: '#00ebff' }, { name: 'Violet', color: '#bd00ff' }, { name: 'Wheat', color: '#eccd86' }, { name: 'Peach', color: '#f7a48b' }, { name: 'Mint', color: '#c0ff80' }, { name: 'Lavender', color: '#dcb9ec' }, { name: 'Coal', color: '#4f4f55' }, { name: 'Snow', color: '#ecf0ff' }, { name: 'Emerald', color: '#00781e' }, { name: 'Peanut', color: '#a46f33' }, { name: 'Neutral', color: '#2e2d2e' }, ]; ================================================ FILE: clients/sanitytest/components/testmeta.js ================================================ import Component from "../../shared/component"; import { createElement } from "../../shared/domutils"; function singleOrPlural(name, count) { if (count === 1) { return name; } return `${name}s`; } export default class TestMeta extends Component { constructor(name, parsingError, results, options) { super({ ...options, className: 'clickable highlightable padded' }); this.name = createElement({ className: 'bold', textContent: name, container: this.container }); let container = createElement({ className: 'indent', container: this.container }); if (parsingError) { createElement({ className: 'error', textContent: 'Parsing failed', container }); } if (results.errors || results.severe || results.warnings || results.unused) { if (results.errors) { createElement({ className: 'error', textContent: `${results.errors} ${singleOrPlural('error', results.errors)}`, container }); } if (results.severe) { createElement({ className: 'severe', textContent: `${results.severe} ${singleOrPlural('severe warning', results.severe)}`, container }); } if (results.warnings) { createElement({ className: 'warning', textContent: `${results.warnings} ${singleOrPlural('warning', results.warnings)}`, container }); } if (results.unused) { createElement({ className: 'unused', textContent: `${results.unused} unused`, container }); } } else { createElement({ className: 'bold', textContent: 'Passed', container }); } } } ================================================ FILE: clients/sanitytest/components/testresults.js ================================================ import { imageDataToImage } from "../../../src/common/canvas"; import Component from "../../shared/component"; import { createElement } from "../../shared/domutils"; import getTooltip from "./tooltips"; import MdlxModel from '../../../src/parsers/mdlx/model'; import { BlpImage, CONTENT_JPG } from '../../../src/parsers/blp/image'; import { DdsImage, FOURCC_ATI2, FOURCC_DXT1, FOURCC_DXT3, FOURCC_DXT5 } from '../../../src/parsers/dds/image'; import TgaImage from '../../../src/parsers/tga/image'; import mdlxSanityTest from '../../../src/utils/mdlx/sanitytest/sanitytest'; import blpSanityTest from '../../../src/utils/blp/sanitytest'; import ddsSanityTest from '../../../src/utils/dds/sanitytest'; export default class TestResults extends Component { constructor(parser) { super(); this.nodes = []; const container = this.container; const isMdlx = parser instanceof MdlxModel; const isBlp = parser instanceof BlpImage; const isDds = parser instanceof DdsImage; const isTga = parser instanceof TgaImage; const isImage = isBlp || isDds || isTga; if (isBlp || isDds || isTga) { createElement({ textContent: `Width: ${parser.width}`, container }); createElement({ textContent: `Height: ${parser.height}`, container }); if (isBlp) { if (parser.content === CONTENT_JPG) { createElement({ textContent: `Content: JPG`, container }); } else { createElement({ textContent: `Content: Palette`, container }); } if (parser.alphaBits > 8) { createElement({ textContent: `Alpha bits: ${parser.alphaBits} (fake)`, container }); } else { createElement({ textContent: `Alpha bits: ${parser.alphaBits}`, container }); } createElement({ textContent: `Mipmaps: ${parser.mipmaps()} (fake: ${parser.fakeMipmaps()})`, container }); } else if (isDds) { if (parser.format === FOURCC_DXT1) { createElement({ textContent: `Content: BC1 (DXT1)`, container }); } else if (parser.format === FOURCC_DXT3) { createElement({ textContent: `Content: BC2 (DXT3)`, container }); } else if (parser.format === FOURCC_DXT5) { createElement({ textContent: `Content: BC3 (DXT5)`, container }); } else if (parser.format === FOURCC_ATI2) { createElement({ textContent: `Content: BC5 (ATI2)`, container }); } else { createElement({ textContent: `Content: Not supported`, container }); } createElement({ textContent: `Mipmaps: ${parser.mipmaps()}`, container }); } createElement({ tagName: 'hr', container }); } let results; if (isMdlx) { results = mdlxSanityTest(parser); } else if (isBlp) { results = blpSanityTest(parser); } else if (isDds) { results = ddsSanityTest(parser); } else { results = {}; } if (results.nodes && results.nodes.length) { for (let node of results.nodes) { this.nodes.push(new TestResultsNode(node, container)); } } else { this.nodes.push(new TestResultsNode({ type: 'bold', message: 'Passed' }, container)); } this.results = results; if (isImage) { createElement({ tagName: 'hr', container }); if (isBlp || isDds) { for (let i = 0, l = parser.mipmaps(); i < l; i++) { try { let imageData; if (isBlp) { imageData = parser.getMipmap(i); } else { imageData = this.getDdsMipmap(parser, i); } this.addMipmap(imageData); } catch (e) { if (this.results.errors === undefined) { this.results.errors = 1; } else { this.results.errors += 1; } this.nodes.push(new TestResultsNode({ type: 'error', message: `Mipmap ${i}: ${e}` }, this.container)); } } } else { this.addMipmap(parser.data); } } } getDdsMipmap(parser, i) { const mipmap = parser.getMipmap(i); if (parser.format === FOURCC_ATI2) { const imageData = new ImageData(mipmap.width, mipmap.height); const inData = mipmap.data; const outData = imageData.data; for (let i = 0, l = mipmap.width * mipmap.height; i < l; i++) { const offset2 = i * 2; const offset4 = i * 4; outData[offset4 + 0] = inData[offset2 + 0]; outData[offset4 + 1] = inData[offset2 + 1]; outData[offset4 + 2] = 0; outData[offset4 + 3] = 255; } return imageData; } else { return new ImageData(new Uint8ClampedArray(mipmap.data.buffer), mipmap.width, mipmap.height); } } addMipmap(imageData) { const image = imageDataToImage(imageData); image.className = 'padded'; this.container.appendChild(image); } filter(unused, warnings, severe, errors) { for (let node of this.nodes) { node.filter(unused, warnings, severe, errors); } } } class TestResultsNode extends Component { constructor(node, parentElement) { super(); let className = ''; let textContent = ''; let tooltip = ''; if (node.type === 'node') { className = 'bold'; textContent = node.name; } else { className = node.type; textContent = node.message; tooltip = getTooltip(textContent); if (tooltip.length) { className += ' pointer'; } } const resultElement = createElement({ className, textContent, title: tooltip, container: this.container }); if (tooltip.length) { createElement({ tagName: 'span', className: 'info_marker', textContent: 'tooltip', container: resultElement }); } this.node = node; this.nodes = []; if (node.type === 'node') { if (node.nodes.length || node.uses === 0) { let container = createElement({ className: 'indent', container: this.container }); if (node.uses === 0) { this.nodes.push(new TestResultsNode({ type: 'unused', message: 'Not used' }, container)); } for (let child of node.nodes) { this.nodes.push(new TestResultsNode(child, container)); } } } parentElement.appendChild(this.container); } filter(unused, warnings, severe, errors) { if (this.matchFilters(unused, warnings, severe, errors)) { if (this.node.type === 'node') { for (let child of this.nodes) { child.filter(unused, warnings, severe, errors); } } this.show(); } else { this.hide(); } } matchFilters(unused, warnings, severe, errors) { let node = this.node; if (node.type === 'node') { return ((node.unused || node.uses === 0) && !unused) || (node.warnings && !warnings) || (node.severe && !severe) || (node.errors && !errors); } else { let type = node.type; return (type === 'unused' && !unused) || (type === 'warning' && !warnings) || (type === 'severe' && !severe) || (type === 'error' && !errors) || type === 'bold'; } } } ================================================ FILE: clients/sanitytest/components/tooltips.js ================================================ export default function getTooltip(message) { if (message.includes('does not match the number of sequences')) { // Number of sequence extents (9) does not match the number of sequences (3) return `Having the wrong amount of geoset extents can in some cases crash War 3 Model Editor (Magos). This does not affect the game.`; } else if (message.includes('has exactly the same value as tracks')) { // Track 3 at frame 1096 has exactly the same value as tracks 2 and 4 return 'A keyframe with the same value as the two keyframes sorrounding it is useless.'; } else if (message.includes('has roughly the same value as tracks')) { // Track 3 at frame 1096 has roughly the same value as tracks 2 and 4 return 'A keyframe with roughly the same value as the two keyframes sorrounding it is many times useless.'; } else if (message.includes('Missing opening track for sequence')) { // Missing opening track for sequence "Death" at frame 21000 where it is needed return `When missing the opening keyframe for an animation, the game will wrap the animation and interpolate between the last and first keyframes. However there is a bug in the game which causes the animation values to reverse. To fix it, add a keyframe at the beginning of the animation. `; } else if (message.includes('has the same frame')) { // Track 7 has the same frame 1267 as track 6 return 'Remove one of the keyframes.' } else if (message === 'Missing the Origin attachment point') { // Missing the Origin attachment point return `Missing the Origin attachment stops many in-game effects from attaching to models. Not relevant to portraits and special effects.`; } else if (message.includes('is not in global sequence')) { // Track 17 at frame 4577 is not in global sequence 2 return `This keyframe uses a global sequence, but its frame is outside of the global sequence's range.`; } else if (message === 'Missing "Stand" sequence') { // Missing "Stand" sequence return `Missing the stand animation can cause issues for models that are used as units. Not relevant to portraits.`; } else if (message === 'Missing "Death" sequence') { // Missing "Death" sequence return `Missing the death animation makes particles and other effects linger for a short time after an object using this model dies. Not relevant to portraits.`; } else if (message.endsWith('is not in any sequence')) { return 'A keyframe that is not in any animation is useless.'; } else if (message.includes('is lower than the track before it at')) { return 'A keyframe is not supposed to have a frame before the previous keyframe.'; } else if (message === 'There are no vertices attached to this bone') { return 'Bones with no attached vertices should preferably be converted to helpers.' } else { //console.log('getTooltip', message) } return ''; } ================================================ FILE: clients/sanitytest/components/viewer.js ================================================ import ModelViewer from '../../../src/viewer/viewer'; import mdxHandler from '../../../src/viewer/handlers/mdx/handler'; import blpHandler from '../../../src/viewer/handlers/blp/handler'; import ddsHandler from '../../../src/viewer/handlers/dds/handler'; import tgaHandler from '../../../src/viewer/handlers/tga/handler'; import Component from "../../shared/component"; import { createElement } from "../../shared/domutils"; import localOrHive from "../../shared/localorhive"; import { setupCamera } from "../../shared/camera"; import ViewerControls from "./viewercontrols"; import createPrimitive from '../../../src/utils/mdlx/primitives/createprimitive'; import { createUnitRectangle, createUnitCube, createUnitSphere } from '../../../src/utils/mdlx/primitives/primitives'; import { filename } from '../../../src/common/path'; import Model from '../../../src/viewer/model'; import Texture from '../../../src/viewer/texture'; import MdxModel from '../../../src/viewer/handlers/mdx/model'; import { Shape } from '../../../src/parsers/mdlx/collisionshape'; export default class Viewer extends Component { constructor(tester, options) { super({ ...options, className: 'viewer' }); this.tester = tester; this.messages = []; this.canvas = createElement({ tagName: 'canvas', style: 'width:100%;height:100%', container: this.container }); this.controls = new ViewerControls(this, { container: this.container }); let viewer = new ModelViewer(this.canvas); let scene = viewer.addScene(); this.viewer = viewer; this.scene = scene; this.visibleTest = null; this.teamColor = 0; scene.color.fill(0.2); this.orbitCamera = setupCamera(scene, { onManualChange: () => { this.setCamera(-1); this.controls.setCamera(-1); }, }); viewer.on('loadstart', (e) => { tester.logger.log(`[Viewer] Loading ${e.fetchUrl}`); }); viewer.on('loadend', (e) => { tester.logger.log(`[Viewer] Loaded ${e.fetchUrl}`); }); viewer.on('error', (e) => { if (e.fetchUrl) { tester.logger.error(`[Viewer] ${e.error}: ${e.fetchUrl}`); } else { tester.logger.error(`[Viewer] ${e.error}: ${e.reason}`); } }); viewer.addHandler(mdxHandler, localOrHive, true); viewer.addHandler(blpHandler); viewer.addHandler(ddsHandler); viewer.addHandler(tgaHandler); this.textureModel = null; this.boxModel = null; this.sphereModel = null; createPrimitive(viewer, createUnitRectangle(), { twoSided: true }) .then((model) => { this.textureModel = model; }); createPrimitive(viewer, createUnitCube(), { lines: true }) .then((model) => { this.boxModel = model; }); createPrimitive(viewer, createUnitSphere(12, 12), { lines: true }) .then((model) => { this.sphereModel = model; }); let lastTime = performance.now(); let step = () => { requestAnimationFrame(step); let now = performance.now(); let dt = now - lastTime; lastTime = now; if (this.controls.animationToggle.clicked) { viewer.updateAndRender(0); } else { viewer.updateAndRender(dt); } if (this.visibleTest) { let instance = this.visibleTest.instance; if (instance.sequenceEnded) { let sequence = instance.sequence; if (!this.controls.cycleToggle.clicked) { sequence += 1; if (sequence === instance.model.sequences.length) { sequence = 0; } this.setSequence(sequence); } } this.controls.frame(instance.frame); } }; step(); } async load(test) { const modelOrTexture = await this.viewer.load(test.parser, (src, params) => { if (src === test.parser) { return src; } // Used for map and API tests. if (test.pathSolver) { return test.pathSolver(src, params); } return localOrHive(src, params); }); if (!modelOrTexture) { return; } let instance; if (modelOrTexture instanceof MdxModel) { instance = modelOrTexture.addInstance(); instance.setTeamColor(this.teamColor); let boundingBox = this.boxModel.addInstance(); boundingBox.hide(); boundingBox.setScene(this.scene); boundingBox.setParent(instance); let boundingSphere = this.sphereModel.addInstance(); boundingSphere.hide(); boundingSphere.setScene(this.scene); boundingSphere.setParent(instance); test.boundingBox = boundingBox; test.boundingSphere = boundingSphere; // let cameraPromises = []; // for (let camera of modelOrTexture.cameras) { // console.log(camera) // cameraPromises.push(ModelViewer.default.utils.mdlx.createPrimitive(this.viewer, ModelViewer.default.utils.mdlx.primitives.createFrustum(camera.fieldOfView, this.canvas.width / this.canvas.height, camera.nearClippingPlane, camera.farClippingPlane), { lines: true })); // } // Promise.all(cameraPromises) // .then((cameraModels) => { // for (let i = 0, l = cameraModels.length; i < l; i++) { // let model = cameraModels[i]; // let instance = model.addInstance(); // //instance.hide(); // instance.setScene(this.scene); // instance.setLocation(modelOrTexture.cameras[i].position); // instance.face(modelOrTexture.cameras[i].targetPosition, [0, 0, 1]); // test.cameras.push(instance); // } // }); for (let shape of modelOrTexture.collisionShapes) { if (shape.type === 0) { const shapeInstance = this.boxModel.addInstance(); const [min, max] = shape.vertices; let x = (max[0] + min[0]) / 2; let y = (max[1] + min[1]) / 2; let z = (max[2] + min[2]) / 2; let w = (max[0] - min[0]) / 2; let d = (max[1] - min[1]) / 2; let h = (max[2] - min[2]) / 2; shapeInstance.hide(); shapeInstance.setLocation([x, y, z]); shapeInstance.setScale([w, d, h]); shapeInstance.dontInheritScaling = false; shapeInstance.setParent(instance.nodes[shape.index]); shapeInstance.setScene(this.scene); test.collisions.push(shapeInstance); } else if (shape.type === 2) { const shapeInstance = this.sphereModel.addInstance(); shapeInstance.hide(); shapeInstance.setParent(instance.nodes[shape.index]); shapeInstance.uniformScale(shape.boundsRadius); shapeInstance.setScene(this.scene); test.collisions.push(shapeInstance); } else { console.log('COLLISION SHAPE NOT SUPPOTED', shape) } } } else { instance = this.textureModel.addInstance(); instance.scale([modelOrTexture.width, modelOrTexture.height, 1]); instance.setTexture(0, modelOrTexture); } instance.hide(); instance.setSequenceLoopMode(2); instance.setScene(this.scene); test.resource = modelOrTexture; test.instance = instance; this.tryToInjectCustomTextures(test); if (test === this.tester.visibleTest) { this.render(test); } } render(test) { if (test.instance) { if (this.visibleTest) { this.visibleTest.instance.hide(); if (this.visibleTest.boundingBox) { this.visibleTest.boundingBox.hide(); this.visibleTest.boundingSphere.hide(); } // for (let camera of this.visibleTest.cameras) { // camera.hide(); // } for (const collision of this.visibleTest.collisions) { collision.hide(); } } this.visibleTest = test; if (test.instance.model.sequences.length) { this.controls.updateInstance(test.instance); this.viewer.clearEmittedObjects(); if (test.instance.sequence === -1) { this.setSequence(0); } else { this.setSequence(test.instance.sequence) } this.controls.show(); } else { this.controls.hide(); } test.instance.show(); this.updateExtents(); // for (let camera of test.cameras) { // camera.show(); // } if (this.controls.collisionsToggle.clicked) { for (const collision of test.collisions) { collision.show(); } } } } updateExtents() { if (this.visibleTest && this.visibleTest.boundingBox) { let mode = this.controls.extentElement.selectedIndex; if (mode === 0 || mode === 2) { this.visibleTest.boundingBox.hide(); } else { this.visibleTest.boundingBox.show(); } if (mode === 0 || mode === 1) { this.visibleTest.boundingSphere.hide(); } else { this.visibleTest.boundingSphere.show(); } } } showCollisions(show) { if (this.visibleTest) { for (const collision of this.visibleTest.collisions) { if (show) { collision.show(); } else { collision.hide(); } } } } setSequence(index) { this.visibleTest.instance.setSequence(index); if (this.visibleTest.boundingBox) { let extent; if (index === -1) { extent = this.visibleTest.parser.extent; } else { extent = this.visibleTest.parser.sequences[index].extent; let { max, min } = extent; // If this sequence has no extent, use the model extent instead. if (max[0] === 0 && max[1] === 0 && max[2] === 0 && min[0] === 0 && min[1] === 0 && min[2] === 0) { extent = this.visibleTest.parser.extent; } } let { max, min } = extent; let x = (max[0] + min[0]) / 2; let y = (max[1] + min[1]) / 2; let z = (max[2] + min[2]) / 2; let w = (max[0] - min[0]) / 2; let d = (max[1] - min[1]) / 2; let h = (max[2] - min[2]) / 2; this.visibleTest.boundingBox.setLocation([x, y, z]); this.visibleTest.boundingBox.setScale([w, d, h]); this.visibleTest.boundingSphere.setLocation([x, y, z]); this.visibleTest.boundingSphere.setUniformScale(extent.boundsRadius); } this.controls.setSequence(index); } setCamera(index) { if (index === -1) { this.orbitCamera.instance = null; } else { this.orbitCamera.applyInstanceCamera(this.visibleTest.instance); } } setTeamColor(index) { this.teamColor = index; if (this.visibleTest) { this.visibleTest.instance.setTeamColor(this.teamColor); } } tryToInjectCustomTextures(customTest) { // If the given test is a texture, inject it into all of the model tests. if (customTest.resource instanceof Texture) { for (let test of this.tester.tests) { if (test !== customTest && test.instance && test.resource instanceof Model) { let textures = test.parser.textures; for (let i = 0, l = textures.length; i < l; i++) { let a = filename(textures[i].path).toLowerCase(); let b = filename(customTest.name).toLowerCase(); if (a === b) { test.instance.setTexture(i, customTest.resource); this.tester.logger.info(`Injected ${customTest.name} as a custom texture for ${test.name}`); } } } } } else { // Otherwise, if it's a model test, inject all of the texture tests into it. for (let test of this.tester.tests) { if (test !== customTest && test.instance) { if (test.resource instanceof Texture) { let textures = customTest.parser.textures; for (let i = 0, l = textures.length; i < l; i++) { let a = filename(textures[i].path).toLowerCase(); let b = filename(test.name).toLowerCase(); if (a === b) { customTest.instance.setTexture(i, test.resource); this.tester.logger.info(`Injected ${test.name} as a custom texture for ${customTest.name}`); } } } else { // Inject this model into others. let emitters = test.parser.particleEmitters; let a = filename(customTest.name).toLowerCase(); for (let i = 0, l = emitters.length; i < l; i++) { let b = filename(emitters[i].path).toLowerCase(); console.log('inject into other', a, b); } // Inject other models into this one. emitters = customTest.parser.particleEmitters; a = filename(customTest.name).toLowerCase(); for (let i = 0, l = emitters.length; i < l; i++) { let b = filename(emitters[i].path).toLowerCase(); console.log('inject from other', a, b); } } } } } } } ================================================ FILE: clients/sanitytest/components/viewercontrols.js ================================================ import { DebugRenderMode } from '../../../src/viewer/viewer'; import Component from "../../shared/component"; import Toggle from "../../shared/components/toggle"; import { clearSelect, createElement } from "../../shared/domutils"; import { TEAM_COLORS } from "./teamcolors"; export default class ViewerControls extends Component { constructor(viewer, options) { super({ ...options, className: 'viewer-controls' }); this.viewer = viewer; // Team colors. let container = createElement({ container: this.container }); createElement({ textContent: 'Team color:', container }); this.teamColorElement = createElement({ tagName: 'div', className: 'controls teamcolor', style: 'background-color:red', container }); this.teamColorsElement = createElement({ tagName: 'select', className: 'controls', onchange: () => { this.viewer.setTeamColor(this.teamColorsElement.selectedIndex); this.teamColorElement.style.backgroundColor = TEAM_COLORS[this.teamColorsElement.selectedIndex].color; }, container }); for (let teamColor of TEAM_COLORS) { this.teamColorsElement.add(createElement({ tagName: 'option', textContent: teamColor.name })); } // Extents. container = createElement({ container: this.container }); createElement({ textContent: 'Show extents:', container }); this.extentElement = createElement({ tagName: 'select', className: 'controls', onchange: () => this.viewer.updateExtents(), container }); this.extentElement.add(createElement({ tagName: 'option', textContent: 'No' })); this.extentElement.add(createElement({ tagName: 'option', textContent: 'Box' })); this.extentElement.add(createElement({ tagName: 'option', textContent: 'Sphere' })); this.extentElement.add(createElement({ tagName: 'option', textContent: 'Both' })); this.extentElement.selectedIndex = 0; // Collision shapes. container = createElement({ container: this.container }); createElement({ textContent: 'Show collisions:', container }); this.collisionsToggle = new Toggle('No', 'Yes', (e) => { this.viewer.showCollisions(e.clicked); }, { className: 'controls', container }); // Run animations. container = createElement({ container: this.container }); createElement({ textContent: 'Run Animations:', container }); this.animationToggle = new Toggle('Yes', 'No', (e) => { if (e.clicked) { this.viewer.viewer.frameTime = 0; } else { this.viewer.viewer.frameTime = 1000 / 60; } }, { className: 'controls', container }); // Cycle animations. container = createElement({ container: this.container }); createElement({ textContent: 'Cycle Animations:', container }); this.cycleToggle = new Toggle('Yes', 'No', null, { className: 'controls', container }); // Select animations. container = createElement({ container: this.container }); createElement({ textContent: 'Animations:', container }); this.sequencesElement = createElement({ tagName: 'select', className: 'controls', onchange: () => { if (!this.cycleToggle.clicked) { this.cycleToggle.toggle(); } this.viewer.viewer.clearEmittedObjects(); this.viewer.setSequence(this.sequencesElement.selectedIndex - 1); }, container }); // Frame. container = createElement({ container: this.container }); createElement({ textContent: 'Frame:', container }); this.frameElement = createElement({ container }); // Camera. container = createElement({ container: this.container }); createElement({ textContent: 'Camera:', container }); this.camerasElement = createElement({ tagName: 'select', className: 'controls', onchange: () => this.viewer.setCamera(this.camerasElement.selectedIndex - 1), container }); // Debug modes. container = createElement({ container: this.container }); createElement({ textContent: 'Debug Mode:', container }); this.debugRenderSelect = createElement({ tagName: 'select', className: 'controls', onchange: () => { // Somewhat hacky way to treat an enum. this.viewer.viewer.debugRenderMode = this.debugRenderSelect.selectedIndex; }, container }); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'None' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Diffuse' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Normal map' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Occlusion' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Roughness' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Metallic' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'TC Factor' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Emissive' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'TexCoords' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Normals' })); this.debugRenderSelect.add(createElement({ tagName: 'option', textContent: 'Tangents' })); } frame(frame) { this.frameElement.textContent = `${Math.floor(frame)}`; } updateInstance(instance) { clearSelect(this.sequencesElement); this.sequencesElement.add(createElement({ tagName: 'option', textContent: 'None' })); for (let sequence of instance.model.sequences) { this.sequencesElement.add(createElement({ tagName: 'option', textContent: sequence.name })); } clearSelect(this.camerasElement); this.camerasElement.add(createElement({ tagName: 'option', textContent: 'None' })); for (let camera of instance.model.cameras) { this.camerasElement.add(createElement({ tagName: 'option', textContent: camera.name })); } } setSequence(sequence) { if (this.sequencesElement.options.length === 1) { sequence = -1; } this.sequencesElement.selectedIndex = sequence + 1; } setCamera(camera) { this.camerasElement.selectedIndex = camera + 1; } } ================================================ FILE: clients/sanitytest/index.css ================================================ html, body { padding: 0; margin: 0; font-family: monaco, monospace; font-size: 14px; } .client { display: grid; width: 100%; height: 100vh; grid-template-rows: auto 1fr; grid-template-columns: 200px 0.9fr 1.1fr; grid-template-areas: "tests-header results-header viewer-and-mdl-header" "tests results viewer-and-mdl"; padding: 5px; grid-gap: 5px; box-sizing: border-box; color: #d8cba7; background-color: black; } .client>* { /* Anything inside a grid has min-height: auto and min-width: auto which means it expands to its size, we need to fix that. */ min-height: 0; min-width: 0; } .welcome { position: absolute; left: 0; right: 0; top: 0; bottom: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: #404040; box-sizing: border-box; } .welcome>* { width: 50%; } .welcome * { padding: 10px; } h1 { font-size: 16px; margin: 0; padding: 0; text-align: center; } .tests-header, .results-header, .viewer-and-mdl-header { background-color: #151515; } .tests-header { grid-area: tests-header; } .tests-body { grid-area: tests; display: grid; grid-template-rows: auto 1fr; grid-auto-columns: 1fr; grid-template-areas: "search-tests" "tests"; grid-gap: 5px; box-sizing: border-box; } .tests { overflow-y: auto; overflow-x: hidden; overflow-wrap: break-word; background-color: #202020; } .results-header { grid-area: results-header; display: flex; align-items: center; justify-content: center; gap: 5px; } .results-body { grid-area: results; overflow-y: auto; overflow-x: hidden; overflow-wrap: break-word; background-color: #202020; padding: 5px; } .viewer-and-mdl-header { grid-area: viewer-and-mdl-header; display: flex; align-items: center; justify-content: center; gap: 5px; } .viewer-and-mdl-body { grid-area: viewer-and-mdl; } .viewer-and-console { display: grid; width: 100%; height: 100%; grid-template-rows: 1fr 200px; grid-template-columns: 1fr; grid-template-areas: "viewer" "console"; grid-gap: 5px; box-sizing: border-box; } .viewer-and-console>* { /* Anything inside a grid has min-height: auto and min-width: auto which means it expands to its size, we need to fix that. */ min-height: 0; min-width: 0; } .viewer { grid-area: viewer; display: grid; grid-auto-columns: 1fr; grid-auto-rows: 1fr; grid-template-areas: 'viewer-and-controls'; } .viewer>* { grid-area: viewer-and-controls; min-height: 0; min-width: 0; } .viewer-controls { display: flex; flex-direction: column; gap: 2px; z-index: 1; pointer-events: none; background-color: transparent; padding: 5px; } .viewer-controls>* { display: flex; gap: 5px; } .controls { pointer-events: all; } .console { grid-area: console; display: grid; grid-template-rows: auto 1fr; grid-gap: 5px; box-sizing: border-box; } .console .tabs { display: flex; flex-direction: row; align-items: center; padding: 2px; gap: 5px; background-color: #202020; } .console .tab-contents { min-height: 0; min-width: 0; overflow-y: auto; overflow-x: hidden; overflow-wrap: break-word; background-color: #202020; padding: 5px; } .mdl { width: 100%; height: 100%; } .mdl-view { display: grid; width: 100%; height: 100%; grid-auto-rows: 1fr; grid-template-columns: 40% 1fr; grid-template-areas: "mdl-structure mdl-source"; grid-gap: 5px; box-sizing: border-box; } .mdl-view>* { /* Anything inside a grid has min-height: auto and min-width: auto which means it expands to its size, we need to fix that. */ min-height: 0; min-width: 0; } .mdl-structure { grid-area: mdl-structure; overflow-y: auto; background-color: #202020; padding: 5px; } .mdl-source { grid-area: mdl-source; overflow-y: auto; background-color: #202020; padding: 5px; } pre { white-space: pre-wrap; margin: 0; } table { border-spacing: 0; } .indent { margin-left: 1em; } .bold { font-weight: bold; } .log { color: #777777; } .info {} .warning { color: rgb(240, 204, 0); } .severe { color: rgb(201, 110, 0); } .error { color: rgb(200, 0, 0); } .unused { color: rgb(80, 136, 2); } .clickable { cursor: pointer; } .highlightable:hover { background-color: #151515; } .highlighted { background-color: #151515; border-left: 3px solid #6f0d10; } .highlighted:hover { background-color: #151515; } .center { text-align: center; } .hidden { display: none; } .padded { padding: 5px; } .teamcolor { width: 20px; height: 20px; } .info_marker { color: grey; padding-left: 5px; font-size: 9px; } .pointer { cursor: pointer; } ================================================ FILE: clients/sanitytest/index.html ================================================  Sanity Test ================================================ FILE: clients/sanitytest/index.js ================================================ import SanityTester from './components/sanitytester'; const tester = new SanityTester(document.body); document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); tester.loadDataTransfer(e.dataTransfer); }); tester.loadAPI(window.location.search); // For debugging etc. window.tester = tester; ================================================ FILE: clients/sanitytest/test.js ================================================ import { basename, extname } from "../../src/common/path"; import MdlxModel from '../../src/parsers/mdlx/model'; import { BlpImage } from '../../src/parsers/blp/image'; import { DdsImage } from '../../src/parsers/dds/image'; import TgaImage from '../../src/parsers/tga/image'; import TestResults from "./components/testresults"; import TestMeta from "./components/testmeta"; import MdlView from "./components/mdlview"; export default class Test { constructor(tester, name, buffer, pathSolver) { let ext = extname(name); let isMdlx = ext === '.mdx' || ext === '.mdl'; let isBlp = ext === '.blp'; let isDds = ext === '.dds'; this.name = name; this.shortName = basename(name); this.parsingError = false; this.results = null; this.mdl = null; this.pathSolver = pathSolver; // Loaded and set by the viewer component. this.resource = null; this.instance = null; this.boundingBox = null; this.boundingSphere = null; // this.cameras = []; this.collisions = []; if (isMdlx) { this.parser = new MdlxModel(); } else if (isBlp) { this.parser = new BlpImage(); } else if (isDds) { this.parser = new DdsImage(); } else { this.parser = new TgaImage(); } try { this.parser.load(buffer); } catch (e) { this.parsingError = true; tester.logger.error(`Failed to parse ${name}: ${e}. The test will attempt to run on whatever data loaded`); } this.results = new TestResults(this.parser); if (isMdlx) { this.mdl = new MdlView(this.parser); } this.meta = new TestMeta(this.shortName, this.parsingError, this.results.results, { onclick: () => tester.render(this) }); } show() { this.meta.highlight(); if (this.results) { this.results.show(); } if (this.mdl) { this.mdl.show(); } } hide() { this.meta.normal(); if (this.results) { this.results.hide(); } if (this.mdl) { this.mdl.hide(); } } } ================================================ FILE: clients/shared/camera.js ================================================ import { vec3, quat } from 'gl-matrix'; // Backwards compat with existing clients. export function setupCamera(scene, options = {}) { return new SimpleOrbitCamera(scene, options); } const vecHeap = vec3.create(); const vecHeap2 = vec3.create(); const quatHeap = quat.create(); const twistHeap = new Float32Array(1); // Get the vector length between two touches. function getTouchesLength(touch1, touch2) { let dx = touch2.clientX - touch1.clientX; let dy = touch2.clientY - touch1.clientY; return Math.sqrt(dx * dx + dy * dy); } // Touch modes. const TOUCH_MODE_INVALID = -1; const TOUCH_MODE_ROTATE = 0; const TOUCH_MODE_ZOOM = 1; // An orbit camera setup example. // Left mouse button controls the orbit itself. // The right mouse button allows to move the camera and the point it's looking at on the XY plane. // Scrolling zooms in and out. export class SimpleOrbitCamera { constructor(scene, options = {}) { this.scene = scene; this.canvas = scene.viewer.canvas; this.camera = scene.camera; // Movement per pixel of movement. this.moveSpeed = options.moveSpeed || 2; // Rotation in radians per pixel of movement. this.rotationSpeed = options.rotationSpeed || (Math.PI / 180); // Zoom factor per scroll. this.zoomFactor = options.zoomFactor || 0.1; this.horizontalAngle = options.horizontalAngle || Math.PI / 2; this.verticalAngle = options.verticalAngle || Math.PI / 4; this.distance = options.distance || 500; this.position = options.position || vec3.create(); // What the camera is looking at. this.target = options.target || vec3.create(); // The twist angle of the camera, which affects the "up" direction. // For example, a twist of 180 degrees, i.e. PI, will flip everything upside down. this.twist = options.twist || 0; // Mouse. this.mouse = { buttons: [false, false, false], x: 0, y: 0, x2: 0, y2: 0 }; // Touches. this.touchMode = TOUCH_MODE_INVALID; this.touches = []; this.instance = null; this.onManualChange = options.onManualChange || null; this.fov = options.fov || Math.PI / 4; this.nearClipPlane = options.nearClipPlane || 1; this.farClipPlane = options.farClipPlane || 200000; this.update(); window.addEventListener('resize', (e) => this.onResize()); setTimeout(() => this.onResize(), 0); // Disable the context menu when right-clicking. this.canvas.addEventListener('contextmenu', (e) => e.preventDefault()); this.canvas.addEventListener('selectstart', (e) => e.preventDefault()); // Track mouse clicks. this.canvas.addEventListener('mousedown', (e) => { e.preventDefault(); this.mouse.buttons[e.button] = true; }); // And mouse unclicks. // On the whole document rather than the canvas to stop annoying behavior when moving the mouse out of the canvas. document.addEventListener('mouseup', (e) => { e.preventDefault(); this.mouse.buttons[e.button] = false; }); // Handle rotating and moving the camera when the mouse moves. window.addEventListener('mousemove', (e) => { this.mouse.x2 = this.mouse.x; this.mouse.y2 = this.mouse.y; this.mouse.x = e.clientX; this.mouse.y = e.clientY; let dx = this.mouse.x - this.mouse.x2; let dy = this.mouse.y - this.mouse.y2; if (this.mouse.buttons[0]) { this.rotate(dx, dy); } if (this.mouse.buttons[2]) { this.move(-dx, dy); } }); // Handle zooming when the mouse scrolls. this.canvas.addEventListener('wheel', (e) => { e.preventDefault(); let deltaY = e.deltaY; if (e.deltaMode === 1) { deltaY = deltaY / 3 * 100; } this.zoom(deltaY / 100); }); // Listen to touches. // Supports 1 or 2 touch points. this.canvas.addEventListener('touchstart', (e) => { e.preventDefault(); let targetTouches = e.targetTouches; if (targetTouches.length === 1) { this.touchMode = TOUCH_MODE_ROTATE; } else if (targetTouches.length == 2) { this.touchMode = TOUCH_MODE_ZOOM; } else { this.touchMode = TOUCH_MODE_INVALID; } this.touches.length = 0; this.touches.push(...targetTouches); }); this.canvas.addEventListener('touchend', (e) => { e.preventDefault(); this.touchMode = TOUCH_MODE_INVALID; }); this.canvas.addEventListener('touchcancel', (e) => { e.preventDefault(); this.touchMode = TOUCH_MODE_INVALID; }); // Rotate or zoom based on the touch mode. this.canvas.addEventListener('touchmove', (e) => { e.preventDefault(); let targetTouches = e.targetTouches; if (this.touchMode === TOUCH_MODE_ROTATE) { let oldTouch = this.touches[0]; let newTouch = targetTouches[0]; let dx = newTouch.clientX - oldTouch.clientX; let dy = newTouch.clientY - oldTouch.clientY; this.rotate(dx, dy); } else if (this.touchMode === TOUCH_MODE_ZOOM) { let len1 = getTouchesLength(this.touches[0], this.touches[1]); let len2 = getTouchesLength(targetTouches[0], targetTouches[1]); this.zoom((len1 - len2) / 50); } this.touches.length = 0; this.touches.push(...targetTouches); }); } update() { if (this.instance) { let instance = this.instance; let mdxCamera = instance.model.cameras[0]; mdxCamera.getTranslation(vecHeap, instance.sequence, instance.frame, instance.counter); vec3.add(vecHeap, vecHeap, mdxCamera.position); mdxCamera.getTargetTranslation(vecHeap2, instance.sequence, instance.frame, instance.counter); vec3.add(vecHeap2, vecHeap2, mdxCamera.targetPosition); mdxCamera.getRotation(twistHeap, instance.sequence, instance.frame, instance.counter); this.twist = twistHeap[0]; // Change to world space in case the instance was moved in any way. // I am not sure how well this will handle scales, twists, and other things. vec3.transformMat4(vecHeap, vecHeap, instance.worldMatrix); vec3.transformMat4(vecHeap2, vecHeap2, instance.worldMatrix); this.moveToAndFace(vecHeap, vecHeap2); } else { this.updateInternalCamera(); } } // Move the camera and the target on the XY plane. move(x, y) { let dirX = this.camera.directionX; let dirY = this.camera.directionY; let w = this.canvas.width; let h = this.canvas.height; let aspect = w / h; let sw = (x / w) * this.distance * aspect; let sh = (y / h) * this.distance; vec3.add(this.target, this.target, vec3.scale(vecHeap, vec3.normalize(vecHeap, vec3.set(vecHeap, dirX[0], dirX[1], 0)), sw)); vec3.add(this.target, this.target, vec3.scale(vecHeap, vec3.normalize(vecHeap, vec3.set(vecHeap, dirY[0], dirY[1], 0)), sh)); this.manualChange(); } // Rotate the camera around the target. rotate(x, y) { this.horizontalAngle -= x * this.rotationSpeed; this.verticalAngle -= y * this.rotationSpeed; this.manualChange(); } // Zoom the camera by changing the distance from the target. zoom(factor) { this.distance = Math.max(1, this.distance * (1 + factor * this.zoomFactor)); this.manualChange(); } manualChange() { this.updateInternalCamera(); if (this.instance) { this.instance = null; if (this.onManualChange) { this.onManualChange(); } } } // Resize the canvas automatically and update the camera. onResize() { let width = Math.max(this.canvas.clientWidth, 1); let height = Math.max(this.canvas.clientHeight, 1); this.canvas.width = width; this.canvas.height = height; this.scene.viewport[2] = width; this.scene.viewport[3] = height; this.camera.perspective(this.fov, width / height, this.nearClipPlane, this.farClipPlane); } moveToAndFace(position, target) { vec3.sub(vecHeap, position, target); let r = vec3.length(vecHeap); let theta = Math.atan2(vecHeap[1], vecHeap[0]); let phi = Math.acos(vecHeap[2] / r); vec3.copy(this.target, target); this.verticalAngle = phi; this.horizontalAngle = theta + Math.PI / 2; this.distance = r; this.updateInternalCamera(); } updateInternalCamera() { // Limit the vertical angle so it doesn't flip. // Since the camera uses a quaternion, flips don't matter to it, but this feels better. this.verticalAngle = Math.min(Math.max(0.01, this.verticalAngle), Math.PI - 0.01); quat.identity(quatHeap); quat.rotateZ(quatHeap, quatHeap, this.horizontalAngle); quat.rotateX(quatHeap, quatHeap, this.verticalAngle); vec3.set(this.position, 0, 0, 1); vec3.transformQuat(this.position, this.position, quatHeap); vec3.scale(this.position, this.position, this.distance); vec3.add(this.position, this.position, this.target); let twist = this.twist - Math.PI / 2; vec3.set(vecHeap, 0, -Math.cos(twist), -Math.sin(twist)); this.camera.moveToAndFace(this.position, this.target, vecHeap); } applyInstanceCamera(instance) { this.instance = instance; this.fov = instance.model.cameras[0].fieldOfView; this.onResize(); this.update(); } } ================================================ FILE: clients/shared/component.js ================================================ import { createElement, hideElement, showElement } from './domutils'; export default class Component { constructor(options) { this.container = createElement({ ...options, component: this }); } hide() { hideElement(this.container); } show() { showElement(this.container); } highlight() { this.container.classList.add('highlighted'); } normal() { this.container.classList.remove('highlighted'); } } ================================================ FILE: clients/shared/components/toggle.js ================================================ import Component from "../component"; export default class Toggle extends Component { constructor(offName, onName, callback, options) { super({ ...options, tagName: 'button', textContent: offName, onclick: () => this.toggle() }); this.offName = offName; this.onName = onName; this.callback = callback; this.clicked = false; } toggle() { this.clicked = !this.clicked; if (this.clicked) { this.container.textContent = this.onName; } else { this.container.textContent = this.offName; } if (this.callback) { this.callback(this); } } } ================================================ FILE: clients/shared/domutils.js ================================================ export function createElement(options) { let tagName = 'div'; if (options && options.tagName) { tagName = options.tagName; } let element = document.createElement(tagName); if (options) { if (options.style) { element.style = options.style; } if (options.className) { element.className = options.className; } if (options.textContent) { element.textContent = options.textContent; } if (options.placeholder) { element.placeholder = options.placeholder; } if (options.readonly) { element.readonly = true; } if (options.href) { element.href = options.href; } if (options.target) { element.target = options.target; } if (options.title) { element.title = options.title; } if (options.onclick) { element.addEventListener('click', (e) => options.onclick(e, options.component)); } if (options.onchange) { element.addEventListener('change', (e) => options.onchange(e, options.component)); } if (options.oninput) { element.addEventListener('input', (e) => options.oninput(e, options.component)); } if (options.container) { options.container.appendChild(element); } } return element; } export function hideElement(element) { element.classList.add('hidden'); } export function showElement(element) { element.classList.remove('hidden'); } export function scrollToBottom(element) { element.scrollTop = element.scrollHeight; } export function scrolledToBottom(element) { return element.scrollHeight - element.clientHeight === element.scrollTop; } export function addTextToRow(row, text) { let cell = row.insertCell(); cell.appendChild(document.createTextNode(text)); return cell; } export function addElementToRow(row, element) { let cell = row.insertCell(); cell.appendChild(element); return cell; } export function clearSelect(element) { for (let l = element.options.length - 1, i = l; i >= 0; i--) { element.remove(i); } } ================================================ FILE: clients/shared/localorhive.js ================================================ import urlWithParams from '../../src/common/urlwithparams'; export default function localOrHive(src, params) { src = src.toLowerCase(); if (window.location.hostname === '127.0.0.1') { return urlWithParams(`${window.location.origin}/assets?path=${src}`, params); } else { // if (params && (params.reforged || params.sc2)) { return `https://www.hiveworkshop.com/casc-contents?path=${src}`; // } else { //return `https://www.hiveworkshop.com/data/static_assets/mpq/tft/${src}`; // } } } ================================================ FILE: clients/shared/utils.js ================================================ // Returns a promise that will resolve in the next VM event loop step. // Used to force the VM to wait, allowing the DOM to update between heavy operations. export function aFrame() { return new Promise((resolve) => { setTimeout(() => resolve(), 0); }); } export async function getAllFileEntries(dataTransfer) { const items = dataTransfer.items; let files = []; let queue = []; for (let i = 0; i < items.length; i++) { queue.push(items[i].webkitGetAsEntry()); } while (queue.length > 0) { let entry = queue.shift(); if (entry.isFile) { files.push(entry); } else if (entry.isDirectory) { queue.push(...await readAllDirectoryEntries(entry.createReader())); } } return files; } async function readAllDirectoryEntries(directoryReader) { let entries = []; let readEntries = await readEntriesPromise(directoryReader); while (readEntries.length > 0) { entries.push(...readEntries); readEntries = await readEntriesPromise(directoryReader); } return entries; } async function readEntriesPromise(directoryReader) { try { return await new Promise((resolve, reject) => { directoryReader.readEntries(resolve, reject); }); } catch (err) { console.log(err); } } export async function readFile(file, asText) { return new Promise((resolve) => { let reader = new FileReader(); reader.addEventListener('loadend', (e) => { resolve(e.target.result); }); if (asText) { reader.readAsText(file); } else { reader.readAsArrayBuffer(file); } }); } export async function readEntry(entry, asText) { return new Promise((resolve) => entry.file(async (file) => resolve(await readFile(file, asText)))); } ================================================ FILE: clients/tests/README.md ================================================ The unit tester. By definition, a test is comprised of an input scene, defined by the resources it needs and the setup script, and the output is the rendered image. The output image is compared against a previously generated image, using the same setup, which was created when the viewer was deemed to work "correctly". ================================================ FILE: clients/tests/components/unittester.js ================================================ import { version } from '../../../src/version'; import UnitTester from '../unittester'; import Component from '../../shared/component'; import { createElement, showElement, hideElement, addElementToRow, addTextToRow } from '../../shared/domutils'; import { wc3Solver } from '../solvers'; import { mdxTests } from '../tests/mdx'; import { mdxPrimitivesTests } from '../tests/mdxprimitives'; import { m3Tests } from '../tests/m3'; import { baseTests } from '../tests/base'; export default class UnitTesterComponent extends Component { constructor(parentElement) { super(); this.mismatchPercentageForFailure = 1; this.passed = 0; let unitTester = new UnitTester(wc3Solver); unitTester.add(mdxTests); unitTester.add(mdxPrimitivesTests); unitTester.add(m3Tests); unitTester.add(baseTests); this.unitTester = unitTester; createElement({ tagName: 'b', textContent: `Viewer version ${version}`, container: this.container }); createElement({ tagName: 'hr', container: this.container }); let controls = createElement({ container: this.container }); this.runButton = createElement({ tagName: 'button', textContent: 'Run', onclick: () => this.run(), container: controls }); this.downloadButton = createElement({ tagName: 'button', textContent: 'Download', onclick: () => this.download(), container: controls }); createElement({ tagName: 'hr', container: this.container }); this.resultsContainer = createElement({ className: 'hidden', container: this.container }); this.resultsMeta = createElement({ container: this.resultsContainer }); let resultsTable = createElement({ tagName: 'table', container: this.resultsContainer }); this.tbody = resultsTable.createTBody(); let thead = resultsTable.createTHead(); let header = thead.insertRow(); addElementToRow(header, createElement({ className: 'bold', textContent: 'Name' })); this.headerResult = addElementToRow(header, createElement({ className: 'bold', textContent: 'Result' })); this.headerNew = addElementToRow(header, createElement({ className: 'bold', textContent: 'New' })); this.headerOld = addElementToRow(header, createElement({ className: 'bold', textContent: 'Old' })); parentElement.appendChild(this.container); } clear() { let section = this.tbody; for (let l = section.rows.length - 1, i = l; i >= 0; i--) { section.deleteRow(i); } } result(result) { let row = this.tbody.insertRow(); addTextToRow(row, result.name); if (result.mismatchPercentage !== undefined) { let passed = result.mismatchPercentage < this.mismatchPercentageForFailure; if (passed) { this.passed += 1; } let total = this.unitTester.tests.length; let ran = this.tbody.rows.length; let className = 'passed'; if (this.passed < ran) { className = 'failed'; } this.resultsMeta.className = className; this.resultsMeta.textContent = `${this.passed} / ${ran} (${total} total)`; let name = passed ? 'passed' : 'failed'; addElementToRow(row, createElement({ className: name, textContent: name })) if (result.testImage) { let wrapper = createElement({ tagName: 'a', className: 'center', href: result.testImage.src, target: '_blank' }); wrapper.appendChild(result.testImage); addElementToRow(row, wrapper); } else { addTextToRow(row, ''); } if (result.comparisonImage) { let wrapper = createElement({ tagName: 'a', className: 'center', href: result.comparisonImage.src, target: '_blank' }); wrapper.appendChild(result.comparisonImage); addElementToRow(row, wrapper); } else { addTextToRow(row, ''); } } } run() { this.passed = 0; this.runButton.disabled = true; this.downloadButton.disabled = true; this.clear(); // In case they were hidden. showElement(this.headerResult); showElement(this.headerNew); showElement(this.headerOld); // In case it was hidden. showElement(this.resultsContainer); this.unitTester.test((entry) => { if (!entry.done) { let result = entry.value; if (result.result < 1) { this.passed++; } this.result(result); } else { this.runButton.disabled = false; this.downloadButton.disabled = false; } }); } download() { this.passed = 0; this.runButton.disabled = true; this.downloadButton.disabled = true; this.clear(); // In case they were shown. hideElement(this.headerResult); hideElement(this.headerNew); hideElement(this.headerOld); // In case it was hidden. showElement(this.resultsContainer); let zip = new JSZip(); this.unitTester.download((entry) => { if (!entry.done) { let result = entry.value; this.result(result); if (result.blob) { this.passed++; zip.file(`${result.name}.png`, result.blob); } else { console.log(`Skipping ${result.name} because it has no blob`); } } else { this.runButton.disabled = false; this.downloadButton.disabled = false; zip.generateAsync({ type: 'blob' }) .then((blob) => { saveAs(blob, `compare_${version}.zip`); }); } }); } } ================================================ FILE: clients/tests/index.html ================================================  Unit Tests ================================================ FILE: clients/tests/index.js ================================================ import UnitTester from './components/unittester'; const tester = new UnitTester(document.body); // For debugging etc. window.tester = tester; ================================================ FILE: clients/tests/solvers.js ================================================ import localOrHive from "../shared/localorhive"; export const wc3Solver = (path, params) => { path = localOrHive(path, params); // GREAT JOB BLIZZARD. AWESOME PATCHES. if (path.endsWith('orcbloodriderlesswyvernrider.mdx') && path.includes('hiveworkshop')) { path = path.replace('orcbloodriderlesswyvernrider.mdx', 'ordbloodriderlesswyvernrider.mdx'); } return path; }; export const sc2Solver = localOrHive; ================================================ FILE: clients/tests/tests/base.js ================================================ import { wc3Solver, sc2Solver } from "../solvers"; export const baseTests = { name: 'base', tests: [ { name: 'attachments', load(viewer) { return [ viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver), viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver), ]; }, test(viewer, scene, camera, models) { let mountainKing = models[0]; let baneling = models[1]; camera.moveToAndFace([450, 0, 160], [0, 0, 160], [0, 0, 1]); let instance1 = mountainKing.addInstance().setSequence(1); let instance3 = mountainKing.addInstance().setSequence(1); let instance5 = mountainKing.addInstance().setSequence(1); let instance2 = baneling.addInstance().setSequence(0).uniformScale(100); let instance4 = baneling.addInstance().setSequence(0).uniformScale(100); let instance6 = baneling.addInstance().setSequence(0).uniformScale(100); instance2.setParent(instance1.getAttachment(3)); instance3.setParent(instance2.getAttachment(4)); instance4.setParent(instance3.getAttachment(3)); instance5.setParent(instance4.getAttachment(4)); instance6.setParent(instance5.getAttachment(3)); scene.addInstance(instance1); scene.addInstance(instance2); scene.addInstance(instance3); scene.addInstance(instance4); scene.addInstance(instance5); scene.addInstance(instance6); }, }, ], }; ================================================ FILE: clients/tests/tests/m3.js ================================================ import { sc2Solver } from "../solvers"; export const m3Tests = { name: 'm3', tests: [ { name: 'base', load(viewer) { return viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 5, 100], [0, 5, 0], [0, 1, 0]); let instance = model.addInstance().uniformScale(50); scene.addInstance(instance); }, }, { name: 'sequence', load(viewer) { return viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 5, 100], [0, 5, 0], [0, 1, 0]); let instance = model.addInstance().uniformScale(50).setSequence(0); instance.frame = 800; scene.addInstance(instance); }, }, { name: 'team-color', load(viewer) { return viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 5, 100], [0, 5, 0], [0, 1, 0]); let instance = model.addInstance().uniformScale(50).setTeamColor(1); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 5, 100], [0, 5, 0], [0, 1, 0]); let instance = model.addInstance().uniformScale(50).setVertexColor([1, 0, 0, 1]); scene.addInstance(instance); }, }, { name: 'vertex-and-team-colors', load(viewer) { return viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 5, 100], [0, 5, 0], [0, 1, 0]); let instance = model.addInstance().uniformScale(50).setVertexColor([1, 0, 0, 1]).setTeamColor(1); scene.addInstance(instance); }, }, { name: 'texture-overriding', load(viewer) { return viewer.load('Assets/Units/Zerg/Baneling/Baneling.m3', sc2Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 5, 140], [0, 5, 0], [0, 1, 0]); let instance = model.addInstance().uniformScale(50).move([25, 0, 0]); let instance2 = model.addInstance().uniformScale(50).move([-25, 0, 0]); let material = model.materials[1][0]; instance.setTexture(0, 0, material.layers[10].texture.texture); scene.addInstance(instance); scene.addInstance(instance2); }, }, ], }; ================================================ FILE: clients/tests/tests/mdx.js ================================================ import { quat } from "gl-matrix"; import { wc3Solver } from "../solvers"; export const mdxTests = { name: 'mdx', tests: [ { name: 'base', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 45], [0, 0, 45], [0, 0, 1]); let instance = model.addInstance(); scene.addInstance(instance); }, }, { name: 'sequence', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 45], [0, 0, 45], [0, 0, 1]); let instance = model.addInstance().setSequence(0); instance.frame = 800; scene.addInstance(instance); }, }, { name: 'team-color', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 45], [0, 0, 45], [0, 0, 1]); let instance = model.addInstance().setTeamColor(1); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 45], [0, 0, 45], [0, 0, 1]); let instance = model.addInstance().setVertexColor([1, 0, 0, 1]); scene.addInstance(instance); }, }, { name: 'vertex-and-team-colors', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 45], [0, 0, 45], [0, 0, 1]); let instance = model.addInstance().setVertexColor([1, 0, 0, 1]).setTeamColor(1); scene.addInstance(instance); }, }, { name: 'texture-animation', tests: [ { name: 'translation-and-slot', load(viewer) { return viewer.load('Units/Human/WaterElemental/WaterElemental.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([200, 0, 85], [0, 0, 85], [0, 0, 1]); let instance = model.addInstance().setSequence(0); instance.frame = 800; scene.addInstance(instance); }, }, { name: 'rotation', load(viewer) { return viewer.load('UI/Feedback/Cooldown/UI-Cooldown-Indicator.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([40, 40, 100], [40, 40, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(0).uniformScale(2100).setSequenceLoopMode(2); instance.frame = 600; scene.addInstance(instance); }, }, { name: 'scale', load(viewer) { return viewer.load('Abilities/Spells/Other/Volcano/Volcano.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([400, 0, 50], [0, 0, 50], [0, 0, 1]); let instance = model.addInstance().setSequence(1); scene.addInstance(instance); }, }, ], }, { name: 'billboarding', tests: [ { name: 'standard', load(viewer) { return viewer.load('Units/Creeps/Gnoll/Gnoll.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([120, -50, 75], [0, 0, 40], [0, 0, 1]); let instance = model.addInstance().setSequence(1).setSequenceLoopMode(2); // Rotate also the instance, to be sure billboarding works in all cases. // It happened in a past implementation that billboaring worked as long as the instance isn't rotated. // Needless to say, it took a long time to find that bug. instance.rotate(quat.setAxisAngle([], [0, 1, 0], -0.785398)); instance.frame = 800; scene.addInstance(instance); viewer.update(); }, }, { name: 'x-axis', load(viewer) { return viewer.load('SharedModels/NEBirth.MDX', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([200, -200, 400], [0, 0, 300], [0, 0, 1]); let instance = model.addInstance().setSequence(0).rotate(quat.setAxisAngle([], [0, 0, 1], -0.785398)); instance.frame += 30000; scene.addInstance(instance); }, }, ], }, { name: 'attachment-model', load(viewer) { return viewer.load('Buildings/Undead/HauntedMine/HauntedMine.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 0, 620], [0, 0, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(0); scene.addInstance(instance); instance.frame = 20000; // update() is used here, because when an attachment becomes visible for the first time, the parent instance resets its sequence. // If the attachment's frame was set without first updating, it will just get reset to the sequence's beginning. viewer.update(); let attachment = instance.attachments[0].internalInstance; attachment.frame = instance.frame; }, }, { name: 'particle-emitter', load(viewer) { return viewer.load('Units/Creeps/AzureDragon/AzureDragon.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([50, -35, 250], [50, -35, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(5); scene.addInstance(instance); for (let i = 0; i < 30; i++) { viewer.update(); } }, }, { name: 'particle-2-emitter', tests: [ { name: 'base', load(viewer) { return viewer.load('Units/Creeps/AzureDragon/AzureDragon.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([300, 0, -20], [0, 0, -20], [0, 0, 1]); let instance = model.addInstance().setSequence(1); scene.addInstance(instance); for (let i = 0; i < 90; i++) { viewer.update(); } }, }, { name: 'squirt', load(viewer) { return viewer.load('Abilities/Spells/Human/Thunderclap/ThunderclapCaster.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 0, 250], [0, 0, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(1); scene.addInstance(instance); for (let i = 0; i < 4; i++) { viewer.update(); } }, }, { name: 'line-emitter', load(viewer) { return viewer.load('Abilities/Spells/Human/Thunderclap/ThunderclapCaster.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([200, 0, 50], [0, 0, 50], [0, 0, 1]); let instance = model.addInstance().setSequence(1); scene.addInstance(instance); for (let i = 0; i < 4; i++) { viewer.update(); } }, }, { name: 'tail', load(viewer) { return viewer.load('Doodads/Dungeon/Props/ForceWall/ForceWall.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([700, 0, 100], [0, 0, 100], [0, 0, 1]); let instance = model.addInstance().setSequence(0).setSequenceLoopMode(2); scene.addInstance(instance); for (let i = 0; i < 100; i++) { viewer.update(); } }, }, { name: 'repeat', load(viewer) { return viewer.load('Doodads/Cinematic/EnergyField/EnergyField.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 600, 100], [0, 0, 50], [0, 0, 1]); let instance = model.addInstance().setSequence(0).setSequenceLoopMode(2); scene.addInstance(instance); for (let i = 0; i < 50; i++) { viewer.update(); } }, }, { name: 'xy-quad', load(viewer) { return viewer.load('Units/Orc/SpiritWyvern/SpiritWyvern.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 300, 100], [0, 0, 50], [0, 0, 1]); let instance = model.addInstance().setSequence(9).setSequenceLoopMode(2); scene.addInstance(instance); for (let i = 0; i < 50; i++) { viewer.update(); } }, }, ], }, { name: 'ribbon-emitter', load(viewer) { return viewer.load('Units/Human/HeroPaladin/HeroPaladin.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([225, -45, 70], [0, 0, 70], [0, 0, 1]); let instance = model.addInstance().setSequence(4).setSequenceLoopMode(2); scene.addInstance(instance); for (let i = 0; i < 24; i++) { viewer.update(); } }, }, { name: 'event-object', tests: [ { name: 'spn', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([-40, 0, 100], [-40, 0, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(9); scene.addInstance(instance); for (let i = 0; i < 50; i++) { viewer.update(); } }, }, { name: 'spl', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 0, 80], [0, 0, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(9); scene.addInstance(instance); for (let i = 0; i < 170; i++) { viewer.update(); } }, }, { name: 'ubr', load(viewer) { return viewer.load('Abilities/Spells/Human/Thunderclap/ThunderclapCaster.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([0, 0, 500], [0, 0, 0], [0, 1, 0]); let instance = model.addInstance().setSequence(1); scene.addInstance(instance); for (let i = 0; i < 20; i++) { viewer.update(); } }, }, ], }, { name: 'texture-overriding', load(viewer) { return viewer.load('Units/Human/Footman/Footman.mdx', wc3Solver); }, test(viewer, scene, camera, model) { camera.moveToAndFace([220, 0, 45], [0, 0, 45], [0, 0, 1]); let instance = model.addInstance().move([0, 40, 0]); let instance2 = model.addInstance().move([0, -40, 0]); instance.setTexture(0, model.textures[2].texture); scene.addInstance(instance); scene.addInstance(instance2); }, }, ], }; ================================================ FILE: clients/tests/tests/mdxprimitives.js ================================================ import { quat } from "gl-matrix"; import createPrimitive from "../../../src/utils/mdlx/primitives/createprimitive"; import { createUnitRectangle, createUnitCube, createUnitSphere, createUnitCylinder, createFrustum } from "../../../src/utils/mdlx/primitives/primitives"; export const mdxPrimitivesTests = { name: 'mdx-primitives', tests: [ { name: 'rectangle', tests: [ { name: 'faces', load(viewer) { return createPrimitive(viewer, createUnitRectangle()); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edges', load(viewer) { return createPrimitive(viewer, createUnitRectangle(), { lines: true }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return createPrimitive(viewer, createUnitRectangle(), { color: new Float32Array([1, 0, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edge-color', load(viewer) { return createPrimitive(viewer, createUnitRectangle(), { lines: true, color: new Float32Array([0, 1, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'texture', load(viewer) { let texture = viewer.load('resources/checkers.jpg'); return createPrimitive(viewer, createUnitRectangle(), { texture }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, ], }, { name: 'cube', tests: [ { name: 'faces', load(viewer) { return createPrimitive(viewer, createUnitCube()); }, test(viewer, scene, camera, model) { camera.move([0, 0, 160]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edges', load(viewer) { return createPrimitive(viewer, createUnitCube(), { lines: true }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 160]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return createPrimitive(viewer, createUnitCube(), { color: new Float32Array([1, 0, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 160]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edge-color', load(viewer) { return createPrimitive(viewer, createUnitCube(), { lines: true, color: new Float32Array([0, 1, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 160]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'texture', load(viewer) { let texture = viewer.load('resources/checkers.jpg'); return createPrimitive(viewer, createUnitCube(), { texture }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 160]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, ], }, { name: 'sphere', tests: [ { name: 'faces', load(viewer) { return createPrimitive(viewer, createUnitSphere(20, 20)); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edges', load(viewer) { return createPrimitive(viewer, createUnitSphere(20, 20), { lines: true }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return createPrimitive(viewer, createUnitSphere(20, 20), { color: new Float32Array([1, 0, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edge-color', load(viewer) { return createPrimitive(viewer, createUnitSphere(20, 20), { lines: true, color: new Float32Array([0, 1, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'texture', load(viewer) { let texture = viewer.load('resources/checkers.jpg'); return createPrimitive(viewer, createUnitSphere(20, 20), { texture }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 120]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, ], }, { name: 'cylinder', tests: [ { name: 'faces', load(viewer) { return createPrimitive(viewer, createUnitCylinder(20)); }, test(viewer, scene, camera, model) { camera.move([0, 0, 150]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edges', load(viewer) { return createPrimitive(viewer, createUnitCylinder(20), { lines: true }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 150]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return createPrimitive(viewer, createUnitCylinder(20), { color: new Float32Array([1, 0, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 150]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'edge-color', load(viewer) { return createPrimitive(viewer, createUnitCylinder(20), { lines: true, color: new Float32Array([0, 1, 0]) }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 150]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, { name: 'texture', load(viewer) { let texture = viewer.load('resources/checkers.jpg'); return createPrimitive(viewer, createUnitCylinder(), { texture }); }, test(viewer, scene, camera, model) { camera.move([0, 0, 150]); let instance = model.addInstance().uniformScale(40).rotate(quat.setAxisAngle([], [1, 0, 0], Math.PI / 8)); scene.addInstance(instance); }, }, ], }, { name: 'frustum', tests: [ { name: 'faces', load(viewer) { return createPrimitive(viewer, createFrustum(Math.PI / 4, 0.75, 8, 120)); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 200], [0, 0, 60], [0, 0, 1]); let instance = model.addInstance(); scene.addInstance(instance); }, }, { name: 'edges', load(viewer) { return createPrimitive(viewer, createFrustum(Math.PI / 4, 0.75, 8, 120), { lines: true }); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 200], [0, 0, 60], [0, 0, 1]); let instance = model.addInstance(); scene.addInstance(instance); }, }, { name: 'vertex-color', load(viewer) { return createPrimitive(viewer, createFrustum(Math.PI / 4, 0.75, 8, 120), { color: new Float32Array([1, 0, 0]) }); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 200], [0, 0, 60], [0, 0, 1]); let instance = model.addInstance(); scene.addInstance(instance); }, }, { name: 'edge-color', load(viewer) { return createPrimitive(viewer, createFrustum(Math.PI / 4, 0.75, 8, 120), { lines: true, color: new Float32Array([0, 1, 0]) }); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 200], [0, 0, 60], [0, 0, 1]); let instance = model.addInstance(); scene.addInstance(instance); }, }, { name: 'texture', load(viewer) { let texture = viewer.load('resources/checkers.jpg'); return createPrimitive(viewer, createFrustum(Math.PI / 4, 0.75, 8, 120), { texture }); }, test(viewer, scene, camera, model) { camera.moveToAndFace([150, 0, 200], [0, 0, 60], [0, 0, 1]); let instance = model.addInstance(); scene.addInstance(instance); }, }, ], }, ], }; ================================================ FILE: clients/tests/unittester.js ================================================ import * as resemble from '../thirdparty/resemble'; import seededRandom from '../../src/common/seededrandom'; import { blobToImage } from '../../src/common/canvas'; import ModelViewer from '../../src/viewer/viewer'; import mdxHandler from '../../src/viewer/handlers/mdx/handler'; import blpHandler from '../../src/viewer/handlers/blp/handler'; import ddsHandler from '../../src/viewer/handlers/dds/handler'; import tgaHandler from '../../src/viewer/handlers/tga/handler'; import m3Handler from '../../src/viewer/handlers/m3/handler'; /** * A unit tester designed for the model viewer. * The input of each test is a pre-defined scene, and the output is the rendered image. * The image is then compared to another image generated from the same test, at a time when rendering it was considered "correct". */ export default class UnitTester { constructor(wc3PathSolver) { let canvas = document.createElement('canvas'); canvas.width = canvas.height = 256; let viewer = new ModelViewer(canvas, { alpha: false, antialias: false }); viewer.gl.clearColor(0.05, 0.05, 0.05, 1); viewer.on('error', (e) => console.log(e)); viewer.addHandler(mdxHandler, wc3PathSolver); viewer.addHandler(blpHandler); viewer.addHandler(ddsHandler); viewer.addHandler(tgaHandler); viewer.addHandler(m3Handler); this.viewer = viewer; this.mathRandom = Math.random; this.tests = []; } /** * Add a test or a hierarchy of tests. */ add(test) { if (test.tests) { this.addBaseName(test.tests, test.name); } else { this.tests.push({ name: test.name, test }); } } /** * Run all of the tests that were added. * The callback will be called with the result of each one. * The results look like iterators: {done: true/false, value: undefine/result }. */ async test(callback) { for (let test of this.tests) { let testBlob = await this.getTestBlob(test); let comparisonBlob = await this.getComparisonBlob(test); if (testBlob && comparisonBlob) { let comparisonResult = await new Promise((resolve) => resemble(testBlob).compareTo(comparisonBlob).ignoreColors().onComplete((data) => resolve(data))); let testImage = await blobToImage(testBlob); let comparisonImage = await blobToImage(comparisonBlob); callback({ done: false, value: { name: test.name, testImage, comparisonImage, mismatchPercentage: comparisonResult.rawMisMatchPercentage } }); } else { // Fail modes. // 1) The test blob exists, but comparison doesn't. This happens when adding new tests. // 2) The comparison blob exists, but the test doesn't. This happens when having issues with fetching the files needed for the tests. // 3) Neither exists. if (testBlob) { callback({ done: false, value: { name: test.name, testImage: await blobToImage(testBlob), mismatchPercentage: 100 } }); } else if (comparisonBlob) { callback({ done: false, value: { name: test.name, comparisonImage: await blobToImage(comparisonBlob), mismatchPercentage: 100 } }); } else { callback({ done: false, value: { name: test.name, mismatchPercentage: 100 } }); } } } callback({ done: true }); } /** * Run all of the tests that were added, and download them. * The tests are not compared against anything. * This is used to update the "correct" results. */ async download(callback) { for (let test of this.tests) { let name = test.name; let blob = await this.getTestBlob(test); if (blob) { callback({ done: false, value: { name, blob } }); } else { callback({ done: false, value: { name } }); } } callback({ done: true }); } /** * Is the given resource or array of resources ok? */ isDataAGo(data) { if (data) { if (Array.isArray(data)) { for (let resource of data) { if (!resource) { return false; } } } return true; } return false; } /** * Given a test, return a promise that will resolve to the blob that resulted from running the test. */ async getTestBlob(test) { let loadHandler = test.test.load; let testHandler = test.test.test; let viewer = this.viewer; // Clear the viewer viewer.clear(); let scene = viewer.addScene(); scene.color.fill(0.05); // Start loading the test. let data = loadHandler(viewer); // Wait until everything loaded. await viewer.whenAllLoaded(); if (Array.isArray(data)) { data = await Promise.all(data); } else { data = await data; } if (this.isDataAGo(data)) { // Replace Math.random with a custom seeded random generator. // This allows to run the viewer in a deterministic environment for tests. // For example, particles have some randomized data, which can make tests mismatch. Math.random = seededRandom(6); // Run the test. testHandler(viewer, scene, scene.camera, data); // Update and render. viewer.updateAndRender(); // Put back Math.random in its place. Math.random = this.mathRandom; // Return the viewer's canvas' blob. return await viewer.toBlob(); } } /** * Given a test, return a promise that will resolve to the comparison image of this test. */ async getComparisonBlob(test) { let response = await fetch(`compare/${test.name}.png`); if (response.ok) { return await response.blob(); } } /** * Adds tests from an hierarchy while appending their names. * Called automatically by add() if needed. */ addBaseName(tests, baseName) { for (let test of tests) { if (test.tests) { this.addBaseName(test.tests, baseName + '-' + test.name); } else { this.tests.push({ name: baseName + '-' + test.name, test }); } } } } ================================================ FILE: clients/textureatlas/index.html ================================================  KEKW
Input
Width:
Height:
Output
Width
Height
Columns
Rows
Revolutions
Cell Width:
32px
Cell Height:
32px
================================================ FILE: clients/textureatlas/index.js ================================================ class TextureAtlasGenerator { constructor() { this.inputWidthElement = document.getElementById('input_width'); this.inputHeightElement = document.getElementById('input_height'); this.outputCellWidthElement = document.getElementById('output_cell_width'); this.outputCellHeightElement = document.getElementById('output_cell_height'); this.statusElement = document.getElementById('status'); this.inputCanvas = document.getElementById('input_canvas'); this.workCanvas = document.getElementById('work_canvas'); this.outputCanvas = document.getElementById('output_canvas'); this.inputCtx = this.inputCanvas.getContext('2d'); this.workCtx = this.workCanvas.getContext('2d'); this.outputCtx = this.outputCanvas.getContext('2d'); this.image = null; this.inputWidth = 0; this.inputHeight = 0; this.width = 256; this.height = 256; this.columns = 8; this.rows = 8; this.revolutions = 1; this.cellWidth = 32; this.cellHeight = 32; document.getElementById('output_width').addEventListener('change', (e) => this.setWidth(e.target.value)); document.getElementById('output_height').addEventListener('change', (e) => this.setHeight(e.target.value)); document.getElementById('output_columns').addEventListener('change', (e) => this.setColumns(e.target.value)); document.getElementById('output_rows').addEventListener('change', (e) => this.setRows(e.target.value)); document.getElementById('output_revolutions').addEventListener('change', (e) => this.setRevolutions(e.target.value)); document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); let file = e.dataTransfer.files[0]; let reader = new FileReader(); reader.addEventListener('loadend', (e) => { let image = new Image(); image.onload = (e) => this.setImage(image); image.onerror = (e) => this.error('Failed to load the file'); image.src = e.target.result; }); reader.readAsDataURL(file); }); this.status('Drag & drop an image anywhere on the page'); } status(status) { this.statusElement.textContent = status; } error(status) { const { workCtx, workCanvas, outputCtx, outputCanvas } = this; workCtx.clearRect(0, 0, workCanvas.width, workCanvas.height); outputCtx.clearRect(0, 0, outputCanvas.width, outputCanvas.height); this.status(status); } setImage(image) { const { inputCanvas, inputCtx, inputWidthElement, inputHeightElement } = this; this.image = image; inputCanvas.width = image.width; inputCanvas.height = image.height; inputCtx.drawImage(image, 0, 0); inputWidthElement.textContent = `${image.width}px`; inputHeightElement.textContent = `${image.height}px`; this.update(); } setWidth(width) { this.width = width; this.update(); } setHeight(height) { this.height = height; this.update(); } setColumns(columns) { this.columns = columns; this.update(); } setRows(rows) { this.rows = rows; this.update(); } setRevolutions(revolutions) { this.revolutions = revolutions; this.update(); } update() { const { image, width, height, columns, rows, revolutions } = this; if (!image) { this.error('Upload an image'); return; } if (width < 1 || height < 1 || columns < 1 || rows < 1) { this.error('No negative values'); return; } this.cellWidth = width / columns; this.cellHeight = height / rows; const { outputCellWidthElement, outputCellHeightElement, cellWidth, cellHeight } = this; outputCellWidthElement.textContent = `${cellWidth}px`; outputCellHeightElement.textContent = `${cellHeight}px`; if (cellWidth !== (cellWidth | 0) || cellHeight !== (cellHeight | 0)) { this.error('No fractional cell sizes'); return; } const { workCanvas, outputCanvas, workCtx, outputCtx } = this; const step = (revolutions * Math.PI * 2) / (columns * rows); workCanvas.width = cellWidth; workCanvas.height = cellHeight; outputCanvas.width = width; outputCanvas.height = height; let angle = 0; for (let y = 0; y < rows; y++) { for (let x = 0; x < columns; x++) { workCtx.clearRect(0, 0, cellWidth, cellHeight); workCtx.save(); workCtx.translate(cellWidth / 2, cellHeight / 2); workCtx.rotate(angle); workCtx.translate(-cellWidth / 2, -cellHeight / 2); workCtx.drawImage(image, 0, 0, cellWidth, cellHeight); workCtx.restore(); outputCtx.drawImage(workCanvas, x * cellWidth, y * cellHeight); angle += step; } } this.status('Right click on the texture atlas to download it, or adjust values and regenerate it'); } } new TextureAtlasGenerator(); ================================================ FILE: clients/thirdparty/filesaver.js ================================================ /* FileSaver.js * A saveAs() & saveTextAs() FileSaver implementation. * 2014-06-24 * * Modify by Brian Chen * Author: Eli Grey, http://eligrey.com * License: X11/MIT * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md */ /*global self */ /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ var saveAs = saveAs // IE 10+ (native saveAs) || (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) // Everyone else || (function (view) { "use strict"; // IE <10 is explicitly unsupported if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { return; } var doc = view.document // only get URL when necessary in case Blob.js hasn't overridden it yet , get_URL = function () { return view.URL || view.webkitURL || view; } , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") , can_use_save_link = !view.externalHost && "download" in save_link , click = function (node) { var event = doc.createEvent("MouseEvents"); event.initMouseEvent( "click", true, false, view, 0, 0, 0, 0, 0 , false, false, false, false, 0, null ); node.dispatchEvent(event); } , webkit_req_fs = view.webkitRequestFileSystem , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem , throw_outside = function (ex) { (view.setImmediate || view.setTimeout)(function () { throw ex; }, 0); } , force_saveable_type = "application/octet-stream" , fs_min_size = 0 , deletion_queue = [] , process_deletion_queue = function () { var i = deletion_queue.length; while (i--) { var file = deletion_queue[i]; if (typeof file === "string") { // file is an object URL get_URL().revokeObjectURL(file); } else { // file is a File file.remove(); } } deletion_queue.length = 0; // clear queue } , dispatch = function (filesaver, event_types, event) { event_types = [].concat(event_types); var i = event_types.length; while (i--) { var listener = filesaver["on" + event_types[i]]; if (typeof listener === "function") { try { listener.call(filesaver, event || filesaver); } catch (ex) { throw_outside(ex); } } } } , FileSaver = function (blob, name) { // First try a.download, then web filesystem, then object URLs var filesaver = this , type = blob.type , blob_changed = false , object_url , target_view , get_object_url = function () { var object_url = get_URL().createObjectURL(blob); deletion_queue.push(object_url); return object_url; } , dispatch_all = function () { dispatch(filesaver, "writestart progress write writeend".split(" ")); } // on any filesys errors revert to saving with object URLs , fs_error = function () { // don't create more object URLs than needed if (blob_changed || !object_url) { object_url = get_object_url(blob); } if (target_view) { target_view.location.href = object_url; } else { window.open(object_url, "_blank"); } filesaver.readyState = filesaver.DONE; dispatch_all(); } , abortable = function (func) { return function () { if (filesaver.readyState !== filesaver.DONE) { return func.apply(this, arguments); } }; } , create_if_not_found = { create: true, exclusive: false } , slice ; filesaver.readyState = filesaver.INIT; if (!name) { name = "download"; } if (can_use_save_link) { object_url = get_object_url(blob); save_link.href = object_url; save_link.download = name; click(save_link); filesaver.readyState = filesaver.DONE; dispatch_all(); return; } // Object and web filesystem URLs have a problem saving in Google Chrome when // viewed in a tab, so I force save with application/octet-stream // http://code.google.com/p/chromium/issues/detail?id=91158 if (view.chrome && type && type !== force_saveable_type) { slice = blob.slice || blob.webkitSlice; blob = slice.call(blob, 0, blob.size, force_saveable_type); blob_changed = true; } // Since I can't be sure that the guessed media type will trigger a download // in WebKit, I append .download to the filename. // https://bugs.webkit.org/show_bug.cgi?id=65440 if (webkit_req_fs && name !== "download") { name += ".download"; } if (type === force_saveable_type || webkit_req_fs) { target_view = view; } if (!req_fs) { fs_error(); return; } fs_min_size += blob.size; req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) { fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) { var save = function () { dir.getFile(name, create_if_not_found, abortable(function (file) { file.createWriter(abortable(function (writer) { writer.onwriteend = function (event) { target_view.location.href = file.toURL(); deletion_queue.push(file); filesaver.readyState = filesaver.DONE; dispatch(filesaver, "writeend", event); }; writer.onerror = function () { var error = writer.error; if (error.code !== error.ABORT_ERR) { fs_error(); } }; "writestart progress write abort".split(" ").forEach(function (event) { writer["on" + event] = filesaver["on" + event]; }); writer.write(blob); filesaver.abort = function () { writer.abort(); filesaver.readyState = filesaver.DONE; }; filesaver.readyState = filesaver.WRITING; }), fs_error); }), fs_error); }; dir.getFile(name, { create: false }, abortable(function (file) { // delete file if it already exists file.remove(); save(); }), abortable(function (ex) { if (ex.code === ex.NOT_FOUND_ERR) { save(); } else { fs_error(); } })); }), fs_error); }), fs_error); } , FS_proto = FileSaver.prototype , saveAs = function (blob, name) { return new FileSaver(blob, name); } ; FS_proto.abort = function () { var filesaver = this; filesaver.readyState = filesaver.DONE; dispatch(filesaver, "abort"); }; FS_proto.readyState = FS_proto.INIT = 0; FS_proto.WRITING = 1; FS_proto.DONE = 2; FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; view.addEventListener("unload", process_deletion_queue, false); saveAs.unload = function () { process_deletion_queue(); view.removeEventListener("unload", process_deletion_queue, false); }; return saveAs; }( typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content )); // `self` is undefined in Firefox for Android content script context // while `this` is nsIContentFrameMessageManager // with an attribute `content` that corresponds to the window if (typeof module !== "undefined" && module !== null) { module.exports = saveAs; } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { define([], function () { return saveAs; }); } String.prototype.endsWithAny = function () { var strArray = Array.prototype.slice.call(arguments), $this = this.toLowerCase().toString(); for (var i = 0; i < strArray.length; i++) { if ($this.indexOf(strArray[i], $this.length - strArray[i].length) !== -1) return true; } return false; }; var saveTextAs = saveTextAs || (function (textContent, fileName, charset) { fileName = fileName || 'download.txt'; charset = charset || 'utf-8'; textContent = (textContent || '').replace(/\r?\n/g, "\r\n"); if (saveAs && Blob) { var blob = new Blob([textContent], { type: "text/plain;charset=" + charset }); saveAs(blob, fileName); return true; } else {//IE9- var saveTxtWindow = window.frames.saveTxtWindow; if (!saveTxtWindow) { saveTxtWindow = document.createElement('iframe'); saveTxtWindow.id = 'saveTxtWindow'; saveTxtWindow.style.display = 'none'; document.body.insertBefore(saveTxtWindow, null); saveTxtWindow = window.frames.saveTxtWindow; if (!saveTxtWindow) { saveTxtWindow = window.open('', '_temp', 'width=100,height=100'); if (!saveTxtWindow) { window.alert('Sorry, download file could not be created.'); return false; } } } var doc = saveTxtWindow.document; doc.open('text/html', 'replace'); doc.charset = charset; if (fileName.endsWithAny('.htm', '.html')) { doc.close(); doc.body.innerHTML = '\r\n' + textContent + '\r\n'; } else { if (!fileName.endsWithAny('.txt')) fileName += '.txt'; doc.write(textContent); doc.close(); } var retValue = doc.execCommand('SaveAs', null, fileName); saveTxtWindow.close(); return retValue; } }) ================================================ FILE: clients/thirdparty/resemble.js ================================================ // NOTE: require("canvas-prebuilt") was commented because it makes webpack throw annoying errors, since my code is running in a browser, not nodejs. /* James Cryer / Huddle URL: https://github.com/Huddle/Resemble.js */ (function(root, factory) { "use strict"; if (typeof define === "function" && define.amd) { define([], factory); } else if (typeof module === "object" && module.exports) { module.exports = factory(); } else { root.resemble = factory(); } })(this, function() { "use strict"; var Img; var Canvas; if (typeof Image !== "undefined") { Img = Image; } else { // Canvas = require("canvas-prebuilt"); // eslint-disable-line global-require Img = Canvas.Image; } var document = typeof window !== "undefined" ? window.document : { createElement: function() { // This will work as long as only createElement is used on window.document return new Canvas(); } }; var oldGlobalSettings = {}; var globalOutputSettings = oldGlobalSettings; function setGlobalOutputSettings(settings) { var msg = "warning resemble.outputSettings mutates global state, and " + "will be removed in 3.0.0"; console.warn(msg); globalOutputSettings = settings; return this; } var resemble = function(fileData) { var pixelTransparency = 1; var errorPixelColor = { // Color for Error Pixels. Between 0 and 255. red: 255, green: 0, blue: 255, alpha: 255 }; var targetPix = {r: 0, g: 0, b: 0, a: 0}; // isAntialiased function colorsDistance(c1, c2) { return ( (Math.abs(c1.r - c2.r) + Math.abs(c1.g - c2.g) + Math.abs(c1.b - c2.b)) / 3 ); } function withinBoundingBox(x, y, width, height, box) { return ( x > (box.left || 0) && x < (box.right || width) && y > (box.top || 0) && y < (box.bottom || height) ); } function withinComparedArea(x, y, width, height) { var isIncluded = true; if ( boundingBox !== undefined && !withinBoundingBox(x, y, width, height, boundingBox) ) { isIncluded = false; } if ( ignoredBox !== undefined && withinBoundingBox(x, y, width, height, ignoredBox) ) { isIncluded = false; } return isIncluded; } var errorPixelTransform = { flat: function(px, offset) { px[offset] = errorPixelColor.red; px[offset + 1] = errorPixelColor.green; px[offset + 2] = errorPixelColor.blue; px[offset + 3] = errorPixelColor.alpha; }, movement: function(px, offset, d1, d2) { px[offset] = (d2.r * (errorPixelColor.red / 255) + errorPixelColor.red) / 2; px[offset + 1] = (d2.g * (errorPixelColor.green / 255) + errorPixelColor.green) / 2; px[offset + 2] = (d2.b * (errorPixelColor.blue / 255) + errorPixelColor.blue) / 2; px[offset + 3] = d2.a; }, flatDifferenceIntensity: function(px, offset, d1, d2) { px[offset] = errorPixelColor.red; px[offset + 1] = errorPixelColor.green; px[offset + 2] = errorPixelColor.blue; px[offset + 3] = colorsDistance(d1, d2); }, movementDifferenceIntensity: function(px, offset, d1, d2) { var ratio = colorsDistance(d1, d2) / 255 * 0.8; px[offset] = (1 - ratio) * (d2.r * (errorPixelColor.red / 255)) + ratio * errorPixelColor.red; px[offset + 1] = (1 - ratio) * (d2.g * (errorPixelColor.green / 255)) + ratio * errorPixelColor.green; px[offset + 2] = (1 - ratio) * (d2.b * (errorPixelColor.blue / 255)) + ratio * errorPixelColor.blue; px[offset + 3] = d2.a; }, diffOnly: function(px, offset, d1, d2) { px[offset] = d2.r; px[offset + 1] = d2.g; px[offset + 2] = d2.b; px[offset + 3] = d2.a; } }; var errorPixel = errorPixelTransform.flat; var errorType; var boundingBox; var ignoredBox; var largeImageThreshold = 1200; var useCrossOrigin = true; var data = {}; var images = []; var updateCallbackArray = []; var tolerance = { // between 0 and 255 red: 16, green: 16, blue: 16, alpha: 16, minBrightness: 16, maxBrightness: 240 }; var ignoreAntialiasing = false; var ignoreColors = false; var scaleToSameSize = false; function triggerDataUpdate() { var len = updateCallbackArray.length; var i; for (i = 0; i < len; i++) { if (typeof updateCallbackArray[i] === "function") { updateCallbackArray[i](data); } } } function loop(w, h, callback) { var x; var y; for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { callback(x, y); } } } function parseImage(sourceImageData, width, height) { var pixelCount = 0; var redTotal = 0; var greenTotal = 0; var blueTotal = 0; var alphaTotal = 0; var brightnessTotal = 0; var whiteTotal = 0; var blackTotal = 0; loop(width, height, function(horizontalPos, verticalPos) { var offset = (verticalPos * width + horizontalPos) * 4; var red = sourceImageData[offset]; var green = sourceImageData[offset + 1]; var blue = sourceImageData[offset + 2]; var alpha = sourceImageData[offset + 3]; var brightness = getBrightness(red, green, blue); if (red === green && red === blue && alpha) { if (red === 0) { blackTotal++; } else if (red === 255) { whiteTotal++; } } pixelCount++; redTotal += red / 255 * 100; greenTotal += green / 255 * 100; blueTotal += blue / 255 * 100; alphaTotal += (255 - alpha) / 255 * 100; brightnessTotal += brightness / 255 * 100; }); data.red = Math.floor(redTotal / pixelCount); data.green = Math.floor(greenTotal / pixelCount); data.blue = Math.floor(blueTotal / pixelCount); data.alpha = Math.floor(alphaTotal / pixelCount); data.brightness = Math.floor(brightnessTotal / pixelCount); data.white = Math.floor(whiteTotal / pixelCount * 100); data.black = Math.floor(blackTotal / pixelCount * 100); triggerDataUpdate(); } function loadImageData(fileDataForImage, callback) { var fileReader; var hiddenImage = new Img(); if (!hiddenImage.setAttribute) { hiddenImage.setAttribute = function setAttribute() {}; } if (useCrossOrigin) { hiddenImage.setAttribute("crossorigin", "anonymous"); } hiddenImage.onerror = function(err) { hiddenImage.onload = null; hiddenImage.onerror = null; // fixes pollution between calls images.push({error: err ? err + "" : "Image load error."}); callback(); }; hiddenImage.onload = function() { hiddenImage.onload = null; // fixes pollution between calls hiddenImage.onerror = null; var hiddenCanvas = document.createElement("canvas"); var imageData; // don't assign to hiddenImage, see https://github.com/Huddle/Resemble.js/pull/87/commits/300d43352a2845aad289b254bfbdc7cd6a37e2d7 var width = hiddenImage.width; var height = hiddenImage.height; if (scaleToSameSize && images.length === 1) { width = images[0].width; height = images[0].height; } hiddenCanvas.width = width; hiddenCanvas.height = height; hiddenCanvas .getContext("2d") .drawImage(hiddenImage, 0, 0, width, height); imageData = hiddenCanvas .getContext("2d") .getImageData(0, 0, width, height); images.push(imageData); callback(imageData, width, height); }; if (typeof fileDataForImage === "string") { hiddenImage.src = fileDataForImage; if (hiddenImage.complete && hiddenImage.naturalWidth > 0) { hiddenImage.onload(); } } else if ( typeof fileDataForImage.data !== "undefined" && typeof fileDataForImage.width === "number" && typeof fileDataForImage.height === "number" ) { images.push(fileDataForImage); callback( fileDataForImage, fileDataForImage.width, fileDataForImage.height ); } else if ( typeof Buffer !== "undefined" && fileDataForImage instanceof Buffer ) { // If we have Buffer, assume we're on Node+Canvas and its supported hiddenImage.src = fileDataForImage; } else { fileReader = new FileReader(); fileReader.onload = function(event) { hiddenImage.src = event.target.result; }; fileReader.readAsDataURL(fileDataForImage); } } function isColorSimilar(a, b, color) { var absDiff = Math.abs(a - b); if (typeof a === "undefined") { return false; } if (typeof b === "undefined") { return false; } if (a === b) { return true; } else if (absDiff < tolerance[color]) { return true; } return false; } function isPixelBrightnessSimilar(d1, d2) { var alpha = isColorSimilar(d1.a, d2.a, "alpha"); var brightness = isColorSimilar( d1.brightness, d2.brightness, "minBrightness" ); return brightness && alpha; } function getBrightness(r, g, b) { return 0.3 * r + 0.59 * g + 0.11 * b; } function isRGBSame(d1, d2) { var red = d1.r === d2.r; var green = d1.g === d2.g; var blue = d1.b === d2.b; return red && green && blue; } function isRGBSimilar(d1, d2) { var red = isColorSimilar(d1.r, d2.r, "red"); var green = isColorSimilar(d1.g, d2.g, "green"); var blue = isColorSimilar(d1.b, d2.b, "blue"); var alpha = isColorSimilar(d1.a, d2.a, "alpha"); return red && green && blue && alpha; } function isContrasting(d1, d2) { return ( Math.abs(d1.brightness - d2.brightness) > tolerance.maxBrightness ); } function getHue(red, green, blue) { var r = red / 255; var g = green / 255; var b = blue / 255; var max = Math.max(r, g, b); var min = Math.min(r, g, b); var h; var d; if (max === min) { h = 0; // achromatic } else { d = max - min; switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; default: h /= 6; } } return h; } function isAntialiased( sourcePix, pix, cacheSet, verticalPos, horizontalPos, width ) { var offset; var distance = 1; var i; var j; var hasHighContrastSibling = 0; var hasSiblingWithDifferentHue = 0; var hasEquivalentSibling = 0; addHueInfo(sourcePix); for (i = distance * -1; i <= distance; i++) { for (j = distance * -1; j <= distance; j++) { if (i === 0 && j === 0) { // ignore source pixel } else { offset = ((verticalPos + j) * width + (horizontalPos + i)) * 4; if (!getPixelInfo(targetPix, pix, offset, cacheSet)) { continue; } addBrightnessInfo(targetPix); addHueInfo(targetPix); if (isContrasting(sourcePix, targetPix)) { hasHighContrastSibling++; } if (isRGBSame(sourcePix, targetPix)) { hasEquivalentSibling++; } if (Math.abs(targetPix.h - sourcePix.h) > 0.3) { hasSiblingWithDifferentHue++; } if ( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1 ) { return true; } } } } if (hasEquivalentSibling < 2) { return true; } return false; } function copyPixel(px, offset, pix) { if (errorType === "diffOnly") { return; } px[offset] = pix.r; // r px[offset + 1] = pix.g; // g px[offset + 2] = pix.b; // b px[offset + 3] = pix.a * pixelTransparency; // a } function copyGrayScalePixel(px, offset, pix) { if (errorType === "diffOnly") { return; } px[offset] = pix.brightness; // r px[offset + 1] = pix.brightness; // g px[offset + 2] = pix.brightness; // b px[offset + 3] = pix.a * pixelTransparency; // a } function getPixelInfo(dst, pix, offset) { if (pix.length > offset) { dst.r = pix[offset]; dst.g = pix[offset + 1]; dst.b = pix[offset + 2]; dst.a = pix[offset + 3]; return true; } return false; } function addBrightnessInfo(pix) { pix.brightness = getBrightness(pix.r, pix.g, pix.b); // 'corrected' lightness } function addHueInfo(pix) { pix.h = getHue(pix.r, pix.g, pix.b); } function analyseImages(img1, img2, width, height) { var hiddenCanvas = document.createElement("canvas"); var data1 = img1.data; var data2 = img2.data; hiddenCanvas.width = width; hiddenCanvas.height = height; var context = hiddenCanvas.getContext("2d"); var imgd = context.createImageData(width, height); var pix = imgd.data; var mismatchCount = 0; var diffBounds = { top: height, left: width, bottom: 0, right: 0 }; var updateBounds = function(x, y) { diffBounds.left = Math.min(x, diffBounds.left); diffBounds.right = Math.max(x, diffBounds.right); diffBounds.top = Math.min(y, diffBounds.top); diffBounds.bottom = Math.max(y, diffBounds.bottom); }; var time = Date.now(); var skip; if ( !!largeImageThreshold && ignoreAntialiasing && (width > largeImageThreshold || height > largeImageThreshold) ) { skip = 6; } var pixel1 = {r: 0, g: 0, b: 0, a: 0}; var pixel2 = {r: 0, g: 0, b: 0, a: 0}; loop(width, height, function(horizontalPos, verticalPos) { if (skip) { // only skip if the image isn't small if ( verticalPos % skip === 0 || horizontalPos % skip === 0 ) { return; } } var offset = (verticalPos * width + horizontalPos) * 4; var isWithinComparedArea = withinComparedArea( horizontalPos, verticalPos, width, height ); if ( !getPixelInfo(pixel1, data1, offset, 1) || !getPixelInfo(pixel2, data2, offset, 2) ) { return; } if (ignoreColors) { addBrightnessInfo(pixel1); addBrightnessInfo(pixel2); if ( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea ) { copyGrayScalePixel(pix, offset, pixel2); } else { errorPixel(pix, offset, pixel1, pixel2); mismatchCount++; updateBounds(horizontalPos, verticalPos); } return; } if (isRGBSimilar(pixel1, pixel2) || !isWithinComparedArea) { copyPixel(pix, offset, pixel1); } else if ( ignoreAntialiasing && (addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry. addBrightnessInfo(pixel2), isAntialiased( pixel1, data1, 1, verticalPos, horizontalPos, width ) || isAntialiased( pixel2, data2, 2, verticalPos, horizontalPos, width )) ) { if ( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea ) { copyGrayScalePixel(pix, offset, pixel2); } else { errorPixel(pix, offset, pixel1, pixel2); mismatchCount++; updateBounds(horizontalPos, verticalPos); } } else { errorPixel(pix, offset, pixel1, pixel2); mismatchCount++; updateBounds(horizontalPos, verticalPos); } }); data.rawMisMatchPercentage = mismatchCount / (height * width) * 100; data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2); data.diffBounds = diffBounds; data.analysisTime = Date.now() - time; data.getImageDataUrl = function(text) { var barHeight = 0; if (text) { barHeight = addLabel(text, context, hiddenCanvas); } context.putImageData(imgd, 0, barHeight); return hiddenCanvas.toDataURL("image/png"); }; if (hiddenCanvas.toBuffer) { data.getBuffer = function(includeOriginal) { if (includeOriginal) { var imageWidth = hiddenCanvas.width + 2; hiddenCanvas.width = imageWidth * 3; context.putImageData(img1, 0, 0); context.putImageData(img2, imageWidth, 0); context.putImageData(imgd, imageWidth * 2, 0); } else { context.putImageData(imgd, 0, 0); } return hiddenCanvas.toBuffer(); }; } } function addLabel(text, context, hiddenCanvas) { var textPadding = 2; context.font = "12px sans-serif"; var textWidth = context.measureText(text).width + textPadding * 2; var barHeight = 22; if (textWidth > hiddenCanvas.width) { hiddenCanvas.width = textWidth; } hiddenCanvas.height += barHeight; context.fillStyle = "#666"; context.fillRect(0, 0, hiddenCanvas.width, barHeight - 4); context.fillStyle = "#fff"; context.fillRect(0, barHeight - 4, hiddenCanvas.width, 4); context.fillStyle = "#fff"; context.textBaseline = "top"; context.font = "12px sans-serif"; context.fillText(text, textPadding, 1); return barHeight; } function normalise(img, w, h) { var c; var context; if (img.height < h || img.width < w) { c = document.createElement("canvas"); c.width = w; c.height = h; context = c.getContext("2d"); context.putImageData(img, 0, 0); return context.getImageData(0, 0, w, h); } return img; } function outputSettings(options) { var key; if (options.errorColor) { for (key in options.errorColor) { if (options.errorColor.hasOwnProperty(key)) { errorPixelColor[key] = options.errorColor[key] === void 0 ? errorPixelColor[key] : options.errorColor[key]; } } } if (options.errorType && errorPixelTransform[options.errorType]) { errorPixel = errorPixelTransform[options.errorType]; errorType = options.errorType; } if ( options.errorPixel && typeof options.errorPixel === "function" ) { errorPixel = options.errorPixel; } pixelTransparency = isNaN(Number(options.transparency)) ? pixelTransparency : options.transparency; if (options.largeImageThreshold !== undefined) { largeImageThreshold = options.largeImageThreshold; } if (options.useCrossOrigin !== undefined) { useCrossOrigin = options.useCrossOrigin; } if (options.boundingBox !== undefined) { boundingBox = options.boundingBox; } if (options.ignoredBox !== undefined) { ignoredBox = options.ignoredBox; } } function compare(one, two) { if (globalOutputSettings !== oldGlobalSettings) { outputSettings(globalOutputSettings); } function onceWeHaveBoth() { var width; var height; if (images.length === 2) { if (images[0].error || images[1].error) { data = {}; data.error = images[0].error ? images[0].error : images[1].error; triggerDataUpdate(); return; } width = images[0].width > images[1].width ? images[0].width : images[1].width; height = images[0].height > images[1].height ? images[0].height : images[1].height; if ( images[0].width === images[1].width && images[0].height === images[1].height ) { data.isSameDimensions = true; } else { data.isSameDimensions = false; } data.dimensionDifference = { width: images[0].width - images[1].width, height: images[0].height - images[1].height }; analyseImages( normalise(images[0], width, height), normalise(images[1], width, height), width, height ); triggerDataUpdate(); } } images = []; loadImageData(one, onceWeHaveBoth); loadImageData(two, onceWeHaveBoth); } function getCompareApi(param) { var secondFileData; var hasMethod = typeof param === "function"; if (!hasMethod) { // assume it's file data secondFileData = param; } var self = { scaleToSameSize: function() { scaleToSameSize = true; if (hasMethod) { param(); } return self; }, useOriginalSize: function() { scaleToSameSize = false; if (hasMethod) { param(); } return self; }, ignoreNothing: function() { tolerance.red = 0; tolerance.green = 0; tolerance.blue = 0; tolerance.alpha = 0; tolerance.minBrightness = 0; tolerance.maxBrightness = 255; ignoreAntialiasing = false; ignoreColors = false; if (hasMethod) { param(); } return self; }, ignoreLess: function() { tolerance.red = 16; tolerance.green = 16; tolerance.blue = 16; tolerance.alpha = 16; tolerance.minBrightness = 16; tolerance.maxBrightness = 240; ignoreAntialiasing = false; ignoreColors = false; if (hasMethod) { param(); } return self; }, ignoreAntialiasing: function() { tolerance.red = 32; tolerance.green = 32; tolerance.blue = 32; tolerance.alpha = 32; tolerance.minBrightness = 64; tolerance.maxBrightness = 96; ignoreAntialiasing = true; ignoreColors = false; if (hasMethod) { param(); } return self; }, ignoreColors: function() { tolerance.alpha = 16; tolerance.minBrightness = 16; tolerance.maxBrightness = 240; ignoreAntialiasing = false; ignoreColors = true; if (hasMethod) { param(); } return self; }, ignoreAlpha: function() { tolerance.red = 16; tolerance.green = 16; tolerance.blue = 16; tolerance.alpha = 255; tolerance.minBrightness = 16; tolerance.maxBrightness = 240; ignoreAntialiasing = false; ignoreColors = false; if (hasMethod) { param(); } return self; }, repaint: function() { if (hasMethod) { param(); } return self; }, outputSettings: function(options) { outputSettings(options); return self; }, onComplete: function(callback) { updateCallbackArray.push(callback); var wrapper = function() { compare(fileData, secondFileData); }; wrapper(); return getCompareApi(wrapper); } }; return self; } var rootSelf = { onComplete: function(callback) { updateCallbackArray.push(callback); loadImageData(fileData, function(imageData, width, height) { parseImage(imageData.data, width, height); }); }, compareTo: function(secondFileData) { return getCompareApi(secondFileData); }, outputSettings: function(options) { outputSettings(options); return rootSelf; } }; return rootSelf; }; function applyIgnore(api, ignore) { switch (ignore) { case "nothing": api.ignoreNothing(); break; case "less": api.ignoreLess(); break; case "antialiasing": api.ignoreAntialiasing(); break; case "colors": api.ignoreColors(); break; case "alpha": api.ignoreAlpha(); break; default: throw new Error("Invalid ignore: " + ignore); } } resemble.compare = function(image1, image2, options, cb) { var callback; var opt; if (typeof options === "function") { callback = options; opt = {}; } else { callback = cb; opt = options || {}; } var res = resemble(image1); var compare; if (opt.output) { res.outputSettings(opt.output); } compare = res.compareTo(image2); if (opt.scaleToSameSize) { compare.scaleToSameSize(); } if (typeof opt.ignore === "string") { applyIgnore(compare, opt.ignore); } else if (opt.ignore && opt.ignore.forEach) { opt.ignore.forEach(function(v) { applyIgnore(compare, v); }); } compare.onComplete(function(data) { if (data.error) { callback(data.error); } else { callback(null, data); } }); }; resemble.outputSettings = setGlobalOutputSettings; return resemble; }); ================================================ FILE: clients/weu/README.md ================================================ This client is used to recover old maps that were created in 3rd party World Editor applications, such as World Editor Unlimited (hence WEU). These 3rd party editors add custom GUI events, conditions, and actions, which cannot be read by the vanila editor, and cause it to crash. Since such 3rd party editors are more or less dead nowadays, it means maps made with them are no longer editable. The weu utility code is used to look for and convert such things back to vanila, when possible, using multiple different tricks. Incidently, it can also mostly convert maps made with the Chinese YDWE editor back to something vanila can read (most likely some manual user actions needed, based on the maps). When given a campaign, this conversion will run for every map in it. NOTE: for technical reasons, this only works for TFT maps, aka W3X files. ================================================ FILE: clients/weu/TriggerDataCustom.txt ================================================ [TriggerParams] UnitStateMaxLifeSec=0,unitstate,UNIT_STATE_MAX_LIFE,WESTRING_USTATE_MAXLIFE SaveLoadOp0=0,integer,0,"0" SaveLoadOp1=0,integer,1,"1" SaveLoadOp2=0,integer,2,"2" SaveLoadOp3=0,integer,3,"3" SaveLoadOp4=0,integer,4,"4" SaveLoadOp5=0,integer,5,"5" SaveLoadOp6=0,integer,6,"6" [TriggerEvents] [TriggerConditions] [TriggerActions] ; WchnHidePlayerUnit=0 ; WchnSetUnitName=0,unit,string ; WchnUnitAddBang=0,unit ; WchnUnitRemoveBang=0,unit ; WchnUnitAddDes=0,unit,boolean ; WchnUnitRemoveDes=0,unit ; WchnPauseAllUnit=0 ; WchnResumeAllUnit=0 ; WchnAddQuestItem=0,AnyType,AnyType,AnyType ; WchnFindQuest=0,AnyType ; WchnUpdtQuest=0,AnyType ; WchnNewQuestReq=0,AnyType,string,AnyType ; WchnCpltQuest=0,AnyType ; WchnCpltQuestReq=0,AnyType,AnyType ; WchnDirectMov=0,camerasetup ; WchnStartMov=0,camerasetup ; WchnEndMov=0,camerasetup ; WchnPanCmr=0,camerasetup,real,boolean ; WchnChangeCmr=0,camerasetup ; WchnEndMovCmrBack=0 ; WchnWait=0,real ; WchnF2U=0,unit,unit,boolean ; WchnGoToF2U=0,unit,region,unit ; WchnGoTo=0,unit,region,boolean ; WchnDlg=0,unit,string,string ; WchnClearDlg=0 ; WchnDlgAT=0,unit,string,string ; WchnHint=0,string ; WchnEnableSkip=0 ; WchnDisableSkip=0 ; WchnWarn=0,string ; WchnError=0,string ; WchnFadeIn=0,real ; WchnFadeOut=0,real [TriggerCalls] ; WchnNewQuest=0,1,AnyType,string,string,boolean,string ; "Map protection" =0,1,AnyType,AnyType =0,1,AnyType,AnyType =0,1,AnyType,AnyType =0,1,AnyType,AnyType =0,1,AnyType,AnyType ================================================ FILE: clients/weu/TriggerDataPTR129.txt ================================================ //*************************************************************************** [TriggerCategories] // Defines categories for organizing trigger functions // Key: Arbitrary category identifier // Value 0: Display text // Value 1: Icon image file // Value 2: Optional flag (defaults to 0) indicating to disable display of category name // TC_ARITHMETIC=WESTRING_TRIGCAT_ARITHMETIC,ReplaceableTextures\WorldEditUI\Actions-AI,1 TC_NOTHING=WESTRING_TRIGCAT_NOTHING,ReplaceableTextures\WorldEditUI\Actions-Nothing,1 TC_COMMENT=WESTRING_TRIGCAT_COMMENT,ReplaceableTextures\WorldEditUI\Actions-Comment,1 TC_CUSTOM=WESTRING_TRIGCAT_CUSTOM,ReplaceableTextures\WorldEditUI\Actions-Nothing,1 TC_CONDITION=WESTRING_TRIGCAT_CONDITION,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_WAIT=WESTRING_TRIGCAT_WAIT,ReplaceableTextures\WorldEditUI\Actions-Wait,1 TC_SETVARIABLE=WESTRING_TRIGCAT_SETVARIABLE,ReplaceableTextures\WorldEditUI\Actions-SetVariables,1 TC_SKIPACTIONS=WESTRING_TRIGCAT_SKIPACTIONS,ReplaceableTextures\WorldEditUI\Actions-Nothing,1 TC_LOGIC=WESTRING_TRIGCAT_LOGIC,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_FORLOOP=WESTRING_TRIGCAT_FORLOOP,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_LAST=WESTRING_TRIGCAT_LAST,ReplaceableTextures\WorldEditUI\Actions-SetVariables,1 TC_AI=WESTRING_TRIGCAT_AI,ReplaceableTextures\WorldEditUI\Actions-AI TC_ANIMATION=WESTRING_TRIGCAT_ANIMATION,ReplaceableTextures\WorldEditUI\Actions-Animation TC_CAMERA=WESTRING_TRIGCAT_CAMERA,ReplaceableTextures\WorldEditUI\Actions-Camera TC_CINEMATIC=WESTRING_TRIGCAT_CINEMATIC,ReplaceableTextures\WorldEditUI\Actions-Camera TC_CONVERSION=WESTRING_TRIGCAT_CONVERSION,ReplaceableTextures\WorldEditUI\Actions-AI TC_TIMER=WESTRING_TRIGCAT_TIMER,ReplaceableTextures\WorldEditUI\Events-Time TC_DESTRUCT=WESTRING_TRIGCAT_DESTRUCT,ReplaceableTextures\WorldEditUI\Actions-Destructibles TC_DIALOG=WESTRING_TRIGCAT_DIALOG,ReplaceableTextures\WorldEditUI\Actions-Dialog TC_ENVIRONMENT=WESTRING_TRIGCAT_ENVIRONMENT,ReplaceableTextures\WorldEditUI\Actions-Environment TC_EVENTRESPONSE=WESTRING_TRIGCAT_EVENTRESPONSE,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_TEXTTAG=WESTRING_TRIGCAT_TEXTTAG,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_GAME=WESTRING_TRIGCAT_GAME,ReplaceableTextures\WorldEditUI\Actions-Game TC_GAMECACHE=WESTRING_TRIGCAT_GAMECACHE,ReplaceableTextures\WorldEditUI\Actions-SetVariables TC_HASHTABLE=WESTRING_TRIGCAT_HASHTABLE,ReplaceableTextures\WorldEditUI\Actions-SetVariables TC_HERO=WESTRING_TRIGCAT_HERO,ReplaceableTextures\WorldEditUI\Actions-Hero TC_ITEM=WESTRING_TRIGCAT_ITEM,ReplaceableTextures\WorldEditUI\Actions-Item TC_IMAGE=WESTRING_TRIGCAT_IMAGE,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_LEADERBOARD=WESTRING_TRIGCAT_LEADERBOARD,ReplaceableTextures\WorldEditUI\Actions-Quest TC_LIGHTNING=WESTRING_TRIGCAT_LIGHTNING,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_MATH=WESTRING_TRIGCAT_MATH,ReplaceableTextures\WorldEditUI\Actions-Logical TC_MELEE=WESTRING_TRIGCAT_MELEE,ReplaceableTextures\WorldEditUI\Actions-Melee TC_MULTIBOARD=WESTRING_TRIGCAT_MULTIBOARD,ReplaceableTextures\WorldEditUI\Actions-Quest TC_NEUTRALBUILDING=WESTRING_TRIGCAT_NEUTRALBUILDING,ReplaceableTextures\WorldEditUI\Actions-Goldmine TC_PLAYER=WESTRING_TRIGCAT_PLAYER,ReplaceableTextures\WorldEditUI\Actions-Player TC_PLAYERGROUP=WESTRING_TRIGCAT_PLAYERGROUP,ReplaceableTextures\WorldEditUI\Actions-PlayerGroup TC_QUEST=WESTRING_TRIGCAT_QUEST,ReplaceableTextures\WorldEditUI\Actions-Quest TC_REGION=WESTRING_TRIGCAT_REGION,ReplaceableTextures\WorldEditUI\Actions-Region TC_UNITSEL=WESTRING_TRIGCAT_UNITSEL,ReplaceableTextures\WorldEditUI\Actions-UnitSelection TC_SOUND=WESTRING_TRIGCAT_SOUND,ReplaceableTextures\WorldEditUI\Actions-Sound TC_SPECIALEFFECT=WESTRING_TRIGCAT_SPECIALEFFECT,ReplaceableTextures\WorldEditUI\Actions-Animation TC_TIME=WESTRING_TRIGCAT_TIME,ReplaceableTextures\WorldEditUI\Events-Time TC_TRIGGER=WESTRING_TRIGCAT_TRIGGER,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_UNIT=WESTRING_TRIGCAT_UNIT,ReplaceableTextures\WorldEditUI\Actions-Unit TC_UNITGROUP=WESTRING_TRIGCAT_UNITGROUP,ReplaceableTextures\WorldEditUI\Actions-UnitGroup TC_UBERSPLAT=WESTRING_TRIGCAT_UBERSPLAT,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_VISIBILITY=WESTRING_TRIGCAT_VISIBILITY,ReplaceableTextures\WorldEditUI\Actions-Visibility //%%% DEBUG - Remove for retail //TC_OBSOLETE=WESTRING_TRIGCAT_OBSOLETE,ReplaceableTextures\WorldEditUI\Editor-TriggerFunction //TC_DEBUG=WESTRING_TRIGCAT_DEBUG,ReplaceableTextures\WorldEditUI\Editor-TriggerFunction // AI Editor only TC_AI_TOWN=WESTRING_TRIGCAT_AI_TOWN,none TC_AI_HERO=WESTRING_TRIGCAT_AI_HERO,none TC_AI_RESOURCES=WESTRING_TRIGCAT_AI_RESOURCES,none TC_AI_MISC=WESTRING_TRIGCAT_AI_MISC,none TC_AI_UNIT=WESTRING_TRIGCAT_AI_UNIT,none TC_AI_UPGRADE=WESTRING_TRIGCAT_AI_UPGRADE,none TC_AI_COMMAND=WESTRING_TRIGCAT_AI_COMMAND,none //*************************************************************************** [TriggerTypes] // Defines all trigger variable types to be used by the Script Editor // Key: type name // Value 0: first game version in which this type is valid // Value 1: flag (0 or 1) indicating if this type can be a global variable // Value 2: flag (0 or 1) indicating if this type can be used with comparison operators // Value 3: string to display in the editor // Value 4: base type, used only for custom types // Value 5: import type, for strings which represent files (optional) // Value 6: flag (0 or 1) indicating to treat this type as the base type in the editor // Trigger Variable Types // These are sorted so that they appear as such in the Variables dialog. abilcode=0,1,1,WESTRING_TRIGTYPE_abilcode,integer attacktype=1,1,1,WESTRING_TRIGTYPE_attacktype boolean=0,1,1,WESTRING_TRIGTYPE_boolean buffcode=1,1,1,WESTRING_TRIGTYPE_buffcode,integer camerasetup=0,1,0,WESTRING_TRIGTYPE_camerasetup weapontype=1,1,1,WESTRING_TRIGTYPE_weapontype damagetype=1,1,1,WESTRING_TRIGTYPE_damagetype destructable=0,1,1,WESTRING_TRIGTYPE_destructable destructablecode=0,1,1,WESTRING_TRIGTYPE_destructablecode,integer defeatcondition=0,1,0,WESTRING_TRIGTYPE_defeatcondition dialog=0,1,0,WESTRING_TRIGTYPE_dialog button=0,1,0,WESTRING_TRIGTYPE_button effecttype=1,1,1,WESTRING_TRIGTYPE_effecttype texttag=1,1,0,WESTRING_TRIGTYPE_texttag gamecache=0,1,0,WESTRING_TRIGTYPE_gamecache gamespeed=0,1,1,WESTRING_TRIGTYPE_gamespeed handle=0,1,0,WESTRING_TRIGTYPE_handle hashtable=0,1,0,WESTRING_TRIGTYPE_hashtable image=1,1,1,WESTRING_TRIGTYPE_image imagetype=1,1,1,WESTRING_TRIGTYPE_imagetype,integer integer=0,1,1,WESTRING_TRIGTYPE_integer item=0,1,1,WESTRING_TRIGTYPE_item itemtype=1,1,1,WESTRING_TRIGTYPE_itemtype itemcode=0,1,1,WESTRING_TRIGTYPE_itemcode,integer leaderboard=0,1,0,WESTRING_TRIGTYPE_leaderboard lightning=1,1,1,WESTRING_TRIGTYPE_lightning lightningtype=1,1,1,WESTRING_TRIGTYPE_lightningtype,string multiboard=1,1,0,WESTRING_TRIGTYPE_multiboard ordercode=0,1,1,WESTRING_TRIGTYPE_ordercode,integer player=0,1,1,WESTRING_TRIGTYPE_player playercolor=0,1,1,WESTRING_TRIGTYPE_playercolor force=0,1,0,WESTRING_TRIGTYPE_force location=0,1,1,WESTRING_TRIGTYPE_location pathingtype=1,1,1,WESTRING_TRIGTYPE_pathingtype quest=0,1,0,WESTRING_TRIGTYPE_quest questitem=0,1,0,WESTRING_TRIGTYPE_questitem race=0,1,1,WESTRING_TRIGTYPE_race real=0,1,1,WESTRING_TRIGTYPE_real rect=0,1,1,WESTRING_TRIGTYPE_rect sound=0,1,0,WESTRING_TRIGTYPE_sound soundtype=1,1,1,WESTRING_TRIGTYPE_soundtype effect=0,1,0,WESTRING_TRIGTYPE_effect string=0,1,1,WESTRING_TRIGTYPE_string techcode=0,1,1,WESTRING_TRIGTYPE_techcode,integer terraindeformation=1,1,0,WESTRING_TRIGTYPE_terraindeformation terrainshape=1,1,1,WESTRING_TRIGTYPE_terrainshape,integer terraintype=1,1,1,WESTRING_TRIGTYPE_terraintype,integer timer=0,1,0,WESTRING_TRIGTYPE_timer timerdialog=0,1,0,WESTRING_TRIGTYPE_timerdialog trigger=0,1,1,WESTRING_TRIGTYPE_trigger ubersplat=1,1,1,WESTRING_TRIGTYPE_ubersplat ubersplattype=1,1,1,WESTRING_TRIGTYPE_ubersplattype,string unit=0,1,1,WESTRING_TRIGTYPE_unit group=0,1,0,WESTRING_TRIGTYPE_group unitcode=0,1,1,WESTRING_TRIGTYPE_unitcode,integer fogmodifier=0,1,0,WESTRING_TRIGTYPE_fogmodifier weathereffect=0,1,0,WESTRING_TRIGTYPE_weathereffect // Trigger Non-Variable Types - Atomic (built-in to the language) code=0,0,0,WESTRING_TRIGTYPE_code // Trigger Non-Variable Types - Basic (from common.j) event=0,0,0,WESTRING_TRIGTYPE_event triggercondition=0,0,0,WESTRING_TRIGTYPE_triggercondition triggeraction=0,0,0,WESTRING_TRIGTYPE_triggeraction boolexpr=0,0,0,WESTRING_TRIGTYPE_boolexpr unittype=0,0,0,WESTRING_TRIGTYPE_unittype alliancetype=0,0,0,WESTRING_TRIGTYPE_alliancetype playerstate=0,0,0,WESTRING_TRIGTYPE_playerstate playerscore=1,0,0,WESTRING_TRIGTYPE_playerscore playergameresult=0,0,0,WESTRING_TRIGTYPE_playergameresult unitstate=0,0,0,WESTRING_TRIGTYPE_unitstate playerunitevent=0,0,0,WESTRING_TRIGTYPE_playerunitevent unitevent=0,0,0,WESTRING_TRIGTYPE_unitevent limitop=0,0,0,WESTRING_TRIGTYPE_limitop gamedifficulty=0,0,1,WESTRING_TRIGTYPE_gamedifficulty gameevent=1,0,0,WESTRING_TRIGTYPE_gameevent aidifficulty=0,0,1,WESTRING_TRIGTYPE_aidifficulty mapdensity=0,0,1,WESTRING_TRIGTYPE_mapdensity mapcontrol=0,0,1,WESTRING_TRIGTYPE_mapcontrol mapflag=0,0,0,WESTRING_TRIGTYPE_mapflag playerslotstate=0,0,1,WESTRING_TRIGTYPE_playerslotstate camerafield=0,0,0,WESTRING_TRIGTYPE_camerafield raritycontrol=0,0,0,WESTRING_TRIGTYPE_raritycontrol blendmode=0,0,0,WESTRING_TRIGTYPE_blendmode fogstate=0,0,0,WESTRING_TRIGTYPE_fogstate volumegroup=0,0,0,WESTRING_TRIGTYPE_volumegroup // Trigger Non-Variable Types - Utility, only used to simplify triggers keyeventtype=1,0,0,WESTRING_TRIGTYPE_keyeventtype,integer keyeventkey=1,0,0,WESTRING_TRIGTYPE_keyeventkey,integer mouseeventtype=1,0,0,WESTRING_TRIGTYPE_mouseeventtype,integer mousebuttontype=1,1,1,WESTRING_TRIGTYPE_mousebuttontype,integer colorchangeoption=0,0,0,WESTRING_TRIGTYPE_colorchangeoption,boolean playerchangecoloroption=0,0,0,WESTRING_TRIGTYPE_playerchangecoloroption,boolean chatmatchtype=0,0,0,WESTRING_TRIGTYPE_chatmatchtype,boolean unitfacingbone=0,0,0,WESTRING_TRIGTYPE_unitfacingbone,string includeoption=0,0,0,WESTRING_TRIGTYPE_inclusionoption,boolean cameraapplyoption=0,0,0,WESTRING_TRIGTYPE_cameraapplyoption,boolean cameraorientationoption=0,0,0,WESTRING_TRIGTYPE_cameraorientationoption,boolean invulnerableoption=0,0,0,WESTRING_TRIGTYPE_invulnerableoption,boolean availabilityoption=0,0,0,WESTRING_TRIGTYPE_availabilityoption,boolean showhideoption=0,0,0,WESTRING_TRIGTYPE_showhideoption,boolean minimizeoption=1,0,0,WESTRING_TRIGTYPE_minimizeoption,boolean skymodelstring=0,0,0,WESTRING_TRIGTYPE_skymodelstring,string,Model cinefiltertexture=0,0,0,WESTRING_TRIGTYPE_cinefiltertexture,string,Image pathingoption=0,0,0,WESTRING_TRIGTYPE_pathingoption,boolean pawnableoption=1,0,0,WESTRING_TRIGTYPE_pawnableoption,boolean dropnodropoption=0,0,0,WESTRING_TRIGTYPE_dropnodropoption,boolean droppableoption=0,0,0,WESTRING_TRIGTYPE_droppableoption,boolean beforeafteroption=0,0,0,WESTRING_TRIGTYPE_beforeafteroption,boolean onoffoption=0,0,0,WESTRING_TRIGTYPE_onoffoption,boolean enabledisableoption=0,0,0,WESTRING_TRIGTYPE_enabledisableoption,boolean enableddisabledoption=0,0,0,WESTRING_TRIGTYPE_enableddisabledoption,boolean rescuableoption=0,0,0,WESTRING_TRIGTYPE_rescuableoption,boolean allowdontoption=0,0,0,WESTRING_TRIGTYPE_allowdontoption,boolean fadedontoption=0,0,0,WESTRING_TRIGTYPE_fadedontoption,boolean unitorderutarg=0,0,0,WESTRING_TRIGTYPE_unitorderutarg,string unitorderptarg=0,0,0,WESTRING_TRIGTYPE_unitorderptarg,string unitorderdtarg=0,0,0,WESTRING_TRIGTYPE_unitorderdtarg,string unitorderitarg=1,0,0,WESTRING_TRIGTYPE_unitorderitarg,string unitordernotarg=0,0,0,WESTRING_TRIGTYPE_unitordernotarg,string heroskillcode=0,0,0,WESTRING_TRIGTYPE_heroskillcode,integer weathereffectcode=0,0,0,WESTRING_TRIGTYPE_weathereffectcode,integer alliancesetting=0,0,0,WESTRING_TRIGTYPE_alliancesetting,integer addsettooption=0,0,0,WESTRING_TRIGTYPE_addsettooption,integer modifymethod=1,0,0,WESTRING_TRIGTYPE_modifymethod,integer waitdontoption=0,0,0,WESTRING_TRIGTYPE_waitdontoption,boolean cratertype=1,0,0,WESTRING_TRIGTYPE_cratertype,boolean rippletype=1,0,0,WESTRING_TRIGTYPE_rippletype,boolean createremoveoption=0,0,0,WESTRING_TRIGTYPE_createremoveoption,boolean addremoveoption=0,0,0,WESTRING_TRIGTYPE_addremoveoption,boolean questtypeoption=0,0,0,WESTRING_TRIGTYPE_questtypeoption,integer questmessagetype=0,0,0,WESTRING_TRIGTYPE_questmessagetype,integer herostat=1,0,0,WESTRING_TRIGTYPE_herostat,integer completionoption=0,0,0,WESTRING_TRIGTYPE_completionoption,boolean failureoption=0,0,0,WESTRING_TRIGTYPE_failureoption,boolean discoveredoption=0,0,0,WESTRING_TRIGTYPE_discoveredoption,boolean pauseresumeoption=0,0,0,WESTRING_TRIGTYPE_pauseresumeoption,boolean periodicoption=0,0,0,WESTRING_TRIGTYPE_periodicoption,boolean leaderboardsortoption=0,0,0,WESTRING_TRIGTYPE_leaderboardsortoption,integer ascendingoption=0,0,0,WESTRING_TRIGTYPE_ascendingoption,boolean sleepwakeoption=0,0,0,WESTRING_TRIGTYPE_sleepwakeoption,boolean pauseunpauseoption=0,0,0,WESTRING_TRIGTYPE_pauseunpauseoption,boolean sharedontoption=0,0,0,WESTRING_TRIGTYPE_sharedontoption,boolean fadetypeoption=0,0,0,WESTRING_TRIGTYPE_fadetypeoption,boolean bufftype=0,0,0,WESTRING_TRIGTYPE_bufftype,integer buffpolarity=1,0,0,WESTRING_TRIGTYPE_buffpolarity,integer buffresist=1,0,0,WESTRING_TRIGTYPE_buffresist,integer cameraboundsadjusttype=0,0,0,WESTRING_TRIGTYPE_cameraboundsadjusttype,integer availableoption=0,0,0,WESTRING_TRIGTYPE_availableoption,boolean explodedontoption=0,0,0,WESTRING_TRIGTYPE_explodedontoption,boolean suspendresumeoption=0,0,0,WESTRING_TRIGTYPE_suspendresumeoption,boolean missionindex=0,0,0,WESTRING_TRIGTYPE_missionindex,integer campaignindex=0,0,0,WESTRING_TRIGTYPE_campaignindex,integer cinematicindex=0,0,0,WESTRING_TRIGTYPE_cinematicindex,integer musictheme=0,0,0,WESTRING_TRIGTYPE_musictheme,string,Sound ambientthemeday=0,0,0,WESTRING_TRIGTYPE_ambientthemeday,string ambientthemenight=0,0,0,WESTRING_TRIGTYPE_ambientthemenight,string unitstatemethod=0,0,0,WESTRING_TRIGTYPE_unitstatemethod,string checkingignoringoption=0,0,0,WESTRING_TRIGTYPE_checkingignoringoption,string playerflag=0,0,0,WESTRING_TRIGTYPE_playerflag,playerstate playerresource=1,0,0,WESTRING_TRIGTYPE_playerresource,playerstate gateoperation=0,0,0,WESTRING_TRIGTYPE_gateoperation,integer elevatorwallop=1,0,0,WESTRING_TRIGTYPE_elevatorwallop,boolean elevatorwalltype=1,0,0,WESTRING_TRIGTYPE_elevatorwalltype,integer useskipoption=0,0,0,WESTRING_TRIGTYPE_useskipoption,boolean seldeseloption=0,0,0,WESTRING_TRIGTYPE_seldeseloption,boolean cachevaluetype=1,0,0,WESTRING_TRIGTYPE_cachevaluetype,integer hashtablevaluetype=1,0,0,WESTRING_TRIGTYPE_hashtablevaluetype,integer fogstyle=0,0,0,WESTRING_TRIGTYPE_fogstyle,integer timedlifebuffcode=1,0,0,WESTRING_TRIGTYPE_timedlifebuffcode,integer aicaptaintype=1,0,0,WESTRING_TRIGTYPE_aicaptaintype,boolean aicommandpop=1,0,0,WESTRING_TRIGTYPE_aicommandpop,boolean scriptcode=1,0,0,WESTRING_TRIGTYPE_scriptcode,string itemstatus=1,0,0,WESTRING_TRIGTYPE_itemstatus,integer itemcodestatus=1,0,0,WESTRING_TRIGTYPE_itemcodestatus,integer minimappingstyle=1,0,0,WESTRING_TRIGTYPE_minimappingstyle,integer corpsetype=1,0,0,WESTRING_TRIGTYPE_corpsetype,integer stringcaseoption=1,0,0,WESTRING_TRIGTYPE_stringcaseoption,boolean // Trigger Non-Variable Types - File strings aiscript=0,0,0,WESTRING_TRIGTYPE_aiscript,string,AIScript,1 modelfile=0,0,0,WESTRING_TRIGTYPE_modelfile,string,Model,1 anyfile=0,0,0,WESTRING_TRIGTYPE_anyfile,string,Any,1 preloadfile=0,0,0,WESTRING_TRIGTYPE_preloadfile,string,Preload,1 imagefile=0,0,0,WESTRING_TRIGTYPE_imagefile,string,Image,1 // Trigger Non-Variable Types - Custom (handled internally by the editor) StringExt=0,0,0,WESTRING_TRIGTYPE_StringExt,string AnyGlobal=0,0,0,WESTRING_TRIGTYPE_AnyGlobal AnyType=0,0,0,WESTRING_TRIGTYPE_AnyType VarAsString_Real=0,0,0,WESTRING_TRIGTYPE_VarAsString_Real ArithmeticOperator=0,0,0,WESTRING_TRIGTYPE_ArithmeticOperator ComparisonOperator=0,0,0,WESTRING_TRIGTYPE_ComparisonOperator EqualNotEqualOperator=0,0,0,WESTRING_TRIGTYPE_EqualNotEqualOperator boolcall=0,0,0,WESTRING_TRIGTYPE_boolcall eventcall=1,0,0,WESTRING_TRIGTYPE_eventcall doodadcode=0,0,0,WESTRING_TRIGTYPE_doodadcode,integer musicfile=0,0,0,WESTRING_TRIGTYPE_musicfile,string integervar=1,0,0,WESTRING_TRIGTYPE_integer,integer //*************************************************************************** [TriggerTypeDefaults] // Defines an optional default value for a trigger type used as a global variable // Key: variable type // Value 0: script text // Value 1: display text (if not present, script text will be used) // // If a type does not have an entry here, it will be set to null if it is a handle // boolean=false,WESTRING_FALSE integer=0 real=0 group=CreateGroup(),WESTRING_TRIGDEFAULT_GROUP force=CreateForce(),WESTRING_TRIGDEFAULT_FORCE timer=CreateTimer(),WESTRING_TRIGDEFAULT_TIMER dialog=DialogCreate(),WESTRING_TRIGDEFAULT_DIALOG //*************************************************************************** [TriggerParams] // Defines possible values for variable types // Key: arbitrary text // Value 0: first game version in which this parameter is valid // Value 1: variable type // Value 2: code text (used in script) // Value 3: display text // // Note: If the code text is a literal string, surround it with backward single quotes (`), // and they will be converted to double quotes in the script. // // Operators OperatorAdd=0,ArithmeticOperator,"+",WESTRING_ARITHMETICOPERATOR_ADD OperatorSubtract=0,ArithmeticOperator,"-",WESTRING_ARITHMETICOPERATOR_SUBTRACT OperatorMultiply=0,ArithmeticOperator,"*",WESTRING_ARITHMETICOPERATOR_MULTIPLY OperatorDivide=0,ArithmeticOperator,"/",WESTRING_ARITHMETICOPERATOR_DIVIDE OperatorEqual=0,ComparisonOperator,"==",WESTRING_COMPARISONOPERATOR_EQUAL OperatorNotEqual=0,ComparisonOperator,"!=",WESTRING_COMPARISONOPERATOR_NOTEQUAL OperatorGreater=0,ComparisonOperator,">",WESTRING_COMPARISONOPERATOR_GREATER OperatorGreaterEq=0,ComparisonOperator,">=",WESTRING_COMPARISONOPERATOR_GREATEREQ OperatorLess=0,ComparisonOperator,"<",WESTRING_COMPARISONOPERATOR_LESS OperatorLessEq=0,ComparisonOperator,"<=",WESTRING_COMPARISONOPERATOR_LESSEQ OperatorEqualENE=0,EqualNotEqualOperator,"==",WESTRING_EQUALNOTEQUALOPERATOR_EQUAL OperatorNotEqualENE=0,EqualNotEqualOperator,"!=",WESTRING_EQUALNOTEQUALOPERATOR_NOTEQUAL // Reals RealQueueDelayQuest=0,real,bj_QUEUE_DELAY_QUEST,WESTRING_QUEUE_DELAY_QUEST RealQueueDelayHint=0,real,bj_QUEUE_DELAY_HINT,WESTRING_QUEUE_DELAY_HINT RealQueueDelaySecret=0,real,bj_QUEUE_DELAY_SECRET,WESTRING_QUEUE_DELAY_SECRET RealHandicapEasy=0,real,bj_HANDICAP_EASY,WESTRING_HANDICAP_EASY RealCellWidth=0,real,bj_CELLWIDTH,WESTRING_REAL_CELLWIDTH RealUnitFacing=0,real,bj_UNIT_FACING,WESTRING_REAL_UNITFACING RealCamDefDistance=0,real,bj_CAMERA_DEFAULT_DISTANCE,WESTRING_CAMDEFAULT_DISTANCE RealCamDefFarZ=0,real,bj_CAMERA_DEFAULT_FARZ,WESTRING_CAMDEFAULT_FARZ RealCamDefAoA=0,real,bj_CAMERA_DEFAULT_AOA,WESTRING_CAMDEFAULT_AOA RealCamDefFoV=0,real,bj_CAMERA_DEFAULT_FOV,WESTRING_CAMDEFAULT_FOV RealCamDefRoll=0,real,bj_CAMERA_DEFAULT_ROLL,WESTRING_CAMDEFAULT_ROLL RealCamDefRotation=0,real,bj_CAMERA_DEFAULT_ROTATION,WESTRING_CAMDEFAULT_ROTATION RealE=0,real,bj_E,WESTRING_REAL_E RealPi=0,real,bj_PI,WESTRING_REAL_PI // Players Player00=0,player,Player(0),WESTRING_PLAYER_00 Player01=0,player,Player(1),WESTRING_PLAYER_01 Player02=0,player,Player(2),WESTRING_PLAYER_02 Player03=0,player,Player(3),WESTRING_PLAYER_03 Player04=0,player,Player(4),WESTRING_PLAYER_04 Player05=0,player,Player(5),WESTRING_PLAYER_05 Player06=0,player,Player(6),WESTRING_PLAYER_06 Player07=0,player,Player(7),WESTRING_PLAYER_07 Player08=0,player,Player(8),WESTRING_PLAYER_08 Player09=0,player,Player(9),WESTRING_PLAYER_09 Player10=0,player,Player(10),WESTRING_PLAYER_10 Player11=0,player,Player(11),WESTRING_PLAYER_11 Player12=0,player,Player(12),WESTRING_PLAYER_12 Player13=0,player,Player(13),WESTRING_PLAYER_13 Player14=0,player,Player(14),WESTRING_PLAYER_14 Player15=0,player,Player(15),WESTRING_PLAYER_15 Player16=0,player,Player(16),WESTRING_PLAYER_16 Player17=0,player,Player(17),WESTRING_PLAYER_17 Player18=0,player,Player(18),WESTRING_PLAYER_18 Player19=0,player,Player(19),WESTRING_PLAYER_19 Player20=0,player,Player(20),WESTRING_PLAYER_20 Player21=0,player,Player(21),WESTRING_PLAYER_21 Player22=0,player,Player(22),WESTRING_PLAYER_22 Player23=0,player,Player(23),WESTRING_PLAYER_23 PlayerNA=0,player,Player(PLAYER_NEUTRAL_AGGRESSIVE),WESTRING_PLAYER_NA PlayerNV=0,player,Player(bj_PLAYER_NEUTRAL_VICTIM),WESTRING_PLAYER_NV PlayerNE=0,player,Player(bj_PLAYER_NEUTRAL_EXTRA),WESTRING_PLAYER_NE PlayerNP=0,player,Player(PLAYER_NEUTRAL_PASSIVE),WESTRING_PLAYER_NP // Forces Force00=0,force,bj_FORCE_PLAYER[0],WESTRING_FORCE_00 Force01=0,force,bj_FORCE_PLAYER[1],WESTRING_FORCE_01 Force02=0,force,bj_FORCE_PLAYER[2],WESTRING_FORCE_02 Force03=0,force,bj_FORCE_PLAYER[3],WESTRING_FORCE_03 Force04=0,force,bj_FORCE_PLAYER[4],WESTRING_FORCE_04 Force05=0,force,bj_FORCE_PLAYER[5],WESTRING_FORCE_05 Force06=0,force,bj_FORCE_PLAYER[6],WESTRING_FORCE_06 Force07=0,force,bj_FORCE_PLAYER[7],WESTRING_FORCE_07 Force08=0,force,bj_FORCE_PLAYER[8],WESTRING_FORCE_08 Force09=0,force,bj_FORCE_PLAYER[9],WESTRING_FORCE_09 Force10=0,force,bj_FORCE_PLAYER[10],WESTRING_FORCE_10 Force11=0,force,bj_FORCE_PLAYER[11],WESTRING_FORCE_11 Force12=0,force,bj_FORCE_PLAYER[12],WESTRING_FORCE_12 Force13=0,force,bj_FORCE_PLAYER[13],WESTRING_FORCE_13 Force14=0,force,bj_FORCE_PLAYER[14],WESTRING_FORCE_14 Force15=0,force,bj_FORCE_PLAYER[15],WESTRING_FORCE_15 Force16=0,force,bj_FORCE_PLAYER[16],WESTRING_FORCE_16 Force17=0,force,bj_FORCE_PLAYER[17],WESTRING_FORCE_17 Force18=0,force,bj_FORCE_PLAYER[18],WESTRING_FORCE_18 Force19=0,force,bj_FORCE_PLAYER[19],WESTRING_FORCE_19 Force20=0,force,bj_FORCE_PLAYER[20],WESTRING_FORCE_20 Force21=0,force,bj_FORCE_PLAYER[21],WESTRING_FORCE_21 Force22=0,force,bj_FORCE_PLAYER[22],WESTRING_FORCE_22 Force23=0,force,bj_FORCE_PLAYER[23],WESTRING_FORCE_23 ForceNA=0,force,bj_FORCE_PLAYER[PLAYER_NEUTRAL_AGGRESSIVE],WESTRING_FORCE_NA ForceNV=0,force,bj_FORCE_PLAYER[bj_PLAYER_NEUTRAL_VICTIM],WESTRING_FORCE_NV ForceNE=0,force,bj_FORCE_PLAYER[bj_PLAYER_NEUTRAL_EXTRA],WESTRING_FORCE_NE ForceNP=0,force,bj_FORCE_PLAYER[PLAYER_NEUTRAL_PASSIVE],WESTRING_FORCE_NP // Player colors Color00=0,playercolor,PLAYER_COLOR_RED,WESTRING_UNITCOLOR_00 Color01=0,playercolor,PLAYER_COLOR_BLUE,WESTRING_UNITCOLOR_01 Color02=0,playercolor,PLAYER_COLOR_CYAN,WESTRING_UNITCOLOR_02 Color03=0,playercolor,PLAYER_COLOR_PURPLE,WESTRING_UNITCOLOR_03 Color04=0,playercolor,PLAYER_COLOR_YELLOW,WESTRING_UNITCOLOR_04 Color05=0,playercolor,PLAYER_COLOR_ORANGE,WESTRING_UNITCOLOR_05 Color06=0,playercolor,PLAYER_COLOR_GREEN,WESTRING_UNITCOLOR_06 Color07=0,playercolor,PLAYER_COLOR_PINK,WESTRING_UNITCOLOR_07 Color08=0,playercolor,PLAYER_COLOR_LIGHT_GRAY,WESTRING_UNITCOLOR_08 Color09=0,playercolor,PLAYER_COLOR_LIGHT_BLUE,WESTRING_UNITCOLOR_09 Color10=0,playercolor,PLAYER_COLOR_AQUA,WESTRING_UNITCOLOR_10 Color11=0,playercolor,PLAYER_COLOR_BROWN,WESTRING_UNITCOLOR_11 Color12=1,playercolor,ConvertPlayerColor(12),WESTRING_UNITCOLOR_12 // Races RaceHuman=0,race,RACE_HUMAN,WESTRING_TRIGRACE_HUMAN RaceOrc=0,race,RACE_ORC,WESTRING_TRIGRACE_ORC RaceUndead=0,race,RACE_UNDEAD,WESTRING_TRIGRACE_UNDEAD RaceNightElf=0,race,RACE_NIGHTELF,WESTRING_TRIGRACE_NIGHTELF RaceDemon=0,race,RACE_DEMON,WESTRING_TRIGRACE_DEMON // Item Classes ItemTypeAny=1,itemtype,ITEM_TYPE_ANY,WESTRING_ITEMTYPE_ANY ItemTypePermanent=1,itemtype,ITEM_TYPE_PERMANENT,WESTRING_ITEMTYPE_PERMANENT ItemTypeCharged=1,itemtype,ITEM_TYPE_CHARGED,WESTRING_ITEMTYPE_CHARGED ItemTypePowerup=1,itemtype,ITEM_TYPE_POWERUP,WESTRING_ITEMTYPE_POWERUP ItemTypeArtifact=1,itemtype,ITEM_TYPE_ARTIFACT,WESTRING_ITEMTYPE_ARTIFACT ItemTypePurchasable=1,itemtype,ITEM_TYPE_PURCHASABLE,WESTRING_ITEMTYPE_PURCHASABLE ItemTypeCampaign=1,itemtype,ITEM_TYPE_CAMPAIGN,WESTRING_ITEMTYPE_CAMPAIGN ItemTypeMiscellaneous=1,itemtype,ITEM_TYPE_MISCELLANEOUS,WESTRING_ITEMTYPE_MISCELLANEOUS ItemTypeUnknown=1,itemtype,ITEM_TYPE_UNKNOWN,WESTRING_ITEMTYPE_UNKNOWN // Units UnitNull=0,unit,null,WESTRING_TRIGUNIT_NULL // Unit-Types UnitTypeNull=0,unitcode,0,WESTRING_TRIGUNITTYPE_NULL // Items ItemNull=0,item,null,WESTRING_TRIGITEM_NULL // Destructables DestructableNull=0,destructable,null,WESTRING_TRIGDESTRUCTABLE_NULL // Rects RectNull=0,rect,null,WESTRING_TRIGRECT_NULL // Sounds SoundNull=0,sound,null,WESTRING_TRIGSOUND_NULL // Music MusicFileMusic=0,musicfile,`music`,WESTRING_TRIGMUSICFILE_MUSIC // Limit operators LimitOpEqual=0,limitop,EQUAL,WESTRING_LIMITOP_EQUAL LimitOpNotEqual=0,limitop,NOT_EQUAL,WESTRING_LIMITOP_NOTEQUAL LimitOpLessThan=0,limitop,LESS_THAN,WESTRING_LIMITOP_LESSTHAN LimitOpLessThanOrEqual=0,limitop,LESS_THAN_OR_EQUAL,WESTRING_LIMITOP_LESSTHANOREQUAL LimitOpGreaterThan=0,limitop,GREATER_THAN,WESTRING_LIMITOP_GREATERTHAN LimitOpGreaterThanOrEqual=0,limitop,GREATER_THAN_OR_EQUAL,WESTRING_LIMITOP_GREATERTHANOREQUAL // Game results GameResultWin=0,playergameresult,PLAYER_GAME_RESULT_VICTORY,WESTRING_VICTORY GameResultLose=0,playergameresult,PLAYER_GAME_RESULT_DEFEAT,WESTRING_DEFEAT GameResultDraw=0,playergameresult,PLAYER_GAME_RESULT_TIE,WESTRING_DRAW // Map flags MapFlagUseHandicaps=0,mapflag,MAP_USE_HANDICAPS,WESTRING_MAPFLAG_USEHANDICAPS MapFlagObservers=0,mapflag,MAP_OBSERVERS,WESTRING_MAPFLAG_OBSERVERS MapFlagObserversChat=0,mapflag,MAP_OBSERVERS_ON_DEATH,WESTRING_MAPFLAG_OBSERVERSONDEATH MapFlagResourceTradingLock=0,mapflag,MAP_LOCK_RESOURCE_TRADING,WESTRING_MAPFLAG_RESOURCETRADINGLOCK MapFlagResourceTradingAllies=0,mapflag,MAP_RESOURCE_TRADING_ALLIES_ONLY,WESTRING_MAPFLAG_RESOURCETRADINGALLIES MapFlagAllianceChangesLock=0,mapflag,MAP_LOCK_ALLIANCE_CHANGES,WESTRING_MAPFLAG_ALLIANCECHANGESLOCK MapFlagAllianceChangesHidden=0,mapflag,MAP_ALLIANCE_CHANGES_HIDDEN,WESTRING_MAPFLAG_ALLIANCECHANGESHIDDEN MapFlagMapReloaded=1,mapflag,MAP_RELOADED,WESTRING_MAPFLAG_MAPRELOADED MapFlagRandomHeroes=1,mapflag,MAP_RANDOM_HERO,WESTRING_MAPFLAG_RANDOM_HERO MapFlagRandomRaces=1,mapflag,MAP_RANDOM_RACES,WESTRING_MAPFLAG_RANDOM_RACES MapFlagFogHideTerrain=1,mapflag,MAP_FOG_HIDE_TERRAIN,WESTRING_MAPFLAG_FOG_HIDE_TERRAIN MapFlagFogMapExplored=1,mapflag,MAP_FOG_MAP_EXPLORED,WESTRING_MAPFLAG_FOG_MAP_EXPLORED MapFlagFogAlwaysVisible=1,mapflag,MAP_FOG_ALWAYS_VISIBLE,WESTRING_MAPFLAG_FOG_ALWAYS_VISIBLE // Player states PlayerStateGold=0,playerstate,PLAYER_STATE_RESOURCE_GOLD,WESTRING_PSTATE_GOLD PlayerStateLumber=0,playerstate,PLAYER_STATE_RESOURCE_LUMBER,WESTRING_PSTATE_LUMBER PlayerStateHeroTokens=0,playerstate,PLAYER_STATE_RESOURCE_HERO_TOKENS,WESTRING_PSTATE_HEROTOKENS PlayerStateGoldUpkeepRate=0,playerstate,PLAYER_STATE_GOLD_UPKEEP_RATE,WESTRING_PSTATE_UPKEEPGOLD PlayerStateLumberUpkeepRate=0,playerstate,PLAYER_STATE_LUMBER_UPKEEP_RATE,WESTRING_PSTATE_UPKEEPLUMBER PlayerStateGoldGathered=0,playerstate,PLAYER_STATE_GOLD_GATHERED,WESTRING_PSTATE_GOLDGATHERED PlayerStateLumberGathered=0,playerstate,PLAYER_STATE_LUMBER_GATHERED,WESTRING_PSTATE_LUMBER_GATHERED PlayerStateFoodUsed=0,playerstate,PLAYER_STATE_RESOURCE_FOOD_USED,WESTRING_PSTATE_FOODUSED PlayerStateFoodCap=0,playerstate,PLAYER_STATE_RESOURCE_FOOD_CAP,WESTRING_PSTATE_FOODCAP PlayerStateFoodLimit=0,playerstate,PLAYER_STATE_FOOD_CAP_CEILING,WESTRING_PSTATE_FOODCAPLIMIT PlayerStateGameResult=0,playerstate,PLAYER_STATE_GAME_RESULT,WESTRING_PSTATE_GAMERESULT // Player states - resources only PlayerResourceGold=1,playerresource,PLAYER_STATE_RESOURCE_GOLD,WESTRING_PRESOURCE_GOLD PlayerResourceLumber=1,playerresource,PLAYER_STATE_RESOURCE_LUMBER,WESTRING_PRESOURCE_LUMBER // Player scores PlayerScoreUnitsTrained=1,playerscore,PLAYER_SCORE_UNITS_TRAINED,WESTRING_PSCORE_UNITSTRAINED PlayerScoreUnitsKilled=1,playerscore,PLAYER_SCORE_UNITS_KILLED,WESTRING_PSCORE_UNITSKILLED PlayerScoreStructBuilt=1,playerscore,PLAYER_SCORE_STRUCT_BUILT,WESTRING_PSCORE_STRUCTBUILT PlayerScoreStructRazed=1,playerscore,PLAYER_SCORE_STRUCT_RAZED,WESTRING_PSCORE_STRUCTRAZED PlayerScoreTechPercent=1,playerscore,PLAYER_SCORE_TECH_PERCENT,WESTRING_PSCORE_TECHPERCENT PlayerScoreFoodProd=1,playerscore,PLAYER_SCORE_FOOD_MAXPROD,WESTRING_PSCORE_FOODPROD PlayerScoreFoodUsed=1,playerscore,PLAYER_SCORE_FOOD_MAXUSED,WESTRING_PSCORE_FOODUSED PlayerScoreHeroesKilled=1,playerscore,PLAYER_SCORE_HEROES_KILLED,WESTRING_PSCORE_HEROESKILLED PlayerScoreItemsGained=1,playerscore,PLAYER_SCORE_ITEMS_GAINED,WESTRING_PSCORE_ITEMSGAINED PlayerScoreMercsHired=1,playerscore,PLAYER_SCORE_MERCS_HIRED,WESTRING_PSCORE_MERCSHIRED PlayerScoreGoldTotal=1,playerscore,PLAYER_SCORE_GOLD_MINED_TOTAL,WESTRING_PSCORE_GOLDTOTAL PlayerScoreGoldUpkeep=1,playerscore,PLAYER_SCORE_GOLD_MINED_UPKEEP,WESTRING_PSCORE_GOLDUPKEEP PlayerScoreGoldLostUpkeep=1,playerscore,PLAYER_SCORE_GOLD_LOST_UPKEEP,WESTRING_PSCORE_GOLDLOSTUPKEEP PlayerScoreGoldLostTax=1,playerscore,PLAYER_SCORE_GOLD_LOST_TAX,WESTRING_PSCORE_GOLDLOSTTAX PlayerScoreGoldGiven=1,playerscore,PLAYER_SCORE_GOLD_GIVEN,WESTRING_PSCORE_GOLDGIVEN PlayerScoreGoldReceived=1,playerscore,PLAYER_SCORE_GOLD_RECEIVED,WESTRING_PSCORE_GOLDRECEIVED PlayerScoreLumberTotal=1,playerscore,PLAYER_SCORE_LUMBER_TOTAL,WESTRING_PSCORE_LUMBERTOTAL PlayerScoreLumberLostUpkeep=1,playerscore,PLAYER_SCORE_LUMBER_LOST_UPKEEP,WESTRING_PSCORE_LUMBERLOSTUPKEEP PlayerScoreLumberLostTax=1,playerscore,PLAYER_SCORE_LUMBER_LOST_TAX,WESTRING_PSCORE_LUMBERLOSTTAX PlayerScoreLumberGiven=1,playerscore,PLAYER_SCORE_LUMBER_GIVEN,WESTRING_PSCORE_LUMBERGIVEN PlayerScoreLumberReceived=1,playerscore,PLAYER_SCORE_LUMBER_RECEIVED,WESTRING_PSCORE_LUMBERECEIVED PlayerScoreUnitTotal=1,playerscore,PLAYER_SCORE_UNIT_TOTAL,WESTRING_PSCORE_UNITTOTAL PlayerScoreHeroTotal=1,playerscore,PLAYER_SCORE_HERO_TOTAL,WESTRING_PSCORE_HEROTOTAL PlayerScoreResourceTotal=1,playerscore,PLAYER_SCORE_RESOURCE_TOTAL,WESTRING_PSCORE_RESOURCETOTAL PlayerScoreTotal=1,playerscore,PLAYER_SCORE_TOTAL,WESTRING_PSCORE_TOTAL // Player flags PlayerFlagUnfollowable=0,playerflag,PLAYER_STATE_UNFOLLOWABLE,WESTRING_PFLAG_UNFOLLOWABLE PlayerFlagGivesBounty=0,playerflag,PLAYER_STATE_GIVES_BOUNTY,WESTRING_PFLAG_GIVESBOUNTY PlayerFlagAlliedVictory=0,playerflag,PLAYER_STATE_ALLIED_VICTORY,WESTRING_PFLAG_ALLIEDVICTORY // Gate states GateOperationClosed=0,gateoperation,bj_GATEOPERATION_CLOSE,WESTRING_GATEOPERATION_CLOSE GateOperationOpen=0,gateoperation,bj_GATEOPERATION_OPEN,WESTRING_GATEOPERATION_OPEN GateOperationDestroyed=0,gateoperation,bj_GATEOPERATION_DESTROY,WESTRING_GATEOPERATION_DESTROY // Elevator wall operations ElevatorWallOpClose=1,elevatorwallop,false,WESTRING_ELEVATORWALLOP_CLOSE ElevatorWallOpOpen=1,elevatorwallop,true,WESTRING_ELEVATORWALLOP_OPEN // Elevator wall choices ElevatorWallTypeAll=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_ALL,WESTRING_ELEVATORWALLTYPE_ALL ElevatorWallTypeEast=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_EAST,WESTRING_ELEVATORWALLTYPE_EAST ElevatorWallTypeNorth=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_NORTH,WESTRING_ELEVATORWALLTYPE_NORTH ElevatorWallTypeSouth=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_SOUTH,WESTRING_ELEVATORWALLTYPE_SOUTH ElevatorWallTypeWest=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_WEST,WESTRING_ELEVATORWALLTYPE_WEST // Usage options UseSkipOptionUse=0,useskipoption,true,WESTRING_USESKIPOPTION_USE UseSkipOptionSkip=0,useskipoption,false,WESTRING_USESKIPOPTION_SKIP // Selection option SelDeselOptionSel=0,seldeseloption,true,WESTRING_SELDESELOPTION_SEL SelDeselOptionDesel=0,seldeseloption,false,WESTRING_SELDESELOPTION_DESEL // AI Captain types AICaptainAttack=1,aicaptaintype,true,WESTRING_AICAPTAIN_ATTACK AICaptainDefense=1,aicaptaintype,false,WESTRING_AICAPTAIN_DEFENSE // AI Command Pop options AICommandPop=1,aicommandpop,true,WESTRING_AICOMMAND_REMOVE AICommandLeave=1,aicommandpop,false,WESTRING_AICOMMAND_LEAVE // Cache value types CacheValueTypeBoolean=1,cachevaluetype,bj_GAMECACHE_BOOLEAN,WESTRING_CACHEVALUETYPE_BOOLEAN CacheValueTypeInteger=1,cachevaluetype,bj_GAMECACHE_INTEGER,WESTRING_CACHEVALUETYPE_INTEGER CacheValueTypeReal=1,cachevaluetype,bj_GAMECACHE_REAL,WESTRING_CACHEVALUETYPE_REAL CacheValueTypeUnit=1,cachevaluetype,bj_GAMECACHE_UNIT,WESTRING_CACHEVALUETYPE_UNIT CacheValueTypeString=1,cachevaluetype,bj_GAMECACHE_STRING,WESTRING_CACHEVALUETYPE_STRING // Hashtable value types (localization stolen from gamecache) HashtableValueTypeBoolean=1,hashtablevaluetype,bj_HASHTABLE_BOOLEAN,WESTRING_CACHEVALUETYPE_BOOLEAN HashtableValueTypeInteger=1,hashtablevaluetype,bj_HASHTABLE_INTEGER,WESTRING_CACHEVALUETYPE_INTEGER HashtableValueTypeReal=1,hashtablevaluetype,bj_HASHTABLE_REAL,WESTRING_CACHEVALUETYPE_REAL HashtableValueTypeString=1,hashtablevaluetype,bj_HASHTABLE_STRING,WESTRING_CACHEVALUETYPE_STRING HashtableValueTypeHandle=1,hashtablevaluetype,bj_HASHTABLE_HANDLE,WESTRING_CACHEVALUETYPE_HANDLE // Map Control MapControlNone=0,mapcontrol,MAP_CONTROL_NONE,WESTRING_MAPCONTROL_NONE MapControlUser=0,mapcontrol,MAP_CONTROL_USER,WESTRING_MAPCONTROL_USER MapControlComputer=0,mapcontrol,MAP_CONTROL_COMPUTER,WESTRING_MAPCONTROL_COMPUTER MapControlRescuable=0,mapcontrol,MAP_CONTROL_RESCUABLE,WESTRING_MAPCONTROL_RESCUABLE MapControlNeutral=0,mapcontrol,MAP_CONTROL_NEUTRAL,WESTRING_MAPCONTROL_NEUTRAL MapControlCreep=0,mapcontrol,MAP_CONTROL_CREEP,WESTRING_MAPCONTROL_CREEP // Player slot states PlayerSlotStateEmpty=0,playerslotstate,PLAYER_SLOT_STATE_EMPTY,WESTRING_PSLOT_EMPTY PlayerSlotStatePlaying=0,playerslotstate,PLAYER_SLOT_STATE_PLAYING,WESTRING_PSLOT_PLAYING PlayerSlotStateLeft=0,playerslotstate,PLAYER_SLOT_STATE_LEFT,WESTRING_PSLOT_LEFT // Player unit events PlayerUnitEventDeath=0,playerunitevent,EVENT_PLAYER_UNIT_DEATH,WESTRING_PUEVENT_DEATH PlayerUnitEventDecay=0,playerunitevent,EVENT_PLAYER_UNIT_DECAY,WESTRING_PUEVENT_DECAY PlayerUnitEventChangesOwner=1,playerunitevent,EVENT_PLAYER_UNIT_CHANGE_OWNER,WESTRING_PUEVENT_CHANGESOWNER PlayerUnitEventHero_Level=0,playerunitevent,EVENT_PLAYER_HERO_LEVEL,WESTRING_PUEVENT_HEROLEVEL PlayerUnitEventHero_Skill=0,playerunitevent,EVENT_PLAYER_HERO_SKILL,WESTRING_PUEVENT_HEROSKILL PlayerUnitEventHero_Revivable=0,playerunitevent,EVENT_PLAYER_HERO_REVIVABLE,WESTRING_PUEVENT_HEROREVIVABLE PlayerUnitEventHeroUseItem=0,playerunitevent,EVENT_PLAYER_UNIT_USE_ITEM,WESTRING_PUEVENT_HEROUSEITEM PlayerUnitEventHeroPickUpItem=0,playerunitevent,EVENT_PLAYER_UNIT_PICKUP_ITEM,WESTRING_PUEVENT_HEROPICKUPITEM PlayerUnitEventHeroDropItem=0,playerunitevent,EVENT_PLAYER_UNIT_DROP_ITEM,WESTRING_PUEVENT_HERODROPITEM PlayerUnitEventSell=1,playerunitevent,EVENT_PLAYER_UNIT_SELL,WESTRING_PUEVENT_SELL PlayerUnitEventSellItem=1,playerunitevent,EVENT_PLAYER_UNIT_SELL_ITEM,WESTRING_PUEVENT_SELLITEM PlayerUnitEventPawnItem=1,playerunitevent,EVENT_PLAYER_UNIT_PAWN_ITEM,WESTRING_PUEVENT_PAWNITEM PlayerUnitEventAttacked=0,playerunitevent,EVENT_PLAYER_UNIT_ATTACKED,WESTRING_PUEVENT_ATTACKED PlayerUnitEventRescued=0,playerunitevent,EVENT_PLAYER_UNIT_RESCUED,WESTRING_PUEVENT_RESCUED PlayerUnitEventSummoned=0,playerunitevent,EVENT_PLAYER_UNIT_SUMMON,WESTRING_PUEVENT_SUMMONED PlayerUnitEventSpellChannel=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_CHANNEL,WESTRING_PUEVENT_SPELLCHANNEL PlayerUnitEventSpellCast=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_CAST,WESTRING_PUEVENT_SPELLCAST PlayerUnitEventSpellEndCast=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_ENDCAST,WESTRING_PUEVENT_SPELLENDCAST PlayerUnitEventSpellEffect=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_EFFECT,WESTRING_PUEVENT_SPELLEFFECT PlayerUnitEventSpellFinish=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_FINISH,WESTRING_PUEVENT_SPELLFINISH PlayerUnitEventLoaded=0,playerunitevent,EVENT_PLAYER_UNIT_LOADED,WESTRING_PUEVENT_LOADED PlayerUnitEventTrain_Start=0,playerunitevent,EVENT_PLAYER_UNIT_TRAIN_START,WESTRING_PUEVENT_TRAINSTART PlayerUnitEventTrain_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_TRAIN_CANCEL,WESTRING_PUEVENT_TRAINCANCEL PlayerUnitEventTrain_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_TRAIN_FINISH,WESTRING_PUEVENT_TRAINFINISH PlayerUnitEventConstruct_Start=0,playerunitevent,EVENT_PLAYER_UNIT_CONSTRUCT_START,WESTRING_PUEVENT_CONSTRUCTSTART PlayerUnitEventConstruct_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL,WESTRING_PUEVENT_CONSTRUCTCANCEL PlayerUnitEventConstruct_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_CONSTRUCT_FINISH,WESTRING_PUEVENT_CONSTRUCTFINISH PlayerUnitEventReviveStart=0,playerunitevent,EVENT_PLAYER_HERO_REVIVE_START,WESTRING_PUEVENT_REVIVESTART PlayerUnitEventReviveCancel=0,playerunitevent,EVENT_PLAYER_HERO_REVIVE_CANCEL,WESTRING_PUEVENT_REVIVECANCEL PlayerUnitEventReviveFinish=0,playerunitevent,EVENT_PLAYER_HERO_REVIVE_FINISH,WESTRING_PUEVENT_REVIVEFINISH PlayerUnitEventUpgrade_Start=0,playerunitevent,EVENT_PLAYER_UNIT_UPGRADE_START,WESTRING_PUEVENT_UPGRADESTART PlayerUnitEventUpgrade_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_UPGRADE_CANCEL,WESTRING_PUEVENT_UPGRADECANCEL PlayerUnitEventUpgrade_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_UPGRADE_FINISH,WESTRING_PUEVENT_UPGRADEFINISH PlayerUnitEventResearch_Start=0,playerunitevent,EVENT_PLAYER_UNIT_RESEARCH_START,WESTRING_PUEVENT_RESEARCHSTART PlayerUnitEventResearch_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_RESEARCH_CANCEL,WESTRING_PUEVENT_RESEARCHCANCEL PlayerUnitEventResearch_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_RESEARCH_FINISH,WESTRING_PUEVENT_RESEARCHFINISH PlayerUnitEventIssued_Unit_Order=0,playerunitevent,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER,WESTRING_PUEVENT_ISSUEDUNITORDER PlayerUnitEventIssued_Point_Order=0,playerunitevent,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER,WESTRING_PUEVENT_ISSUEDPOINTORDER PlayerUnitEventIssued_Order=0,playerunitevent,EVENT_PLAYER_UNIT_ISSUED_ORDER,WESTRING_PUEVENT_ISSUEDORDER // Unit events UnitEventDeath=0,unitevent,EVENT_UNIT_DEATH,WESTRING_UEVENT_DEATH UnitEventDecay=0,unitevent,EVENT_UNIT_DECAY,WESTRING_UEVENT_DECAY UnitEventChangesOwner=1,unitevent,EVENT_UNIT_CHANGE_OWNER,WESTRING_UEVENT_CHANGESOWNER UnitEventDamaged=0,unitevent,EVENT_UNIT_DAMAGED,WESTRING_UEVENT_DAMAGED UnitEventHeroLevel=0,unitevent,EVENT_UNIT_HERO_LEVEL,WESTRING_UEVENT_HEROLEVEL UnitEventHeroSkill=0,unitevent,EVENT_UNIT_HERO_SKILL,WESTRING_UEVENT_HEROSKILL UnitEventHeroRevivable=0,unitevent,EVENT_UNIT_HERO_REVIVABLE,WESTRING_UEVENT_HEROREVIVABLE UnitEventHeroUseItem=0,unitevent,EVENT_UNIT_USE_ITEM,WESTRING_UEVENT_HEROUSEITEM UnitEventHeroPickUpItem=0,unitevent,EVENT_UNIT_PICKUP_ITEM,WESTRING_UEVENT_HEROPICKUPITEM UnitEventHeroDropItem=0,unitevent,EVENT_UNIT_DROP_ITEM,WESTRING_UEVENT_HERODROPITEM UnitEventSell=1,unitevent,EVENT_UNIT_SELL,WESTRING_UEVENT_SELL UnitEventSellItem=1,unitevent,EVENT_UNIT_SELL_ITEM,WESTRING_UEVENT_SELLITEM UnitEventPawnItem=1,unitevent,EVENT_UNIT_PAWN_ITEM,WESTRING_UEVENT_PAWNITEM UnitEventAttacked=0,unitevent,EVENT_UNIT_ATTACKED,WESTRING_UEVENT_ATTACKED UnitEventRescued=0,unitevent,EVENT_UNIT_RESCUED,WESTRING_UEVENT_RESCUED UnitEventSelected=0,unitevent,EVENT_UNIT_SELECTED,WESTRING_UEVENT_SELECTED UnitEventDeselected=0,unitevent,EVENT_UNIT_DESELECTED,WESTRING_UEVENT_DESELECTED UnitEventSpellChannel=1,unitevent,EVENT_UNIT_SPELL_CHANNEL,WESTRING_UEVENT_SPELLCHANNEL UnitEventSpellCast=1,unitevent,EVENT_UNIT_SPELL_CAST,WESTRING_UEVENT_SPELLCAST UnitEventSpellEndCast=1,unitevent,EVENT_UNIT_SPELL_ENDCAST,WESTRING_UEVENT_SPELLENDCAST UnitEventSpellEffect=1,unitevent,EVENT_UNIT_SPELL_EFFECT,WESTRING_UEVENT_SPELLEFFECT UnitEventSpellFinish=1,unitevent,EVENT_UNIT_SPELL_FINISH,WESTRING_UEVENT_SPELLFINISH UnitEventLoaded=0,unitevent,EVENT_UNIT_LOADED,WESTRING_UEVENT_LOADED UnitEventAcquiredTarget=0,unitevent,EVENT_UNIT_ACQUIRED_TARGET,WESTRING_UEVENT_ACQUIREDTARGET UnitEventTargetInRange=0,unitevent,EVENT_UNIT_TARGET_IN_RANGE,WESTRING_UEVENT_TARGETINRANGE UnitEventTrainStart=0,unitevent,EVENT_UNIT_TRAIN_START,WESTRING_UEVENT_TRAINSTART UnitEventTrainCancel=0,unitevent,EVENT_UNIT_TRAIN_CANCEL,WESTRING_UEVENT_TRAINCANCEL UnitEventTrainFinish=0,unitevent,EVENT_UNIT_TRAIN_FINISH,WESTRING_UEVENT_TRAINFINISH UnitEventReviveStart=0,unitevent,EVENT_UNIT_HERO_REVIVE_START,WESTRING_UEVENT_REVIVESTART UnitEventReviveCancel=0,unitevent,EVENT_UNIT_HERO_REVIVE_CANCEL,WESTRING_UEVENT_REVIVECANCEL UnitEventReviveFinish=0,unitevent,EVENT_UNIT_HERO_REVIVE_FINISH,WESTRING_UEVENT_REVIVEFINISH UnitEventUpgradeStart=0,unitevent,EVENT_UNIT_UPGRADE_START,WESTRING_UEVENT_UPGRADESTART UnitEventUpgradeCancel=0,unitevent,EVENT_UNIT_UPGRADE_CANCEL,WESTRING_UEVENT_UPGRADECANCEL UnitEventUpgradeFinish=0,unitevent,EVENT_UNIT_UPGRADE_FINISH,WESTRING_UEVENT_UPGRADEFINISH UnitEventResearchStart=0,unitevent,EVENT_UNIT_RESEARCH_START,WESTRING_UEVENT_RESEARCHSTART UnitEventResearchCancel=0,unitevent,EVENT_UNIT_RESEARCH_CANCEL,WESTRING_UEVENT_RESEARCHCANCEL UnitEventResearchFinish=0,unitevent,EVENT_UNIT_RESEARCH_FINISH,WESTRING_UEVENT_RESEARCHFINISH UnitEventIssueUnitOrder=0,unitevent,EVENT_UNIT_ISSUED_TARGET_ORDER,WESTRING_UEVENT_ISSUEUNITORDER UnitEventIssuePointOrder=0,unitevent,EVENT_UNIT_ISSUED_POINT_ORDER,WESTRING_UEVENT_ISSUEPOINTORDER UnitEventIssueOrder=0,unitevent,EVENT_UNIT_ISSUED_ORDER,WESTRING_UEVENT_ISSUEORDER // Unit states (read-only) UnitStateLife=0,unitstate,UNIT_STATE_LIFE,WESTRING_USTATE_LIFE UnitStateMaxLife=0,unitstate,UNIT_STATE_MAX_LIFE,WESTRING_USTATE_MAXLIFE UnitStateMana=0,unitstate,UNIT_STATE_MANA,WESTRING_USTATE_MANA UnitStateMaxMana=0,unitstate,UNIT_STATE_MAX_MANA,WESTRING_USTATE_MAXMANA // Keyboard Event Types KeyEventTypeDepress=1,keyeventtype,bj_KEYEVENTTYPE_DEPRESS,WESTRING_KEYEVENTTYPE_DEPRESS KeyEventTypeRelease=1,keyeventtype,bj_KEYEVENTTYPE_RELEASE,WESTRING_KEYEVENTTYPE_RELEASE // Keyboard Event Keys KeyEventKeyLeft=1,keyeventkey,bj_KEYEVENTKEY_LEFT,WESTRING_KEYEVENTKEY_LEFT KeyEventKeyRight=1,keyeventkey,bj_KEYEVENTKEY_RIGHT,WESTRING_KEYEVENTKEY_RIGHT KeyEventKeyDown=1,keyeventkey,bj_KEYEVENTKEY_DOWN,WESTRING_KEYEVENTKEY_DOWN KeyEventKeyUp=1,keyeventkey,bj_KEYEVENTKEY_UP,WESTRING_KEYEVENTKEY_UP // Mouse Event Types MouseEventTypeDown=1,mouseeventtype,bj_MOUSEEVENTTYPE_DOWN,WESTRING_MOUSEEVENTTYPE_DOWN MouseEventTypeUp=1,mouseeventtype,bj_MOUSEEVENTTYPE_UP,WESTRING_MOUSEEVENTTYPE_UP MouseEventTypeMove=1,mouseeventtype,bj_MOUSEEVENTTYPE_MOVE,WESTRING_MOUSEEVENTTYPE_MOVE // Mouse Button Types MouseButtonTypeLeft=1,mousebuttontype,MOUSE_BUTTON_TYPE_LEFT,WESTRING_MOUSEBUTTONTYPE_LEFT MouseButtonTypeMiddle=1,mousebuttontype,MOUSE_BUTTON_TYPE_MIDDLE,WESTRING_MOUSEBUTTONTYPE_MIDDLE MouseButtonTypeRight=1,mousebuttontype,MOUSE_BUTTON_TYPE_RIGHT,WESTRING_MOUSEBUTTONTYPE_RIGHT // Unit types UnitTypeStructure=0,unittype,UNIT_TYPE_STRUCTURE,WESTRING_UNITTYPE_STRUCTURE UnitTypeHero=0,unittype,UNIT_TYPE_HERO,WESTRING_UNITTYPE_HERO UnitTypeGround=0,unittype,UNIT_TYPE_GROUND,WESTRING_UNITTYPE_GROUND UnitTypeFlying=0,unittype,UNIT_TYPE_FLYING,WESTRING_UNITTYPE_FLYING UnitTypeAttacksGround=0,unittype,UNIT_TYPE_ATTACKS_GROUND,WESTRING_UNITTYPE_ATTACKSGROUND UnitTypeAttacksFlying=0,unittype,UNIT_TYPE_ATTACKS_FLYING,WESTRING_UNITTYPE_ATTACKSFLYING UnitTypeMeleeAttacker=0,unittype,UNIT_TYPE_MELEE_ATTACKER,WESTRING_UNITTYPE_MELEEATTACKER UnitTypeRangedAttacker=0,unittype,UNIT_TYPE_RANGED_ATTACKER,WESTRING_UNITTYPE_RANGEDATTACKER UnitTypeSummoned=0,unittype,UNIT_TYPE_SUMMONED,WESTRING_UNITTYPE_SUMMONED UnitTypePlagued=0,unittype,UNIT_TYPE_PLAGUED,WESTRING_UNITTYPE_PLAGUED UnitTypeSnared=0,unittype,UNIT_TYPE_SNARED,WESTRING_UNITTYPE_SNARED UnitTypeStunned=0,unittype,UNIT_TYPE_STUNNED,WESTRING_UNITTYPE_STUNNED UnitTypeUndead=0,unittype,UNIT_TYPE_UNDEAD,WESTRING_UNITTYPE_UNDEAD UnitTypeMechanical=0,unittype,UNIT_TYPE_MECHANICAL,WESTRING_UNITTYPE_MECHANICAL UnitTypeAncient=0,unittype,UNIT_TYPE_ANCIENT,WESTRING_UNITTYPE_ANCIENT UnitTypePeon=0,unittype,UNIT_TYPE_PEON,WESTRING_UNITTYPE_PEON UnitTypeTownHall=0,unittype,UNIT_TYPE_TOWNHALL,WESTRING_UNITTYPE_TOWNHALL UnitTypeSapper=0,unittype,UNIT_TYPE_SAPPER,WESTRING_UNITTYPE_SAPPER UnitTypePoisoned=0,unittype,UNIT_TYPE_POISONED,WESTRING_UNITTYPE_POISONED UnitTypePolymorphed=0,unittype,UNIT_TYPE_POLYMORPHED,WESTRING_UNITTYPE_POLYMORPHED UnitTypeSleeping=0,unittype,UNIT_TYPE_SLEEPING,WESTRING_UNITTYPE_SLEEPING UnitTypeResistant=1,unittype,UNIT_TYPE_RESISTANT,WESTRING_UNITTYPE_RESISTANT UnitTypeEthereal=1,unittype,UNIT_TYPE_ETHEREAL,WESTRING_UNITTYPE_ETHEREAL UnitTypeMagicImmune=0,unittype,UNIT_TYPE_MAGIC_IMMUNE,WESTRING_UNITTYPE_MAGICIMMUNE // Game speeds GameSpeedSlowest=0,gamespeed,MAP_SPEED_SLOWEST,WESTRING_GAMESPEED_SLOWEST GameSpeedSlow=0,gamespeed,MAP_SPEED_SLOW,WESTRING_GAMESPEED_SLOW GameSpeedNormal=0,gamespeed,MAP_SPEED_NORMAL,WESTRING_GAMESPEED_NORMAL GameSpeedFast=0,gamespeed,MAP_SPEED_FAST,WESTRING_GAMESPEED_FAST GameSpeedFastest=0,gamespeed,MAP_SPEED_FASTEST,WESTRING_GAMESPEED_FASTEST // Game difficulties GameDifficultyEasy=0,gamedifficulty,MAP_DIFFICULTY_EASY,WESTRING_GAMEDIFFICULTY_EASY GameDifficultyNormal=0,gamedifficulty,MAP_DIFFICULTY_NORMAL,WESTRING_GAMEDIFFICULTY_NORMAL GameDifficultyHard=0,gamedifficulty,MAP_DIFFICULTY_HARD,WESTRING_GAMEDIFFICULTY_HARD // Melee AI difficulties AIDifficultyNewbie=0,aidifficulty,AI_DIFFICULTY_NEWBIE,WESTRING_AIDIFFICULTY_NEWBIE AIDifficultyNormal=0,aidifficulty,AI_DIFFICULTY_NORMAL,WESTRING_AIDIFFICULTY_NORMAL AIDifficultyInsane=0,aidifficulty,AI_DIFFICULTY_INSANE,WESTRING_AIDIFFICULTY_INSANE // Map densities MapDensityNone=0,mapdensity,MAP_DENSITY_NONE,WESTRING_MAPDENSITY_NONE MapDensityLight=0,mapdensity,MAP_DENSITY_LIGHT,WESTRING_MAPDENSITY_LIGHT MapDensityMedium=0,mapdensity,MAP_DENSITY_MEDIUM,WESTRING_MAPDENSITY_MEDIUM MapDensityHeavy=0,mapdensity,MAP_DENSITY_HEAVY,WESTRING_MAPDENSITY_HEAVY // Alliance settings AllianceSettingUnallied=0,alliancesetting,bj_ALLIANCE_UNALLIED,WESTRING_ALLIANCE_UNALLIED AllianceSettingUnalliedVision=0,alliancesetting,bj_ALLIANCE_UNALLIED_VISION,WESTRING_ALLIANCE_UNALLIEDVISION AllianceSettingNeutral=0,alliancesetting,bj_ALLIANCE_NEUTRAL,WESTRING_ALLIANCE_NEUTRAL AllianceSettingNeutralVision=1,alliancesetting,bj_ALLIANCE_NEUTRAL_VISION,WESTRING_ALLIANCE_NEUTRAL_VISION AllianceSettingAllied=0,alliancesetting,bj_ALLIANCE_ALLIED,WESTRING_ALLIANCE_ALLIED AllianceSettingAlliedVision=0,alliancesetting,bj_ALLIANCE_ALLIED_VISION,WESTRING_ALLIANCE_ALLIEDVISION AllianceSettingAlliedUnits=0,alliancesetting,bj_ALLIANCE_ALLIED_UNITS,WESTRING_ALLIANCE_ALLIEDUNITS AllianceSettingAlliedAdvUnits=0,alliancesetting,bj_ALLIANCE_ALLIED_ADVUNITS,WESTRING_ALLIANCE_ALLIEDADVUNITS // Alliance types AllianceTypePassive=0,alliancetype,ALLIANCE_PASSIVE,WESTRING_ALLIANCE_PASSIVE AllianceTypeSharedVision=0,alliancetype,ALLIANCE_SHARED_VISION,WESTRING_ALLIANCE_SHAREDVISION AllianceTypeSharedControl=0,alliancetype,ALLIANCE_SHARED_CONTROL,WESTRING_ALLIANCE_SHAREDCONTROL AllianceTypeSharedFullControl=0,alliancetype,ALLIANCE_SHARED_ADVANCED_CONTROL,WESTRING_ALLIANCE_SHAREDFULLCONTROL AllianceTypeXP=0,alliancetype,ALLIANCE_SHARED_XP,WESTRING_ALLIANCE_XP AllianceTypeSpells=0,alliancetype,ALLIANCE_SHARED_SPELLS,WESTRING_ALLIANCE_SPELLS AllianceTypeHelpRequest=0,alliancetype,ALLIANCE_HELP_REQUEST,WESTRING_ALLIANCE_HELPREQUEST AllianceTypeHelpResponse=0,alliancetype,ALLIANCE_HELP_RESPONSE,WESTRING_ALLIANCE_HELPRESPONSE // Attack types AttackTypeNormal=1,attacktype,ATTACK_TYPE_NORMAL,WESTRING_UE_ATTACKTYPE_SPELLS AttackTypeMelee=1,attacktype,ATTACK_TYPE_MELEE,WESTRING_UE_ATTACKTYPE_NORMAL AttackTypePierce=1,attacktype,ATTACK_TYPE_PIERCE,WESTRING_UE_ATTACKTYPE_PIERCE AttackTypeSiege=1,attacktype,ATTACK_TYPE_SIEGE,WESTRING_UE_ATTACKTYPE_SIEGE AttackTypeMagic=1,attacktype,ATTACK_TYPE_MAGIC,WESTRING_UE_ATTACKTYPE_MAGIC AttackTypeChaos=1,attacktype,ATTACK_TYPE_CHAOS,WESTRING_UE_ATTACKTYPE_CHAOS AttackTypeHero=1,attacktype,ATTACK_TYPE_HERO,WESTRING_UE_ATTACKTYPE_HERO // Damage types DamageTypeUnknown=1,damagetype,DAMAGE_TYPE_UNKNOWN,WESTRING_DAMAGE_TYPE_UNKNOWN DamageTypeNormal=1,damagetype,DAMAGE_TYPE_NORMAL,WESTRING_DAMAGE_TYPE_NORMAL DamageTypeEnhanced=1,damagetype,DAMAGE_TYPE_ENHANCED,WESTRING_DAMAGE_TYPE_ENHANCED DamageTypeFire=1,damagetype,DAMAGE_TYPE_FIRE,WESTRING_DAMAGE_TYPE_FIRE DamageTypeCold=1,damagetype,DAMAGE_TYPE_COLD,WESTRING_DAMAGE_TYPE_COLD DamageTypeLightning=1,damagetype,DAMAGE_TYPE_LIGHTNING,WESTRING_DAMAGE_TYPE_LIGHTNING DamageTypePoison=1,damagetype,DAMAGE_TYPE_POISON,WESTRING_DAMAGE_TYPE_POISON DamageTypeDisease=1,damagetype,DAMAGE_TYPE_DISEASE,WESTRING_DAMAGE_TYPE_DISEASE DamageTypeDivine=1,damagetype,DAMAGE_TYPE_DIVINE,WESTRING_DAMAGE_TYPE_DIVINE DamageTypeMagic=1,damagetype,DAMAGE_TYPE_MAGIC,WESTRING_DAMAGE_TYPE_MAGIC DamageTypeSonic=1,damagetype,DAMAGE_TYPE_SONIC,WESTRING_DAMAGE_TYPE_SONIC DamageTypeAcid=1,damagetype,DAMAGE_TYPE_ACID,WESTRING_DAMAGE_TYPE_ACID DamageTypeForce=1,damagetype,DAMAGE_TYPE_FORCE,WESTRING_DAMAGE_TYPE_FORCE DamageTypeDeath=1,damagetype,DAMAGE_TYPE_DEATH,WESTRING_DAMAGE_TYPE_DEATH DamageTypeMind=1,damagetype,DAMAGE_TYPE_MIND,WESTRING_DAMAGE_TYPE_MIND DamageTypePlant=1,damagetype,DAMAGE_TYPE_PLANT,WESTRING_DAMAGE_TYPE_PLANT DamageTypeDefensive=1,damagetype,DAMAGE_TYPE_DEFENSIVE,WESTRING_DAMAGE_TYPE_DEFENSIVE DamageTypeDemolition=1,damagetype,DAMAGE_TYPE_DEMOLITION,WESTRING_DAMAGE_TYPE_DEMOLITION DamageTypeSlowPoison=1,damagetype,DAMAGE_TYPE_SLOW_POISON,WESTRING_DAMAGE_TYPE_SLOW_POISON DamageTypeSpiritLink=1,damagetype,DAMAGE_TYPE_SPIRIT_LINK,WESTRING_DAMAGE_TYPE_SPIRIT_LINK DamageTypeShadowStrike=1,damagetype,DAMAGE_TYPE_SHADOW_STRIKE,WESTRING_DAMAGE_TYPE_SHADOW_STRIKE DamageTypeUniversal=1,damagetype,DAMAGE_TYPE_UNIVERSAL,WESTRING_DAMAGE_TYPE_UNIVERSAL // Weapon types WeaponTypeMetalLightChop=1,weapontype,WEAPON_TYPE_METAL_LIGHT_CHOP,WESTRING_UE_COMBATSOUND_METALLIGHTCHOP WeaponTypeMetalMediumChop=1,weapontype,WEAPON_TYPE_METAL_MEDIUM_CHOP,WESTRING_UE_COMBATSOUND_METALMEDIUMCHOP WeaponTypeMetalHeavyChop=1,weapontype,WEAPON_TYPE_METAL_HEAVY_CHOP,WESTRING_UE_COMBATSOUND_METALHEAVYCHOP WeaponTypeMetalLightSlice=1,weapontype,WEAPON_TYPE_METAL_LIGHT_SLICE,WESTRING_UE_COMBATSOUND_METALLIGHTSLICE WeaponTypeMetalMediumSlice=1,weapontype,WEAPON_TYPE_METAL_MEDIUM_SLICE,WESTRING_UE_COMBATSOUND_METALMEDIUMSLICE WeaponTypeMetalHeavySlice=1,weapontype,WEAPON_TYPE_METAL_HEAVY_SLICE,WESTRING_UE_COMBATSOUND_METALHEAVYSLICE WeaponTypeMetalMediumBash=1,weapontype,WEAPON_TYPE_METAL_MEDIUM_BASH,WESTRING_UE_COMBATSOUND_METALMEDIUMBASH WeaponTypeMetalHeavyBash=1,weapontype,WEAPON_TYPE_METAL_HEAVY_BASH,WESTRING_UE_COMBATSOUND_METALHEAVYBASH WeaponTypeWoodLightBash=1,weapontype,WEAPON_TYPE_WOOD_LIGHT_BASH,WESTRING_UE_COMBATSOUND_WOODLIGHTBASH WeaponTypeWoodMediumBash=1,weapontype,WEAPON_TYPE_WOOD_MEDIUM_BASH,WESTRING_UE_COMBATSOUND_WOODMEDIUMBASH WeaponTypeWoodHeavyBash=1,weapontype,WEAPON_TYPE_WOOD_HEAVY_BASH,WESTRING_UE_COMBATSOUND_WOODHEAVYBASH WeaponTypeAxeMediumChop=1,weapontype,WEAPON_TYPE_AXE_MEDIUM_CHOP,WESTRING_UE_COMBATSOUND_AXEMEDIUMCHOP WeaponTypeRockHeavyBash=1,weapontype,WEAPON_TYPE_ROCK_HEAVY_BASH,WESTRING_UE_COMBATSOUND_ROCKHEAVYBASH PathingTypeAny=1,pathingtype,PATHING_TYPE_ANY,WESTRING_PATHINGTYPE_ANY PathingTypeWalkability=1,pathingtype,PATHING_TYPE_WALKABILITY,WESTRING_PATHINGTYPE_WALKABILITY PathingTypeFlyability=1,pathingtype,PATHING_TYPE_FLYABILITY,WESTRING_PATHINGTYPE_FLYABILITY PathingTypeBuildability=1,pathingtype,PATHING_TYPE_BUILDABILITY,WESTRING_PATHINGTYPE_BUILDABILITY PathingTypePeonHarvestPathing=1,pathingtype,PATHING_TYPE_PEONHARVESTPATHING,WESTRING_PATHINGTYPE_PEONHARVESTPATHING PathingTypeBlightPathing=1,pathingtype,PATHING_TYPE_BLIGHTPATHING,WESTRING_PATHINGTYPE_BLIGHTPATHING PathingTypeFloatability=1,pathingtype,PATHING_TYPE_FLOATABILITY,WESTRING_PATHINGTYPE_FLOATABILITY PathingTypeAmphibiousPathing=1,pathingtype,PATHING_TYPE_AMPHIBIOUSPATHING,WESTRING_PATHINGTYPE_AMPHIBIOUSPATHING // Camera fields CameraFieldTargetDistance=0,camerafield,CAMERA_FIELD_TARGET_DISTANCE,WESTRING_CAMERA_TARGETDISTANCE CameraFieldFarZ=0,camerafield,CAMERA_FIELD_FARZ,WESTRING_CAMERA_FARZ CameraFieldAOA=0,camerafield,CAMERA_FIELD_ANGLE_OF_ATTACK,WESTRING_CAMERA_AOA CameraFieldFOV=0,camerafield,CAMERA_FIELD_FIELD_OF_VIEW,WESTRING_CAMERA_FOV CameraFieldRoll=0,camerafield,CAMERA_FIELD_ROLL,WESTRING_CAMERA_ROLL CameraFieldRotation=0,camerafield,CAMERA_FIELD_ROTATION,WESTRING_CAMERA_ROTATION CameraFieldZOffset=1,camerafield,CAMERA_FIELD_ZOFFSET,WESTRING_CAMERA_ZOFFSET // Animation rarity controls RarityControlFrequent=0,raritycontrol,RARITY_FREQUENT,WESTRING_RARITY_FREQUENT RarityControlRare=0,raritycontrol,RARITY_RARE,WESTRING_RARITY_RARE // Blending Methods BlendModeNone=0,blendmode,BLEND_MODE_NONE,WESTRING_BLENDMODE_NONE BlendModeBlend=0,blendmode,BLEND_MODE_BLEND,WESTRING_BLENDMODE_BLEND BlendModeAdditive=0,blendmode,BLEND_MODE_ADDITIVE,WESTRING_BLENDMODE_ADDITIVE BlendModeModulate=0,blendmode,BLEND_MODE_MODULATE,WESTRING_BLENDMODE_MODULATE BlendModeModulate2x=0,blendmode,BLEND_MODE_MODULATE_2X,WESTRING_BLENDMODE_MODULATE_2X BlendModeKeyAlpha=0,blendmode,BLEND_MODE_KEYALPHA,WESTRING_BLENDMODE_KEYALPHA // Volume Groups VolumeGroupAmbient=0,volumegroup,SOUND_VOLUMEGROUP_AMBIENTSOUNDS,WESTRING_VOLUMEGROUP_AMBIENTSOUNDS VolumeGroupSpells=0,volumegroup,SOUND_VOLUMEGROUP_SPELLS,WESTRING_VOLUMEGROUP_SPELLS VolumeGroupCombat=0,volumegroup,SOUND_VOLUMEGROUP_COMBAT,WESTRING_VOLUMEGROUP_COMBAT VolumeGroupFire=0,volumegroup,SOUND_VOLUMEGROUP_FIRE,WESTRING_VOLUMEGROUP_FIRE VolumeGroupMusic=0,volumegroup,SOUND_VOLUMEGROUP_MUSIC,WESTRING_VOLUMEGROUP_MUSIC VolumeGroupUnitMovement=0,volumegroup,SOUND_VOLUMEGROUP_UNITMOVEMENT,WESTRING_VOLUMEGROUP_UNITMOVEMENT VolumeGroupUnitSounds=0,volumegroup,SOUND_VOLUMEGROUP_UNITSOUNDS,WESTRING_VOLUMEGROUP_UNITSOUNDS VolumeGroupUI=0,volumegroup,SOUND_VOLUMEGROUP_UI,WESTRING_VOLUMEGROUP_UI EffectTypeEffect=1,effecttype,EFFECT_TYPE_EFFECT,WESTRING_EFFECT_TYPE_EFFECT EffectTypeTarget=1,effecttype,EFFECT_TYPE_TARGET,WESTRING_EFFECT_TYPE_TARGET EffectTypeCaster=1,effecttype,EFFECT_TYPE_CASTER,WESTRING_EFFECT_TYPE_CASTER EffectTypeSpecial=1,effecttype,EFFECT_TYPE_SPECIAL,WESTRING_EFFECT_TYPE_SPECIAL EffectTypeAreaEffect=1,effecttype,EFFECT_TYPE_AREA_EFFECT,WESTRING_EFFECT_TYPE_AREA_EFFECT EffectTypeMissile=1,effecttype,EFFECT_TYPE_MISSILE,WESTRING_EFFECT_TYPE_MISSILE EffectTypeLightning=1,effecttype,EFFECT_TYPE_LIGHTNING,WESTRING_EFFECT_TYPE_LIGHTNING SoundTypeEffect=1,soundtype,SOUND_TYPE_EFFECT,WESTRING_SOUND_TYPE_EFFECT SoundTypeEffectLooped=1,soundtype,SOUND_TYPE_EFFECT_LOOPED,WESTRING_SOUND_TYPE_EFFECT_LOOPED // Fog states FogStateMasked=0,fogstate,FOG_OF_WAR_MASKED,WESTRING_FOGSTATE_MASKED FogStateFogged=0,fogstate,FOG_OF_WAR_FOGGED,WESTRING_FOGSTATE_FOGGED FogStateVisible=0,fogstate,FOG_OF_WAR_VISIBLE,WESTRING_FOGSTATE_VISIBLE // Fog styles FogStyleLinear=0,fogstyle,0,WESTRING_FOGSTYLE_LINEAR FogStyleExp1=0,fogstyle,1,WESTRING_FOGSTYLE_EXP1 FogStyleExp2=0,fogstyle,2,WESTRING_FOGSTYLE_EXP2 // Timed-life buff codes TimedLifeBuffCodeAnimateDead=1,timedlifebuffcode,'BUan',WESTRING_TIMEDLIFEBUFFCODE_ANIMATEDEAD TimedLifeBuffCodePlagueWard=1,timedlifebuffcode,'Bapl',WESTRING_TIMEDLIFEBUFFCODE_PLAGUEWARD TimedLifeBuffCodeForceOfNature=1,timedlifebuffcode,'BEfn',WESTRING_TIMEDLIFEBUFFCODE_FORCEOFNATURE TimedLifeBuffCodeGeneric=1,timedlifebuffcode,'BTLF',WESTRING_TIMEDLIFEBUFFCODE_GENERIC TimedLifeBuffCodeHealingWard=1,timedlifebuffcode,'Bhwd',WESTRING_TIMEDLIFEBUFFCODE_HEALINGWARD TimedLifeBuffCodeRaiseDead=1,timedlifebuffcode,'Brai',WESTRING_TIMEDLIFEBUFFCODE_RAISEDEAD TimedLifeBuffCodeWaterElemental=1,timedlifebuffcode,'BHwe',WESTRING_TIMEDLIFEBUFFCODE_WATERELEMENTAL // Item status codes ItemStatusHidden=1,itemstatus,bj_ITEM_STATUS_HIDDEN,WESTRING_ITEMSTATUS_HIDDEN ItemStatusOwned=1,itemstatus,bj_ITEM_STATUS_OWNED,WESTRING_ITEMSTATUS_OWNED ItemStatusInvulnerable=1,itemstatus,bj_ITEM_STATUS_INVULNERABLE,WESTRING_ITEMSTATUS_INVULNERABLE ItemStatusPowerup=1,itemstatus,bj_ITEM_STATUS_POWERUP,WESTRING_ITEMSTATUS_POWERUP ItemStatusSellable=1,itemstatus,bj_ITEM_STATUS_SELLABLE,WESTRING_ITEMSTATUS_SELLABLE ItemStatusPawnable=1,itemstatus,bj_ITEM_STATUS_PAWNABLE,WESTRING_ITEMSTATUS_PAWNABLE // Itemcode status codes ItemcodeStatusPowerup=1,itemcodestatus,bj_ITEMCODE_STATUS_POWERUP,WESTRING_ITEMCODESTATUS_POWERUP ItemcodeStatusSellable=1,itemcodestatus,bj_ITEMCODE_STATUS_SELLABLE,WESTRING_ITEMCODESTATUS_SELLABLE ItemcodeStatusPawnable=1,itemcodestatus,bj_ITEMCODE_STATUS_PAWNABLE,WESTRING_ITEMCODESTATUS_PAWNABLE // Minimap ping styles MinimapPingStyleSimple=1,minimappingstyle,bj_MINIMAPPINGSTYLE_SIMPLE,WESTRING_MINIMAPPINGSTYLE_SIMPLE MinimapPingStyleFlashy=1,minimappingstyle,bj_MINIMAPPINGSTYLE_FLASHY,WESTRING_MINIMAPPINGSTYLE_FLASHY MinimapPingStyleAttack=1,minimappingstyle,bj_MINIMAPPINGSTYLE_ATTACK,WESTRING_MINIMAPPINGSTYLE_ATTACK // Corpse creation styles CorpseTypeFlesh=1,corpsetype,bj_CORPSETYPE_FLESH,WESTRING_CORPSETYPE_FLESH CorpseTypeBone=1,corpsetype,bj_CORPSETYPE_BONE,WESTRING_CORPSETYPE_BONE // String case option StringCaseLower=1,stringcaseoption,false,WESTRING_STRINGCASE_LOWER StringCaseUpper=1,stringcaseoption,true,WESTRING_STRINGCASE_UPPER // Change color option ChangeColorTrue=0,colorchangeoption,true,WESTRING_CHANGECOLOR_CHANGE ChangeColorFalse=0,colorchangeoption,false,WESTRING_CHANGECOLOR_RETAIN // Player Change Color option PlayerChangeColorChange=0,playerchangecoloroption,true,WESTRING_SETPLAYERCOLOR_CHANGE PlayerChangeColorRetain=0,playerchangecoloroption,false,WESTRING_SETPLAYERCOLOR_RETAIN // Chat match types ChatMatchTypeExact=0,chatmatchtype,true,WESTRING_CHATMATCH_EXACT ChatMatchTypeSubstring=0,chatmatchtype,false,WESTRING_CHATMATCH_SUBSTRING // UnitFacing bones UnitFacingBoneHead=0,unitfacingbone,`bone_head`,WESTRING_UNITFACINGBONE_HEAD UnitFacingBoneChest=0,unitfacingbone,`bone_chest`,WESTRING_UNITFACINGBONE_CHEST // Include option InclusionInclude=0,includeoption,true,WESTRING_INCLUSION_INCLUDE InclusionExclude=0,includeoption,false,WESTRING_INCLUSION_EXCLUDE // Camera Pan option CameraApply=0,cameraapplyoption,true,WESTRING_CAMERAAPPLYOPTION_APPLY CameraApplyNoPan=0,cameraapplyoption,false,WESTRING_CAMERAAPPLYOPTION_APPLYNOPAN // Camera Orientation option CameraOrientationNormal=0,cameraorientationoption,false,WESTRING_CAMERAORIENTATION_NORMAL CameraOrientationInherit=0,cameraorientationoption,true,WESTRING_CAMERAORIENTATION_INHERIT // Invulnerability option InvulnerabilityInvulnerable=0,invulnerableoption,true,WESTRING_INVULNERABILITY_INVULNERABLE InvulnerabilityVulnerable=0,invulnerableoption,false,WESTRING_INVULNERABILITY_VULNERABLE // Availability option AvailabilityOptionAvailable=0,availabilityoption,true,WESTRING_AVAILABILITY_AVAILABLE AvailabilityOptionUnavailable=0,availabilityoption,false,WESTRING_AVAILABILITY_UNAVAILABLE // ShowHide option ShowHideHide=0,showhideoption,false,WESTRING_SHOWHIDE_HIDE ShowHideShow=0,showhideoption,true,WESTRING_SHOWHIDE_SHOW // Minimize option Minimize=1,minimizeoption,true,WESTRING_MINIMIZEOPTION_MINIMIZE Maximize=1,minimizeoption,false,WESTRING_MINIMIZEOPTION_MAXIMIZE // Sky Model SkyModelNone=0,skymodelstring,null,WESTRING_SKYMODEL_NONE SkyModelSky08=0,skymodelstring,`Environment\\Sky\\BlizzardSky\\BlizzardSky.mdl`,WESTRING_SKYMODEL_SKY08 SkyModelSky02=0,skymodelstring,`Environment\\Sky\\DalaranSky\\DalaranSky.mdl`,WESTRING_SKYMODEL_SKY02 SkyModelSky06=0,skymodelstring,`Environment\\Sky\\FelwoodSky\\FelwoodSky.mdl`,WESTRING_SKYMODEL_SKY06 SkyModelSky07=0,skymodelstring,`Environment\\Sky\\FoggedSky\\FoggedSky.mdl`,WESTRING_SKYMODEL_SKY07 SkyModelSky01=0,skymodelstring,`Environment\\Sky\\Sky\\SkyLight.mdl`,WESTRING_SKYMODEL_SKY01 SkyModelSky03=0,skymodelstring,`Environment\\Sky\\LordaeronFallSky\\LordaeronFallSky.mdl`,WESTRING_SKYMODEL_SKY03 SkyModelSky04=0,skymodelstring,`Environment\\Sky\\LordaeronSummerSky\\LordaeronSummerSky.mdl`,WESTRING_SKYMODEL_SKY04 SkyModelSky05=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSky\\LordaeronWinterSky.mdl`,WESTRING_SKYMODEL_SKY05 SkyModelSky09=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyBrightGreen\\LordaeronWinterSkyBrightGreen.mdl`,WESTRING_SKYMODEL_SKY09 SkyModelSky10=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyPink\\LordaeronWinterSkyPink.mdl`,WESTRING_SKYMODEL_SKY10 SkyModelSky11=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyPurple\\LordaeronWinterSkyPurple.mdl`,WESTRING_SKYMODEL_SKY11 SkyModelSky12=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyRed\\LordaeronWinterSkyRed.mdl`,WESTRING_SKYMODEL_SKY12 SkyModelSky13=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyYellow\\LordaeronWinterSkyYellow.mdl`,WESTRING_SKYMODEL_SKY13 SkyModelSky14=1,skymodelstring,`Environment\\Sky\\Outland_Sky\\Outland_Sky.mdl`,WESTRING_SKYMODEL_SKY14 // Cinematic filter textures CineFilterTextureWhite=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\White_mask.blp`,WESTRING_CINEFILTERTEX_WHITE CineFilterTextureBlack=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Black_mask.blp`,WESTRING_CINEFILTERTEX_BLACK CineFilterTextureHaze=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\HazeFilter_mask.blp`,WESTRING_CINEFILTERTEX_HAZE CineFilterTextureGroundFog=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\GroundFog_mask.blp`,WESTRING_CINEFILTERTEX_GROUNDFOG CineFilterTextureHazeAndFog=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\HazeAndFogFilter_Mask.blp`,WESTRING_CINEFILTERTEX_HAZEANDFOG CineFilterTextureDiagonal=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\DiagonalSlash_mask.blp`,WESTRING_CINEFILTERTEX_DIAGONAL CineFilterTextureDream=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\DreamFilter_Mask.blp`,WESTRING_CINEFILTERTEX_DREAM CineFilterTextureScope=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Scope_Mask.blp`,WESTRING_CINEFILTERTEX_SCOPE CineFilterTexturePow=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\SpecialPowMask.blp`,WESTRING_CINEFILTERTEX_POW CineFilterTextureSplat=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\SpecialSplatMask.blp`,WESTRING_CINEFILTERTEX_SPLAT CineFilterTexturePanda=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Panda-n-Cub.blp`,WESTRING_CINEFILTERTEX_PANDA // Music themes MusicThemeArthas=1,musictheme,`Sound\\Music\\mp3Music\\ArthasTheme.mp3`,WESTRING_MUSICTHEME_ARTHAS MusicThemeBloodElf=1,musictheme,`Sound\\Music\\mp3Music\\BloodElfTheme.mp3`,WESTRING_MUSICTHEME_BLOODELF MusicThemeComradeship=0,musictheme,`Sound\\Music\\mp3Music\\Comradeship.mp3`,WESTRING_MUSICTHEME_COMRADESHIP MusicThemeCredits=0,musictheme,`Sound\\Music\\mp3Music\\Credits.mp3`,WESTRING_MUSICTHEME_CREDITS MusicThemeDarkAgents=0,musictheme,`Sound\\Music\\mp3Music\\DarkAgents.mp3`,WESTRING_MUSICTHEME_DARKAGENTS MusicThemeDarkVictory=0,musictheme,`Sound\\Music\\mp3Music\\DarkVictory.mp3`,WESTRING_MUSICTHEME_DARKVICTORY MusicThemeDoom=0,musictheme,`Sound\\Music\\mp3Music\\Doom.mp3`,WESTRING_MUSICTHEME_DOOM MusicThemeHeroicVictory=0,musictheme,`Sound\\Music\\mp3Music\\HeroicVictory.mp3`,WESTRING_MUSICTHEME_HEROIC_VICTORY MusicThemeHuman1=0,musictheme,`Sound\\Music\\mp3Music\\Human1.mp3`,WESTRING_MUSICTHEME_HUMAN1 MusicThemeHuman2=0,musictheme,`Sound\\Music\\mp3Music\\Human2.mp3`,WESTRING_MUSICTHEME_HUMAN2 MusicThemeHuman3=0,musictheme,`Sound\\Music\\mp3Music\\Human3.mp3`,WESTRING_MUSICTHEME_HUMAN3 MusicThemeHumanX1=1,musictheme,`Sound\\Music\\mp3Music\\HumanX1.mp3`,WESTRING_MUSICTHEME_HUMANX1 MusicThemeDefeatHuman=0,musictheme,`Sound\\Music\\mp3Music\\HumanDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_HUMAN MusicThemeVictoryHuman=0,musictheme,`Sound\\Music\\mp3Music\\HumanVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_HUMAN MusicThemeIllidan=1,musictheme,`Sound\\Music\\mp3Music\\IllidansTheme.mp3`,WESTRING_MUSICTHEME_ILLIDAN MusicThemeLichKing=1,musictheme,`Sound\\Music\\mp3Music\\LichKingTheme.mp3`,WESTRING_MUSICTHEME_LICHKING MusicThemeMainScreen=0,musictheme,`Sound\\Music\\mp3Music\\MainScreen.mp3`,WESTRING_MUSICTHEME_MAINSCREEN MusicThemeMainScreenX=1,musictheme,`Sound\\Music\\mp3Music\\War3XMainScreen.mp3`,WESTRING_MUSICTHEME_MAINSCREENX MusicThemeNaga=1,musictheme,`Sound\\Music\\mp3Music\\NagaTheme.mp3`,WESTRING_MUSICTHEME_NAGA MusicThemeNightElf1=0,musictheme,`Sound\\Music\\mp3Music\\NightElf1.mp3`,WESTRING_MUSICTHEME_NIGHTELF1 MusicThemeNightElf2=0,musictheme,`Sound\\Music\\mp3Music\\NightElf2.mp3`,WESTRING_MUSICTHEME_NIGHTELF2 MusicThemeNightElf3=0,musictheme,`Sound\\Music\\mp3Music\\NightElf3.mp3`,WESTRING_MUSICTHEME_NIGHTELF3 MusicThemeNightElfX1=1,musictheme,`Sound\\Music\\mp3Music\\NightElfX1.mp3`,WESTRING_MUSICTHEME_NIGHTELFX1 MusicThemeDefeatNightElf=0,musictheme,`Sound\\Music\\mp3Music\\NightElfDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_NIGHTELF MusicThemeVictoryNightElf=0,musictheme,`Sound\\Music\\mp3Music\\NightElfVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_NIGHTELF MusicThemeOrc1=0,musictheme,`Sound\\Music\\mp3Music\\Orc1.mp3`,WESTRING_MUSICTHEME_ORC1 MusicThemeOrc2=0,musictheme,`Sound\\Music\\mp3Music\\Orc2.mp3`,WESTRING_MUSICTHEME_ORC2 MusicThemeOrc3=0,musictheme,`Sound\\Music\\mp3Music\\Orc3.mp3`,WESTRING_MUSICTHEME_ORC3 MusicThemeOrcX1=1,musictheme,`Sound\\Music\\mp3Music\\OrcX1.mp3`,WESTRING_MUSICTHEME_ORCX1 MusicThemeDefeatOrc=0,musictheme,`Sound\\Music\\mp3Music\\OrcDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_ORC MusicThemeOrcTheme=1,musictheme,`Sound\\Music\\mp3Music\\OrcTheme.mp3`,WESTRING_MUSICTHEME_ORC_THEME MusicThemeVictoryOrc=0,musictheme,`Sound\\Music\\mp3Music\\OrcVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_ORC MusicThemePersuit=1,musictheme,`Sound\\Music\\mp3Music\\PursuitTheme.mp3`,WESTRING_MUSICTHEME_PURSUIT MusicThemeSadMystery=0,musictheme,`Sound\\Music\\mp3Music\\SadMystery.mp3`,WESTRING_MUSICTHEME_SADMYSTERY MusicThemeTension=0,musictheme,`Sound\\Music\\mp3Music\\Tension.mp3`,WESTRING_MUSICTHEME_TENSION MusicThemeTragicConfrontation=0,musictheme,`Sound\\Music\\mp3Music\\TragicConfrontation.mp3`,WESTRING_MUSICTHEME_TRAGICCONFRONTATION MusicThemeUndead1=0,musictheme,`Sound\\Music\\mp3Music\\Undead1.mp3`,WESTRING_MUSICTHEME_UNDEAD1 MusicThemeUndead2=0,musictheme,`Sound\\Music\\mp3Music\\Undead2.mp3`,WESTRING_MUSICTHEME_UNDEAD2 MusicThemeUndead3=0,musictheme,`Sound\\Music\\mp3Music\\Undead3.mp3`,WESTRING_MUSICTHEME_UNDEAD3 MusicThemeUndeadX1=1,musictheme,`Sound\\Music\\mp3Music\\UndeadX1.mp3`,WESTRING_MUSICTHEME_UNDEADX1 MusicThemeDefeatUndead=0,musictheme,`Sound\\Music\\mp3Music\\UndeadDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_UNDEAD MusicThemeVictoryUndead=0,musictheme,`Sound\\Music\\mp3Music\\UndeadVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_UNDEAD // Daytime Ambient Themes AmbientThemeDayA=0,ambientthemeday,`AshenvaleDay`,WESTRING_AMBIENTTHEMEDAY_A AmbientThemeDayB=0,ambientthemeday,`BarrensDay`,WESTRING_AMBIENTTHEMEDAY_B AmbientThemeDayK=1,ambientthemeday,`BlackCitadelDay`,WESTRING_AMBIENTTHEMEDAY_K AmbientThemeDayY=0,ambientthemeday,`CityScapeDay`,WESTRING_AMBIENTTHEMEDAY_Y AmbientThemeDayX=0,ambientthemeday,`DalaranDay`,WESTRING_AMBIENTTHEMEDAY_X AmbientThemeDayJ=1,ambientthemeday,`DalaranRuinsDay`,WESTRING_AMBIENTTHEMEDAY_J AmbientThemeDayD=0,ambientthemeday,`DungeonDay`,WESTRING_AMBIENTTHEMEDAY_D AmbientThemeDayC=0,ambientthemeday,`FelwoodDay`,WESTRING_AMBIENTTHEMEDAY_C AmbientThemeDayI=1,ambientthemeday,`IceCrownDay`,WESTRING_AMBIENTTHEMEDAY_I AmbientThemeDayF=0,ambientthemeday,`LordaeronFallDay`,WESTRING_AMBIENTTHEMEDAY_F AmbientThemeDayL=0,ambientthemeday,`LordaeronSummerDay`,WESTRING_AMBIENTTHEMEDAY_L AmbientThemeDayW=0,ambientthemeday,`LordaeronWinterDay`,WESTRING_AMBIENTTHEMEDAY_W AmbientThemeDayN=0,ambientthemeday,`NorthrendDay`,WESTRING_AMBIENTTHEMEDAY_N AmbientThemeDayO=1,ambientthemeday,`BlackCitadelDay`,WESTRING_AMBIENTTHEMEDAY_O AmbientThemeDayZ=1,ambientthemeday,`SunkenRuinsDay`,WESTRING_AMBIENTTHEMEDAY_Z AmbientThemeDayV=0,ambientthemeday,`VillageDay`,WESTRING_AMBIENTTHEMEDAY_V AmbientThemeDayQ=0,ambientthemeday,`VillageFallDay`,WESTRING_AMBIENTTHEMEDAY_Q // Nighttime Ambient Themes AmbientThemeNightA=0,ambientthemenight,`AshenvaleNight`,WESTRING_AMBIENTTHEMENIGHT_A AmbientThemeNightB=0,ambientthemenight,`BarrensNight`,WESTRING_AMBIENTTHEMENIGHT_B AmbientThemeNightK=1,ambientthemenight,`BlackCitadelNight`,WESTRING_AMBIENTTHEMENIGHT_K AmbientThemeNightY=0,ambientthemenight,`CityScapeNight`,WESTRING_AMBIENTTHEMENIGHT_Y AmbientThemeNightX=0,ambientthemenight,`DalaranNight`,WESTRING_AMBIENTTHEMENIGHT_X AmbientThemeNightJ=1,ambientthemenight,`DalaranRuinsNight`,WESTRING_AMBIENTTHEMENIGHT_J AmbientThemeNightD=0,ambientthemenight,`DungeonNight`,WESTRING_AMBIENTTHEMENIGHT_D AmbientThemeNightC=0,ambientthemenight,`FelwoodNight`,WESTRING_AMBIENTTHEMENIGHT_C AmbientThemeNightI=1,ambientthemenight,`IceCrownNight`,WESTRING_AMBIENTTHEMENIGHT_I AmbientThemeNightF=0,ambientthemenight,`LordaeronFallNight`,WESTRING_AMBIENTTHEMENIGHT_F AmbientThemeNightL=0,ambientthemenight,`LordaeronSummerNight`,WESTRING_AMBIENTTHEMENIGHT_L AmbientThemeNightW=0,ambientthemenight,`LordaeronWinterNight`,WESTRING_AMBIENTTHEMENIGHT_W AmbientThemeNightN=0,ambientthemenight,`NorthrendNight`,WESTRING_AMBIENTTHEMENIGHT_N AmbientThemeNightO=1,ambientthemenight,`BlackCitadelNight`,WESTRING_AMBIENTTHEMENIGHT_O AmbientThemeNightZ=1,ambientthemenight,`SunkenRuinsNight`,WESTRING_AMBIENTTHEMENIGHT_Z AmbientThemeNightV=0,ambientthemenight,`VillageNight`,WESTRING_AMBIENTTHEMENIGHT_V AmbientThemeNightQ=0,ambientthemenight,`VillageFallNight`,WESTRING_AMBIENTTHEMENIGHT_Q // Unit State Method UnitStateMethodAbsolute=0,unitstatemethod,bj_UNIT_STATE_METHOD_ABSOLUTE,WESTRING_UNITSTATEMETHOD_ABSOLUTE UnitStateMethodRelative=0,unitstatemethod,bj_UNIT_STATE_METHOD_RELATIVE,WESTRING_UNITSTATEMETHOD_RELATIVE UnitStateMethodDefaults=0,unitstatemethod,bj_UNIT_STATE_METHOD_DEFAULTS,WESTRING_UNITSTATEMETHOD_DEFAULTS UnitStateMethodMaximum=0,unitstatemethod,bj_UNIT_STATE_METHOD_MAXIMUM,WESTRING_UNITSTATEMETHOD_MAXIMUM // CheckingIgnoring option CheckingIgnoringChecking=0,checkingignoringoption,true,WESTRING_CHECKINGIGNORINGOPTION_CHECKING CheckingIgnoringIgnoring=0,checkingignoringoption,false,WESTRING_CHECKINGIGNORINGOPTION_IGNORING // Pathing option PathingOn=0,pathingoption,true,WESTRING_PATHING_ON PathingOff=0,pathingoption,false,WESTRING_PATHING_OFF // Pawnable option PawnableOptionPawnable=1,pawnableoption,true,WESTRING_PAWNABLEOPTION_PAWNABLE PawnableOptionUnpawnable=1,pawnableoption,false,WESTRING_PAWNABLEOPTION_UNPAWNABLE // DropOnDeath option DropNoDropOptionDrop=0,dropnodropoption,true,WESTRING_DROPNODROPOPTION_DROP DropNoDropOptionNoDrop=0,dropnodropoption,false,WESTRING_DROPNODROPOPTION_NODROP // Droppable option DroppableOptionDrop=0,droppableoption,true,WESTRING_DROPPABLE_DROP DroppableOptionNoDrop=0,droppableoption,false,WESTRING_DROPPABLE_NODROP // BeforeAfter option BeforeAfterBefore=0,beforeafteroption,false,WESTRING_BEFOREAFTER_BEFORE BeforeAfterAfter=0,beforeafteroption,true,WESTRING_BEFOREAFTER_AFTER // OnOff option OnOffOn=0,onoffoption,true,WESTRING_ONOFF_ON OnOffOff=0,onoffoption,false,WESTRING_ONOFF_OFF // EnableDisable option EnableDisableEnable=0,enabledisableoption,true,WESTRING_ENABLEDISABLE_ENABLE EnableDisableDisable=0,enabledisableoption,false,WESTRING_ENABLEDISABLE_DISABLE // EnabledDisabled option EnabledDisabledEnabled=0,enableddisabledoption,true,WESTRING_ENABLEDDISABLED_ENABLED EnabledDisabledDisabled=0,enableddisabledoption,false,WESTRING_ENABLEDDISABLED_DISABLED // Rescuable option RescuableOptionRescuable=0,rescuableoption,true,WESTRING_RESCUABLEOPTION_RESCUABLE RescuableOptionUnrescuable=0,rescuableoption,false,WESTRING_RESCUABLEOPTION_UNRESCUABLE // AllowDont option AllowDontAllow=0,allowdontoption,true,WESTRING_ALLOWDONTOPTION_ALLOW AllowDontDont=0,allowdontoption,false,WESTRING_ALLOWDONTOPTION_DONT // FadeDont option FadeDontFade=0,fadedontoption,true,WESTRING_FADEDONTOPTION_FADE FadeDontDont=0,fadedontoption,false,WESTRING_FADEDONTOPTION_DONT // AddSetTo option AddSetToAdd=0,addsettooption,bj_TIMETYPE_ADD,WESTRING_ADDSETTOOPTION_ADD AddSetToSub=0,addsettooption,bj_TIMETYPE_SUB,WESTRING_ADDSETTOOPTION_SUB AddSetToSet=0,addsettooption,bj_TIMETYPE_SET,WESTRING_ADDSETTOOPTION_SET // Modify methods ModifyMethodAdd=1,modifymethod,bj_MODIFYMETHOD_ADD,WESTRING_MODIFYMETHOD_ADD ModifyMethodSub=1,modifymethod,bj_MODIFYMETHOD_SUB,WESTRING_MODIFYMETHOD_SUB ModifyMethodSet=1,modifymethod,bj_MODIFYMETHOD_SET,WESTRING_MODIFYMETHOD_SET // WaitDont option WaitDontWait=0,waitdontoption,true,WESTRING_WAITDONTOPTION_WAIT WaitDontDont=0,waitdontoption,false,WESTRING_WAITDONTOPTION_DONT // CraterTypes CraterTypeTemporary=1,cratertype,false,WESTRING_CRATERTYPE_TEMPORARY CraterTypePermanent=1,cratertype,true,WESTRING_CRATERTYPE_PERMANENT // RippleTypes RippleTypeNormal=1,rippletype,false,WESTRING_RIPPLETYPE_NORMAL RippleTypeDepression=1,rippletype,true,WESTRING_RIPPLETYPE_DEPRESSION // CreateRemove option CreateRemoveCreate=0,createremoveoption,true,WESTRING_CREATEREMOVEOPTION_CREATE CreateRemoveRemove=0,createremoveoption,false,WESTRING_CREATEREMOVEOPTION_REMOVE // AddRemove option AddRemoveAdd=0,addremoveoption,true,WESTRING_ADDREMOVEOPTION_ADD AddRemoveRemove=0,addremoveoption,false,WESTRING_ADDREMOVEOPTION_REMOVE // QuestType option QuestTypeReqDiscovered=0,questtypeoption,bj_QUESTTYPE_REQ_DISCOVERED,WESTRING_QUESTTYPE_REQ_DISCOVERED QuestTypeOptDiscovered=0,questtypeoption,bj_QUESTTYPE_OPT_DISCOVERED,WESTRING_QUESTTYPE_OPT_DISCOVERED QuestTypeReqUndiscovered=0,questtypeoption,bj_QUESTTYPE_REQ_UNDISCOVERED,WESTRING_QUESTTYPE_REQ_UNDISCOVERED QuestTypeOptUndiscovered=0,questtypeoption,bj_QUESTTYPE_OPT_UNDISCOVERED,WESTRING_QUESTTYPE_OPT_UNDISCOVERED // QuestMessageType option QuestMessageTypeDiscovered=0,questmessagetype,bj_QUESTMESSAGE_DISCOVERED,WESTRING_QUESTMESSAGE_DISCOVERED QuestMessageTypeUpdated=0,questmessagetype,bj_QUESTMESSAGE_UPDATED,WESTRING_QUESTMESSAGE_UPDATED QuestMessageTypeCompleted=0,questmessagetype,bj_QUESTMESSAGE_COMPLETED,WESTRING_QUESTMESSAGE_COMPLETED QuestMessageTypeFailed=0,questmessagetype,bj_QUESTMESSAGE_FAILED,WESTRING_QUESTMESSAGE_FAILED QuestMessageTypeRequirement=0,questmessagetype,bj_QUESTMESSAGE_REQUIREMENT,WESTRING_QUESTMESSAGE_REQUIREMENT QuestMessageTypeMissionFailed=0,questmessagetype,bj_QUESTMESSAGE_MISSIONFAILED,WESTRING_QUESTMESSAGE_MISSIONFAILED QuestMessageTypeAlwaysHint=0,questmessagetype,bj_QUESTMESSAGE_ALWAYSHINT,WESTRING_QUESTMESSAGE_ALWAYSHINT QuestMessageTypeHint=0,questmessagetype,bj_QUESTMESSAGE_HINT,WESTRING_QUESTMESSAGE_HINT QuestMessageTypeSecret=0,questmessagetype,bj_QUESTMESSAGE_SECRET,WESTRING_QUESTMESSAGE_SECRET QuestMessageTypeWarning=1,questmessagetype,bj_QUESTMESSAGE_WARNING,WESTRING_QUESTMESSAGE_WARNING QuestMessageTypeUnitAcquired=0,questmessagetype,bj_QUESTMESSAGE_UNITACQUIRED,WESTRING_QUESTMESSAGE_UNITACQUIRED QuestMessageTypeUnitAvailable=0,questmessagetype,bj_QUESTMESSAGE_UNITAVAILABLE,WESTRING_QUESTMESSAGE_UNITAVAILABLE QuestMessageTypeItemAcquired=0,questmessagetype,bj_QUESTMESSAGE_ITEMACQUIRED,WESTRING_QUESTMESSAGE_ITEMACQUIRED // Hero Stats HeroStatStr=1,herostat,bj_HEROSTAT_STR,WESTRING_HEROSTAT_STR HeroStatAgi=1,herostat,bj_HEROSTAT_AGI,WESTRING_HEROSTAT_AGI HeroStatInt=1,herostat,bj_HEROSTAT_INT,WESTRING_HEROSTAT_INT // Completion option CompletionOptionCompleted=0,completionoption,true,WESTRING_COMPLETIONOPTION_COMPLETED CompletionOptionIncomplete=0,completionoption,false,WESTRING_COMPLETIONOPTION_INCOMPLETE // Failure option FailureOptionFailed=0,failureoption,true,WESTRING_FAILUREOPTION_FAILED FailureOptionNotFailed=0,failureoption,false,WESTRING_FAILUREOPTION_NOTFAILED // Discovered option DiscoveredOptionDiscovered=0,discoveredoption,true,WESTRING_DISCOVEREDOPTION_DISCOVERED DiscoveredOptionUndiscovered=0,discoveredoption,false,WESTRING_DISCOVEREDOPTION_UNDISCOVERED // PauseResume option PauseResumePause=0,pauseresumeoption,true,WESTRING_PAUSERESUMEOPTION_PAUSE PauseResumeResume=0,pauseresumeoption,false,WESTRING_PAUSERESUMEOPTION_RESUME // Periodic option PeriodicOptionOneTime=0,periodicoption,false,WESTRING_PERIODICOPTION_ONETIME PeriodicOptionPeriodic=0,periodicoption,true,WESTRING_PERIODICOPTION_PERIODIC // LeaderboardSort option LeaderboardSortByValue=0,leaderboardsortoption,bj_SORTTYPE_SORTBYVALUE,WESTRING_LEADERBOARDSORT_BYVALUE LeaderboardSortByPlayer=0,leaderboardsortoption,bj_SORTTYPE_SORTBYPLAYER,WESTRING_LEADERBOARDSORT_BYPLAYER LeaderboardSortByLabel=0,leaderboardsortoption,bj_SORTTYPE_SORTBYLABEL,WESTRING_LEADERBOARDSORT_BYLABEL // Ascending option AscendingOptionAscending=0,ascendingoption,true,WESTRING_ASCENDINGOPTION_ASCENDING AscendingOptionDescending=0,ascendingoption,false,WESTRING_ASCENDINGOPTION_DESCENDING // SleepWake option SleepWakeOptionSleep=0,sleepwakeoption,true,WESTRING_SLEEPWAKEOPTION_SLEEP SleepWakeOptionWake=0,sleepwakeoption,false,WESTRING_SLEEPWAKEOPTION_WAKE // PauseUnpause option PauseUnpauseOptionPause=0,pauseunpauseoption,true,WESTRING_PAUSEUNPAUSEOPTION_PAUSE PauseUnpauseOptionUnpause=0,pauseunpauseoption,false,WESTRING_PAUSEUNPAUSEOPTION_UNPAUSE // ShareDont option ShareDontOptionShare=0,sharedontoption,true,WESTRING_SHAREDONTOPTION_SHARE ShareDontOptionDont=0,sharedontoption,false,WESTRING_SHAREDONTOPTION_DONT // InOut option FadeTypeOptionFadeOutIn=0,fadetypeoption,bj_CINEFADETYPE_FADEOUTIN,WESTRING_FADETYPEOPTION_FADEOUTIN FadeTypeOptionFadeOut=0,fadetypeoption,bj_CINEFADETYPE_FADEOUT,WESTRING_FADETYPEOPTION_FADEOUT FadeTypeOptionFadeIn=0,fadetypeoption,bj_CINEFADETYPE_FADEIN,WESTRING_FADETYPEOPTION_FADEIN // Buff Types BuffTypeAll=0,bufftype,bj_REMOVEBUFFS_ALL,WESTRING_BUFFTYPE_ALL BuffTypeNonTLife=1,bufftype,bj_REMOVEBUFFS_NONTLIFE,WESTRING_BUFFTYPE_NONTLIFE BuffTypePositive=0,bufftype,bj_REMOVEBUFFS_POSITIVE,WESTRING_BUFFTYPE_POSITIVE BuffTypeNegative=0,bufftype,bj_REMOVEBUFFS_NEGATIVE,WESTRING_BUFFTYPE_NEGATIVE // Buff Polarity options BuffPolarityPositive=1,buffpolarity,bj_BUFF_POLARITY_POSITIVE,WESTRING_BUFF_POLARITY_POSITIVE BuffPolarityNegative=1,buffpolarity,bj_BUFF_POLARITY_NEGATIVE,WESTRING_BUFF_POLARITY_NEGATIVE BuffPolarityEither=1,buffpolarity,bj_BUFF_POLARITY_EITHER,WESTRING_BUFF_POLARITY_EITHER // Buff Resistance types BuffResistMagic=1,buffresist,bj_BUFF_RESIST_MAGIC,WESTRING_BUFF_RESIST_MAGIC BuffResistPhysical=1,buffresist,bj_BUFF_RESIST_PHYSICAL,WESTRING_BUFF_RESIST_PHYSICAL BuffResistEither=1,buffresist,bj_BUFF_RESIST_EITHER,WESTRING_BUFF_RESIST_EITHER BuffResistBoth=1,buffresist,bj_BUFF_RESIST_BOTH,WESTRING_BUFF_RESIST_BOTH // Camera Bounds Adjustment Type CameraBoundsAdjustAdd=0,cameraboundsadjusttype,bj_CAMERABOUNDS_ADJUST_ADD,WESTRING_CAMERABOUNDSADJUST_ADD CameraBoundsAdjustSub=0,cameraboundsadjusttype,bj_CAMERABOUNDS_ADJUST_SUB,WESTRING_CAMERABOUNDSADJUST_SUB // Availability Option AvailableOptionAvailable=0,availableoption,true,WESTRING_AVAILABLEOPTION_AVAILABLE AvailableOptionUnavailable=0,availableoption,false,WESTRING_AVAILABLEOPTION_UNAVAILABLE // Explode Option ExplodeDontExplode=0,explodedontoption,true,WESTRING_EXPLODEDONTOPTION_EXPLODE ExplodeDontDont=0,explodedontoption,false,WESTRING_EXPLODEDONTOPTION_DONT // SuspendResume Option SuspendResumeSuspend=0,suspendresumeoption,true,WESTRING_SUSPENDRESUMEOPTION_SUSPEND SuspendResumeResume=0,suspendresumeoption,true,WESTRING_SUSPENDRESUMEOPTION_RESUME // Tournament Game Event Types GameEventTourneySoon=1,gameevent,EVENT_GAME_TOURNAMENT_FINISH_SOON,WESTRING_GAMEEVENT_TOURNAMENTFINISHSOON GameEventTourneyNow=1,gameevent,EVENT_GAME_TOURNAMENT_FINISH_NOW,WESTRING_GAMEEVENT_TOURNAMENTFINISHNOW // Mission Index // Tutorial MissionIndexT00=0,missionindex,bj_MISSION_INDEX_T00,WESTRING_MISSION_INDEX_T00 MissionIndexT01=0,missionindex,bj_MISSION_INDEX_T01,WESTRING_MISSION_INDEX_T01 // Human MissionIndexH00=0,missionindex,bj_MISSION_INDEX_H00,WESTRING_MISSION_INDEX_H00 MissionIndexH01=0,missionindex,bj_MISSION_INDEX_H01,WESTRING_MISSION_INDEX_H01 MissionIndexH02=0,missionindex,bj_MISSION_INDEX_H02,WESTRING_MISSION_INDEX_H02 MissionIndexH03=0,missionindex,bj_MISSION_INDEX_H03,WESTRING_MISSION_INDEX_H03 MissionIndexH04=0,missionindex,bj_MISSION_INDEX_H04,WESTRING_MISSION_INDEX_H04 MissionIndexH05=0,missionindex,bj_MISSION_INDEX_H05,WESTRING_MISSION_INDEX_H05 MissionIndexH06=0,missionindex,bj_MISSION_INDEX_H06,WESTRING_MISSION_INDEX_H06 MissionIndexH07=0,missionindex,bj_MISSION_INDEX_H07,WESTRING_MISSION_INDEX_H07 MissionIndexH08=0,missionindex,bj_MISSION_INDEX_H08,WESTRING_MISSION_INDEX_H08 MissionIndexH09=0,missionindex,bj_MISSION_INDEX_H09,WESTRING_MISSION_INDEX_H09 MissionIndexH10=0,missionindex,bj_MISSION_INDEX_H10,WESTRING_MISSION_INDEX_H10 MissionIndexH11=0,missionindex,bj_MISSION_INDEX_H11,WESTRING_MISSION_INDEX_H11 // Undead MissionIndexU00=0,missionindex,bj_MISSION_INDEX_U00,WESTRING_MISSION_INDEX_U00 MissionIndexU01=0,missionindex,bj_MISSION_INDEX_U01,WESTRING_MISSION_INDEX_U01 MissionIndexU02=0,missionindex,bj_MISSION_INDEX_U02,WESTRING_MISSION_INDEX_U02 MissionIndexU03=0,missionindex,bj_MISSION_INDEX_U03,WESTRING_MISSION_INDEX_U03 MissionIndexU05=0,missionindex,bj_MISSION_INDEX_U05,WESTRING_MISSION_INDEX_U05 MissionIndexU07=0,missionindex,bj_MISSION_INDEX_U07,WESTRING_MISSION_INDEX_U07 MissionIndexU08=0,missionindex,bj_MISSION_INDEX_U08,WESTRING_MISSION_INDEX_U08 MissionIndexU09=0,missionindex,bj_MISSION_INDEX_U09,WESTRING_MISSION_INDEX_U09 MissionIndexU10=0,missionindex,bj_MISSION_INDEX_U10,WESTRING_MISSION_INDEX_U10 MissionIndexU11=0,missionindex,bj_MISSION_INDEX_U11,WESTRING_MISSION_INDEX_U11 // Orc MissionIndexO00=0,missionindex,bj_MISSION_INDEX_O00,WESTRING_MISSION_INDEX_O00 MissionIndexO01=0,missionindex,bj_MISSION_INDEX_O01,WESTRING_MISSION_INDEX_O01 MissionIndexO02=0,missionindex,bj_MISSION_INDEX_O02,WESTRING_MISSION_INDEX_O02 MissionIndexO03=0,missionindex,bj_MISSION_INDEX_O03,WESTRING_MISSION_INDEX_O03 MissionIndexO04=0,missionindex,bj_MISSION_INDEX_O04,WESTRING_MISSION_INDEX_O04 MissionIndexO05=0,missionindex,bj_MISSION_INDEX_O05,WESTRING_MISSION_INDEX_O05 MissionIndexO06=0,missionindex,bj_MISSION_INDEX_O06,WESTRING_MISSION_INDEX_O06 MissionIndexO07=0,missionindex,bj_MISSION_INDEX_O07,WESTRING_MISSION_INDEX_O07 MissionIndexO08=0,missionindex,bj_MISSION_INDEX_O08,WESTRING_MISSION_INDEX_O08 MissionIndexO09=0,missionindex,bj_MISSION_INDEX_O09,WESTRING_MISSION_INDEX_O09 MissionIndexO10=0,missionindex,bj_MISSION_INDEX_O10,WESTRING_MISSION_INDEX_O10 // Night Elf MissionIndexN00=0,missionindex,bj_MISSION_INDEX_N00,WESTRING_MISSION_INDEX_N00 MissionIndexN01=0,missionindex,bj_MISSION_INDEX_N01,WESTRING_MISSION_INDEX_N01 MissionIndexN02=0,missionindex,bj_MISSION_INDEX_N02,WESTRING_MISSION_INDEX_N02 MissionIndexN03=0,missionindex,bj_MISSION_INDEX_N03,WESTRING_MISSION_INDEX_N03 MissionIndexN04=0,missionindex,bj_MISSION_INDEX_N04,WESTRING_MISSION_INDEX_N04 MissionIndexN05=0,missionindex,bj_MISSION_INDEX_N05,WESTRING_MISSION_INDEX_N05 MissionIndexN06=0,missionindex,bj_MISSION_INDEX_N06,WESTRING_MISSION_INDEX_N06 MissionIndexN07=0,missionindex,bj_MISSION_INDEX_N07,WESTRING_MISSION_INDEX_N07 // Expansion Night Elf MissionIndexXN00=1,missionindex,bj_MISSION_INDEX_XN00,WESTRING_MISSION_INDEX_XN00 MissionIndexXN01=1,missionindex,bj_MISSION_INDEX_XN01,WESTRING_MISSION_INDEX_XN01 MissionIndexXN02=1,missionindex,bj_MISSION_INDEX_XN02,WESTRING_MISSION_INDEX_XN02 MissionIndexXN03=1,missionindex,bj_MISSION_INDEX_XN03,WESTRING_MISSION_INDEX_XN03 MissionIndexXN04=1,missionindex,bj_MISSION_INDEX_XN04,WESTRING_MISSION_INDEX_XN04 MissionIndexXN05=1,missionindex,bj_MISSION_INDEX_XN05,WESTRING_MISSION_INDEX_XN05 MissionIndexXN06=1,missionindex,bj_MISSION_INDEX_XN06,WESTRING_MISSION_INDEX_XN06 MissionIndexXN07=1,missionindex,bj_MISSION_INDEX_XN07,WESTRING_MISSION_INDEX_XN07 MissionIndexXN08=1,missionindex,bj_MISSION_INDEX_XN08,WESTRING_MISSION_INDEX_XN08 MissionIndexXN09=1,missionindex,bj_MISSION_INDEX_XN09,WESTRING_MISSION_INDEX_XN09 MissionIndexXN10=1,missionindex,bj_MISSION_INDEX_XN10,WESTRING_MISSION_INDEX_XN10 // Expansion Human MissionIndexXH00=1,missionindex,bj_MISSION_INDEX_XH00,WESTRING_MISSION_INDEX_XH00 MissionIndexXH01=1,missionindex,bj_MISSION_INDEX_XH01,WESTRING_MISSION_INDEX_XH01 MissionIndexXH02=1,missionindex,bj_MISSION_INDEX_XH02,WESTRING_MISSION_INDEX_XH02 MissionIndexXH03=1,missionindex,bj_MISSION_INDEX_XH03,WESTRING_MISSION_INDEX_XH03 MissionIndexXH04=1,missionindex,bj_MISSION_INDEX_XH04,WESTRING_MISSION_INDEX_XH04 MissionIndexXH05=1,missionindex,bj_MISSION_INDEX_XH05,WESTRING_MISSION_INDEX_XH05 MissionIndexXH06=1,missionindex,bj_MISSION_INDEX_XH06,WESTRING_MISSION_INDEX_XH06 MissionIndexXH07=1,missionindex,bj_MISSION_INDEX_XH07,WESTRING_MISSION_INDEX_XH07 MissionIndexXH08=1,missionindex,bj_MISSION_INDEX_XH08,WESTRING_MISSION_INDEX_XH08 MissionIndexXH09=1,missionindex,bj_MISSION_INDEX_XH09,WESTRING_MISSION_INDEX_XH09 // Expansion Undead MissionIndexXU00=1,missionindex,bj_MISSION_INDEX_XU00,WESTRING_MISSION_INDEX_XU00 MissionIndexXU01=1,missionindex,bj_MISSION_INDEX_XU01,WESTRING_MISSION_INDEX_XU01 MissionIndexXU02=1,missionindex,bj_MISSION_INDEX_XU02,WESTRING_MISSION_INDEX_XU02 MissionIndexXU03=1,missionindex,bj_MISSION_INDEX_XU03,WESTRING_MISSION_INDEX_XU03 MissionIndexXU04=1,missionindex,bj_MISSION_INDEX_XU04,WESTRING_MISSION_INDEX_XU04 MissionIndexXU05=1,missionindex,bj_MISSION_INDEX_XU05,WESTRING_MISSION_INDEX_XU05 MissionIndexXU06=1,missionindex,bj_MISSION_INDEX_XU06,WESTRING_MISSION_INDEX_XU06 MissionIndexXU07=1,missionindex,bj_MISSION_INDEX_XU07,WESTRING_MISSION_INDEX_XU07 MissionIndexXU08=1,missionindex,bj_MISSION_INDEX_XU08,WESTRING_MISSION_INDEX_XU08 MissionIndexXU09=1,missionindex,bj_MISSION_INDEX_XU09,WESTRING_MISSION_INDEX_XU09 MissionIndexXU10=1,missionindex,bj_MISSION_INDEX_XU10,WESTRING_MISSION_INDEX_XU10 MissionIndexXU11=1,missionindex,bj_MISSION_INDEX_XU11,WESTRING_MISSION_INDEX_XU11 MissionIndexXU12=1,missionindex,bj_MISSION_INDEX_XU12,WESTRING_MISSION_INDEX_XU12 MissionIndexXU13=1,missionindex,bj_MISSION_INDEX_XU13,WESTRING_MISSION_INDEX_XU13 // Expansion Orc MissionIndexXO00=1,missionindex,bj_MISSION_INDEX_XO00,WESTRING_MISSION_INDEX_XO00 // Campaign Index CampaignIndexT=0,campaignindex,bj_CAMPAIGN_INDEX_T,WESTRING_CAMPAIGN_INDEX_T CampaignIndexH=0,campaignindex,bj_CAMPAIGN_INDEX_H,WESTRING_CAMPAIGN_INDEX_H CampaignIndexU=0,campaignindex,bj_CAMPAIGN_INDEX_U,WESTRING_CAMPAIGN_INDEX_U CampaignIndexO=0,campaignindex,bj_CAMPAIGN_INDEX_O,WESTRING_CAMPAIGN_INDEX_O CampaignIndexN=0,campaignindex,bj_CAMPAIGN_INDEX_N,WESTRING_CAMPAIGN_INDEX_N CampaignIndexXN=1,campaignindex,bj_CAMPAIGN_INDEX_XN,WESTRING_CAMPAIGN_INDEX_XN CampaignIndexXH=1,campaignindex,bj_CAMPAIGN_INDEX_XH,WESTRING_CAMPAIGN_INDEX_XH CampaignIndexXU=1,campaignindex,bj_CAMPAIGN_INDEX_XU,WESTRING_CAMPAIGN_INDEX_XU CampaignIndexXO=1,campaignindex,bj_CAMPAIGN_INDEX_XO,WESTRING_CAMPAIGN_INDEX_XO // Cinematic Index CinematicIndexTOP=0,cinematicindex,bj_CINEMATICINDEX_TOP,WESTRING_CINEMATICTYPE_TOP CinematicIndexHOP=0,cinematicindex,bj_CINEMATICINDEX_HOP,WESTRING_CINEMATICTYPE_HOP CinematicIndexHED=0,cinematicindex,bj_CINEMATICINDEX_HED,WESTRING_CINEMATICTYPE_HED CinematicIndexUED=0,cinematicindex,bj_CINEMATICINDEX_UED,WESTRING_CINEMATICTYPE_UED CinematicIndexOED=0,cinematicindex,bj_CINEMATICINDEX_OED,WESTRING_CINEMATICTYPE_OED CinematicIndexNED=0,cinematicindex,bj_CINEMATICINDEX_NED,WESTRING_CINEMATICTYPE_NED CinematicIndexXOP=1,cinematicindex,bj_CINEMATICINDEX_XOP,WESTRING_CINEMATICTYPE_XOP CinematicIndexXED=1,cinematicindex,bj_CINEMATICINDEX_XED,WESTRING_CINEMATICTYPE_XED // Trigger Unit-Targeted Unit Orders // Common UnitOrderAttackUnit=0,unitorderutarg,`attack`,WESTRING_UNITORDERUTARG_ATTACK UnitOrderAttackUnitOnce=0,unitorderutarg,`attackonce`,WESTRING_UNITORDERUTARG_ATTACKONCE UnitOrderMoveUnit=0,unitorderutarg,`move`,WESTRING_UNITORDERUTARG_MOVE UnitOrderSmartUnit=1,unitorderutarg,`smart`,WESTRING_UNITORDERUTARG_SMART UnitOrderHarvest=0,unitorderutarg,`harvest`,WESTRING_UNITORDERUTARG_HARVEST UnitOrderRevive=0,unitorderutarg,`revive`,WESTRING_UNITORDERUTARG_REVIVE UnitOrderLoad=0,unitorderutarg,`load`,WESTRING_UNITORDERUTARG_LOAD UnitOrderUnload=0,unitorderutarg,`unload`,WESTRING_UNITORDERUTARG_UNLOAD UnitOrderBoard=0,unitorderutarg,`board`,WESTRING_UNITORDERUTARG_BOARD UnitOrderForceBoard=0,unitorderutarg,`forceboard`,WESTRING_UNITORDERUTARG_FORCEBOARD // Human UnitOrderRepair=0,unitorderutarg,`repair`,WESTRING_UNITORDERUTARG_REPAIR UnitOrderInnerFire=0,unitorderutarg,`innerfire`,WESTRING_UNITORDERUTARG_INNERFIRE UnitOrderDispel=0,unitorderutarg,`dispel`,WESTRING_UNITORDERUTARG_DISPEL UnitOrderHeal=0,unitorderutarg,`heal`,WESTRING_UNITORDERUTARG_HEAL UnitOrderSlow=0,unitorderutarg,`slow`,WESTRING_UNITORDERUTARG_SLOW UnitOrderInvisibility=0,unitorderutarg,`invisibility`,WESTRING_UNITORDERUTARG_INVISIBILITY UnitOrderPolymorph=0,unitorderutarg,`polymorph`,WESTRING_UNITORDERUTARG_POLYMORPH UnitOrderControlMagic=1,unitorderutarg,`controlmagic`,WESTRING_UNITORDERUTARG_CONTROLMAGIC UnitOrderSpellSteal=1,unitorderutarg,`spellsteal`,WESTRING_UNITORDERUTARG_SPELLSTEAL UnitOrderAerialShackles=1,unitorderutarg,`magicleash`,WESTRING_UNITORDERUTARG_AERIALSHACKLES UnitOrderMassTeleport=0,unitorderutarg,`massteleport`,WESTRING_UNITORDERUTARG_MASSTELEPORT UnitOrderBanish=1,unitorderutarg,`banish`,WESTRING_UNITORDERUTARG_BANISH UnitOrderSiphonMana=1,unitorderutarg,`drain`,WESTRING_UNITORDERUTARG_SIPHONMANA UnitOrderThunderBolt=0,unitorderutarg,`thunderbolt`,WESTRING_UNITORDERUTARG_THUNDERBOLT UnitOrderHolyBolt=0,unitorderutarg,`holybolt`,WESTRING_UNITORDERUTARG_HOLYBOLT // Orc UnitOrderRepairO=0,unitorderutarg,`repair`,WESTRING_UNITORDERUTARG_REPAIRO UnitOrderEnsnare=0,unitorderutarg,`ensnare`,WESTRING_UNITORDERUTARG_ENSNARE UnitOrderUnstableConcoction=1,unitorderutarg,`unstableconcoction`,WESTRING_UNITORDERUTARG_UNSTABLECONCOCTION UnitOrderPurge=0,unitorderutarg,`purge`,WESTRING_UNITORDERUTARG_PURGE UnitOrderLightningShield=0,unitorderutarg,`lightningshield`,WESTRING_UNITORDERUTARG_LIGHTNINGSHIELD UnitOrderBloodlust=0,unitorderutarg,`bloodlust`,WESTRING_UNITORDERUTARG_BLOODLUST UnitOrderSpiritLink=1,unitorderutarg,`spiritlink`,WESTRING_UNITORDERUTARG_SPIRITLINK UnitOrderDevour=0,unitorderutarg,`devour`,WESTRING_UNITORDERUTARG_DEVOUR UnitOrderChainLightning=0,unitorderutarg,`chainlightning`,WESTRING_UNITORDERUTARG_CHAINLIGHTNING UnitOrderHealingWave=1,unitorderutarg,`healingwave`,WESTRING_UNITORDERUTARG_HEALINGWAVE UnitOrderHex=1,unitorderutarg,`hex`,WESTRING_UNITORDERUTARG_HEX UnitOrderAncestralSpiritTarg=1,unitorderutarg,`ancestralspirittarg`,WESTRING_UNITORDERUTARG_ANCESTRALSPIRIT // Night Elf UnitOrderRenew=0,unitorderutarg,`renew`,WESTRING_UNITORDERUTARG_RENEW UnitOrderEntangle=0,unitorderutarg,`entangle`,WESTRING_UNITORDERUTARG_ENTANGLE UnitOrderEntangleInstant=0,unitorderutarg,`entangleinstant`,WESTRING_UNITORDERUTARG_ENTANGLEINSTANT UnitOrderReplenish=0,unitorderutarg,`recharge`,WESTRING_UNITORDERUTARG_REPLENISH UnitOrderMountHippogryph=0,unitorderutarg,`mounthippogryph`,WESTRING_UNITORDERUTARG_MOUNTHIPPOGRYPH UnitOrderLoadArcher=0,unitorderutarg,`loadarcher`,WESTRING_UNITORDERUTARG_LOADARCHER UnitOrderAutoDispel=0,unitorderutarg,`autodispel`,WESTRING_UNITORDERUTARG_AUTODISPEL UnitOrderFaerieFire=0,unitorderutarg,`faeriefire`,WESTRING_UNITORDERUTARG_FAERIEFIRE UnitOrderCyclone=0,unitorderutarg,`cyclone`,WESTRING_UNITORDERUTARG_CYCLONE UnitOrderRejuvination=0,unitorderutarg,`rejuvination`,WESTRING_UNITORDERUTARG_REJUVINATION UnitOrderVengeance=1,unitorderutarg,`vengeance`,WESTRING_UNITORDERUTARG_VENGEANCE UnitOrderManaBurn=0,unitorderutarg,`manaburn`,WESTRING_UNITORDERUTARG_MANABURN UnitOrderEntanglingRoots=0,unitorderutarg,`entanglingroots`,WESTRING_UNITORDERUTARG_ENTANGLINGROOTS UnitOrderShadowStrike=1,unitorderutarg,`shadowstrike`,WESTRING_UNITORDERUTARG_SHADOWSTRIKE // Undead UnitOrderRestoration=0,unitorderutarg,`restoration`,WESTRING_UNITORDERUTARG_RESTORE UnitOrderSacrificeAcolyte=0,unitorderutarg,`sacrifice`,WESTRING_UNITORDERUTARG_SACRIFICEACOLYTE UnitOrderSacrifice=0,unitorderutarg,`requestsacrifice`,WESTRING_UNITORDERUTARG_SACRIFICE UnitOrderUnsummon=0,unitorderutarg,`unsummon`,WESTRING_UNITORDERUTARG_UNSUMMON UnitOrderWeb=0,unitorderutarg,`web`,WESTRING_UNITORDERUTARG_WEB UnitOrderRaiseDead=0,unitorderutarg,`raisedead`,WESTRING_UNITORDERUTARG_RAISEDEAD UnitOrderUnholyFrenzy=0,unitorderutarg,`unholyfrenzy`,WESTRING_UNITORDERUTARG_UNHOLYFRENZY UnitOrderCripple=0,unitorderutarg,`cripple`,WESTRING_UNITORDERUTARG_CRIPPLE UnitOrderCurse=0,unitorderutarg,`curse`,WESTRING_UNITORDERUTARG_CURSE UnitOrderAntiMagicShell=0,unitorderutarg,`antimagicshell`,WESTRING_UNITORDERUTARG_ANTIMAGICSHELL UnitOrderPossession=0,unitorderutarg,`possession`,WESTRING_UNITORDERUTARG_POSSESSION UnitOrderAbsorbMana=1,unitorderutarg,`absorb`,WESTRING_UNITORDERUTARG_ABSORBMANA UnitOrderFlamingAttack=1,unitorderutarg,`flamingattacktarg`,WESTRING_UNITORDERUTARG_FLAMINGATTACK UnitOrderImpale=1,unitorderutarg,`impale`,WESTRING_UNITORDERUTARG_IMPALE UnitOrderCarrionScarabs=1,unitorderutarg,`carrionscarabs`,WESTRING_UNITORDERUTARG_CARRIONSCARABS UnitOrderDeathCoil=0,unitorderutarg,`deathcoil`,WESTRING_UNITORDERUTARG_DEATHCOIL UnitOrderDeathPact=0,unitorderutarg,`deathpact`,WESTRING_UNITORDERUTARG_DEATHPACT UnitOrderSleep=0,unitorderutarg,`sleep`,WESTRING_UNITORDERUTARG_SLEEP UnitOrderFrostNova=0,unitorderutarg,`frostnova`,WESTRING_UNITORDERUTARG_FROSTNOVA UnitOrderFrostArmor=0,unitorderutarg,`frostarmor`,WESTRING_UNITORDERUTARG_FROSTARMOR UnitOrderDarkRitual=0,unitorderutarg,`darkritual`,WESTRING_UNITORDERUTARG_DARKRITUAL // Neutral UnitOrderCreepDevour=1,unitorderutarg,`creepdevour`,WESTRING_UNITORDERUTARG_CREEPDEVOUR UnitOrderFirebolt=0,unitorderutarg,`firebolt`,WESTRING_UNITORDERUTARG_FIREBOLT UnitOrderCreepHeal=0,unitorderutarg,`creepheal`,WESTRING_UNITORDERUTARG_CREEPHEAL UnitOrderCreepThunderBolt=0,unitorderutarg,`creepthunderbolt`,WESTRING_UNITORDERUTARG_CREEPTHUNDERBOLT UnitOrderParasite=1,unitorderutarg,`parasite`,WESTRING_UNITORDERUTARG_PARASITE UnitOrderSelfDestructUnit=1,unitorderutarg,`selfdestruct`,WESTRING_UNITORDERUTARG_SELFDESTRUCT UnitOrderBlackArrow=1,unitorderutarg,`blackarrow`,WESTRING_UNITORDERUTARG_BLACKARROW UnitOrderCharm=1,unitorderutarg,`charm`,WESTRING_UNITORDERUTARG_CHARM UnitOrderLifeDrain=1,unitorderutarg,`drain`,WESTRING_UNITORDERUTARG_LIFEDRAIN UnitOrderColdArrow=1,unitorderutarg,`coldarrowstarg`,WESTRING_UNITORDERUTARG_COLDARROW UnitOrderForkedLightning=1,unitorderutarg,`forkedlightning`,WESTRING_UNITORDERUTARG_FORKEDLIGHTNING UnitOrderStrongDrink=1,unitorderutarg,`drunkenhaze`,WESTRING_UNITORDERUTARG_STRONGDRINK UnitOrderDoom=1,unitorderutarg,`doom`,WESTRING_UNITORDERUTARG_DOOM UnitOrderAcidBomb=1,unitorderutarg,`acidbomb`,WESTRING_UNITORDERUTARG_ACIDBOMB UnitOrderTransmute=1,unitorderutarg,`transmute`,WESTRING_UNITORDERUTARG_TRANSMUTE UnitOrderSoulBurn=1,unitorderutarg,`soulburn`,WESTRING_UNITORDERUTARG_SOULBURN UnitOrderPoisonArrow=0,unitorderutarg,`poisonarrowstarg`,WESTRING_UNITORDERUTARG_POISONARROW UnitOrderIncinerateArrow=1,unitorderutarg,`incineratearrow`,WESTRING_UNITORDERUTARG_INCINERATEARROW // Special UnitOrderFingerOfDeath=0,unitorderutarg,`fingerofdeath`,WESTRING_UNITORDERUTARG_FINGEROFDEATH UnitOrderDarkConversion=0,unitorderutarg,`darkconversion`,WESTRING_UNITORDERUTARG_DARKCONVERSION UnitOrderSoulPreservation=0,unitorderutarg,`soulpreservation`,WESTRING_UNITORDERUTARG_SOULPRESERVATION UnitOrderDarkConversionFast=0,unitorderutarg,`darkconversion`,WESTRING_UNITORDERUTARG_DARKCONVERSIONFAST // Trigger Point-Targeted Unit Orders // Common UnitOrderAttack=0,unitorderptarg,`attack`,WESTRING_UNITORDERPTARG_ATTACK UnitOrderAttackGround=0,unitorderptarg,`attackground`,WESTRING_UNITORDERPTARG_ATTACKGROUND UnitOrderMove=0,unitorderptarg,`move`,WESTRING_UNITORDERPTARG_MOVE UnitOrderPatrol=0,unitorderptarg,`patrol`,WESTRING_UNITORDERPTARG_PATROL UnitOrderSmartPoint=1,unitorderptarg,`smart`,WESTRING_UNITORDERPTARG_SMART UnitOrderSetRally=0,unitorderptarg,`setrally`,WESTRING_UNITORDERPTARG_SETRALLY UnitOrderUnloadAll=0,unitorderptarg,`unloadall`,WESTRING_UNITORDERPTARG_UNLOADALL // Human UnitOrderFlare=0,unitorderptarg,`flare`,WESTRING_UNITORDERPTARG_FLARE UnitOrderCloudOfFog=1,unitorderptarg,`cloudoffog`,WESTRING_UNITORDERPTARG_CLOUDOFFOG UnitOrderBlizzard=0,unitorderptarg,`blizzard`,WESTRING_UNITORDERPTARG_BLIZZARD UnitOrderFlameStrike=1,unitorderptarg,`flamestrike`,WESTRING_UNITORDERPTARG_FLAMESTRIKE // Orc UnitOrderSentryWard=0,unitorderptarg,`evileye`,WESTRING_UNITORDERPTARG_SENTRYWARD UnitOrderStasisTrap=0,unitorderptarg,`stasistrap`,WESTRING_UNITORDERPTARG_STASISTRAP UnitOrderHealingWard=0,unitorderptarg,`healingward`,WESTRING_UNITORDERPTARG_HEALINGWARD UnitOrderDisenchant=1,unitorderptarg,`disenchant`,WESTRING_UNITORDERPTARG_DISENCHANT UnitOrderFarSight=0,unitorderptarg,`farsight`,WESTRING_UNITORDERPTARG_FARSIGHT UnitOrderEarthquake=0,unitorderptarg,`earthquake`,WESTRING_UNITORDERPTARG_EARTHQUAKE UnitOrderSerpentWard=1,unitorderptarg,`ward`,WESTRING_UNITORDERPTARG_SERPENTWARD UnitOrderShockwave=0,unitorderptarg,`shockwave`,WESTRING_UNITORDERPTARG_SHOCKWAVE // Night Elf UnitOrderRoot=0,unitorderptarg,`root`,WESTRING_UNITORDERPTARG_ROOT UnitOrderDetonate=0,unitorderptarg,`detonate`,WESTRING_UNITORDERPTARG_DETONATE UnitOrderForceOfNature=0,unitorderptarg,`forceofnature`,WESTRING_UNITORDERPTARG_FORCEOFNATURE UnitOrderStarfall=0,unitorderptarg,`obsolete`,WESTRING_UNITORDERPTARG_STARFALL UnitOrderBlink=1,unitorderptarg,`blink`,WESTRING_UNITORDERPTARG_BLINK // Undead UnitOrderDevourMagic=1,unitorderptarg,`devourmagic`,WESTRING_UNITORDERPTARG_DEVOURMAGIC UnitOrderImpalePoint=1,unitorderptarg,`impale`,WESTRING_UNITORDERPTARG_IMPALE UnitOrderCarrionSwarm=0,unitorderptarg,`carrionswarm`,WESTRING_UNITORDERPTARG_CARRIONSWARM UnitOrderDarkSummoning=0,unitorderptarg,`dreadlordinferno`,WESTRING_UNITORDERPTARG_DARKSUMMONING UnitOrderDeathAndDecay=0,unitorderptarg,`deathanddecay`,WESTRING_UNITORDERPTARG_DEATHANDDECAY // Neutral UnitOrderBreathOfFrost=1,unitorderptarg,`breathoffrost`,WESTRING_UNITORDERPTARG_BREATHOFFROST UnitOrderMonsoon=1,unitorderptarg,`monsoon`,WESTRING_UNITORDERPTARG_MONSOON UnitOrderSelfDestruct=0,unitorderptarg,`selfdestruct`,WESTRING_UNITORDERPTARG_SELFDESTRUCT UnitOrderStampede=1,unitorderptarg,`stampede`,WESTRING_UNITORDERPTARG_STAMPEDE UnitOrderSilence=1,unitorderptarg,`silence`,WESTRING_UNITORDERPTARG_SILENCE UnitOrderTornado=1,unitorderptarg,`tornado`,WESTRING_UNITORDERPTARG_TORNADO UnitOrderBreathOfFire=1,unitorderptarg,`breathoffire`,WESTRING_UNITORDERPTARG_BREATHOFFIRE UnitOrderHeroRainOfFire=1,unitorderptarg,`rainoffire`,WESTRING_UNITORDERPTARG_HERORAINOFFIRE UnitOrderHealingSpray=1,unitorderptarg,`healingspray`,WESTRING_UNITORDERPTARG_HEALINGSPRAY UnitOrderClusterRockets=1,unitorderptarg,`clusterrockets`,WESTRING_UNITORDERPTARG_CLUSTERROCKETS UnitOrderSummonFactory=1,unitorderptarg,`summonfactory`,WESTRING_UNITORDERPTARG_SUMMONFACTORY UnitOrderVolcano=1,unitorderptarg,`volcano`,WESTRING_UNITORDERPTARG_VOLCANO // Special UnitOrderDarkPortal=0,unitorderptarg,`darkportal`,WESTRING_UNITORDERPTARG_DARKPORTAL UnitOrderRainOfChaos=0,unitorderptarg,`rainoffire`,WESTRING_UNITORDERPTARG_RAINOFCHAOS UnitOrderRainOfFire=0,unitorderptarg,`rainoffire`,WESTRING_UNITORDERPTARG_RAINOFFIRE UnitOrderInferno=0,unitorderptarg,`inferno`,WESTRING_UNITORDERPTARG_INFERNO UnitOrderDarkSummoningOld=0,unitorderptarg,`darksummoning`,WESTRING_UNITORDERPTARG_DARKSUMMONINGOLD // Trigger Destructible-Targeted Unit Orders // Common UnitOrderAttackDestructible=0,unitorderdtarg,`attack`,WESTRING_UNITORDERDTARG_ATTACK UnitOrderSmartDestructible=1,unitorderdtarg,`smart`,WESTRING_UNITORDERDTARG_SMART UnitOrderHarvestDestructible=0,unitorderdtarg,`harvest`,WESTRING_UNITORDERDTARG_HARVEST // Human // Orc // Night Elf UnitOrderConsumeTree=0,unitorderdtarg,`eattree`,WESTRING_UNITORDERDTARG_CONSUMETREE UnitOrderSentinel=0,unitorderdtarg,`sentinel`,WESTRING_UNITORDERDTARG_SENTINEL UnitOrderGrabTree=1,unitorderdtarg,`grabtree`,WESTRING_UNITORDERDTARG_GRABTREE // Undead // Neutral // Special // Trigger Item-Targeted Unit Orders // Common UnitOrderAttackItem=1,unitorderitarg,`attack`,WESTRING_UNITORDERITARG_ATTACK UnitOrderAttackItemOnce=1,unitorderitarg,`attackonce`,WESTRING_UNITORDERITARG_ATTACKONCE UnitOrderMoveItem=1,unitorderitarg,`move`,WESTRING_UNITORDERITARG_MOVE UnitOrderSmartItem=1,unitorderitarg,`smart`,WESTRING_UNITORDERITARG_SMART // Trigger Immediate / Untargeted Unit Orders // Common UnitOrderStop=0,unitordernotarg,`stop`,WESTRING_UNITORDERNOTARG_STOP UnitOrderHoldPosition=0,unitordernotarg,`holdposition`,WESTRING_UNITORDERNOTARG_HOLDPOSITION UnitOrderAutoHarvestGold=0,unitordernotarg,`autoharvestgold`,WESTRING_UNITORDERNOTARG_AUTOHARVESTGOLD UnitOrderAutoHarvestLumber=0,unitordernotarg,`autoharvestlumber`,WESTRING_UNITORDERNOTARG_AUTOHARVESTLUMBER UnitOrderReturnResources=0,unitordernotarg,`returnresources`,WESTRING_UNITORDERNOTARG_RETURNRESOURCES UnitOrderBuild=1,unitordernotarg,`build`,WESTRING_UNITORDERNOTARG_BUILD UnitOrderLevelup=1,unitordernotarg,`levelup`,WESTRING_UNITORDERNOTARG_LEVELUP // Human UnitOrderHumanBuild=1,unitordernotarg,`humanbuild`,WESTRING_UNITORDERNOTARG_HUMANBUILD UnitOrderTownBellOn=0,unitordernotarg,`townbellon`,WESTRING_UNITORDERNOTARG_TOWNBELLON UnitOrderTownBellOff=0,unitordernotarg,`townbelloff`,WESTRING_UNITORDERNOTARG_TOWNBELLOFF UnitOrderMilitia=0,unitordernotarg,`militia`,WESTRING_UNITORDERNOTARG_MILITIA UnitOrderMilitiaOff=0,unitordernotarg,`militiaoff`,WESTRING_UNITORDERNOTARG_MILITIAOFF UnitOrderRepairOn=0,unitordernotarg,`repairon`,WESTRING_UNITORDERNOTARG_REPAIRON UnitOrderRepairOff=0,unitordernotarg,`repairoff`,WESTRING_UNITORDERNOTARG_REPAIROFF UnitOrderDefend=0,unitordernotarg,`defend`,WESTRING_UNITORDERNOTARG_DEFEND UnitOrderUnDefend=0,unitordernotarg,`undefend`,WESTRING_UNITORDERNOTARG_UNDEFEND UnitOrderHealOn=0,unitordernotarg,`healon`,WESTRING_UNITORDERNOTARG_HEALON UnitOrderHealOff=0,unitordernotarg,`healoff`,WESTRING_UNITORDERNOTARG_HEALOFF UnitOrderInnerFireOn=0,unitordernotarg,`innerfireon`,WESTRING_UNITORDERNOTARG_INNERFIREON UnitOrderInnerFireOff=0,unitordernotarg,`innerfireoff`,WESTRING_UNITORDERNOTARG_INNERFIREOFF UnitOrderSlowOn=0,unitordernotarg,`slowon`,WESTRING_UNITORDERNOTARG_SLOWON UnitOrderSlowOff=0,unitordernotarg,`slowoff`,WESTRING_UNITORDERNOTARG_SLOWOFF UnitOrderSpellStealOn=1,unitordernotarg,`spellstealon`,WESTRING_UNITORDERNOTARG_SPELLSTEALON UnitOrderSpellStealOff=1,unitordernotarg,`spellstealoff`,WESTRING_UNITORDERNOTARG_SPELLSTEALOFF UnitOrderWaterElemental=0,unitordernotarg,`waterelemental`,WESTRING_UNITORDERNOTARG_WATERELEMENTAL UnitOrderPhoenix=1,unitordernotarg,`phoenix`,WESTRING_UNITORDERNOTARG_PHOENIX UnitOrderThunderClap=0,unitordernotarg,`thunderclap`,WESTRING_UNITORDERNOTARG_THUNDERCLAP UnitOrderAvatar=0,unitordernotarg,`avatar`,WESTRING_UNITORDERNOTARG_AVATAR UnitOrderDivineShield=0,unitordernotarg,`divineshield`,WESTRING_UNITORDERNOTARG_DIVINESHIELD UnitOrderUnDivineShield=0,unitordernotarg,`undivineshield`,WESTRING_UNITORDERNOTARG_UNDIVINESHIELD UnitOrderResurrection=0,unitordernotarg,`resurrection`,WESTRING_UNITORDERNOTARG_RESURRECTION // Orc UnitOrderOrcBuild=1,unitordernotarg,`orcbuild`,WESTRING_UNITORDERNOTARG_ORCBUILD UnitOrderBattleStations=0,unitordernotarg,`battlestations`,WESTRING_UNITORDERNOTARG_BATTLESTATIONS UnitOrderStandDown=0,unitordernotarg,`standdown`,WESTRING_UNITORDERNOTARG_STANDDOWN UnitOrderRepairOOn=0,unitordernotarg,`repairon`,WESTRING_UNITORDERNOTARG_REPAIROON UnitOrderRepairOOff=0,unitordernotarg,`repairoff`,WESTRING_UNITORDERNOTARG_REPAIROOFF UnitOrderBerserk=1,unitordernotarg,`berserk`,WESTRING_UNITORDERNOTARG_BERSERK UnitOrderBloodlustOn=0,unitordernotarg,`bloodluston`,WESTRING_UNITORDERNOTARG_BLOODLUSTON UnitOrderBloodlustOff=0,unitordernotarg,`bloodlustoff`,WESTRING_UNITORDERNOTARG_BLOODLUSTOFF UnitOrderAncestralSpirit=1,unitordernotarg,`ancestralspirit`,WESTRING_UNITORDERNOTARG_ANCESTRALSPIRIT UnitOrderEtherealForm=1,unitordernotarg,`uncorporealform`,WESTRING_UNITORDERNOTARG_ETHEREALFORM UnitOrderCorporealForm=1,unitordernotarg,`corporealform`,WESTRING_UNITORDERNOTARG_CORPOREALFORM UnitOrderWindWalk=0,unitordernotarg,`windwalk`,WESTRING_UNITORDERNOTARG_WINDWALK UnitOrderMirrorImage=0,unitordernotarg,`mirrorimage`,WESTRING_UNITORDERNOTARG_MIRRORIMAGE UnitOrderWhirlWind=0,unitordernotarg,`whirlwind`,WESTRING_UNITORDERNOTARG_BLADESTORM UnitOrderSpiritWolf=0,unitordernotarg,`spiritwolf`,WESTRING_UNITORDERNOTARG_FERALSPIRIT UnitOrderVoodoo=1,unitordernotarg,`voodoo`,WESTRING_UNITORDERNOTARG_VOODOO UnitOrderStomp=0,unitordernotarg,`stomp`,WESTRING_UNITORDERNOTARG_WARSTOMP // Night Elf UnitOrderNightElfBuild=1,unitordernotarg,`nightelfbuild`,WESTRING_UNITORDERNOTARG_NIGHTELFBUILD UnitOrderUnRoot=0,unitordernotarg,`unroot`,WESTRING_UNITORDERNOTARG_UNROOT UnitOrderAutoEntangle=1,unitordernotarg,`autoentangle`,WESTRING_UNITORDERNOTARG_AUTOENTANGLE UnitOrderAutoEntangleInstant=1,unitordernotarg,`autoentangleinstant`,WESTRING_UNITORDERNOTARG_AUTOENTANGLEINSTANT UnitOrderReplenishOn=1,unitordernotarg,`rechargeon`,WESTRING_UNITORDERNOTARG_REPLENISHON UnitOrderReplenishOff=1,unitordernotarg,`rechargeoff`,WESTRING_UNITORDERNOTARG_REPLENISHOFF UnitOrderAmbush=0,unitordernotarg,`ambush`,WESTRING_UNITORDERNOTARG_HIDE UnitOrderRenewOn=0,unitordernotarg,`renewon`,WESTRING_UNITORDERNOTARG_RENEWON UnitOrderRenewOff=0,unitordernotarg,`renewoff`,WESTRING_UNITORDERNOTARG_RENEWOFF UnitOrderCoupleInstant1=1,unitordernotarg,`coupleinstant`,WESTRING_UNITORDERNOTARG_COUPLEINSTANT1 UnitOrderCoupleInstant2=1,unitordernotarg,`coupleinstant`,WESTRING_UNITORDERNOTARG_COUPLEINSTANT2 UnitOrderDecouple=1,unitordernotarg,`decouple`,WESTRING_UNITORDERNOTARG_DECOUPLE UnitOrderAutoDispelOn=0,unitordernotarg,`autodispelon`,WESTRING_UNITORDERNOTARG_AUTODISPELON UnitOrderAutoDispelOff=0,unitordernotarg,`autodispeloff`,WESTRING_UNITORDERNOTARG_AUTODISPELOFF UnitOrderFaerieFireOn=0,unitordernotarg,`faeriefireon`,WESTRING_UNITORDERNOTARG_FAERIEFIREON UnitOrderFaerieFireOff=0,unitordernotarg,`faeriefireoff`,WESTRING_UNITORDERNOTARG_FAERIEFIREOFF UnitOrderRavenForm=0,unitordernotarg,`ravenform`,WESTRING_UNITORDERNOTARG_RAVENFORM UnitOrderUnRavenForm=0,unitordernotarg,`unravenform`,WESTRING_UNITORDERNOTARG_UNRAVENFORM UnitOrderRoar=0,unitordernotarg,`roar`,WESTRING_UNITORDERNOTARG_ROAR UnitOrderBearForm=0,unitordernotarg,`bearform`,WESTRING_UNITORDERNOTARG_BEARFORM UnitOrderUnBearForm=0,unitordernotarg,`unbearform`,WESTRING_UNITORDERNOTARG_UNBEARFORM UnitOrderTaunt=1,unitordernotarg,`taunt`,WESTRING_UNITORDERNOTARG_TAUNT UnitOrderManaFlareOn=1,unitordernotarg,`manaflareon`,WESTRING_UNITORDERNOTARG_MANAFLAREON UnitOrderManaFlareOff=1,unitordernotarg,`manaflareoff`,WESTRING_UNITORDERNOTARG_MANAFLAREOFF UnitOrderPhaseShift=1,unitordernotarg,`phaseshift`,WESTRING_UNITORDERNOTARG_PHASESHIFT UnitOrderPhaseShiftOn=1,unitordernotarg,`phaseshifton`,WESTRING_UNITORDERNOTARG_PHASESHIFTON UnitOrderPhaseShiftOff=1,unitordernotarg,`phaseshiftoff`,WESTRING_UNITORDERNOTARG_PHASESHIFTOFF UnitOrderVengeanceInstant=1,unitordernotarg,`vengeanceinstant`,WESTRING_UNITORDERNOTARG_VENGEANCEINSTANT UnitOrderVengeanceOn=1,unitordernotarg,`vengeanceon`,WESTRING_UNITORDERNOTARG_VENGEANCEON UnitOrderVengeanceOff=1,unitordernotarg,`vengeanceoff`,WESTRING_UNITORDERNOTARG_VENGEANCEOFF UnitOrderImmolation=0,unitordernotarg,`immolation`,WESTRING_UNITORDERNOTARG_IMMOLATION UnitOrderUnImmolation=0,unitordernotarg,`unimmolation`,WESTRING_UNITORDERNOTARG_UNIMMOLATION UnitOrderMetamorphosis=0,unitordernotarg,`metamorphosis`,WESTRING_UNITORDERNOTARG_METAMORPHOSIS UnitOrderTranquility=0,unitordernotarg,`tranquility`,WESTRING_UNITORDERNOTARG_TRANQUILITY UnitOrderSearingArrows=0,unitordernotarg,`flamingarrows`,WESTRING_UNITORDERNOTARG_SEARINGARROWS UnitOrderUnSearingArrows=0,unitordernotarg,`unflamingarrows`,WESTRING_UNITORDERNOTARG_UNSEARINGARROWS UnitOrderScout=0,unitordernotarg,`scout`,WESTRING_UNITORDERNOTARG_SCOUT UnitOrderStarfall2=0,unitordernotarg,`starfall`,WESTRING_UNITORDERNOTARG_STARFALL UnitOrderFanOfKnives=1,unitordernotarg,`fanofknives`,WESTRING_UNITORDERNOTARG_FANOFKNIVES UnitOrderSpiritOfVengeance=1,unitordernotarg,`spiritofvengeance`,WESTRING_UNITORDERNOTARG_SPIRITOFVENGEANCE // Undead UnitOrderUndeadBuild=1,unitordernotarg,`undeadbuild`,WESTRING_UNITORDERNOTARG_UNDEADBUILD UnitOrderRestorationOn=0,unitordernotarg,`restorationon`,WESTRING_UNITORDERNOTARG_RESTOREON UnitOrderRestorationOff=0,unitordernotarg,`restorationoff`,WESTRING_UNITORDERNOTARG_RESTOREOFF UnitOrderCannibalize=0,unitordernotarg,`cannibalize`,WESTRING_UNITORDERNOTARG_CANNIBALIZE UnitOrderWebOn=0,unitordernotarg,`webon`,WESTRING_UNITORDERNOTARG_WEBON UnitOrderWebOff=0,unitordernotarg,`weboff`,WESTRING_UNITORDERNOTARG_WEBOFF UnitOrderBurrow=1,unitordernotarg,`burrow`,WESTRING_UNITORDERNOTARG_BURROW UnitOrderUnBurrow=1,unitordernotarg,`unburrow`,WESTRING_UNITORDERNOTARG_UNBURROW UnitOrderLoadCorpse=0,unitordernotarg,`loadcorpse`,WESTRING_UNITORDERNOTARG_LOADCORPSE UnitOrderUnloadAllCorpses=0,unitordernotarg,`unloadallcorpses`,WESTRING_UNITORDERNOTARG_UNLOADALLCORPSES UnitOrderStoneForm=0,unitordernotarg,`stoneform`,WESTRING_UNITORDERNOTARG_STONEFORM UnitOrderUnStoneForm=0,unitordernotarg,`unstoneform`,WESTRING_UNITORDERNOTARG_UNSTONEFORM UnitOrderRaiseDeadInstant=1,unitordernotarg,`instant`,WESTRING_UNITORDERNOTARG_RAISEDEAD UnitOrderRaiseDeadOn=0,unitordernotarg,`raisedeadon`,WESTRING_UNITORDERNOTARG_RAISEDEADON UnitOrderRaiseDeadOff=0,unitordernotarg,`raisedeadoff`,WESTRING_UNITORDERNOTARG_RAISEDEADOFF UnitOrderCurseOn=0,unitordernotarg,`curseon`,WESTRING_UNITORDERNOTARG_CURSEON UnitOrderCurseOff=0,unitordernotarg,`curseoff`,WESTRING_UNITORDERNOTARG_CURSEOFF UnitOrderFlamingAttackOn=1,unitordernotarg,`flamingattack`,WESTRING_UNITORDERNOTARG_FLAMINGATTACKON UnitOrderFlamingAttackOff=1,unitordernotarg,`unflamingattack`,WESTRING_UNITORDERNOTARG_FLAMINGATTACKOFF UnitOrderSphinxForm=1,unitordernotarg,`avengerform`,WESTRING_UNITORDERNOTARG_SPHINXFORM UnitOrderReplenishLife=1,unitordernotarg,`replenishlife`,WESTRING_UNITORDERNOTARG_REPLENISHLIFE UnitOrderReplenishLifeOn=1,unitordernotarg,`replenishlifeon`,WESTRING_UNITORDERNOTARG_REPLENISHLIFEON UnitOrderReplenishLifeOff=1,unitordernotarg,`replenishlifeoff`,WESTRING_UNITORDERNOTARG_REPLENISHLIFEOFF UnitOrderReplenishMana=1,unitordernotarg,`replenishmana`,WESTRING_UNITORDERNOTARG_REPLENISHMANA UnitOrderReplenishManaOn=1,unitordernotarg,`replenishmanaon`,WESTRING_UNITORDERNOTARG_REPLENISHMANAON UnitOrderReplenishManaOff=1,unitordernotarg,`replenishmanaoff`,WESTRING_UNITORDERNOTARG_REPLENISHMANAOFF UnitOrderCarrionScarabsOn=1,unitordernotarg,`carrionscarabson`,WESTRING_UNITORDERNOTARG_CARRIONSCARABSON UnitOrderCarrionScarabsOff=1,unitordernotarg,`carrionscarabsoff`,WESTRING_UNITORDERNOTARG_CARRIONSCARABSOFF UnitOrderCarrionScarabsInstant=1,unitordernotarg,`carrionscarabsinstant`,WESTRING_UNITORDERNOTARG_CARRIONSCARABS UnitOrderLocustSwarm=1,unitordernotarg,`locustswarm`,WESTRING_UNITORDERNOTARG_LOCUSTSWARM UnitOrderAnimateDead=0,unitordernotarg,`animatedead`,WESTRING_UNITORDERNOTARG_ANIMATEDEAD UnitOrderFrostArmorOn=0,unitordernotarg,`frostarmoron`,WESTRING_UNITORDERNOTARG_FROSTARMORON UnitOrderFrostArmorOff=0,unitordernotarg,`frostarmoroff`,WESTRING_UNITORDERNOTARG_FROSTARMOROFF // Neutral UnitOrderNagaBuild=1,unitordernotarg,`nagabuild`,WESTRING_UNITORDERNOTARG_NAGABUILD UnitOrderCreepAnimateDead=0,unitordernotarg,`creepanimatedead`,WESTRING_UNITORDERNOTARG_CREEPANIMATEDEAD UnitOrderCreepHealOn=0,unitordernotarg,`creephealon`,WESTRING_UNITORDERNOTARG_CREEPHEALON UnitOrderCreepHealOff=0,unitordernotarg,`creephealoff`,WESTRING_UNITORDERNOTARG_CREEPHEALOFF UnitOrderRevenge=0,unitordernotarg,`revenge`,WESTRING_UNITORDERNOTARG_REVENGE UnitOrderCreepThunderClap=0,unitordernotarg,`creepthunderclap`,WESTRING_UNITORDERNOTARG_CREEPTHUNDERCLAP UnitOrderWateryMinion=1,unitordernotarg,`wateryminion`,WESTRING_UNITORDERNOTARG_WATERYMINION UnitOrderSelfDestructOn=1,unitordernotarg,`selfdestructon`,WESTRING_UNITORDERNOTARG_SELFDESTRUCTON UnitOrderSelfDestructOff=1,unitordernotarg,`selfdestructoff`,WESTRING_UNITORDERNOTARG_SELFDESTRUCTOFF UnitOrderSummonGrizzly=1,unitordernotarg,`summongrizzly`,WESTRING_UNITORDERNOTARG_SUMMONGRIZZLY UnitOrderSummonQuillbeast=1,unitordernotarg,`summonquillbeast`,WESTRING_UNITORDERNOTARG_SUMMONQUILLBEAST UnitOrderSummonWarEagle=1,unitordernotarg,`summonwareagle`,WESTRING_UNITORDERNOTARG_SUMMONWAREAGLE UnitOrderBlackArrowOn=1,unitordernotarg,`blackarrowon`,WESTRING_UNITORDERNOTARG_BLACKARROWON UnitOrderBlackArrowOff=1,unitordernotarg,`blackarrowoff`,WESTRING_UNITORDERNOTARG_BLACKARROWOFF UnitOrderColdArrowOn=1,unitordernotarg,`coldarrows`,WESTRING_UNITORDERNOTARG_COLDARROWON UnitOrderColdArrowOff=1,unitordernotarg,`uncoldarrows`,WESTRING_UNITORDERNOTARG_COLDARROWOFF UnitOrderManaShieldOn=1,unitordernotarg,`manashieldon`,WESTRING_UNITORDERNOTARG_MANASHIELDON UnitOrderManaShieldOff=1,unitordernotarg,`manashieldoff`,WESTRING_UNITORDERNOTARG_MANASHIELDOFF UnitOrderElementalFury=1,unitordernotarg,`elementalfury`,WESTRING_UNITORDERNOTARG_ELEMENTALFURY UnitOrderHowlOfTerror=1,unitordernotarg,`howlofterror`,WESTRING_UNITORDERNOTARG_HOWLOFTERROR UnitOrderPoisonArrows=0,unitordernotarg,`poisonarrows`,WESTRING_UNITORDERNOTARG_POISONARROWON UnitOrderUnPoisonArrows=0,unitordernotarg,`unpoisonarrows`,WESTRING_UNITORDERNOTARG_POISONARROWOFF UnitOrderChemicalRage=1,unitordernotarg,`chemicalrage`,WESTRING_UNITORDERNOTARG_CHEMICALRAGE UnitOrderRoboGoblin=1,unitordernotarg,`robogoblin`,WESTRING_UNITORDERNOTARG_ROBOGOBLIN UnitOrderUnRoboGoblin=1,unitordernotarg,`unrobogoblin`,WESTRING_UNITORDERNOTARG_UNROBOGOBLIN UnitOrderLavaMonster=1,unitordernotarg,`lavamonster`,WESTRING_UNITORDERNOTARG_LAVAMONSTER UnitOrderIncinerateArrowOn=1,unitordernotarg,`incineratearrowon`,WESTRING_UNITORDERNOTARG_INCINERATEARROWON UnitOrderIncinerateArrowOff=1,unitordernotarg,`incineratearrowoff`,WESTRING_UNITORDERNOTARG_INCINERATEARROWOFF // Special UnitOrderChannel=1,unitordernotarg,`channel`,WESTRING_UNITORDERNOTARG_CHANNEL UnitOrderMedivhRavenForm=0,unitordernotarg,`ravenform`,WESTRING_UNITORDERNOTARG_MEDIVHRAVENFORM UnitOrderMedivhUnRavenForm=0,unitordernotarg,`unravenform`,WESTRING_UNITORDERNOTARG_MEDIVHUNRAVENFORM UnitOrderRexxarBattleRoar=1,unitordernotarg,`battleroar`,WESTRING_UNITORDERNOTARG_REXXARBATTLEROAR UnitOrderColdArrows=0,unitordernotarg,`coldarrows`,WESTRING_UNITORDERNOTARG_COLDARROWS UnitOrderUnColdArrows=0,unitordernotarg,`uncoldarrows`,WESTRING_UNITORDERNOTARG_UNCOLDARROWS // Hero Skills // Human Archmage HeroSkillBlizzard=0,heroskillcode,'AHbz',WESTRING_HEROSKILL_BLIZZARD HeroSkillWaterElemental=0,heroskillcode,'AHwe',WESTRING_HEROSKILL_WATERELEMENTAL HeroSkillBrillianceAura=0,heroskillcode,'AHab',WESTRING_HEROSKILL_BRILLIANCEAURA HeroSkillMassTeleport=0,heroskillcode,'AHmt',WESTRING_HEROSKILL_MASSTELEPORT // Human Blood Mage HeroSkillFlameStrike=1,heroskillcode,'AHfs',WESTRING_HEROSKILL_FLAMESTRIKE HeroSkillBanish=1,heroskillcode,'AHbn',WESTRING_HEROSKILL_BANISH HeroSkillSiphonMana=1,heroskillcode,'AHdr',WESTRING_HEROSKILL_SIPHONMANA HeroSkillPhoenix=1,heroskillcode,'AHpx',WESTRING_HEROSKILL_PHOENIX // Human Mountain King HeroSkillStormBolt=0,heroskillcode,'AHtb',WESTRING_HEROSKILL_STORMBOLT HeroSkillThunderClap=0,heroskillcode,'AHtc',WESTRING_HEROSKILL_THUNDERCLAP HeroSkillBash=0,heroskillcode,'AHbh',WESTRING_HEROSKILL_BASH HeroSkillAvatar=0,heroskillcode,'AHav',WESTRING_HEROSKILL_AVATAR // Human Paladin HeroSkillDivineShield=0,heroskillcode,'AHds',WESTRING_HEROSKILL_DIVINESHIELD HeroSkillHolyBolt=0,heroskillcode,'AHhb',WESTRING_HEROSKILL_HOLYBOLT HeroSkillDevotionAura=0,heroskillcode,'AHad',WESTRING_HEROSKILL_DEVOTIONAURA HeroSkillResurrection=0,heroskillcode,'AHre',WESTRING_HEROSKILL_RESURRECTION // Orc Blademaster HeroSkillWindWalk=0,heroskillcode,'AOwk',WESTRING_HEROSKILL_WINDWALK HeroSkillMirrorImage=0,heroskillcode,'AOmi',WESTRING_HEROSKILL_MIRRORIMAGE HeroSkillCriticalStrike=0,heroskillcode,'AOcr',WESTRING_HEROSKILL_CRITICALSTRIKE HeroSkillWhirlwind=0,heroskillcode,'AOww',WESTRING_HEROSKILL_WHIRLWIND // Orc Far Seer HeroSkillChainLightning=0,heroskillcode,'AOcl',WESTRING_HEROSKILL_CHAINLIGHTNING HeroSkillFarSight=0,heroskillcode,'AOfs',WESTRING_HEROSKILL_FARSIGHT HeroSkillSpiritWolf=0,heroskillcode,'AOsf',WESTRING_HEROSKILL_SPIRITWOLF HeroSkillEarthquake=0,heroskillcode,'AOeq',WESTRING_HEROSKILL_EARTHQUAKE // Orc Shadow Hunter HeroSkillHealingWave=1,heroskillcode,'AOhw',WESTRING_HEROSKILL_HEALINGWAVE HeroSkillHex=1,heroskillcode,'AOhx',WESTRING_HEROSKILL_HEX HeroSkillSerpentWard=1,heroskillcode,'AOsw',WESTRING_HEROSKILL_SERPENTWARD HeroSkillVoodoo=1,heroskillcode,'AOvd',WESTRING_HEROSKILL_VOODOO // Orc Tauren Chieftain HeroSkillShockwave=0,heroskillcode,'AOsh',WESTRING_HEROSKILL_SHOCKWAVE HeroSkillWarStomp=0,heroskillcode,'AOws',WESTRING_HEROSKILL_WARSTOMP HeroSkillEnduranceAura=0,heroskillcode,'AOae',WESTRING_HEROSKILL_ENDURANCEAURA HeroSkillReincarnation=0,heroskillcode,'AOre',WESTRING_HEROSKILL_REINCARNATION // Undead Crypt Lord HeroSkillImpale=1,heroskillcode,'AUim',WESTRING_HEROSKILL_IMPALE HeroSkillThornyShield=1,heroskillcode,'AUts',WESTRING_HEROSKILL_THORNYSHIELD HeroSkillCarrionScarabs=1,heroskillcode,'AUcb',WESTRING_HEROSKILL_CARRIONSCARABS HeroSkillLocustSwarm=1,heroskillcode,'AUls',WESTRING_HEROSKILL_LOCUSTSWARM // Undead Death Knight HeroSkillDeathCoil=0,heroskillcode,'AUdc',WESTRING_HEROSKILL_DEATHCOIL HeroSkillDeathPact=0,heroskillcode,'AUdp',WESTRING_HEROSKILL_DEATHPACT HeroSkillUnholyAura=0,heroskillcode,'AUau',WESTRING_HEROSKILL_UNHOLYAURA HeroSkillAnimateDead=0,heroskillcode,'AUan',WESTRING_HEROSKILL_ANIMATEDEAD // Undead Dread Lord HeroSkillCarrionSwarm=0,heroskillcode,'AUcs',WESTRING_HEROSKILL_CARRIONSWARM HeroSkillSleep=0,heroskillcode,'AUsl',WESTRING_HEROSKILL_SLEEP HeroSkillVampiricAura=0,heroskillcode,'AUav',WESTRING_HEROSKILL_VAMPIRICAURA HeroSkillDarkSummoning=0,heroskillcode,'AUin',WESTRING_HEROSKILL_DARKSUMMONING // Undead Lich HeroSkillFrostNova=0,heroskillcode,'AUfn',WESTRING_HEROSKILL_FROSTNOVA HeroSkillFrostArmor=0,heroskillcode,'AUfa',WESTRING_HEROSKILL_FROSTARMOR HeroSkillDarkRitual=0,heroskillcode,'AUdr',WESTRING_HEROSKILL_DARKRITUAL HeroSkillDeathAndDecay=0,heroskillcode,'AUdd',WESTRING_HEROSKILL_DEATHANDDECAY // Night Elf Demon Hunter HeroSkillManaBurn=0,heroskillcode,'AEmb',WESTRING_HEROSKILL_MANABURN HeroSkillImmolation=0,heroskillcode,'AEim',WESTRING_HEROSKILL_IMMOLATION HeroSkillEvasion=0,heroskillcode,'AEev',WESTRING_HEROSKILL_EVASION HeroSkillMetamorphosis=0,heroskillcode,'AEme',WESTRING_HEROSKILL_METAMORPHOSIS // Night Elf Keeper of the Grove HeroSkillEntanglingRoots=0,heroskillcode,'AEer',WESTRING_HEROSKILL_ENTANGLINGROOTS HeroSkillForceOfNature=0,heroskillcode,'AEfn',WESTRING_HEROSKILL_FORCEOFNATURE HeroSkillThornsAura=0,heroskillcode,'AEah',WESTRING_HEROSKILL_THORNSAURA HeroSkillTranquility=0,heroskillcode,'AEtq',WESTRING_HEROSKILL_TRANQUILITY // Night Elf Priestess of the Moon HeroSkillScout=0,heroskillcode,'AEst',WESTRING_HEROSKILL_SCOUT HeroSkillSearingArrows=0,heroskillcode,'AHfa',WESTRING_HEROSKILL_SEARINGARROWS HeroSkillTrueshotAura=0,heroskillcode,'AEar',WESTRING_HEROSKILL_TRUESHOTAURA HeroSkillStarfall=0,heroskillcode,'AEsf',WESTRING_HEROSKILL_STARFALL // Night Elf Warden HeroSkillFanOfKnives=1,heroskillcode,'AEfk',WESTRING_HEROSKILL_FANOFKNIVES HeroSkillBlink=1,heroskillcode,'AEbl',WESTRING_HEROSKILL_BLINK HeroSkillShadowTouch=1,heroskillcode,'AEsh',WESTRING_HEROSKILL_SHADOWTOUCH HeroSkillSpiritOfVengeance=1,heroskillcode,'AEsv',WESTRING_HEROSKILL_SPIRITOFVENGEANCE // Neutral Beast Master HeroSkillGrizzly=1,heroskillcode,'ANsg',WESTRING_HEROSKILL_GRIZZLY HeroSkillQuillbeast=1,heroskillcode,'ANsq',WESTRING_HEROSKILL_QUILLBEAST HeroSkillWarEagle=1,heroskillcode,'ANsw',WESTRING_HEROSKILL_WAREAGLE HeroSkillStampede=1,heroskillcode,'ANst',WESTRING_HEROSKILL_STAMPEDE // Neutral Dark Ranger HeroSkillSilence=1,heroskillcode,'ANsi',WESTRING_HEROSKILL_SILENCE HeroSkillBlackArrow=1,heroskillcode,'ANba',WESTRING_HEROSKILL_BLACKARROW HeroSkillLifeDrain=1,heroskillcode,'ANdr',WESTRING_HEROSKILL_LIFEDRAIN HeroSkillCharm=1,heroskillcode,'ANch',WESTRING_HEROSKILL_CHARM // Neutral Naga Sea Witch HeroSkillForkedLightning=1,heroskillcode,'ANfl',WESTRING_HEROSKILL_FORKEDLIGHTNING HeroSkillColdArrow=1,heroskillcode,'ANfa',WESTRING_HEROSKILL_COLDARROW HeroSkillManaShield=1,heroskillcode,'ANms',WESTRING_HEROSKILL_MANASHIELD HeroSkillTornado=1,heroskillcode,'ANto',WESTRING_HEROSKILL_TORNADO // Neutral Pandaren Brewmaster HeroSkillBreathOfFire=1,heroskillcode,'ANbf',WESTRING_HEROSKILL_BREATHOFFIRE HeroSkillStrongDrink=1,heroskillcode,'ANdh',WESTRING_HEROSKILL_STRONGDRINK HeroSkillDrunkenBrawler=1,heroskillcode,'ANdb',WESTRING_HEROSKILL_DRUNKENBRAWLER HeroSkillElementalFury=1,heroskillcode,'ANef',WESTRING_HEROSKILL_ELEMENTALFURY // Neutral Pit Lord HeroSkillRainOfFire=1,heroskillcode,'ANrf',WESTRING_HEROSKILL_RAINOFFIRE HeroSkillHowlOfTerror=1,heroskillcode,'ANht',WESTRING_HEROSKILL_HOWLOFTERROR HeroSkillCleavingAttack=1,heroskillcode,'ANca',WESTRING_HEROSKILL_CLEAVINGATTACK HeroSkillDoom=1,heroskillcode,'ANdo',WESTRING_HEROSKILL_DOOM // Neutral Alchemist HeroSkillAcidBomb=1,heroskillcode,'ANab',WESTRING_HEROSKILL_ACIDBOMB HeroSkillChemicalRage=1,heroskillcode,'ANcr',WESTRING_HEROSKILL_CHEMICALRAGE HeroSkillHealingSpray=1,heroskillcode,'ANhs',WESTRING_HEROSKILL_HEALINGSPRAY HeroSkillTransmute=1,heroskillcode,'ANtm',WESTRING_HEROSKILL_TRANSMUTE // Neutral Tinker HeroSkillEngineeringUpgrade=1,heroskillcode,'ANeg',WESTRING_HEROSKILL_ENGINEERINGUPGRADE HeroSkillClusterRockets=1,heroskillcode,'ANcs',WESTRING_HEROSKILL_CLUSTERROCKETS HeroSkillSummonFactory=1,heroskillcode,'ANsy',WESTRING_HEROSKILL_SUMMONFACTORY HeroSkillRoboGoblin=1,heroskillcode,'ANrg',WESTRING_HEROSKILL_ROBOGOBLIN // Neutral Fire Lord HeroSkillIncinerate=1,heroskillcode,'ANic',WESTRING_HEROSKILL_INCINERATE HeroSkillIncinerateArrow=1,heroskillcode,'ANia',WESTRING_HEROSKILL_INCINERATEARROW HeroSkillSoulBurn=1,heroskillcode,'ANso',WESTRING_HEROSKILL_SOULBURN HeroSkillLavaMonster=1,heroskillcode,'ANlm',WESTRING_HEROSKILL_LAVAMONSTER HeroSkillVolcano=1,heroskillcode,'ANvc',WESTRING_HEROSKILL_VOLCANO // Special Akama HeroSkillChainLightning2=1,heroskillcode,'AOcl',WESTRING_HEROSKILL_AKAMA_CHAINLIGHTNING HeroSkillSpiritBeast=1,heroskillcode,'ACs7',WESTRING_HEROSKILL_AKAMA_FERALSPIRIT HeroSkillShadowTouch2=1,heroskillcode,'AEsh',WESTRING_HEROSKILL_AKAMA_SHADOWTOUCH HeroSkillReincarnation2=1,heroskillcode,'ANr2',WESTRING_HEROSKILL_AKAMA_REINCARNATION // Special Archimonde HeroSkillDarkPortal=0,heroskillcode,'ANdp',WESTRING_HEROSKILL_DARKPORTAL HeroSkillRainOfChaos=0,heroskillcode,'ANrc',WESTRING_HEROSKILL_RAINOFCHAOS HeroSkillArchiBash=0,heroskillcode,'AHah',WESTRING_HEROSKILL_ARCHIBASH HeroSkillFingerOfDeath=0,heroskillcode,'ANfd',WESTRING_HEROSKILL_FINGEROFDEATH // Special Balnazar HeroSkillBalnaSleep=1,heroskillcode,'AUsl',WESTRING_HEROSKILL_BALNA_SLEEP HeroSkillBalnaVampiricAura=1,heroskillcode,'AUav',WESTRING_HEROSKILL_BALNA_VAMPIRICAURA HeroSkillBalnaRainOfChaos=1,heroskillcode,'ANr3',WESTRING_HEROSKILL_BALNA_RAINOFCHAOS HeroSkillBalnaFingerOfPain=1,heroskillcode,'ACf3',WESTRING_HEROSKILL_BALNA_FINGEROFPAIN HeroSkillBalnaEarthquake=1,heroskillcode,'AOeq',WESTRING_HEROSKILL_BALNA_EARTHQUAKE // Special Chen HeroSkillChenBreathOfFire=1,heroskillcode,'ANcf',WESTRING_HEROSKILL_CHEN_BREATHOFFIRE HeroSkillChenStrongDrink=1,heroskillcode,'Acdh',WESTRING_HEROSKILL_CHEN_STRONGDRINK HeroSkillChenDrunkenBrawler=1,heroskillcode,'Acdb',WESTRING_HEROSKILL_CHEN_DRUNKENBRAWLER HeroSkillChenElementalFury=1,heroskillcode,'Acef',WESTRING_HEROSKILL_CHEN_ELEMENTALFURY HeroSkillChenAttributeBonus=1,heroskillcode,'Aamk',WESTRING_HEROSKILL_CHEN_ATTRIBUTEBONUS // Special Detheroc HeroSkillDetheSleep=1,heroskillcode,'AUsl',WESTRING_HEROSKILL_DETHE_SLEEP HeroSkillDetheShadowTouch=1,heroskillcode,'AEsh',WESTRING_HEROSKILL_DETHE_SHADOWTOUCH HeroSkillDetheCarrionSwarm=1,heroskillcode,'AUcs',WESTRING_HEROSKILL_DETHE_CARRIONSWARM HeroSkillDetheDeathAndDecay=1,heroskillcode,'AUdd',WESTRING_HEROSKILL_DETHE_DEATHANDDECAY // Special Garithos HeroSkillGaritShockwave=1,heroskillcode,'ANsh',WESTRING_HEROSKILL_GARIT_SHOCKWAVE HeroSkillGaritHolyLight=1,heroskillcode,'AHhb',WESTRING_HEROSKILL_GARIT_HOLYLIGHT HeroSkillGaritDevotionAura=1,heroskillcode,'AHad',WESTRING_HEROSKILL_GARIT_DEVOTIONAURA HeroSkillGaritAvatar=1,heroskillcode,'ANav',WESTRING_HEROSKILL_GARIT_AVATAR // Special Illidan HeroSkillIllimorphosis=0,heroskillcode,'AEIl',WESTRING_HEROSKILL_ILLIMORPHOSIS HeroSkillEvilIllimorphosis=0,heroskillcode,'AEvi',WESTRING_HEROSKILL_EVILILLIMORPHOSIS // Special Malganis HeroSkillMalganisSleep=0,heroskillcode,'ANdc',WESTRING_HEROSKILL_DARKCONVERSION HeroSkillSoulPreservation=0,heroskillcode,'ANsl',WESTRING_HEROSKILL_SOULPRESERVATION // Special Manaroth HeroSkillManarothReincarnation=0,heroskillcode,'ANrn',WESTRING_HEROSKILL_MANAROTHREINCARNATION // Special Rexxar HeroSkillRexxarGrizzly=1,heroskillcode,'Arsg',WESTRING_HEROSKILL_REXXAR_GRIZZLY HeroSkillRexxarQuillbeast=1,heroskillcode,'Arsq',WESTRING_HEROSKILL_REXXAR_QUILLBEAST HeroSkillRexxarStormBolt=1,heroskillcode,'ANsb',WESTRING_HEROSKILL_REXXAR_STORMBOLT HeroSkillRexxarStampede=1,heroskillcode,'Arsp',WESTRING_HEROSKILL_REXXAR_STAMPEDE HeroSkillRexxarAttributeBonus=1,heroskillcode,'Aamk',WESTRING_HEROSKILL_REXXAR_ATTRIBUTEBONUS // Special Rokhan HeroSkillRokhanHealingWave=1,heroskillcode,'ANhw',WESTRING_HEROSKILL_ROKHAN_HEALINGWAVE HeroSkillRokhanHex=1,heroskillcode,'ANhx',WESTRING_HEROSKILL_ROKHAN_HEX HeroSkillRokhanSerpentWard=1,heroskillcode,'Arsw',WESTRING_HEROSKILL_ROKHAN_SERPENTWARD HeroSkillRokhanVoodooSpirits=1,heroskillcode,'AOls',WESTRING_HEROSKILL_ROKHAN_VOODOOSPIRITS HeroSkillRokhanAttributeBonus=1,heroskillcode,'Aamk',WESTRING_HEROSKILL_ROKHAN_ATTRIBUTEBONUS // Special Sylvanas Windrunner HeroSkillColdArrows=0,heroskillcode,'AHca',WESTRING_HEROSKILL_COLDARROWS // Special Tichondrius HeroSkillTichondriusInferno=0,heroskillcode,'SNin',WESTRING_HEROSKILL_TICHONDRIUSINFERNO // Special Varimathras HeroSkillVarimSleep=1,heroskillcode,'AUsl',WESTRING_HEROSKILL_VARIM_SLEEP HeroSkillVarimVampiricAura=1,heroskillcode,'AUav',WESTRING_HEROSKILL_VARIM_VAMPIRICAURA HeroSkillVarimRainOfFire=1,heroskillcode,'ANrf',WESTRING_HEROSKILL_VARIM_RAINOFFIRE HeroSkillVarimDoom=1,heroskillcode,'ANdo',WESTRING_HEROSKILL_VARIM_DOOM // Special Warlock HeroSkillInfernal=0,heroskillcode,'ANin',WESTRING_HEROSKILL_INFERNAL // Special Miscellaneous HeroSkillMalganisSleepFast=0,heroskillcode,'SNdc',WESTRING_HEROSKILL_DARKCONVERSIONFAST HeroSkillDarkSummoningOld=0,heroskillcode,'AUds',WESTRING_HEROSKILL_DARKSUMMONINGOLD // Weather Effects WeatherAshenvaleHeavyRain=0,weathereffectcode,'RAhr',WESTRING_WEATHER_ASHENVALEHEAVYRAIN WeatherAshenvaleLightRain=0,weathereffectcode,'RAlr',WESTRING_WEATHER_ASHENVALELIGHTRAIN WeatherDalaranShield=0,weathereffectcode,'MEds',WESTRING_WEATHER_DALARANSHIELD WeatherDungeonHeavyBlueFog=0,weathereffectcode,'FDbh',WESTRING_WEATHER_DUNGEONHEAVYBLUEFOG WeatherDungeonLightBlueFog=0,weathereffectcode,'FDbl',WESTRING_WEATHER_DUNGEONBLUEFOG WeatherDungeonHeavyGreenFog=0,weathereffectcode,'FDgh',WESTRING_WEATHER_DUNGEONHEAVYGREENFOG WeatherDungeonLightGreenFog=0,weathereffectcode,'FDgl',WESTRING_WEATHER_DUNGEONGREENFOG WeatherDungeonHeavyRedFog=0,weathereffectcode,'FDrh',WESTRING_WEATHER_DUNGEONHEAVYREDFOG WeatherDungeonLightRedFog=0,weathereffectcode,'FDrl',WESTRING_WEATHER_DUNGEONREDFOG WeatherDungeonHeavyWhiteFog=0,weathereffectcode,'FDwh',WESTRING_WEATHER_DUNGEONHEAVYWHITEFOG WeatherDungeonLightWhiteFog=0,weathereffectcode,'FDwl',WESTRING_WEATHER_DUNGEONWHITEFOG WeatherLordaeronHeavyRain=0,weathereffectcode,'RLhr',WESTRING_WEATHER_LORDAERONHEAVYRAIN WeatherLordaeronLightRain=0,weathereffectcode,'RLlr',WESTRING_WEATHER_LORDAERONLIGHTRAIN WeatherNorthrendBlizzard=0,weathereffectcode,'SNbs',WESTRING_WEATHER_NORTHRENDBLIZZARD WeatherNorthrendHeavySnow=0,weathereffectcode,'SNhs',WESTRING_WEATHER_NORTHRENDHEAVYSNOW WeatherNorthrendLightSnow=0,weathereffectcode,'SNls',WESTRING_WEATHER_NORTHRENDLIGHTSNOW WeatherOutlandWind=1,weathereffectcode,'WOcw',WESTRING_WEATHER_OUTLANDWIND WeatherOutlandWindLight=1,weathereffectcode,'WOlw',WESTRING_WEATHER_OUTLANDWINDLIGHT WeatherRaysOfLight=0,weathereffectcode,'LRaa',WESTRING_WEATHER_RAYSOFLIGHT WeatherRaysOfMoonlight=0,weathereffectcode,'LRma',WESTRING_WEATHER_RAYSOFMOONLIGHT WeatherHeavyWind=0,weathereffectcode,'WNcw',WESTRING_WEATHER_WIND // Tile IDs TerrainTypeLdrt=1,terraintype,'Ldrt',WESTRING_TERRAINTYPE_Ldrt TerrainTypeLdro=1,terraintype,'Ldro',WESTRING_TERRAINTYPE_Ldro TerrainTypeLdrg=1,terraintype,'Ldrg',WESTRING_TERRAINTYPE_Ldrg TerrainTypeLrok=1,terraintype,'Lrok',WESTRING_TERRAINTYPE_Lrok TerrainTypeLgrs=1,terraintype,'Lgrs',WESTRING_TERRAINTYPE_Lgrs TerrainTypeLgrd=1,terraintype,'Lgrd',WESTRING_TERRAINTYPE_Lgrd TerrainTypeFdrt=1,terraintype,'Fdrt',WESTRING_TERRAINTYPE_Fdrt TerrainTypeFdro=1,terraintype,'Fdro',WESTRING_TERRAINTYPE_Fdro TerrainTypeFdrg=1,terraintype,'Fdrg',WESTRING_TERRAINTYPE_Fdrg TerrainTypeFrok=1,terraintype,'Frok',WESTRING_TERRAINTYPE_Frok TerrainTypeFgrs=1,terraintype,'Fgrs',WESTRING_TERRAINTYPE_Fgrs TerrainTypeFgrd=1,terraintype,'Fgrd',WESTRING_TERRAINTYPE_Fgrd TerrainTypeWdrt=1,terraintype,'Wdrt',WESTRING_TERRAINTYPE_Wdrt TerrainTypeWdro=1,terraintype,'Wdro',WESTRING_TERRAINTYPE_Wdro TerrainTypeWsng=1,terraintype,'Wsng',WESTRING_TERRAINTYPE_Wsng TerrainTypeWrok=1,terraintype,'Wrok',WESTRING_TERRAINTYPE_Wrok TerrainTypeWgrs=1,terraintype,'Wgrs',WESTRING_TERRAINTYPE_Wgrs TerrainTypeWsnw=1,terraintype,'Wsnw',WESTRING_TERRAINTYPE_Wsnw TerrainTypeBdrt=1,terraintype,'Bdrt',WESTRING_TERRAINTYPE_Bdrt TerrainTypeBdrh=1,terraintype,'Bdrh',WESTRING_TERRAINTYPE_Bdrh TerrainTypeBdrr=1,terraintype,'Bdrr',WESTRING_TERRAINTYPE_Bdrr TerrainTypeBdrg=1,terraintype,'Bdrg',WESTRING_TERRAINTYPE_Bdrg TerrainTypeBdsr=1,terraintype,'Bdsr',WESTRING_TERRAINTYPE_Bdsr TerrainTypeBdsd=1,terraintype,'Bdsd',WESTRING_TERRAINTYPE_Bdsd TerrainTypeBflr=1,terraintype,'Bflr',WESTRING_TERRAINTYPE_Bflr TerrainTypeBgrr=1,terraintype,'Bgrr',WESTRING_TERRAINTYPE_Bgrr TerrainTypeAdrt=1,terraintype,'Adrt',WESTRING_TERRAINTYPE_Adrt TerrainTypeAdrd=1,terraintype,'Adrd',WESTRING_TERRAINTYPE_Adrd TerrainTypeAgrs=1,terraintype,'Agrs',WESTRING_TERRAINTYPE_Agrs TerrainTypeArck=1,terraintype,'Arck',WESTRING_TERRAINTYPE_Arck TerrainTypeAgrd=1,terraintype,'Agrd',WESTRING_TERRAINTYPE_Agrd TerrainTypeAvin=1,terraintype,'Avin',WESTRING_TERRAINTYPE_Avin TerrainTypeAdrg=1,terraintype,'Adrg',WESTRING_TERRAINTYPE_Adrg TerrainTypeAlvd=1,terraintype,'Alvd',WESTRING_TERRAINTYPE_Alvd TerrainTypeCdrt=1,terraintype,'Cdrt',WESTRING_TERRAINTYPE_Cdrt TerrainTypeCdrd=1,terraintype,'Cdrd',WESTRING_TERRAINTYPE_Cdrd TerrainTypeCpos=1,terraintype,'Cpos',WESTRING_TERRAINTYPE_Cpos TerrainTypeCrck=1,terraintype,'Crck',WESTRING_TERRAINTYPE_Crck TerrainTypeCvin=1,terraintype,'Cvin',WESTRING_TERRAINTYPE_Cvin TerrainTypeCgrs=1,terraintype,'Cgrs',WESTRING_TERRAINTYPE_Cgrs TerrainTypeClvg=1,terraintype,'Clvg',WESTRING_TERRAINTYPE_Clvg TerrainTypeNdrt=1,terraintype,'Ndrt',WESTRING_TERRAINTYPE_Ndrt TerrainTypeNdrd=1,terraintype,'Ndrd',WESTRING_TERRAINTYPE_Ndrd TerrainTypeNrck=1,terraintype,'Nrck',WESTRING_TERRAINTYPE_Nrck TerrainTypeNgrs=1,terraintype,'Ngrs',WESTRING_TERRAINTYPE_Ngrs TerrainTypeNice=1,terraintype,'Nice',WESTRING_TERRAINTYPE_Nice TerrainTypeNsnw=1,terraintype,'Nsnw',WESTRING_TERRAINTYPE_Nsnw TerrainTypeNsnr=1,terraintype,'Nsnr',WESTRING_TERRAINTYPE_Nsnr TerrainTypeYdrt=1,terraintype,'Ydrt',WESTRING_TERRAINTYPE_Ydrt TerrainTypeYdtr=1,terraintype,'Ydtr',WESTRING_TERRAINTYPE_Ydtr TerrainTypeYblm=1,terraintype,'Yblm',WESTRING_TERRAINTYPE_Yblm TerrainTypeYbtl=1,terraintype,'Ybtl',WESTRING_TERRAINTYPE_Ybtl TerrainTypeYsqd=1,terraintype,'Ysqd',WESTRING_TERRAINTYPE_Ysqd TerrainTypeYrtl=1,terraintype,'Yrtl',WESTRING_TERRAINTYPE_Yrtl TerrainTypeYgsb=1,terraintype,'Ygsb',WESTRING_TERRAINTYPE_Ygsb TerrainTypeYhdg=1,terraintype,'Yhdg',WESTRING_TERRAINTYPE_Yhdg TerrainTypeYwmb=1,terraintype,'Ywmb',WESTRING_TERRAINTYPE_Ywmb TerrainTypeVdrt=1,terraintype,'Vdrt',WESTRING_TERRAINTYPE_Vdrt TerrainTypeVdrr=1,terraintype,'Vdrr',WESTRING_TERRAINTYPE_Vdrr TerrainTypeVcrp=1,terraintype,'Vcrp',WESTRING_TERRAINTYPE_Vcrp TerrainTypeVcbp=1,terraintype,'Vcbp',WESTRING_TERRAINTYPE_Vcbp TerrainTypeVstp=1,terraintype,'Vstp',WESTRING_TERRAINTYPE_Vstp TerrainTypeVgrs=1,terraintype,'Vgrs',WESTRING_TERRAINTYPE_Vgrs TerrainTypeVrck=1,terraintype,'Vrck',WESTRING_TERRAINTYPE_Vrck TerrainTypeVgrt=1,terraintype,'Vgrt',WESTRING_TERRAINTYPE_Vgrt TerrainTypeQdrt=1,terraintype,'Qdrt',WESTRING_TERRAINTYPE_Qdrt TerrainTypeQdrr=1,terraintype,'Qdrr',WESTRING_TERRAINTYPE_Qdrr TerrainTypeQcrp=1,terraintype,'Qcrp',WESTRING_TERRAINTYPE_Qcrp TerrainTypeQcbp=1,terraintype,'Qcbp',WESTRING_TERRAINTYPE_Qcbp TerrainTypeQstp=1,terraintype,'Qstp',WESTRING_TERRAINTYPE_Qstp TerrainTypeQgrs=1,terraintype,'Qgrs',WESTRING_TERRAINTYPE_Qgrs TerrainTypeQrck=1,terraintype,'Qrck',WESTRING_TERRAINTYPE_Qrck TerrainTypeQgrt=1,terraintype,'Qgrt',WESTRING_TERRAINTYPE_Qgrt TerrainTypeXdrt=1,terraintype,'Xdrt',WESTRING_TERRAINTYPE_Xdrt TerrainTypeXdtr=1,terraintype,'Xdtr',WESTRING_TERRAINTYPE_Xdtr TerrainTypeXblm=1,terraintype,'Xblm',WESTRING_TERRAINTYPE_Xblm TerrainTypeXbtl=1,terraintype,'Xbtl',WESTRING_TERRAINTYPE_Xbtl TerrainTypeXsqd=1,terraintype,'Xsqd',WESTRING_TERRAINTYPE_Xsqd TerrainTypeXrtl=1,terraintype,'Xrtl',WESTRING_TERRAINTYPE_Xrtl TerrainTypeXgsb=1,terraintype,'Xgsb',WESTRING_TERRAINTYPE_Xgsb TerrainTypeXhdg=1,terraintype,'Xhdg',WESTRING_TERRAINTYPE_Xhdg TerrainTypeXwmb=1,terraintype,'Xwmb',WESTRING_TERRAINTYPE_Xwmb TerrainTypeDdrt=1,terraintype,'Ddrt',WESTRING_TERRAINTYPE_Ddrt TerrainTypeDbrk=1,terraintype,'Dbrk',WESTRING_TERRAINTYPE_Dbrk TerrainTypeDrds=1,terraintype,'Drds',WESTRING_TERRAINTYPE_Drds TerrainTypeDlvc=1,terraintype,'Dlvc',WESTRING_TERRAINTYPE_Dlvc TerrainTypeDlav=1,terraintype,'Dlav',WESTRING_TERRAINTYPE_Dlav TerrainTypeDdkr=1,terraintype,'Ddkr',WESTRING_TERRAINTYPE_Ddkr TerrainTypeDgrs=1,terraintype,'Dgrs',WESTRING_TERRAINTYPE_Dgrs TerrainTypeDsqd=1,terraintype,'Dsqd',WESTRING_TERRAINTYPE_Dsqd TerrainTypeGdrt=1,terraintype,'Gdrt',WESTRING_TERRAINTYPE_Gdrt TerrainTypeGbrk=1,terraintype,'Gbrk',WESTRING_TERRAINTYPE_Gbrk TerrainTypeGrds=1,terraintype,'Grds',WESTRING_TERRAINTYPE_Grds TerrainTypeGlvc=1,terraintype,'Glvc',WESTRING_TERRAINTYPE_Glvc TerrainTypeGlav=1,terraintype,'Glav',WESTRING_TERRAINTYPE_Glav TerrainTypeGdkr=1,terraintype,'Gdkr',WESTRING_TERRAINTYPE_Gdkr TerrainTypeGgrs=1,terraintype,'Ggrs',WESTRING_TERRAINTYPE_Ggrs TerrainTypeGsqd=1,terraintype,'Gsqd',WESTRING_TERRAINTYPE_Gsqd TerrainTypeZdrt=1,terraintype,'Zdrt',WESTRING_TERRAINTYPE_Zdrt TerrainTypeZdtr=1,terraintype,'Zdtr',WESTRING_TERRAINTYPE_Zdtr TerrainTypeZdrg=1,terraintype,'Zdrg',WESTRING_TERRAINTYPE_Zdrg TerrainTypeZbks=1,terraintype,'Zbks',WESTRING_TERRAINTYPE_Zbks TerrainTypeZsan=1,terraintype,'Zsan',WESTRING_TERRAINTYPE_Zsan TerrainTypeZbkl=1,terraintype,'Zbkl',WESTRING_TERRAINTYPE_Zbkl TerrainTypeZtil=1,terraintype,'Ztil',WESTRING_TERRAINTYPE_Ztil TerrainTypeZgrs=1,terraintype,'Zgrs',WESTRING_TERRAINTYPE_Zgrs TerrainTypeZvin=1,terraintype,'Zvin',WESTRING_TERRAINTYPE_Zvin TerrainTypeIdrt=1,terraintype,'Idrt',WESTRING_TERRAINTYPE_Idrt TerrainTypeIdtr=1,terraintype,'Idtr',WESTRING_TERRAINTYPE_Idtr TerrainTypeIdki=1,terraintype,'Idki',WESTRING_TERRAINTYPE_Idki TerrainTypeIbkb=1,terraintype,'Ibkb',WESTRING_TERRAINTYPE_Ibkb TerrainTypeIrbk=1,terraintype,'Irbk',WESTRING_TERRAINTYPE_Irbk TerrainTypeItbk=1,terraintype,'Itbk',WESTRING_TERRAINTYPE_Itbk TerrainTypeIice=1,terraintype,'Iice',WESTRING_TERRAINTYPE_Iice TerrainTypeIbsq=1,terraintype,'Ibsq',WESTRING_TERRAINTYPE_Ibsq TerrainTypeIsnw=1,terraintype,'Isnw',WESTRING_TERRAINTYPE_Isnw TerrainTypeOdrt=1,terraintype,'Odrt',WESTRING_TERRAINTYPE_Odrt TerrainTypeOdtr=1,terraintype,'Odtr',WESTRING_TERRAINTYPE_Odtr TerrainTypeOsmb=1,terraintype,'Osmb',WESTRING_TERRAINTYPE_Osmb TerrainTypeOfst=1,terraintype,'Ofst',WESTRING_TERRAINTYPE_Ofst TerrainTypeOlgb=1,terraintype,'Olgb',WESTRING_TERRAINTYPE_Olgb TerrainTypeOrok=1,terraintype,'Orok',WESTRING_TERRAINTYPE_Orok TerrainTypeOfsl=1,terraintype,'Ofsl',WESTRING_TERRAINTYPE_Ofsl TerrainTypeOaby=1,terraintype,'Oaby',WESTRING_TERRAINTYPE_Oaby TerrainTypeKdrt=1,terraintype,'Kdrt',WESTRING_TERRAINTYPE_Kdrt TerrainTypeKfsl=1,terraintype,'Kfsl',WESTRING_TERRAINTYPE_Kfsl TerrainTypeKdtr=1,terraintype,'Kdtr',WESTRING_TERRAINTYPE_Kdtr TerrainTypeKfst=1,terraintype,'Kfst',WESTRING_TERRAINTYPE_Kfst TerrainTypeKsmb=1,terraintype,'Ksmb',WESTRING_TERRAINTYPE_Ksmb TerrainTypeKlgb=1,terraintype,'Klgb',WESTRING_TERRAINTYPE_Klgb TerrainTypeKsqt=1,terraintype,'Ksqt',WESTRING_TERRAINTYPE_Ksqt TerrainTypeKdkt=1,terraintype,'Kdkt',WESTRING_TERRAINTYPE_Kdkt TerrainTypeJdrt=1,terraintype,'Jdrt',WESTRING_TERRAINTYPE_Jdrt TerrainTypeJdtr=1,terraintype,'Jdtr',WESTRING_TERRAINTYPE_Jdtr TerrainTypeJblm=1,terraintype,'Jblm',WESTRING_TERRAINTYPE_Jblm TerrainTypeJbtl=1,terraintype,'Jbtl',WESTRING_TERRAINTYPE_Jbtl TerrainTypeJsqd=1,terraintype,'Jsqd',WESTRING_TERRAINTYPE_Jsqd TerrainTypeJrtl=1,terraintype,'Jrtl',WESTRING_TERRAINTYPE_Jrtl TerrainTypeJgsb=1,terraintype,'Jgsb',WESTRING_TERRAINTYPE_Jgsb TerrainTypeJhdg=1,terraintype,'Jhdg',WESTRING_TERRAINTYPE_Jhdg TerrainTypeJwmb=1,terraintype,'Jwmb',WESTRING_TERRAINTYPE_Jwmb TerrainTypecAc2=1,terraintype,'cAc2',WESTRING_TERRAINTYPE_cAc2 TerrainTypecAc1=1,terraintype,'cAc1',WESTRING_TERRAINTYPE_cAc1 TerrainTypecBc2=1,terraintype,'cBc2',WESTRING_TERRAINTYPE_cBc2 TerrainTypecBc1=1,terraintype,'cBc1',WESTRING_TERRAINTYPE_cBc1 TerrainTypecKc1=1,terraintype,'cKc1',WESTRING_TERRAINTYPE_cKc1 TerrainTypecKc2=1,terraintype,'cKc2',WESTRING_TERRAINTYPE_cKc2 TerrainTypecYc2=1,terraintype,'cYc2',WESTRING_TERRAINTYPE_cYc2 TerrainTypecYc1=1,terraintype,'cYc1',WESTRING_TERRAINTYPE_cYc1 TerrainTypecXc2=1,terraintype,'cXc2',WESTRING_TERRAINTYPE_cXc2 TerrainTypecXc1=1,terraintype,'cXc1',WESTRING_TERRAINTYPE_cXc1 TerrainTypecJc2=1,terraintype,'cJc2',WESTRING_TERRAINTYPE_cJc2 TerrainTypecJc1=1,terraintype,'cJc1',WESTRING_TERRAINTYPE_cJc1 TerrainTypecDc2=1,terraintype,'cDc2',WESTRING_TERRAINTYPE_cDc2 TerrainTypecDc1=1,terraintype,'cDc1',WESTRING_TERRAINTYPE_cDc1 TerrainTypecCc2=1,terraintype,'cCc2',WESTRING_TERRAINTYPE_cCc2 TerrainTypecCc1=1,terraintype,'cCc1',WESTRING_TERRAINTYPE_cCc1 TerrainTypecIc2=1,terraintype,'cIc2',WESTRING_TERRAINTYPE_cIc2 TerrainTypecIc1=1,terraintype,'cIc1',WESTRING_TERRAINTYPE_cIc1 TerrainTypecFc2=1,terraintype,'cFc2',WESTRING_TERRAINTYPE_cFc2 TerrainTypecFc1=1,terraintype,'cFc1',WESTRING_TERRAINTYPE_cFc1 TerrainTypecLc2=1,terraintype,'cLc2',WESTRING_TERRAINTYPE_cLc2 TerrainTypecLc1=1,terraintype,'cLc1',WESTRING_TERRAINTYPE_cLc1 TerrainTypecWc2=1,terraintype,'cWc2',WESTRING_TERRAINTYPE_cWc2 TerrainTypecWc1=1,terraintype,'cWc1',WESTRING_TERRAINTYPE_cWc1 TerrainTypecNc2=1,terraintype,'cNc2',WESTRING_TERRAINTYPE_cNc2 TerrainTypecNc1=1,terraintype,'cNc1',WESTRING_TERRAINTYPE_cNc1 TerrainTypecOc1=1,terraintype,'cOc1',WESTRING_TERRAINTYPE_cOc1 TerrainTypecOc2=1,terraintype,'cOc2',WESTRING_TERRAINTYPE_cOc2 TerrainTypecZc2=1,terraintype,'cZc2',WESTRING_TERRAINTYPE_cZc2 TerrainTypecZc1=1,terraintype,'cZc1',WESTRING_TERRAINTYPE_cZc1 TerrainTypecGc2=1,terraintype,'cGc2',WESTRING_TERRAINTYPE_cGc2 TerrainTypecGc1=1,terraintype,'cGc1',WESTRING_TERRAINTYPE_cGc1 TerrainTypecVc2=1,terraintype,'cVc2',WESTRING_TERRAINTYPE_cVc2 TerrainTypecVc1=1,terraintype,'cVc1',WESTRING_TERRAINTYPE_cVc1 TerrainTypecQc2=1,terraintype,'cQc2',WESTRING_TERRAINTYPE_cQc2 TerrainTypecQc1=1,terraintype,'cQc1',WESTRING_TERRAINTYPE_cQc1 // Terrain Shapes TerrainShapeCircle=1,terrainshape,0,WESTRING_TERRAINSHAPE_CIRCLE TerrainShapeSquare=1,terrainshape,1,WESTRING_TERRAINSHAPE_SQUARE // Lightning Types LightningTypeCLPB=1,lightningtype,`CLPB`,WESTRING_LIGHTNINGTYPE_CLPB LightningTypeCLSB=1,lightningtype,`CLSB`,WESTRING_LIGHTNINGTYPE_CLSB LightningTypeDRAB=1,lightningtype,`DRAB`,WESTRING_LIGHTNINGTYPE_DRAB LightningTypeDRAL=1,lightningtype,`DRAL`,WESTRING_LIGHTNINGTYPE_DRAL LightningTypeDRAM=1,lightningtype,`DRAM`,WESTRING_LIGHTNINGTYPE_DRAM LightningTypeAFOD=1,lightningtype,`AFOD`,WESTRING_LIGHTNINGTYPE_AFOD LightningTypeFORK=1,lightningtype,`FORK`,WESTRING_LIGHTNINGTYPE_FORK LightningTypeHWPB=1,lightningtype,`HWPB`,WESTRING_LIGHTNINGTYPE_HWPB LightningTypeHWSB=1,lightningtype,`HWSB`,WESTRING_LIGHTNINGTYPE_HWSB LightningTypeCHIM=1,lightningtype,`CHIM`,WESTRING_LIGHTNINGTYPE_CHIM LightningTypeLEAS=1,lightningtype,`LEAS`,WESTRING_LIGHTNINGTYPE_LEAS LightningTypeMBUR=1,lightningtype,`MBUR`,WESTRING_LIGHTNINGTYPE_MBUR LightningTypeMFPB=1,lightningtype,`MFPB`,WESTRING_LIGHTNINGTYPE_MFPB LightningTypeSPLK=1,lightningtype,`SPLK`,WESTRING_LIGHTNINGTYPE_SPLK // Image types ImageTypeShadow=1,imagetype,0,WESTRING_IMAGETYPE_SHADOW ImageTypeSelection=1,imagetype,1,WESTRING_IMAGETYPE_SELECTION ImageTypeIndicator=1,imagetype,2,WESTRING_IMAGETYPE_INDICATOR ImageTypeOcclusionMark=1,imagetype,3,WESTRING_IMAGETYPE_OCCLUSIONMARK ImageTypeUbersplat=1,imagetype,4,WESTRING_IMAGETYPE_UBERSPLAT ImageTypeLast=1,imagetype,5,WESTRING_IMAGETYPE_LAST // Ubersplat codes UbersplatTypeTEST=1,ubersplattype,`TEST`,WESTRING_UBERSPLAT_TEST UbersplatTypeLSDS=1,ubersplattype,`LSDS`,WESTRING_UBERSPLAT_LSDS UbersplatTypeLSDM=1,ubersplattype,`LSDM`,WESTRING_UBERSPLAT_LSDM UbersplatTypeLSDL=1,ubersplattype,`LSDL`,WESTRING_UBERSPLAT_LSDL UbersplatTypeHCRT=1,ubersplattype,`HCRT`,WESTRING_UBERSPLAT_HCRT UbersplatTypeUDSU=1,ubersplattype,`UDSU`,WESTRING_UBERSPLAT_UDSU UbersplatTypeDNCS=1,ubersplattype,`DNCS`,WESTRING_UBERSPLAT_DNCS UbersplatTypeHMTP=1,ubersplattype,`HMTP`,WESTRING_UBERSPLAT_HMTP UbersplatTypeSCTP=1,ubersplattype,`SCTP`,WESTRING_UBERSPLAT_SCTP UbersplatTypeAMRC=1,ubersplattype,`AMRC`,WESTRING_UBERSPLAT_AMRC UbersplatTypeDRKC=1,ubersplattype,`DRKC`,WESTRING_UBERSPLAT_DRKC UbersplatTypeDOSB=1,ubersplattype,`DOSB`,WESTRING_UBERSPLAT_DOSB UbersplatTypeDOMB=1,ubersplattype,`DOMB`,WESTRING_UBERSPLAT_DOMB UbersplatTypeDOLB=1,ubersplattype,`DOLB`,WESTRING_UBERSPLAT_DOLB UbersplatTypeDHSB=1,ubersplattype,`DHSB`,WESTRING_UBERSPLAT_DHSB UbersplatTypeDHMB=1,ubersplattype,`DHMB`,WESTRING_UBERSPLAT_DHMB UbersplatTypeDHLB=1,ubersplattype,`DHLB`,WESTRING_UBERSPLAT_DHLB UbersplatTypeDUSB=1,ubersplattype,`DUSB`,WESTRING_UBERSPLAT_DUSB UbersplatTypeDUMB=1,ubersplattype,`DUMB`,WESTRING_UBERSPLAT_DUMB UbersplatTypeDULB=1,ubersplattype,`DULB`,WESTRING_UBERSPLAT_DULB UbersplatTypeDNSB=1,ubersplattype,`DNSB`,WESTRING_UBERSPLAT_DNSB UbersplatTypeDNMB=1,ubersplattype,`DNMB`,WESTRING_UBERSPLAT_DNMB UbersplatTypeDNSA=1,ubersplattype,`DNSA`,WESTRING_UBERSPLAT_DNSA UbersplatTypeDNMA=1,ubersplattype,`DNMA`,WESTRING_UBERSPLAT_DNMA UbersplatTypeHSMA=1,ubersplattype,`HSMA`,WESTRING_UBERSPLAT_HSMA UbersplatTypeHMED=1,ubersplattype,`HMED`,WESTRING_UBERSPLAT_HMED UbersplatTypeHLAR=1,ubersplattype,`HLAR`,WESTRING_UBERSPLAT_HLAR UbersplatTypeOSMA=1,ubersplattype,`OSMA`,WESTRING_UBERSPLAT_OSMA UbersplatTypeOMED=1,ubersplattype,`OMED`,WESTRING_UBERSPLAT_OMED UbersplatTypeOLAR=1,ubersplattype,`OLAR`,WESTRING_UBERSPLAT_OLAR UbersplatTypeUSMA=1,ubersplattype,`USMA`,WESTRING_UBERSPLAT_USMA UbersplatTypeUMED=1,ubersplattype,`UMED`,WESTRING_UBERSPLAT_UMED UbersplatTypeULAR=1,ubersplattype,`ULAR`,WESTRING_UBERSPLAT_ULAR UbersplatTypeESMA=1,ubersplattype,`ESMA`,WESTRING_UBERSPLAT_ESMA UbersplatTypeEMDA=1,ubersplattype,`EMDA`,WESTRING_UBERSPLAT_EMDA UbersplatTypeESMB=1,ubersplattype,`ESMB`,WESTRING_UBERSPLAT_ESMB UbersplatTypeEMDB=1,ubersplattype,`EMDB`,WESTRING_UBERSPLAT_EMDB UbersplatTypeHTOW=1,ubersplattype,`HTOW`,WESTRING_UBERSPLAT_HTOW UbersplatTypeHCAS=1,ubersplattype,`HCAS`,WESTRING_UBERSPLAT_HCAS UbersplatTypeNGOL=1,ubersplattype,`NGOL`,WESTRING_UBERSPLAT_NGOL UbersplatTypeTHND=1,ubersplattype,`THND`,WESTRING_UBERSPLAT_THND UbersplatTypeNDGS=1,ubersplattype,`NDGS`,WESTRING_UBERSPLAT_NDGS UbersplatTypeCLTS=1,ubersplattype,`CLTS`,WESTRING_UBERSPLAT_CLTS UbersplatTypeHFS1=1,ubersplattype,`HFS1`,WESTRING_UBERSPLAT_HFS1 UbersplatTypeHFS2=1,ubersplattype,`HFS2`,WESTRING_UBERSPLAT_HFS2 UbersplatTypeUSBR=1,ubersplattype,`USBR`,WESTRING_UBERSPLAT_USBR UbersplatTypeNLAR=1,ubersplattype,`NLAR`,WESTRING_UBERSPLAT_NLAR UbersplatTypeNMED=1,ubersplattype,`NMED`,WESTRING_UBERSPLAT_NMED UbersplatTypeDPSW=1,ubersplattype,`DPSW`,WESTRING_UBERSPLAT_DPSW UbersplatTypeDPSE=1,ubersplattype,`DPSE`,WESTRING_UBERSPLAT_DPSE UbersplatTypeNVOL=1,ubersplattype,`NVOL`,WESTRING_UBERSPLAT_NVOL UbersplatTypeNVCR=1,ubersplattype,`NVCR`,WESTRING_UBERSPLAT_NVCR //*************************************************************************** [TriggerEvents] // Defines events available in the editor // Key: script event function // Value 0: first game version in which this function is valid // Value 1+: argument types // Note that the first argument is always a `trigger`, and is excluded here // Special events not defined in scripts, handled internally by the editor MapInitializationEvent=0,nothing _MapInitializationEvent_Defaults= _MapInitializationEvent_Category=TC_NOTHING // Destructible events TriggerRegisterDeathEvent=0,destructable _TriggerRegisterDeathEvent_Defaults=_ _TriggerRegisterDeathEvent_Category=TC_DESTRUCT TriggerRegisterDestDeathInRegionEvent=1,rect _TriggerRegisterDestDeathInRegionEvent_Defaults=_ _TriggerRegisterDestDeathInRegionEvent_Category=TC_DESTRUCT // Dialog events TriggerRegisterDialogEventBJ=0,dialog _TriggerRegisterDialogEventBJ_Defaults=_ _TriggerRegisterDialogEventBJ_Category=TC_DIALOG // Game events TriggerRegisterGameStateEventTimeOfDay=0,limitop,real _TriggerRegisterGameStateEventTimeOfDay_Defaults=LimitOpEqual,12 _TriggerRegisterGameStateEventTimeOfDay_Limits=_,_,0,24 _TriggerRegisterGameStateEventTimeOfDay_Category=TC_GAME TriggerRegisterVariableEvent=0,VarAsString_Real,limitop,real _TriggerRegisterVariableEvent_Defaults=_,LimitOpEqual,0 _TriggerRegisterVariableEvent_Category=TC_GAME TriggerRegisterGameLoadedEventBJ=1,nothing _TriggerRegisterGameLoadedEventBJ_Defaults= _TriggerRegisterGameLoadedEventBJ_Category=TC_GAME TriggerRegisterGameSavedEventBJ=1,nothing _TriggerRegisterGameSavedEventBJ_Defaults= _TriggerRegisterGameSavedEventBJ_Category=TC_GAME TriggerRegisterShowSkillEventBJ=0,nothing _TriggerRegisterShowSkillEventBJ_Defaults= _TriggerRegisterShowSkillEventBJ_Category=TC_GAME TriggerRegisterBuildSubmenuEventBJ=0,nothing _TriggerRegisterBuildSubmenuEventBJ_Defaults= _TriggerRegisterBuildSubmenuEventBJ_Category=TC_GAME TriggerRegisterGameEvent=1,gameevent _TriggerRegisterGameEvent_Defaults=GameEventTourneyNow _TriggerRegisterGameEvent_Category=TC_GAME // Player events TriggerRegisterPlayerChatEvent=0,player,string,chatmatchtype _TriggerRegisterPlayerChatEvent_Defaults=Player00,_,ChatMatchTypeExact _TriggerRegisterPlayerChatEvent_Category=TC_PLAYER TriggerRegisterPlayerEventEndCinematic=0,player _TriggerRegisterPlayerEventEndCinematic_Defaults=Player00 _TriggerRegisterPlayerEventEndCinematic_Category=TC_PLAYER TriggerRegisterPlayerSelectionEventBJ=0,player,seldeseloption _TriggerRegisterPlayerSelectionEventBJ_Defaults=Player00,SelDeselOptionSel _TriggerRegisterPlayerSelectionEventBJ_Category=TC_PLAYER TriggerRegisterPlayerKeyEventBJ=1,player,keyeventtype,keyeventkey _TriggerRegisterPlayerKeyEventBJ_Defaults=Player00,KeyEventTypeDepress,KeyEventKeyLeft _TriggerRegisterPlayerKeyEventBJ_Category=TC_PLAYER TriggerRegisterPlayerMouseEventBJ=1,player,mouseeventtype _TriggerRegisterPlayerMouseEventBJ_Defaults=Player00,MouseEventTypeDown _TriggerRegisterPlayerMouseEventBJ_Category=TC_PLAYER TriggerRegisterPlayerStateEvent=0,player,playerstate,limitop,real _TriggerRegisterPlayerStateEvent_Defaults=Player00,PlayerStateGold,LimitOpGreaterThanOrEqual,1000 _TriggerRegisterPlayerStateEvent_Category=TC_PLAYER TriggerRegisterPlayerEventAllianceChanged=0,player _TriggerRegisterPlayerEventAllianceChanged_Defaults=Player00 _TriggerRegisterPlayerEventAllianceChanged_Category=TC_PLAYER TriggerRegisterPlayerAllianceChange=0,player,alliancetype _TriggerRegisterPlayerAllianceChange_Defaults=Player00,AllianceTypePassive _TriggerRegisterPlayerAllianceChange_Category=TC_PLAYER TriggerRegisterPlayerEventVictory=0,player _TriggerRegisterPlayerEventVictory_Defaults=Player00 _TriggerRegisterPlayerEventVictory_Category=TC_PLAYER TriggerRegisterPlayerEventDefeat=0,player _TriggerRegisterPlayerEventDefeat_Defaults=Player00 _TriggerRegisterPlayerEventDefeat_Category=TC_PLAYER TriggerRegisterPlayerEventLeave=1,player _TriggerRegisterPlayerEventLeave_Defaults=Player00 _TriggerRegisterPlayerEventLeave_Category=TC_PLAYER // Timer events TriggerRegisterTimerEventSingle=0,real _TriggerRegisterTimerEventSingle_Defaults=5 _TriggerRegisterTimerEventSingle_Limits=0,_ _TriggerRegisterTimerEventSingle_Category=TC_TIME TriggerRegisterTimerEventPeriodic=0,real _TriggerRegisterTimerEventPeriodic_Defaults=2 _TriggerRegisterTimerEventPeriodic_Limits=0,_ _TriggerRegisterTimerEventPeriodic_Category=TC_TIME TriggerRegisterTimerExpireEventBJ=0,timer _TriggerRegisterTimerExpireEventBJ_Defaults=_ _TriggerRegisterTimerExpireEventBJ_Category=TC_TIME // Unit events TriggerRegisterUnitEvent=0,unit,unitevent _TriggerRegisterUnitEvent_Defaults=_,UnitEventDeath _TriggerRegisterUnitEvent_Category=TC_UNIT TriggerRegisterPlayerUnitEventSimple=0,player,playerunitevent _TriggerRegisterPlayerUnitEventSimple_Defaults=Player00,PlayerUnitEventDeath _TriggerRegisterPlayerUnitEventSimple_Category=TC_UNIT TriggerRegisterAnyUnitEventBJ=1,playerunitevent _TriggerRegisterAnyUnitEventBJ_Defaults=PlayerUnitEventDeath _TriggerRegisterAnyUnitEventBJ_Category=TC_UNIT TriggerRegisterEnterRectSimple=0,rect _TriggerRegisterEnterRectSimple_Defaults=_ _TriggerRegisterEnterRectSimple_Category=TC_UNIT TriggerRegisterLeaveRectSimple=0,rect _TriggerRegisterLeaveRectSimple_Defaults=_ _TriggerRegisterLeaveRectSimple_Category=TC_UNIT TriggerRegisterUnitInRangeSimple=0,real,unit _TriggerRegisterUnitInRangeSimple_Defaults=256,_ _TriggerRegisterUnitInRangeSimple_Defaults=0,_,_,_ _TriggerRegisterUnitInRangeSimple_Category=TC_UNIT TriggerRegisterUnitLifeEvent=0,unit,limitop,real _TriggerRegisterUnitLifeEvent_Defaults=_,LimitOpLessThan,50 _TriggerRegisterUnitLifeEvent_Category=TC_UNIT TriggerRegisterUnitManaEvent=0,unit,limitop,real _TriggerRegisterUnitManaEvent_Defaults=_,LimitOpLessThan,50 _TriggerRegisterUnitManaEvent_Category=TC_UNIT //*************************************************************************** [TriggerConditions] // Defines boolean condition functions // Key: condition function name // Value 0: first game version in which this function is valid // Value 1+: argument types OperatorCompareBoolean=0,boolean,EqualNotEqualOperator,boolean _OperatorCompareBoolean_Defaults=IsUnitType,OperatorEqualENE,true _OperatorCompareBoolean_Category=TC_CONDITION _OperatorCompareBoolean_UseWithAI=1 _OperatorCompareBoolean_AIDefaults=true,OperatorEqualENE,true OperatorCompareAbilityId=1,abilcode,EqualNotEqualOperator,abilcode _OperatorCompareAbilityId_Defaults=GetSpellAbilityId,OperatorEqualENE,AUan _OperatorCompareAbilityId_Category=TC_CONDITION OperatorCompareBuffId=1,buffcode,EqualNotEqualOperator,buffcode _OperatorCompareBuffId_Defaults=_,OperatorEqualENE,_ _OperatorCompareBuffId_Category=TC_CONDITION OperatorCompareDestructible=0,destructable,EqualNotEqualOperator,destructable _OperatorCompareDestructible_Defaults=_,OperatorEqualENE,_ _OperatorCompareDestructible_Category=TC_CONDITION OperatorCompareDestructableCode=0,destructablecode,EqualNotEqualOperator,destructablecode _OperatorCompareDestructableCode_Defaults=GetDestructableTypeId,OperatorEqualENE,LTlt _OperatorCompareDestructableCode_Category=TC_CONDITION OperatorCompareButton=0,button,EqualNotEqualOperator,button _OperatorCompareButton_Defaults=GetClickedButtonBJ,OperatorEqualENE,_ _OperatorCompareButton_Category=TC_CONDITION OperatorCompareGameDifficulty=0,gamedifficulty,EqualNotEqualOperator,gamedifficulty _OperatorCompareGameDifficulty_Defaults=GetGameDifficulty,OperatorEqualENE,GameDifficultyNormal _OperatorCompareGameDifficulty_Category=TC_CONDITION OperatorCompareGameSpeed=0,gamespeed,EqualNotEqualOperator,gamespeed _OperatorCompareGameSpeed_Defaults=GetGameSpeed,OperatorEqualENE,GameSpeedNormal _OperatorCompareGameSpeed_Category=TC_CONDITION OperatorCompareHeroSkill=0,heroskillcode,EqualNotEqualOperator,heroskillcode _OperatorCompareHeroSkill_Defaults=GetLearnedSkillBJ,OperatorEqualENE,HeroSkillBlizzard _OperatorCompareHeroSkill_Category=TC_CONDITION OperatorCompareInteger=0,integer,ComparisonOperator,integer _OperatorCompareInteger_Defaults=CountUnitsInGroup,OperatorEqual,0 _OperatorCompareInteger_Category=TC_CONDITION _OperatorCompareInteger_UseWithAI=1 _OperatorCompareInteger_AIDefaults=0,OperatorEqual,0 OperatorCompareItem=0,item,EqualNotEqualOperator,item _OperatorCompareItem_Defaults=_,OperatorEqualENE,_ _OperatorCompareItem_Category=TC_CONDITION OperatorCompareItemType=1,itemtype,EqualNotEqualOperator,itemtype _OperatorCompareItemType_Defaults=GetItemType,OperatorEqualENE,ItemTypePowerup _OperatorCompareItemType_Category=TC_CONDITION OperatorCompareItemCode=0,itemcode,EqualNotEqualOperator,itemcode _OperatorCompareItemCode_Defaults=GetItemTypeId,OperatorEqualENE,texp _OperatorCompareItemCode_Category=TC_CONDITION OperatorCompareMouseButton=1,mousebuttontype,EqualNotEqualOperator,mousebuttontype _OperatorCompareMouseButton_Defaults=GetTriggerPlayerMouseButton,OperatorEqualENE,MouseButtonTypeLeft _OperatorCompareMouseButton_Categroy=TC_CONDITION OperatorCompareMeleeDifficulty=1,aidifficulty,EqualNotEqualOperator,aidifficulty _OperatorCompareMeleeDifficulty_Defaults=GetAIDifficulty,OperatorEqualENE,AIDifficultyNormal _OperatorCompareMeleeDifficulty_Category=TC_CONDITION OperatorCompareOrderCode=0,ordercode,EqualNotEqualOperator,ordercode _OperatorCompareOrderCode_Defaults=GetIssuedOrderIdBJ,OperatorEqualENE,String2OrderIdBJ _OperatorCompareOrderCode_Category=TC_CONDITION OperatorComparePlayer=0,player,EqualNotEqualOperator,player _OperatorComparePlayer_Defaults=GetOwningPlayer,OperatorEqualENE,Player00 _OperatorComparePlayer_Category=TC_CONDITION OperatorComparePlayerColor=0,playercolor,EqualNotEqualOperator,playercolor _OperatorComparePlayerColor_Defaults=GetPlayerColor,OperatorEqualENE,Color00 _OperatorComparePlayerColor_Category=TC_CONDITION OperatorComparePlayerControl=0,mapcontrol,EqualNotEqualOperator,mapcontrol _OperatorComparePlayerControl_Defaults=GetPlayerController,OperatorEqualENE,MapControlUser _OperatorComparePlayerControl_Category=TC_CONDITION OperatorComparePlayerSlotStatus=0,playerslotstate,EqualNotEqualOperator,playerslotstate _OperatorComparePlayerSlotStatus_Defaults=GetPlayerSlotState,OperatorEqualENE,PlayerSlotStatePlaying _OperatorComparePlayerSlotStatus_Category=TC_CONDITION //OperatorComparePoint=0,location,EqualNotEqualOperator,location //_OperatorComparePoint_Defaults=_,OperatorEqualENE,_ //_OperatorComparePoint_Category=TC_CONDITION OperatorCompareRace=0,race,EqualNotEqualOperator,race _OperatorCompareRace_Defaults=GetPlayerRace,OperatorEqualENE,RaceHuman _OperatorCompareRace_Category=TC_CONDITION OperatorCompareReal=0,real,ComparisonOperator,real _OperatorCompareReal_Defaults=GetUnitStateSwap,OperatorGreaterEq,10 _OperatorCompareReal_Category=TC_CONDITION //OperatorCompareRegion=0,rect,EqualNotEqualOperator,rect //_OperatorCompareRegion_Defaults=_,OperatorEqualENE,_ //_OperatorCompareRegion_Category=TC_CONDITION OperatorCompareString=0,string,EqualNotEqualOperator,string _OperatorCompareString_Defaults=GetEventPlayerChatString,OperatorEqualENE,_ _OperatorCompareString_Category=TC_CONDITION OperatorCompareTechCode=0,techcode,EqualNotEqualOperator,techcode _OperatorCompareTechCode_Defaults=GetResearched,OperatorEqualENE,_ _OperatorCompareTechCode_Category=TC_CONDITION OperatorCompareTerrainType=1,terraintype,EqualNotEqualOperator,terraintype _OperatorCompareTerrainType_Defaults=GetTerrainTypeBJ,OperatorEqualENE,TerrainTypeLdrt _OperatorCompareTerrainType_Category=TC_CONDITION OperatorCompareTrigger=0,trigger,EqualNotEqualOperator,trigger _OperatorCompareTrigger_Defaults=_,OperatorEqualENE,_ _OperatorCompareTrigger_Category=TC_CONDITION OperatorCompareUnit=0,unit,EqualNotEqualOperator,unit _OperatorCompareUnit_Defaults=GetTriggerUnit,OperatorEqualENE,_ _OperatorCompareUnit_Category=TC_CONDITION OperatorCompareUnitCode=0,unitcode,EqualNotEqualOperator,unitcode _OperatorCompareUnitCode_Defaults=GetUnitTypeId,OperatorEqualENE,hfoo _OperatorCompareUnitCode_Category=TC_CONDITION GetBooleanAnd=0,boolcall,boolcall _GetBooleanAnd_Defaults=_,_ _GetBooleanAnd_Category=TC_CONDITION _GetBooleanAnd_UseWithAI=1 GetBooleanOr=0,boolcall,boolcall _GetBooleanOr_Defaults=_,_ _GetBooleanOr_Category=TC_CONDITION _GetBooleanOr_UseWithAI=1 // Specially handled by the editor AndMultiple=1,nothing _AndMultiple_Category=TC_CONDITION // Specially handled by the editor OrMultiple=1,nothing _OrMultiple_Category=TC_CONDITION //*************************************************************************** [TriggerActions] // Defines action functions // Key: action function name // Value 0: first game version in which this function is valid // Value 1+: argument types DoNothing=0,nothing _DoNothing_Defaults= _DoNothing_Category=TC_NOTHING CommentString=0,scriptcode _CommentString_Defaults=_ _CommentString_Category=TC_COMMENT CustomScriptCode=1,scriptcode _CustomScriptCode_Defaults=_ _CustomScriptCode_Category=TC_CUSTOM TriggerSleepAction=0,real _TriggerSleepAction_Defaults=2 _TriggerSleepAction_Limits=0,_ _TriggerSleepAction_Category=TC_WAIT PolledWait=1,real _PolledWait_Defaults=2 _PolledWait_Limits=0,_ _PolledWait_Category=TC_WAIT WaitForCondition=1,boolexpr,real _WaitForCondition_Defaults=_,1 _WaitForCondition_Limits=_,_,0.1,_ _WaitForCondition_Category=TC_WAIT WaitForSoundBJ=0,sound,real _WaitForSoundBJ_Defaults=GetLastPlayedSound,0 _WaitForSoundBJ_Category=TC_WAIT // Specially handled by the editor SetVariable=0,AnyGlobal,Null _SetVariable_Defaults=_,_ _SetVariable_Category=TC_SETVARIABLE // Specially handled by the editor ReturnAction=0,nothing _ReturnAction_Defaults= _ReturnAction_Category=TC_SKIPACTIONS // Specially handled by the editor IfThenElseMultiple=1,nothing _IfThenElseMultiple_Category=TC_LOGIC // Specially handled by the editor IfThenElse=0,boolexpr,code,code _IfThenElse_Defaults=_,DoNothing,DoNothing _IfThenElse_Category=TC_LOGIC // Specially handled by the editor ForLoopAMultiple=1,integer,integer _ForLoopAMultiple_Defaults=1,10 _ForLoopAMultiple_Category=TC_FORLOOP // Specially handled by the editor ForLoopBMultiple=1,integer,integer _ForLoopBMultiple_Defaults=1,10 _ForLoopBMultiple_Category=TC_FORLOOP // Specially handled by the editor ForLoopVarMultiple=1,integervar,integer,integer _ForLoopVarMultiple_Defaults=_,1,10 _ForLoopVarMultiple_Category=TC_FORLOOP // Specially handled by the editor ForLoopA=0,integer,integer,code _ForLoopA_Defaults=1,10,DoNothing _ForLoopA_Category=TC_FORLOOP // Specially handled by the editor ForLoopB=0,integer,integer,code _ForLoopB_Defaults=1,10,DoNothing _ForLoopB_Category=TC_FORLOOP // Specially handled by the editor ForLoopVar=1,integervar,integer,integer,code _ForLoopVar_Defaults=_,1,10,DoNothing _ForLoopVar_Category=TC_FORLOOP // AI actions StartMeleeAI=0,player,aiscript _StartMeleeAI_Defaults=Player00,"map.ai" _StartMeleeAI_Category=TC_AI StartCampaignAI=0,player,aiscript _StartCampaignAI_Defaults=Player00,"map.ai" _StartCampaignAI_Category=TC_AI CommandAI=0,player,integer,integer _CommandAI_Defaults=Player00,_,_ _CommandAI_Category=TC_AI RemoveGuardPosition=0,unit _RemoveGuardPosition_Defaults=_ _RemoveGuardPosition_Category=TC_AI RemoveAllGuardPositions=0,player _RemoveAllGuardPositions_Defaults=Player00 _RemoveAllGuardPositions_Category=TC_AI RecycleGuardPosition=0,unit _RecycleGuardPosition_Defaults=_ _RecycleGuardPosition_Category=TC_AI LockGuardPosition=1,unit _LockGuardPosition_Defaults=_ _LockGuardPosition_Category=TC_AI // Animation actions SetUnitAnimation=0,unit,string _SetUnitAnimation_Defaults=_,"stand" _SetUnitAnimation_Category=TC_ANIMATION SetUnitAnimationWithRarity=0,unit,string,raritycontrol _SetUnitAnimationWithRarity_Defaults=_,"stand",RarityControlFrequent _SetUnitAnimationWithRarity_Category=TC_ANIMATION QueueUnitAnimationBJ=0,unit,string _QueueUnitAnimationBJ_Defaults=_,"stand" _QueueUnitAnimationBJ_Category=TC_ANIMATION ResetUnitAnimation=0,unit _ResetUnitAnimation_Defaults=_ _ResetUnitAnimation_Category=TC_ANIMATION AddUnitAnimationPropertiesBJ=0,addremoveoption,string,unit _AddUnitAnimationPropertiesBJ_Defaults=AddRemoveAdd,"gold",_ _AddUnitAnimationPropertiesBJ_Category=TC_ANIMATION SetUnitLookAt=0,unit,unitfacingbone,unit,real,real,real _SetUnitLookAt_Defaults=_,UnitFacingBoneHead,_,0,0,90 _SetUnitLookAt_Category=TC_ANIMATION ResetUnitLookAt=0,unit _ResetUnitLookAt_Defaults=_ _ResetUnitLookAt_Category=TC_ANIMATION SetUnitScalePercent=0,unit,real,real,real _SetUnitScalePercent_Defaults=_,100,100,100 _SetUnitScalePercent_Limits=_,_,0,_,0,_,0,_ _SetUnitScalePercent_Category=TC_ANIMATION SetUnitVertexColorBJ=0,unit,real,real,real,real _SetUnitVertexColorBJ_Defaults=_,100,100,100,0 _SetUnitVertexColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _SetUnitVertexColorBJ_Category=TC_ANIMATION SetUnitTimeScalePercent=0,unit,real _SetUnitTimeScalePercent_Defaults=_,100 _SetUnitTimeScalePercent_Limits=_,_,0,_ _SetUnitTimeScalePercent_Category=TC_ANIMATION SetUnitTurnSpeedBJ=0,unit,real _SetUnitTurnSpeedBJ_Defaults=GetTriggerUnit,0.5 _SetUnitTurnSpeedBJ_Limits=_,_,0,1 _SetUnitTurnSpeedBJ_Category=TC_ANIMATION SetUnitBlendTimeBJ=0,unit,real _SetUnitBlendTimeBJ_Defaults=GetTriggerUnit,_ _SetUnitBlendTimeBJ_Category=TC_ANIMATION SetUnitFlyHeightBJ=0,unit,real,real _SetUnitFlyHeightBJ_Defaults=GetTriggerUnit,_,_ _SetUnitFlyHeightBJ_Category=TC_ANIMATION SetUnitPropWindowBJ=0,unit,real _SetUnitPropWindowBJ_Defaults=GetTriggerUnit,_ _SetUnitPropWindowBJ_Category=TC_ANIMATION SetDestructableAnimationBJ=0,destructable,string _SetDestructableAnimationBJ_Defaults=_,"stand" _SetDestructableAnimationBJ_Category=TC_ANIMATION QueueDestructableAnimationBJ=0,destructable,string _QueueDestructableAnimationBJ_Defaults=_,"stand" _QueueDestructableAnimationBJ_Category=TC_ANIMATION SetDestAnimationSpeedPercent=1,destructable,real _SetDestAnimationSpeedPercent_Defaults=_,100 _SetDestAnimationSpeedPercent_Category=TC_ANIMATION SetDoodadAnimationRectBJ=0,string,doodadcode,rect _SetDoodadAnimationRectBJ_Defaults="death",_,GetPlayableMapRect _SetDoodadAnimationRectBJ_Category=TC_ANIMATION SetDoodadAnimationBJ=0,string,doodadcode,real,location _SetDoodadAnimationBJ_Defaults="death",_,128,GetRectCenter _SetDoodadAnimationBJ_Category=TC_ANIMATION // Camera actions CameraSetupApplyForPlayer=0,cameraapplyoption,camerasetup,player,real _CameraSetupApplyForPlayer_Defaults=CameraApply,_,Player00,0 _CameraSetupApplyForPlayer_Limits=_,_,_,_,_,_,0,_ _CameraSetupApplyForPlayer_Category=TC_CAMERA PanCameraToTimedLocForPlayer=0,player,location,real _PanCameraToTimedLocForPlayer_Defaults=Player00,GetRectCenter,0 _PanCameraToTimedLocForPlayer_Limits=_,_,_,_,0,_ _PanCameraToTimedLocForPlayer_Category=TC_CAMERA PanCameraToTimedLocWithZForPlayer=0,player,location,real,real _PanCameraToTimedLocWithZForPlayer_Defaults=Player00,GetRectCenter,0,0 _PanCameraToTimedLocWithZForPlayer_Limits=_,_,_,_,_,_,0,_ _PanCameraToTimedLocWithZForPlayer_Category=TC_CAMERA SmartCameraPanBJ=0,player,location,real _SmartCameraPanBJ_Defaults=Player00,GetRectCenter,0.5 _SmartCameraPanBJ_Limits=_,_,_,_,0,_ _SmartCameraPanBJ_Category=TC_CAMERA SetCameraFieldForPlayer=0,player,camerafield,real,real _SetCameraFieldForPlayer_Defaults=Player00,CameraFieldTargetDistance,CameraSetupGetFieldSwap,0 _SetCameraFieldForPlayer_Limits=_,_,_,_,_,_,0,_ _SetCameraFieldForPlayer_Category=TC_CAMERA RotateCameraAroundLocBJ=1,real,location,player,real _RotateCameraAroundLocBJ_Defaults=90,GetRectCenter,Player00,2 _RotateCameraAroundLocBJ_Limits=_,_,_,_,_,_,0,_ _RotateCameraAroundLocBJ_Category=TC_CAMERA SetCameraTargetControllerNoZForPlayer=0,player,unit,real,real,cameraorientationoption _SetCameraTargetControllerNoZForPlayer_Defaults=Player00,GetTriggerUnit,0,0,CameraOrientationNormal _SetCameraTargetControllerNoZForPlayer_Category=TC_CAMERA SetCameraOrientControllerForPlayerBJ=0,player,unit,real,real _SetCameraOrientControllerForPlayerBJ_Defaults=Player00,GetTriggerUnit,0,0 _SetCameraOrientControllerForPlayerBJ_Category=TC_CAMERA SetCinematicCameraForPlayer=0,player,modelfile _SetCinematicCameraForPlayer_Defaults=Player00,"cinematic.mdl" _SetCinematicCameraForPlayer_Category=TC_CAMERA StopCameraForPlayerBJ=0,player _StopCameraForPlayerBJ_Defaults=Player00 _StopCameraForPlayerBJ_Category=TC_CAMERA ResetToGameCameraForPlayer=0,player,real _ResetToGameCameraForPlayer_Defaults=Player00,0 _ResetToGameCameraForPlayer_Limits=_,_,0,_ _ResetToGameCameraForPlayer_Category=TC_CAMERA CameraSetSmoothingFactorBJ=0,real _CameraSetSmoothingFactorBJ_Defaults=1 _CameraSetSmoothingFactorBJ_Limits=0,_ _CameraSetSmoothingFactorBJ_Category=TC_CAMERA CameraResetSmoothingFactorBJ=0,nothing _CameraResetSmoothingFactorBJ_Defaults= _CameraResetSmoothingFactorBJ_Category=TC_CAMERA CameraSetSourceNoiseForPlayer=0,player,real,real _CameraSetSourceNoiseForPlayer_Defaults=Player00,10,0.1 _CameraSetSourceNoiseForPlayer_Category=TC_CAMERA CameraSetTargetNoiseForPlayer=0,player,real,real _CameraSetTargetNoiseForPlayer_Defaults=Player00,10,0.1 _CameraSetTargetNoiseForPlayer_Category=TC_CAMERA CameraSetEQNoiseForPlayer=1,player,real _CameraSetEQNoiseForPlayer_Defaults=Player00,3 _CameraSetEQNoiseForPlayer_Limits=_,_,0,_ _CameraSetEQNoiseForPlayer_Category=TC_CAMERA CameraClearNoiseForPlayer=0,player _CameraClearNoiseForPlayer_Defaults=Player00 _CameraClearNoiseForPlayer_Category=TC_CAMERA AdjustCameraBoundsForPlayerBJ=0,cameraboundsadjusttype,player,real,real,real,real _AdjustCameraBoundsForPlayerBJ_Defaults=CameraBoundsAdjustAdd,Player00,0,0,0,0 _AdjustCameraBoundsForPlayerBJ_Category=TC_CAMERA SetCameraBoundsToRectForPlayerBJ=0,player,rect _SetCameraBoundsToRectForPlayerBJ_Defaults=Player00,_ _SetCameraBoundsToRectForPlayerBJ_Category=TC_CAMERA SetCameraQuickPositionLocForPlayer=0,player,location _SetCameraQuickPositionLocForPlayer_Defaults=Player00,GetRectCenter _SetCameraQuickPositionLocForPlayer_Category=TC_CAMERA // Cinematic actions TransmissionFromUnitWithNameBJ=0,force,unit,StringExt,sound,StringExt,addsettooption,real,waitdontoption _TransmissionFromUnitWithNameBJ_Defaults=GetPlayersAll,_,_,SoundNull,_,AddSetToAdd,0,WaitDontWait _TransmissionFromUnitWithNameBJ_Category=TC_CINEMATIC TransmissionFromUnitTypeWithNameBJ=0,force,player,unitcode,StringExt,location,sound,StringExt,addsettooption,real,waitdontoption _TransmissionFromUnitTypeWithNameBJ_Defaults=GetPlayersAll,Player00,hfoo,_,GetRectCenter,SoundNull,_,AddSetToAdd,0,WaitDontWait _TransmissionFromUnitTypeWithNameBJ_Category=TC_CINEMATIC ForceCinematicSubtitlesBJ=1,onoffoption _ForceCinematicSubtitlesBJ_Defaults=OnOffOn _ForceCinematicSubtitlesBJ_Category=TC_CINEMATIC CinematicModeBJ=0,onoffoption,force _CinematicModeBJ_Defaults=OnOffOn,GetPlayersAll _CinematicModeBJ_Category=TC_CINEMATIC CinematicModeExBJ=1,onoffoption,force,real _CinematicModeExBJ_Defaults=OnOffOn,GetPlayersAll,0.2 _CinematicModeExBJ_Category=TC_CINEMATIC CinematicFadeBJ=0,fadetypeoption,real,cinefiltertexture,real,real,real,real _CinematicFadeBJ_Defaults=FadeTypeOptionFadeOutIn,2,CineFilterTextureWhite,0,0,0,0 _CinematicFadeBJ_Limits=_,_,0,_,_,_,0,100,0,100,0,100,0,100 _CinematicFadeBJ_Category=TC_CINEMATIC CinematicFilterGenericBJ=0,real,blendmode,cinefiltertexture,real,real,real,real,real,real,real,real _CinematicFilterGenericBJ_Defaults=2,BlendModeBlend,CineFilterTextureWhite,100,100,100,100,0,0,0,0 _CinematicFilterGenericBJ_Limits=0,_,_,_,_,_,0,100,0,100,0,100,0,100,0,100,0,100,0,100,0,100 _CinematicFilterGenericBJ_Category=TC_CINEMATIC DisplayCineFilterBJ=0,showhideoption _DisplayCineFilterBJ_Defaults=ShowHideHide _DisplayCineFilterBJ_Category=TC_CINEMATIC PingMinimapLocForForce=0,force,location,real _PingMinimapLocForForce_Defaults=GetPlayersAll,GetRectCenter,1 _PingMinimapLocForForce_Limits=_,_,_,_,0,_ _PingMinimapLocForForce_Category=TC_CINEMATIC PingMinimapLocForForceEx=1,force,location,real,minimappingstyle,real,real,real _PingMinimapLocForForceEx_Defaults=GetPlayersAll,GetRectCenter,1,MinimapPingStyleSimple,100,100,100 _PingMinimapLocForForceEx_Limits=_,_,_,_,0,_,_,_,0,100,0,100,0,100 _PingMinimapLocForForceEx_Category=TC_CINEMATIC UnitAddIndicatorBJ=0,unit,real,real,real,real _UnitAddIndicatorBJ_Defaults=_,100,100,100,0 _UnitAddIndicatorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _UnitAddIndicatorBJ_Category=TC_CINEMATIC DestructableAddIndicatorBJ=0,destructable,real,real,real,real _DestructableAddIndicatorBJ_Defaults=_,100,100,100,0 _DestructableAddIndicatorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _DestructableAddIndicatorBJ_Category=TC_CINEMATIC ItemAddIndicatorBJ=0,item,real,real,real,real _ItemAddIndicatorBJ_Defaults=_,100,100,100,0 _ItemAddIndicatorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _ItemAddIndicatorBJ_Category=TC_CINEMATIC ClearTextMessagesBJ=0,force _ClearTextMessagesBJ_Defaults=GetPlayersAll _ClearTextMessagesBJ_Category=TC_CINEMATIC ShowInterfaceForceOff=0,force,real _ShowInterfaceForceOff_Defaults=GetPlayersAll,2 _ShowInterfaceForceOff_Limits=_,_,0,_ _ShowInterfaceForceOff_Category=TC_CINEMATIC ShowInterfaceForceOn=0,force,real _ShowInterfaceForceOn_Defaults=GetPlayersAll,2 _ShowInterfaceForceOn_Limits=_,_,0,_ _ShowInterfaceForceOn_Category=TC_CINEMATIC SetUserControlForceOff=0,force _SetUserControlForceOff_Defaults=GetPlayersAll _SetUserControlForceOff_Category=TC_CINEMATIC SetUserControlForceOn=0,force _SetUserControlForceOn_Defaults=GetPlayersAll _SetUserControlForceOn_Category=TC_CINEMATIC EnableOcclusionBJ=0,enabledisableoption,force _EnableOcclusionBJ_Defaults=EnableDisableDisable,GetPlayersAll _EnableOcclusionBJ_Category=TC_CINEMATIC EnableWorldFogBoundaryBJ=0,enabledisableoption,force _EnableWorldFogBoundaryBJ_Defaults=EnableDisableDisable,GetPlayersAll _EnableWorldFogBoundaryBJ_Category=TC_CINEMATIC // Countdown Timer actions StartTimerBJ=0,timer,periodicoption,real _StartTimerBJ_Defaults=_,PeriodicOptionOneTime,30 _StartTimerBJ_Limits=_,_,_,_,0,_ _StartTimerBJ_Category=TC_TIMER PauseTimerBJ=0,pauseresumeoption,timer _PauseTimerBJ_Defaults=PauseResumePause,GetLastCreatedTimerBJ _PauseTimerBJ_Category=TC_TIMER CreateTimerDialogBJ=0,timer,StringExt _CreateTimerDialogBJ_Defaults=GetLastCreatedTimerBJ,_ _CreateTimerDialogBJ_Category=TC_TIMER DestroyTimerDialogBJ=0,timerdialog _DestroyTimerDialogBJ_Defaults=GetLastCreatedTimerDialogBJ _DestroyTimerDialogBJ_Category=TC_TIMER TimerDialogDisplayForPlayerBJ=1,showhideoption,timerdialog,player _TimerDialogDisplayForPlayerBJ_Defaults=ShowHideHide,GetLastCreatedTimerDialogBJ,Player00 _TimerDialogDisplayForPlayerBJ_Category=TC_TIMER TimerDialogDisplayBJ=0,showhideoption,timerdialog _TimerDialogDisplayBJ_Defaults=ShowHideHide,GetLastCreatedTimerDialogBJ _TimerDialogDisplayBJ_Category=TC_TIMER TimerDialogSetTitleBJ=0,timerdialog,StringExt _TimerDialogSetTitleBJ_Defaults=GetLastCreatedTimerDialogBJ,_ _TimerDialogSetTitleBJ_Category=TC_TIMER TimerDialogSetTitleColorBJ=0,timerdialog,real,real,real,real _TimerDialogSetTitleColorBJ_Defaults=GetLastCreatedTimerDialogBJ,100,80,20,0 _TimerDialogSetTitleColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _TimerDialogSetTitleColorBJ_Category=TC_TIMER TimerDialogSetTimeColorBJ=0,timerdialog,real,real,real,real _TimerDialogSetTimeColorBJ_Defaults=GetLastCreatedTimerDialogBJ,100,80,20,0 _TimerDialogSetTimeColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _TimerDialogSetTimeColorBJ_Category=TC_TIMER //TimerDialogSetSpeedBJ=0,timerdialog,real //_TimerDialogSetSpeedBJ_Defaults=GetLastCreatedTimerDialogBJ,1 //_TimerDialogSetSpeedBJ_Category=TC_TIMER // Destructable actions CreateDestructableLoc=0,destructablecode,location,real,real,integer _CreateDestructableLoc_Defaults=LTlt,GetRectCenter,GetRandomDirectionDeg,1,0 _CreateDestructableLoc_Limits=_,_,_,_,_,_,0,_,0,_ _CreateDestructableLoc_Category=TC_DESTRUCT CreateDeadDestructableLocBJ=0,destructablecode,location,real,real,integer _CreateDeadDestructableLocBJ_Defaults=LTlt,GetRectCenter,GetRandomDirectionDeg,1,0 _CreateDeadDestructableLocBJ_Limits=_,_,_,_,_,_,0,_,0,_ _CreateDeadDestructableLocBJ_Category=TC_DESTRUCT KillDestructable=0,destructable _KillDestructable_Defaults=GetLastCreatedDestructable _KillDestructable_Category=TC_DESTRUCT RemoveDestructable=0,destructable _RemoveDestructable_Defaults=GetLastCreatedDestructable _RemoveDestructable_Category=TC_DESTRUCT DestructableRestoreLife=0,destructable,real,showhideoption _DestructableRestoreLife_Defaults=GetLastCreatedDestructable,GetDestructableMaxLife,ShowHideShow _DestructableRestoreLife_Category=TC_DESTRUCT ShowDestructableBJ=1,showhideoption,destructable _ShowDestructableBJ_Defaults=ShowHideHide,GetLastCreatedDestructable _ShowDestructableBJ_Category=TC_DESTRUCT SetDestructableLifePercentBJ=0,destructable,real _SetDestructableLifePercentBJ_Defaults=GetLastCreatedDestructable,100 _SetDestructableLifePercentBJ_Limits=_,_,0,100 _SetDestructableLifePercentBJ_Category=TC_DESTRUCT SetDestructableLife=0,destructable,real _SetDestructableLife_Defaults=GetLastCreatedDestructable,GetDestructableMaxLife _SetDestructableLife_Limits=_,_,0,_ _SetDestructableLife_Category=TC_DESTRUCT SetDestructableMaxLifeBJ=0,destructable,real _SetDestructableMaxLifeBJ_Defaults=GetLastCreatedDestructable,100 _SetDestructableMaxLifeBJ_Limits=_,_,0,_ _SetDestructableMaxLifeBJ_Category=TC_DESTRUCT ModifyGateBJ=0,gateoperation,destructable _ModifyGateBJ_Defaults=GateOperationOpen,_ _ModifyGateBJ_Category=TC_DESTRUCT ChangeElevatorWalls=1,elevatorwallop,elevatorwalltype,destructable _ChangeElevatorWalls_Defaults=ElevatorWallOpClose,ElevatorWallTypeAll,_ _ChangeElevatorWalls_Category=TC_DESTRUCT ChangeElevatorHeight=1,destructable,integer _ChangeElevatorHeight_Defaults=_,1 _ChangeElevatorHeight_Limits=_,_,1,3 _ChangeElevatorHeight_Category=TC_DESTRUCT SetDestructableInvulnerableBJ=0,destructable,invulnerableoption _SetDestructableInvulnerableBJ_Defaults=GetLastCreatedDestructable,InvulnerabilityInvulnerable _SetDestructableInvulnerableBJ_Category=TC_DESTRUCT SetDestructableOccluderHeight=1,destructable,real _SetDestructableOccluderHeight_Defaults=_,128 _SetDestructableOccluderHeight_Category=TC_DESTRUCT EnumDestructablesInRectAllMultiple=1,rect _EnumDestructablesInRectAllMultiple_Defaults=GetPlayableMapRect _EnumDestructablesInRectAllMultiple_Category=TC_DESTRUCT _EnumDestructablesInRectAllMultiple_ScriptName=EnumDestructablesInRectAll EnumDestructablesInCircleBJMultiple=1,real,location _EnumDestructablesInCircleBJMultiple_Defaults=256,GetRectCenter _EnumDestructablesInCircleBJMultiple_Category=TC_DESTRUCT _EnumDestructablesInCircleBJMultiple_ScriptName=EnumDestructablesInCircleBJ EnumDestructablesInRectAll=0,rect,code _EnumDestructablesInRectAll_Defaults=GetPlayableMapRect,DoNothing _EnumDestructablesInRectAll_Category=TC_DESTRUCT EnumDestructablesInCircleBJ=0,real,location,code _EnumDestructablesInCircleBJ_Defaults=256,GetRectCenter,DoNothing _EnumDestructablesInCircleBJ_Category=TC_DESTRUCT // Dialog actions DialogDisplayBJ=0,showhideoption,dialog,player _DialogDisplayBJ_Defaults=ShowHideShow,_,Player00 _DialogDisplayBJ_Category=TC_DIALOG DialogSetMessageBJ=0,dialog,StringExt _DialogSetMessageBJ_Defaults=_,_ _DialogSetMessageBJ_Category=TC_DIALOG DialogAddButtonBJ=0,dialog,StringExt _DialogAddButtonBJ_Defaults=_,_ _DialogAddButtonBJ_Category=TC_DIALOG DialogClearBJ=0,dialog _DialogClearBJ_Defaults=_ _DialogClearBJ_Category=TC_DIALOG // Environment actions AddWeatherEffectSaveLast=0,rect,weathereffectcode _AddWeatherEffectSaveLast_Defaults=GetPlayableMapRect,WeatherAshenvaleHeavyRain _AddWeatherEffectSaveLast_Category=TC_ENVIRONMENT EnableWeatherEffect=0,weathereffect,onoffoption _EnableWeatherEffect_Defaults=GetLastCreatedWeatherEffect,OnOffOn _EnableWeatherEffect_Category=TC_ENVIRONMENT RemoveWeatherEffectBJ=0,weathereffect _RemoveWeatherEffectBJ_Defaults=GetLastCreatedWeatherEffect _RemoveWeatherEffectBJ_Category=TC_ENVIRONMENT TerrainDeformationCraterBJ=1,real,cratertype,location,real,real _TerrainDeformationCraterBJ_Defaults=0.5,CraterTypeTemporary,GetRectCenter,512,64 _TerrainDeformationCraterBJ_Limits=0.01,_,_,_,_,_,1,_,_,_ _TerrainDeformationCraterBJ_Category=TC_ENVIRONMENT TerrainDeformationRippleBJ=1,real,rippletype,location,real,real,real,real,real _TerrainDeformationRippleBJ_Defaults=4,RippleTypeNormal,GetRectCenter,1024,1024,64,1,512 _TerrainDeformationRippleBJ_Limits=0.01,_,_,_,_,_,0,_,1,_,_,_,0.01,_,1,_ _TerrainDeformationRippleBJ_Category=TC_ENVIRONMENT TerrainDeformationWaveBJ=1,real,location,location,real,real,real _TerrainDeformationWaveBJ_Defaults=0.5,GetRectCenter,GetRectCenter,256,96,0 _TerrainDeformationWaveBJ_Limits=0.01,_,_,_,_,_,0,_,_,_,0,_ _TerrainDeformationWaveBJ_Category=TC_ENVIRONMENT TerrainDeformationRandomBJ=1,real,location,real,real,real,real _TerrainDeformationRandomBJ_Defaults=4,GetRectCenter,512,-32,32,0.1 _TerrainDeformationRandomBJ_Limits=0.01,_,_,_,0,_,_,_,_,_,0.01,_ _TerrainDeformationRandomBJ_Category=TC_ENVIRONMENT TerrainDeformationStopBJ=1,terraindeformation,real _TerrainDeformationStopBJ_Defaults=GetLastCreatedTerrainDeformation,0 _TerrainDeformationStopBJ_Limits=_,_,0,_ _TerrainDeformationStopBJ_Category=TC_ENVIRONMENT TerrainDeformStopAll=1,nothing _TerrainDeformStopAll_Defaults= _TerrainDeformStopAll_Category=TC_ENVIRONMENT SetWaterDeforms=1,onoffoption _SetWaterDeforms_Defaults=OnOffOn _SetWaterDeforms_Category=TC_ENVIRONMENT SetTerrainTypeBJ=1,location,terraintype,integer,integer,terrainshape _SetTerrainTypeBJ_Defaults=GetRectCenter,TerrainTypeLdrt,-1,1,TerrainShapeCircle _SetTerrainTypeBJ_Category=TC_ENVIRONMENT SetTerrainPathableBJ=1,location,pathingtype,onoffoption _SetTerrainPathableBJ_Defaults=GetRectCenter,PathingTypeWalkability,OnOffOn _SetTerrainPathableBJ_Category=TC_ENVIRONMENT SetWaterBaseColorBJ=1,real,real,real,real _SetWaterBaseColorBJ_Defaults=100,100,100,0 _SetWaterBaseColorBJ_Limits=0,100,0,100,0,100,0,100 _SetWaterBaseColorBJ_Category=TC_ENVIRONMENT SetSkyModel=0,skymodelstring _SetSkyModel_Defaults=SkyModelNone _SetSkyModel_Category=TC_ENVIRONMENT SetTerrainFogExBJ=0,fogstyle,real,real,real,real,real,real _SetTerrainFogExBJ_Defaults=FogStyleLinear,1000,8000,0,100,100,100 _SetTerrainFogExBJ_Limits=_,_,0,_,0,_,0,_,0,100,0,100,0,100 _SetTerrainFogExBJ_Category=TC_ENVIRONMENT ResetTerrainFogBJ=0,nothing _ResetTerrainFogBJ_Defaults= _ResetTerrainFogBJ_Category=TC_ENVIRONMENT SetBlightRectBJ=0,createremoveoption,player,rect _SetBlightRectBJ_Defaults=CreateRemoveCreate,Player00,GetPlayableMapRect _SetBlightRectBJ_Category=TC_ENVIRONMENT SetBlightRadiusLocBJ=0,createremoveoption,player,location,real _SetBlightRadiusLocBJ_Defaults=CreateRemoveCreate,Player00,GetRectCenter,512 _SetBlightRadiusLocBJ_Limits=_,_,_,_,_,_,0,_ _SetBlightRadiusLocBJ_Category=TC_ENVIRONMENT // Text Tag actions CreateTextTagLocBJ=1,StringExt,location,real,real,real,real,real,real _CreateTextTagLocBJ_Defaults=_,GetRectCenter,0,10,100,100,100,0 _CreateTextTagLocBJ_Limits=_,_,_,_,_,_,1,_,0,100,0,100,0,100,0,100 _CreateTextTagLocBJ_Category=TC_TEXTTAG CreateTextTagUnitBJ=1,StringExt,unit,real,real,real,real,real,real _CreateTextTagUnitBJ_Defaults=_,_,0,10,100,100,100,0 _CreateTextTagUnitBJ_Limits=_,_,_,_,_,_,1,_,0,100,0,100,0,100,0,100 _CreateTextTagUnitBJ_Category=TC_TEXTTAG DestroyTextTagBJ=1,texttag _DestroyTextTagBJ_Defaults=GetLastCreatedTextTag _DestroyTextTagBJ_Category=TC_TEXTTAG ShowTextTagForceBJ=1,showhideoption,texttag,force _ShowTextTagForceBJ_Defaults=ShowHideShow,GetLastCreatedTextTag,GetPlayersAll _ShowTextTagForceBJ_Category=TC_TEXTTAG SetTextTagVelocityBJ=1,texttag,real,real _SetTextTagVelocityBJ_Defaults=GetLastCreatedTextTag,64,90 _SetTextTagVelocityBJ_Category=TC_TEXTTAG SetTextTagColorBJ=1,texttag,real,real,real,real _SetTextTagColorBJ_Defaults=GetLastCreatedTextTag,100,100,100,0 _SetTextTagColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _SetTextTagColorBJ_Category=TC_TEXTTAG SetTextTagPosBJ=1,texttag,location,real _SetTextTagPosBJ_Defaults=GetLastCreatedTextTag,GetRectCenter,0 _SetTextTagPosBJ_Category=TC_TEXTTAG SetTextTagPosUnitBJ=1,texttag,unit,real _SetTextTagPosUnitBJ_Defaults=GetLastCreatedTextTag,_,0 _SetTextTagPosUnitBJ_Category=TC_TEXTTAG SetTextTagTextBJ=1,texttag,StringExt,real _SetTextTagTextBJ_Defaults=GetLastCreatedTextTag,_,10 _SetTextTagTextBJ_Category=TC_TEXTTAG SetTextTagSuspendedBJ=1,texttag,enabledisableoption _SetTextTagSuspendedBJ_Defaults=GetLastCreatedTextTag,EnableDisableEnable _SetTextTagSuspendedBJ_Category=TC_TEXTTAG SetTextTagPermanentBJ=1,texttag,enabledisableoption _SetTextTagPermanentBJ_Defaults=GetLastCreatedTextTag,EnableDisableEnable _SetTextTagPermanentBJ_Category=TC_TEXTTAG SetTextTagLifespanBJ=1,texttag,real _SetTextTagLifespanBJ_Defaults=GetLastCreatedTextTag,5 _SetTextTagLifespanBJ_Category=TC_TEXTTAG SetTextTagFadepointBJ=1,texttag,real _SetTextTagFadepointBJ_Defaults=GetLastCreatedTextTag,4 _SetTextTagFadepointBJ_Category=TC_TEXTTAG SetTextTagAgeBJ=1,texttag,real _SetTextTagAgeBJ_Defaults=GetLastCreatedTextTag,0 _SetTextTagAgeBJ_Category=TC_TEXTTAG // Game actions DisplayTextToForce=0,force,StringExt _DisplayTextToForce_Defaults=GetPlayersAll,_ _DisplayTextToForce_Category=TC_GAME DisplayTimedTextToForce=0,force,real,StringExt _DisplayTimedTextToForce_Defaults=GetPlayersAll,30,_ _DisplayTimedTextToForce_Limits=_,_,0,_,_,_ _DisplayTimedTextToForce_Category=TC_GAME PauseGameOn=0,nothing _PauseGameOn_Defaults= _PauseGameOn_Category=TC_GAME PauseGameOff=0,nothing _PauseGameOff_Defaults= _PauseGameOff_Category=TC_GAME SetGameSpeed=0,gamespeed _SetGameSpeed_Defaults=GameSpeedNormal _SetGameSpeed_Category=TC_GAME LockGameSpeedBJ=0,nothing _LockGameSpeedBJ_Defaults= _LockGameSpeedBJ_Category=TC_GAME UnlockGameSpeedBJ=0,nothing _UnlockGameSpeedBJ_Defaults= _UnlockGameSpeedBJ_Category=TC_GAME SetMapFlag=0,mapflag,onoffoption _SetMapFlag_Defaults=MapFlagUseHandicaps,OnOffOn _SetMapFlag_Category=TC_GAME SetTimeOfDay=0,real _SetTimeOfDay_Defaults=12 _SetTimeOfDay_Limits=0,24 _SetTimeOfDay_Category=TC_GAME SetTimeOfDayScalePercentBJ=0,real _SetTimeOfDayScalePercentBJ_Defaults=100 _SetTimeOfDayScalePercentBJ_Defaults=0,_ _SetTimeOfDayScalePercentBJ_Category=TC_GAME UseTimeOfDayBJ=0,onoffoption _UseTimeOfDayBJ_Defaults=OnOffOff _UseTimeOfDayBJ_Category=TC_GAME ShareEverythingWithTeam=0,player _ShareEverythingWithTeam_Defaults=Player00 _ShareEverythingWithTeam_Category=TC_GAME MakeUnitsPassiveForPlayer=0,player _MakeUnitsPassiveForPlayer_Defaults=Player00 _MakeUnitsPassiveForPlayer_Category=TC_GAME SetNextLevelBJ=0,string _SetNextLevelBJ_Defaults="Maps\MapName.w3m" _SetNextLevelBJ_Category=TC_GAME CustomVictoryBJ=0,player,useskipoption,useskipoption _CustomVictoryBJ_Defaults=Player00,UseSkipOptionUse,UseSkipOptionUse _CustomVictoryBJ_Category=TC_GAME CustomDefeatBJ=0,player,StringExt _CustomDefeatBJ_Defaults=Player00,WESTRING_PEVENT_DEFEAT_MSG _CustomDefeatBJ_Category=TC_GAME LoadGameBJ=1,anyfile,useskipoption _LoadGameBJ_Defaults="LoadFile.w3z",UseSkipOptionSkip _LoadGameBJ_Category=TC_GAME SaveAndLoadGameBJ=1,anyfile,anyfile,useskipoption _SaveAndLoadGameBJ_Defaults="SaveFile.w3z","LoadFile.w3z",UseSkipOptionSkip _SaveAndLoadGameBJ_Category=TC_GAME SaveAndChangeLevelBJ=1,anyfile,anyfile,useskipoption _SaveAndChangeLevelBJ_Defaults="SaveFile.w3z","Maps\MapName.w3x",UseSkipOptionSkip _SaveAndChangeLevelBJ_Category=TC_GAME RenameSaveDirectoryBJ=1,anyfile,anyfile _RenameSaveDirectoryBJ_Defaults=_,_ _RenameSaveDirectoryBJ_Category=TC_GAME RemoveSaveDirectoryBJ=1,anyfile _RemoveSaveDirectoryBJ_Defaults=_ _RemoveSaveDirectoryBJ_Category=TC_GAME CopySaveGameBJ=1,anyfile,anyfile _CopySaveGameBJ_Defaults=_,_ _CopySaveGameBJ_Category=TC_GAME SetCampaignMenuRaceBJ=0,campaignindex _SetCampaignMenuRaceBJ_Defaults=CampaignIndexH _SetCampaignMenuRaceBJ_Category=TC_GAME SetMissionAvailableBJ=0,enabledisableoption,missionindex _SetMissionAvailableBJ_Defaults=EnableDisableEnable,MissionIndexH01 _SetMissionAvailableBJ_Category=TC_GAME SetCampaignAvailableBJ=0,enabledisableoption,campaignindex _SetCampaignAvailableBJ_Defaults=EnableDisableEnable,CampaignIndexH _SetCampaignAvailableBJ_Category=TC_GAME SetCinematicAvailableBJ=0,enabledisableoption,cinematicindex _SetCinematicAvailableBJ_Defaults=EnableDisableEnable,CinematicIndexHED _SetCinematicAvailableBJ_Category=TC_GAME ShowCustomCampaignButton=1,showhideoption,integer _ShowCustomCampaignButton_Defaults=ShowHideShow,1 _ShowCustomCampaignButton_Limits=_,_,1,_ _ShowCustomCampaignButton_Category=TC_GAME SetAllyColorFilterState=1,integer _SetAllyColorFilterState_Defaults=0 _SetAllyColorFilterState_Limits=0,2 _SetAllyColorFilterState_Category=TC_GAME SetCreepCampFilterState=1,showhideoption _SetCreepCampFilterState_Defaults=ShowHideHide _SetCreepCampFilterState_Category=TC_GAME EnableMinimapFilterButtons=1,enabledisableoption,enabledisableoption _EnableMinimapFilterButtons_Defaults=EnableDisableDisable,EnableDisableDisable _EnableMinimapFilterButtons_Category=TC_GAME EnableSelect=1,enabledisableoption,enabledisableoption _EnableSelect_Defaults=EnableDisableEnable,EnableDisableEnable _EnableSelect_Category=TC_GAME EnableDragSelect=1,enabledisableoption,enabledisableoption _EnableDragSelect_Defaults=EnableDisableEnable,EnableDisableEnable _EnableDragSelect_Category=TC_GAME EnablePreSelect=1,enabledisableoption,enabledisableoption _EnablePreSelect_Defaults=EnableDisableEnable,EnableDisableEnable _EnablePreSelect_Category=TC_GAME ForceUIKeyBJ=0,player,string _ForceUIKeyBJ_Defaults=Player00,"A" _ForceUIKeyBJ_Category=TC_GAME ForceUICancelBJ=0,player _ForceUICancelBJ_Defaults=Player00 _ForceUICancelBJ_Category=TC_GAME Preload=0,anyfile _Preload_Defaults=_ _Preload_Category=TC_GAME PreloadEnd=0,real _PreloadEnd_Defaults=0.5 _PreloadEnd_Category=TC_GAME Preloader=0,preloadfile _Preloader_Defaults= _Preloader_Category=TC_GAME // Game Cache actions InitGameCacheBJ=0,string _InitGameCacheBJ_Defaults="MapName.w3v" _InitGameCacheBJ_Category=TC_GAMECACHE SaveGameCacheBJ=0,gamecache _SaveGameCacheBJ_Defaults=GetLastCreatedGameCacheBJ _SaveGameCacheBJ_Category=TC_GAMECACHE StoreUnitBJ=0,unit,string,string,gamecache _StoreUnitBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreUnitBJ_Category=TC_GAMECACHE StoreRealBJ=0,real,string,string,gamecache _StoreRealBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreRealBJ_Category=TC_GAMECACHE StoreIntegerBJ=0,integer,string,string,gamecache _StoreIntegerBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreIntegerBJ_Category=TC_GAMECACHE StoreBooleanBJ=0,boolean,string,string,gamecache _StoreBooleanBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreBooleanBJ_Category=TC_GAMECACHE StoreStringBJ=1,string,string,string,gamecache _StoreStringBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreStringBJ_Category=TC_GAMECACHE // Hashtable actions InitHashtableBJ=0 _InitHashtableBJ_Defaults= _InitHashtableBJ_Category=TC_HASHTABLE SaveRealBJ=0,real,integer,integer,hashtable _SaveRealBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveRealBJ_Category=TC_HASHTABLE SaveIntegerBJ=0,integer,integer,integer,hashtable _SaveIntegerBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveIntegerBJ_Category=TC_HASHTABLE SaveBooleanBJ=0,boolean,integer,integer,hashtable _SaveBooleanBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveBooleanBJ_Category=TC_HASHTABLE SaveStringBJ=1,string,integer,integer,hashtable _SaveStringBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveStringBJ_Category=TC_HASHTABLE SavePlayerHandleBJ=0,player,integer,integer,hashtable _SavePlayerHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SavePlayerHandleBJ_Category=TC_HASHTABLE SaveWidgetHandleBJ=0,widget,integer,integer,hashtable _SaveWidgetHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveWidgetHandleBJ_Category=TC_HASHTABLE SaveDestructableHandleBJ=0,destructable,integer,integer,hashtable _SaveDestructableHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveDestructableHandleBJ_Category=TC_HASHTABLE SaveItemHandleBJ=0,item,integer,integer,hashtable _SaveItemHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveItemHandleBJ_Category=TC_HASHTABLE SaveUnitHandleBJ=0,unit,integer,integer,hashtable _SaveUnitHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveUnitHandleBJ_Category=TC_HASHTABLE SaveAbilityHandleBJ=0,ability,integer,integer,hashtable _SaveAbilityHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveAbilityHandleBJ_Category=TC_HASHTABLE SaveTimerHandleBJ=0,timer,integer,integer,hashtable _SaveTimerHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTimerHandleBJ_Category=TC_HASHTABLE //SaveTriggerRegionHandleBJ=0,region,integer,integer,hashtable //_SaveTriggerRegionHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ //_SaveTriggerRegionHandleBJ_Category=TC_HASHTABLE SaveTriggerHandleBJ=0,trigger,integer,integer,hashtable _SaveTriggerHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTriggerHandleBJ_Category=TC_HASHTABLE SaveTriggerConditionHandleBJ=0,triggercondition,integer,integer,hashtable _SaveTriggerConditionHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTriggerConditionHandleBJ_Category=TC_HASHTABLE SaveTriggerActionHandleBJ=0,triggeraction,integer,integer,hashtable _SaveTriggerActionHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTriggerActionHandleBJ_Category=TC_HASHTABLE SaveTriggerEventHandleBJ=0,eventid,integer,integer,hashtable _SaveTriggerEventHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTriggerEventHandleBJ_Category=TC_HASHTABLE SaveForceHandleBJ=0,force,integer,integer,hashtable _SaveForceHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveForceHandleBJ_Category=TC_HASHTABLE SaveGroupHandleBJ=0,group,integer,integer,hashtable _SaveGroupHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveGroupHandleBJ_Category=TC_HASHTABLE SaveLocationHandleBJ=0,location,integer,integer,hashtable _SaveLocationHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveLocationHandleBJ_Category=TC_HASHTABLE SaveRegionHandleBJ=0,region,integer,integer,hashtable _SaveRegionHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveRegionHandleBJ_Category=TC_HASHTABLE SaveRectHandleBJ=0,rect,integer,integer,hashtable _SaveRectHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveRectHandleBJ_Category=TC_HASHTABLE SaveBooleanExprHandleBJ=0,boolexpr,integer,integer,hashtable _SaveBooleanExprHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveBooleanExprHandleBJ_Category=TC_HASHTABLE //SaveConditionFuncHandleBJ=0,conditionfunc,integer,integer,hashtable //_SaveConditionFuncHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ //_SaveConditionFuncHandleBJ_Category=TC_HASHTABLE //SaveFilterFuncHandleBJ=0,filterfunc,integer,integer,hashtable //_SaveFilterFuncHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ //_SaveFilterFuncHandleBJ_Category=TC_HASHTABLE SaveSoundHandleBJ=0,sound,integer,integer,hashtable _SaveSoundHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveSoundHandleBJ_Category=TC_HASHTABLE //SaveRaceHandleBJ=0,race,integer,integer,hashtable //_SaveRaceHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ //_SaveRaceHandleBJ_Category=TC_HASHTABLE SaveEffectHandleBJ=0,effect,integer,integer,hashtable _SaveEffectHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveEffectHandleBJ_Category=TC_HASHTABLE SaveUnitPoolHandleBJ=0,unitpool,integer,integer,hashtable _SaveUnitPoolHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveUnitPoolHandleBJ_Category=TC_HASHTABLE SaveItemPoolHandleBJ=0,itempool,integer,integer,hashtable _SaveItemPoolHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveItemPoolHandleBJ_Category=TC_HASHTABLE SaveQuestHandleBJ=0,quest,integer,integer,hashtable _SaveQuestHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveQuestHandleBJ_Category=TC_HASHTABLE SaveQuestItemHandleBJ=0,questitem,integer,integer,hashtable _SaveQuestItemHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveQuestItemHandleBJ_Category=TC_HASHTABLE SaveDefeatConditionHandleBJ=0,defeatcondition,integer,integer,hashtable _SaveDefeatConditionHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveDefeatConditionHandleBJ_Category=TC_HASHTABLE SaveTimerDialogHandleBJ=0,timerdialog,integer,integer,hashtable _SaveTimerDialogHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTimerDialogHandleBJ_Category=TC_HASHTABLE SaveLeaderboardHandleBJ=0,leaderboard,integer,integer,hashtable _SaveLeaderboardHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveLeaderboardHandleBJ_Category=TC_HASHTABLE SaveMultiboardHandleBJ=0,multiboard,integer,integer,hashtable _SaveMultiboardHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveMultiboardHandleBJ_Category=TC_HASHTABLE SaveMultiboardItemHandleBJ=0,multiboarditem,integer,integer,hashtable _SaveMultiboardItemHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveMultiboardItemHandleBJ_Category=TC_HASHTABLE SaveTrackableHandleBJ=0,trackable,integer,integer,hashtable _SaveTrackableHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTrackableHandleBJ_Category=TC_HASHTABLE SaveGameCacheHandleBJ=0,gamecache,integer,integer,hashtable _SaveGameCacheHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveGameCacheHandleBJ_Category=TC_HASHTABLE SaveDialogHandleBJ=0,dialog,integer,integer,hashtable _SaveDialogHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveDialogHandleBJ_Category=TC_HASHTABLE SaveButtonHandleBJ=0,button,integer,integer,hashtable _SaveButtonHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveButtonHandleBJ_Category=TC_HASHTABLE //SaveVersionHandleBJ=0,version,integer,integer,hashtable //_SaveVersionHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ //_SaveVersionHandleBJ_Category=TC_HASHTABLE //SaveItemTypeHandleBJ=0,itemtype,integer,integer,hashtable //_SaveItemTypeHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ //_SaveItemTypeHandleBJ_Category=TC_HASHTABLE SaveTextTagHandleBJ=0,texttag,integer,integer,hashtable _SaveTextTagHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveTextTagHandleBJ_Category=TC_HASHTABLE SaveLightningHandleBJ=0,lightning,integer,integer,hashtable _SaveLightningHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveLightningHandleBJ_Category=TC_HASHTABLE SaveImageHandleBJ=0,image,integer,integer,hashtable _SaveImageHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveImageHandleBJ_Category=TC_HASHTABLE SaveUbersplatHandleBJ=0,ubersplat,integer,integer,hashtable _SaveUbersplatHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveUbersplatHandleBJ_Category=TC_HASHTABLE SaveFogStateHandleBJ=0,fogstate,integer,integer,hashtable _SaveFogStateHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveFogStateHandleBJ_Category=TC_HASHTABLE SaveFogModifierHandleBJ=0,fogmodifier,integer,integer,hashtable _SaveFogModifierHandleBJ_Defaults=_,_,_,GetLastCreatedHashtableBJ _SaveFogModifierHandleBJ_Category=TC_HASHTABLE RestoreUnitLocFacingAngleBJ=0,string,string,gamecache,player,location,real _RestoreUnitLocFacingAngleBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ,Player00,GetRectCenter,0 _RestoreUnitLocFacingAngleBJ_Category=TC_GAMECACHE RestoreUnitLocFacingPointBJ=0,string,string,gamecache,player,location,location _RestoreUnitLocFacingPointBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ,Player00,GetRectCenter,GetUnitLoc _RestoreUnitLocFacingPointBJ_Category=TC_GAMECACHE ReloadGameCachesFromDisk=1,nothing _ReloadGameCachesFromDisk_Defaults= _ReloadGameCachesFromDisk_Category=TC_GAMECACHE FlushGameCacheBJ=1,gamecache _FlushGameCacheBJ_Defaults=GetLastCreatedGameCacheBJ _FlushGameCacheBJ_Category=TC_GAMECACHE FlushStoredMissionBJ=1,string,gamecache _FlushStoredMissionBJ_Defaults="Category",GetLastCreatedGameCacheBJ _FlushStoredMissionBJ_Category=TC_GAMECACHE FlushParentHashtableBJ=1,hashtable _FlushParentHashtableBJ_Defaults=GetLastCreatedHashtableBJ _FlushParentHashtableBJ_Category=TC_HASHTABLE FlushChildHashtableBJ=1,integer,hashtable _FlushChildHashtableBJ_Defaults=_,GetLastCreatedHashtableBJ _FlushChildHashtableBJ_Category=TC_HASHTABLE // Hero actions SelectHeroSkill=0,unit,heroskillcode _SelectHeroSkill_Defaults=GetTriggerUnit,HeroSkillBlizzard _SelectHeroSkill_Category=TC_HERO SetHeroLevel=0,unit,integer,showhideoption _SetHeroLevel_Defaults=GetTriggerUnit,2,ShowHideHide _SetHeroLevel_Limits=_,_,1,_,_,_ _SetHeroLevel_Category=TC_HERO _SetHeroLevel_ScriptName=SetHeroLevelBJ SetHeroXP=0,unit,integer,showhideoption _SetHeroXP_Defaults=GetTriggerUnit,4000,ShowHideHide _SetHeroXP_Limits=_,_,0,_,_,_ _SetHeroXP_Category=TC_HERO AddHeroXPSwapped=0,integer,unit,showhideoption _AddHeroXPSwapped_Defaults=1000,GetTriggerUnit,ShowHideHide _AddHeroXPSwapped_Category=TC_HERO SuspendHeroXPBJ=0,enabledisableoption,unit _SuspendHeroXPBJ_Defaults=EnableDisableDisable,GetTriggerUnit _SuspendHeroXPBJ_Category=TC_HERO SetPlayerHandicapXPBJ=0,player,real _SetPlayerHandicapXPBJ_Defaults=Player00,100 _SetPlayerHandicapXPBJ_Limits=_,_,0,_ _SetPlayerHandicapXPBJ_Category=TC_HERO ReviveHeroLoc=0,unit,location,showhideoption _ReviveHeroLoc_Defaults=_,GetRectCenter,ShowHideHide _ReviveHeroLoc_Category=TC_HERO ModifyHeroStat=1,herostat,unit,modifymethod,integer _ModifyHeroStat_Defaults=HeroStatStr,_,ModifyMethodAdd,10 _ModifyHeroStat_Category=TC_HERO ModifyHeroSkillPoints=1,unit,modifymethod,integer _ModifyHeroSkillPoints_Defaults=_,ModifyMethodAdd,1 _ModifyHeroSkillPoints_Category=TC_HERO SetReservedLocalHeroButtons=1,integer _SetReservedLocalHeroButtons_Defaults=3 _SetReservedLocalHeroButtons_Limits=0,6 _SetReservedLocalHeroButtons_Category=TC_HERO UnitAddItemSwapped=0,item,unit _UnitAddItemSwapped_Defaults=GetLastCreatedItem,GetTriggerUnit _UnitAddItemSwapped_Category=TC_HERO UnitAddItemByIdSwapped=0,itemcode,unit _UnitAddItemByIdSwapped_Defaults=texp,GetTriggerUnit _UnitAddItemByIdSwapped_Category=TC_HERO UnitRemoveItemSwapped=0,item,unit _UnitRemoveItemSwapped_Defaults=_,_ _UnitRemoveItemSwapped_Category=TC_HERO UnitRemoveItemFromSlotSwapped=0,integer,unit _UnitRemoveItemFromSlotSwapped_Defaults=1,_ _UnitRemoveItemFromSlotSwapped_Limits=1,6,_,_ _UnitRemoveItemFromSlotSwapped_Category=TC_HERO UnitUseItemTarget=0,unit,item,unit _UnitUseItemTarget_Defaults=_,GetLastCreatedItem,_ _UnitUseItemTarget_Category=TC_HERO UnitUseItemPointLoc=0,unit,item,location _UnitUseItemPointLoc_Defaults=_,GetLastCreatedItem,GetRectCenter _UnitUseItemPointLoc_Category=TC_HERO UnitUseItemDestructable=0,unit,item,destructable _UnitUseItemDestructable_Defaults=_,GetLastCreatedItem,_ _UnitUseItemDestructable_Category=TC_HERO UnitUseItem=0,unit,item _UnitUseItem_Defaults=_,GetLastCreatedItem _UnitUseItem_Category=TC_HERO // Item actions CreateItemLoc=0,itemcode,location _CreateItemLoc_Defaults=texp,GetRectCenter _CreateItemLoc_Category=TC_ITEM RemoveItem=0,item _RemoveItem_Defaults=GetLastCreatedItem _RemoveItem_Category=TC_ITEM SetItemVisibleBJ=1,showhideoption,item _SetItemVisibleBJ_Defaults=ShowHideHide,GetLastCreatedItem _SetItemVisibleBJ_Category=TC_ITEM SetItemPositionLoc=0,item,location _SetItemPositionLoc_Defaults=GetLastCreatedItem,GetRectCenter _SetItemPositionLoc_Category=TC_ITEM SetItemLifeBJ=0,item,real _SetItemLifeBJ_Defaults=GetLastCreatedItem,50 _SetItemLifeBJ_Limits=_,_,0,_ _SetItemLifeBJ_Category=TC_ITEM SetItemCharges=1,item,integer _SetItemCharges_Defaults=GetLastCreatedItem,1 _SetItemCharges_Limits=_,_,0,_ _SetItemCharges_Category=TC_ITEM SetItemInvulnerableBJ=0,item,invulnerableoption _SetItemInvulnerableBJ_Defaults=GetLastCreatedItem,InvulnerabilityInvulnerable _SetItemInvulnerableBJ_Category=TC_ITEM SetItemPawnable=1,item,pawnableoption _SetItemPawnable_Defaults=GetLastCreatedItem,PawnableOptionPawnable _SetItemPawnable_Category=TC_ITEM SetItemDroppableBJ=0,item,dropnodropoption _SetItemDroppableBJ_Defaults=GetLastCreatedItem,DropNoDropOptionNoDrop _SetItemDroppableBJ_Category=TC_ITEM SetItemDropOnDeathBJ=0,item,droppableoption _SetItemDropOnDeathBJ_Defaults=GetLastCreatedItem,DroppableOptionDrop _SetItemDropOnDeathBJ_Category=TC_ITEM SetItemPlayerBJ=0,item,player,colorchangeoption _SetItemPlayerBJ_Defaults=GetLastCreatedItem,Player00,ChangeColorTrue _SetItemPlayerBJ_Category=TC_ITEM SetItemUserData=1,item,integer _SetItemUserData_Defaults=_,0 _SetItemUserData_Category=TC_ITEM EnumItemsInRectBJMultiple=1,rect _EnumItemsInRectBJMultiple_Defaults=GetPlayableMapRect _EnumItemsInRectBJMultiple_Category=TC_ITEM _EnumItemsInRectBJMultiple_ScriptName=EnumItemsInRectBJ EnumItemsInRectBJ=1,rect,code _EnumItemsInRectBJ_Defaults=GetPlayableMapRect,DoNothing _EnumItemsInRectBJ_Category=TC_ITEM // Image actions CreateImageBJ=1,string,real,location,real,imagetype _CreateImageBJ_Defaults="ReplaceableTextures\Splats\AuraRune9b.blp",256,GetRectCenter,0,ImageTypeIndicator _CreateImageBJ_Category=TC_IMAGE DestroyImage=1,image _DestroyImage_Defaults=GetLastCreatedImage _DestroyImage_Category=TC_IMAGE ShowImageBJ=1,showhideoption,image _ShowImageBJ_Defaults=ShowHideShow,GetLastCreatedImage _ShowImageBJ_Category=TC_IMAGE SetImageConstantHeight=1,image,enabledisableoption,real _SetImageConstantHeight_Defaults=GetLastCreatedImage,EnableDisableEnable,0 _SetImageConstantHeight_Category=TC_IMAGE SetImagePositionBJ=1,image,location,real _SetImagePositionBJ_Defaults=GetLastCreatedImage,GetRectCenter,0 _SetImagePositionBJ_Category=TC_IMAGE SetImageColorBJ=1,image,real,real,real,real _SetImageColorBJ_Defaults=GetLastCreatedImage,100,100,100,0 _SetImageColorBJ_Category=TC_IMAGE SetImageRender=1,image,enabledisableoption _SetImageRender_Defaults=GetLastCreatedImage,EnableDisableEnable _SetImageRender_Category=TC_IMAGE SetImageRenderAlways=1,image,enabledisableoption _SetImageRenderAlways_Defaults=GetLastCreatedImage,EnableDisableEnable _SetImageRenderAlways_Category=TC_IMAGE SetImageAboveWater=1,image,enabledisableoption,enabledisableoption _SetImageAboveWater_Defaults=GetLastCreatedImage,EnableDisableEnable,EnableDisableEnable _SetImageAboveWater_Category=TC_IMAGE SetImageType=1,image,imagetype _SetImageType_Defaults=GetLastCreatedImage,ImageTypeIndicator _SetImageType_Category=TC_IMAGE // Leaderboard actions CreateLeaderboardBJ=0,force,StringExt _CreateLeaderboardBJ_Defaults=GetPlayersAll,_ _CreateLeaderboardBJ_Category=TC_LEADERBOARD DestroyLeaderboardBJ=0,leaderboard _DestroyLeaderboardBJ_Defaults=GetLastCreatedLeaderboard _DestroyLeaderboardBJ_Category=TC_LEADERBOARD LeaderboardSortItemsBJ=0,leaderboard,leaderboardsortoption,ascendingoption _LeaderboardSortItemsBJ_Defaults=GetLastCreatedLeaderboard,LeaderboardSortByValue,AscendingOptionDescending _LeaderboardSortItemsBJ_Category=TC_LEADERBOARD LeaderboardDisplayBJ=0,showhideoption,leaderboard _LeaderboardDisplayBJ_Defaults=ShowHideHide,GetLastCreatedLeaderboard _LeaderboardDisplayBJ_Category=TC_LEADERBOARD LeaderboardSetLabelBJ=0,leaderboard,StringExt _LeaderboardSetLabelBJ_Defaults=GetLastCreatedLeaderboard,_ _LeaderboardSetLabelBJ_Category=TC_LEADERBOARD LeaderboardSetLabelColorBJ=0,leaderboard,real,real,real,real _LeaderboardSetLabelColorBJ_Defaults=GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetLabelColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _LeaderboardSetLabelColorBJ_Category=TC_LEADERBOARD LeaderboardSetValueColorBJ=0,leaderboard,real,real,real,real _LeaderboardSetValueColorBJ_Defaults=GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetValueColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _LeaderboardSetValueColorBJ_Category=TC_LEADERBOARD LeaderboardSetStyleBJ=0,leaderboard,showhideoption,showhideoption,showhideoption,showhideoption _LeaderboardSetStyleBJ_Defaults=GetLastCreatedLeaderboard,ShowHideShow,ShowHideShow,ShowHideShow,ShowHideShow _LeaderboardSetStyleBJ_Category=TC_LEADERBOARD LeaderboardAddItemBJ=0,player,leaderboard,StringExt,integer _LeaderboardAddItemBJ_Defaults=Player00,GetLastCreatedLeaderboard,_,0 _LeaderboardAddItemBJ_Category=TC_LEADERBOARD LeaderboardRemovePlayerItemBJ=0,player,leaderboard _LeaderboardRemovePlayerItemBJ_Defaults=Player00,GetLastCreatedLeaderboard _LeaderboardRemovePlayerItemBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemLabelBJ=0,player,leaderboard,StringExt _LeaderboardSetPlayerItemLabelBJ_Defaults=Player00,GetLastCreatedLeaderboard,_ _LeaderboardSetPlayerItemLabelBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemLabelColorBJ=0,player,leaderboard,real,real,real,real _LeaderboardSetPlayerItemLabelColorBJ_Defaults=Player00,GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetPlayerItemLabelColorBJ_Limits=_,_,_,_,0,100,0,100,0,100,0,100 _LeaderboardSetPlayerItemLabelColorBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemValueBJ=0,player,leaderboard,integer _LeaderboardSetPlayerItemValueBJ_Defaults=Player00,GetLastCreatedLeaderboard,0 _LeaderboardSetPlayerItemValueBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemValueColorBJ=0,player,leaderboard,real,real,real,real _LeaderboardSetPlayerItemValueColorBJ_Defaults=Player00,GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetPlayerItemValueColorBJ_Limits=_,_,_,_,0,100,0,100,0,100,0,100 _LeaderboardSetPlayerItemValueColorBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemStyleBJ=0,player,leaderboard,showhideoption,showhideoption,showhideoption _LeaderboardSetPlayerItemStyleBJ_Defaults=Player00,GetLastCreatedLeaderboard,ShowHideShow,ShowHideShow,ShowHideShow _LeaderboardSetPlayerItemStyleBJ_Category=TC_LEADERBOARD // Lightning actions AddLightningLoc=1,lightningtype,location,location _AddLightningLoc_Defaults=LightningTypeCLPB,GetUnitLoc,GetRectCenter _AddLightningLoc_Category=TC_LIGHTNING DestroyLightningBJ=1,lightning _DestroyLightningBJ_Defaults=GetLastCreatedLightningBJ _DestroyLightningBJ_Category=TC_LIGHTNING MoveLightningLoc=1,lightning,location,location _MoveLightningLoc_Defaults=GetLastCreatedLightningBJ,GetUnitLoc,GetRectCenter _MoveLightningLoc_Category=TC_LIGHTNING SetLightningColorBJ=1,lightning,real,real,real,real _SetLightningColorBJ_Defaults=GetLastCreatedLightningBJ,1,1,1,1 _SetLightningColorBJ_Category=TC_LIGHTNING // Melee Game actions MeleeStartingVisibility=0,nothing _MeleeStartingVisibility_Defaults= _MeleeStartingVisibility_Category=TC_MELEE MeleeStartingHeroLimit=0,nothing _MeleeStartingHeroLimit_Defaults= _MeleeStartingHeroLimit_Category=TC_MELEE MeleeGrantHeroItems=0,nothing _MeleeGrantHeroItems_Defaults= _MeleeGrantHeroItems_Category=TC_MELEE MeleeStartingResources=0,nothing _MeleeStartingResources_Defaults= _MeleeStartingResources_Category=TC_MELEE MeleeClearExcessUnits=0,nothing _MeleeClearExcessUnits_Defaults= _MeleeClearExcessUnits_Category=TC_MELEE MeleeStartingUnits=0,nothing _MeleeStartingUnits_Defaults= _MeleeStartingUnits_Category=TC_MELEE MeleeStartingAI=0,nothing _MeleeStartingAI_Defaults= _MeleeStartingAI_Category=TC_MELEE MeleeInitVictoryDefeat=0,nothing _MeleeInitVictoryDefeat_Defaults= _MeleeInitVictoryDefeat_Category=TC_MELEE MeleeStartingUnitsForPlayer=1,race,player,location,includeoption _MeleeStartingUnitsForPlayer_Defaults=RaceHuman,Player00,GetPlayerStartLocationLoc,InclusionInclude _MeleeStartingUnitsForPlayer_Category=TC_MELEE // Multiboard actions CreateMultiboardBJ=1,integer,integer,StringExt _CreateMultiboardBJ_Defaults=1,1,_ _CreateMultiboardBJ_Limits=1,28,1,32,_,512 _CreateMultiboardBJ_Category=TC_MULTIBOARD DestroyMultiboardBJ=1,multiboard _DestroyMultiboardBJ_Defaults=GetLastCreatedMultiboard _DestroyMultiboardBJ_Category=TC_MULTIBOARD MultiboardDisplayBJ=1,showhideoption,multiboard _MultiboardDisplayBJ_Defaults=ShowHideHide,GetLastCreatedMultiboard _MultiboardDisplayBJ_Category=TC_MULTIBOARD MultiboardAllowDisplayBJ=1,showhideoption _MultiboardAllowDisplayBJ_Defaults=ShowHideHide _MultiboardAllowDisplayBJ_Category=TC_MULTIBOARD MultiboardMinimizeBJ=1,minimizeoption,multiboard _MultiboardMinimizeBJ_Defaults=Minimize,GetLastCreatedMultiboard _MultiboardMinimizeBJ_Category=TC_MULTIBOARD MultiboardClear=1,multiboard _MultiboardClear_Defaults=GetLastCreatedMultiboard _MultiboardClear_Category=TC_MULTIBOARD MultiboardSetTitleText=1,multiboard,StringExt _MultiboardSetTitleText_Defaults=GetLastCreatedMultiboard,_ _MultiboardSetTitleText_Limits=_,_,_,512 _MultiboardSetTitleText_Category=TC_MULTIBOARD MultiboardSetTitleTextColorBJ=1,multiboard,real,real,real,real _MultiboardSetTitleTextColorBJ_Defaults=GetLastCreatedMultiboard,100,80,20,0 _MultiboardSetTitleTextColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _MultiboardSetTitleTextColorBJ_Category=TC_MULTIBOARD MultiboardSetRowCount=1,multiboard,integer _MultiboardSetRowCount_Defaults=GetLastCreatedMultiboard,1 _MultiboardSetRowCount_Limits=_,_,1,32 _MultiboardSetRowCount_Category=TC_MULTIBOARD MultiboardSetColumnCount=1,multiboard,integer _MultiboardSetColumnCount_Defaults=GetLastCreatedMultiboard,1 _MultiboardSetColumnCount_Limits=_,_,1,28 _MultiboardSetColumnCount_Category=TC_MULTIBOARD MultiboardSetItemStyleBJ=1,multiboard,integer,integer,showhideoption,showhideoption _MultiboardSetItemStyleBJ_Defaults=GetLastCreatedMultiboard,1,1,ShowHideShow,ShowHideShow _MultiboardSetItemStyleBJ_Limits=_,_,0,_,0,_,_,_,_,_ _MultiboardSetItemStyleBJ_Category=TC_MULTIBOARD MultiboardSetItemValueBJ=1,multiboard,integer,integer,StringExt _MultiboardSetItemValueBJ_Defaults=GetLastCreatedMultiboard,1,1,_ _MultiboardSetItemValueBJ_Limits=_,_,0,_,0,_,_,128 _MultiboardSetItemValueBJ_Category=TC_MULTIBOARD MultiboardSetItemColorBJ=1,multiboard,integer,integer,real,real,real,real _MultiboardSetItemColorBJ_Defaults=GetLastCreatedMultiboard,1,1,100,80,20,0 _MultiboardSetItemColorBJ_Limits=_,_,0,_,0,_,0,100,0,100,0,100,0,100 _MultiboardSetItemColorBJ_Category=TC_MULTIBOARD MultiboardSetItemWidthBJ=1,multiboard,integer,integer,real _MultiboardSetItemWidthBJ_Defaults=GetLastCreatedMultiboard,1,1,3 _MultiboardSetItemWidthBJ_Limits=_,_,0,_,0,_,0,100 _MultiboardSetItemWidthBJ_Category=TC_MULTIBOARD MultiboardSetItemIconBJ=1,multiboard,integer,integer,imagefile _MultiboardSetItemIconBJ_Defaults=GetLastCreatedMultiboard,1,1,"UI\Feedback\Resources\ResourceGold.blp" _MultiboardSetItemIconBJ_Limits=_,_,0,_,0,_,_,_ _MultiboardSetItemIconBJ_Category=TC_MULTIBOARD // Neutral Building actions AddResourceAmountBJ=0,integer,unit _AddResourceAmountBJ_Defaults=5000,_ _AddResourceAmountBJ_Category=TC_NEUTRALBUILDING SetResourceAmount=0,unit,integer _SetResourceAmount_Defaults=_,12500 _SetResourceAmount_Limits=_,_,0,_ _SetResourceAmount_Category=TC_NEUTRALBUILDING BlightGoldMineForPlayer=0,unit,player _BlightGoldMineForPlayer_Defaults=_,Player00 _BlightGoldMineForPlayer_Category=TC_NEUTRALBUILDING WaygateActivateBJ=0,enabledisableoption,unit _WaygateActivateBJ_Defaults=EnableDisableEnable,_ _WaygateActivateBJ_Category=TC_NEUTRALBUILDING WaygateSetDestinationLocBJ=0,unit,location _WaygateSetDestinationLocBJ_Defaults=_,GetRectCenter _WaygateSetDestinationLocBJ_Category=TC_NEUTRALBUILDING SetAltMinimapIcon=1,imagefile _SetAltMinimapIcon_Defaults="UI\Minimap\Minimap-Tower" _SetAltMinimapIcon_Category=TC_NEUTRALBUILDING UnitSetUsesAltIconBJ=1,onoffoption,unit _UnitSetUsesAltIconBJ_Defaults=OnOffOn,_ _UnitSetUsesAltIconBJ_Category=TC_NEUTRALBUILDING AddItemToStockBJ=1,itemcode,unit,integer,integer _AddItemToStockBJ_Defaults=texp,GetTriggerUnit,0,1 _AddItemToStockBJ_Category=TC_NEUTRALBUILDING AddItemToAllStock=1,itemcode,integer,integer _AddItemToAllStock_Defaults=texp,0,1 _AddItemToAllStock_Category=TC_NEUTRALBUILDING AddUnitToStockBJ=1,unitcode,unit,integer,integer _AddUnitToStockBJ_Defaults=hfoo,GetTriggerUnit,0,1 _AddUnitToStockBJ_Category=TC_NEUTRALBUILDING AddUnitToAllStock=1,unitcode,integer,integer _AddUnitToAllStock_Defaults=hfoo,0,1 _AddUnitToAllStock_Category=TC_NEUTRALBUILDING RemoveItemFromStockBJ=1,itemcode,unit _RemoveItemFromStockBJ_Defaults=texp,GetTriggerUnit _RemoveItemFromStockBJ_Category=TC_NEUTRALBUILDING RemoveItemFromAllStock=1,itemcode _RemoveItemFromAllStock_Defaults=texp _RemoveItemFromAllStock_Category=TC_NEUTRALBUILDING RemoveUnitFromStockBJ=1,unitcode,unit _RemoveUnitFromStockBJ_Defaults=hfoo,GetTriggerUnit _RemoveUnitFromStockBJ_Category=TC_NEUTRALBUILDING RemoveUnitFromAllStock=1,unitcode _RemoveUnitFromAllStock_Defaults=hfoo _RemoveUnitFromAllStock_Category=TC_NEUTRALBUILDING SetItemTypeSlots=1,unit,integer _SetItemTypeSlots_Defaults=GetTriggerUnit,6 _SetItemTypeSlots_Category=TC_NEUTRALBUILDING SetAllItemTypeSlots=1,integer _SetAllItemTypeSlots_Defaults=6 _SetAllItemTypeSlots_Category=TC_NEUTRALBUILDING SetUnitTypeSlots=1,unit,integer _SetUnitTypeSlots_Defaults=GetTriggerUnit,6 _SetUnitTypeSlots_Category=TC_NEUTRALBUILDING SetAllUnitTypeSlots=1,integer _SetAllUnitTypeSlots_Defaults=6 _SetAllUnitTypeSlots_Category=TC_NEUTRALBUILDING // Player actions SetPlayerState=0,player,playerstate,integer _SetPlayerState_Defaults=Player00,PlayerStateGold,750 _SetPlayerState_Category=TC_PLAYER _SetPlayerState_ScriptName=SetPlayerStateBJ AdjustPlayerStateBJ=0,integer,player,playerstate _AdjustPlayerStateBJ_Defaults=1000,Player00,PlayerStateGold _AdjustPlayerStateBJ_Category=TC_PLAYER SetPlayerFlagBJ=0,playerflag,onoffoption,player _SetPlayerFlagBJ_Defaults=PlayerFlagGivesBounty,OnOffOff,PlayerNA _SetPlayerFlagBJ_Category=TC_PLAYER SetPlayerTaxRateBJ=1,integer,playerresource,player,player, _SetPlayerTaxRateBJ_Defaults=0,PlayerResourceGold,Player00,Player01 _SetPlayerTaxRateBJ_Limits=0,100,_,_,_,_,_,_ _SetPlayerTaxRateBJ_Category=TC_PLAYER EnableCreepSleepBJ=1,enabledisableoption _EnableCreepSleepBJ_Defaults=EnableDisableDisable _EnableCreepSleepBJ_Category=TC_PLAYER SetPlayerAllianceStateBJ=0,player,player,alliancesetting _SetPlayerAllianceStateBJ_Defaults=Player00,Player01,AllianceSettingAlliedVision _SetPlayerAllianceStateBJ_Category=TC_PLAYER SetPlayerAllianceBJ=0,player,alliancetype,onoffoption,player _SetPlayerAllianceBJ_Defaults=Player00,AllianceTypePassive,OnOffOn,Player01 _SetPlayerAllianceBJ_Category=TC_PLAYER SetPlayerAbilityAvailableBJ=0,enabledisableoption,abilcode,player _SetPlayerAbilityAvailableBJ_Defaults=EnableDisableDisable,_,Player00 _SetPlayerAbilityAvailableBJ_Category=TC_PLAYER SetPlayerUnitAvailableBJ=0,unitcode,availabilityoption,player _SetPlayerUnitAvailableBJ_Defaults=hfoo,AvailabilityOptionAvailable,Player00 _SetPlayerUnitAvailableBJ_Category=TC_PLAYER SetPlayerUnitMaxAllowed=1,unitcode,integer,player _SetPlayerUnitMaxAllowed_Defaults=hfoo,1,Player00 _SetPlayerUnitMaxAllowed_Limits=_,_,-1,_,_,_ _SetPlayerUnitMaxAllowed_Category=TC_PLAYER _SetPlayerUnitMaxAllowed_ScriptName=SetPlayerTechMaxAllowedSwap SetPlayerMaxHeroesAllowed=1,integer,player _SetPlayerMaxHeroesAllowed_Defaults=3,Player00 _SetPlayerMaxHeroesAllowed_Limits=-1,_,_,_ _SetPlayerMaxHeroesAllowed_Category=TC_PLAYER SetPlayerTechResearchedSwap=0,techcode,integer,player _SetPlayerTechResearchedSwap_Defaults=_,0,Player00 _SetPlayerTechResearchedSwap_Limits=_,_,0,_,_,_ _SetPlayerTechResearchedSwap_Category=TC_PLAYER SetPlayerTechMaxAllowedSwap=0,techcode,integer,player _SetPlayerTechMaxAllowedSwap_Defaults=_,0,Player00 _SetPlayerTechMaxAllowedSwap_Limits=_,_,0,_,_,_ _SetPlayerTechMaxAllowedSwap_Category=TC_PLAYER SetPlayerColorBJ=0,player,playercolor,playerchangecoloroption _SetPlayerColorBJ_Defaults=Player00,Color00,PlayerChangeColorChange _SetPlayerColorBJ_Category=TC_PLAYER SetPlayerHandicapBJ=0,player,real _SetPlayerHandicapBJ_Defaults=Player00,100 _SetPlayerHandicapBJ_Limits=_,_,1,10000 _SetPlayerHandicapBJ_Category=TC_PLAYER SetPlayerOnScoreScreenBJ=0,showhideoption,player _SetPlayerOnScoreScreenBJ_Defaults=ShowHideHide,Player00 _SetPlayerOnScoreScreenBJ_Category=TC_PLAYER SetPlayerName=1,player,StringExt _SetPlayerName_Defaults=Player00,_ _SetPlayerName_Category=TC_PLAYER // Player Group actions // Specially handled by the editor ForForceMultiple=1,force _ForForceMultiple_Defaults=GetPlayersAll _ForForceMultiple_Category=TC_PLAYERGROUP _ForForceMultiple_ScriptName=ForForce ForForce=0,force,code _ForForce_Defaults=GetPlayersAll,DoNothing _ForForce_Category=TC_PLAYERGROUP ForceAddPlayerSimple=0,player,force _ForceAddPlayerSimple_Defaults=Player00,_ _ForceAddPlayerSimple_Category=TC_PLAYERGROUP ForceRemovePlayerSimple=0,player,force _ForceRemovePlayerSimple_Defaults=Player00,_ _ForceRemovePlayerSimple_Category=TC_PLAYERGROUP ForceClear=0,force _ForceClear_Defaults=_ _ForceClear_Category=TC_PLAYERGROUP SetForceAllianceStateBJ=1,force,force,alliancesetting _SetForceAllianceStateBJ_Defaults=GetPlayersAll,GetPlayersAll,AllianceSettingAlliedVision _SetForceAllianceStateBJ_Category=TC_PLAYERGROUP // Quest actions QuestMessageBJ=0,force,questmessagetype,StringExt _QuestMessageBJ_Defaults=GetPlayersAll,QuestMessageTypeUpdated,_ _QuestMessageBJ_Category=TC_QUEST CreateQuestBJ=0,questtypeoption,StringExt,StringExt,imagefile _CreateQuestBJ_Defaults=QuestTypeReqDiscovered,_,_,"ReplaceableTextures\CommandButtons\BTNAmbush.blp" _CreateQuestBJ_Limits=_,_,_,24,_,_,_,_ _CreateQuestBJ_Category=TC_QUEST DestroyQuestBJ=0,quest _DestroyQuestBJ_Defaults=GetLastCreatedQuestBJ _DestroyQuestBJ_Category=TC_QUEST QuestSetEnabledBJ=0,enabledisableoption,quest _QuestSetEnabledBJ_Defaults=EnableDisableDisable,GetLastCreatedQuestBJ _QuestSetEnabledBJ_Category=TC_QUEST QuestSetCompletedBJ=0,quest,completionoption _QuestSetCompletedBJ_Defaults=GetLastCreatedQuestBJ,CompletionOptionCompleted _QuestSetCompletedBJ_Category=TC_QUEST QuestSetFailedBJ=0,quest,failureoption _QuestSetFailedBJ_Defaults=GetLastCreatedQuestBJ,FailureOptionFailed _QuestSetFailedBJ_Category=TC_QUEST QuestSetDiscoveredBJ=0,quest,discoveredoption _QuestSetDiscoveredBJ_Defaults=GetLastCreatedQuestBJ,DiscoveredOptionDiscovered _QuestSetDiscoveredBJ_Category=TC_QUEST QuestSetTitleBJ=0,quest,StringExt _QuestSetTitleBJ_Defaults=GetLastCreatedQuestBJ,_ _QuestSetTitleBJ_Category=TC_QUEST QuestSetDescriptionBJ=0,quest,StringExt _QuestSetDescriptionBJ_Defaults=GetLastCreatedQuestBJ,_ _QuestSetDescriptionBJ_Category=TC_QUEST CreateQuestItemBJ=0,quest,StringExt _CreateQuestItemBJ_Defaults=GetLastCreatedQuestBJ,_ _CreateQuestItemBJ_Category=TC_QUEST QuestItemSetCompletedBJ=0,questitem,completionoption _QuestItemSetCompletedBJ_Defaults=GetLastCreatedQuestItemBJ,CompletionOptionCompleted _QuestItemSetCompletedBJ_Category=TC_QUEST QuestItemSetDescriptionBJ=0,questitem,StringExt _QuestItemSetDescriptionBJ_Defaults=GetLastCreatedQuestItemBJ,_ _QuestItemSetDescriptionBJ_Category=TC_QUEST CreateDefeatConditionBJ=0,StringExt _CreateDefeatConditionBJ_Defaults=_ _CreateDefeatConditionBJ_Category=TC_QUEST DestroyDefeatConditionBJ=0,defeatcondition _DestroyDefeatConditionBJ_Defaults=GetLastCreatedDefeatConditionBJ _DestroyDefeatConditionBJ_Category=TC_QUEST DefeatConditionSetDescriptionBJ=0,defeatcondition,StringExt _DefeatConditionSetDescriptionBJ_Defaults=GetLastCreatedDefeatConditionBJ,_ _DefeatConditionSetDescriptionBJ_Category=TC_QUEST FlashQuestDialogButtonBJ=0,nothing _FlashQuestDialogButtonBJ_Defaults= _FlashQuestDialogButtonBJ_Category=TC_QUEST // Region actions MoveRectToLoc=0,rect,location _MoveRectToLoc_Defaults=_,GetRectCenter _MoveRectToLoc_Category=TC_REGION // Selection actions ClearSelectionForPlayer=1,player _ClearSelectionForPlayer_Defaults=Player00 _ClearSelectionForPlayer_Category=TC_UNITSEL SelectGroupForPlayerBJ=1,group,player _SelectGroupForPlayerBJ_Defaults=_,Player00 _SelectGroupForPlayerBJ_Category=TC_UNITSEL SelectUnitForPlayerSingle=1,unit,player _SelectUnitForPlayerSingle_Defaults=GetTriggerUnit,Player00 _SelectUnitForPlayerSingle_Category=TC_UNITSEL SelectUnitAddForPlayer=1,unit,player _SelectUnitAddForPlayer_Defaults=GetTriggerUnit,Player00 _SelectUnitAddForPlayer_Category=TC_UNITSEL SelectUnitRemoveForPlayer=1,unit,player _SelectUnitRemoveForPlayer_Defaults=GetTriggerUnit,Player00 _SelectUnitRemoveForPlayer_Category=TC_UNITSEL ClearSelection=0,nothing _ClearSelection_Defaults= _ClearSelection_Category=TC_UNITSEL SelectGroupBJ=0,group _SelectGroupBJ_Defaults=_ _SelectGroupBJ_Category=TC_UNITSEL SelectUnitSingle=0,unit _SelectUnitSingle_Defaults=GetTriggerUnit _SelectUnitSingle_Category=TC_UNITSEL SelectUnitAdd=0,unit _SelectUnitAdd_Defaults=GetTriggerUnit _SelectUnitAdd_Category=TC_UNITSEL SelectUnitRemove=0,unit _SelectUnitRemove_Defaults=GetTriggerUnit _SelectUnitRemove_Category=TC_UNITSEL // Sound actions PlaySoundBJ=0,sound _PlaySoundBJ_Defaults=_ _PlaySoundBJ_Category=TC_SOUND PlaySoundAtPointBJ=1,sound,real,location,real _PlaySoundAtPointBJ_Defaults=_,100,GetRectCenter,0 _PlaySoundAtPointBJ_Limits=_,_,0,100,_,_,_,_ _PlaySoundAtPointBJ_Category=TC_SOUND PlaySoundOnUnitBJ=1,sound,real,unit _PlaySoundOnUnitBJ_Defaults=_,100,_ _PlaySoundOnUnitBJ_Limits=_,_,0,100,_,_ _PlaySoundOnUnitBJ_Category=TC_SOUND PlaySoundFromOffsetBJ=1,sound,real,real _PlaySoundFromOffsetBJ_Defaults=_,100,0,0 _PlaySoundFromOffsetBJ_Limits=_,_,0,100,0,_,0,_ _PlaySoundFromOffsetBJ_Category=TC_SOUND StopSoundBJ=0,sound,fadedontoption _StopSoundBJ_Defaults=_,FadeDontFade _StopSoundBJ_Category=TC_SOUND KillSoundWhenDoneBJ=0,sound _KillSoundWhenDoneBJ_Defaults=_ _KillSoundWhenDoneBJ_Category=TC_SOUND SetSoundVolumeBJ=0,sound,real _SetSoundVolumeBJ_Defaults=_,100 _SetSoundVolumeBJ_Limits=_,_,0,100 _SetSoundVolumeBJ_Category=TC_SOUND SetSoundOffsetBJ=1,real,sound _SetSoundOffsetBJ_Defaults=0,_ _SetSoundOffsetBJ_Limits=0,_,_,_ _SetSoundOffsetBJ_Category=TC_SOUND SetSoundDistanceCutoffBJ=0,sound,real _SetSoundDistanceCutoffBJ_Defaults=_,_ _SetSoundDistanceCutoffBJ_Category=TC_SOUND SetSoundPitchBJ=0,sound,real _SetSoundPitchBJ_Defaults=_,_ _SetSoundPitchBJ_Category=TC_SOUND AttachSoundToUnitBJ=0,sound,unit _AttachSoundToUnitBJ_Defaults=_,_ _AttachSoundToUnitBJ_Category=TC_SOUND SetSoundPositionLocBJ=0,sound,location,real _SetSoundPositionLocBJ_Defaults=_,GetRectCenter,0 _SetSoundPositionLocBJ_Category=TC_SOUND SetSoundDistances=0,sound,real,real _SetSoundDistances_Defaults=_,_,_ _SetSoundDistances_Limits=_,_,0,_,0,_ _SetSoundDistances_Category=TC_SOUND SetStackedSoundBJ=0,addremoveoption,sound,rect _SetStackedSoundBJ_Defaults=AddRemoveAdd,_,_ _SetStackedSoundBJ_Category=TC_SOUND SetAmbientDaySound=0,ambientthemeday _SetAmbientDaySound_Defaults=AmbientThemeDayL _SetAmbientDaySound_Category=TC_SOUND SetAmbientNightSound=0,ambientthemenight _SetAmbientNightSound_Defaults=AmbientThemeNightL _SetAmbientNightSound_Category=TC_SOUND EnableDawnDusk=0,enabledisableoption _EnableDawnDusk_Defaults=EnableDisableEnable _EnableDawnDusk_Category=TC_SOUND SetMapMusicIndexedBJ=0,musicfile,integer _SetMapMusicIndexedBJ_Defaults=MusicFileMusic,0 _SetMapMusicIndexedBJ_Category=TC_SOUND SetMapMusicRandomBJ=0,musicfile _SetMapMusicRandomBJ_Defaults=MusicFileMusic _SetMapMusicRandomBJ_Category=TC_SOUND ClearMapMusicBJ=0,nothing _ClearMapMusicBJ_Defaults= _ClearMapMusicBJ_Category=TC_SOUND PlayMusicBJ=0,musicfile _PlayMusicBJ_Defaults=_ _PlayMusicBJ_Category=TC_SOUND PlayMusicExBJ=1,musicfile,real,real _PlayMusicExBJ_Defaults=_,0,0 _PlayMusicExBJ_Limits=_,_,0,_,0,_ _PlayMusicExBJ_Category=TC_SOUND PlayThematicMusicBJ=0,musictheme _PlayThematicMusicBJ_Defaults=MusicThemeHeroicVictory _PlayThematicMusicBJ_Category=TC_SOUND PlayThematicMusicExBJ=1,musictheme,real _PlayThematicMusicExBJ_Defaults=MusicThemeHeroicVictory,0 _PlayThematicMusicExBJ_Limits=_,_,0,_ _PlayThematicMusicExBJ_Category=TC_SOUND EndThematicMusicBJ=0,nothing _EndThematicMusicBJ_Defaults= _EndThematicMusicBJ_Category=TC_SOUND StopMusicBJ=0,fadedontoption _StopMusicBJ_Defaults=FadeDontFade _StopMusicBJ_Category=TC_SOUND ResumeMusicBJ=0,nothing _ResumeMusicBJ_Defaults= _ResumeMusicBJ_Category=TC_SOUND SetMusicVolumeBJ=0,real _SetMusicVolumeBJ_Defaults=100 _SetMusicVolumeBJ_Limits=0,100 _SetMusicVolumeBJ_Category=TC_SOUND SetMusicOffsetBJ=1,real _SetMusicOffsetBJ_Defaults=0 _SetMusicOffsetBJ_Limits=0,_ _SetMusicOffsetBJ_Category=TC_SOUND SetThematicMusicOffsetBJ=1,real _SetThematicMusicOffsetBJ_Defaults=0 _SetThematicMusicOffsetBJ_Limits=0,_ _SetThematicMusicOffsetBJ_Category=TC_SOUND VolumeGroupSetVolumeBJ=0,volumegroup,real _VolumeGroupSetVolumeBJ_Defaults=VolumeGroupMusic,100 _VolumeGroupSetVolumeBJ_Limits=_,_,0,100 _VolumeGroupSetVolumeBJ_Category=TC_SOUND SetCineModeVolumeGroupsBJ=0,nothing _SetCineModeVolumeGroupsBJ_Defaults= _SetCineModeVolumeGroupsBJ_Category=TC_SOUND SetSpeechVolumeGroupsBJ=0,nothing _SetSpeechVolumeGroupsBJ_Defaults= _SetSpeechVolumeGroupsBJ_Category=TC_SOUND VolumeGroupResetBJ=0,nothing _VolumeGroupResetBJ_Defaults= _VolumeGroupResetBJ_Category=TC_SOUND // Special Effect actions AddSpecialEffectLocBJ=0,location,modelfile _AddSpecialEffectLocBJ_Defaults=GetRectCenter,"Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl" _AddSpecialEffectLocBJ_Category=TC_SPECIALEFFECT AddSpecialEffectTargetUnitBJ=0,string,unit,modelfile _AddSpecialEffectTargetUnitBJ_Defaults="overhead",GetTriggerUnit,"Abilities\Spells\Other\TalkToMe\TalkToMe.mdl" _AddSpecialEffectTargetUnitBJ_Category=TC_SPECIALEFFECT DestroyEffectBJ=0,effect _DestroyEffectBJ_Defaults=GetLastCreatedEffectBJ _DestroyEffectBJ_Category=TC_SPECIALEFFECT // Trigger actions DisableTrigger=0,trigger _DisableTrigger_Defaults=GetTriggeringTrigger _DisableTrigger_Category=TC_TRIGGER EnableTrigger=0,trigger _EnableTrigger_Defaults=GetTriggeringTrigger _EnableTrigger_Category=TC_TRIGGER ConditionalTriggerExecute=0,trigger _ConditionalTriggerExecute_Defaults=_ _ConditionalTriggerExecute_Category=TC_TRIGGER TriggerExecute=0,trigger _TriggerExecute_Defaults=_ _TriggerExecute_Category=TC_TRIGGER QueuedTriggerAddBJ=0,trigger,checkingignoringoption _QueuedTriggerAddBJ_Defaults=_,CheckingIgnoringChecking _QueuedTriggerAddBJ_Category=TC_TRIGGER QueuedTriggerRemoveBJ=0,trigger _QueuedTriggerRemoveBJ_Defaults=GetTriggeringTrigger _QueuedTriggerRemoveBJ_Category=TC_TRIGGER QueuedTriggerClearBJ=0,nothing _QueuedTriggerClearBJ_Defaults= _QueuedTriggerClearBJ_Category=TC_TRIGGER QueuedTriggerClearInactiveBJ=0,nothing _QueuedTriggerClearInactiveBJ_Defaults= _QueuedTriggerClearInactiveBJ_Category=TC_TRIGGER // This function is handled internally by the editor AddTriggerEvent=1,trigger,eventcall _AddTriggerEvent_Defaults=GetTriggeringTrigger,_ _AddTriggerEvent_Category=TC_TRIGGER // Unit actions CreateNUnitsAtLoc=0,integer,unitcode,player,location,real _CreateNUnitsAtLoc_Defaults=1,hfoo,Player00,GetRectCenter,RealUnitFacing _CreateNUnitsAtLoc_Limits=1,_,_,_,_,_,_,_,0,360 _CreateNUnitsAtLoc_Category=TC_UNIT CreateNUnitsAtLocFacingLocBJ=0,integer,unitcode,player,location,location _CreateNUnitsAtLocFacingLocBJ_Defaults=1,hfoo,Player00,GetRectCenter,GetUnitLoc _CreateNUnitsAtLocFacingLocBJ_Limits=1,_,_,_,_,_,_,_,_,_ _CreateNUnitsAtLocFacingLocBJ_Category=TC_UNIT CreateCorpseLocBJ=0,unitcode,player,location _CreateCorpseLocBJ_Defaults=hfoo,Player00,GetRectCenter _CreateCorpseLocBJ_Category=TC_UNIT CreatePermanentCorpseLocBJ=1,corpsetype,unitcode,player,location,real _CreatePermanentCorpseLocBJ_Defaults=CorpseTypeBone,hfoo,Player00,GetRectCenter,GetRandomDirectionDeg _CreatePermanentCorpseLocBJ_Limits=_,_,_,_,_,_,_,_,0,360 _CreatePermanentCorpseLocBJ_Category=TC_UNIT KillUnit=0,unit _KillUnit_Defaults=GetTriggerUnit _KillUnit_Category=TC_UNIT RemoveUnit=0,unit _RemoveUnit_Defaults=GetTriggerUnit _RemoveUnit_Category=TC_UNIT ExplodeUnitBJ=0,unit _ExplodeUnitBJ_Defaults=GetTriggerUnit _ExplodeUnitBJ_Category=TC_UNIT ReplaceUnitBJ=0,unit,unitcode,unitstatemethod _ReplaceUnitBJ_Defaults=GetTriggerUnit,hfoo,UnitStateMethodRelative _ReplaceUnitBJ_Category=TC_UNIT ShowUnitHide=0,unit _ShowUnitHide_Defaults=_ _ShowUnitHide_Category=TC_UNIT ShowUnitShow=0,unit _ShowUnitShow_Defaults=_ _ShowUnitShow_Category=TC_UNIT SetUnitColor=0,unit,playercolor _SetUnitColor_Defaults=GetTriggerUnit,Color00 _SetUnitColor_Category=TC_UNIT SetUnitOwner=0,unit,player,colorchangeoption _SetUnitOwner_Defaults=_,Player00,ChangeColorTrue _SetUnitOwner_Category=TC_UNIT UnitShareVisionBJ=0,sharedontoption,unit,player _UnitShareVisionBJ_Defaults=ShareDontOptionShare,GetTriggerUnit,Player00 _UnitShareVisionBJ_Category=TC_UNIT SetUnitPositionLoc=0,unit,location _SetUnitPositionLoc_Defaults=GetTriggerUnit,GetRectCenter _SetUnitPositionLoc_Category=TC_UNIT SetUnitPositionLocFacingBJ=0,unit,location,real _SetUnitPositionLocFacingBJ_Defaults=GetTriggerUnit,GetRectCenter,RealUnitFacing _SetUnitPositionLocFacingBJ_Category=TC_UNIT SetUnitPositionLocFacingLocBJ=0,unit,location,location _SetUnitPositionLocFacingLocBJ_Defaults=GetTriggerUnit,GetRectCenter,GetUnitLoc _SetUnitPositionLocFacingLocBJ_Category=TC_UNIT SetUnitRallyPoint=1,unit,location _SetUnitRallyPoint_Defaults=GetTriggerUnit,GetRectCenter _SetUnitRallyPoint_Category=TC_UNIT SetUnitRallyUnit=1,unit,unit _SetUnitRallyUnit_Defaults=GetTriggerUnit,_ _SetUnitRallyUnit_Category=TC_UNIT SetUnitRallyDestructable=1,unit,destructable _SetUnitRallyDestructable_Defaults=GetTriggerUnit,_ _SetUnitRallyDestructable_Category=TC_UNIT SetUnitLifePercentBJ=0,unit,real _SetUnitLifePercentBJ_Defaults=GetTriggerUnit,100 _SetUnitLifePercentBJ_Limits=_,_,0,100 _SetUnitLifePercentBJ_Category=TC_UNIT SetUnitManaPercentBJ=0,unit,real _SetUnitManaPercentBJ_Defaults=GetTriggerUnit,100 _SetUnitManaPercentBJ_Limits=_,_,0,100 _SetUnitManaPercentBJ_Category=TC_UNIT SetUnitLifeBJ=0,unit,real _SetUnitLifeBJ_Defaults=GetTriggerUnit,GetUnitStateSwap _SetUnitLifeBJ_Defaults=_,_,0,_ _SetUnitLifeBJ_Category=TC_UNIT SetUnitManaBJ=0,unit,real _SetUnitManaBJ_Defaults=GetTriggerUnit,0 _SetUnitManaBJ_Limits=_,_,0,_ _SetUnitManaBJ_Category=TC_UNIT EndUnitAbilityCooldown=0,unit,abilcode _EndUnitAbilityCooldown_Defaults=_,_ _EndUnitAbilityCooldown_Category=TC_UNIT SetAbilityTooltip=0,abilcode,string,integer _SetAbilityTooltip_Defaults=_,_,1 _SetAbilityTooltip_Limits=_,_,_,_,1,_ _SetAbilityTooltip_Category=TC_GAME SetAbilityOnTooltip=0,abilcode,string,integer _SetAbilityOnTooltip_Defaults=_,_,1 _SetAbilityOnTooltip_Limits=_,_,_,_,1,_ _SetAbilityOnTooltip_Category=TC_GAME SetAbilityExtendedTooltip=0,abilcode,string,integer _SetAbilityExtendedTooltip_Defaults=_,_,1 _SetAbilityExtendedTooltip_Limits=_,_,_,_,1,_ _SetAbilityExtendedTooltip_Category=TC_GAME SetAbilityOnExtendedTooltip=0,abilcode,string,integer _SetAbilityOnExtendedTooltip_Defaults=_,_,1 _SetAbilityOnExtendedTooltip_Limits=_,_,_,_,1,_ _SetAbilityOnExtendedTooltip_Category=TC_GAME SetAbilityResearchTooltip=0,abilcode,string,integer _SetAbilityResearchTooltip_Defaults=_,_,1 _SetAbilityResearchTooltip_Limits=_,_,_,_,1,_ _SetAbilityResearchTooltip_Category=TC_GAME SetAbilityResearchExtendedTooltip=0,abilcode,string,integer _SetAbilityResearchExtendedTooltip_Defaults=_,_,1 _SetAbilityResearchExtendedTooltip_Limits=_,_,_,_,1,_ _SetAbilityResearchExtendedTooltip_Category=TC_GAME SetAbilityIcon=0,abilcode,string,integer _SetAbilityIcon_Defaults=_,_,1 _SetAbilityIcon_Limits=_,_,_,_,1,_ _SetAbilityIcon_Category=TC_GAME SetAbilityOnIcon=0,abilcode,string,integer _SetAbilityOnIcon_Defaults=_,_,1 _SetAbilityOnIcon_Limits=_,_,_,_,1,_ _SetAbilityOnIcon_Category=TC_GAME SetAbilityPosX=0,abilcode,integer _SetAbilityPosX_Defaults=_,0 _SetAbilityPosX_Limits=_,_,0,3 _SetAbilityPosX_Category=TC_GAME SetAbilityOnPosX=0,abilcode,integer _SetAbilityOnPosX_Defaults=_,0 _SetAbilityOnPosX_Limits=_,_,0,3 _SetAbilityOnPosX_Category=TC_GAME SetAbilityPosY=0,abilcode,integer _SetAbilityPosY_Defaults=_,0 _SetAbilityPosY_Limits=_,_,0,2 _SetAbilityPosY_Category=TC_GAME SetAbilityOnPosY=0,abilcode,integer _SetAbilityOnPosY_Defaults=_,0 _SetAbilityOnPosY_Limits=_,_,0,2 _SetAbilityOnPosY_Category=TC_GAME SetEventDamage=0,real _SetEventDamage_Defaults=0.0 _SetEventDamage_Category=TC_EVENTRESPONSE SetItemName=0,item,string _SetItemName_Defaults=GetLastCreatedItem,_ _SetItemName_Category=TC_ITEM SetItemTooltip=0,item,string _SetItemTooltip_Defaults=GetLastCreatedItem,_ _SetItemTooltip_Category=TC_ITEM SetItemDescription=0,item,string _SetItemDescription_Defaults=GetLastCreatedItem,_ _SetItemDescription_Category=TC_ITEM SetItemExtendedTooltip=0,item,string _SetItemExtendedTooltip_Defaults=GetLastCreatedItem,_ _SetItemExtendedTooltip_Category=TC_ITEM SetItemIconPath=0,item,string _SetItemIconPath_Defaults=GetLastCreatedItem,_ _SetItemIconPath_Category=TC_ITEM SetUnitMaxHP=0,unit,integer _SetUnitMaxHP_Defaults=GetTriggerUnit,500 _SetUnitMaxHP_Limits=_,_,1,_ _SetUnitMaxHP_Category=TC_UNIT SetUnitMaxMana=0,unit,integer _SetUnitMaxMana_Defaults=GetTriggerUnit,300 _SetUnitMaxManaSetUnitMaxMana_Limits=_,_,0,_ _SetUnitMaxMana_Category=TC_UNIT SetUnitArmor=0,unit,real _SetUnitArmor_Defaults=GetTriggerUnit,0.00 _SetUnitArmor_Limits=_,_,0.00,_ _SetUnitArmor_Category=TC_UNIT UnitHideAbility=0,unit,abilcode,boolean _UnitHideAbility_Defaults=GetTriggerUnit,_,true _UnitHideAbility_Category=TC_UNIT UnitDisableAbility=0,unit,abilcode,boolean,boolean _UnitDisableAbility_Defaults=GetTriggerUnit,_,true,true _UnitDisableAbility_Category=TC_UNIT UnitCancelTimedLife=0,unit _UnitCancelTimedLife_Defaults=GetTriggeredUnit _UnitCancelTimedLife_Category=TC_UNIT UnitInterruptAttack=0,unit _UnitInterruptAttack_Defaults=GetTriggeredUnit _UnitInterruptAttack_Category=TC_UNIT SetUnitAbilityCooldown=0,unit,abilcode,integer,real _SetUnitAbilityCooldown_Defaults=GetTriggerUnit,_,1,5.00 _SetUnitAbilityCooldown_Limits=_,_,_,_,1,_,0.00,_ _SetUnitAbilityCooldown_Category=TC_UNIT SetUnitBaseDamage=0,unit,integer,integer _SetUnitBaseDamage_Defaults=GetTriggerUnit,10,0 _SetUnitBaseDamage_Limits=_,_,0,_,0,1 _SetUnitBaseDamage_Category=TC_UNIT SetUnitDiceNumber=0,unit,integer,integer _SetUnitDiceNumber_Defaults=GetTriggerUnit,4,0 _SetUnitDiceNumber_Limits=_,_,0,_,0,1 _SetUnitDiceNumber_Category=TC_UNIT SetUnitDiceSides=0,unit,integer,integer _SetUnitDiceSides_Defaults=GetTriggerUnit,1,0 _SetUnitDiceSides_Limits=_,_,0,_,0, _SetUnitDiceSides_Category=TC_UNIT SetUnitAttackCooldown=0,unit,real,integer _SetUnitAttackCooldown_Defaults=GetTriggerUnit,2.00,1 _SetUnitAttackCooldown_Limits=_,_,0.001,_,1,2 _SetUnitAttackCooldown_Category=TC_UNIT SetUnitName=0,unit,string _SetUnitName_Defaults=GetTriggerUnit,_ _SetUnitName_Category=TC_UNIT SetUnitNameAll=0,unit,string _SetUnitNameAll_Defaults=GetTriggerUnit,_ _SetUnitNameAll_Category=TC_UNIT SetHeroProperName=0,unit,string _SetHeroProperName_Defaults=GetTriggerUnit,_ _SetHeroProperName_Category=TC_HERO // Special Effect SetSpecialEffectColorByPlayer=0,effect,player _SetSpecialEffectColorByPlayer_Defaults=GetLastCreatedEffectBJ,player(0) _SetSpecialEffectColorByPlayer_Category=TC_SPECIALEFFECT SetSpecialEffectColor=0,effect,integer,integer,integer _SetSpecialEffectColor_Defaults=GetLastCreatedEffectBJ,255,255,255 _SetSpecialEffectColor_Limits=_,_,0,255,0,255,0,255 _SetSpecialEffectColor_Category=TC_SPECIALEFFECT SetSpecialEffectAlpha=0,effect,integer _SetSpecialEffectAlpha_Defaults=GetLastCreatedEffectBJ,255 _SetSpecialEffectAlpha_Limits=_,_,0,255 _SetSpecialEffectAlpha_Category=TC_SPECIALEFFECT SetSpecialEffectScale=0,effect,real _SetSpecialEffectScale_Defaults=GetLastCreatedEffectBJ,1.0 _SetSpecialEffectScale_Category=TC_SPECIALEFFECT SetSpecialEffectPosition=0,effect,real,real,real _SetSpecialEffectPosition_Defaults=GetLastCreatedEffectBJ,0.0,0.0,0.0 _SetSpecialEffectPosition_Category=TC_SPECIALEFFECT SetSpecialEffectX=0,effect,real _SetSpecialEffectX_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectX_Category=TC_SPECIALEFFECT SetSpecialEffectY=0,effect,real _SetSpecialEffectY_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectY_Category=TC_SPECIALEFFECT SetSpecialEffectZ=0,effect,real _SetSpecialEffectZ_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectZ_Category=TC_SPECIALEFFECT SetSpecialEffectPositionLoc=0,effect,location _SetSpecialEffectPositionLoc_Defaults=GetLastCreatedEffectBJ,GetRectCenter _SetSpecialEffectPositionLoc_Category=TC_SPECIALEFFECT SetSpecialEffectHeight=0,effect,real _SetSpecialEffectHeight_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectHeight_Category=TC_SPECIALEFFECT SetSpecialEffectOrientation=0,effect,real,real,real _SetSpecialEffectOrientation_Defaults=GetLastCreatedEffectBJ,0.0,0.0,0.0 _SetSpecialEffectOrientation_Category=TC_SPECIALEFFECT SetSpecialEffectYaw=0,effect,real _SetSpecialEffectYaw_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectYaw_Category=TC_SPECIALEFFECT SetSpecialEffectPitch=0,effect,real _SetSpecialEffectPitch_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectPitch_Category=TC_SPECIALEFFECT SetSpecialEffectRoll=0,effect,real _SetSpecialEffectRoll_Defaults=GetLastCreatedEffectBJ,0.0 _SetSpecialEffectRoll_Category=TC_SPECIALEFFECT SetSpecialEffectTimeScale=0,effect,real _SetSpecialEffectTimeScale_Defaults=GetLastCreatedEffectBJ,1.0 _SetSpecialEffectTimeScale_Category=TC_SPECIALEFFECT SetSpecialEffectTime=0,effect,real _SetSpecialEffectTime_Defaults=GetLastCreatedEffectBJ, 1.0 _SetSpecialEffectTime_Category=TC_SPECIALEFFECT PlaySpecialEffect=0,effect,integer _PlaySpecialEffect_Defaults=GetLastCreatedEffectBJ, 0 _PlaySpecialEffect_Category=TC_SPECIALEFFECT PlaySpecialEffectWithTimeScale=0,effect,integer,real _PlaySpecialEffectWithTimeScale_Defaults=GetLastCreatedEffectBJ, 0, 1.0 _PlaySpecialEffectWithTimeScale_Category=TC_SPECIALEFFECT SetUnitInvulnerable=0,unit,invulnerableoption _SetUnitInvulnerable_Defaults=GetTriggerUnit,InvulnerabilityInvulnerable _SetUnitInvulnerable_Category=TC_UNIT PauseUnitBJ=0,pauseunpauseoption,unit _PauseUnitBJ_Defaults=PauseUnpauseOptionPause,GetTriggerUnit _PauseUnitBJ_Category=TC_UNIT PauseAllUnitsBJ=0,pauseunpauseoption _PauseAllUnitsBJ_Defaults=PauseUnpauseOptionPause _PauseAllUnitsBJ_Category=TC_UNIT UnitPauseTimedLifeBJ=1,pauseunpauseoption,unit _UnitPauseTimedLifeBJ_Defaults=PauseUnpauseOptionPause,GetTriggerUnit _UnitPauseTimedLifeBJ_Category=TC_UNIT UnitApplyTimedLifeBJ=1,real,timedlifebuffcode,unit _UnitApplyTimedLifeBJ_Defaults=60,TimedLifeBuffCodeGeneric,GetTriggerUnit _UnitApplyTimedLifeBJ_Limits=0,_,_,_,_,_ _UnitApplyTimedLifeBJ_Category=TC_UNIT SetUnitExplodedBJ=0,unit,explodedontoption _SetUnitExplodedBJ_Defaults=GetTriggerUnit,ExplodeDontExplode _SetUnitExplodedBJ_Category=TC_UNIT UnitSuspendDecayBJ=0,suspendresumeoption,unit _UnitSuspendDecayBJ_Defaults=SuspendResumeSuspend,GetTriggerUnit _UnitSuspendDecayBJ_Category=TC_UNIT UnitResetCooldown=1,unit _UnitResetCooldown_Defaults=GetTriggerUnit _UnitResetCooldown_Category=TC_UNIT UnitSetConstructionProgress=1,unit,integer _UnitSetConstructionProgress_Defaults=GetTriggerUnit,50 _UnitSetConstructionProgress_Limits=_,_,0,100 _UnitSetConstructionProgress_Category=TC_UNIT UnitSetUpgradeProgress=1,unit,integer _UnitSetUpgradeProgress_Defaults=GetTriggerUnit,50 _UnitSetUpgradeProgress_Limits=_,_,0,100 _UnitSetUpgradeProgress_Category=TC_UNIT UnitAddSleepPerm=0,unit,sleepwakeoption _UnitAddSleepPerm_Defaults=GetTriggerUnit,SleepWakeOptionSleep _UnitAddSleepPerm_Category=TC_UNIT UnitSetCanSleepBJ=0,unit,sleepwakeoption _UnitSetCanSleepBJ_Defaults=GetTriggerUnit,SleepWakeOptionSleep _UnitSetCanSleepBJ_Category=TC_UNIT UnitWakeUpBJ=0,unit _UnitWakeUpBJ_Defaults=GetTriggerUnit _UnitWakeUpBJ_Category=TC_UNIT UnitGenerateAlarms=1,unit,onoffoption _UnitGenerateAlarms_Defaults=GetTriggerUnit,OnOffOff _UnitGenerateAlarms_Category=TC_UNIT RescueUnitBJ=0,unit,player,colorchangeoption _RescueUnitBJ_Defaults=_,Player00,ChangeColorTrue _RescueUnitBJ_Category=TC_UNIT MakeUnitRescuableToForceBJ=0,unit,rescuableoption,force _MakeUnitRescuableToForceBJ_Defaults=_,RescuableOptionRescuable,Force00 _MakeUnitRescuableToForceBJ_Category=TC_UNIT SetUnitRescueRange=0,unit,real _SetUnitRescueRange_Defaults=_,384 _SetUnitRescueRange_Limits=_,_,0,_ _SetUnitRescueRange_Category=TC_UNIT SetRescueUnitColorChangeBJ=0,colorchangeoption _SetRescueUnitColorChangeBJ_Defaults=ChangeColorFalse _SetRescueUnitColorChangeBJ_Category=TC_UNIT SetRescueBuildingColorChangeBJ=0,colorchangeoption _SetRescueBuildingColorChangeBJ_Defaults=ChangeColorFalse _SetRescueBuildingColorChangeBJ_Category=TC_UNIT SetUnitUseFoodBJ=1,enabledisableoption,unit _SetUnitUseFoodBJ_Defaults=EnableDisableDisable,_ _SetUnitUseFoodBJ_Category=TC_UNIT SetUnitFacingToFaceUnitTimed=0,unit,unit,real _SetUnitFacingToFaceUnitTimed_Defaults=_,_,0 _SetUnitFacingToFaceUnitTimed_Limits=_,_,_,_,0,_ _SetUnitFacingToFaceUnitTimed_Category=TC_UNIT SetUnitFacingToFaceLocTimed=0,unit,location,real _SetUnitFacingToFaceLocTimed_Defaults=_,GetRectCenter,0 _SetUnitFacingToFaceLocTimed_Limits=_,_,_,_,0,_ _SetUnitFacingToFaceLocTimed_Category=TC_UNIT SetUnitFacingTimed=0,unit,real,real _SetUnitFacingTimed_Defaults=_,RealUnitFacing,0 _SetUnitFacingTimed_Limits=_,_,_,_,0,_ _SetUnitFacingTimed_Category=TC_UNIT SetUnitMoveSpeed=0,unit,real _SetUnitMoveSpeed_Defaults=_,GetUnitDefaultMoveSpeed _SetUnitMoveSpeed_Category=TC_UNIT SetUnitPathing=0,unit,pathingoption _SetUnitPathing_Defaults=_,PathingOff _SetUnitPathing_Category=TC_UNIT SetUnitAcquireRangeBJ=0,unit,real _SetUnitAcquireRangeBJ_Defaults=_,_ _SetUnitAcquireRangeBJ_Category=TC_UNIT SetUnitUserData=1,unit,integer _SetUnitUserData_Defaults=_,0 _SetUnitUserData_Category=TC_UNIT UnitRemoveBuffsBJ=0,bufftype,unit _UnitRemoveBuffsBJ_Defaults=BuffTypeAll,GetTriggerUnit _UnitRemoveBuffsBJ_Category=TC_UNIT UnitRemoveBuffsExBJ=1,buffpolarity,buffresist,unit,includeoption,includeoption _UnitRemoveBuffsExBJ_Defaults=BuffPolarityEither,BuffResistEither,GetTriggerUnit,InclusionInclude,InclusionInclude _UnitRemoveBuffsExBJ_Category=TC_UNIT UnitRemoveBuffBJ=1,buffcode,unit _UnitRemoveBuffBJ_Defaults=_,GetTriggerUnit _UnitRemoveBuffBJ_Category=TC_UNIT UnitAddAbilityBJ=1,abilcode,unit _UnitAddAbilityBJ_Defaults=_,GetTriggerUnit _UnitAddAbilityBJ_Category=TC_UNIT UnitRemoveAbilityBJ=0,abilcode,unit _UnitRemoveAbilityBJ_Defaults=_,GetTriggerUnit _UnitRemoveAbilityBJ_Category=TC_UNIT UnitAddTypeBJ=1,unittype,unit _UnitAddTypeBJ_Defaults=UnitTypeMechanical,GetTriggerUnit _UnitAddTypeBJ_Category=TC_UNIT UnitRemoveTypeBJ=1,unittype,unit _UnitRemoveTypeBJ_Defaults=UnitTypeMechanical,GetTriggerUnit _UnitRemoveTypeBJ_Category=TC_UNIT IssueTargetOrder=0,unit,unitorderutarg,unit _IssueTargetOrder_Defaults=_,UnitOrderAttackUnit,_ _IssueTargetOrder_Category=TC_UNIT _IssueTargetOrder_ScriptName=IssueTargetOrderBJ IssuePointOrderLoc=0,unit,unitorderptarg,location _IssuePointOrderLoc_Defaults=_,UnitOrderMove,GetRectCenter _IssuePointOrderLoc_Category=TC_UNIT _IssuePointOrderLoc_ScriptName=IssuePointOrderLocBJ IssueTargetDestructableOrder=0,unit,unitorderdtarg,destructable _IssueTargetDestructableOrder_Defaults=_,UnitOrderHarvestDestructible,_ _IssueTargetDestructableOrder_Category=TC_UNIT IssueTargetItemOrder=0,unit,unitorderitarg,item _IssueTargetItemOrder_Defaults=_,UnitOrderSmartItem,_ _IssueTargetItemOrder_Category=TC_UNIT IssueImmediateOrder=0,unit,unitordernotarg _IssueImmediateOrder_Defaults=_,UnitOrderStop _IssueImmediateOrder_Category=TC_UNIT _IssueImmediateOrder_ScriptName=IssueImmediateOrderBJ IssueTrainOrderByIdBJ=0,unit,unitcode _IssueTrainOrderByIdBJ_Defaults=_,hfoo _IssueTrainOrderByIdBJ_Category=TC_UNIT IssueUpgradeOrderByIdBJ=0,unit,techcode _IssueUpgradeOrderByIdBJ_Defaults=_,Rhde _IssueUpgradeOrderByIdBJ_Category=TC_UNIT IssueBuildOrderByIdLocBJ=0,unit,unitcode,location _IssueBuildOrderByIdLocBJ_Defaults=_,hbar,GetRectCenter _IssueBuildOrderByIdLocBJ_Category=TC_UNIT UnitDropItemPointLoc=1,unit,item,location _UnitDropItemPointLoc_Defaults=_,GetLastCreatedItem,GetRectCenter _UnitDropItemPointLoc_Category=TC_UNIT UnitDropItemSlotBJ=1,unit,item,integer _UnitDropItemSlotBJ_Defaults=_,GetLastCreatedItem,1 _UnitDropItemSlotBJ_Limits=_,_,_,_,1,6 _UnitDropItemSlotBJ_Category=TC_UNIT UnitDropItemTargetBJ=1,unit,item,unit _UnitDropItemTargetBJ_Defaults=_,GetLastCreatedItem,_ _UnitDropItemTargetBJ_Category=TC_UNIT UnitDamagePointLoc=1,unit,real,real,location,real,attacktype,damagetype _UnitDamagePointLoc_Defaults=GetTriggerUnit,0,500,GetRectCenter,100,AttackTypeNormal,DamageTypeNormal _UnitDamagePointLoc_Category=TC_UNIT UnitDamageTargetBJ=1,unit,unit,real,attacktype,damagetype _UnitDamageTargetBJ_Defaults=GetTriggerUnit,GetTriggerUnit,500,AttackTypeNormal,DamageTypeNormal _UnitDamageTargetBJ_Category=TC_UNIT DecUnitAbilityLevelSwapped=1,abilcode,unit _DecUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit _DecUnitAbilityLevelSwapped_Category=TC_UNIT IncUnitAbilityLevelSwapped=1,abilcode,unit _IncUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit _IncUnitAbilityLevelSwapped_Category=TC_UNIT SetUnitAbilityLevelSwapped=1,abilcode,unit,integer _SetUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit,1 _SetUnitAbilityLevelSwapped_Limits=_,_,_,_,1,_ _SetUnitAbilityLevelSwapped_Category=TC_UNIT // Unit Group actions // Specially handled by the editor ForGroupMultiple=1,group _ForGroupMultiple_Defaults=GetUnitsInRectAll _ForGroupMultiple_Category=TC_UNITGROUP _ForGroupMultiple_ScriptName=ForGroupBJ ForGroup=0,group,code _ForGroup_Defaults=GetUnitsInRectAll,DoNothing _ForGroup_Category=TC_UNITGROUP _ForGroup_ScriptName=ForGroupBJ GroupAddUnitSimple=0,unit,group _GroupAddUnitSimple_Defaults=GetTriggerUnit,_ _GroupAddUnitSimple_Category=TC_UNITGROUP GroupAddGroup=0,group,group _GroupAddGroup_Defaults=_,_ _GroupAddGroup_Category=TC_UNITGROUP GroupRemoveUnitSimple=0,unit,group _GroupRemoveUnitSimple_Defaults=GetTriggerUnit,_ _GroupRemoveUnitSimple_Category=TC_UNITGROUP GroupRemoveGroup=0,group,group _GroupRemoveGroup_Defaults=_,_ _GroupRemoveGroup_Category=TC_UNITGROUP GroupClear=0,group _GroupClear_Defaults=_ _GroupClear_Category=TC_UNITGROUP GroupTargetOrder=0,group,unitorderutarg,unit _GroupTargetOrder_Defaults=GetUnitsInRectAll,UnitOrderAttackUnit,_ _GroupTargetOrder_Category=TC_UNITGROUP _GroupTargetOrder_ScriptName=GroupTargetOrderBJ GroupPointOrderLoc=0,group,unitorderptarg,location _GroupPointOrderLoc_Defaults=GetUnitsInRectAll,UnitOrderMove,GetRectCenter _GroupPointOrderLoc_Category=TC_UNITGROUP _GroupPointOrderLoc_ScriptName=GroupPointOrderLocBJ GroupTargetDestructableOrder=0,group,unitorderdtarg,destructable _GroupTargetDestructableOrder_Defaults=GetUnitsInRectAll,UnitOrderHarvestDestructible,_ _GroupTargetDestructableOrder_Category=TC_UNITGROUP GroupTargetItemOrder=0,group,unitorderitarg,item _GroupTargetItemOrder_Defaults=GetUnitsInRectAll,UnitOrderAttackItem,_ _GroupTargetItemOrder_Category=TC_UNITGROUP GroupImmediateOrder=0,group,unitordernotarg _GroupImmediateOrder_Defaults=GetUnitsInRectAll,UnitOrderStop _GroupImmediateOrder_Category=TC_UNITGROUP _GroupImmediateOrder_ScriptName=GroupImmediateOrderBJ GroupTrainOrderByIdBJ=0,group,unitcode _GroupTrainOrderByIdBJ_Defaults=GetUnitsInRectAll,hfoo _GroupTrainOrderByIdBJ_Category=TC_UNITGROUP // Ubersplat actions CreateUbersplatBJ=1,location,ubersplattype,real,real,real,real,enabledisableoption,enabledisableoption _CreateUberSplatBJ_Defaults=GetRectCenter,UbersplatTypeNGOL,100,100,100,0,EnableDisableDisable,EnableDisableDisable _CreateUberSplatBJ_Category=TC_UBERSPLAT DestroyUbersplat=1,ubersplat _DestroyUbersplat_Defaults=GetLastCreatedUbersplat _DestroyUbersplat_Category=TC_UBERSPLAT ResetUbersplat=1,ubersplat _ResetUbersplat_Defaults=GetLastCreatedUbersplat _ResetUbersplat_Category=TC_UBERSPLAT FinishUbersplat=1,ubersplat _FinishUbersplat_Defaults=GetLastCreatedUbersplat _FinishUbersplat_Category=TC_UBERSPLAT ShowUbersplatBJ=1,showhideoption,ubersplat _ShowUbersplatBJ_Defaults=ShowHideShow,GetLastCreatedUbersplat _ShowUbersplatBJ_Category=TC_UBERSPLAT SetUbersplatRender=1,ubersplat,enabledisableoption _SetUbersplatRender_Defaults=GetLastCreatedUbersplat,EnableDisableEnable _SetUbersplatRender_Category=TC_UBERSPLAT SetUbersplatRenderAlways=1,ubersplat,enabledisableoption _SetUbersplatRenderAlways_Defaults=GetLastCreatedUbersplat,EnableDisableEnable _SetUbersplatRenderAlways_Category=TC_UBERSPLAT // Visibility actions FogEnableOn=0,nothing _FogEnableOn_Defaults= _FogEnableOn_Category=TC_VISIBILITY FogEnableOff=0,nothing _FogEnableOff_Defaults= _FogEnableOff_Category=TC_VISIBILITY FogMaskEnableOn=0,nothing _FogMaskEnableOn_Defaults= _FogMaskEnableOn_Category=TC_VISIBILITY FogMaskEnableOff=0,nothing _FogMaskEnableOff_Defaults= _FogMaskEnableOff_Category=TC_VISIBILITY CreateFogModifierRectBJ=0,enableddisabledoption,player,fogstate,rect _CreateFogModifierRectBJ_Defaults=EnabledDisabledEnabled,Player00,FogStateVisible,GetPlayableMapRect _CreateFogModifierRectBJ_Category=TC_VISIBILITY CreateFogModifierRadiusLocBJ=0,enableddisabledoption,player,fogstate,location,real _CreateFogModifierRadiusLocBJ_Defaults=EnabledDisabledEnabled,Player00,FogStateVisible,GetRectCenter,512 _CreateFogModifierRadiusLocBJ_Defaults=_,_,_,_,_,_,_,_,0,_ _CreateFogModifierRadiusLocBJ_Category=TC_VISIBILITY FogModifierStart=0,fogmodifier _FogModifierStart_Defaults=GetLastCreatedFogModifier _FogModifierStart_Category=TC_VISIBILITY FogModifierStop=0,fogmodifier _FogModifierStop_Defaults=GetLastCreatedFogModifier _FogModifierStop_Category=TC_VISIBILITY DestroyFogModifier=0,fogmodifier _DestroyFogModifier_Defaults=GetLastCreatedFogModifier _DestroyFogModifier_Category=TC_VISIBILITY // Obsolete actions //AddPerfLogLabel=0,string //_AddPerfLogLabel_Defaults="Triggered Debug Label" //_AddPerfLogLabel_Category=TC_OBSOLETE //Cheat=0,string //_Cheat_Defaults="warnings" //_Cheat_Category=TC_OBSOLETE //*************************************************************************** [TriggerCalls] // Defines function calls which may be used as parameter values // Key: Function name // Value 0: first game version in which this function is valid // Value 1: flag (0 or 1) indicating if the call can be used in events // Value 2: return type // Value 3+: argument types // // Note: Operators are specially handled by the editor // returns boolean IsDestructableAliveBJ=0,0,boolean,destructable _IsDestructableAliveBJ_Defaults=GetLastCreatedDestructable _IsDestructableAliveBJ_Category=TC_DESTRUCT IsDestructableDeadBJ=0,0,boolean,destructable _IsDestructableDeadBJ_Defaults=GetLastCreatedDestructable _IsDestructableDeadBJ_Category=TC_DESTRUCT IsDestructableInvulnerableBJ=0,0,boolean,destructable _IsDestructableInvulnerableBJ_Defaults=GetLastCreatedDestructable _IsDestructableInvulnerableBJ_Category=TC_DESTRUCT IsPointBlightedBJ=1,1,boolean,location _IsPointBlightedBJ_Defaults=GetRectCenter _IsPointBlightedBJ_Category=TC_ENVIRONMENT IsTerrainPathableBJ=1,1,boolean,location,pathingtype _IsTerrainPathableBJ_Defaults=GetRectCenter,PathingTypeWalkability _IsTerrainPathableBJ_Category=TC_ENVIRONMENT IsMapFlagSet=0,1,boolean,mapflag _IsMapFlagSet_Defaults=MapFlagUseHandicaps _IsMapFlagSet_Category=TC_GAME IsCustomCampaignButtonVisibile=1,0,boolean,integer _IsCustomCampaignButtonVisibile_Defaults=1 _IsCustomCampaignButtonVisibile_Limits=1,_ _IsCustomCampaignButtonVisibile_Category=TC_GAME GetCreepCampFilterState=1,1,boolean _GetCreepCampFilterState_Category=TC_GAME SaveGameExists=1,0,boolean,anyfile _SaveGameExists_Defaults=_ _SaveGameExists_Category=TC_GAME GetStoredBooleanBJ=0,0,boolean,string,string,gamecache _GetStoredBooleanBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredBooleanBJ_Category=TC_GAMECACHE IsUnitSelectable=0,1,boolean,unit _IsUnitSelectable_Defaults=GetTriggerUnit _IsUnitSelectable_Category=TC_UNIT IsUnitInvulnerable=0,1,boolean,unit _IsUnitInvulnerable_Defaults=GetTriggerUnit _IsUnitInvulnerable_Category=TC_UNIT // Hashtable GetHandleIdBJ=1,1,integer,handle _GetHandleIdBJ_Defaults= _GetHandleIdBJ_Category=TC_HASHTABLE StringHashBJ=1,1,integer,string _StringHashBJ_Defaults= _StringHashBJ_Category=TC_HASHTABLE LoadIntegerBJ=0,0,integer,integer,integer,hashtable _LoadIntegerBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadIntegerBJ_Category=TC_HASHTABLE LoadRealBJ=0,0,real,integer,integer,hashtable _LoadRealBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadRealBJ_Category=TC_HASHTABLE LoadStringBJ=1,0,string,integer,integer,hashtable _LoadStringBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadStringBJ_Category=TC_HASHTABLE LoadBooleanBJ=0,0,boolean,integer,integer,hashtable _LoadBooleanBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadBooleanBJ_Category=TC_HASHTABLE LoadPlayerHandleBJ=0,0,player,integer,integer,hashtable _LoadPlayerHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadPlayerHandleBJ_Category=TC_HASHTABLE LoadWidgetHandleBJ=0,0,widget,integer,integer,hashtable _LoadWidgetHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadWidgetHandleBJ_Category=TC_HASHTABLE LoadDestructableHandleBJ=0,0,destructable,integer,integer,hashtable _LoadDestructableHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadDestructableHandleBJ_Category=TC_HASHTABLE LoadItemHandleBJ=0,0,item,integer,integer,hashtable _LoadItemHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadItemHandleBJ_Category=TC_HASHTABLE LoadUnitHandleBJ=0,0,unit,integer,integer,hashtable _LoadUnitHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadUnitHandleBJ_Category=TC_HASHTABLE LoadAbilityHandleBJ=0,0,ability,integer,integer,hashtable _LoadAbilityHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadAbilityHandleBJ_Category=TC_HASHTABLE LoadTimerHandleBJ=0,0,timer,integer,integer,hashtable _LoadTimerHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTimerHandleBJ_Category=TC_HASHTABLE //LoadTriggerRegionHandleBJ=0,0,region,integer,integer,hashtable //_LoadTriggerRegionHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ //_LoadTriggerRegionHandleBJ_Category=TC_HASHTABLE LoadTriggerHandleBJ=0,0,trigger,integer,integer,hashtable _LoadTriggerHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTriggerHandleBJ_Category=TC_HASHTABLE LoadTriggerConditionHandleBJ=0,0,triggercondition,integer,integer,hashtable _LoadTriggerConditionHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTriggerConditionHandleBJ_Category=TC_HASHTABLE LoadTriggerActionHandleBJ=0,0,triggeraction,integer,integer,hashtable _LoadTriggerActionHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTriggerActionHandleBJ_Category=TC_HASHTABLE LoadTriggerEventHandleBJ=0,0,eventid,integer,integer,hashtable _LoadTriggerEventHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTriggerEventHandleBJ_Category=TC_HASHTABLE LoadForceHandleBJ=0,0,force,integer,integer,hashtable _LoadForceHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadForceHandleBJ_Category=TC_HASHTABLE LoadGroupHandleBJ=0,0,group,integer,integer,hashtable _LoadGroupHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadGroupHandleBJ_Category=TC_HASHTABLE LoadLocationHandleBJ=0,0,location,integer,integer,hashtable _LoadLocationHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadLocationHandleBJ_Category=TC_HASHTABLE LoadRegionHandleBJ=0,0,region,integer,integer,hashtable _LoadRegionHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadRegionHandleBJ_Category=TC_HASHTABLE LoadRectHandleBJ=0,0,rect,integer,integer,hashtable _LoadRectHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadRectHandleBJ_Category=TC_HASHTABLE LoadBooleanExprHandleBJ=0,0,boolexpr,integer,integer,hashtable _LoadBooleanExprHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadBooleanExprHandleBJ_Category=TC_HASHTABLE //LoadConditionFuncHandleBJ=0,0,conditionfunc,integer,integer,hashtable //_LoadConditionFuncHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ //_LoadConditionFuncHandleBJ_Category=TC_HASHTABLE //LoadFilterFuncHandleBJ=0,0,filterfunc,integer,integer,hashtable //_LoadFilterFuncHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ //_LoadFilterFuncHandleBJ_Category=TC_HASHTABLE LoadSoundHandleBJ=0,0,sound,integer,integer,hashtable _LoadSoundHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadSoundHandleBJ_Category=TC_HASHTABLE //LoadRaceHandleBJ=0,0,race,integer,integer,hashtable //_LoadRaceHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ //_LoadRaceHandleBJ_Category=TC_HASHTABLE LoadEffectHandleBJ=0,0,effect,integer,integer,hashtable _LoadEffectHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadEffectHandleBJ_Category=TC_HASHTABLE LoadUnitPoolHandleBJ=0,0,unitpool,integer,integer,hashtable _LoadUnitPoolHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadUnitPoolHandleBJ_Category=TC_HASHTABLE LoadItemPoolHandleBJ=0,0,itempool,integer,integer,hashtable _LoadItemPoolHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadItemPoolHandleBJ_Category=TC_HASHTABLE LoadQuestHandleBJ=0,0,quest,integer,integer,hashtable _LoadQuestHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadQuestHandleBJ_Category=TC_HASHTABLE LoadQuestItemHandleBJ=0,0,questitem,integer,integer,hashtable _LoadQuestItemHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadQuestItemHandleBJ_Category=TC_HASHTABLE LoadDefeatConditionHandleBJ=0,0,defeatcondition,integer,integer,hashtable _LoadDefeatConditionHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadDefeatConditionHandleBJ_Category=TC_HASHTABLE LoadTimerDialogHandleBJ=0,0,timerdialog,integer,integer,hashtable _LoadTimerDialogHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTimerDialogHandleBJ_Category=TC_HASHTABLE LoadLeaderboardHandleBJ=0,0,leaderboard,integer,integer,hashtable _LoadLeaderboardHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadLeaderboardHandleBJ_Category=TC_HASHTABLE LoadMultiboardHandleBJ=0,0,multiboard,integer,integer,hashtable _LoadMultiboardHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadMultiboardHandleBJ_Category=TC_HASHTABLE LoadMultiboardItemHandleBJ=0,0,multiboarditem,integer,integer,hashtable _LoadMultiboardItemHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadMultiboardItemHandleBJ_Category=TC_HASHTABLE LoadTrackableHandleBJ=0,0,trackable,integer,integer,hashtable _LoadTrackableHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTrackableHandleBJ_Category=TC_HASHTABLE LoadDialogHandleBJ=0,0,dialog,integer,integer,hashtable _LoadDialogHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadDialogHandleBJ_Category=TC_HASHTABLE LoadButtonHandleBJ=0,0,button,integer,integer,hashtable _LoadButtonHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadButtonHandleBJ_Category=TC_HASHTABLE //LoadVersionHandleBJ=0,0,version,integer,integer,hashtable //_LoadVersionHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ //_LoadVersionHandleBJ_Category=TC_HASHTABLE //LoadItemTypeHandleBJ=0,0,itemtype,integer,integer,hashtable //_LoadItemTypeHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ //_LoadItemTypeHandleBJ_Category=TC_HASHTABLE LoadTextTagHandleBJ=0,0,texttag,integer,integer,hashtable _LoadTextTagHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadTextTagHandleBJ_Category=TC_HASHTABLE LoadLightningHandleBJ=0,0,lightning,integer,integer,hashtable _LoadLightningHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadLightningHandleBJ_Category=TC_HASHTABLE LoadImageHandleBJ=0,0,image,integer,integer,hashtable _LoadImageHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadImageHandleBJ_Category=TC_HASHTABLE LoadUbersplatHandleBJ=0,0,ubersplat,integer,integer,hashtable _LoadUbersplatHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadUbersplatHandleBJ_Category=TC_HASHTABLE LoadFogStateHandleBJ=0,0,fogstate,integer,integer,hashtable _LoadFogStateHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadFogStateHandleBJ_Category=TC_HASHTABLE LoadFogModifierHandleBJ=0,0,fogmodifier,integer,integer,hashtable _LoadFogModifierHandleBJ_Defaults=_,_,GetLastCreatedHashtableBJ _LoadFogModifierHandleBJ_Category=TC_HASHTABLE HaveStoredValue=1,0,boolean,string,cachevaluetype,string,gamecache _HaveStoredValue_Defaults=_,CacheValueTypeUnit,"Category",GetLastCreatedGameCacheBJ _HaveStoredValue_Category=TC_GAMECACHE HaveSavedValue=1,0,boolean,integer,hashtablevaluetype,integer,hashtable _HaveSavedValue_Defaults=_,HashtableValueTypeHandle,_,GetLastCreatedHashtableBJ _HaveSavedValue_Category=TC_HASHTABLE UnitHasItem=0,1,boolean,unit,item _UnitHasItem_Defaults=GetTriggerUnit,GetLastCreatedItem _UnitHasItem_Category=TC_HERO UnitHasItemOfTypeBJ=0,1,boolean,unit,itemcode _UnitHasItemOfTypeBJ_Defaults=GetTriggerUnit,texp _UnitHasItemOfTypeBJ_Category=TC_HERO IsSuspendedXP=0,0,boolean,unit _IsSuspendedXP_Defaults=GetTriggerUnit _IsSuspendedXP_Category=TC_HERO CheckItemStatus=1,0,boolean,item,itemstatus _CheckItemStatus_Defaults=GetLastCreatedItem,ItemStatusHidden _CheckItemStatus_Category=TC_ITEM CheckItemcodeStatus=1,0,boolean,itemcode,itemcodestatus _CheckItemcodeStatus_Defaults=GetItemTypeId,ItemcodeStatusPowerup _CheckItemcodeStatus_Category=TC_ITEM IsItemHiddenBJ=1,0,boolean,item _IsItemHiddenBJ_Defaults=GetLastCreatedItem _IsItemHiddenBJ_Category=TC_ITEM IsItemOwned=1,0,boolean,item _IsItemOwned_Defaults=GetLastCreatedItem _IsItemOwned_Category=TC_ITEM RectContainsItem=1,1,boolean,item,rect _RectContainsItem_Defaults=GetLastCreatedItem,GetRectCenter _RectContainsItem_Category=TC_ITEM IsItemInvulnerable=0,0,boolean,item _IsItemInvulnerable_Defaults=GetLastCreatedItem _IsItemInvulnerable_Category=TC_ITEM LeaderboardHasPlayerItemBJ=0,0,boolean,leaderboard,player _LeaderboardHasPlayerItemBJ_Defaults=GetLastCreatedLeaderboard,Player00 _LeaderboardHasPlayerItemBJ_Category=TC_LEADERBOARD IsMultiboardDisplayed=1,0,boolean,multiboard _IsMultiboardDisplayed_Defaults=GetLastCreatedMultiboard _IsMultiboardDisplayed_Category=TC_MULTIBOARD IsMultiboardMinimized=1,0,boolean,multiboard _IsMultiboardMinimized_Defaults=GetLastCreatedMultiboard _IsMultiboardMinimized_Category=TC_MULTIBOARD WaygateIsActiveBJ=0,0,boolean,unit _WaygateIsActiveBJ_Defaults=_ _WaygateIsActiveBJ_Category=TC_NEUTRALBUILDING IsPlayerFlagSetBJ=0,0,boolean,playerflag,player _IsPlayerFlagSetBJ_Defaults=PlayerFlagGivesBounty,PlayerNA _IsPlayerFlagSetBJ_Category=TC_PLAYER IsPlayerAlly=0,1,boolean,player,player _IsPlayerAlly_Defaults=GetTriggerPlayer,Player00 _IsPlayerAlly_Category=TC_PLAYER IsPlayerEnemy=0,1,boolean,player,player _IsPlayerEnemy_Defaults=GetTriggerPlayer,Player00 _IsPlayerEnemy_Category=TC_PLAYER GetPlayerAlliance=0,1,boolean,player,player,alliancetype _GetPlayerAlliance_Defaults=GetTriggerPlayer,Player00,AllianceTypePassive _GetPlayerAlliance_Category=TC_PLAYER IsPlayerInForce=0,1,boolean,player,force _IsPlayerInForce_Defaults=Player00,GetPlayersAll _IsPlayerInForce_Category=TC_PLAYER IsQuestItemCompleted=0,0,boolean,questitem _IsQuestItemCompleted_Defaults=GetLastCreatedQuestItemBJ _IsQuestItemCompleted_Category=TC_QUEST IsQuestEnabled=0,0,boolean,quest _IsQuestEnabled_Defaults=GetLastCreatedQuestBJ _IsQuestEnabled_Category=TC_QUEST IsQuestCompleted=0,0,boolean,quest _IsQuestCompleted_Defaults=GetLastCreatedQuestBJ _IsQuestCompleted_Category=TC_QUEST IsQuestFailed=0,0,boolean,quest _IsQuestFailed_Defaults=GetLastCreatedQuestBJ _IsQuestFailed_Category=TC_QUEST IsQuestDiscovered=0,0,boolean,quest _IsQuestDiscovered_Defaults=GetLastCreatedQuestBJ _IsQuestDiscovered_Category=TC_QUEST IsQuestRequired=0,0,boolean,quest _IsQuestRequired_Defaults=GetLastCreatedQuestBJ _IsQuestRequired_Category=TC_QUEST RectContainsLoc=0,1,boolean,rect,location _RectContainsLoc_Defaults=GetPlayableMapRect,GetRectCenter _RectContainsLoc_Category=TC_REGION IsTriggerEnabled=0,1,boolean,trigger _IsTriggerEnabled_Defaults=GetTriggeringTrigger _IsTriggerEnabled_Category=TC_TRIGGER TriggerEvaluate=0,1,boolean,trigger _TriggerEvaluate_Defaults=_ _TriggerEvaluate_Category=TC_TRIGGER IsTriggerQueuedBJ=0,0,boolean,trigger _IsTriggerQueuedBJ_Defaults=_ _IsTriggerQueuedBJ_Category=TC_TRIGGER IsTriggerQueueEmptyBJ=0,0,boolean _IsTriggerQueueEmptyBJ_Defaults= _IsTriggerQueueEmptyBJ_Category=TC_TRIGGER IsUnitType=0,1,boolean,unit,unittype _IsUnitType_Defaults=GetTriggerUnit,UnitTypeStructure _IsUnitType_Category=TC_UNIT IsUnitIdType=1,1,boolean,unitcode,unittype _IsUnitIdType_Defaults=GetUnitTypeId,UnitTypeStructure _IsUnitIdType_Category=TC_UNIT IsUnitInGroup=0,1,boolean,unit,group _IsUnitInGroup_Defaults=GetTriggerUnit,GetUnitsInRectAll _IsUnitInGroup_Category=TC_UNIT RectContainsUnit=0,1,boolean,rect,unit _RectContainsUnit_Defaults=GetPlayableMapRect,GetTriggerUnit _RectContainsUnit_Category=TC_UNIT IsUnitAliveBJ=0,0,boolean,unit _IsUnitAliveBJ_Defaults=GetTriggerUnit _IsUnitAliveBJ_Category=TC_UNIT IsUnitDeadBJ=0,0,boolean,unit _IsUnitDeadBJ_Defaults=GetTriggerUnit _IsUnitDeadBJ_Category=TC_UNIT IsUnitPausedBJ=0,0,boolean,unit _IsUnitPausedBJ_Defaults=GetTriggerUnit _IsUnitPausedBJ_Category=TC_UNIT IsUnitHiddenBJ=0,0,boolean,unit _IsUnitHiddenBJ_Defaults=GetTriggerUnit _IsUnitHiddenBJ_Category=TC_UNIT IsUnitIllusionBJ=0,0,boolean,unit _IsUnitIllusionBJ_Defaults=GetTriggerUnit _IsUnitIllusionBJ_Category=TC_UNIT UnitCanSleepPerm=0,0,boolean,unit _UnitCanSleepPerm_Defaults=GetTriggerUnit _UnitCanSleepPerm_Category=TC_UNIT UnitCanSleepBJ=0,0,boolean,unit _UnitCanSleepBJ_Defaults=GetTriggerUnit _UnitCanSleepBJ_Category=TC_UNIT UnitIsSleepingBJ=0,0,boolean,unit _UnitIsSleepingBJ_Defaults=GetTriggerUnit _UnitIsSleepingBJ_Category=TC_UNIT DoesUnitGenerateAlarms=1,0,boolean,unit _DoesUnitGenerateAlarms_Defaults=GetTriggerUnit _DoesUnitGenerateAlarms_Category=TC_UNIT IsUnitLoadedBJ=0,0,boolean,unit _IsUnitLoadedBJ_Defaults=GetTriggerUnit _IsUnitLoadedBJ_Category=TC_UNIT IsUnitInTransportBJ=0,0,boolean,unit,unit _IsUnitInTransportBJ_Defaults=GetTriggerUnit,_ _IsUnitInTransportBJ_Category=TC_UNIT IsUnitSelected=0,1,boolean,unit,player _IsUnitSelected_Defaults=GetTriggerUnit,Player00 _IsUnitSelected_Category=TC_UNIT IsUnitAlly=0,1,boolean,unit,player _IsUnitAlly_Defaults=GetTriggerUnit,Player00 _IsUnitAlly_Category=TC_UNIT IsUnitEnemy=0,1,boolean,unit,player _IsUnitEnemy_Defaults=GetTriggerUnit,Player00 _IsUnitEnemy_Category=TC_UNIT UnitHasBuffBJ=1,1,boolean,unit,buffcode _UnitHasBuffBJ_Defaults=GetTriggerUnit,_ _UnitHasBuffBJ_Category=TC_UNIT IsUnitGroupEmptyBJ=0,1,boolean,group _IsUnitGroupEmptyBJ_Defaults=_ _IsUnitGroupEmptyBJ_Category=TC_UNITGROUP IsUnitGroupInRectBJ=0,1,boolean,group,rect _IsUnitGroupInRectBJ_Defaults=_ _IsUnitGroupInRectBJ_Category=TC_UNITGROUP IsUnitGroupDeadBJ=0,1,boolean,group _IsUnitGroupDeadBJ_Defaults=_ _IsUnitGroupDeadBJ_Category=TC_UNITGROUP IsFogEnabled=0,1,boolean _IsFogEnabled_Defaults= _IsFogEnabled_Category=TC_VISIBILITY IsFogMaskEnabled=0,1,boolean _IsFogMaskEnabled_Defaults= _IsFogMaskEnabled_Category=TC_VISIBILITY IsUnitVisible=0,1,boolean,unit,player _IsUnitVisible_Defaults=GetTriggerUnit,Player00 _IsUnitVisible_Category=TC_VISIBILITY IsUnitInvisible=0,1,boolean,unit,player _IsUnitInvisible_Defaults=GetTriggerUnit,Player00 _IsUnitInvisible_Category=TC_VISIBILITY IsUnitFogged=0,1,boolean,unit,player _IsUnitFogged_Defaults=GetTriggerUnit,Player00 _IsUnitFogged_Category=TC_VISIBILITY IsUnitMasked=0,1,boolean,unit,player _IsUnitMasked_Defaults=GetTriggerUnit,Player00 _IsUnitMasked_Category=TC_VISIBILITY IsLocationVisibleToPlayer=0,1,boolean,location,player _IsLocationVisibleToPlayer_Defaults=GetRectCenter,Player00 _IsLocationVisibleToPlayer_Category=TC_VISIBILITY IsLocationFoggedToPlayer=0,1,boolean,location,player _IsLocationFoggedToPlayer_Defaults=GetRectCenter,Player00 _IsLocationFoggedToPlayer_Category=TC_VISIBILITY IsLocationMaskedToPlayer=0,1,boolean,location,player _IsLocationMaskedToPlayer_Defaults=GetRectCenter,Player00 _IsLocationMaskedToPlayer_Category=TC_VISIBILITY // returns integer OperatorInt=0,1,integer,integer,ArithmeticOperator,integer _OperatorInt_Defaults=_,OperatorAdd,1 _OperatorInt_Category=TC_ARITHMETIC _OperatorInt_UseWithAI=1 GetForLoopIndexA=0,0,integer _GetForLoopIndexA_Defaults= _GetForLoopIndexA_Category=TC_FORLOOP GetForLoopIndexB=0,0,integer _GetForLoopIndexB_Defaults= _GetForLoopIndexB_Category=TC_FORLOOP StringLength=1,1,integer,string _StringLength_Defaults=GetEventPlayerChatString _StringLength_Category=TC_NOTHING R2I=0,1,integer,real _R2I_Defaults=GetUnitStateSwap _R2I_Category=TC_CONVERSION S2I=0,1,integer,string _S2I_Defaults=GetEventPlayerChatString _S2I_Category=TC_CONVERSION GetElevatorHeight=1,1,integer,destructable _GetElevatorHeight_Defaults=_ _GetElevatorHeight_Category=TC_DESTRUCT GetTerrainCliffLevelBJ=1,1,integer,location _GetTerrainCliffLevelBJ_Defaults=GetRectCenter _GetTerrainCliffLevelBJ_Category=TC_ENVIRONMENT GetTerrainVarianceBJ=1,1,integer,location _GetTerrainVarianceBJ_Defaults=GetRectCenter _GetTerrainVarianceBJ_Category=TC_ENVIRONMENT GetLearnedSkillLevel=0,0,integer _GetLearnedSkillLevel_Defaults= _GetLearnedSkillLevel_Category=TC_EVENTRESPONSE GetPlayers=0,1,integer _GetPlayers_Defaults= _GetPlayers_Category=TC_GAME GetTeams=0,1,integer _GetTeams_Defaults= _GetTeams_Category=TC_GAME GetAllyColorFilterState=1,1,integer _GetAllyColorFilterState_Defaults= _GetAllyColorFilterState_Category=TC_GAME GetTournamentFinishNowRule=1,0,integer _GetTournamentFinishNowRule_Defaults= _GetTournamentFinishNowRule_Category=TC_GAME GetTournamentScore=1,0,integer,player _GetTournamentScore_Defaults=Player00 _GetTournamentScore_Category=TC_GAME GetAbilityPosX=1,1,integer,abilcode _GetAbilityPosX_Defaults=_ _GetAbilityPosX_Category=TC_GAME GetAbilityOnPosX=1,1,integer,abilcode _GetAbilityOnPosX_Defaults=_ _GetAbilityOnPosX_Category=TC_GAME GetAbilityPosY=1,1,integer,abilcode _GetAbilityPosY_Defaults=_ _GetAbilityPosY_Category=TC_GAME GetAbilityOnPosY=1,1,integer,abilcode _GetAbilityOnPosY_Defaults=_ _GetAbilityOnPosY_Category=TC_GAME GetStoredIntegerBJ=0,0,integer,string,string,gamecache _GetStoredIntegerBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredIntegerBJ_Category=TC_GAMECACHE GetHeroLevel=0,1,integer,unit _GetHeroLevel_Defaults=GetTriggerUnit _GetHeroLevel_Category=TC_HERO GetHeroXP=0,1,integer,unit _GetHeroXP_Defaults=GetTriggerUnit _GetHeroXP_Category=TC_HERO GetHeroStatBJ=1,1,integer,herostat,unit,includeoption _GetHeroStatBJ_Defaults=HeroStatStr,_,InclusionExclude _GetHeroStatBJ_Category=TC_HERO GetHeroSkillPoints=1,1,integer,unit _GetHeroSkillPoints_Defaults=_ _GetHeroSkillPoints_Category=TC_HERO GetItemLevel=1,1,integer,item _GetItemLevel_Defaults=GetLastCreatedItem _GetItemLevel_Category=TC_ITEM GetItemCharges=1,1,integer,item _GetItemCharges_Defaults=GetLastCreatedItem _GetItemCharges_Category=TC_ITEM GetItemUserData=1,1,integer,item _GetItemUserData_Defaults=_ _GetItemUserData_Category=TC_ITEM LeaderboardGetPlayerIndexBJ=0,0,integer,player,leaderboard _LeaderboardGetPlayerIndexBJ_Defaults=Player00,GetLastCreatedLeaderboard _LeaderboardGetPlayerIndexBJ_Category=TC_LEADERBOARD GetRandomInt=0,1,integer,integer,integer _GetRandomInt_Defaults=1,10 _GetRandomInt_Category=TC_MATH IMinBJ=0,1,integer,integer,integer _IMinBJ_Defaults=_,_ _IMinBJ_Category=TC_MATH IMaxBJ=0,1,integer,integer,integer _IMaxBJ_Defaults=_,_ _IMaxBJ_Category=TC_MATH IAbsBJ=0,1,integer,integer _IAbsBJ_Defaults=_ _IAbsBJ_Category=TC_MATH ISignBJ=0,1,integer,integer _ISignBJ_Defaults=_ _ISignBJ_Category=TC_MATH ModuloInteger=0,1,integer,integer,integer _ModuloInteger_Defaults=_,_ _ModuloInteger_Category=TC_MATH MultiboardGetRowCount=1,1,integer,multiboard _MultiboardGetRowCount_Defaults=GetLastCreatedMultiboard _MultiboardGetRowCount_Category=TC_MULTIBOARD MultiboardGetColumnCount=1,1,integer,multiboard _MultiboardGetColumnCount_Defaults=GetLastCreatedMultiboard _MultiboardGetColumnCount_Category=TC_MULTIBOARD GetResourceAmount=0,1,integer,unit _GetResourceAmount_Defaults=_ _GetResourceAmount_Category=TC_NEUTRALBUILDING GetPlayerState=0,1,integer,player,playerstate _GetPlayerState_Defaults=Player00,PlayerStateGold _GetPlayerState_Category=TC_PLAYER GetPlayerTaxRateBJ=1,1,integer,playerresource,player,player _GetPlayerTaxRateBJ_Defaults=PlayerResourceGold,Player00,Player01 _GetPlayerTaxRateBJ_Category=TC_PLAYER GetPlayerScore=1,1,integer,player,playerscore _GetPlayerScore_Defaults=Player00,PlayerScoreTotal _GetPlayerScore_Category=TC_PLAYER GetConvertedPlayerId=0,1,integer,player _GetConvertedPlayerId_Defaults=GetTriggerPlayer _GetConvertedPlayerId_Category=TC_PLAYER GetPlayerStructureCount=0,1,integer,player,includeoption _GetPlayerStructureCount_Defaults=Player00,InclusionExclude _GetPlayerStructureCount_Category=TC_PLAYER GetPlayerUnitCount=0,1,integer,player,includeoption _GetPlayerUnitCount_Defaults=Player00,InclusionExclude _GetPlayerUnitCount_Category=TC_PLAYER GetPlayerTechCountSimple=0,1,integer,techcode,player _GetPlayerTechCountSimple_Defaults=_,Player00 _GetPlayerTechCountSimple_Category=TC_PLAYER GetPlayerTechMaxAllowedSwap=0,1,integer,techcode,player _GetPlayerTechMaxAllowedSwap_Defaults=_,Player00 _GetPlayerTechMaxAllowedSwap_Category=TC_PLAYER GetPlayerTeam=0,1,integer,player _GetPlayerTeam_Defaults=Player00 _GetPlayerTeam_Category=TC_PLAYER CountPlayersInForceBJ=0,1,integer,force _CountPlayersInForceBJ_Defaults=GetPlayersByMapControl _CountPlayersInForceBJ_Category=TC_PLAYER GetTriggerPlayerMouseButton=1,1,mousebuttontype _GetTriggerPlayerMouseButton_Defaults= _GetTriggerPlayerMouseButton_Category=TC_PLAYER CountUnitsInGroup=0,1,integer,group _CountUnitsInGroup_Defaults=GetUnitsInRectAll _CountUnitsInGroup_Category=TC_UNIT CountLivingPlayerUnitsOfTypeId=1,1,integer,unitcode,player _CountLivingPlayerUnitsOfTypeId_Defaults=hfoo,Player00 _CountLivingPlayerUnitsOfTypeId_Category=TC_UNIT GetUnitFoodUsed=0,1,integer,unit _GetUnitFoodUsed_Defaults=GetTriggerUnit _GetUnitFoodUsed_Category=TC_UNIT GetUnitFoodMade=0,1,integer,unit _GetUnitFoodMade_Defaults=GetTriggerUnit _GetUnitFoodMade_Category=TC_UNIT GetFoodUsed=1,1,integer,unitcode _GetFoodUsed_Defaults=hfoo _GetFoodUsed_Category=TC_UNIT GetFoodMade=0,1,integer,unitcode _GetFoodMade_Defaults=hfoo _GetFoodMade_Category=TC_UNIT GetUnitPointValue=0,1,integer,unit _GetUnitPointValue_Defaults=GetTriggerUnit _GetUnitPointValue_Category=TC_UNIT GetUnitPointValueByType=0,1,integer,unitcode _GetUnitPointValueByType_Defaults=hfoo _GetUnitPointValueByType_Category=TC_UNIT GetUnitUserData=1,1,integer,unit _GetUnitUserData_Defaults=_ _GetUnitUserData_Category=TC_UNIT GetUnitLevel=1,1,integer,unit _GetUnitLevel_Defaults=GetTriggerUnit _GetUnitLevel_Category=TC_UNIT GetUnitAbilityLevelSwapped=1,1,integer,abilcode,unit _GetUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit _GetUnitAbilityLevelSwapped_Category=TC_UNIT UnitInventoryCount=1,1,integer,unit _UnitInventoryCount_Defaults=GetTriggerUnit _UnitInventoryCount_Category=TC_UNIT UnitInventorySizeBJ=1,1,integer,unit _UnitInventorySizeBJ_Defaults=GetTriggerUnit _UnitInventorySizeBJ_Category=TC_UNIT UnitCountBuffsExBJ=1,1,integer,buffpolarity,buffresist,unit,includeoption,includeoption _UnitCountBuffsExBJ_Defaults=BuffPolarityEither,BuffResistEither,GetTriggerUnit,InclusionInclude,InclusionInclude _UnitCountBuffsExBJ_Category=TC_UNIT GetUnitMaxHP=0,1,integer,unit _GetUnitMaxHP_Defaults=GetTriggerUnit _GetUnitMaxHP_Category=TC_UNIT GetUnitMaxMana=0,1,integer,unit _GetUnitMaxMana_Defaults=GetTriggerUnit _GetUnitMaxMana_Category=TC_UNIT GetUnitBaseDamage=0,1,integer,unit,integer _GetUnitBaseDamage_Defaults=GetTriggerUnit,1 _GetUnitBaseDamage_Category=TC_UNIT GetUnitDiceNumber=0,1,integer,unit,integer _GetUnitDiceNumber_Defaults=GetTriggerUnit,1 _GetUnitDiceNumber_Category=TC_UNIT GetUnitDiceSides=0,1,integer,unit,integer _GetUnitDiceSides_Defaults=GetTriggerUnit,1 _GetUnitDiceSides_Category=TC_UNIT GetTriggerEvalCount=0,1,integer,trigger _GetTriggerEvalCount_Defaults=GetTriggeringTrigger _GetTriggerEvalCount_Category=TC_TRIGGER GetTriggerExecCount=0,1,integer,trigger _GetTriggerExecCount_Defaults=GetTriggeringTrigger _GetTriggerExecCount_Category=TC_TRIGGER QueuedTriggerCountBJ=0,0,integer _QueuedTriggerCountBJ_Defaults= _QueuedTriggerCountBJ_Category=TC_TRIGGER GetAbilityManaCost=0,1,integer,abilcode,integer _GetAbilityManaCost_Defaults=_,1 _GetAbilityManaCost_Limits=_,_,1,_ _GetAbilityManaCost_Category=TC_GAME GetUnitAbilityManaCost=0,1,integer,unit,abilcode,integer _GetUnitAbilityManaCost_Defaults=GetTriggerUnit,_,1 _GetUnitAbilityManaCost_Limits-_,_,_,_,1,_ _GetUnitAbilityManaCost_Category=TC_UNIT // returns real OperatorReal=0,1,real,real,ArithmeticOperator,real _OperatorReal_Defaults=1,OperatorAdd,1 _OperatorReal_Category=TC_ARITHMETIC GetLocationX=0,1,real,location _GetLocationX_Defaults=GetRectCenter _GetLocationX_Category=TC_NOTHING GetLocationY=0,1,real,location _GetLocationY_Defaults=GetRectCenter _GetLocationY_Category=TC_NOTHING CameraSetupGetFieldSwap=0,1,real,camerafield,camerasetup _CameraSetupGetFieldSwap_Defaults=CameraFieldTargetDistance,_ _CameraSetupGetFieldSwap_Category=TC_CAMERA GetCameraField=0,1,real,camerafield _GetCameraField_Defaults=CameraFieldTargetDistance _GetCameraField_Category=TC_CAMERA GetCameraTargetPositionX=0,1,real _GetCameraTargetPositionX_Defaults= _GetCameraTargetPositionX_Category=TC_CAMERA GetCameraTargetPositionY=0,1,real _GetCameraTargetPositionY_Defaults= _GetCameraTargetPositionY_Category=TC_CAMERA GetCameraTargetPositionZ=0,1,real _GetCameraTargetPositionZ_Defaults= _GetCameraTargetPositionZ_Category=TC_CAMERA GetCameraEyePositionX=0,1,real _GetCameraEyePositionX_Defaults= _GetCameraEyePositionX_Category=TC_CAMERA GetCameraEyePositionY=0,1,real _GetCameraEyePositionY_Defaults= _GetCameraEyePositionY_Category=TC_CAMERA GetCameraEyePositionZ=0,1,real _GetCameraEyePositionZ_Defaults= _GetCameraEyePositionZ_Category=TC_CAMERA GetLastTransmissionDurationBJ=0,1,real _GetLastTransmissionDurationBJ_Defaults= _GetLastTransmissionDurationBJ_Category=TC_CINEMATIC I2R=0,1,real,integer _I2R_Defaults=GetUnitPointValueByType _I2R_Category=TC_CONVERSION S2R=0,1,real,string _S2R_Defaults=GetEventPlayerChatString _S2R_Category=TC_CONVERSION Deg2Rad=0,1,real,real _Deg2Rad_Defaults=0 _Deg2Rad_Category=TC_CONVERSION Rad2Deg=0,1,real,real _Rad2Deg_Defaults=0 _Rad2Deg_Category=TC_CONVERSION TimerGetElapsed=0,1,real,timer _TimerGetElapsed_Defaults=_ _TimerGetElapsed_Category=TC_TIMER TimerGetRemaining=0,1,real,timer _TimerGetRemaining_Defaults=_ _TimerGetRemaining_Category=TC_TIMER TimerGetTimeout=0,1,real,timer _TimerGetTimeout_Defaults=_ _TimerGetTimeout_Category=TC_TIMER GetDestructableLife=0,1,real,destructable _GetDestructableLife_Defaults=GetLastCreatedDestructable _GetDestructableLife_Category=TC_DESTRUCT GetDestructableMaxLife=0,1,real,destructable _GetDestructableMaxLife_Defaults=GetLastCreatedDestructable _GetDestructableMaxLife_Category=TC_DESTRUCT GetDestructableOccluderHeight=1,1,real,destructable _GetDestructableOccluderHeight_Defaults=GetLastCreatedDestructable _GetDestructableOccluderHeight_Category=TC_DESTRUCT GetEventDamage=0,0,real _GetEventDamage_Defaults= _GetEventDamage_Category=TC_EVENTRESPONSE GetTournamentFinishSoonTimeRemaining=1,0,real _GetTournamentFinishSoonTimeRemaining_Defaults= _GetTournamentFinishSoonTimeRemaining_Category=TC_EVENTRESPONSE GetTimeOfDay=0,1,real _GetTimeOfDay_Defaults= _GetTimeOfDay_Category=TC_GAME GetTimeOfDayScalePercentBJ=0,1,real _GetTimeOfDayScalePercentBJ_Defaults= _GetTimeOfDayScalePercentBJ_Category=TC_GAME GetStoredRealBJ=0,0,real,string,string,gamecache _GetStoredRealBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredRealBJ_Category=TC_GAMECACHE GetItemLifeBJ=0,0,real,item _GetItemLifeBJ_Defaults=GetLastCreatedItem _GetItemLifeBJ_Category=TC_ITEM GetLightningColorRBJ=1,0,real,lightning _GetLightningColorRBJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorRBJ_Category=TC_LIGHTNING GetLightningColorGBJ=1,0,real,lightning _GetLightningColorGBJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorGBJ_Category=TC_LIGHTNING GetLightningColorBBJ=1,0,real,lightning _GetLightningColorBBJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorBBJ_Category=TC_LIGHTNING GetLightningColorABJ=1,0,real,lightning _GetLightningColorABJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorABJ_Category=TC_LIGHTNING GetRandomReal=0,1,real,real,real _GetRandomReal_Defaults=0,1 _GetRandomReal_Category=TC_MATH GetRandomDirectionDeg=0,1,real _GetRandomDirectionDeg_Defaults= _GetRandomDirectionDeg_Category=TC_MATH GetRandomPercentageBJ=0,1,real _GetRandomPercentageBJ_Defaults= _GetRandomPercentageBJ_Category=TC_MATH DistanceBetweenPoints=0,1,real,location,location _DistanceBetweenPoints_Defaults=GetUnitLoc,GetUnitLoc _DistanceBetweenPoints_Category=TC_MATH AngleBetweenPoints=0,1,real,location,location _AngleBetweenPoints_Defaults=GetUnitLoc,GetUnitLoc _AngleBetweenPoints_Category=TC_MATH RMinBJ=0,1,real,real,real _RMinBJ_Defaults=_,_ _RMinBJ_Category=TC_MATH RMaxBJ=0,1,real,real,real _RMaxBJ_Defaults=_,_ _RMaxBJ_Category=TC_MATH RAbsBJ=0,1,real,real _RAbsBJ_Defaults=_ _RAbsBJ_Category=TC_MATH RSignBJ=0,1,real,real _RSignBJ_Defaults=_ _RSignBJ_Category=TC_MATH ModuloReal=0,1,real,real,real _ModuloReal_Defaults=_,_ _ModuloReal_Category=TC_MATH Pow=0,1,real,real,real _Pow_Defaults=_,_ _Pow_Category=TC_MATH SquareRoot=0,1,real,real _SquareRoot_Defaults=_ _SquareRoot_Limits=0,_ _SquareRoot_Category=TC_MATH SinBJ=0,1,real,real _SinBJ_Defaults=GetUnitFacing _SinBJ_Category=TC_MATH CosBJ=0,1,real,real _CosBJ_Defaults=GetUnitFacing _CosBJ_Category=TC_MATH TanBJ=0,1,real,real _TanBJ_Defaults=GetUnitFacing _TanBJ_Category=TC_MATH AsinBJ=0,1,real,real _AsinBJ_Defaults=_ _AsinBJ_Limits=-1,1 _AsinBJ_Category=TC_MATH AcosBJ=0,1,real,real _AcosBJ_Defaults=_ _AcosBJ_Limits=-1,1 _AcosBJ_Category=TC_MATH AtanBJ=0,1,real,real _AtanBJ_Defaults=_ _AtanBJ_Category=TC_MATH Atan2BJ=0,1,real,real,real _Atan2BJ_Defaults=_,_ _Atan2BJ_Category=TC_MATH GetPlayerHandicapXPBJ=0,0,real,player _GetPlayerHandicapXPBJ_Defaults=Player00 _GetPlayerHandicapXPBJ_Category=TC_PLAYER GetPlayerHandicapBJ=0,0,real,player _GetPlayerHandicapBJ_Defaults=Player00 _GetPlayerHandicapBJ_Category=TC_PLAYER GetTriggerPlayerMouseX=1,1,real _GetTriggerPlayerMouseX_Defaults= _GetTriggerPlayerMouseX_Category=TC_PLAYER GetTriggerPlayerMouseY=1,1,real _GetTriggerPlayerMouseY_Defaults= _GetTriggerPlayerMouseY_Category=TC_PLAYER GetTriggerPlayerMousePosition=1,1,location _GetTriggerPlayerMousePosition_Defaults= _GetTriggerPlayerMousePosition_Category=TC_PLAYER GetRectCenterX=0,1,real,rect _GetRectCenterX_Defaults=GetPlayableMapRect _GetRectCenterX_Category=TC_REGION GetRectCenterY=0,1,real,rect _GetRectCenterY_Defaults=GetPlayableMapRect _GetRectCenterY_Category=TC_REGION GetRectMinX=0,1,real,rect _GetRectMinX_Defaults=GetPlayableMapRect _GetRectMinX_Category=TC_REGION GetRectMinY=0,1,real,rect _GetRectMinY_Defaults=GetPlayableMapRect _GetRectMinY_Category=TC_REGION GetRectMaxX=0,1,real,rect _GetRectMaxX_Defaults=GetPlayableMapRect _GetRectMaxX_Category=TC_REGION GetRectMaxY=0,1,real,rect _GetRectMaxY_Defaults=GetPlayableMapRect _GetRectMaxY_Category=TC_REGION GetRectWidthBJ=0,1,real,rect _GetRectWidthBJ_Defaults=_ _GetRectWidthBJ_Category=TC_REGION GetRectHeightBJ=0,1,real,rect _GetRectHeightBJ_Defaults=_ _GetRectHeightBJ_Category=TC_REGION GetSoundDurationBJ=0,1,real,sound _GetSoundDurationBJ_Defaults=GetLastPlayedSound _GetSoundDurationBJ_Category=TC_SOUND GetSoundFileDurationBJ=0,1,real,musicfile _GetSoundFileDurationBJ_Defaults=GetLastPlayedMusic _GetSoundFileDurationBJ_Category=TC_SOUND GetUnitStateSwap=0,1,real,unitstate,unit _GetUnitStateSwap_Defaults=UnitStateLife,GetTriggerUnit _GetUnitStateSwap_Category=TC_UNIT GetUnitLifePercent=1,1,real,unit _GetUnitLifePercent_Defaults=GetTriggerUnit _GetUnitLifePercent_Category=TC_UNIT GetUnitManaPercent=1,1,real,unit _GetUnitManaPercent_Defaults=GetTriggerUnit _GetUnitManaPercent_Category=TC_UNIT GetUnitFacing=0,1,real,unit _GetUnitFacing_Defaults=GetTriggerUnit _GetUnitFacing_Category=TC_UNIT GetUnitMoveSpeed=0,1,real,unit _GetUnitMoveSpeed_Defaults=GetTriggerUnit _GetUnitMoveSpeed_Category=TC_UNIT GetUnitDefaultMoveSpeed=0,1,real,unit _GetUnitDefaultMoveSpeed_Defaults=GetTriggerUnit _GetUnitDefaultMoveSpeed_Category=TC_UNIT GetUnitAcquireRange=0,1,real,unit _GetUnitAcquireRange_Defaults=GetTriggerUnit _GetUnitAcquireRange_Category=TC_UNIT GetUnitDefaultAcquireRange=0,1,real,unit _GetUnitDefaultAcquireRange_Defaults=GetTriggerUnit _GetUnitDefaultAcquireRange_Category=TC_UNIT GetUnitTurnSpeed=0,1,real,unit _GetUnitTurnSpeed_Defaults=GetTriggerUnit _GetUnitTurnSpeed_Category=TC_UNIT GetUnitDefaultTurnSpeed=0,1,real,unit _GetUnitDefaultTurnSpeed_Defaults=GetTriggerUnit _GetUnitDefaultTurnSpeed_Category=TC_UNIT GetUnitPropWindowBJ=0,1,real,unit _GetUnitPropWindowBJ_Defaults=GetTriggerUnit _GetUnitPropWindowBJ_Category=TC_UNIT GetUnitDefaultPropWindowBJ=0,1,real,unit _GetUnitDefaultPropWindowBJ_Defaults=GetTriggerUnit _GetUnitDefaultPropWindowBJ_Category=TC_UNIT GetUnitFlyHeight=0,1,real,unit _GetUnitFlyHeight_Defaults=GetTriggerUnit _GetUnitFlyHeight_Category=TC_UNIT GetUnitDefaultFlyHeight=0,1,real,unit _GetUnitDefaultFlyHeight_Defaults=GetTriggerUnit _GetUnitDefaultFlyHeight_Category=TC_UNIT GetUnitAttackCooldown=0,1,real,unit,integer _GetUnitAttackCooldown_Defaults=GetTriggerUnit,1 _GetUnitAttackCooldown_Category=TC_UNIT GetUnitArmor=0,1,real,unit _GetUnitArmor_Defaults=GetTriggerUnit _GetUnitArmor_Category=TC_UNIT GetAbilityCooldown=0,1,real,abilcode,integer _GetAbilityCooldown_Defaults=_,1 _GetAbilityCooldown_Limits=_,_,1,_ _GetAbilityCooldown_Category=TC_GAME GetUnitAbilityCooldown=0,1,real,unit,abilcode,integer _GetUnitAbilityCooldown_Defaults=GetTriggerUnit,_,1 _GetUnitAbilityCooldown_Limits=_,_,_,_,1,_ _GetUnitAbilityCooldown_Category=TC_UNIT GetUnitAbilityCooldownRemaining=0,1,real,unit,abilcode _GetUnitAbilityCooldownRemaining_Defaults=GetTriggerUnit,_ _GetUnitAbilityCooldownRemaining_Category=TC_UNIT GetUnitCollisionSize=0,1,real,unit _GetUnitCollisionSize=GetTriggerUnit _GetUnitCollisionSize=TC_UNIT GetLocalUnitZ=0,1,real,unit _GetLocalUnitZ_Defaults=GetTriggerUnit _GetLocalUnitZ_Category=TC_UNIT GetLocalSpecialEffectX=0,1,real,effect _GetLocalSpecialEffectX_Defaults=GetLastCreatedEffectBJ _GetLocalSpecialEffectX_Category=TC_SPECIALEFFECT GetLocalSpecialEffectY=0,1,real,effect _GetLocalSpecialEffectY_Defaults=GetLastCreatedEffectBJ _GetLocalSpecialEffectY_Category=TC_SPECIALEFFECT GetLocalSpecialEffectZ=0,1,real,effect _GetLocalSpecialEffectZ_Defaults=GetLastCreatedEffectBJ _GetLocalSpecialEffectZ_Category=TC_SPECIALEFFECT // returns string OperatorString=0,1,string,string,string _OperatorString_Defaults=_,_ _OperatorString_Category=TC_NOTHING SubStringBJ=0,1,string,string,integer,integer _SubStringBJ_Defaults=_,1,5 _SubStringBJ_Category=TC_NOTHING I2S=0,1,string,integer _I2S_Defaults=GetConvertedPlayerId _I2S_Category=TC_CONVERSION R2S=0,1,string,real _R2S_Defaults=GetUnitStateSwap _R2S_Category=TC_CONVERSION R2SW=0,1,string,real,integer,integer _R2SW_Defaults=GetUnitStateSwap,1,2 _R2SW_Limits=_,_,0,_,0,_ _R2SW_Category=TC_CONVERSION OrderId2StringBJ=0,1,string,ordercode _OrderId2StringBJ_Defaults=GetIssuedOrderIdBJ _OrderId2StringBJ_Category=TC_CONVERSION UnitId2StringBJ=0,1,string,unitcode _UnitId2StringBJ_Defaults=GetUnitTypeId _UnitId2StringBJ_Category=TC_CONVERSION StringIdentity=1,0,string,StringExt _StringIdentity_Defaults=_ _StringIdentity_Category=TC_CONVERSION StringCase=1,1,string,StringExt,stringcaseoption _StringCase_Defaults=_,StringCaseLower _StringCase_Category=TC_CONVERSION GetDestructableName=1,1,string,destructable _GetDestructableName_Defaults=GetLastCreatedDestructable _GetDestructableName_Category=TC_DESTRUCT GetEventPlayerChatString=0,0,string _GetEventPlayerChatString_Defaults= _GetEventPlayerChatString_Category=TC_EVENTRESPONSE GetEventPlayerChatStringMatched=0,0,string _GetEventPlayerChatStringMatched_Defaults= _GetEventPlayerChatStringMatched_Category=TC_EVENTRESPONSE GetSaveBasicFilename=1,0,string _GetSaveBasicFilename_Defaults= _GetSaveBasicFilename_Category=TC_EVENTRESPONSE GetAbilityName=1,1,string,abilcode _GetAbilityName_Defaults=_ _GetAbilityName_Category=TC_GAME GetAbilityEffectBJ=1,1,string,abilcode,effecttype,integer _GetAbilityEffectBJ_Defaults=_,EffectTypeEffect,0 _GetAbilityEffectBJ_Category=TC_GAME GetAbilitySoundBJ=1,1,string,abilcode,soundtype _GetAbilitySoundBJ_Defaults=_,SoundTypeEffect _GetAbilitySoundBJ_Category=TC_GAME GetAbilityTooltip=1,1,string,abilcode,integer _GetAbilityTooltip_Defaults=_,1 _GetAbilityTooltip_Limits=_,_,1,_ _GetAbilityTooltip_Category=TC_GAME GetAbilityOnTooltip=1,1,string,abilcode,integer _GetAbilityOnTooltip_Defaults=_,1 _GetAbilityOnTooltip_Limits=_,_,1,_ _GetAbilityOnTooltip_Category=TC_GAME GetAbilityExtendedTooltip=1,1,string,abilcode,integer _GetAbilityExtendedTooltip_Defaults=_,1 _GetAbilityExtendedTooltip_Limits=_,_,1,_ _GetAbilityExtendedTooltip_Category=TC_GAME GetAbilityOnExtendedTooltip=1,1,string,abilcode,integer _GetAbilityOnExtendedTooltip_Defaults=_,1 _GetAbilityOnExtendedTooltip_Limits=_,_,1,_ _GetAbilityOnExtendedTooltip_Category=TC_GAME GetAbilityResearchTooltip=1,1,string,abilcode,integer _GetAbilityResearchTooltip_Defaults=_,1 _GetAbilityResearchTooltip_Limits=_,_,1,_ _GetAbilityResearchTooltip_Category=TC_GAME GetAbilityResearchExtendedTooltip=1,1,string,abilcode,integer _GetAbilityResearchExtendedTooltip_Defaults=_,1 _GetAbilityResearchExtendedTooltip_Limits=_,_,1,_ _GetAbilityResearchExtendedTooltip_Category=TC_GAME GetAbilityIcon=1,1,string,abilcode,integer _GetAbilityIcon_Defaults=_,1 _GetAbilityIcon_Limits=_,_,1,_ _GetAbilityIcon_Category=TC_GAME GetAbilityOnIcon=1,1,string,abilcode,integer _GetAbilityOnIcon_Defaults=_,1 _GetAbilityOnIcon_Limits=_,_,1,_ _GetAbilityOnIcon_Category=TC_GAME GetStoredStringBJ=1,0,string,string,string,gamecache _GetStoredStringBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredStringBJ_Category=TC_GAMECACHE GetHeroProperName=1,1,string,unit _GetHeroProperName_Defaults=GetTriggerUnit _GetHeroProperName_Category=TC_HERO GetItemName=1,1,string,item _GetItemName_Defaults=GetLastCreatedItem _GetItemName_Category=TC_ITEM GetItemDescription=1,1,string,item _GetItemDescription_Defaults=GetLastCreatedItem _GetItemDescription_Category=TC_ITEM GetItemTooltip=1,1,string,item _GetItemTooltip_Defaults=GetLastCreatedItem _GetItemTooltip_Category=TC_ITEM GetItemExtendedTooltip=1,1,string,item _GetItemExtendedTooltip_Defaults=GetLastCreatedItem _GetItemExtendedTooltip_Category=TC_ITEM GetItemIconPath=1,1,string,item _GetItemIconPath_Defaults=GetLastCreatedItem _GetItemIconPath_Category=TC_ITEM MultiboardGetTitleText=1,1,string,multiboard _MultiboardGetTitleText_Defaults=GetLastCreatedMultiboard _MultiboardGetTitleText_Category=TC_MULTIBOARD GetPlayerName=0,1,string,player _GetPlayerName_Defaults=GetTriggerPlayer _GetPlayerName_Category=TC_PLAYER GetTriggerName=1,1,string _GetTriggerName_Defaults= _GetTriggerName_Category=TC_TRIGGER GetUnitName=0,1,string,unit _GetUnitName_Defaults=GetTriggerUnit _GetUnitName_Category=TC_UNIT // returns location GetRectCenter=0,1,location,rect _GetRectCenter_Defaults=GetPlayableMapRect _GetRectCenter_Category=TC_NOTHING GetRandomLocInRect=0,1,location,rect _GetRandomLocInRect_Defaults=GetPlayableMapRect _GetRandomLocInRect_Category=TC_NOTHING OffsetLocation=0,1,location,location,real,real _OffsetLocation_Defaults=GetRectCenter,0,0 _OffsetLocation_Category=TC_NOTHING PolarProjectionBJ=0,1,location,location,real,real _PolarProjectionBJ_Defaults=GetRectCenter,256,0 _PolarProjectionBJ_Category=TC_NOTHING CameraSetupGetDestPositionLoc=0,1,location,camerasetup _CameraSetupGetDestPositionLoc_Defaults=_ _CameraSetupGetDestPositionLoc_Category=TC_CAMERA GetCameraTargetPositionLoc=0,1,location _GetCameraTargetPositionLoc_Defaults= _GetCameraTargetPositionLoc_Category=TC_CAMERA GetCameraEyePositionLoc=0,1,location _GetCameraEyePositionLoc_Defaults= _GetCameraEyePositionLoc_Category=TC_CAMERA Location=0,1,location,real,real _Location_Defaults=0,0 _Location_Category=TC_CONVERSION GetDestructableLoc=0,1,location,destructable _GetDestructableLoc_Defaults=GetLastCreatedDestructable _GetDestructableLoc_Category=TC_DESTRUCT GetOrderPointLoc=0,0,location _GetOrderPointLoc_Defaults= _GetOrderPointLoc_Category=TC_EVENTRESPONSE GetSpellTargetLoc=1,0,location _GetSpellTargetLoc_Defaults= _GetSpellTargetLoc_Category=TC_EVENTRESPONSE GetItemLoc=0,1,location,item _GetItemLoc_Defaults=GetLastCreatedItem _GetItemLoc_Category=TC_ITEM WaygateGetDestinationLocBJ=0,0,location,unit _WaygateGetDestinationLocBJ_Defaults=_ _WaygateGetDestinationLocBJ_Category=TC_NEUTRALBUILDING GetPlayerStartLocationLoc=0,1,location,player _GetPlayerStartLocationLoc_Defaults=Player00 _GetPlayerStartLocationLoc_Category=TC_PLAYER GetUnitLoc=0,1,location,unit _GetUnitLoc_Defaults=GetTriggerUnit _GetUnitLoc_Category=TC_UNIT GetUnitRallyPoint=1,1,location,unit _GetUnitRallyPoint_Defaults=GetTriggerUnit _GetUnitRallyPoint_Category=TC_UNIT // returns rect GetCurrentCameraBoundsMapRectBJ=0,1,rect _GetCurrentCameraBoundsMapRectBJ_Defaults= _GetCurrentCameraBoundsMapRectBJ_Category=TC_NOTHING GetCameraBoundsMapRect=0,1,rect _GetCameraBoundsMapRect_Defaults= _GetCameraBoundsMapRect_Category=TC_NOTHING GetPlayableMapRect=0,1,rect _GetPlayableMapRect_Defaults= _GetPlayableMapRect_Category=TC_NOTHING GetEntireMapRect=0,1,rect _GetEntireMapRect_Defaults= _GetEntireMapRect_Category=TC_NOTHING OffsetRectBJ=0,0,rect,rect,real,real _OffsetRectBJ_Defaults=_,0,0 _OffsetRectBJ_Category=TC_NOTHING RectFromCenterSizeBJ=0,1,rect,location,real,real _RectFromCenterSizeBJ_Defaults=GetUnitLoc,_,_ _RectFromCenterSizeBJ_Category=TC_CONVERSION Rect=0,1,rect,real,real,real,real _Rect_Defaults=0,0,0,0 _Rect_Category=TC_CONVERSION RectFromLoc=0,1,rect,location,location _RectFromLoc_Defaults=Location,Location _RectFromLoc_Category=TC_CONVERSION // returns unit GetLastCreatedUnit=0,0,unit _GetLastCreatedUnit_Defaults= _GetLastCreatedUnit_Category=TC_LAST GetLastRestoredUnitBJ=0,0,unit _GetLastRestoredUnitBJ_Defaults= _GetLastRestoredUnitBJ_Category=TC_LAST GetLastReplacedUnitBJ=0,0,unit _GetLastReplacedUnitBJ_Defaults= _GetLastReplacedUnitBJ_Category=TC_LAST GetLastHauntedGoldMine=0,0,unit _GetLastHauntedGoldMine_Defaults= _GetLastHauntedGoldMine_Category=TC_LAST GetEnumUnit=0,0,unit _GetEnumUnit_Defaults= _GetEnumUnit_Category=TC_NOTHING GetFilterUnit=0,0,unit _GetFilterUnit_Defaults= _GetFilterUnit_Category=TC_NOTHING GroupPickRandomUnit=0,0,unit,group _GroupPickRandomUnit_Defaults=_ _GroupPickRandomUnit_Category=TC_NOTHING GetAttackedUnitBJ=0,0,unit _GetAttackedUnitBJ_Defaults= _GetAttackedUnitBJ_Category=TC_EVENTRESPONSE GetAttacker=0,0,unit _GetAttacker_Defaults= _GetAttacker_Category=TC_EVENTRESPONSE GetBuyingUnit=1,0,unit _GetBuyingUnit_Defaults= _GetBuyingUnit_Category=TC_EVENTRESPONSE GetCancelledStructure=0,0,unit _GetCancelledStructure_Defaults= _GetCancelledStructure_Category=TC_EVENTRESPONSE GetSpellAbilityUnit=1,0,unit _GetSpellAbilityUnit_Defaults= _GetSpellAbilityUnit_Category=TC_EVENTRESPONSE GetConstructingStructure=0,0,unit _GetConstructingStructure_Defaults= _GetConstructingStructure_Category=TC_EVENTRESPONSE GetConstructedStructure=0,0,unit _GetConstructedStructure_Defaults= _GetConstructedStructure_Category=TC_EVENTRESPONSE GetEventDamageSource=1,0,unit _GetEventDamageSource_Defaults= _GetEventDamageSource_Category=TC_EVENTRESPONSE GetDecayingUnit=0,0,unit _GetDecayingUnit_Defaults= _GetDecayingUnit_Category=TC_EVENTRESPONSE GetDyingUnit=0,0,unit _GetDyingUnit_Defaults= _GetDyingUnit_Category=TC_EVENTRESPONSE GetEnteringUnit=0,0,unit _GetEnteringUnit_Defaults= _GetEnteringUnit_Category=TC_EVENTRESPONSE GetManipulatingUnit=0,0,unit _GetManipulatingUnit_Defaults= _GetManipulatingUnit_Category=TC_EVENTRESPONSE GetKillingUnitBJ=0,0,unit _GetKillingUnitBJ_Defaults= _GetKillingUnitBJ_Category=TC_EVENTRESPONSE GetLearningUnit=0,0,unit _GetLearningUnit_Defaults= _GetLearningUnit_Category=TC_EVENTRESPONSE GetLeavingUnit=0,0,unit _GetLeavingUnit_Defaults= _GetLeavingUnit_Category=TC_EVENTRESPONSE GetLevelingUnit=0,0,unit _GetLevelingUnit_Defaults= _GetLevelingUnit_Category=TC_EVENTRESPONSE GetLoadedUnitBJ=0,0,unit _GetLoadedUnitBJ_Defaults= _GetLoadedUnitBJ_Category=TC_EVENTRESPONSE GetOrderedUnit=0,0,unit _GetOrderedUnit_Defaults= _GetOrderedUnit_Category=TC_EVENTRESPONSE GetChangingUnit=1,0,unit _GetChangingUnit_Defaults= _GetChangingUnit_Category=TC_EVENTRESPONSE GetResearchingUnit=0,0,unit _GetResearchingUnit_Defaults= _GetResearchingUnit_Category=TC_EVENTRESPONSE GetRevivableUnit=0,0,unit _GetRevivableUnit_Defaults= _GetRevivableUnit_Category=TC_EVENTRESPONSE GetRevivingUnit=0,0,unit _GetRevivingUnit_Defaults= _GetRevivingUnit_Category=TC_EVENTRESPONSE GetSellingUnit=1,0,unit _GetSellingUnit_Defaults= _GetSellingUnit_Category=TC_EVENTRESPONSE GetSoldUnit=1,0,unit _GetSoldUnit_Defaults= _GetSoldUnit_Category=TC_EVENTRESPONSE GetSummonedUnit=0,0,unit _GetSummonedUnit_Defaults= _GetSummonedUnit_Category=TC_EVENTRESPONSE GetSummoningUnit=0,0,unit _GetSummoningUnit_Defaults= _GetSummoningUnit_Category=TC_EVENTRESPONSE GetOrderTargetUnit=0,0,unit _GetOrderTargetUnit_Defaults= _GetOrderTargetUnit_Category=TC_EVENTRESPONSE GetSpellTargetUnit=1,0,unit _GetSpellTargetUnit_Defaults= _GetSpellTargetUnit_Category=TC_EVENTRESPONSE GetEventTargetUnit=0,0,unit _GetEventTargetUnit_Defaults= _GetEventTargetUnit_Category=TC_EVENTRESPONSE GetTrainedUnit=0,0,unit _GetTrainedUnit_Defaults= _GetTrainedUnit_Category=TC_EVENTRESPONSE GetTransportUnitBJ=0,0,unit _GetTransportUnitBJ_Defaults= _GetTransportUnitBJ_Category=TC_EVENTRESPONSE GetTriggerUnit=0,0,unit _GetTriggerUnit_Defaults= _GetTriggerUnit_Category=TC_EVENTRESPONSE GetUnitRallyUnit=1,0,unit,unit _GetUnitRallyUnit_Defaults=GetTriggerUnit _GetUnitRallyUnit_Category=TC_UNIT // returns unitcode GetUnitTypeId=0,1,unitcode,unit _GetUnitTypeId_Defaults=GetTriggerUnit _GetUnitTypeId_Category=TC_NOTHING ChooseRandomCreepBJ=0,1,unitcode,integer _ChooseRandomCreepBJ_Defaults=1 _ChooseRandomCreepBJ_Limits=-1,10 _ChooseRandomCreepBJ_Category=TC_NOTHING ChooseRandomNPBuildingBJ=0,1,unitcode _ChooseRandomNPBuildingBJ_Defaults= _ChooseRandomNPBuildingBJ_Category=TC_NOTHING String2UnitIdBJ=0,1,unitcode,string _String2UnitIdBJ_Defaults=footman _String2UnitIdBJ_Category=TC_CONVERSION GetTrainedUnitType=0,0,unitcode _GetTrainedUnitType_Defaults= _GetTrainedUnitType_Category=TC_EVENTRESPONSE // returns ordercode String2OrderIdBJ=0,0,ordercode,string _String2OrderIdBJ_Defaults=stop _String2OrderIdBJ_Category=TC_CONVERSION UnitId2OrderIdBJ=0,0,ordercode,unitcode _UnitId2OrderIdBJ_Defaults=hfoo _UnitId2OrderIdBJ_Category=TC_CONVERSION GetIssuedOrderIdBJ=0,0,ordercode _GetIssuedOrderIdBJ_Defaults= _GetIssuedOrderIdBJ_Category=TC_EVENTRESPONSE GetUnitCurrentOrder=1,0,ordercode,unit _GetUnitCurrentOrder_Defaults=GetTriggerUnit _GetUnitCurrentOrder_Category=TC_UNIT // returns destructable GetLastCreatedDestructable=0,0,destructable _GetLastCreatedDestructable_Defaults= _GetLastCreatedDestructable_Category=TC_LAST RandomDestructableInRectSimpleBJ=0,0,destructable,rect _RandomDestructableInRectSimpleBJ_Defaults=_ _RandomDestructableInRectSimpleBJ_Category=TC_NOTHING RandomDestructableInRectBJ=0,0,destructable,rect,boolexpr _RandomDestructableInRectBJ_Defaults=_,_ _RandomDestructableInRectBJ_Category=TC_NOTHING GetEnumDestructable=0,0,destructable _GetEnumDestructable_Defaults= _GetEnumDestructable_Category=TC_NOTHING GetFilterDestructable=0,0,destructable _GetFilterDestructable_Defaults= _GetFilterDestructable_Category=TC_NOTHING GetDyingDestructable=0,0,destructable _GetDyingDestructable_Defaults= _GetDyingDestructable_Category=TC_EVENTRESPONSE GetOrderTargetDestructable=0,0,destructable _GetOrderTargetDestructable_Defaults= _GetOrderTargetDestructable_Category=TC_EVENTRESPONSE GetSpellTargetDestructable=1,0,destructable _GetSpellTargetDestructable_Defaults= _GetSpellTargetDestructable_Category=TC_EVENTRESPONSE GetUnitRallyDestructable=1,0,destructable,unit _GetUnitRallyDestructable_Defaults=GetTriggerUnit _GetUnitRallyDestructable_Category=TC_UNIT // returns destructablecode GetDestructableTypeId=0,1,destructablecode,destructable _GetDestructableTypeId_Defaults=GetLastCreatedDestructable _GetDestructableTypeId_Category=TC_NOTHING // returns item GetLastCreatedItem=0,0,item _GetLastCreatedItem_Defaults= _GetLastCreatedItem_Category=TC_LAST GetLastRemovedItem=0,0,item _GetLastRemovedItem_Defaults= _GetLastRemovedItem_Category=TC_LAST RandomItemInRectSimpleBJ=1,0,item,rect _RandomItemInRectSimpleBJ_Defaults=_ _RandomItemInRectSimpleBJ_Category=TC_NOTHING RandomItemInRectBJ=1,0,item,rect,boolexpr _RandomItemInRectBJ_Defaults=_,_ _RandomItemInRectBJ_Category=TC_NOTHING GetEnumItem=1,0,item _GetEnumItem_Defaults= _GetEnumItem_Category=TC_NOTHING GetFilterItem=1,0,item _GetFilterItem_Defaults= _GetFilterItem_Category=TC_NOTHING UnitItemInSlotBJ=0,0,item,unit,integer _UnitItemInSlotBJ_Defaults=_,1 _UnitItemInSlotBJ_Limits=_,_,1,6 _UnitItemInSlotBJ_Category=TC_NOTHING GetItemOfTypeFromUnitBJ=0,0,item,unit,itemcode _GetItemOfTypeFromUnitBJ_Defaults=_,texp _GetItemOfTypeFromUnitBJ_Category=TC_NOTHING GetManipulatedItem=0,0,item _GetManipulatedItem_Defaults= _GetManipulatedItem_Category=TC_EVENTRESPONSE GetSoldItem=1,0,item _GetSoldItem_Defaults= _GetSoldItem_Category=TC_EVENTRESPONSE GetOrderTargetItem=0,0,item _GetOrderTargetItem_Defaults= _GetOrderTargetItem_Category=TC_EVENTRESPONSE GetSpellTargetItem=1,0,item _GetSpellTargetItem_Defaults= _GetSpellTargetItem_Category=TC_EVENTRESPONSE // returns itemtype GetItemType=1,1,itemtype,item _GetItemType_Defaults=GetLastCreatedItem _GetItemType_Category=TC_NOTHING // returns itemcode GetItemTypeId=0,1,itemcode,item _GetItemTypeId_Defaults=GetLastCreatedItem _GetItemTypeId_Category=TC_NOTHING ChooseRandomItemBJ=0,1,itemcode,integer _ChooseRandomItemBJ_Defaults=1 _ChooseRandomItemBJ_Limits=-1,10 _ChooseRandomItemBJ_Category=TC_NOTHING ChooseRandomItemExBJ=1,1,itemcode,integer,itemtype _ChooseRandomItemExBJ_Defaults=1,ItemTypeAny _ChooseRandomItemExBJ_Limits=-1,8,_,_ _ChooseRandomItemExBJ_Category=TC_NOTHING // returns techcode GetResearched=0,1,techcode _GetResearched_Defaults= _GetResearched_Category=TC_EVENTRESPONSE // returns abilcode GetSpellAbilityId=1,0,abilcode _GetSpellAbilityId_Defaults= _GetSpellAbilityId_Category=TC_EVENTRESPONSE // returns heroskillcode GetLearnedSkillBJ=0,0,heroskillcode _GetLearnedSkillBJ_Defaults= _GetLearnedSkillBJ_Category=TC_EVENTRESPONSE // returns player GetEnumPlayer=0,0,player _GetEnumPlayer_Defaults= _GetEnumPlayer_Category=TC_NOTHING GetFilterPlayer=0,0,player _GetFilterPlayer_Defaults= _GetFilterPlayer_Category=TC_NOTHING GetOwningPlayer=0,1,player,unit _GetOwningPlayer_Defaults=GetTriggerUnit _GetOwningPlayer_Category=TC_NOTHING GetItemPlayer=0,1,player,item _GetItemPlayer_Defaults=GetLastCreatedItem _GetItemPlayer_Category=TC_NOTHING ForcePickRandomPlayer=0,0,player,force _ForcePickRandomPlayer_Defaults=_ _ForcePickRandomPlayer_Category=TC_NOTHING ConvertedPlayer=0,1,player,integer _ConvertedPlayer_Defaults=1 _ConvertedPlayer_Limits=1,28 _ConvertedPlayer_Category=TC_CONVERSION GetChangingUnitPrevOwner=1,0,player _GetChangingUnitPrevOwner_Defaults= _GetChangingUnitPrevOwner_Category=TC_EVENTRESPONSE GetTriggerPlayer=0,0,player _GetTriggerPlayer_Defaults= _GetTriggerPlayer_Category=TC_EVENTRESPONSE LeaderboardGetIndexedPlayerBJ=1,0,player,integer,leaderboard _LeaderboardGetIndexedPlayerBJ_Defaults=1,GetLastCreatedLeaderboard _LeaderboardGetIndexedPlayerBJ_Limits=1,28 _LeaderboardGetIndexedPlayerBJ_Category=TC_LEADERBOARD // returns group GetLastCreatedGroup=0,0,group _GetLastCreatedGroup_Defaults= _GetLastCreatedGroup_Category=TC_LAST GetRandomSubGroup=1,0,group,integer,group _GetRandomSubGroup_Defaults=4,GetUnitsInRectAll _GetRandomSubGroup_Category=TC_NOTHING GetUnitsInRectAll=0,0,group,rect _GetUnitsInRectAll_Defaults=GetPlayableMapRect _GetUnitsInRectAll_Category=TC_NOTHING GetUnitsInRectOfPlayer=0,0,group,rect,player _GetUnitsInRectOfPlayer_Defaults=GetPlayableMapRect,Player00 _GetUnitsInRectOfPlayer_Category=TC_NOTHING GetUnitsInRectMatching=0,0,group,rect,boolexpr _GetUnitsInRectMatching_Defaults=GetPlayableMapRect,_ _GetUnitsInRectMatching_Category=TC_NOTHING GetUnitsInRangeOfLocAll=0,0,group,real,location _GetUnitsInRangeOfLocAll_Defaults=512,GetRectCenter _GetUnitsInRangeOfLocAll_Limits=0,_,_,_ _GetUnitsInRangeOfLocAll_Category=TC_NOTHING GetUnitsInRangeOfLocMatching=0,0,group,real,location,boolexpr _GetUnitsInRangeOfLocMatching_Defaults=512,GetRectCenter,_ _GetUnitsInRangeOfLocMatching_Limits=0,_,_,_,_,_ _GetUnitsInRangeOfLocMatching_Category=TC_NOTHING GetUnitsOfPlayerAll=0,0,group,player _GetUnitsOfPlayerAll_Defaults=Player00 _GetUnitsOfPlayerAll_Category=TC_NOTHING GetUnitsOfPlayerAndTypeId=0,0,group,player,unitcode _GetUnitsOfPlayerAndTypeId_Defaults=Player00,hfoo _GetUnitsOfPlayerAndTypeId_Category=TC_NOTHING GetUnitsOfPlayerMatching=0,0,group,player,boolexpr _GetUnitsOfPlayerMatching_Defaults=Player00,_ _GetUnitsOfPlayerMatching_Category=TC_NOTHING GetUnitsOfTypeIdAll=0,0,group,unitcode _GetUnitsOfTypeIdAll_Defaults=hfoo _GetUnitsOfTypeIdAll_Category=TC_NOTHING GetUnitsSelectedAll=0,0,group,player _GetUnitsSelectedAll_Defaults=Player00 _GetUnitsSelectedAll_Category=TC_NOTHING // returns force GetPlayersAll=0,0,force _GetPlayersAll_Defaults= _GetPlayersAll_Category=TC_NOTHING GetPlayersByMapControl=0,0,force,mapcontrol _GetPlayersByMapControl_Defaults=MapControlComputer _GetPlayersByMapControl_Category=TC_NOTHING GetPlayersMatching=0,0,force,boolexpr _GetPlayersMatching_Defaults=_ _GetPlayersMatching_Category=TC_NOTHING GetPlayersAllies=0,0,force,player _GetPlayersAllies_Defaults=Player00 _GetPlayersAllies_Category=TC_NOTHING GetPlayersEnemies=0,0,force,player _GetPlayersEnemies_Defaults=Player00 _GetPlayersEnemies_Category=TC_NOTHING GetForceOfPlayer=0,0,force,player _GetForceOfPlayer_Defaults=Player00 _GetForceOfPlayer_Category=TC_NOTHING // returns race GetPlayerRace=0,1,race,player _GetPlayerRace_Defaults=Player00 _GetPlayerRace_Category=TC_NOTHING GetUnitRace=0,1,race,unit _GetUnitRace_Defaults=GetTriggerUnit _GetUnitRace_Category=TC_NOTHING // returns camerasetup GetCurrentCameraSetup=0,0,camerasetup _GetCurrentCameraSetup_Defaults= _GetCurrentCameraSetup_Category=TC_NOTHING // returns fogmodifier GetLastCreatedFogModifier=0,0,fogmodifier _GetLastCreatedFogModifier_Defaults= _GetLastCreatedFogModifier_Category=TC_LAST // returns trigger GetTriggeringTrigger=0,0,trigger _GetTriggeringTrigger_Defaults= _GetTriggeringTrigger_Category=TC_NOTHING // returns gamedifficulty GetGameDifficulty=0,1,gamedifficulty _GetGameDifficulty_Defaults= _GetGameDifficulty_Category=TC_NOTHING // returns aidifficulty GetAIDifficulty=1,1,aidifficulty,player _GetAIDifficulty_Defaults=Player00 _GetAIDifficulty_Category=TC_NOTHING // returns gamespeed GetGameSpeed=0,1,gamespeed _GetGameSpeed_Defaults= _GetGameSpeed_Category=TC_NOTHING // returns mapcontrol GetPlayerController=0,1,mapcontrol,player _GetPlayerController_Defaults=Player00 _GetPlayerController_Category=TC_NOTHING // returns playercolor GetPlayerColor=0,1,playercolor,player _GetPlayerColor_Defaults=Player00 _GetPlayerColor_Category=TC_NOTHING // returns playerslotstate GetPlayerSlotState=0,1,playerslotstate,player _GetPlayerSlotState_Defaults=Player00 _GetPlayerSlotState_Category=TC_NOTHING // returns effect GetLastCreatedEffectBJ=0,0,effect _GetLastCreatedEffectBJ_Defaults= _GetLastCreatedEffectBJ_Category=TC_LAST // returns lightning GetLastCreatedLightningBJ=1,0,lightning _GetLastCreatedLightningBJ_Defaults= _GetLastCreatedLightningBJ_Category=TC_LAST // returns image GetLastCreatedImage=1,0,image _GetLastCreatedImage_Defaults= _GetLastCreatedImage_Category=TC_LAST // returns ubersplat GetLastCreatedUbersplat=1,0,ubersplat _GetLastCreatedUbersplat_Defaults= _GetLastCreatedUbersplat_Category=TC_LAST // returns weathereffect GetLastCreatedWeatherEffect=0,0,weathereffect _GetLastCreatedWeatherEffect_Defaults= _GetLastCreatedWeatherEffect_Category=TC_LAST // returns terraindeformation GetLastCreatedTerrainDeformation=1,0,terraindeformation _GetLastCreatedTerrainDeformation_Defaults= _GetLastCreatedTerrainDeformation_Category=TC_LAST // returns terraintype GetTerrainTypeBJ=1,1,terraintype,location _GetTerrainTypeBJ_Defaults=GetRectCenter _GetTerrainTypeBJ_Category=TC_ENVIRONMENT // returns sound GetLastPlayedSound=0,0,sound _GetLastPlayedSound_Defaults= _GetLastPlayedSound_Category=TC_LAST // returns musicfile GetLastPlayedMusic=0,0,musicfile _GetLastPlayedMusic_Defaults= _GetLastPlayedMusic_Category=TC_LAST // returns quest GetLastCreatedQuestBJ=0,0,quest _GetLastCreatedQuestBJ_Defaults= _GetLastCreatedQuestBJ_Category=TC_LAST // returns questitem GetLastCreatedQuestItemBJ=0,0,questitem _GetLastCreatedQuestItemBJ_Defaults= _GetLastCreatedQuestItemBJ_Category=TC_LAST // returns defeatcondition GetLastCreatedDefeatConditionBJ=0,0,defeatcondition _GetLastCreatedDefeatConditionBJ_Defaults= _GetLastCreatedDefeatConditionBJ_Category=TC_LAST // returns dialog GetClickedDialogBJ=0,0,dialog _GetClickedDialogBJ_Defaults= _GetClickedDialogBJ_Category=TC_EVENTRESPONSE // returns button GetLastCreatedButtonBJ=0,0,button _GetLastCreatedButtonBJ_Defaults= _GetLastCreatedButtonBJ_Category=TC_LAST GetClickedButtonBJ=0,0,button _GetClickedButtonBJ_Defaults= _GetClickedButtonBJ_Category=TC_EVENTRESPONSE // returns leaderboard GetLastCreatedLeaderboard=0,0,leaderboard _GetLastCreatedLeaderboard_Defaults= _GetLastCreatedLeaderboard_Category=TC_LAST PlayerGetLeaderboardBJ=0,0,leaderboard,player _PlayerGetLeaderboardBJ_Defaults=Player00 _PlayerGetLeaderboardBJ_Category=TC_NOTHING // returns multiboard GetLastCreatedMultiboard=1,0,multiboard _GetLastCreatedMultiboard_Defaults= _GetLastCreatedMultiboard_Category=TC_LAST // returns timer GetLastCreatedTimerBJ=0,0,timer _GetLastCreatedTimerBJ_Defaults= _GetLastCreatedTimerBJ_Category=TC_LAST GetExpiredTimer=0,0,timer _GetExpiredTimer_Defaults= _GetExpiredTimer_Category=TC_EVENTRESPONSE // returns timerdialog GetLastCreatedTimerDialogBJ=0,0,timerdialog _GetLastCreatedTimerDialogBJ_Defaults= _GetLastCreatedTimerDialogBJ_Category=TC_LAST // returns gamecache GetLastCreatedGameCacheBJ=0,0,gamecache _GetLastCreatedGameCacheBJ_Defaults= _GetLastCreatedGameCacheBJ_Category=TC_LAST // returns hashtable GetLastCreatedHashtableBJ=0,0,hashtable _GetLastCreatedHashtableBJ_Defaults= _GetLastCreatedHashtableBJ_Category=TC_LAST // returns texttag GetLastCreatedTextTag=1,0,texttag _GetLastCreatedTextTag_Defaults= _GetLastCreatedTextTag_Category=TC_LAST //*************************************************************************** [DefaultTriggerCategories] // Defines categories to be automatically added to new maps NumCategories=1 Category01=WESTRING_INITIALIZATION //*************************************************************************** [DefaultTriggers] // Defines triggers to be automatically added to new maps NumTriggers=1 // Melee Initialization Trigger01Name=WESTRING_MELEEINITIALIZATION Trigger01Comment=WESTRING_MELEEINITIALIZATION_COMMENT Trigger01Category=1 Trigger01Events=1 Trigger01Event01=MapInitializationEvent Trigger01Conditions=0 Trigger01Actions=8 Trigger01Action01=MeleeStartingVisibility Trigger01Action02=MeleeStartingHeroLimit Trigger01Action03=MeleeGrantHeroItems Trigger01Action04=MeleeStartingResources Trigger01Action05=MeleeClearExcessUnits Trigger01Action06=MeleeStartingUnits Trigger01Action07=MeleeStartingAI Trigger01Action08=MeleeInitVictoryDefeat ================================================ FILE: clients/weu/TriggerDataWEU.txt ================================================ [TriggerCategories] TC_ARITHMETIC=WESTRING_TRIGCAT_ARITHMETIC,ReplaceableTextures\WorldEditUI\Actions-AI,1 TC_NOTHING=WESTRING_TRIGCAT_NOTHING,ReplaceableTextures\WorldEditUI\Actions-Nothing,1 TC_COMMENT=WESTRING_TRIGCAT_COMMENT,ReplaceableTextures\WorldEditUI\Actions-Comment,1 TC_CUSTOM=WESTRING_TRIGCAT_CUSTOM,ReplaceableTextures\WorldEditUI\Actions-Nothing,1 TC_CONDITION=WESTRING_TRIGCAT_CONDITION,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_WAIT=WESTRING_TRIGCAT_WAIT,ReplaceableTextures\WorldEditUI\Actions-Wait,1 TC_SETVARIABLE=WESTRING_TRIGCAT_SETVARIABLE,ReplaceableTextures\WorldEditUI\Actions-SetVariables,1 TC_SKIPACTIONS=WESTRING_TRIGCAT_SKIPACTIONS,ReplaceableTextures\WorldEditUI\Actions-Nothing,1 TC_LOGIC=WESTRING_TRIGCAT_LOGIC,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_FORLOOP=WESTRING_TRIGCAT_FORLOOP,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_LAST=WESTRING_TRIGCAT_LAST,ReplaceableTextures\WorldEditUI\Actions-SetVariables,1 TC_AI=WESTRING_TRIGCAT_AI,ReplaceableTextures\WorldEditUI\Actions-AI TC_ANIMATION=WESTRING_TRIGCAT_ANIMATION,ReplaceableTextures\WorldEditUI\Actions-Animation TC_CAMERA=WESTRING_TRIGCAT_CAMERA,ReplaceableTextures\WorldEditUI\Actions-Camera TC_CINEMATIC=WESTRING_TRIGCAT_CINEMATIC,ReplaceableTextures\WorldEditUI\Actions-Camera TC_CONVERSION=WESTRING_TRIGCAT_CONVERSION,ReplaceableTextures\WorldEditUI\Actions-AI TC_TIMER=WESTRING_TRIGCAT_TIMER,ReplaceableTextures\WorldEditUI\Events-Time TC_DESTRUCT=WESTRING_TRIGCAT_DESTRUCT,ReplaceableTextures\WorldEditUI\Actions-Destructibles TC_DIALOG=WESTRING_TRIGCAT_DIALOG,ReplaceableTextures\WorldEditUI\Actions-Dialog TC_ENVIRONMENT=WESTRING_TRIGCAT_ENVIRONMENT,ReplaceableTextures\WorldEditUI\Actions-Environment TC_EVENTRESPONSE=WESTRING_TRIGCAT_EVENTRESPONSE,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_TEXTTAG=WESTRING_TRIGCAT_TEXTTAG,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_GAME=WESTRING_TRIGCAT_GAME,ReplaceableTextures\WorldEditUI\Actions-Game TC_GAMECACHE=WESTRING_TRIGCAT_GAMECACHE,ReplaceableTextures\WorldEditUI\Actions-SetVariables TC_HERO=WESTRING_TRIGCAT_HERO,ReplaceableTextures\WorldEditUI\Actions-Hero TC_IMAGE=WESTRING_TRIGCAT_IMAGE,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_ITEM=WESTRING_TRIGCAT_ITEM,ReplaceableTextures\WorldEditUI\Actions-Item TC_LEADERBOARD=WESTRING_TRIGCAT_LEADERBOARD,ReplaceableTextures\WorldEditUI\Actions-Quest TC_LOCATION=WESTRING_TRIGCAT_LOCATION,ReplaceableTextures\WorldEditUI\Actions-Region TC_LIGHTNING=WESTRING_TRIGCAT_LIGHTNING,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_MATH=WESTRING_TRIGCAT_MATH,ReplaceableTextures\WorldEditUI\Actions-Logical TC_MELEE=WESTRING_TRIGCAT_MELEE,ReplaceableTextures\WorldEditUI\Actions-Melee TC_MULTIBOARD=WESTRING_TRIGCAT_MULTIBOARD,ReplaceableTextures\WorldEditUI\Actions-Quest TC_NEUTRALBUILDING=WESTRING_TRIGCAT_NEUTRALBUILDING,ReplaceableTextures\WorldEditUI\Actions-Goldmine TC_PLAYER=WESTRING_TRIGCAT_PLAYER,ReplaceableTextures\WorldEditUI\Actions-Player TC_PLAYERGROUP=WESTRING_TRIGCAT_PLAYERGROUP,ReplaceableTextures\WorldEditUI\Actions-PlayerGroup TC_QUEST=WESTRING_TRIGCAT_QUEST,ReplaceableTextures\WorldEditUI\Actions-Quest TC_REGION=WESTRING_TRIGCAT_REGION,ReplaceableTextures\WorldEditUI\Actions-Region TC_RECTANGLE=WESTRING_TRIGCAT_RECTANGLE,ReplaceableTextures\WorldEditUI\Actions-Regions TC_UNITSEL=WESTRING_TRIGCAT_UNITSEL,ReplaceableTextures\WorldEditUI\Actions-UnitSelection TC_SOUND=WESTRING_TRIGCAT_SOUND,ReplaceableTextures\WorldEditUI\Actions-Sound TC_SPECIALEFFECT=WESTRING_TRIGCAT_SPECIALEFFECT,ReplaceableTextures\WorldEditUI\Actions-Animation TC_TIME=WESTRING_TRIGCAT_TIME,ReplaceableTextures\WorldEditUI\Events-Time TC_TRIGGER=WESTRING_TRIGCAT_TRIGGER,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_UBERSPLAT=WESTRING_TRIGCAT_UBERSPLAT,ReplaceableTextures\WorldEditUI\Actions-Nothing TC_TRACKABLE=WESTRING_TRIGCAT_TRACKABLE,ReplaceableTextures\WorldEditUI\Actions-Trackable TC_UNIT=WESTRING_TRIGCAT_UNIT,ReplaceableTextures\WorldEditUI\Actions-Unit TC_UNITGROUP=WESTRING_TRIGCAT_UNITGROUP,ReplaceableTextures\WorldEditUI\Actions-UnitGroup TC_VISIBILITY=WESTRING_TRIGCAT_VISIBILITY,ReplaceableTextures\WorldEditUI\Actions-Visibility TC_COMPATIBILITY=WESTRING_TRIGCAT_COMPATIBILITY,ReplaceableTextures\WorldEditUI\Actions-Compatibility TC_RETURNSUCCESS=WESTRING_TRIGCAT_RETURNSUCCESS,ReplaceableTextures\WorldEditUI\Actions-Success TC_AI_TOWN=WESTRING_TRIGCAT_AI_TOWN,none TC_AI_HERO=WESTRING_TRIGCAT_AI_HERO,none TC_AI_RESOURCES=WESTRING_TRIGCAT_AI_RESOURCES,none TC_AI_MISC=WESTRING_TRIGCAT_AI_MISC,none TC_AI_UNIT=WESTRING_TRIGCAT_AI_UNIT,none TC_AI_UPGRADE=WESTRING_TRIGCAT_AI_UPGRADE,none TC_AI_COMMAND=WESTRING_TRIGCAT_AI_COMMAND,none [TriggerTypes] abilcode=0,1,1,WESTRING_TRIGTYPE_abilcode,integer attacktype=0,1,1,WESTRING_TRIGTYPE_attacktype boolean=0,1,1,WESTRING_TRIGTYPE_boolean buffcode=1,1,1,WESTRING_TRIGTYPE_buffcode,integer camerasetup=0,1,0,WESTRING_TRIGTYPE_camerasetup weapontype=0,1,1,WESTRING_TRIGTYPE_weapontype damagetype=0,1,1,WESTRING_TRIGTYPE_damagetype destructable=0,1,1,WESTRING_TRIGTYPE_destructable destructablecode=0,1,1,WESTRING_TRIGTYPE_destructablecode,integer defeatcondition=0,1,0,WESTRING_TRIGTYPE_defeatcondition dialog=0,1,0,WESTRING_TRIGTYPE_dialog button=0,1,0,WESTRING_TRIGTYPE_button effecttype=0,1,1,WESTRING_TRIGTYPE_effecttype texttag=1,1,0,WESTRING_TRIGTYPE_texttag gamecache=0,1,0,WESTRING_TRIGTYPE_gamecache gamespeed=0,1,1,WESTRING_TRIGTYPE_gamespeed image=1,1,1,WESTRING_TRIGTYPE_image imagetype=0,1,1,WESTRING_TRIGTYPE_imagetype,integer integer=0,1,1,WESTRING_TRIGTYPE_integer item=0,1,1,WESTRING_TRIGTYPE_item itemtype=1,1,1,WESTRING_TRIGTYPE_itemtype itemcode=0,1,1,WESTRING_TRIGTYPE_itemcode,integer leaderboard=0,1,0,WESTRING_TRIGTYPE_leaderboard lightning=1,1,1,WESTRING_TRIGTYPE_lightning lightningtype=0,1,1,WESTRING_TRIGTYPE_lightningtype,string multiboard=1,1,0,WESTRING_TRIGTYPE_multiboard multiboarditem=1,1,1,WESTRING_TRIGTYPE_multiboarditem ordercode=0,1,1,WESTRING_TRIGTYPE_ordercode,integer player=0,1,1,WESTRING_TRIGTYPE_player playercolor=0,1,1,WESTRING_TRIGTYPE_playercolor force=0,1,0,WESTRING_TRIGTYPE_force location=0,1,1,WESTRING_TRIGTYPE_location pathingtype=0,1,1,WESTRING_TRIGTYPE_pathingtype quest=0,1,0,WESTRING_TRIGTYPE_quest questitem=0,1,0,WESTRING_TRIGTYPE_questitem race=0,1,1,WESTRING_TRIGTYPE_race real=0,1,1,WESTRING_TRIGTYPE_real rect=0,1,1,WESTRING_TRIGTYPE_rect region=1,1,1,WESTRING_TRIGTYPE_rectanglereg sound=0,1,0,WESTRING_TRIGTYPE_sound soundtype=0,1,1,WESTRING_TRIGTYPE_soundtype effect=0,1,0,WESTRING_TRIGTYPE_effect string=0,1,1,WESTRING_TRIGTYPE_string techcode=0,1,1,WESTRING_TRIGTYPE_techcode,integer terraindeformation=1,1,0,WESTRING_TRIGTYPE_terraindeformation terrainshape=0,1,1,WESTRING_TRIGTYPE_terrainshape,integer terraintype=0,1,1,WESTRING_TRIGTYPE_terraintype,integer timer=0,1,0,WESTRING_TRIGTYPE_timer timerdialog=0,1,0,WESTRING_TRIGTYPE_timerdialog trackable=0,1,0,WESTRING_TRIGTYPE_trackable trigger=0,1,1,WESTRING_TRIGTYPE_trigger unit=0,1,1,WESTRING_TRIGTYPE_unit group=0,1,0,WESTRING_TRIGTYPE_group unitcode=0,1,1,WESTRING_TRIGTYPE_unitcode,integer fogmodifier=0,1,0,WESTRING_TRIGTYPE_fogmodifier weathereffect=0,1,0,WESTRING_TRIGTYPE_weathereffect code=0,0,0,WESTRING_TRIGTYPE_code event=0,1,0,WESTRING_TRIGTYPE_event triggercondition=0,1,0,WESTRING_TRIGTYPE_triggercondition triggeraction=0,1,0,WESTRING_TRIGTYPE_triggeraction ubersplat=1,1,1,WESTRING_TRIGTYPE_ubersplat ubersplattype=0,1,1,WESTRING_TRIGTYPE_ubersplattype,string boolexpr=0,1,1,WESTRING_TRIGTYPE_boolexpr eventid=0,1,1,WESTRING_TRIGTYPE_eventid gamestate=0,0,0,WESTRING_TRIGTYPE_gamestate igamestate=0,0,0,WESTRING_TRIGTYPE_igamestate unittype=0,0,0,WESTRING_TRIGTYPE_unittype alliancetype=0,0,0,WESTRING_TRIGTYPE_alliancetype playerstate=0,0,0,WESTRING_TRIGTYPE_playerstate playerscore=1,0,0,WESTRING_TRIGTYPE_playerscore playergameresult=0,0,0,WESTRING_TRIGTYPE_playergameresult unitstate=0,0,0,WESTRING_TRIGTYPE_unitstate playerunitevent=0,0,0,WESTRING_TRIGTYPE_playerunitevent unitevent=0,0,0,WESTRING_TRIGTYPE_unitevent limitop=0,0,0,WESTRING_TRIGTYPE_limitop gamedifficulty=0,0,1,WESTRING_TRIGTYPE_gamedifficulty gameevent=1,0,0,WESTRING_TRIGTYPE_gameevent aidifficulty=0,0,1,WESTRING_TRIGTYPE_aidifficulty mapdensity=0,0,1,WESTRING_TRIGTYPE_mapdensity mapcontrol=0,0,1,WESTRING_TRIGTYPE_mapcontrol mapflag=0,0,0,WESTRING_TRIGTYPE_mapflag playerslotstate=0,0,1,WESTRING_TRIGTYPE_playerslotstate camerafield=0,0,0,WESTRING_TRIGTYPE_camerafield raritycontrol=0,0,0,WESTRING_TRIGTYPE_raritycontrol blendmode=0,0,0,WESTRING_TRIGTYPE_blendmode fogstate=0,0,0,WESTRING_TRIGTYPE_fogstate volumegroup=0,0,0,WESTRING_TRIGTYPE_volumegroup keyeventtype=1,0,0,WESTRING_TRIGTYPE_keyeventtype,integer keyeventkey=1,0,0,WESTRING_TRIGTYPE_keyeventkey,integer colorchangeoption=0,0,0,WESTRING_TRIGTYPE_colorchangeoption,boolean playerchangecoloroption=0,0,0,WESTRING_TRIGTYPE_playerchangecoloroption,boolean chatmatchtype=0,0,0,WESTRING_TRIGTYPE_chatmatchtype,boolean unitfacingbone=0,0,0,WESTRING_TRIGTYPE_unitfacingbone,string includeoption=0,0,0,WESTRING_TRIGTYPE_inclusionoption,boolean cameraapplyoption=0,0,0,WESTRING_TRIGTYPE_cameraapplyoption,boolean cameraorientationoption=0,0,0,WESTRING_TRIGTYPE_cameraorientationoption,boolean invulnerableoption=0,0,0,WESTRING_TRIGTYPE_invulnerableoption,boolean availabilityoption=0,0,0,WESTRING_TRIGTYPE_availabilityoption,boolean showhideoption=0,0,0,WESTRING_TRIGTYPE_showhideoption,boolean minimizeoption=1,0,0,WESTRING_TRIGTYPE_minimizeoption,boolean skymodelstring=0,0,0,WESTRING_TRIGTYPE_skymodelstring,string,Model cinefiltertexture=0,0,0,WESTRING_TRIGTYPE_cinefiltertexture,string,Image playerresource=1,0,0,WESTRING_TRIGTYPE_playerresource,playerstate pathingoption=0,0,0,WESTRING_TRIGTYPE_pathingoption,boolean pawnableoption=1,0,0,WESTRING_TRIGTYPE_pawnableoption,boolean dropnodropoption=0,0,0,WESTRING_TRIGTYPE_dropnodropoption,boolean droppableoption=0,0,0,WESTRING_TRIGTYPE_droppableoption,boolean beforeafteroption=0,0,0,WESTRING_TRIGTYPE_beforeafteroption,boolean onoffoption=0,0,0,WESTRING_TRIGTYPE_onoffoption,boolean enabledisableoption=0,0,0,WESTRING_TRIGTYPE_enabledisableoption,boolean enableddisabledoption=0,0,0,WESTRING_TRIGTYPE_enableddisabledoption,boolean rescuableoption=0,0,0,WESTRING_TRIGTYPE_rescuableoption,boolean allowdontoption=0,0,0,WESTRING_TRIGTYPE_allowdontoption,boolean fadedontoption=0,0,0,WESTRING_TRIGTYPE_fadedontoption,boolean unitorderutarg=0,0,0,WESTRING_TRIGTYPE_unitorderutarg,string unitorderptarg=0,0,0,WESTRING_TRIGTYPE_unitorderptarg,string unitorderdtarg=0,0,0,WESTRING_TRIGTYPE_unitorderdtarg,string unitordernotarg=0,0,0,WESTRING_TRIGTYPE_unitordernotarg,string heroskillcode=0,1,1,WESTRING_TRIGTYPE_heroskillcode,integer weathereffectcode=0,0,0,WESTRING_TRIGTYPE_weathereffectcode,integer alliancesetting=0,0,0,WESTRING_TRIGTYPE_alliancesetting,integer addsettooption=0,0,0,WESTRING_TRIGTYPE_addsettooption,integer modifymethod=1,0,0,WESTRING_TRIGTYPE_modifymethod,integer waitdontoption=0,0,0,WESTRING_TRIGTYPE_waitdontoption,boolean cratertype=1,0,0,WESTRING_TRIGTYPE_cratertype,boolean rippletype=1,0,0,WESTRING_TRIGTYPE_rippletype,boolean createremoveoption=0,0,0,WESTRING_TRIGTYPE_createremoveoption,boolean addremoveoption=0,0,0,WESTRING_TRIGTYPE_addremoveoption,boolean questtypeoption=0,0,0,WESTRING_TRIGTYPE_questtypeoption,integer questmessagetype=0,0,0,WESTRING_TRIGTYPE_questmessagetype,integer herostat=1,0,0,WESTRING_TRIGTYPE_herostat,integer completionoption=0,0,0,WESTRING_TRIGTYPE_completionoption,boolean failureoption=0,0,0,WESTRING_TRIGTYPE_failureoption,boolean discoveredoption=0,0,0,WESTRING_TRIGTYPE_discoveredoption,boolean pauseresumeoption=0,0,0,WESTRING_TRIGTYPE_pauseresumeoption,boolean periodicoption=0,0,0,WESTRING_TRIGTYPE_periodicoption,boolean leaderboardsortoption=0,0,0,WESTRING_TRIGTYPE_leaderboardsortoption,integer ascendingoption=0,0,0,WESTRING_TRIGTYPE_ascendingoption,boolean sleepwakeoption=0,0,0,WESTRING_TRIGTYPE_sleepwakeoption,boolean pauseunpauseoption=0,0,0,WESTRING_TRIGTYPE_pauseunpauseoption,boolean sharedontoption=0,0,0,WESTRING_TRIGTYPE_sharedontoption,boolean fadetypeoption=0,0,0,WESTRING_TRIGTYPE_fadetypeoption,boolean bufftype=0,0,0,WESTRING_TRIGTYPE_bufftype,integer buffpolarity=1,0,0,WESTRING_TRIGTYPE_buffpolarity,integer buffresist=1,0,0,WESTRING_TRIGTYPE_buffresist,integer cameraboundsadjusttype=0,0,0,WESTRING_TRIGTYPE_cameraboundsadjusttype,integer availableoption=0,0,0,WESTRING_TRIGTYPE_availableoption,boolean explodedontoption=0,0,0,WESTRING_TRIGTYPE_explodedontoption,boolean suspendresumeoption=0,0,0,WESTRING_TRIGTYPE_suspendresumeoption,boolean missionindex=0,0,0,WESTRING_TRIGTYPE_missionindex,integer campaignindex=0,0,0,WESTRING_TRIGTYPE_campaignindex,integer cinematicindex=0,0,0,WESTRING_TRIGTYPE_cinematicindex,integer musictheme=0,0,0,WESTRING_TRIGTYPE_musictheme,string,Sound ambientthemeday=0,0,0,WESTRING_TRIGTYPE_ambientthemeday,string ambientthemenight=0,0,0,WESTRING_TRIGTYPE_ambientthemenight,string unitstatemethod=0,0,0,WESTRING_TRIGTYPE_unitstatemethod,string checkingignoringoption=0,0,0,WESTRING_TRIGTYPE_checkingignoringoption,string playerflag=0,0,0,WESTRING_TRIGTYPE_playerflag,playerstate gateoperation=0,0,0,WESTRING_TRIGTYPE_gateoperation,integer elevatorwallop=1,0,0,WESTRING_TRIGTYPE_elevatorwallop,boolean elevatorwalltype=1,0,0,WESTRING_TRIGTYPE_elevatorwalltype,integer useskipoption=0,0,0,WESTRING_TRIGTYPE_useskipoption,boolean seldeseloption=0,0,0,WESTRING_TRIGTYPE_seldeseloption,boolean cachevaluetype=1,0,0,WESTRING_TRIGTYPE_cachevaluetype,integer fogstyle=0,0,0,WESTRING_TRIGTYPE_fogstyle,integer timedlifebuffcode=1,0,0,WESTRING_TRIGTYPE_timedlifebuffcode,integer aicaptaintype=1,0,0,WESTRING_TRIGTYPE_aicaptaintype,boolean aicommandpop=1,0,0,WESTRING_TRIGTYPE_aicommandpop,boolean scriptcode=1,0,0,WESTRING_TRIGTYPE_scriptcode,string itemstatus=1,0,0,WESTRING_TRIGTYPE_itemstatus,integer itemcodestatus=1,0,0,WESTRING_TRIGTYPE_itemcodestatus,integer minimappingstyle=1,0,0,WESTRING_TRIGTYPE_minimappingstyle,integer corpsetype=1,0,0,WESTRING_TRIGTYPE_corpsetype,integer stringcaseoption=1,0,0,WESTRING_TRIGTYPE_stringcaseoption,boolean unitorderitarg=0,0,0,WESTRING_TRIGTYPE_unitorderitarg,string unitorderinstant=0,0,0,WESTRING_TRIGTYPE_unitorderinstant,string permanentoption=0,0,0,WESTRING_TRIGTYPE_permanentoption,boolean effecttypebuff=0,0,0,WESTRING_TRIGTYPE_effecttypeoption,effecttype gameeventoption=0,0,0,WESTRING_TRIGTYPE_gameeventoption,gameevent playereventoption=0,0,0,WESTRING_TRIGTYPE_playereventoption,playerevent camfollowfield=1,0,0,WESTRING_TRIGTYPE_camfollowfield,integer brightnesshex=1,0,0,WESTRING_TRIGTYPE_brightnesshex,string colorhex=1,0,0,WESTRING_TRIGTYPE_colorhex,string racepreset=1,0,0,WESTRING_TRIGTYPE_racepreset,integer sfxtype=1,0,0,WESTRING_TRIGTYPE_sfxtype,integer burnstyle=1,0,0,WESTRING_TRIGTYPE_burnstyle,string unituiname=0,0,0,WESTRING_TRIGTYPE_unituiname,string lightningcode=1,0,0,WESTRING_TRIGTYPE_lightningcode,string missilemdl=1,0,0,WESTRING_TRIGTYPE_missilemdl,string saveloadop=1,0,0,WESTRING_TRIGTYPE_saveloadop,integer saveignoreoption=1,0,0,WESTRING_TRIGTYPE_saveignoreoption,boolean circledirection=1,0,0,WESTRING_TRIGTYPE_circledirection,integer increasedecreaseoption=1,0,0,WESTRING_TRIGTYPE_increasedecreaseoption,boolean largesmalloption=1,0,0,WESTRING_TRIGTYPE_largesmalloption,boolean dummyitem=1,0,0,WESTRING_TRIGTYPE_dummyitem,integer buildableoption=1,0,0,WESTRING_TRIGTYPE_buildableoption,boolean dropoption=1,0,0,WESTRING_TRIGTYPE_dropoption,boolean enterleaveoption=1,0,0,WESTRING_TRIGTYPE_enterleaveoption,boolean aibuildtype=1,0,0,WESTRING_TRIGTYPE_aibuildtype,integer aicanceltype=1,0,0,WESTRING_TRIGTYPE_aicanceltype,integer airestricttype=1,0,0,WESTRING_TRIGTYPE_airestricttype,integer aimode=1,0,0,WESTRING_TRIGTYPE_aimode,integer basicabil=1,0,0,WESTRING_TRIGTYPE_basicabil,integer rpercentage=1,0,0,WESTRING_TRIGTYPE_rpercentage,integer gpercentage=1,0,0,WESTRING_TRIGTYPE_gpercentage,integer bpercentage=1,0,0,WESTRING_TRIGTYPE_bpercentage,integer colorchannel=1,0,0,WESTRING_TRIGTYPE_colorchannel,string glowcolor=1,0,0,WESTRING_TRIGTYPE_glowcolor,string aiscript=0,0,0,WESTRING_TRIGTYPE_aiscript,string,AIScript,1 modelfile=0,0,0,WESTRING_TRIGTYPE_modelfile,string,Model,1 anyfile=0,0,0,WESTRING_TRIGTYPE_anyfile,string,Any,1 preloadfile=0,0,0,WESTRING_TRIGTYPE_preloadfile,string,Preload,1 imagefile=0,0,0,WESTRING_TRIGTYPE_imagefile,string,Image,1 StringExt=0,0,0,WESTRING_TRIGTYPE_StringExt,string AnyGlobal=0,0,0,WESTRING_TRIGTYPE_AnyGlobal AnyType=0,0,0,WESTRING_TRIGTYPE_AnyType VarAsString_Real=0,0,0,WESTRING_TRIGTYPE_VarAsString_Real ArithmeticOperator=0,0,0,WESTRING_TRIGTYPE_ArithmeticOperator ComparisonOperator=0,0,0,WESTRING_TRIGTYPE_ComparisonOperator EqualNotEqualOperator=0,0,0,WESTRING_TRIGTYPE_EqualNotEqualOperator boolcall=0,0,0,WESTRING_TRIGTYPE_boolcall eventcall=1,0,0,WESTRING_TRIGTYPE_eventcall doodadcode=0,0,0,WESTRING_TRIGTYPE_doodadcode,integer musicfile=0,0,0,WESTRING_TRIGTYPE_musicfile,string integervar=1,0,0,WESTRING_TRIGTYPE_integer,integer [TriggerTypeDefaults] boolean=false,WESTRING_FALSE integer=0 real=0 group=CreateGroup(),WESTRING_TRIGDEFAULT_GROUP force=CreateForce(),WESTRING_TRIGDEFAULT_FORCE timer=CreateTimer(),WESTRING_TRIGDEFAULT_TIMER dialog=DialogCreate(),WESTRING_TRIGDEFAULT_DIALOG multiboard=CreateMultiboard(),WESTRING_TRIGDEFAULT_MULTIBOARD region=CreateRegion(),WESTRING_TRIGDEFAULT_REGION trigger=CreateTrigger(),WESTRING_TRIGDEFAULT_TRIGGER [TriggerParams] OperatorAdd=0,ArithmeticOperator,"+",WESTRING_ARITHMETICOPERATOR_ADD OperatorSubtract=0,ArithmeticOperator,"-",WESTRING_ARITHMETICOPERATOR_SUBTRACT OperatorMultiply=0,ArithmeticOperator,"*",WESTRING_ARITHMETICOPERATOR_MULTIPLY OperatorDivide=0,ArithmeticOperator,"/",WESTRING_ARITHMETICOPERATOR_DIVIDE OperatorEqual=0,ComparisonOperator,"==",WESTRING_COMPARISONOPERATOR_EQUAL OperatorNotEqual=0,ComparisonOperator,"!=",WESTRING_COMPARISONOPERATOR_NOTEQUAL OperatorGreater=0,ComparisonOperator,">",WESTRING_COMPARISONOPERATOR_GREATER OperatorGreaterEq=0,ComparisonOperator,">=",WESTRING_COMPARISONOPERATOR_GREATEREQ OperatorLess=0,ComparisonOperator,"<",WESTRING_COMPARISONOPERATOR_LESS OperatorLessEq=0,ComparisonOperator,"<=",WESTRING_COMPARISONOPERATOR_LESSEQ OperatorEqualENE=0,EqualNotEqualOperator,"==",WESTRING_EQUALNOTEQUALOPERATOR_EQUAL OperatorNotEqualENE=0,EqualNotEqualOperator,"!=",WESTRING_EQUALNOTEQUALOPERATOR_NOTEQUAL RealQueueDelayQuest=0,real,bj_QUEUE_DELAY_QUEST,WESTRING_QUEUE_DELAY_QUEST RealQueueDelayHint=0,real,bj_QUEUE_DELAY_HINT,WESTRING_QUEUE_DELAY_HINT RealQueueDelaySecret=0,real,bj_QUEUE_DELAY_SECRET,WESTRING_QUEUE_DELAY_SECRET RealHandicapEasy=0,real,bj_HANDICAP_EASY,WESTRING_HANDICAP_EASY RealCellWidth=0,real,bj_CELLWIDTH,WESTRING_REAL_CELLWIDTH RealUnitFacing=0,real,bj_UNIT_FACING,WESTRING_REAL_UNITFACING RealCamDefDistance=0,real,bj_CAMERA_DEFAULT_DISTANCE,WESTRING_CAMDEFAULT_DISTANCE RealCamDefFarZ=0,real,bj_CAMERA_DEFAULT_FARZ,WESTRING_CAMDEFAULT_FARZ RealCamDefAoA=0,real,bj_CAMERA_DEFAULT_AOA,WESTRING_CAMDEFAULT_AOA RealCamDefFoV=0,real,bj_CAMERA_DEFAULT_FOV,WESTRING_CAMDEFAULT_FOV RealCamDefRoll=0,real,bj_CAMERA_DEFAULT_ROLL,WESTRING_CAMDEFAULT_ROLL RealCamDefRotation=0,real,bj_CAMERA_DEFAULT_ROTATION,WESTRING_CAMDEFAULT_ROTATION RealE=0,real,bj_E,WESTRING_REAL_E RealPi=0,real,bj_PI,WESTRING_REAL_PI RealGameStartedThreshold=0,real,bj_GAME_STARTED_THRESHOLD,WESTRING_REAL_GAMESTARTEDTHRESHOLD IntegerMaxInventory=0,integer,bj_MAX_INVENTORY,WESTRING_INTEGER_MAXINVENTORY IntegerMaxPlayers=0,integer,bj_MAX_PLAYERS,WESTRING_INTEGER_MAXPLAYERS IntegerMaxPlayerSlots=0,integer,bj_MAX_PLAYER_SLOTS,WESTRING_INTEGER_MAXPLAYERSLOTS LeaderboardNull=0,leaderboard,null,WESTRING_TRIGLEADERBOARD_NULL MultiboardNull=0,multiboard,null,WESTRING_TRIGMULTIBOARD_NULL RegionNull=0,region,null,WESTRING_TRIGREGION_NULL TriggerNull=0,trigger,null,WESTRING_TRIGTRIGGER_NULL TrackableNull=0,trackable,null,WESTRING_TRIGTRACKABLE_NULL EmptyString=1,string,"``",WESTRING_PRESET_EMPTYSTRING AttachPointOverhead=0,string,`overhead`,WESTRING_ATTACHPOINT_OVERHEAD AttachPointHead=0,string,`head`,WESTRING_ATTACHPOINT_HEAD AttachPointChest=0,string,`chest`,WESTRING_ATTACHPOINT_CHEST AttachPointOrigin=0,string,`origin`,WESTRING_ATTACHPOINT_ORIGIN AttachPointHand=0,string,`hand`,WESTRING_ATTACHPOINT_HAND AttachPointFoot=0,string,`foot`,WESTRING_ATTACHPOINT_FOOT AttachPointWeapon=0,string,`weapon`,WESTRING_ATTACHPOINT_WEAPON AttachPointSprite=0,string,`sprite`,WESTRING_ATTACHPOINT_SPRITE AttachPointMedium=0,string,`medium`,WESTRING_ATTACHPOINT_MEDIUM AttachPointLarge=0,string,`large`,WESTRING_ATTACHPOINT_LARGE AttHandRight=1,string,"`hand right`",WESTRING_ATTHANDRIGHT AttHandLeft=1,string,"`hand left`",WESTRING_ATTHANDLEFT AttFootRight=1,string,"`foot right`",WESTRING_ATTFOOTRIGHT AttFootLeft=1,string,"`foot left`",WESTRING_ATTFOOTLEFT AttFootRightMount=1,string,"`foot right mount`",WESTRING_ATTFOOTRIGHTMOUNT AttFootLeftMount=1,string,"`foot left mount`",WESTRING_ATTFOOTLEFTMOUNT AttFootRightMountRear=1,string,"`foot right mount rear`",WESTRING_ATTFOOTRIGHTMOUNTREAR AttFootLeftMountRear=1,string,"`foot left mount rear`",WESTRING_ATTFOOTLEFTMOUNTREAR AttSpriteFirst=1,string,"`sprite first`",WESTRING_ATTSPRITEFIRST AttSpriteSecond=1,string,"`sprite second`",WESTRING_ATTSPRITESECOND AttSpriteThird=1,string,"`sprite third`",WESTRING_ATTSPRITETHIRD AttSpriteFourth=1,string,"`sprite fourth`",WESTRING_ATTSPRITEFOURTH AttSpriteFifth=1,string,"`sprite fifth`",WESTRING_ATTSPRITEFIFTH AttSpriteSixth=1,string,"`sprite sixth`",WESTRING_ATTSPRITESIXTH AttSpriteRallypoint=1,string,"`sprite rallypoint`",WESTRING_ATTSPRITERALLYPOINT AttMediumFirst=1,string,"`medium first`",WESTRING_ATTMEDIUMFIRST AttMediumSecond=1,string,"`medium second`",WESTRING_ATTMEDIUMSECOND AttMediumThird=1,string,"`medium third`",WESTRING_ATTMEDIUMTHIRD AttMediumFourth=1,string,"`medium fourth`",WESTRING_ATTMEDIUMFOURTH AttMediumFifth=1,string,"`medium fifth`",WESTRING_ATTMEDIUMFIFTH AttMediumSixth=1,string,"`medium sixth`",WESTRING_ATTMEDIUMSIXTH AttMediumRallypoint=1,string,"`medium rallypoint`",WESTRING_ATTMEDIUMRALLYPOINT AttLargeFirst=1,string,"`large first`",WESTRING_ATTLARGEFIRST AttLargeSecond=1,string,"`large second`",WESTRING_ATTLARGESECOND AttLargeThird=1,string,"`large third`",WESTRING_ATTLARGETHIRD AttLargeFourth=1,string,"`large fourth`",WESTRING_ATTLARGEFOURTH AttLargeFifth=1,string,"`large fifth`",WESTRING_ATTLARGEFIFTH AttLargeSixth=1,string,"`large sixth`",WESTRING_ATTLARGESIXTH AttLargeRallypoint=1,string,"`large rallypoint`",WESTRING_ATTLARGERALLYPOINT AttachPointModifierLeft=0,string,` left`,WESTRING_ATTACHPOINTMODIFIER_LEFT AttachPointModifierRight=0,string,` right`,WESTRING_ATTACHPOINTMODIFIER_RIGHT AttachPointModifierMount=0,string,` mount`,WESTRING_ATTACHPOINTMODIFIER_MOUNT AttachPointModifierRear=0,string,` rear`,WESTRING_ATTACHPOINTMODIFIER_REAR AttachPointModifierFirst=0,string,` first`,WESTRING_ATTACHPOINTMODIFIER_FIRST AttachPointModifierSecond=0,string,` second`,WESTRING_ATTACHPOINTMODIFIER_SECOND AttachPointModifierThird=0,string,` third`,WESTRING_ATTACHPOINTMODIFIER_THIRD AttachPointModifierFourth=0,string,` fourth`,WESTRING_ATTACHPOINTMODIFIER_FOURTH AttachPointModifierFifth=0,string,` fifth`,WESTRING_ATTACHPOINTMODIFIER_FIFTH AttachPointModifierSixth=0,string,` sixth`,WESTRING_ATTACHPOINTMODIFIER_SIXTH AttachPointModifierRallypoint=0,string,` rallypoint`,WESTRING_ATTACHPOINTMODIFIER_RALLYPOINT PlayerStateGivesBounty=0,playerstate,PLAYER_STATE_GIVES_BOUNTY,WESTRING_PLAYER_STATE_GIVES_BOUNTY PlayerStateAlliedVictory=0,playerstate,PLAYER_STATE_ALLIED_VICTORY,WESTRING_PLAYER_STATE_ALLIED_VICTORY PlayerStateIsPlaced=0,playerstate,PLAYER_STATE_PLACED,WESTRING_PLAYER_STATE_PLACED PlayerStateObserverOnDeath=0,playerstate,PLAYER_STATE_OBSERVER_ON_DEATH,WESTRING_PLAYER_STATE_OBSERVER_ON_DEATH PlayerStateIsObserver=0,playerstate,PLAYER_STATE_OBSERVER,WESTRING_PLAYER_STATE_OBSERVER PlayerStateIsUnfollowable=0,playerstate,PLAYER_STATE_UNFOLLOWABLE,WESTRING_PLAYER_STATE_UNFOLLOWABLE PlayerStateCreepSleep=0,playerstate,PLAYER_STATE_NO_CREEP_SLEEP,WESTRING_PLAYER_STATE_NO_CREEP_SLEEP OrderCodePoisonArrows=0,ordercode,OrderId("poisonarrows"),WESTRING_UNITORDERNOTARG_POISONARROWON OrderCodeUnPoisonArrows=0,ordercode,OrderId("unpoisonarrows"),WESTRING_UNITORDERNOTARG_POISONARROWOFF OrderCodeClusterRockets=1,ordercode,OrderId("clusterrockets"),WESTRING_UNITORDERPTARG_CLUSTERROCKETS OrderCodeSummonFactory=1,ordercode,OrderId("summonfactory"),WESTRING_UNITORDERPTARG_SUMMONFACTORY OrderCodeRoboGoblin=1,ordercode,OrderId("robogoblin"),WESTRING_UNITORDERNOTARG_ROBOGOBLIN OrderCodeUnRoboGoblin=1,ordercode,OrderId("unrobogoblin"),WESTRING_UNITORDERNOTARG_UNROBOGOBLIN OrderCodeAcidBomb=1,ordercode,OrderId("acidbomb"),WESTRING_UNITORDERUTARG_ACIDBOMB OrderCodeTransmute=1,ordercode,OrderId("transmute"),WESTRING_UNITORDERUTARG_TRANSMUTE OrderCodeSoulBurn=1,ordercode,OrderId("soulburn"),WESTRING_UNITORDERUTARG_SOULBURN OrderCodeHealingSpray=1,ordercode,OrderId("healingspray"),WESTRING_UNITORDERPTARG_HEALINGSPRAY OrderCodeVolcano=1,ordercode,OrderId("volcano"),WESTRING_UNITORDERPTARG_VOLCANO OrderCodeChemicalRage=1,ordercode,OrderId("chemicalrage"),WESTRING_UNITORDERNOTARG_CHEMICALRAGE OrderCodeLavaMonster=1,ordercode,OrderId("lavamonster"),WESTRING_UNITORDERNOTARG_LAVAMONSTER UnitOrderAcidBomb=1,unitorderutarg,`acidbomb`,WESTRING_UNITORDERUTARG_ACIDBOMB UnitOrderTransmute=1,unitorderutarg,`transmute`,WESTRING_UNITORDERUTARG_TRANSMUTE UnitOrderSoulBurn=1,unitorderutarg,`soulburn`,WESTRING_UNITORDERUTARG_SOULBURN UnitOrderPoisonArrow=0,unitorderutarg,`poisonarrowstarg`,WESTRING_UNITORDERUTARG_POISONARROW UnitOrderSummonFactory=1,unitorderptarg,`summonfactory`,WESTRING_UNITORDERPTARG_SUMMONFACTORY UnitOrderVolcano=1,unitorderptarg,`volcano`,WESTRING_UNITORDERPTARG_VOLCANO UnitOrderHealingSpray=1,unitorderptarg,`healingspray`,WESTRING_UNITORDERPTARG_HEALINGSPRAY UnitOrderClusterRockets=1,unitorderptarg,`clusterrockets`,WESTRING_UNITORDERPTARG_CLUSTERROCKETS UnitOrderChemicalRage=1,unitordernotarg,`chemicalrage`,WESTRING_UNITORDERNOTARG_CHEMICALRAGE UnitOrderRoboGoblin=1,unitordernotarg,`robogoblin`,WESTRING_UNITORDERNOTARG_ROBOGOBLIN UnitOrderUnRoboGoblin=1,unitordernotarg,`unrobogoblin`,WESTRING_UNITORDERNOTARG_UNROBOGOBLIN UnitOrderLavaMonster=1,unitordernotarg,`lavamonster`,WESTRING_UNITORDERNOTARG_LAVAMONSTER UnitOrderIncinerateArrowOn=1,unitordernotarg,`incineratearrowon`,WESTRING_UNITORDERNOTARG_INCINERATEARROWON UnitOrderIncinerateArrowOff=1,unitordernotarg,`incineratearrowoff`,WESTRING_UNITORDERNOTARG_INCINERATEARROWOFF HeroSkillAcidBomb=1,heroskillcode,'ANab',WESTRING_HEROSKILL_ACIDBOMB HeroSkillChemicalRage=1,heroskillcode,'ANcr',WESTRING_HEROSKILL_CHEMICALRAGE HeroSkillHealingSpray=1,heroskillcode,'ANhs',WESTRING_HEROSKILL_HEALINGSPRAY HeroSkillTransmute=1,heroskillcode,'ANtm',WESTRING_HEROSKILL_TRANSMUTE HeroSkillEngineeringUpgrade=1,heroskillcode,'ANeg',WESTRING_HEROSKILL_ENGINEERINGUPGRADE HeroSkillClusterRockets=1,heroskillcode,'ANcs',WESTRING_HEROSKILL_CLUSTERROCKETS HeroSkillSummonFactory=1,heroskillcode,'ANsy',WESTRING_HEROSKILL_SUMMONFACTORY HeroSkillRoboGoblin=1,heroskillcode,'ANrg',WESTRING_HEROSKILL_ROBOGOBLIN HeroSkillIncinerate=1,heroskillcode,'ANic',WESTRING_HEROSKILL_INCINERATE HeroSkillIncinerateArrow=1,heroskillcode,'ANia',WESTRING_HEROSKILL_INCINERATEARROW HeroSkillSoulBurn=1,heroskillcode,'ANso',WESTRING_HEROSKILL_SOULBURN HeroSkillLavaMonster=1,heroskillcode,'ANlm',WESTRING_HEROSKILL_LAVAMONSTER HeroSkillVolcano=1,heroskillcode,'ANvc',WESTRING_HEROSKILL_VOLCANO unknownAloc=0,abilcode,'Aloc',WESTRING_UNKNOWNABIL_ALOC unknownAatk=0,abilcode,'Aatk',WESTRING_UNKNOWNABIL_AATK unknownAmov=0,abilcode,'Amov',WESTRING_UNKNOWNABIL_AMOV unknownAalr=0,abilcode,'Aalr',WESTRING_UNKNOWNABIL_AALR unknownAfir=0,abilcode,'Afir',WESTRING_UNKNOWNABIL_AFIR unknownAfih=0,abilcode,'Afih',WESTRING_UNKNOWNABIL_AFIH unknownAfin=0,abilcode,'Afin',WESTRING_UNKNOWNABIL_AFIN unknownAfio=0,abilcode,'Afio',WESTRING_UNKNOWNABIL_AFIO unknownAfiu=0,abilcode,'Afiu',WESTRING_UNKNOWNABIL_AFIU unknownAher=0,abilcode,'Aher',WESTRING_UNKNOWNABIL_AHER unknownAsla=0,abilcode,'Asla',WESTRING_UNKNOWNABIL_ASLA unknownARal=0,abilcode,'ARal',WESTRING_UNKNOWNABIL_ARAL unknownApit=0,abilcode,'Apit',WESTRING_UNKNOWNABIL_APIT unknownArev=0,abilcode,'Arev',WESTRING_UNKNOWNABIL_AREV unknownAawa=0,abilcode,'Aawa',WESTRING_UNKNOWNABIL_AAWA unknownAGbu=0,abilcode,'AGbu',WESTRING_UNKNOWNABIL_AGBU unknownAHbu=0,abilcode,'AHbu',WESTRING_UNKNOWNABIL_AHBU unknownAObu=0,abilcode,'AObu',WESTRING_UNKNOWNABIL_AOBU unknownAEbu=0,abilcode,'AEbu',WESTRING_UNKNOWNABIL_AEBU unknownAUbu=0,abilcode,'AUbu',WESTRING_UNKNOWNABIL_AUBU unknownANbu=0,abilcode,'ANbu',WESTRING_UNKNOWNABIL_ANBU BooleanIsSinglePlayer=0,boolean,bj_isSinglePlayer,WESTRING_BOOLEAN_IS_SINGLEPLAYER ScriptCodeWantDestroyGroup=0,scriptcode,set bj_wantDestroyGroup = true,WESTRING_SCRIPT_WANTDESTROY ScriptCodeLoopStart=0,scriptcode,loop,WESTRING_SCRIPT_LOOP ScriptCodeLoopEnd=0,scriptcode,endloop,WESTRING_SCRIPT_ENDLOOP GamestateDivineIntervention=1,gamestate,GAME_STATE_DIVINE_INTERVENTION,WESTRING_GAME_STATE_DIVINE_INTERVENTION GamestateDisconnected=1,gamestate,GAME_STATE_DISCONNECTED,WESTRING_GAME_STATE_DISCONNECTED GamestateTimeOfDay=1,gamestate,GAME_STATE_TIME_OF_DAY,WESTRING_GAME_STATE_TIME_OF_DAY IGamestateDivineIntervention=1,igamestate,GAME_STATE_DIVINE_INTERVENTION,WESTRING_GAME_STATE_DIVINE_INTERVENTION IGamestateDisconnected=1,igamestate,GAME_STATE_DISCONNECTED,WESTRING_GAME_STATE_DISCONNECTED EventIdGameEnterRegion=1,eventid,EVENT_GAME_ENTER_REGION,WESTRING_GAMEEVENTOPTION_ENTERREGION EventIdGameLeaveRegion=1,eventid,EVENT_GAME_LEAVE_REGION,WESTRING_GAMEEVENTOPTION_LEAVEREGION EventIdGameStateLimit=1,eventid,EVENT_GAME_STATE_LIMIT,WESTRING_GAMEEVENTOPTION_STATELIMIT EventIdGameVariableLimit=1,eventid,EVENT_GAME_VARIABLE_LIMIT,WESTRING_GAMEEVENTOPTION_VARLIMIT EventIdGameUnitStateLimit=1,eventid,EVENT_UNIT_STATE_LIMIT,WESTRING_EVENTID_UNIT_STATE_LIMIT EventIdPlayerStateLimit=1,eventid,EVENT_PLAYER_STATE_LIMIT,WESTRING_EVENTID_EVENT_PLAYER_STATE_LIMIT EventIdGameVictory=1,eventid,EVENT_GAME_VICTORY,WESTRING_EVENTID_GAME_VICTORY EventIdGameEndLevel=1,eventid,EVENT_GAME_END_LEVEL,WESTRING_EVENTID_EVENT_GAME_END_LEVEL EventIdGameTimerExpired=1,eventid,EVENT_GAME_TIMER_EXPIRED,WESTRING_EVENTID_EVENT_GAME_TIMER_EXPIRED EventIdGameShowSkills=1,eventid,EVENT_GAME_SHOW_SKILL,WESTRING_EVENTID_EVENT_GAME_SHOW_SKILL EventIdGameBuildSubmenu=1,eventid,EVENT_GAME_BUILD_SUBMENU,WESTRING_EVENTID_EVENT_GAME_BUILD_SUBMENU EventIdPlayerAllianceChanged=1,eventid,EVENT_PLAYER_ALLIANCE_CHANGED,WESTRING_EVENTID_EVENT_PLAYER_ALLIANCE_CHANGED EventIdPlayerDefeat=1,eventid,EVENT_PLAYER_DEFEAT,WESTRING_EVENTID_EVENT_PLAYER_DEFEAT EventIdPlayerVictory=1,eventid,EVENT_PLAYER_VICTORY,WESTRING_EVENTID_EVENT_PLAYER_VICTORY EventIdPlayerLeave=1,eventid,EVENT_PLAYER_LEAVE,WESTRING_EVENTID_EVENT_PLAYER_LEAVE EventIdPlayerChat=1,eventid,EVENT_PLAYER_CHAT,WESTRING_EVENTID_EVENT_PLAYER_CHAT EventIdPlayerEndCinematic=1,eventid,EVENT_PLAYER_END_CINEMATIC,WESTRING_EVENTID_EVENT_PLAYER_END_CINEMATIC EventIdPlayerWidgetDeath=1,eventid,EVENT_WIDGET_DEATH,WESTRING_EVENTID_EVENT_WIDGET_DEATH EventIdPlayerDialogButtonClick=1,eventid,EVENT_DIALOG_BUTTON_CLICK,WESTRING_EVENTID_EVENT_DIALOG_BUTTON_CLICK EventIdPlayerDialogClick=1,eventid,EVENT_DIALOG_CLICK,WESTRING_EVENTID_EVENT_DIALOG_CLICK EventIdPlayerUnitEventDeath=1,eventid,EVENT_PLAYER_UNIT_DEATH,WESTRING_PUEVENT_DEATH EventIdPlayerUnitEventDecay=1,eventid,EVENT_PLAYER_UNIT_DECAY,WESTRING_PUEVENT_DECAY EventIdPlayerUnitEventHero_Level=1,eventid,EVENT_PLAYER_HERO_LEVEL,WESTRING_PUEVENT_HEROLEVEL EventIdPlayerUnitEventHero_Skill=1,eventid,EVENT_PLAYER_HERO_SKILL,WESTRING_PUEVENT_HEROSKILL EventIdPlayerUnitEventHero_Revivable=1,eventid,EVENT_PLAYER_HERO_REVIVABLE,WESTRING_PUEVENT_HEROREVIVABLE EventIdPlayerUnitEventHeroUseItem=1,eventid,EVENT_PLAYER_UNIT_USE_ITEM,WESTRING_PUEVENT_HEROUSEITEM EventIdPlayerUnitEventHeroPickUpItem=1,eventid,EVENT_PLAYER_UNIT_PICKUP_ITEM,WESTRING_PUEVENT_HEROPICKUPITEM EventIdPlayerUnitEventHeroDropItem=1,eventid,EVENT_PLAYER_UNIT_DROP_ITEM,WESTRING_PUEVENT_HERODROPITEM EventIdPlayerUnitEventAttacked=1,eventid,EVENT_PLAYER_UNIT_ATTACKED,WESTRING_PUEVENT_ATTACKED EventIdPlayerUnitEventRescued=1,eventid,EVENT_PLAYER_UNIT_RESCUED,WESTRING_PUEVENT_RESCUED EventIdPlayerUnitEventSummoned=1,eventid,EVENT_PLAYER_UNIT_SUMMON,WESTRING_PUEVENT_SUMMONED EventIdPlayerUnitEventLoaded=1,eventid,EVENT_PLAYER_UNIT_LOADED,WESTRING_PUEVENT_LOADED EventIdPlayerUnitEventTrain_Start=1,eventid,EVENT_PLAYER_UNIT_TRAIN_START,WESTRING_PUEVENT_TRAINSTART EventIdPlayerUnitEventTrain_Cancel=1,eventid,EVENT_PLAYER_UNIT_TRAIN_CANCEL,WESTRING_PUEVENT_TRAINCANCEL EventIdPlayerUnitEventTrain_Finish=1,eventid,EVENT_PLAYER_UNIT_TRAIN_FINISH,WESTRING_PUEVENT_TRAINFINISH EventIdPlayerUnitEventConstruct_Start=1,eventid,EVENT_PLAYER_UNIT_CONSTRUCT_START,WESTRING_PUEVENT_CONSTRUCTSTART EventIdPlayerUnitEventConstruct_Cancel=1,eventid,EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL,WESTRING_PUEVENT_CONSTRUCTCANCEL EventIdPlayerUnitEventConstruct_Finish=1,eventid,EVENT_PLAYER_UNIT_CONSTRUCT_FINISH,WESTRING_PUEVENT_CONSTRUCTFINISH EventIdPlayerUnitEventReviveStart=1,eventid,EVENT_PLAYER_HERO_REVIVE_START,WESTRING_PUEVENT_REVIVESTART EventIdPlayerUnitEventReviveCancel=1,eventid,EVENT_PLAYER_HERO_REVIVE_CANCEL,WESTRING_PUEVENT_REVIVECANCEL EventIdPlayerUnitEventReviveFinish=1,eventid,EVENT_PLAYER_HERO_REVIVE_FINISH,WESTRING_PUEVENT_REVIVEFINISH EventIdPlayerUnitEventUpgrade_Start=1,eventid,EVENT_PLAYER_UNIT_UPGRADE_START,WESTRING_PUEVENT_UPGRADESTART EventIdPlayerUnitEventUpgrade_Cancel=1,eventid,EVENT_PLAYER_UNIT_UPGRADE_CANCEL,WESTRING_PUEVENT_UPGRADECANCEL EventIdPlayerUnitEventUpgrade_Finish=1,eventid,EVENT_PLAYER_UNIT_UPGRADE_FINISH,WESTRING_PUEVENT_UPGRADEFINISH EventIdPlayerUnitEventResearch_Start=1,eventid,EVENT_PLAYER_UNIT_RESEARCH_START,WESTRING_PUEVENT_RESEARCHSTART EventIdPlayerUnitEventResearch_Cancel=1,eventid,EVENT_PLAYER_UNIT_RESEARCH_CANCEL,WESTRING_PUEVENT_RESEARCHCANCEL EventIdPlayerUnitEventResearch_Finish=1,eventid,EVENT_PLAYER_UNIT_RESEARCH_FINISH,WESTRING_PUEVENT_RESEARCHFINISH EventIdPlayerUnitEventIssued_Unit_Order=1,eventid,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER,WESTRING_PUEVENT_ISSUEDUNITORDER EventIdPlayerUnitEventIssued_Point_Order=1,eventid,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER,WESTRING_PUEVENT_ISSUEDPOINTORDER EventIdPlayerUnitEventIssued_Order=1,eventid,EVENT_PLAYER_UNIT_ISSUED_ORDER,WESTRING_PUEVENT_ISSUEDORDER EventIdUnitEventSummon=1,eventid,EVENT_UNIT_SUMMON,WESTRING_UEVENT_SUMMON EventIdUnitEventDeath=1,eventid,EVENT_UNIT_DEATH,WESTRING_UEVENT_DEATH EventIdUnitEventDecay=1,eventid,EVENT_UNIT_DECAY,WESTRING_UEVENT_DECAY EventIdUnitEventDamaged=1,eventid,EVENT_UNIT_DAMAGED,WESTRING_UEVENT_DAMAGED EventIdUnitEventHeroLevel=1,eventid,EVENT_UNIT_HERO_LEVEL,WESTRING_UEVENT_HEROLEVEL EventIdUnitEventHeroSkill=1,eventid,EVENT_UNIT_HERO_SKILL,WESTRING_UEVENT_HEROSKILL EventIdUnitEventHeroRevivable=1,eventid,EVENT_UNIT_HERO_REVIVABLE,WESTRING_UEVENT_HEROREVIVABLE EventIdUnitEventHeroUseItem=1,eventid,EVENT_UNIT_USE_ITEM,WESTRING_UEVENT_HEROUSEITEM EventIdUnitEventHeroPickUpItem=1,eventid,EVENT_UNIT_PICKUP_ITEM,WESTRING_UEVENT_HEROPICKUPITEM EventIdUnitEventHeroDropItem=1,eventid,EVENT_UNIT_DROP_ITEM,WESTRING_UEVENT_HERODROPITEM EventIdUnitEventAttacked=1,eventid,EVENT_UNIT_ATTACKED,WESTRING_UEVENT_ATTACKED EventIdUnitEventRescued=1,eventid,EVENT_UNIT_RESCUED,WESTRING_UEVENT_RESCUED EventIdUnitEventSelected=1,eventid,EVENT_UNIT_SELECTED,WESTRING_UEVENT_SELECTED EventIdUnitEventDeselected=1,eventid,EVENT_UNIT_DESELECTED,WESTRING_UEVENT_DESELECTED EventIdUnitEventLoaded=1,eventid,EVENT_UNIT_LOADED,WESTRING_UEVENT_LOADED EventIdUnitEventAcquiredTarget=1,eventid,EVENT_UNIT_ACQUIRED_TARGET,WESTRING_UEVENT_ACQUIREDTARGET EventIdUnitEventTargetInRange=1,eventid,EVENT_UNIT_TARGET_IN_RANGE,WESTRING_UEVENT_TARGETINRANGE EventIdUnitEventTrainStart=1,eventid,EVENT_UNIT_TRAIN_START,WESTRING_UEVENT_TRAINSTART EventIdUnitEventTrainCancel=1,eventid,EVENT_UNIT_TRAIN_CANCEL,WESTRING_UEVENT_TRAINCANCEL EventIdUnitEventTrainFinish=1,eventid,EVENT_UNIT_TRAIN_FINISH,WESTRING_UEVENT_TRAINFINISH EventIdUnitEventReviveStart=1,eventid,EVENT_UNIT_HERO_REVIVE_START,WESTRING_UEVENT_REVIVESTART EventIdUnitEventReviveCancel=1,eventid,EVENT_UNIT_HERO_REVIVE_CANCEL,WESTRING_UEVENT_REVIVECANCEL EventIdUnitEventReviveFinish=1,eventid,EVENT_UNIT_HERO_REVIVE_FINISH,WESTRING_UEVENT_REVIVEFINISH EventIdUnitEventUpgradeStart=1,eventid,EVENT_UNIT_UPGRADE_START,WESTRING_UEVENT_UPGRADESTART EventIdUnitEventUpgradeCancel=1,eventid,EVENT_UNIT_UPGRADE_CANCEL,WESTRING_UEVENT_UPGRADECANCEL EventIdUnitEventUpgradeFinish=1,eventid,EVENT_UNIT_UPGRADE_FINISH,WESTRING_UEVENT_UPGRADEFINISH EventIdUnitEventResearchStart=1,eventid,EVENT_UNIT_RESEARCH_START,WESTRING_UEVENT_RESEARCHSTART EventIdUnitEventResearchCancel=1,eventid,EVENT_UNIT_RESEARCH_CANCEL,WESTRING_UEVENT_RESEARCHCANCEL EventIdUnitEventResearchFinish=1,eventid,EVENT_UNIT_RESEARCH_FINISH,WESTRING_UEVENT_RESEARCHFINISH EventIdUnitEventIssueUnitOrder=1,eventid,EVENT_UNIT_ISSUED_TARGET_ORDER,WESTRING_UEVENT_ISSUEUNITORDER EventIdUnitEventIssuePointOrder=1,eventid,EVENT_UNIT_ISSUED_POINT_ORDER,WESTRING_UEVENT_ISSUEPOINTORDER EventIdEventIdUnitEventIssueOrder=1,eventid,EVENT_UNIT_ISSUED_ORDER,WESTRING_UEVENT_ISSUEORDER EventIdGameLoaded=1,eventid,EVENT_GAME_LOADED,WESTRING_EVENTIDGAMELOADED EventIdGameSaved=1,eventid,EVENT_GAME_SAVE,WESTRING_EVENTIDGAMESAVED EventIdLeftDown=1,eventid,EVENT_PLAYER_ARROW_LEFT_DOWN,WESTRING_EVENTIDLEFTDOWN EventIdRightDown=1,eventid,EVENT_PLAYER_ARROW_RIGHT_DOWN,WESTRING_EVENTIDRIGHTDOWN EventIdUpDown=1,eventid,EVENT_PLAYER_ARROW_UP_DOWN,WESTRING_EVENTIDUPDOWN EventIdDownDown=1,eventid,EVENT_PLAYER_ARROW_DOWN_DOWN,WESTRING_EVENTIDDOWNDOWN EventIdLeftUp=1,eventid,EVENT_PLAYER_ARROW_LEFT_UP,WESTRING_EVENTIDLEFTUP EventIdRightUp=1,eventid,EVENT_PLAYER_ARROW_RIGHT_UP,WESTRING_EVENTIDRIGHTUP EventIdUpUp=1,eventid,EVENT_PLAYER_ARROW_UP_UP,WESTRING_EVENTIDUPUP EventIdDownUp=1,eventid,EVENT_PLAYER_ARROW_DOWN_UP,WESTRING_EVENTIDDOWNUP EventIdPlayerUnitEventUnitSell=1,eventid,EVENT_PLAYER_UNIT_SELL,WESTRING_EVENTIDPLAYERUNITEVENTUNITSELL EventIdPlayerUnitEventChangeOwner=1,eventid,EVENT_PLAYER_UNIT_CHANGE_OWNER,WESTRING_EVENTIDPLAYERUNITEVENTCHANGEOWNER EventIdPlayerUnitEventItemSell=1,eventid,EVENT_PLAYER_UNIT_SELL_ITEM,WESTRING_EVENTIDPLAYERUNITEVENTITEMSELL EventIdPlayerUnitEventSpellChannel=1,eventid,EVENT_PLAYER_UNIT_SPELL_CHANNEL,WESTRING_EVENTIDPLAYERUNITEVENTSPELLCHANNEL EventIdPlayerUnitEventSpellCast=1,eventid,EVENT_PLAYER_UNIT_SPELL_CAST,WESTRING_EVENTIDPLAYERUNITEVENTSPELLCAST EventIdPlayerUnitEvent=1,eventid,EVENT_PLAYER_UNIT_SPELL_EFFECT,WESTRING_EVENTIDPLAYERUNITEVENT EventIdPlayerUnitEvent=1,eventid,EVENT_PLAYER_UNIT_SPELL_FINISH,WESTRING_EVENTIDPLAYERUNITEVENT EventIdPlayerUnitEvent=1,eventid,EVENT_PLAYER_UNIT_SPELL_ENDCAST,WESTRING_EVENTIDPLAYERUNITEVENT EventIdUnitEventUnitSell=1,eventid,EVENT_UNIT_SELL,WESTRING_EVENTIDUNITEVENTUNITSELL EventIdUnitEventChangeOwner=1,eventid,EVENT_UNIT_CHANGE_OWNER,WESTRING_EVENTIDUNITEVENTCHANGEOWNER EventIdUnitEventItemSell=1,eventid,EVENT_UNIT_SELL_ITEM,WESTRING_EVENTIDUNITEVENTITEMSELL EventIdUnitEventSpellChannel=1,eventid,EVENT_UNIT_SPELL_CHANNEL,WESTRING_EVENTIDUNITEVENTSPELLCHANNEL EventIdUnitEventSpellCast=1,eventid,EVENT_UNIT_SPELL_CAST,WESTRING_EVENTIDUNITEVENTSPELLCAST EventIdUnitEvent=1,eventid,EVENT_UNIT_SPELL_EFFECT,WESTRING_EVENTIDUNITEVENT EventIdUnitEvent=1,eventid,EVENT_UNIT_SPELL_FINISH,WESTRING_EVENTIDUNITEVENT EventIdUnitEvent=1,eventid,EVENT_UNIT_SPELL_ENDCAST,WESTRING_EVENTIDUNITEVENT EventIdTrackableHit=1,eventid,EVENT_GAME_TRACKABLE_HIT,WESTRING_GAMEEVENTOPTION_TRACKABLEHIT EventIdTrackableTrack=1,eventid,EVENT_GAME_TRACKABLE_TRACK,WESTRING_GAMEEVENTOPTION_TRACKABLETRACK UnitUINamearchmage=0,unituiname,`archmage`,WESTRING_UNITUINAMEARCHMAGE UnitUINamebloodmage=0,unituiname,`bloodmage`,WESTRING_UNITUINAMEBLOODMAGE UnitUINamemountainking=0,unituiname,`mountainking`,WESTRING_UNITUINAMEMOUNTAINKING UnitUINamepaladin=0,unituiname,`paladin`,WESTRING_UNITUINAMEPALADIN UnitUINamehumantransportship=0,unituiname,`humantransportship`,WESTRING_UNITUINAMEHUMANTRANSPORTSHIP UnitUINamehumanbattleship=0,unituiname,`humanbattleship`,WESTRING_UNITUINAMEHUMANBATTLESHIP UnitUINamehumandestroyer=0,unituiname,`humandestroyer`,WESTRING_UNITUINAMEHUMANDESTROYER UnitUINamedragonhawk=0,unituiname,`dragonhawk`,WESTRING_UNITUINAMEDRAGONHAWK UnitUINamefootman=0,unituiname,`footman`,WESTRING_UNITUINAMEFOOTMAN UnitUINamegryphonrider=0,unituiname,`gryphonrider`,WESTRING_UNITUINAMEGRYPHONRIDER UnitUINameflyingmachine=0,unituiname,`flyingmachine`,WESTRING_UNITUINAMEFLYINGMACHINE UnitUINameknight=0,unituiname,`knight`,WESTRING_UNITUINAMEKNIGHT UnitUINamemilitia=0,unituiname,`militia`,WESTRING_UNITUINAMEMILITIA UnitUINamepriest=0,unituiname,`priest`,WESTRING_UNITUINAMEPRIEST UnitUINamemortarteam=0,unituiname,`mortarteam`,WESTRING_UNITUINAMEMORTARTEAM UnitUINamesiegeengine=0,unituiname,`siegeengine`,WESTRING_UNITUINAMESIEGEENGINE UnitUINamepeasant=0,unituiname,`peasant`,WESTRING_UNITUINAMEPEASANT UnitUINamephoenix=0,unituiname,`phoenix`,WESTRING_UNITUINAMEPHOENIX UnitUINamephoenixegg=0,unituiname,`phoenixegg`,WESTRING_UNITUINAMEPHOENIXEGG UnitUINamerifleman=0,unituiname,`rifleman`,WESTRING_UNITUINAMERIFLEMAN UnitUINamerocketengine=0,unituiname,`rocketengine`,WESTRING_UNITUINAMEROCKETENGINE UnitUINamesorceress=0,unituiname,`sorceress`,WESTRING_UNITUINAMESORCERESS UnitUINamespellbreaker=0,unituiname,`spellbreaker`,WESTRING_UNITUINAMESPELLBREAKER UnitUINamewaterelemental1=0,unituiname,`waterelemental1`,WESTRING_UNITUINAMEWATERELEMENTAL1 UnitUINamewaterelemental2=0,unituiname,`waterelemental2`,WESTRING_UNITUINAMEWATERELEMENTAL2 UnitUINamewaterelemental3=0,unituiname,`waterelemental3`,WESTRING_UNITUINAMEWATERELEMENTAL3 UnitUINamealtarofkings=0,unituiname,`altarofkings`,WESTRING_UNITUINAMEALTAROFKINGS UnitUINameworkshop=0,unituiname,`workshop`,WESTRING_UNITUINAMEWORKSHOP UnitUINamearcanesanctum=0,unituiname,`arcanesanctum`,WESTRING_UNITUINAMEARCANESANCTUM UnitUINamehumanarcanetower=0,unituiname,`humanarcanetower`,WESTRING_UNITUINAMEHUMANARCANETOWER UnitUINamehumanbarracks=0,unituiname,`humanbarracks`,WESTRING_UNITUINAMEHUMANBARRACKS UnitUINameblacksmith=0,unituiname,`blacksmith`,WESTRING_UNITUINAMEBLACKSMITH UnitUINamecastle=0,unituiname,`castle`,WESTRING_UNITUINAMECASTLE UnitUINamecannontower=0,unituiname,`cannontower`,WESTRING_UNITUINAMECANNONTOWER UnitUINamegryphonaviary=0,unituiname,`gryphonaviary`,WESTRING_UNITUINAMEGRYPHONAVIARY UnitUINameguardtower=0,unituiname,`guardtower`,WESTRING_UNITUINAMEGUARDTOWER UnitUINamefarm=0,unituiname,`farm`,WESTRING_UNITUINAMEFARM UnitUINamekeep=0,unituiname,`keep`,WESTRING_UNITUINAMEKEEP UnitUINamehumanlumbermill=0,unituiname,`humanlumbermill`,WESTRING_UNITUINAMEHUMANLUMBERMILL UnitUINamehumanshipyard=0,unituiname,`humanshipyard`,WESTRING_UNITUINAMEHUMANSHIPYARD UnitUINametownhall=0,unituiname,`townhall`,WESTRING_UNITUINAMETOWNHALL UnitUINamearcanevault=0,unituiname,`arcanevault`,WESTRING_UNITUINAMEARCANEVAULT UnitUINamescouttower=0,unituiname,`scouttower`,WESTRING_UNITUINAMESCOUTTOWER UnitUINameblademaster=0,unituiname,`blademaster`,WESTRING_UNITUINAMEBLADEMASTER UnitUINamefarseer=0,unituiname,`farseer`,WESTRING_UNITUINAMEFARSEER UnitUINameshadowhunter=0,unituiname,`shadowhunter`,WESTRING_UNITUINAMESHADOWHUNTER UnitUINametaurenchieftain=0,unituiname,`taurenchieftain`,WESTRING_UNITUINAMETAURENCHIEFTAIN UnitUINamewatcherward=0,unituiname,`watcherward`,WESTRING_UNITUINAMEWATCHERWARD UnitUINameorcishtransportship=0,unituiname,`orcishtransportship`,WESTRING_UNITUINAMEORCISHTRANSPORTSHIP UnitUINamedemolisher=0,unituiname,`demolisher`,WESTRING_UNITUINAMEDEMOLISHER UnitUINameorcishdestroyer=0,unituiname,`orcishdestroyer`,WESTRING_UNITUINAMEORCISHDESTROYER UnitUINamewitchdoctor=0,unituiname,`witchdoctor`,WESTRING_UNITUINAMEWITCHDOCTOR UnitUINamesentryward=0,unituiname,`sentryward`,WESTRING_UNITUINAMESENTRYWARD UnitUINamegrunt=0,unituiname,`grunt`,WESTRING_UNITUINAMEGRUNT UnitUINameheadhunter=0,unituiname,`headhunter`,WESTRING_UNITUINAMEHEADHUNTER UnitUINamehealingward=0,unituiname,`healingward`,WESTRING_UNITUINAMEHEALINGWARD UnitUINamekotobeast=0,unituiname,`kotobeast`,WESTRING_UNITUINAMEKOTOBEAST UnitUINamepeon=0,unituiname,`peon`,WESTRING_UNITUINAMEPEON UnitUINamewolfrider=0,unituiname,`wolfrider`,WESTRING_UNITUINAMEWOLFRIDER UnitUINameshaman=0,unituiname,`shaman`,WESTRING_UNITUINAMESHAMAN UnitUINameserpentward1=0,unituiname,`serpentward1`,WESTRING_UNITUINAMESERPENTWARD1 UnitUINameserpentward2=0,unituiname,`serpentward2`,WESTRING_UNITUINAMESERPENTWARD2 UnitUINameserpentward3=0,unituiname,`serpentward3`,WESTRING_UNITUINAMESERPENTWARD3 UnitUINameserpentward4=0,unituiname,`serpentward4`,WESTRING_UNITUINAMESERPENTWARD4 UnitUINamespiritwalkermorph=0,unituiname,`spiritwalkermorph`,WESTRING_UNITUINAMESPIRITWALKERMORPH UnitUINamespiritwalker=0,unituiname,`spiritwalker`,WESTRING_UNITUINAMESPIRITWALKER UnitUINamespiritwolf1=0,unituiname,`spiritwolf1`,WESTRING_UNITUINAMESPIRITWOLF1 UnitUINamespiritwolf2=0,unituiname,`spiritwolf2`,WESTRING_UNITUINAMESPIRITWOLF2 UnitUINamespiritwolf3=0,unituiname,`spiritwolf3`,WESTRING_UNITUINAMESPIRITWOLF3 UnitUINametauren=0,unituiname,`tauren`,WESTRING_UNITUINAMETAUREN UnitUINameberserker=0,unituiname,`berserker`,WESTRING_UNITUINAMEBERSERKER UnitUINametrollbatrider=0,unituiname,`trollbatrider`,WESTRING_UNITUINAMETROLLBATRIDER UnitUINamestasistraptotem=0,unituiname,`stasistraptotem`,WESTRING_UNITUINAMESTASISTRAPTOTEM UnitUINamewindrider=0,unituiname,`windrider`,WESTRING_UNITUINAMEWINDRIDER UnitUINamealtarofstorms=0,unituiname,`altarofstorms`,WESTRING_UNITUINAMEALTAROFSTORMS UnitUINameorcbarracks=0,unituiname,`orcbarracks`,WESTRING_UNITUINAMEORCBARRACKS UnitUINamebeastiary=0,unituiname,`beastiary`,WESTRING_UNITUINAMEBEASTIARY UnitUINamewarmill=0,unituiname,`warmill`,WESTRING_UNITUINAMEWARMILL UnitUINamefortress=0,unituiname,`fortress`,WESTRING_UNITUINAMEFORTRESS UnitUINamegreathall=0,unituiname,`greathall`,WESTRING_UNITUINAMEGREATHALL UnitUINameorcshipyard=0,unituiname,`orcshipyard`,WESTRING_UNITUINAMEORCSHIPYARD UnitUINamespiritlodge=0,unituiname,`spiritlodge`,WESTRING_UNITUINAMESPIRITLODGE UnitUINamestronghold=0,unituiname,`stronghold`,WESTRING_UNITUINAMESTRONGHOLD UnitUINametrollburrow=0,unituiname,`trollburrow`,WESTRING_UNITUINAMETROLLBURROW UnitUINametaurentotem=0,unituiname,`taurentotem`,WESTRING_UNITUINAMETAURENTOTEM UnitUINamevoodoolounge=0,unituiname,`voodoolounge`,WESTRING_UNITUINAMEVOODOOLOUNGE UnitUINamewatchtower=0,unituiname,`watchtower`,WESTRING_UNITUINAMEWATCHTOWER UnitUINamedemonhunter=0,unituiname,`demonhunter`,WESTRING_UNITUINAMEDEMONHUNTER UnitUINamedemonhuntermorphed=0,unituiname,`demonhuntermorphed`,WESTRING_UNITUINAMEDEMONHUNTERMORPHED UnitUINamekeeperofthegrove=0,unituiname,`keeperofthegrove`,WESTRING_UNITUINAMEKEEPEROFTHEGROVE UnitUINamepriestessofthemoon=0,unituiname,`priestessofthemoon`,WESTRING_UNITUINAMEPRIESTESSOFTHEMOON UnitUINamewarden=0,unituiname,`warden`,WESTRING_UNITUINAMEWARDEN UnitUINamearcher=0,unituiname,`archer`,WESTRING_UNITUINAMEARCHER UnitUINameglaivethrower=0,unituiname,`glaivethrower`,WESTRING_UNITUINAMEGLAIVETHROWER UnitUINamenightelfbattleship=0,unituiname,`nightelfbattleship`,WESTRING_UNITUINAMENIGHTELFBATTLESHIP UnitUINamechimaera=0,unituiname,`chimaera`,WESTRING_UNITUINAMECHIMAERA UnitUINamedruidoftheclawmorphed=0,unituiname,`druidoftheclawmorphed`,WESTRING_UNITUINAMEDRUIDOFTHECLAWMORPHED UnitUINamenightelfdestroyer=0,unituiname,`nightelfdestroyer`,WESTRING_UNITUINAMENIGHTELFDESTROYER UnitUINamedruidoftheclaw=0,unituiname,`druidoftheclaw`,WESTRING_UNITUINAMEDRUIDOFTHECLAW UnitUINamedruidofthetalon=0,unituiname,`druidofthetalon`,WESTRING_UNITUINAMEDRUIDOFTHETALON UnitUINamedryad=0,unituiname,`dryad`,WESTRING_UNITUINAMEDRYAD UnitUINamedruidofthetalonmorphed=0,unituiname,`druidofthetalonmorphed`,WESTRING_UNITUINAMEDRUIDOFTHETALONMORPHED UnitUINamefaeriedragon=0,unituiname,`faeriedragon`,WESTRING_UNITUINAMEFAERIEDRAGON UnitUINameforceofnature=0,unituiname,`forceofnature`,WESTRING_UNITUINAMEFORCEOFNATURE UnitUINamehippogryph=0,unituiname,`hippogryph`,WESTRING_UNITUINAMEHIPPOGRYPH UnitUINameriddenhippogryph=0,unituiname,`riddenhippogryph`,WESTRING_UNITUINAMERIDDENHIPPOGRYPH UnitUINamemountaingiant=0,unituiname,`mountaingiant`,WESTRING_UNITUINAMEMOUNTAINGIANT UnitUINamehuntress=0,unituiname,`huntress`,WESTRING_UNITUINAMEHUNTRESS UnitUINamespiritofvengeance=0,unituiname,`spiritofvengeance`,WESTRING_UNITUINAMESPIRITOFVENGEANCE UnitUINamevengeance=0,unituiname,`vengeance`,WESTRING_UNITUINAMEVENGEANCE UnitUINamewisp=0,unituiname,`wisp`,WESTRING_UNITUINAMEWISP UnitUINameancientoflore=0,unituiname,`ancientoflore`,WESTRING_UNITUINAMEANCIENTOFLORE UnitUINameancientofwar=0,unituiname,`ancientofwar`,WESTRING_UNITUINAMEANCIENTOFWAR UnitUINameancientofwind=0,unituiname,`ancientofwind`,WESTRING_UNITUINAMEANCIENTOFWIND UnitUINamealtarofelders=0,unituiname,`altarofelders`,WESTRING_UNITUINAMEALTAROFELDERS UnitUINameancientofwonders=0,unituiname,`ancientofwonders`,WESTRING_UNITUINAMEANCIENTOFWONDERS UnitUINamehuntershall=0,unituiname,`huntershall`,WESTRING_UNITUINAMEHUNTERSHALL UnitUINamechimaeraroost=0,unituiname,`chimaeraroost`,WESTRING_UNITUINAMECHIMAERAROOST UnitUINameentangledgoldmine=0,unituiname,`entangledgoldmine`,WESTRING_UNITUINAMEENTANGLEDGOLDMINE UnitUINamemoonwell=0,unituiname,`moonwell`,WESTRING_UNITUINAMEMOONWELL UnitUINamenightelfshipyard=0,unituiname,`nightelfshipyard`,WESTRING_UNITUINAMENIGHTELFSHIPYARD UnitUINametreeofages=0,unituiname,`treeofages`,WESTRING_UNITUINAMETREEOFAGES UnitUINametreeofeternity=0,unituiname,`treeofeternity`,WESTRING_UNITUINAMETREEOFETERNITY UnitUINametreeoflife=0,unituiname,`treeoflife`,WESTRING_UNITUINAMETREEOFLIFE UnitUINameancientprotector=0,unituiname,`ancientprotector`,WESTRING_UNITUINAMEANCIENTPROTECTOR UnitUINamecryptlord=0,unituiname,`cryptlord`,WESTRING_UNITUINAMECRYPTLORD UnitUINamedeathknight=0,unituiname,`deathknight`,WESTRING_UNITUINAMEDEATHKNIGHT UnitUINamedreadlord=0,unituiname,`dreadlord`,WESTRING_UNITUINAMEDREADLORD UnitUINamelich=0,unituiname,`lich`,WESTRING_UNITUINAMELICH UnitUINameabomination=0,unituiname,`abomination`,WESTRING_UNITUINAMEABOMINATION UnitUINameacolyte=0,unituiname,`acolyte`,WESTRING_UNITUINAMEACOLYTE UnitUINamebanshee=0,unituiname,`banshee`,WESTRING_UNITUINAMEBANSHEE UnitUINameobsidiandestroyer=0,unituiname,`obsidiandestroyer`,WESTRING_UNITUINAMEOBSIDIANDESTROYER UnitUINamecryptfiendmorph=0,unituiname,`cryptfiendmorph`,WESTRING_UNITUINAMECRYPTFIENDMORPH UnitUINamecryptfiend=0,unituiname,`cryptfiend`,WESTRING_UNITUINAMECRYPTFIEND UnitUINamecarrionscarab1=0,unituiname,`carrionscarab1`,WESTRING_UNITUINAMECARRIONSCARAB1 UnitUINamecarrionscarab2=0,unituiname,`carrionscarab2`,WESTRING_UNITUINAMECARRIONSCARAB2 UnitUINamecarrionscarab3=0,unituiname,`carrionscarab3`,WESTRING_UNITUINAMECARRIONSCARAB3 UnitUINamecarrionscarabburrowed2=0,unituiname,`carrionscarabburrowed2`,WESTRING_UNITUINAMECARRIONSCARABBURROWED2 UnitUINamecarrionscarabburrowed3=0,unituiname,`carrionscarabburrowed3`,WESTRING_UNITUINAMECARRIONSCARABBURROWED3 UnitUINamefrostwyrm=0,unituiname,`frostwyrm`,WESTRING_UNITUINAMEFROSTWYRM UnitUINamegargoyle=0,unituiname,`gargoyle`,WESTRING_UNITUINAMEGARGOYLE UnitUINameghoul=0,unituiname,`ghoul`,WESTRING_UNITUINAMEGHOUL UnitUINamegargoylemorphed=0,unituiname,`gargoylemorphed`,WESTRING_UNITUINAMEGARGOYLEMORPHED UnitUINamelocust=0,unituiname,`locust`,WESTRING_UNITUINAMELOCUST UnitUINamemeatwagon=0,unituiname,`meatwagon`,WESTRING_UNITUINAMEMEATWAGON UnitUINamenecromancer=0,unituiname,`necromancer`,WESTRING_UNITUINAMENECROMANCER UnitUINameobsidianstatue=0,unituiname,`obsidianstatue`,WESTRING_UNITUINAMEOBSIDIANSTATUE UnitUINameplagueward=0,unituiname,`plagueward`,WESTRING_UNITUINAMEPLAGUEWARD UnitUINameshade=0,unituiname,`shade`,WESTRING_UNITUINAMESHADE UnitUINameskeletonwarrior=0,unituiname,`skeletonwarrior`,WESTRING_UNITUINAMESKELETONWARRIOR UnitUINameskeletalmage=0,unituiname,`skeletalmage`,WESTRING_UNITUINAMESKELETALMAGE UnitUINameundeadbattleship=0,unituiname,`undeadbattleship`,WESTRING_UNITUINAMEUNDEADBATTLESHIP UnitUINamealtarofdarkness=0,unituiname,`altarofdarkness`,WESTRING_UNITUINAMEALTAROFDARKNESS UnitUINameboneyard=0,unituiname,`boneyard`,WESTRING_UNITUINAMEBONEYARD UnitUINameundeadgoldmine2=0,unituiname,`undeadgoldmine2`,WESTRING_UNITUINAMEUNDEADGOLDMINE2 UnitUINamegraveyard=0,unituiname,`graveyard`,WESTRING_UNITUINAMEGRAVEYARD UnitUINamenecropolis1=0,unituiname,`necropolis1`,WESTRING_UNITUINAMENECROPOLIS1 UnitUINamenecropolis2=0,unituiname,`necropolis2`,WESTRING_UNITUINAMENECROPOLIS2 UnitUINamenecropolis=0,unituiname,`necropolis`,WESTRING_UNITUINAMENECROPOLIS UnitUINamesacrificialpit=0,unituiname,`sacrificialpit`,WESTRING_UNITUINAMESACRIFICIALPIT UnitUINamecrypt=0,unituiname,`crypt`,WESTRING_UNITUINAMECRYPT UnitUINameundeadshipyard=0,unituiname,`undeadshipyard`,WESTRING_UNITUINAMEUNDEADSHIPYARD UnitUINameslaughterhouse=0,unituiname,`slaughterhouse`,WESTRING_UNITUINAMESLAUGHTERHOUSE UnitUINametempleofthedamned=0,unituiname,`templeofthedamned`,WESTRING_UNITUINAMETEMPLEOFTHEDAMNED UnitUINametombofrelics=0,unituiname,`tombofrelics`,WESTRING_UNITUINAMETOMBOFRELICS UnitUINameziggurat1=0,unituiname,`ziggurat1`,WESTRING_UNITUINAMEZIGGURAT1 UnitUINamefrosttower=0,unituiname,`frosttower`,WESTRING_UNITUINAMEFROSTTOWER UnitUINameziggurat=0,unituiname,`ziggurat`,WESTRING_UNITUINAMEZIGGURAT UnitUINamedarkranger=0,unituiname,`darkranger`,WESTRING_UNITUINAMEDARKRANGER UnitUINamebeastmaster=0,unituiname,`beastmaster`,WESTRING_UNITUINAMEBEASTMASTER UnitUINameseawitch=0,unituiname,`seawitch`,WESTRING_UNITUINAMESEAWITCH UnitUINamepandarenbrewmaster=0,unituiname,`pandarenbrewmaster`,WESTRING_UNITUINAMEPANDARENBREWMASTER UnitUINamepitlord=0,unituiname,`pitlord`,WESTRING_UNITUINAMEPITLORD UnitUINamedarkminion1=0,unituiname,`darkminion1`,WESTRING_UNITUINAMEDARKMINION1 UnitUINamedarkminion2=0,unituiname,`darkminion2`,WESTRING_UNITUINAMEDARKMINION2 UnitUINamedarkminion3=0,unituiname,`darkminion3`,WESTRING_UNITUINAMEDARKMINION3 UnitUINamegrizzlybear1=0,unituiname,`grizzlybear1`,WESTRING_UNITUINAMEGRIZZLYBEAR1 UnitUINamegrizzlybear2=0,unituiname,`grizzlybear2`,WESTRING_UNITUINAMEGRIZZLYBEAR2 UnitUINamegrizzlybear3=0,unituiname,`grizzlybear3`,WESTRING_UNITUINAMEGRIZZLYBEAR3 UnitUINamemisha1=0,unituiname,`misha1`,WESTRING_UNITUINAMEMISHA1 UnitUINamemisha2=0,unituiname,`misha2`,WESTRING_UNITUINAMEMISHA2 UnitUINamemisha3=0,unituiname,`misha3`,WESTRING_UNITUINAMEMISHA3 UnitUINamemisha4=0,unituiname,`misha4`,WESTRING_UNITUINAMEMISHA4 UnitUINamepanda1=0,unituiname,`panda1`,WESTRING_UNITUINAMEPANDA1 UnitUINamepanda2=0,unituiname,`panda2`,WESTRING_UNITUINAMEPANDA2 UnitUINamepanda3=0,unituiname,`panda3`,WESTRING_UNITUINAMEPANDA3 UnitUINamepanda4=0,unituiname,`panda4`,WESTRING_UNITUINAMEPANDA4 UnitUINamepanda5=0,unituiname,`panda5`,WESTRING_UNITUINAMEPANDA5 UnitUINamepanda6=0,unituiname,`panda6`,WESTRING_UNITUINAMEPANDA6 UnitUINamequillbeast1=0,unituiname,`quillbeast1`,WESTRING_UNITUINAMEQUILLBEAST1 UnitUINamequillbeast2=0,unituiname,`quillbeast2`,WESTRING_UNITUINAMEQUILLBEAST2 UnitUINamequillbeast3=0,unituiname,`quillbeast3`,WESTRING_UNITUINAMEQUILLBEAST3 UnitUINamequillbeast4=0,unituiname,`quillbeast4`,WESTRING_UNITUINAMEQUILLBEAST4 UnitUINamewareagle1=0,unituiname,`wareagle1`,WESTRING_UNITUINAMEWAREAGLE1 UnitUINamewareagle2=0,unituiname,`wareagle2`,WESTRING_UNITUINAMEWAREAGLE2 UnitUINamewareagle3=0,unituiname,`wareagle3`,WESTRING_UNITUINAMEWAREAGLE3 UnitUINameazuredrake=0,unituiname,`azuredrake`,WESTRING_UNITUINAMEAZUREDRAKE UnitUINameazuredragon=0,unituiname,`azuredragon`,WESTRING_UNITUINAMEAZUREDRAGON UnitUINameazuredragonwhelp=0,unituiname,`azuredragonwhelp`,WESTRING_UNITUINAMEAZUREDRAGONWHELP UnitUINameancienthydra=0,unituiname,`ancienthydra`,WESTRING_UNITUINAMEANCIENTHYDRA UnitUINamebarbedarachnathid=0,unituiname,`barbedarachnathid`,WESTRING_UNITUINAMEBARBEDARACHNATHID UnitUINamebarbedarachnathidmerc=0,unituiname,`barbedarachnathidmerc`,WESTRING_UNITUINAMEBARBEDARACHNATHIDMERC UnitUINamecrystalarachnathid=0,unituiname,`crystalarachnathid`,WESTRING_UNITUINAMECRYSTALARACHNATHID UnitUINameearthborerarachnathid=0,unituiname,`earthborerarachnathid`,WESTRING_UNITUINAMEEARTHBORERARACHNATHID UnitUINameoverlordarachnathid=0,unituiname,`overlordarachnathid`,WESTRING_UNITUINAMEOVERLORDARACHNATHID UnitUINamewarriorarachnathid=0,unituiname,`warriorarachnathid`,WESTRING_UNITUINAMEWARRIORARACHNATHID UnitUINamebattlegolem=0,unituiname,`battlegolem`,WESTRING_UNITUINAMEBATTLEGOLEM UnitUINameassassin=0,unituiname,`assassin`,WESTRING_UNITUINAMEASSASSIN UnitUINamedoomguard=0,unituiname,`doomguard`,WESTRING_UNITUINAMEDOOMGUARD UnitUINamedoomguardsummoned=0,unituiname,`doomguardsummoned`,WESTRING_UNITUINAMEDOOMGUARDSUMMONED UnitUINamebandit=0,unituiname,`bandit`,WESTRING_UNITUINAMEBANDIT UnitUINamebluedragonspawnapprentice=0,unituiname,`bluedragonspawnapprentice`,WESTRING_UNITUINAMEBLUEDRAGONSPAWNAPPRENTICE UnitUINameblackdrake=0,unituiname,`blackdrake`,WESTRING_UNITUINAMEBLACKDRAKE UnitUINamebluedragonspawnmeddler=0,unituiname,`bluedragonspawnmeddler`,WESTRING_UNITUINAMEBLUEDRAGONSPAWNMEDDLER UnitUINamebluedragonspawnoverseer=0,unituiname,`bluedragonspawnoverseer`,WESTRING_UNITUINAMEBLUEDRAGONSPAWNOVERSEER UnitUINameblackdragonwhelp=0,unituiname,`blackdragonwhelp`,WESTRING_UNITUINAMEBLACKDRAGONWHELP UnitUINamebluedragonspawnsorceror=0,unituiname,`bluedragonspawnsorceror`,WESTRING_UNITUINAMEBLUEDRAGONSPAWNSORCEROR UnitUINamebluedragonspawnwarrior=0,unituiname,`bluedragonspawnwarrior`,WESTRING_UNITUINAMEBLUEDRAGONSPAWNWARRIOR UnitUINamebanditlord=0,unituiname,`banditlord`,WESTRING_UNITUINAMEBANDITLORD UnitUINamebarbedarachnathidburrowed=0,unituiname,`barbedarachnathidburrowed`,WESTRING_UNITUINAMEBARBEDARACHNATHIDBURROWED UnitUINametransportship=0,unituiname,`transportship`,WESTRING_UNITUINAMETRANSPORTSHIP UnitUINamebrigand=0,unituiname,`brigand`,WESTRING_UNITUINAMEBRIGAND UnitUINameblackdragon=0,unituiname,`blackdragon`,WESTRING_UNITUINAMEBLACKDRAGON UnitUINamebronzedragon=0,unituiname,`bronzedragon`,WESTRING_UNITUINAMEBRONZEDRAGON UnitUINamebronzedrake=0,unituiname,`bronzedrake`,WESTRING_UNITUINAMEBRONZEDRAKE UnitUINamebronzedragonwhelp=0,unituiname,`bronzedragonwhelp`,WESTRING_UNITUINAMEBRONZEDRAGONWHELP UnitUINamecentaurarcher=0,unituiname,`centaurarcher`,WESTRING_UNITUINAMECENTAURARCHER UnitUINamecentauroutrunner=0,unituiname,`centauroutrunner`,WESTRING_UNITUINAMECENTAUROUTRUNNER UnitUINamecentaurdrudge=0,unituiname,`centaurdrudge`,WESTRING_UNITUINAMECENTAURDRUDGE UnitUINamewateryminioncliffrunner=0,unituiname,`wateryminioncliffrunner`,WESTRING_UNITUINAMEWATERYMINIONCLIFFRUNNER UnitUINamecentaurimpaler=0,unituiname,`centaurimpaler`,WESTRING_UNITUINAMECENTAURIMPALER UnitUINamecentaursorceror=0,unituiname,`centaursorceror`,WESTRING_UNITUINAMECENTAURSORCEROR UnitUINamecentaurkhan=0,unituiname,`centaurkhan`,WESTRING_UNITUINAMECENTAURKHAN UnitUINamesuccubus=0,unituiname,`succubus`,WESTRING_UNITUINAMESUCCUBUS UnitUINamemaidenofpain=0,unituiname,`maidenofpain`,WESTRING_UNITUINAMEMAIDENOFPAIN UnitUINamequeenofsuffering=0,unituiname,`queenofsuffering`,WESTRING_UNITUINAMEQUEENOFSUFFERING UnitUINameviletemptress=0,unituiname,`viletemptress`,WESTRING_UNITUINAMEVILETEMPTRESS UnitUINameviletormentor=0,unituiname,`viletormentor`,WESTRING_UNITUINAMEVILETORMENTOR UnitUINamerevenantofthedepths=0,unituiname,`revenantofthedepths`,WESTRING_UNITUINAMEREVENANTOFTHEDEPTHS UnitUINamedarktrollberserker=0,unituiname,`darktrollberserker`,WESTRING_UNITUINAMEDARKTROLLBERSERKER UnitUINamedarktrollhighpriest=0,unituiname,`darktrollhighpriest`,WESTRING_UNITUINAMEDARKTROLLHIGHPRIEST UnitUINamedarktrollshadowpriest=0,unituiname,`darktrollshadowpriest`,WESTRING_UNITUINAMEDARKTROLLSHADOWPRIEST UnitUINamedarktroll=0,unituiname,`darktroll`,WESTRING_UNITUINAMEDARKTROLL UnitUINamedarktrolltrapper=0,unituiname,`darktrolltrapper`,WESTRING_UNITUINAMEDARKTROLLTRAPPER UnitUINamedarktrollwarlord=0,unituiname,`darktrollwarlord`,WESTRING_UNITUINAMEDARKTROLLWARLORD UnitUINameelderhydra=0,unituiname,`elderhydra`,WESTRING_UNITUINAMEELDERHYDRA UnitUINamebereserkelemental=0,unituiname,`bereserkelemental`,WESTRING_UNITUINAMEBERESERKELEMENTAL UnitUINameenragedelemental=0,unituiname,`enragedelemental`,WESTRING_UNITUINAMEENRAGEDELEMENTAL UnitUINamecorruptedent=0,unituiname,`corruptedent`,WESTRING_UNITUINAMECORRUPTEDENT UnitUINameenforcer=0,unituiname,`enforcer`,WESTRING_UNITUINAMEENFORCER UnitUINamepoisonent=0,unituiname,`poisonent`,WESTRING_UNITUINAMEPOISONENT UnitUINameplagueent=0,unituiname,`plagueent`,WESTRING_UNITUINAMEPLAGUEENT UnitUINameeredardiabolist=0,unituiname,`eredardiabolist`,WESTRING_UNITUINAMEEREDARDIABOLIST UnitUINameeredarsorceror=0,unituiname,`eredarsorceror`,WESTRING_UNITUINAMEEREDARSORCEROR UnitUINameeredarwarlock=0,unituiname,`eredarwarlock`,WESTRING_UNITUINAMEEREDARWARLOCK UnitUINamefelstalker=0,unituiname,`felstalker`,WESTRING_UNITUINAMEFELSTALKER UnitUINamebloodfiend=0,unituiname,`bloodfiend`,WESTRING_UNITUINAMEBLOODFIEND UnitUINameforgottenone=0,unituiname,`forgottenone`,WESTRING_UNITUINAMEFORGOTTENONE UnitUINametentacle=0,unituiname,`tentacle`,WESTRING_UNITUINAMETENTACLE UnitUINamefelguard=0,unituiname,`felguard`,WESTRING_UNITUINAMEFELGUARD UnitUINamefacelessonedeathbringer=0,unituiname,`facelessonedeathbringer`,WESTRING_UNITUINAMEFACELESSONEDEATHBRINGER UnitUINamefacelessonetrickster=0,unituiname,`facelessonetrickster`,WESTRING_UNITUINAMEFACELESSONETRICKSTER UnitUINamefacelessoneterror=0,unituiname,`facelessoneterror`,WESTRING_UNITUINAMEFACELESSONETERROR UnitUINameoverlord=0,unituiname,`overlord`,WESTRING_UNITUINAMEOVERLORD UnitUINamepolarfurbolgchampion=0,unituiname,`polarfurbolgchampion`,WESTRING_UNITUINAMEPOLARFURBOLGCHAMPION UnitUINamepolarfurbolgeldershaman=0,unituiname,`polarfurbolgeldershaman`,WESTRING_UNITUINAMEPOLARFURBOLGELDERSHAMAN UnitUINamepolarfurbolg=0,unituiname,`polarfurbolg`,WESTRING_UNITUINAMEPOLARFURBOLG UnitUINamepolarfurbolgshaman=0,unituiname,`polarfurbolgshaman`,WESTRING_UNITUINAMEPOLARFURBOLGSHAMAN UnitUINamepolarfurbolgtracker=0,unituiname,`polarfurbolgtracker`,WESTRING_UNITUINAMEPOLARFURBOLGTRACKER UnitUINamepolarfurbolgursawarrior=0,unituiname,`polarfurbolgursawarrior`,WESTRING_UNITUINAMEPOLARFURBOLGURSAWARRIOR UnitUINamefurbolgancient=0,unituiname,`furbolgancient`,WESTRING_UNITUINAMEFURBOLGANCIENT UnitUINamefurbolgtracker=0,unituiname,`furbolgtracker`,WESTRING_UNITUINAMEFURBOLGTRACKER UnitUINamefurbolgeldershaman=0,unituiname,`furbolgeldershaman`,WESTRING_UNITUINAMEFURBOLGELDERSHAMAN UnitUINamefurbolgchampion=0,unituiname,`furbolgchampion`,WESTRING_UNITUINAMEFURBOLGCHAMPION UnitUINamefurbolg=0,unituiname,`furbolg`,WESTRING_UNITUINAMEFURBOLG UnitUINamefurbolgpanda=0,unituiname,`furbolgpanda`,WESTRING_UNITUINAMEFURBOLGPANDA UnitUINamefurbolgshaman=0,unituiname,`furbolgshaman`,WESTRING_UNITUINAMEFURBOLGSHAMAN UnitUINameforesttrollhighpriest=0,unituiname,`foresttrollhighpriest`,WESTRING_UNITUINAMEFORESTTROLLHIGHPRIEST UnitUINameforesttrollshadowpriest=0,unituiname,`foresttrollshadowpriest`,WESTRING_UNITUINAMEFORESTTROLLSHADOWPRIEST UnitUINameforesttrollberserker=0,unituiname,`foresttrollberserker`,WESTRING_UNITUINAMEFORESTTROLLBERSERKER UnitUINameforesttrollking=0,unituiname,`foresttrollking`,WESTRING_UNITUINAMEFORESTTROLLKING UnitUINameforesttroll=0,unituiname,`foresttroll`,WESTRING_UNITUINAMEFORESTTROLL UnitUINameforesttrolltrapper=0,unituiname,`foresttrolltrapper`,WESTRING_UNITUINAMEFORESTTROLLTRAPPER UnitUINamegreendrake=0,unituiname,`greendrake`,WESTRING_UNITUINAMEGREENDRAKE UnitUINamegranitegolem=0,unituiname,`granitegolem`,WESTRING_UNITUINAMEGRANITEGOLEM UnitUINameghost=0,unituiname,`ghost`,WESTRING_UNITUINAMEGHOST UnitUINamewraith=0,unituiname,`wraith`,WESTRING_UNITUINAMEWRAITH UnitUINamegoblinshredder=0,unituiname,`goblinshredder`,WESTRING_UNITUINAMEGOBLINSHREDDER UnitUINamegoblinlandmine=0,unituiname,`goblinlandmine`,WESTRING_UNITUINAMEGOBLINLANDMINE UnitUINamegnollpoacher=0,unituiname,`gnollpoacher`,WESTRING_UNITUINAMEGNOLLPOACHER UnitUINamegnollbrute=0,unituiname,`gnollbrute`,WESTRING_UNITUINAMEGNOLLBRUTE UnitUINamegnoll1=0,unituiname,`gnoll1`,WESTRING_UNITUINAMEGNOLL1 UnitUINamegnollassassin=0,unituiname,`gnollassassin`,WESTRING_UNITUINAMEGNOLLASSASSIN UnitUINamegnollking=0,unituiname,`gnollking`,WESTRING_UNITUINAMEGNOLLKING UnitUINamegnoll3=0,unituiname,`gnoll3`,WESTRING_UNITUINAMEGNOLL3 UnitUINamegreendragon=0,unituiname,`greendragon`,WESTRING_UNITUINAMEGREENDRAGON UnitUINamemudgolem=0,unituiname,`mudgolem`,WESTRING_UNITUINAMEMUDGOLEM UnitUINamegreendragonwhelp=0,unituiname,`greendragonwhelp`,WESTRING_UNITUINAMEGREENDRAGONWHELP UnitUINamegoblinsapper=0,unituiname,`goblinsapper`,WESTRING_UNITUINAMEGOBLINSAPPER UnitUINamerockgolem=0,unituiname,`rockgolem`,WESTRING_UNITUINAMEROCKGOLEM UnitUINameharpyscout=0,unituiname,`harpyscout`,WESTRING_UNITUINAMEHARPYSCOUT UnitUINamedeceiver=0,unituiname,`deceiver`,WESTRING_UNITUINAMEDECEIVER UnitUINamefallenpriest=0,unituiname,`fallenpriest`,WESTRING_UNITUINAMEFALLENPRIEST UnitUINameheretic=0,unituiname,`heretic`,WESTRING_UNITUINAMEHERETIC UnitUINameharpyhag=0,unituiname,`harpyhag`,WESTRING_UNITUINAMEHARPYHAG UnitUINameharpyqueen=0,unituiname,`harpyqueen`,WESTRING_UNITUINAMEHARPYQUEEN UnitUINameharpyrogue=0,unituiname,`harpyrogue`,WESTRING_UNITUINAMEHARPYROGUE UnitUINameharpywitch=0,unituiname,`harpywitch`,WESTRING_UNITUINAMEHARPYWITCH UnitUINamecampaignturtle=0,unituiname,`campaignturtle`,WESTRING_UNITUINAMECAMPAIGNTURTLE UnitUINamehydra=0,unituiname,`hydra`,WESTRING_UNITUINAMEHYDRA UnitUINamehydrahatchling=0,unituiname,`hydrahatchling`,WESTRING_UNITUINAMEHYDRAHATCHLING UnitUINameinfernaljuggernaut=0,unituiname,`infernaljuggernaut`,WESTRING_UNITUINAMEINFERNALJUGGERNAUT UnitUINameinfernalcontraption=0,unituiname,`infernalcontraption`,WESTRING_UNITUINAMEINFERNALCONTRAPTION UnitUINameinfernal=0,unituiname,`infernal`,WESTRING_UNITUINAMEINFERNAL UnitUINameinfernalmachine=0,unituiname,`infernalmachine`,WESTRING_UNITUINAMEINFERNALMACHINE UnitUINameicetrollhighpriest=0,unituiname,`icetrollhighpriest`,WESTRING_UNITUINAMEICETROLLHIGHPRIEST UnitUINameicetrollshadowpriest=0,unituiname,`icetrollshadowpriest`,WESTRING_UNITUINAMEICETROLLSHADOWPRIEST UnitUINameicetroll=0,unituiname,`icetroll`,WESTRING_UNITUINAMEICETROLL UnitUINameicetrollberserker=0,unituiname,`icetrollberserker`,WESTRING_UNITUINAMEICETROLLBERSERKER UnitUINameicetrolltrapper=0,unituiname,`icetrolltrapper`,WESTRING_UNITUINAMEICETROLLTRAPPER UnitUINameicetrollwarlord=0,unituiname,`icetrollwarlord`,WESTRING_UNITUINAMEICETROLLWARLORD UnitUINameenrangedjunglestalker=0,unituiname,`enrangedjunglestalker`,WESTRING_UNITUINAMEENRANGEDJUNGLESTALKER UnitUINameelderjunglestalker=0,unituiname,`elderjunglestalker`,WESTRING_UNITUINAMEELDERJUNGLESTALKER UnitUINamejunglestalker=0,unituiname,`junglestalker`,WESTRING_UNITUINAMEJUNGLESTALKER UnitUINamekobold=0,unituiname,`kobold`,WESTRING_UNITUINAMEKOBOLD UnitUINamekoboldgeomancer=0,unituiname,`koboldgeomancer`,WESTRING_UNITUINAMEKOBOLDGEOMANCER UnitUINamekoboldtaskmaster=0,unituiname,`koboldtaskmaster`,WESTRING_UNITUINAMEKOBOLDTASKMASTER UnitUINamekobolttunneler=0,unituiname,`kobolttunneler`,WESTRING_UNITUINAMEKOBOLTTUNNELER UnitUINamelobstrokkdeepseer=0,unituiname,`lobstrokkdeepseer`,WESTRING_UNITUINAMELOBSTROKKDEEPSEER UnitUINamelobstrokktidallord=0,unituiname,`lobstrokktidallord`,WESTRING_UNITUINAMELOBSTROKKTIDALLORD UnitUINamelobstrokkpooldweller=0,unituiname,`lobstrokkpooldweller`,WESTRING_UNITUINAMELOBSTROKKPOOLDWELLER UnitUINamelobstrokkprawn=0,unituiname,`lobstrokkprawn`,WESTRING_UNITUINAMELOBSTROKKPRAWN UnitUINamelobstrokkprawnsummoned=0,unituiname,`lobstrokkprawnsummoned`,WESTRING_UNITUINAMELOBSTROKKPRAWNSUMMONED UnitUINamedeeplordrevenant=0,unituiname,`deeplordrevenant`,WESTRING_UNITUINAMEDEEPLORDREVENANT UnitUINamelobstrokksnapper=0,unituiname,`lobstrokksnapper`,WESTRING_UNITUINAMELOBSTROKKSNAPPER UnitUINamelobstrokktidecaller=0,unituiname,`lobstrokktidecaller`,WESTRING_UNITUINAMELOBSTROKKTIDECALLER UnitUINamelightninglizard=0,unituiname,`lightninglizard`,WESTRING_UNITUINAMELIGHTNINGLIZARD UnitUINamemonsterlure=0,unituiname,`monsterlure`,WESTRING_UNITUINAMEMONSTERLURE UnitUINamemammoth=0,unituiname,`mammoth`,WESTRING_UNITUINAMEMAMMOTH UnitUINamemurgulbloodgill=0,unituiname,`murgulbloodgill`,WESTRING_UNITUINAMEMURGULBLOODGILL UnitUINamemurgulcliffrunner=0,unituiname,`murgulcliffrunner`,WESTRING_UNITUINAMEMURGULCLIFFRUNNER UnitUINamediremammoth=0,unituiname,`diremammoth`,WESTRING_UNITUINAMEDIREMAMMOTH UnitUINamemurlocflesheater=0,unituiname,`murlocflesheater`,WESTRING_UNITUINAMEMURLOCFLESHEATER UnitUINamemagnataurdestroyer=0,unituiname,`magnataurdestroyer`,WESTRING_UNITUINAMEMAGNATAURDESTROYER UnitUINamemagnataurreaver=0,unituiname,`magnataurreaver`,WESTRING_UNITUINAMEMAGNATAURREAVER UnitUINamemagnataurwarrior=0,unituiname,`magnataurwarrior`,WESTRING_UNITUINAMEMAGNATAURWARRIOR UnitUINameicetuskmammoth=0,unituiname,`icetuskmammoth`,WESTRING_UNITUINAMEICETUSKMAMMOTH UnitUINamemurlocmutant=0,unituiname,`murlocmutant`,WESTRING_UNITUINAMEMURLOCMUTANT UnitUINamemurlocplaguebearer=0,unituiname,`murlocplaguebearer`,WESTRING_UNITUINAMEMURLOCPLAGUEBEARER UnitUINamemurloctiderunner=0,unituiname,`murloctiderunner`,WESTRING_UNITUINAMEMURLOCTIDERUNNER UnitUINamemurlocnightcrawler=0,unituiname,`murlocnightcrawler`,WESTRING_UNITUINAMEMURLOCNIGHTCRAWLER UnitUINamemurlochuntsman=0,unituiname,`murlochuntsman`,WESTRING_UNITUINAMEMURLOCHUNTSMAN UnitUINamemurgulreaver=0,unituiname,`murgulreaver`,WESTRING_UNITUINAMEMURGULREAVER UnitUINamemurgulshadowcaster=0,unituiname,`murgulshadowcaster`,WESTRING_UNITUINAMEMURGULSHADOWCASTER UnitUINamemurgulsnarecaster=0,unituiname,`murgulsnarecaster`,WESTRING_UNITUINAMEMURGULSNARECASTER UnitUINamemurgultidewarrior=0,unituiname,`murgultidewarrior`,WESTRING_UNITUINAMEMURGULTIDEWARRIOR UnitUINamenagamyrmidon=0,unituiname,`nagamyrmidon`,WESTRING_UNITUINAMENAGAMYRMIDON UnitUINamenagamyrmidonmorph=0,unituiname,`nagamyrmidonmorph`,WESTRING_UNITUINAMENAGAMYRMIDONMORPH UnitUINamenetherdrake=0,unituiname,`netherdrake`,WESTRING_UNITUINAMENETHERDRAKE UnitUINamenetherdragon=0,unituiname,`netherdragon`,WESTRING_UNITUINAMENETHERDRAGON UnitUINamenetherdragonhatchling=0,unituiname,`netherdragonhatchling`,WESTRING_UNITUINAMENETHERDRAGONHATCHLING UnitUINamenagamurgul=0,unituiname,`nagamurgul`,WESTRING_UNITUINAMENAGAMURGUL UnitUINamenagaroyalguard=0,unituiname,`nagaroyalguard`,WESTRING_UNITUINAMENAGAROYALGUARD UnitUINamenagaroyalguardmorph=0,unituiname,`nagaroyalguardmorph`,WESTRING_UNITUINAMENAGAROYALGUARDMORPH UnitUINamesummoner=0,unituiname,`summoner`,WESTRING_UNITUINAMESUMMONER UnitUINamesiren=0,unituiname,`siren`,WESTRING_UNITUINAMESIREN UnitUINamenerubianwarrior=0,unituiname,`nerubianwarrior`,WESTRING_UNITUINAMENERUBIANWARRIOR UnitUINamenerubianwebspinner=0,unituiname,`nerubianwebspinner`,WESTRING_UNITUINAMENERUBIANWEBSPINNER UnitUINamenerubianqueen=0,unituiname,`nerubianqueen`,WESTRING_UNITUINAMENERUBIANQUEEN UnitUINamenerubianseer=0,unituiname,`nerubianseer`,WESTRING_UNITUINAMENERUBIANSEER UnitUINamenerubianspiderlord=0,unituiname,`nerubianspiderlord`,WESTRING_UNITUINAMENERUBIANSPIDERLORD UnitUINamestonemaulwarchief=0,unituiname,`stonemaulwarchief`,WESTRING_UNITUINAMESTONEMAULWARCHIEF UnitUINameogrelord=0,unituiname,`ogrelord`,WESTRING_UNITUINAMEOGRELORD UnitUINameogre2=0,unituiname,`ogre2`,WESTRING_UNITUINAMEOGRE2 UnitUINamestonemaulmagi=0,unituiname,`stonemaulmagi`,WESTRING_UNITUINAMESTONEMAULMAGI UnitUINamestonemaulogre=0,unituiname,`stonemaulogre`,WESTRING_UNITUINAMESTONEMAULOGRE UnitUINameogre1=0,unituiname,`ogre1`,WESTRING_UNITUINAMEOGRE1 UnitUINameogremagi=0,unituiname,`ogremagi`,WESTRING_UNITUINAMEOGREMAGI UnitUINameowlbear=0,unituiname,`owlbear`,WESTRING_UNITUINAMEOWLBEAR UnitUINameenragedowlbear=0,unituiname,`enragedowlbear`,WESTRING_UNITUINAMEENRAGEDOWLBEAR UnitUINameberserkowlbear=0,unituiname,`berserkowlbear`,WESTRING_UNITUINAMEBERSERKOWLBEAR UnitUINamepurplefelstalker=0,unituiname,`purplefelstalker`,WESTRING_UNITUINAMEPURPLEFELSTALKER UnitUINamefelravager=0,unituiname,`felravager`,WESTRING_UNITUINAMEFELRAVAGER UnitUINamepolarbear=0,unituiname,`polarbear`,WESTRING_UNITUINAMEPOLARBEAR UnitUINamegiantpolarbear=0,unituiname,`giantpolarbear`,WESTRING_UNITUINAMEGIANTPOLARBEAR UnitUINamequillboarhunter=0,unituiname,`quillboarhunter`,WESTRING_UNITUINAMEQUILLBOARHUNTER UnitUINamereddragonwhelp=0,unituiname,`reddragonwhelp`,WESTRING_UNITUINAMEREDDRAGONWHELP UnitUINamereddrake=0,unituiname,`reddrake`,WESTRING_UNITUINAMEREDDRAKE UnitUINamereefelemental=0,unituiname,`reefelemental`,WESTRING_UNITUINAMEREEFELEMENTAL UnitUINamerogue=0,unituiname,`rogue`,WESTRING_UNITUINAMEROGUE UnitUINamedeathrevenant=0,unituiname,`deathrevenant`,WESTRING_UNITUINAMEDEATHREVENANT UnitUINamefirerevenant=0,unituiname,`firerevenant`,WESTRING_UNITUINAMEFIREREVENANT UnitUINameicerevenant=0,unituiname,`icerevenant`,WESTRING_UNITUINAMEICEREVENANT UnitUINamelightningrevenant=0,unituiname,`lightningrevenant`,WESTRING_UNITUINAMELIGHTNINGREVENANT UnitUINamefrostrevenant=0,unituiname,`frostrevenant`,WESTRING_UNITUINAMEFROSTREVENANT UnitUINamereddragon=0,unituiname,`reddragon`,WESTRING_UNITUINAMEREDDRAGON UnitUINamerazormanebrute=0,unituiname,`razormanebrute`,WESTRING_UNITUINAMERAZORMANEBRUTE UnitUINamerazormanechieftain=0,unituiname,`razormanechieftain`,WESTRING_UNITUINAMERAZORMANECHIEFTAIN UnitUINamerazormanemedicineman=0,unituiname,`razormanemedicineman`,WESTRING_UNITUINAMERAZORMANEMEDICINEMAN UnitUINamerazormanescout=0,unituiname,`razormanescout`,WESTRING_UNITUINAMERAZORMANESCOUT UnitUINamequillboar=0,unituiname,`quillboar`,WESTRING_UNITUINAMEQUILLBOAR UnitUINamesatyrtrickster=0,unituiname,`satyrtrickster`,WESTRING_UNITUINAMESATYRTRICKSTER UnitUINamebroodmother=0,unituiname,`broodmother`,WESTRING_UNITUINAMEBROODMOTHER UnitUINamesnapdragonmorph=0,unituiname,`snapdragonmorph`,WESTRING_UNITUINAMESNAPDRAGONMORPH UnitUINamespidercrab2=0,unituiname,`spidercrab2`,WESTRING_UNITUINAMESPIDERCRAB2 UnitUINamespidercrab3=0,unituiname,`spidercrab3`,WESTRING_UNITUINAMESPIDERCRAB3 UnitUINamespidercrab=0,unituiname,`spidercrab`,WESTRING_UNITUINAMESPIDERCRAB UnitUINameseaelemental=0,unituiname,`seaelemental`,WESTRING_UNITUINAMESEAELEMENTAL UnitUINameseagiantbehemoth=0,unituiname,`seagiantbehemoth`,WESTRING_UNITUINAMESEAGIANTBEHEMOTH UnitUINamesiegegolem=0,unituiname,`siegegolem`,WESTRING_UNITUINAMESIEGEGOLEM UnitUINameseagianthunter=0,unituiname,`seagianthunter`,WESTRING_UNITUINAMESEAGIANTHUNTER UnitUINameseagiant=0,unituiname,`seagiant`,WESTRING_UNITUINAMESEAGIANT UnitUINamegiantspider=0,unituiname,`giantspider`,WESTRING_UNITUINAMEGIANTSPIDER UnitUINameskeletalarcher=0,unituiname,`skeletalarcher`,WESTRING_UNITUINAMESKELETALARCHER UnitUINameskeleton=0,unituiname,`skeleton`,WESTRING_UNITUINAMESKELETON UnitUINameburningarcher=0,unituiname,`burningarcher`,WESTRING_UNITUINAMEBURNINGARCHER UnitUINamegiantskeleton=0,unituiname,`giantskeleton`,WESTRING_UNITUINAMEGIANTSKELETON UnitUINameskeletalmarksman=0,unituiname,`skeletalmarksman`,WESTRING_UNITUINAMESKELETALMARKSMAN UnitUINameskeletalorc=0,unituiname,`skeletalorc`,WESTRING_UNITUINAMESKELETALORC UnitUINamesludgeflinger=0,unituiname,`sludgeflinger`,WESTRING_UNITUINAMESLUDGEFLINGER UnitUINamesalamanderhatchling=0,unituiname,`salamanderhatchling`,WESTRING_UNITUINAMESALAMANDERHATCHLING UnitUINamesalamanderlord=0,unituiname,`salamanderlord`,WESTRING_UNITUINAMESALAMANDERLORD UnitUINamesludgeminion=0,unituiname,`sludgeminion`,WESTRING_UNITUINAMESLUDGEMINION UnitUINamesludgemonstrosity=0,unituiname,`sludgemonstrosity`,WESTRING_UNITUINAMESLUDGEMONSTROSITY UnitUINamesalamander=0,unituiname,`salamander`,WESTRING_UNITUINAMESALAMANDER UnitUINamesalamandervizier=0,unituiname,`salamandervizier`,WESTRING_UNITUINAMESALAMANDERVIZIER UnitUINamesnapdragon=0,unituiname,`snapdragon`,WESTRING_UNITUINAMESNAPDRAGON UnitUINamewateryminionsnarecaster=0,unituiname,`wateryminionsnarecaster`,WESTRING_UNITUINAMEWATERYMINIONSNARECASTER UnitUINameskeletalorcchampion=0,unituiname,`skeletalorcchampion`,WESTRING_UNITUINAMESKELETALORCCHAMPION UnitUINameskeletalorcgrunt=0,unituiname,`skeletalorcgrunt`,WESTRING_UNITUINAMESKELETALORCGRUNT UnitUINamespiderblack=0,unituiname,`spiderblack`,WESTRING_UNITUINAMESPIDERBLACK UnitUINamespiderling=0,unituiname,`spiderling`,WESTRING_UNITUINAMESPIDERLING UnitUINameforestspider=0,unituiname,`forestspider`,WESTRING_UNITUINAMEFORESTSPIDER UnitUINamespiritpig=0,unituiname,`spiritpig`,WESTRING_UNITUINAMESPIRITPIG UnitUINamespider=0,unituiname,`spider`,WESTRING_UNITUINAMESPIDER UnitUINameancientsasquatch=0,unituiname,`ancientsasquatch`,WESTRING_UNITUINAMEANCIENTSASQUATCH UnitUINameeldersasquatch=0,unituiname,`eldersasquatch`,WESTRING_UNITUINAMEELDERSASQUATCH UnitUINamesasquatchoracle=0,unituiname,`sasquatchoracle`,WESTRING_UNITUINAMESASQUATCHORACLE UnitUINamesasquatch=0,unituiname,`sasquatch`,WESTRING_UNITUINAMESASQUATCH UnitUINamestormreaverapprentice=0,unituiname,`stormreaverapprentice`,WESTRING_UNITUINAMESTORMREAVERAPPRENTICE UnitUINamestormreaverhermit=0,unituiname,`stormreaverhermit`,WESTRING_UNITUINAMESTORMREAVERHERMIT UnitUINamestormreavernecrolyte=0,unituiname,`stormreavernecrolyte`,WESTRING_UNITUINAMESTORMREAVERNECROLYTE UnitUINamerevenantoftheseas=0,unituiname,`revenantoftheseas`,WESTRING_UNITUINAMEREVENANTOFTHESEAS UnitUINamestormreaverwarlock=0,unituiname,`stormreaverwarlock`,WESTRING_UNITUINAMESTORMREAVERWARLOCK UnitUINamespittingspider=0,unituiname,`spittingspider`,WESTRING_UNITUINAMESPITTINGSPIDER UnitUINamesatyrhellcaller=0,unituiname,`satyrhellcaller`,WESTRING_UNITUINAMESATYRHELLCALLER UnitUINamesatyrsoulstealer=0,unituiname,`satyrsoulstealer`,WESTRING_UNITUINAMESATYRSOULSTEALER UnitUINamesatyrshadowdancer=0,unituiname,`satyrshadowdancer`,WESTRING_UNITUINAMESATYRSHADOWDANCER UnitUINamestormwyrm=0,unituiname,`stormwyrm`,WESTRING_UNITUINAMESTORMWYRM UnitUINamesatyr=0,unituiname,`satyr`,WESTRING_UNITUINAMESATYR UnitUINamethunderlizard=0,unituiname,`thunderlizard`,WESTRING_UNITUINAMETHUNDERLIZARD UnitUINametuskarrspearman=0,unituiname,`tuskarrspearman`,WESTRING_UNITUINAMETUSKARRSPEARMAN UnitUINametuskarrchieftain=0,unituiname,`tuskarrchieftain`,WESTRING_UNITUINAMETUSKARRCHIEFTAIN UnitUINametuskarrfighter=0,unituiname,`tuskarrfighter`,WESTRING_UNITUINAMETUSKARRFIGHTER UnitUINametuskarrhealer=0,unituiname,`tuskarrhealer`,WESTRING_UNITUINAMETUSKARRHEALER UnitUINametuskarrsorceror=0,unituiname,`tuskarrsorceror`,WESTRING_UNITUINAMETUSKARRSORCEROR UnitUINametuskarrtrapper=0,unituiname,`tuskarrtrapper`,WESTRING_UNITUINAMETUSKARRTRAPPER UnitUINametuskarrwarrior=0,unituiname,`tuskarrwarrior`,WESTRING_UNITUINAMETUSKARRWARRIOR UnitUINametornado=0,unituiname,`tornado`,WESTRING_UNITUINAMETORNADO UnitUINamedragonturtle=0,unituiname,`dragonturtle`,WESTRING_UNITUINAMEDRAGONTURTLE UnitUINamegargantuanseaturtle=0,unituiname,`gargantuanseaturtle`,WESTRING_UNITUINAMEGARGANTUANSEATURTLE UnitUINameseaturtlehatchling=0,unituiname,`seaturtlehatchling`,WESTRING_UNITUINAMESEATURTLEHATCHLING UnitUINameseaturtle=0,unituiname,`seaturtle`,WESTRING_UNITUINAMESEATURTLE UnitUINamegiantseaturtle=0,unituiname,`giantseaturtle`,WESTRING_UNITUINAMEGIANTSEATURTLE UnitUINamerevenantofthetides=0,unituiname,`revenantofthetides`,WESTRING_UNITUINAMEREVENANTOFTHETIDES UnitUINamewateryminiontidewarrior=0,unituiname,`wateryminiontidewarrior`,WESTRING_UNITUINAMEWATERYMINIONTIDEWARRIOR UnitUINameunbrokendarkhunter=0,unituiname,`unbrokendarkhunter`,WESTRING_UNITUINAMEUNBROKENDARKHUNTER UnitUINameunbrokenrager=0,unituiname,`unbrokenrager`,WESTRING_UNITUINAMEUNBROKENRAGER UnitUINameunbrokendarkweaver=0,unituiname,`unbrokendarkweaver`,WESTRING_UNITUINAMEUNBROKENDARKWEAVER UnitUINameeldervoidwalker=0,unituiname,`eldervoidwalker`,WESTRING_UNITUINAMEELDERVOIDWALKER UnitUINamegreatervoidwalker=0,unituiname,`greatervoidwalker`,WESTRING_UNITUINAMEGREATERVOIDWALKER UnitUINamelesservoidwalker=0,unituiname,`lesservoidwalker`,WESTRING_UNITUINAMELESSERVOIDWALKER UnitUINamevoidwalker=0,unituiname,`voidwalker`,WESTRING_UNITUINAMEVOIDWALKER UnitUINamewendigo1=0,unituiname,`wendigo1`,WESTRING_UNITUINAMEWENDIGO1 UnitUINamenagacoutl=0,unituiname,`nagacoutl`,WESTRING_UNITUINAMENAGACOUTL UnitUINameapprenticewizard=0,unituiname,`apprenticewizard`,WESTRING_UNITUINAMEAPPRENTICEWIZARD UnitUINamedirewolf=0,unituiname,`direwolf`,WESTRING_UNITUINAMEDIREWOLF UnitUINamegiantwolf=0,unituiname,`giantwolf`,WESTRING_UNITUINAMEGIANTWOLF UnitUINametimberwolf=0,unituiname,`timberwolf`,WESTRING_UNITUINAMETIMBERWOLF UnitUINameancientwendigo=0,unituiname,`ancientwendigo`,WESTRING_UNITUINAMEANCIENTWENDIGO UnitUINameelderwendigo=0,unituiname,`elderwendigo`,WESTRING_UNITUINAMEELDERWENDIGO UnitUINamewendigoshaman=0,unituiname,`wendigoshaman`,WESTRING_UNITUINAMEWENDIGOSHAMAN UnitUINamewargolem=0,unituiname,`wargolem`,WESTRING_UNITUINAMEWARGOLEM UnitUINamewindserpent=0,unituiname,`windserpent`,WESTRING_UNITUINAMEWINDSERPENT UnitUINamewhitedirewolf=0,unituiname,`whitedirewolf`,WESTRING_UNITUINAMEWHITEDIREWOLF UnitUINamewhitewolf=0,unituiname,`whitewolf`,WESTRING_UNITUINAMEWHITEWOLF UnitUINamegiantwhitewolf=0,unituiname,`giantwhitewolf`,WESTRING_UNITUINAMEGIANTWHITEWOLF UnitUINamedarkwizard=0,unituiname,`darkwizard`,WESTRING_UNITUINAMEDARKWIZARD UnitUINamerenegadewizard=0,unituiname,`renegadewizard`,WESTRING_UNITUINAMERENEGADEWIZARD UnitUINameroguewizard=0,unituiname,`roguewizard`,WESTRING_UNITUINAMEROGUEWIZARD UnitUINamegoblinzeppelin=0,unituiname,`goblinzeppelin`,WESTRING_UNITUINAMEGOBLINZEPPELIN UnitUINamezombie=0,unituiname,`zombie`,WESTRING_UNITUINAMEZOMBIE UnitUINamechaplain=0,unituiname,`chaplain`,WESTRING_UNITUINAMECHAPLAIN UnitUINamehydromancer=0,unituiname,`hydromancer`,WESTRING_UNITUINAMEHYDROMANCER UnitUINamealbatross=0,unituiname,`albatross`,WESTRING_UNITUINAMEALBATROSS UnitUINamecrab=0,unituiname,`crab`,WESTRING_UNITUINAMECRAB UnitUINamedeer=0,unituiname,`deer`,WESTRING_UNITUINAMEDEER UnitUINamedog=0,unituiname,`dog`,WESTRING_UNITUINAMEDOG UnitUINameduneworm=0,unituiname,`duneworm`,WESTRING_UNITUINAMEDUNEWORM UnitUINamefelboar=0,unituiname,`felboar`,WESTRING_UNITUINAMEFELBOAR UnitUINamehermitcrab=0,unituiname,`hermitcrab`,WESTRING_UNITUINAMEHERMITCRAB UnitUINameowl2=0,unituiname,`owl2`,WESTRING_UNITUINAMEOWL2 UnitUINameowl3=0,unituiname,`owl3`,WESTRING_UNITUINAMEOWL3 UnitUINameowl=0,unituiname,`owl`,WESTRING_UNITUINAMEOWL UnitUINamepig=0,unituiname,`pig`,WESTRING_UNITUINAMEPIG UnitUINamepenguin=0,unituiname,`penguin`,WESTRING_UNITUINAMEPENGUIN UnitUINamewaterpenguin=0,unituiname,`waterpenguin`,WESTRING_UNITUINAMEWATERPENGUIN UnitUINamerat=0,unituiname,`rat`,WESTRING_UNITUINAMERAT UnitUINameseal=0,unituiname,`seal`,WESTRING_UNITUINAMESEAL UnitUINameamphibioussheep=0,unituiname,`amphibioussheep`,WESTRING_UNITUINAMEAMPHIBIOUSSHEEP UnitUINamesheep=0,unituiname,`sheep`,WESTRING_UNITUINAMESHEEP UnitUINameflyingsheep=0,unituiname,`flyingsheep`,WESTRING_UNITUINAMEFLYINGSHEEP UnitUINamewatersheep=0,unituiname,`watersheep`,WESTRING_UNITUINAMEWATERSHEEP UnitUINameskink=0,unituiname,`skink`,WESTRING_UNITUINAMESKINK UnitUINamesnowyowl=0,unituiname,`snowyowl`,WESTRING_UNITUINAMESNOWYOWL UnitUINamevillagerman=0,unituiname,`villagerman`,WESTRING_UNITUINAMEVILLAGERMAN UnitUINamevillagerkid2=0,unituiname,`villagerkid2`,WESTRING_UNITUINAMEVILLAGERKID2 UnitUINamevillagerman2=0,unituiname,`villagerman2`,WESTRING_UNITUINAMEVILLAGERMAN2 UnitUINamevillagerkid=0,unituiname,`villagerkid`,WESTRING_UNITUINAMEVILLAGERKID UnitUINamevillagerwoman=0,unituiname,`villagerwoman`,WESTRING_UNITUINAMEVILLAGERWOMAN UnitUINamevulture=0,unituiname,`vulture`,WESTRING_UNITUINAMEVULTURE UnitUINamecitybuildingSmall 0=0,unituiname,`citybuildingSmall 0`,WESTRING_UNITUINAMECITYBUILDINGSMALL 0 UnitUINamecitybuildingSmall 1=0,unituiname,`citybuildingSmall 1`,WESTRING_UNITUINAMECITYBUILDINGSMALL 1 UnitUINamecitybuildingSmall 2=0,unituiname,`citybuildingSmall 2`,WESTRING_UNITUINAMECITYBUILDINGSMALL 2 UnitUINamecitybuildingSmall 3=0,unituiname,`citybuildingSmall 3`,WESTRING_UNITUINAMECITYBUILDINGSMALL 3 UnitUINamecitybuildingSmall 4=0,unituiname,`citybuildingSmall 4`,WESTRING_UNITUINAMECITYBUILDINGSMALL 4 UnitUINamecitybuildingSmall 5=0,unituiname,`citybuildingSmall 5`,WESTRING_UNITUINAMECITYBUILDINGSMALL 5 UnitUINamecitybuildingSmall 6=0,unituiname,`citybuildingSmall 6`,WESTRING_UNITUINAMECITYBUILDINGSMALL 6 UnitUINamecitybuildingSmall 7=0,unituiname,`citybuildingSmall 7`,WESTRING_UNITUINAMECITYBUILDINGSMALL 7 UnitUINamecitybuildingSmall 8=0,unituiname,`citybuildingSmall 8`,WESTRING_UNITUINAMECITYBUILDINGSMALL 8 UnitUINamecitybuildingSmall 9=0,unituiname,`citybuildingSmall 9`,WESTRING_UNITUINAMECITYBUILDINGSMALL 9 UnitUINamecitybuildingSmall a=0,unituiname,`citybuildingSmall a`,WESTRING_UNITUINAMECITYBUILDINGSMALL A UnitUINamecitybuildingSmall b=0,unituiname,`citybuildingSmall b`,WESTRING_UNITUINAMECITYBUILDINGSMALL B UnitUINameCityBuildingLarge 0=0,unituiname,`CityBuildingLarge 0`,WESTRING_UNITUINAMECITYBUILDINGLARGE 0 UnitUINameCityBuildingLarge 1=0,unituiname,`CityBuildingLarge 1`,WESTRING_UNITUINAMECITYBUILDINGLARGE 1 UnitUINameCityBuildingLarge 2=0,unituiname,`CityBuildingLarge 2`,WESTRING_UNITUINAMECITYBUILDINGLARGE 2 UnitUINameCityBuildingLarge 3=0,unituiname,`CityBuildingLarge 3`,WESTRING_UNITUINAMECITYBUILDINGLARGE 3 UnitUINamecentaurtent=0,unituiname,`centaurtent`,WESTRING_UNITUINAMECENTAURTENT UnitUINamecircleofpower=0,unituiname,`circleofpower`,WESTRING_UNITUINAMECIRCLEOFPOWER UnitUINamecircleofpowermedium=0,unituiname,`circleofpowermedium`,WESTRING_UNITUINAMECIRCLEOFPOWERMEDIUM UnitUINamecircleofpowerlarge=0,unituiname,`circleofpowerlarge`,WESTRING_UNITUINAMECIRCLEOFPOWERLARGE UnitUINamecentaurtent1=0,unituiname,`centaurtent1`,WESTRING_UNITUINAMECENTAURTENT1 UnitUINamecentaurtent2=0,unituiname,`centaurtent2`,WESTRING_UNITUINAMECENTAURTENT2 UnitUINamechieftainhut=0,unituiname,`chieftainhut`,WESTRING_UNITUINAMECHIEFTAINHUT UnitUINamedraneihut0=0,unituiname,`draneihut0`,WESTRING_UNITUINAMEDRANEIHUT0 UnitUINamedraneihut1=0,unituiname,`draneihut1`,WESTRING_UNITUINAMEDRANEIHUT1 UnitUINamedraeneihaven=0,unituiname,`draeneihaven`,WESTRING_UNITUINAMEDRAENEIHAVEN UnitUINamedraeneiwarriorshall=0,unituiname,`draeneiwarriorshall`,WESTRING_UNITUINAMEDRAENEIWARRIORSHALL UnitUINamedraeneiseerden=0,unituiname,`draeneiseerden`,WESTRING_UNITUINAMEDRAENEISEERDEN UnitUINamegreendragonroost=0,unituiname,`greendragonroost`,WESTRING_UNITUINAMEGREENDRAGONROOST UnitUINameblackdragonroost=0,unituiname,`blackdragonroost`,WESTRING_UNITUINAMEBLACKDRAGONROOST UnitUINameoutlanddragonroost=0,unituiname,`outlanddragonroost`,WESTRING_UNITUINAMEOUTLANDDRAGONROOST UnitUINamereddragonroost=0,unituiname,`reddragonroost`,WESTRING_UNITUINAMEREDDRAGONROOST UnitUINamebluedragonroost=0,unituiname,`bluedragonroost`,WESTRING_UNITUINAMEBLUEDRAGONROOST UnitUINamebronzedragonroost=0,unituiname,`bronzedragonroost`,WESTRING_UNITUINAMEBRONZEDRAGONROOST UnitUINameforesttrollhut0=0,unituiname,`foresttrollhut0`,WESTRING_UNITUINAMEFORESTTROLLHUT0 UnitUINameforesttrollhut1=0,unituiname,`foresttrollhut1`,WESTRING_UNITUINAMEFORESTTROLLHUT1 UnitUINamefountainofhealth=0,unituiname,`fountainofhealth`,WESTRING_UNITUINAMEFOUNTAINOFHEALTH UnitUINamefurbolghut1=0,unituiname,`furbolghut1`,WESTRING_UNITUINAMEFURBOLGHUT1 UnitUINamefurbolghut2=0,unituiname,`furbolghut2`,WESTRING_UNITUINAMEFURBOLGHUT2 UnitUINamegoblinammodump=0,unituiname,`goblinammodump`,WESTRING_UNITUINAMEGOBLINAMMODUMP UnitUINamegoblinmerchant=0,unituiname,`goblinmerchant`,WESTRING_UNITUINAMEGOBLINMERCHANT UnitUINamegnollhut=0,unituiname,`gnollhut`,WESTRING_UNITUINAMEGNOLLHUT UnitUINamegranaryinfected=0,unituiname,`granaryinfected`,WESTRING_UNITUINAMEGRANARYINFECTED UnitUINamegoldmine=0,unituiname,`goldmine`,WESTRING_UNITUINAMEGOLDMINE UnitUINamegnollhut2=0,unituiname,`gnollhut2`,WESTRING_UNITUINAMEGNOLLHUT2 UnitUINamegrainwarehouse=0,unituiname,`grainwarehouse`,WESTRING_UNITUINAMEGRAINWAREHOUSE UnitUINameharpynest=0,unituiname,`harpynest`,WESTRING_UNITUINAMEHARPYNEST UnitUINamemercenarycampl=0,unituiname,`mercenarycampl`,WESTRING_UNITUINAMEMERCENARYCAMPL UnitUINamemurgulhut0=0,unituiname,`murgulhut0`,WESTRING_UNITUINAMEMURGULHUT0 UnitUINamemurgulhut1=0,unituiname,`murgulhut1`,WESTRING_UNITUINAMEMURGULHUT1 UnitUINamemurlochut0=0,unituiname,`murlochut0`,WESTRING_UNITUINAMEMURLOCHUT0 UnitUINamemurlochut1=0,unituiname,`murlochut1`,WESTRING_UNITUINAMEMURLOCHUT1 UnitUINamefountainofmana=0,unituiname,`fountainofmana`,WESTRING_UNITUINAMEFOUNTAINOFMANA UnitUINamemercenarycampv=0,unituiname,`mercenarycampv`,WESTRING_UNITUINAMEMERCENARYCAMPV UnitUINamemercenarycampf=0,unituiname,`mercenarycampf`,WESTRING_UNITUINAMEMERCENARYCAMPF UnitUINamemercenarycampw=0,unituiname,`mercenarycampw`,WESTRING_UNITUINAMEMERCENARYCAMPW UnitUINamemercenarycampb=0,unituiname,`mercenarycampb`,WESTRING_UNITUINAMEMERCENARYCAMPB UnitUINamemercenarycampa=0,unituiname,`mercenarycampa`,WESTRING_UNITUINAMEMERCENARYCAMPA UnitUINamemercenarycampc=0,unituiname,`mercenarycampc`,WESTRING_UNITUINAMEMERCENARYCAMPC UnitUINamemercenarycampn=0,unituiname,`mercenarycampn`,WESTRING_UNITUINAMEMERCENARYCAMPN UnitUINamemercenarycampy=0,unituiname,`mercenarycampy`,WESTRING_UNITUINAMEMERCENARYCAMPY UnitUINamemercenarycampx=0,unituiname,`mercenarycampx`,WESTRING_UNITUINAMEMERCENARYCAMPX UnitUINamemercenarycampd=0,unituiname,`mercenarycampd`,WESTRING_UNITUINAMEMERCENARYCAMPD UnitUINamemercenarycampg=0,unituiname,`mercenarycampg`,WESTRING_UNITUINAMEMERCENARYCAMPG UnitUINamemercenarycampz=0,unituiname,`mercenarycampz`,WESTRING_UNITUINAMEMERCENARYCAMPZ UnitUINamemercenarycampi=0,unituiname,`mercenarycampi`,WESTRING_UNITUINAMEMERCENARYCAMPI UnitUINamemercenarycampo=0,unituiname,`mercenarycampo`,WESTRING_UNITUINAMEMERCENARYCAMPO UnitUINamemercenarycampk=0,unituiname,`mercenarycampk`,WESTRING_UNITUINAMEMERCENARYCAMPK UnitUINamemarketplace=0,unituiname,`marketplace`,WESTRING_UNITUINAMEMARKETPLACE UnitUINamenerubianziggurat=0,unituiname,`nerubianziggurat`,WESTRING_UNITUINAMENERUBIANZIGGURAT UnitUINamegoblinshipyard=0,unituiname,`goblinshipyard`,WESTRING_UNITUINAMEGOBLINSHIPYARD UnitUINamecantina=0,unituiname,`cantina`,WESTRING_UNITUINAMECANTINA UnitUINametent=0,unituiname,`tent`,WESTRING_UNITUINAMETENT UnitUINameicetrollhut0=0,unituiname,`icetrollhut0`,WESTRING_UNITUINAMEICETROLLHUT0 UnitUINameicetrollhut1=0,unituiname,`icetrollhut1`,WESTRING_UNITUINAMEICETROLLHUT1 UnitUINametent2=0,unituiname,`tent2`,WESTRING_UNITUINAMETENT2 UnitUINametaurentent=0,unituiname,`taurentent`,WESTRING_UNITUINAMETAURENTENT UnitUINametaurentent2=0,unituiname,`taurentent2`,WESTRING_UNITUINAMETAURENTENT2 UnitUINamewaygate=0,unituiname,`waygate`,WESTRING_UNITUINAMEWAYGATE UnitUINamecenarius=0,unituiname,`cenarius`,WESTRING_UNITUINAMECENARIUS UnitUINameevilillidan=0,unituiname,`evilillidan`,WESTRING_UNITUINAMEEVILILLIDAN UnitUINameevilillidandemonform=0,unituiname,`evilillidandemonform`,WESTRING_UNITUINAMEEVILILLIDANDEMONFORM UnitUINamefurion=0,unituiname,`furion`,WESTRING_UNITUINAMEFURION UnitUINameillidandemonform=0,unituiname,`illidandemonform`,WESTRING_UNITUINAMEILLIDANDEMONFORM UnitUINameillidan=0,unituiname,`illidan`,WESTRING_UNITUINAMEILLIDAN UnitUINameillidanmorphed=0,unituiname,`illidanmorphed`,WESTRING_UNITUINAMEILLIDANMORPHED UnitUINamekeeperofthegroveghost=0,unituiname,`keeperofthegroveghost`,WESTRING_UNITUINAMEKEEPEROFTHEGROVEGHOST UnitUINamemalfurion=0,unituiname,`malfurion`,WESTRING_UNITUINAMEMALFURION UnitUINamemalfurionnostag=0,unituiname,`malfurionnostag`,WESTRING_UNITUINAMEMALFURIONNOSTAG UnitUINametyrande=0,unituiname,`tyrande`,WESTRING_UNITUINAMETYRANDE UnitUINamemaiev=0,unituiname,`maiev`,WESTRING_UNITUINAMEMAIEV UnitUINameantonidus=0,unituiname,`antonidus`,WESTRING_UNITUINAMEANTONIDUS UnitUINameadmiralproudmoore=0,unituiname,`admiralproudmoore`,WESTRING_UNITUINAMEADMIRALPROUDMOORE UnitUINamearthaswithfrostmourne=0,unituiname,`arthaswithfrostmourne`,WESTRING_UNITUINAMEARTHASWITHFROSTMOURNE UnitUINamearthas=0,unituiname,`arthas`,WESTRING_UNITUINAMEARTHAS UnitUINamedagren=0,unituiname,`dagren`,WESTRING_UNITUINAMEDAGREN UnitUINamehalahk=0,unituiname,`halahk`,WESTRING_UNITUINAMEHALAHK UnitUINamejaina=0,unituiname,`jaina`,WESTRING_UNITUINAMEJAINA UnitUINamekael=0,unituiname,`kael`,WESTRING_UNITUINAMEKAEL UnitUINamelordgarithos=0,unituiname,`lordgarithos`,WESTRING_UNITUINAMELORDGARITHOS UnitUINamemuradinbronzebeard=0,unituiname,`muradinbronzebeard`,WESTRING_UNITUINAMEMURADINBRONZEBEARD UnitUINamemargoth=0,unituiname,`margoth`,WESTRING_UNITUINAMEMARGOTH UnitUINamepaladinboss1=0,unituiname,`paladinboss1`,WESTRING_UNITUINAMEPALADINBOSS1 UnitUINamepaladinboss2=0,unituiname,`paladinboss2`,WESTRING_UNITUINAMEPALADINBOSS2 UnitUINameuther=0,unituiname,`uther`,WESTRING_UNITUINAMEUTHER UnitUINameladyvashj=0,unituiname,`ladyvashj`,WESTRING_UNITUINAMELADYVASHJ UnitUINamesylvanuswindrunner=0,unituiname,`sylvanuswindrunner`,WESTRING_UNITUINAMESYLVANUSWINDRUNNER UnitUINameblackrockblademaster=0,unituiname,`blackrockblademaster`,WESTRING_UNITUINAMEBLACKROCKBLADEMASTER UnitUINamekiljaeden=0,unituiname,`kiljaeden`,WESTRING_UNITUINAMEKILJAEDEN UnitUINamekiljaedencinematic=0,unituiname,`kiljaedencinematic`,WESTRING_UNITUINAMEKILJAEDENCINEMATIC UnitUINamemagtheridon=0,unituiname,`magtheridon`,WESTRING_UNITUINAMEMAGTHERIDON UnitUINamemannoroth=0,unituiname,`mannoroth`,WESTRING_UNITUINAMEMANNOROTH UnitUINameoldpitlord=0,unituiname,`oldpitlord`,WESTRING_UNITUINAMEOLDPITLORD UnitUINamesinjostormstout=0,unituiname,`sinjostormstout`,WESTRING_UNITUINAMESINJOSTORMSTOUT UnitUINamecairnebloodhoof=0,unituiname,`cairnebloodhoof`,WESTRING_UNITUINAMECAIRNEBLOODHOOF UnitUINamecairnebloodhoofexp=0,unituiname,`cairnebloodhoofexp`,WESTRING_UNITUINAMECAIRNEBLOODHOOFEXP UnitUINamedrekthar=0,unituiname,`drekthar`,WESTRING_UNITUINAMEDREKTHAR UnitUINameguldan=0,unituiname,`guldan`,WESTRING_UNITUINAMEGULDAN UnitUINamegromhellscream=0,unituiname,`gromhellscream`,WESTRING_UNITUINAMEGROMHELLSCREAM UnitUINamepossessedgromhellscream=0,unituiname,`possessedgromhellscream`,WESTRING_UNITUINAMEPOSSESSEDGROMHELLSCREAM UnitUINamerexxar=0,unituiname,`rexxar`,WESTRING_UNITUINAMEREXXAR UnitUINamerokhan=0,unituiname,`rokhan`,WESTRING_UNITUINAMEROKHAN UnitUINamesamuro=0,unituiname,`samuro`,WESTRING_UNITUINAMESAMURO UnitUINamecairnebloodhoofcinematic=0,unituiname,`cairnebloodhoofcinematic`,WESTRING_UNITUINAMECAIRNEBLOODHOOFCINEMATIC UnitUINamethrall=0,unituiname,`thrall`,WESTRING_UNITUINAMETHRALL UnitUINameanubarak=0,unituiname,`anubarak`,WESTRING_UNITUINAMEANUBARAK UnitUINamebalnazzar=0,unituiname,`balnazzar`,WESTRING_UNITUINAMEBALNAZZAR UnitUINamekelthuzadlichcinematic=0,unituiname,`kelthuzadlichcinematic`,WESTRING_UNITUINAMEKELTHUZADLICHCINEMATIC UnitUINamedetheroc=0,unituiname,`detheroc`,WESTRING_UNITUINAMEDETHEROC UnitUINameevilarthas=0,unituiname,`evilarthas`,WESTRING_UNITUINAMEEVILARTHAS UnitUINamekelthuzadlich=0,unituiname,`kelthuzadlich`,WESTRING_UNITUINAMEKELTHUZADLICH UnitUINamemalganis=0,unituiname,`malganis`,WESTRING_UNITUINAMEMALGANIS UnitUINameevilsylvanas=0,unituiname,`evilsylvanas`,WESTRING_UNITUINAMEEVILSYLVANAS UnitUINametichondrius=0,unituiname,`tichondrius`,WESTRING_UNITUINAMETICHONDRIUS UnitUINamevarimathras=0,unituiname,`varimathras`,WESTRING_UNITUINAMEVARIMATHRAS UnitUINamevengyr=0,unituiname,`vengyr`,WESTRING_UNITUINAMEVENGYR UnitUINamearchimonde=0,unituiname,`archimonde`,WESTRING_UNITUINAMEARCHIMONDE UnitUINameghostlyarchmage=0,unituiname,`ghostlyarchmage`,WESTRING_UNITUINAMEGHOSTLYARCHMAGE UnitUINameillidanwagon=0,unituiname,`illidanwagon`,WESTRING_UNITUINAMEILLIDANWAGON UnitUINamenightelfrunner=0,unituiname,`nightelfrunner`,WESTRING_UNITUINAMENIGHTELFRUNNER UnitUINamenaisha=0,unituiname,`naisha`,WESTRING_UNITUINAMENAISHA UnitUINameshandris=0,unituiname,`shandris`,WESTRING_UNITUINAMESHANDRIS UnitUINamenightelftransportship=0,unituiname,`nightelftransportship`,WESTRING_UNITUINAMENIGHTELFTRANSPORTSHIP UnitUINamebloodelfwagon=0,unituiname,`bloodelfwagon`,WESTRING_UNITUINAMEBLOODELFWAGON UnitUINamethecaptain=0,unituiname,`thecaptain`,WESTRING_UNITUINAMETHECAPTAIN UnitUINameriderlesshorse=0,unituiname,`riderlesshorse`,WESTRING_UNITUINAMERIDERLESSHORSE UnitUINamehighelvenswordsman=0,unituiname,`highelvenswordsman`,WESTRING_UNITUINAMEHIGHELVENSWORDSMAN UnitUINamepackhorse=0,unituiname,`packhorse`,WESTRING_UNITUINAMEPACKHORSE UnitUINameakama=0,unituiname,`akama`,WESTRING_UNITUINAMEAKAMA UnitUINamespiritbeast=0,unituiname,`spiritbeast`,WESTRING_UNITUINAMESPIRITBEAST UnitUINamespiritbeast2=0,unituiname,`spiritbeast2`,WESTRING_UNITUINAMESPIRITBEAST2 UnitUINamespiritbeast3=0,unituiname,`spiritbeast3`,WESTRING_UNITUINAMESPIRITBEAST3 UnitUINamedemolisherdraenei=0,unituiname,`demolisherdraenei`,WESTRING_UNITUINAMEDEMOLISHERDRAENEI UnitUINamebloodelfengineer=0,unituiname,`bloodelfengineer`,WESTRING_UNITUINAMEBLOODELFENGINEER UnitUINamebloodelflieutenant=0,unituiname,`bloodelflieutenant`,WESTRING_UNITUINAMEBLOODELFLIEUTENANT UnitUINamebattleship=0,unituiname,`battleship`,WESTRING_UNITUINAMEBATTLESHIP UnitUINamechaosgrunt=0,unituiname,`chaosgrunt`,WESTRING_UNITUINAMECHAOSGRUNT UnitUINamechaoswolfrider=0,unituiname,`chaoswolfrider`,WESTRING_UNITUINAMECHAOSWOLFRIDER UnitUINamechaoswarlock=0,unituiname,`chaoswarlock`,WESTRING_UNITUINAMECHAOSWARLOCK UnitUINamechaoskotobeast=0,unituiname,`chaoskotobeast`,WESTRING_UNITUINAMECHAOSKOTOBEAST UnitUINamechaospeon=0,unituiname,`chaospeon`,WESTRING_UNITUINAMECHAOSPEON UnitUINamedalaranmutant=0,unituiname,`dalaranmutant`,WESTRING_UNITUINAMEDALARANMUTANT UnitUINamedraeneidarkslayer=0,unituiname,`draeneidarkslayer`,WESTRING_UNITUINAMEDRAENEIDARKSLAYER UnitUINamedraeneivindicator=0,unituiname,`draeneivindicator`,WESTRING_UNITUINAMEDRAENEIVINDICATOR UnitUINamedraeneistalker=0,unituiname,`draeneistalker`,WESTRING_UNITUINAMEDRAENEISTALKER UnitUINamedraeneiguardian=0,unituiname,`draeneiguardian`,WESTRING_UNITUINAMEDRAENEIGUARDIAN UnitUINamedraeneiharbinger=0,unituiname,`draeneiharbinger`,WESTRING_UNITUINAMEDRAENEIHARBINGER UnitUINamedalaranreject=0,unituiname,`dalaranreject`,WESTRING_UNITUINAMEDALARANREJECT UnitUINamedraeneidisciple=0,unituiname,`draeneidisciple`,WESTRING_UNITUINAMEDRAENEIDISCIPLE UnitUINamedraeneiprotector=0,unituiname,`draeneiprotector`,WESTRING_UNITUINAMEDRAENEIPROTECTOR UnitUINamedraeneiseer=0,unituiname,`draeneiseer`,WESTRING_UNITUINAMEDRAENEISEER UnitUINamedraeneiwatcher=0,unituiname,`draeneiwatcher`,WESTRING_UNITUINAMEDRAENEIWATCHER UnitUINamedraeneilaborer=0,unituiname,`draeneilaborer`,WESTRING_UNITUINAMEDRAENEILABORER UnitUINamedraeneisalamander=0,unituiname,`draeneisalamander`,WESTRING_UNITUINAMEDRAENEISALAMANDER UnitUINameengineergazlowe=0,unituiname,`engineergazlowe`,WESTRING_UNITUINAMEENGINEERGAZLOWE UnitUINameemissary=0,unituiname,`emissary`,WESTRING_UNITUINAMEEMISSARY UnitUINamefleshgolem=0,unituiname,`fleshgolem`,WESTRING_UNITUINAMEFLESHGOLEM UnitUINamegoblinblaster=0,unituiname,`goblinblaster`,WESTRING_UNITUINAMEGOBLINBLASTER UnitUINamehighelvenarcher=0,unituiname,`highelvenarcher`,WESTRING_UNITUINAMEHIGHELVENARCHER UnitUINamehighelvenfemale=0,unituiname,`highelvenfemale`,WESTRING_UNITUINAMEHIGHELVENFEMALE UnitUINamehighelvenmale=0,unituiname,`highelvenmale`,WESTRING_UNITUINAMEHIGHELVENMALE UnitUINamebloodelfworker=0,unituiname,`bloodelfworker`,WESTRING_UNITUINAMEBLOODELFWORKER UnitUINamejailorkassan=0,unituiname,`jailorkassan`,WESTRING_UNITUINAMEJAILORKASSAN UnitUINamemedivhmorphed=0,unituiname,`medivhmorphed`,WESTRING_UNITUINAMEMEDIVHMORPHED UnitUINamemedivh=0,unituiname,`medivh`,WESTRING_UNITUINAMEMEDIVH UnitUINamemurgulslave=0,unituiname,`murgulslave`,WESTRING_UNITUINAMEMURGULSLAVE UnitUINamemisha=0,unituiname,`misha`,WESTRING_UNITUINAMEMISHA UnitUINamesearinox=0,unituiname,`searinox`,WESTRING_UNITUINAMESEARINOX UnitUINamesupportcolumn=0,unituiname,`supportcolumn`,WESTRING_UNITUINAMESUPPORTCOLUMN UnitUINamenightelfassassin=0,unituiname,`nightelfassassin`,WESTRING_UNITUINAMENIGHTELFASSASSIN UnitUINametharifas=0,unituiname,`tharifas`,WESTRING_UNITUINAMETHARIFAS UnitUINamewar2warlock=0,unituiname,`war2warlock`,WESTRING_UNITUINAMEWAR2WARLOCK UnitUINamewatcher=0,unituiname,`watcher`,WESTRING_UNITUINAMEWATCHER UnitUINamedrakthul=0,unituiname,`drakthul`,WESTRING_UNITUINAMEDRAKTHUL UnitUINamegarthok=0,unituiname,`garthok`,WESTRING_UNITUINAMEGARTHOK UnitUINamejuggernaut=0,unituiname,`juggernaut`,WESTRING_UNITUINAMEJUGGERNAUT UnitUINamemathog=0,unituiname,`mathog`,WESTRING_UNITUINAMEMATHOG UnitUINamenazgrel=0,unituiname,`nazgrel`,WESTRING_UNITUINAMENAZGREL UnitUINamekotobeastnorider=0,unituiname,`kotobeastnorider`,WESTRING_UNITUINAMEKOTOBEASTNORIDER UnitUINamespiritwyvern=0,unituiname,`spiritwyvern`,WESTRING_UNITUINAMESPIRITWYVERN UnitUINamevoljin=0,unituiname,`voljin`,WESTRING_UNITUINAMEVOLJIN UnitUINamechaoswarlord=0,unituiname,`chaoswarlord`,WESTRING_UNITUINAMECHAOSWARLORD UnitUINameriderlesswyvern=0,unituiname,`riderlesswyvern`,WESTRING_UNITUINAMERIDERLESSWYVERN UnitUINameabominationcinematic=0,unituiname,`abominationcinematic`,WESTRING_UNITUINAMEABOMINATIONCINEMATIC UnitUINameairbarge=0,unituiname,`airbarge`,WESTRING_UNITUINAMEAIRBARGE UnitUINameazurelordfrostwyrm=0,unituiname,`azurelordfrostwyrm`,WESTRING_UNITUINAMEAZURELORDFROSTWYRM UnitUINameazureloredragon=0,unituiname,`azureloredragon`,WESTRING_UNITUINAMEAZURELOREDRAGON UnitUINameundeadtransportship=0,unituiname,`undeadtransportship`,WESTRING_UNITUINAMEUNDEADTRANSPORTSHIP UnitUINameundeaddestroyer=0,unituiname,`undeaddestroyer`,WESTRING_UNITUINAMEUNDEADDESTROYER UnitUINamekelthuzadghost=0,unituiname,`kelthuzadghost`,WESTRING_UNITUINAMEKELTHUZADGHOST UnitUINamekelthuzadnecro=0,unituiname,`kelthuzadnecro`,WESTRING_UNITUINAMEKELTHUZADNECRO UnitUINamesylvanusbanshee=0,unituiname,`sylvanusbanshee`,WESTRING_UNITUINAMESYLVANUSBANSHEE UnitUINameshimmeringportal=0,unituiname,`shimmeringportal`,WESTRING_UNITUINAMESHIMMERINGPORTAL UnitUINamearcaneobservatory=0,unituiname,`arcaneobservatory`,WESTRING_UNITUINAMEARCANEOBSERVATORY UnitUINamebloodfountain=0,unituiname,`bloodfountain`,WESTRING_UNITUINAMEBLOODFOUNTAIN UnitUINamebookofsummoning=0,unituiname,`bookofsummoning`,WESTRING_UNITUINAMEBOOKOFSUMMONING UnitUINamebouldertower=0,unituiname,`bouldertower`,WESTRING_UNITUINAMEBOULDERTOWER UnitUINamebouldertowerupgrade=0,unituiname,`bouldertowerupgrade`,WESTRING_UNITUINAMEBOULDERTOWERUPGRADE UnitUINamebarrowden=0,unituiname,`barrowden`,WESTRING_UNITUINAMEBARROWDEN UnitUINamecorruptedancientprotector=0,unituiname,`corruptedancientprotector`,WESTRING_UNITUINAMECORRUPTEDANCIENTPROTECTOR UnitUINamecorruptedancientofwar=0,unituiname,`corruptedancientofwar`,WESTRING_UNITUINAMECORRUPTEDANCIENTOFWAR UnitUINamecorruptedmoonwell=0,unituiname,`corruptedmoonwell`,WESTRING_UNITUINAMECORRUPTEDMOONWELL UnitUINamecorruptedtreeofages=0,unituiname,`corruptedtreeofages`,WESTRING_UNITUINAMECORRUPTEDTREEOFAGES UnitUINamecorruptedtreeofeternity=0,unituiname,`corruptedtreeofeternity`,WESTRING_UNITUINAMECORRUPTEDTREEOFETERNITY UnitUINamecorruptedtreeoflife=0,unituiname,`corruptedtreeoflife`,WESTRING_UNITUINAMECORRUPTEDTREEOFLIFE UnitUINamedefiledfountainoflife=0,unituiname,`defiledfountainoflife`,WESTRING_UNITUINAMEDEFILEDFOUNTAINOFLIFE UnitUINamedalaranguardtower=0,unituiname,`dalaranguardtower`,WESTRING_UNITUINAMEDALARANGUARDTOWER UnitUINamedarkportalse=0,unituiname,`darkportalse`,WESTRING_UNITUINAMEDARKPORTALSE UnitUINamedarkportalsw=0,unituiname,`darkportalsw`,WESTRING_UNITUINAMEDARKPORTALSW UnitUINamedemongate=0,unituiname,`demongate`,WESTRING_UNITUINAMEDEMONGATE UnitUINamedragonbuilding=0,unituiname,`dragonbuilding`,WESTRING_UNITUINAMEDRAGONBUILDING UnitUINamecoldtower=0,unituiname,`coldtower`,WESTRING_UNITUINAMECOLDTOWER UnitUINamecoldtowerupgrade=0,unituiname,`coldtowerupgrade`,WESTRING_UNITUINAMECOLDTOWERUPGRADE UnitUINameelvenfarm0=0,unituiname,`elvenfarm0`,WESTRING_UNITUINAMEELVENFARM0 UnitUINameelvenfarm1=0,unituiname,`elvenfarm1`,WESTRING_UNITUINAMEELVENFARM1 UnitUINameelvenfarm2=0,unituiname,`elvenfarm2`,WESTRING_UNITUINAMEELVENFARM2 UnitUINameelvenfarm3=0,unituiname,`elvenfarm3`,WESTRING_UNITUINAMEELVENFARM3 UnitUINameelvenfarm4=0,unituiname,`elvenfarm4`,WESTRING_UNITUINAMEELVENFARM4 UnitUINameelvenfarm5=0,unituiname,`elvenfarm5`,WESTRING_UNITUINAMEELVENFARM5 UnitUINameelvenfarm6=0,unituiname,`elvenfarm6`,WESTRING_UNITUINAMEELVENFARM6 UnitUINameelvenfarm7=0,unituiname,`elvenfarm7`,WESTRING_UNITUINAMEELVENFARM7 UnitUINameelvenfarm=0,unituiname,`elvenfarm`,WESTRING_UNITUINAMEELVENFARM UnitUINameearthfurytower=0,unituiname,`earthfurytower`,WESTRING_UNITUINAMEEARTHFURYTOWER UnitUINameskyfurytower=0,unituiname,`skyfurytower`,WESTRING_UNITUINAMESKYFURYTOWER UnitUINameelvenguardtower=0,unituiname,`elvenguardtower`,WESTRING_UNITUINAMEELVENGUARDTOWER UnitUINameenergytower=0,unituiname,`energytower`,WESTRING_UNITUINAMEENERGYTOWER UnitUINameenergytowerupgrade=0,unituiname,`energytowerupgrade`,WESTRING_UNITUINAMEENERGYTOWERUPGRADE UnitUINamepurplefountain=0,unituiname,`purplefountain`,WESTRING_UNITUINAMEPURPLEFOUNTAIN UnitUINamefrostmourne=0,unituiname,`frostmourne`,WESTRING_UNITUINAMEFROSTMOURNE UnitUINamefruitstand=0,unituiname,`fruitstand`,WESTRING_UNITUINAMEFRUITSTAND UnitUINameflametower=0,unituiname,`flametower`,WESTRING_UNITUINAMEFLAMETOWER UnitUINameflametowerupgrade=0,unituiname,`flametowerupgrade`,WESTRING_UNITUINAMEFLAMETOWERUPGRADE UnitUINameelvenfishingvillage0=0,unituiname,`elvenfishingvillage0`,WESTRING_UNITUINAMEELVENFISHINGVILLAGE0 UnitUINameelvenfishingvillage1=0,unituiname,`elvenfishingvillage1`,WESTRING_UNITUINAMEELVENFISHINGVILLAGE1 UnitUINameelvenfishingvillage2=0,unituiname,`elvenfishingvillage2`,WESTRING_UNITUINAMEELVENFISHINGVILLAGE2 UnitUINameelvenfishingvillage3=0,unituiname,`elvenfishingvillage3`,WESTRING_UNITUINAMEELVENFISHINGVILLAGE3 UnitUINameelvenfishingvillage4=0,unituiname,`elvenfishingvillage4`,WESTRING_UNITUINAMEELVENFISHINGVILLAGE4 UnitUINamegemstoneobelisk=0,unituiname,`gemstoneobelisk`,WESTRING_UNITUINAMEGEMSTONEOBELISK UnitUINamehornofcenarius=0,unituiname,`hornofcenarius`,WESTRING_UNITUINAMEHORNOFCENARIUS UnitUINamehighelfbarracks=0,unituiname,`highelfbarracks`,WESTRING_UNITUINAMEHIGHELFBARRACKS UnitUINameicecrownobelisk=0,unituiname,`icecrownobelisk`,WESTRING_UNITUINAMEICECROWNOBELISK UnitUINametreasurebox=0,unituiname,`treasurebox`,WESTRING_UNITUINAMETREASUREBOX UnitUINamemagicvault=0,unituiname,`magicvault`,WESTRING_UNITUINAMEMAGICVAULT UnitUINamealtarofthedepths=0,unituiname,`altarofthedepths`,WESTRING_UNITUINAMEALTAROFTHEDEPTHS UnitUINamecoralbed=0,unituiname,`coralbed`,WESTRING_UNITUINAMECORALBED UnitUINameshrineofazshara=0,unituiname,`shrineofazshara`,WESTRING_UNITUINAMESHRINEOFAZSHARA UnitUINamespawninggrounds=0,unituiname,`spawninggrounds`,WESTRING_UNITUINAMESPAWNINGGROUNDS UnitUINametidalguardian=0,unituiname,`tidalguardian`,WESTRING_UNITUINAMETIDALGUARDIAN UnitUINametempleoftides=0,unituiname,`templeoftides`,WESTRING_UNITUINAMETEMPLEOFTIDES UnitUINamepigfarm=0,unituiname,`pigfarm`,WESTRING_UNITUINAMEPIGFARM UnitUINamepowergenerator=0,unituiname,`powergenerator`,WESTRING_UNITUINAMEPOWERGENERATOR UnitUINameshrine=0,unituiname,`shrine`,WESTRING_UNITUINAMESHRINE UnitUINamedeathtower=0,unituiname,`deathtower`,WESTRING_UNITUINAMEDEATHTOWER UnitUINamedeathtowerupgrade=0,unituiname,`deathtowerupgrade`,WESTRING_UNITUINAMEDEATHTOWERUPGRADE UnitUINameruinedelvenfishingvillage0=0,unituiname,`ruinedelvenfishingvillage0`,WESTRING_UNITUINAMERUINEDELVENFISHINGVILLAGE0 UnitUINameruinedelvenfishingvillage1=0,unituiname,`ruinedelvenfishingvillage1`,WESTRING_UNITUINAMERUINEDELVENFISHINGVILLAGE1 UnitUINameruinedelvenfishingvillage2=0,unituiname,`ruinedelvenfishingvillage2`,WESTRING_UNITUINAMERUINEDELVENFISHINGVILLAGE2 UnitUINamewyverncage1=0,unituiname,`wyverncage1`,WESTRING_UNITUINAMEWYVERNCAGE1 UnitUINamewyverncage2=0,unituiname,`wyverncage2`,WESTRING_UNITUINAMEWYVERNCAGE2 UnitUINamechaosorcburrow=0,unituiname,`chaosorcburrow`,WESTRING_UNITUINAMECHAOSORCBURROW UnitUINamezoneindicator=0,unituiname,`zoneindicator`,WESTRING_UNITUINAMEZONEINDICATOR UnitUINamebindstonese=0,unituiname,`bindstonese`,WESTRING_UNITUINAMEBINDSTONESE UnitUINamebindstonesw=0,unituiname,`bindstonesw`,WESTRING_UNITUINAMEBINDSTONESW UnitUINamechaosspaceorc=0,unituiname,`chaosspaceorc`,WESTRING_UNITUINAMECHAOSSPACEORC UnitUINamehydralisk=0,unituiname,`hydralisk`,WESTRING_UNITUINAMEHYDRALISK UnitUINameorcjuggernaut=0,unituiname,`orcjuggernaut`,WESTRING_UNITUINAMEORCJUGGERNAUT UnitUINamemarine=0,unituiname,`marine`,WESTRING_UNITUINAMEMARINE UnitUINametheshoveler=0,unituiname,`theshoveler`,WESTRING_UNITUINAMETHESHOVELER UnitUINamesammycube=0,unituiname,`sammycube`,WESTRING_UNITUINAMESAMMYCUBE UnitUINamezergling=0,unituiname,`zergling`,WESTRING_UNITUINAMEZERGLING UnitUINamelichking=0,unituiname,`lichking`,WESTRING_UNITUINAMELICHKING RegionNull=0,region,null,WESTRING_TRIGREGION_NULL RaceNone=0,race,ConvertRace(0),WESTRING_TRIGRACE_NONE RaceOther=0,race,RACE_OTHER,WESTRING_TRIGRACE_OTHER RaceCreep=0,race,ConvertRace(8),WESTRING_TRIGRACE_CREEP RaceCommoner=0,race,ConvertRace(9),WESTRING_TRIGRACE_COMMONER RaceCritter=0,race,ConvertRace(10),WESTRING_TRIGRACE_CRITTER RaceNaga=0,race,ConvertRace(11),WESTRING_TRIGRACE_NAGA SaveIgnoreOptionSave=1,saveignoreoption,true,WESTRING_SAVEIGNORESAVE SaveIgnoreOptionIgnore=1,saveignoreoption,false,WESTRING_SAVEIGNOREIGNORE MapFlagFixedColors=0,mapflag,MAP_FIXED_COLORS,WESTRING_MAPFLAG_FIXEDCOLORS MapFlagCheats=0,mapflag,MAP_CHEATS,WESTRING_MAPFLAG_CHEATS MapFlagCheatsHidden=0,mapflag,MAP_CHEATS_HIDDED,WESTRING_MAPFLAG_CHEATSHIDDEN MapFlagLockSpeed=0,mapflag,MAP_LOCK_SPEED,WESTRING_MAPFLAG_LOCKSPEED MapFlagLockRandomSeed=0,mapflag,MAP_LOCK_RANDOM_SEED,WESTRING_MAPFLAG_RANDOMSEED MapFlagSharedAdvancedControl=0,mapflag,MAP_SHARED_ADVANCED_CONTROL,WESTRING_MAPFLAG_SHAREDADVANCEDCONTROL PermanentPerm=0,permanentoption,true,WESTRING_PERMANENTOPTION_PERM PermanentNoPerm=0,permanentoption,false,WESTRING_PERMANENTOPTION_NOPERM EffectTypeEffectBuff=0,effecttypebuff,EFFECT_TYPE_EFFECT,WESTRING_EFFECTTYPEOPTION_EFFECT EffectTypeTargetBuff=0,effecttypebuff,EFFECT_TYPE_TARGET,WESTRING_EFFECTTYPEOPTION_TARGET EffectTypeSpecialBuff=0,effecttypebuff,EFFECT_TYPE_SPECIAL,WESTRING_EFFECTTYPEOPTION_SPECIAL UnitOrderAttackItem=1,unitorderitarg,`attack`,WESTRING_UNITORDERITARG_ATTACK UnitOrderAttackItemOnce=1,unitorderitarg,`attackonce`,WESTRING_UNITORDERITARG_ATTACKONCE UnitOrderMoveItem=1,unitorderitarg,`move`,WESTRING_UNITORDERITARG_MOVE UnitOrderSmartItem=1,unitorderitarg,`smart`,WESTRING_UNITORDERITARG_SMART GameEventVictory=0,gameeventoption,EVENT_GAME_VICTORY,WESTRING_GAMEEVENTOPTION_VICTORY GameEventEndLevel=0,gameeventoption,EVENT_GAME_END_LEVEL,WESTRING_GAMEEVENTOPTION_ENDLEVEL GameEventVariableLimit=0,gameeventoption,EVENT_GAME_VARIABLE_LIMIT,WESTRING_GAMEEVENTOPTION_VARLIMIT GameEventStateLimit=0,gameeventoption,EVENT_GAME_STATE_LIMIT,WESTRING_GAMEEVENTOPTION_STATELIMIT GameEventTimerExpired=0,gameeventoption,EVENT_GAME_TIMER_EXPIRED,WESTRING_GAMEEVENTOPTION_TIMEREXPIRED GameEventEnterRegion=0,gameeventoption,EVENT_GAME_ENTER_REGION,WESTRING_GAMEEVENTOPTION_ENTERREGION GameEventLeaveRegion=0,gameeventoption,EVENT_GAME_LEAVE_REGION,WESTRING_GAMEEVENTOPTION_LEAVEREGION GameEventTrackableHit=0,gameeventoption,EVENT_GAME_TRACKABLE_HIT,WESTRING_GAMEEVENTOPTION_TRACKABLEHIT GameEventTrackableTrack=0,gameeventoption,EVENT_GAME_TRACKABLE_TRACK,WESTRING_GAMEEVENTOPTION_TRACKABLETRACK GameEventShowSkill=0,gameeventoption,EVENT_GAME_SHOW_SKILL,WESTRING_GAMEEVENTOPTION_SHOWSKILL GameEventBuildSubMenu=0,gameeventoption,EVENT_GAME_BUILD_SUBMENU,WESTRING_GAMEEVENTOPTION_BUILDMENU GameEventLoad=1,gameeventoption,EVENT_GAME_LOADED,"Game Loaded" GameEventSave=1,gameeventoption,EVENT_GAME_SAVE,"Game Saved" PlayerEventStateLimit=0,playereventoption,EVENT_PLAYER_STATE_LIMIT,WESTRING_PLAYEREVENTOPTION_STATELIMIT PlayerEventAllianceChange=0,playereventoption,EVENT_PLAYER_ALLIANCE_CHANGED,WESTRING_PLAYEREVENTOPTION_ALLIANCECHANGE PlayerEventDefeat=0,playereventoption,EVENT_PLAYER_DEFEAT,WESTRING_PLAYEREVENTOPTION_DEFEAT PlayerEventVictory=0,playereventoption,EVENT_PLAYER_VICTORY,WESTRING_PLAYEREVENTOPTION_VICTORY PlayerEventLeave=0,playereventoption,EVENT_PLAYER_LEAVE,WESTRING_PLAYEREVENTOPTION_LEAVE PlayerEventChat=0,playereventoption,EVENT_PLAYER_CHAT,WESTRING_PLAYEREVENTOPTION_CHAT PlayerEventEndCinematic=0,playereventoption,EVENT_PLAYER_END_CINEMATIC,WESTRING_PLAYEREVENTOPTION_ENDCINEMATIC PlayerEventALD=1,playereventoption,EVENT_PLAYER_ARROW_LEFT_DOWN,WESTRING_PLAYEREVENTALD PlayerEventALU=1,playereventoption,EVENT_PLAYER_ARROW_LEFT_UP,WESTRING_PLAYEREVENTALU PlayerEventARD=1,playereventoption,EVENT_PLAYER_ARROW_RIGHT_DOWN,WESTRING_PLAYEREVENTARD PlayerEventARU=1,playereventoption,EVENT_PLAYER_ARROW_RIGHT_UP,WESTRING_PLAYEREVENTARU PlayerEventADD=1,playereventoption,EVENT_PLAYER_ARROW_DOWN_DOWN,WESTRING_PLAYEREVENTADD PlayerEventADU=1,playereventoption,EVENT_PLAYER_ARROW_DOWN_UP,WESTRING_PLAYEREVENTADU PlayerEventAUD=1,playereventoption,EVENT_PLAYER_ARROW_UP_DOWN,WESTRING_PLAYEREVENTAUD PlayerEventAUU=1,playereventoption,EVENT_PLAYER_ARROW_UP_UP,WESTRING_PLAYEREVENTAUU PlayerUnitEventHidden=0,playerunitevent,EVENT_PLAYER_UNIT_HIDDEN,WESTRING_PUEVENT_HIDDEN PlayerUnitEventDetected=0,playerunitevent,EVENT_PLAYER_UNIT_DETECTED,WESTRING_PUEVENT_DETECTED UnitEventHidden=0,unitevent,EVENT_UNIT_HIDDEN,WESTRING_UEVENT_HIDDEN UnitEventDetected=0,unitevent,EVENT_UNIT_DETECTED,WESTRING_UEVENT_DETECTED UnitTypePlagued=0,unittype,UNIT_TYPE_PLAGUED,WESTRING_UNITTYPE_PLAGUED UnitTypeSnared=0,unittype,UNIT_TYPE_SNARED,WESTRING_UNITTYPE_SNARED UnitTypeStunned=0,unittype,UNIT_TYPE_STUNNED,WESTRING_UNITTYPE_STUNNED UnitTypePoisoned=0,unittype,UNIT_TYPE_POISONED,WESTRING_UNITTYPE_POISONED UnitTypePolymorphed=0,unittype,UNIT_TYPE_POLYMORPHED,WESTRING_UNITTYPE_POLYMORPHED UnitTypeSleeping=0,unittype,UNIT_TYPE_SLEEPING,WESTRING_UNITTYPE_SLEEPING UnitTypeResistant=0,unittype,UNIT_TYPE_RESISTANT,WESTRING_UNITTYPE_RESISTANT UnitTypeEthereal=0,unittype,UNIT_TYPE_ETHEREAL,WESTRING_UNITTYPE_ETHEREAL UnitTypeMagicImmune=0,unittype,UNIT_TYPE_MAGIC_IMMUNE,WESTRING_UNITTYPE_MAGICIMMUNE UnitTypeGiant=0,unittype,UNIT_TYPE_GIANT,WESTRING_UNITTYPE_GIANT UnitTypedead=0,unittype,UNIT_TYPE_DEAD,WESTRING_UNITTYPE_DEAD UnitTypeTauren=0,unittype,UNIT_TYPE_ Glowcolor0=1,glowcolor,"`Red`",WESTRING_GLOWCOLOR0 Glowcolor1=1,glowcolor,"`Blue`",WESTRING_GLOWCOLOR1 Glowcolor2=1,glowcolor,"`Teal`",WESTRING_GLOWCOLOR2 Glowcolor3=1,glowcolor,"`Pruple`",WESTRING_GLOWCOLOR3 Glowcolor4=1,glowcolor,"`Yellow`",WESTRING_GLOWCOLOR4 Glowcolor5=1,glowcolor,"`Orange`",WESTRING_GLOWCOLOR5 Glowcolor6=1,glowcolor,"`Green`",WESTRING_GLOWCOLOR6 Glowcolor7=1,glowcolor,"`Pink`",WESTRING_GLOWCOLOR7 Glowcolor8=1,glowcolor,"`Gray`",WESTRING_GLOWCOLOR8 Glowcolor9=1,glowcolor,"`LightBlue`",WESTRING_GLOWCOLOR9 Glowcolor10=1,glowcolor,"`DarkGreen`",WESTRING_GLOWCOLOR10 Glowcolor11=1,glowcolor,"`Brown`",WESTRING_GLOWCOLOR11 Glowcolor12=1,glowcolor,"`Neutral`",WESTRING_GLOWCOLOR12 Glowcolor13=1,glowcolor,bj_EmptyString,WESTRING_GLOWCOLOR13 Increase=1,increasedecreaseoption,true,WESTRING_INCREASE Decrease=1,increasedecreaseoption,false,WESTRING_DECREASE UpgrRaceHuman1=1,racepreset,0,WESTRING_UPGRRACEHUMAN1 UpgrRaceOrc1=1,racepreset,1,WESTRING_UPGRRACEORC1 UpgrRaceUndead1=1,racepreset,2,WESTRING_UPGRRACEUNDEAD1 UpgrRaceNightelf1=1,racepreset,3,WESTRING_UPGRRACENIGHTELF1 UpgrRaceHuman2=1,racepreset,4,WESTRING_UPGRRACEHUMAN2 UpgrRaceOrc2=1,racepreset,5,WESTRING_UPGRRACEORC2 UpgrRaceUndead2=1,racepreset,6,WESTRING_UPGRRACEUNDEAD2 UpgrRaceNightelf2=1,racepreset,7,WESTRING_UPGRRACENIGHTELF2 VeryBright=1,brightnesshex,"`ff`",WESTRING_PRESET_FF Bright=1,brightnesshex,"`bb`",WESTRING_PRESET_BB NormalBright=1,brightnesshex,"`99`",WESTRING_PRESET_99 QuiteDark=1,brightnesshex,"`55`",WESTRING_PRESET_55 Dark=1,brightnesshex,"`00`",WESTRING_PRESET_00 ColorRed=1,colorhex,"`ff0000`",WESTRING_PRESET_COLORRED ColorBlue=1,colorhex,"`0000ff`",WESTRING_PRESET_COLORBLUE ColorCyan=1,colorhex,"`00ffff`",WESTRING_PRESET_COLORCYAN ColorPurple=1,colorhex,"`660099`",WESTRING_PRESET_COLORPURPLE ColorYellow=1,colorhex,"`ffff00`",WESTRING_PRESET_COLORYELLOW ColorOrange=1,colorhex,"`ff9933`",WESTRING_PRESET_COLORORANGE ColorGreen=1,colorhex,"`00ff00`",WESTRING_PRESET_COLORGREEN ColorPink=1,colorhex,"`ff00ff`",WESTRING_PRESET_COLORPINK ColorLightGray=1,colorhex,"`dddddd`",WESTRING_PRESET_COLORLIGHTGRAY ColorLightBlue=1,colorhex,"`33ccff`",WESTRING_PRESET_COLORLIGHTBLUE ColorAqua=1,colorhex,"`7fffd4`",WESTRING_PRESET_COLORAQUA ColorBrown=1,colorhex,"`660000`",WESTRING_PRESET_COLORBROWN ColorBlack=1,colorhex,"`000000`",WESTRING_PRESET_COLORBLACK ColorWhite=1,colorhex,"`ffffff`",WESTRING_PRESET_COLORWHITE ColorGold=1,colorhex,"`ffcc00`",WESTRING_PRESET_COLORGOLD ColorHexSNOW=1,colorhex,`FFFAFA`,WESTRING_HEXPRESET_SNOW ColorHexGHOSTWHITE=1,colorhex,`F8F8FF`,WESTRING_HEXPRESET_GHOSTWHITE ColorHexWHITESMOKE=1,colorhex,`F5F5F5`,WESTRING_HEXPRESET_WHITESMOKE ColorHexGAINSBORO=1,colorhex,`DCDCDC`,WESTRING_HEXPRESET_GAINSBORO ColorHexFLORALWHITE=1,colorhex,`FFFAF0`,WESTRING_HEXPRESET_FLORALWHITE ColorHexOLDLACE=1,colorhex,`FDF5E6`,WESTRING_HEXPRESET_OLDLACE ColorHexLINEN=1,colorhex,`FAF0E6`,WESTRING_HEXPRESET_LINEN ColorHexANTIQUEWHITE=1,colorhex,`FAEBD7`,WESTRING_HEXPRESET_ANTIQUEWHITE ColorHexPAPAYAWHIP=1,colorhex,`FFEFD5`,WESTRING_HEXPRESET_PAPAYAWHIP ColorHexBLANCHEDALMOND=1,colorhex,`FFEBCD`,WESTRING_HEXPRESET_BLANCHEDALMOND ColorHexBISQUE=1,colorhex,`FFE4C4`,WESTRING_HEXPRESET_BISQUE ColorHexPEACHPUFF=1,colorhex,`FFDAB9`,WESTRING_HEXPRESET_PEACHPUFF ColorHexNAVAJOWHITE=1,colorhex,`FFDEAD`,WESTRING_HEXPRESET_NAVAJOWHITE ColorHexMOCCASIN=1,colorhex,`FFE4B5`,WESTRING_HEXPRESET_MOCCASIN ColorHexCORNSILK=1,colorhex,`FFF8DC`,WESTRING_HEXPRESET_CORNSILK ColorHexIVORY=1,colorhex,`FFFFF0`,WESTRING_HEXPRESET_IVORY ColorHexLEMONCHIFFON=1,colorhex,`FFFACD`,WESTRING_HEXPRESET_LEMONCHIFFON ColorHexSEASHELL=1,colorhex,`FFF5EE`,WESTRING_HEXPRESET_SEASHELL ColorHexHONEYDEW=1,colorhex,`F0FFF0`,WESTRING_HEXPRESET_HONEYDEW ColorHexMINTCREAM=1,colorhex,`F5FFFA`,WESTRING_HEXPRESET_MINTCREAM ColorHexAZURE=1,colorhex,`F0FFFF`,WESTRING_HEXPRESET_AZURE ColorHexALICEBLUE=1,colorhex,`F0F8FF`,WESTRING_HEXPRESET_ALICEBLUE ColorHexLAVENDER=1,colorhex,`E6E6FA`,WESTRING_HEXPRESET_LAVENDER ColorHexLAVENDERBLUSH=1,colorhex,`FFF0F5`,WESTRING_HEXPRESET_LAVENDERBLUSH ColorHexMISTYROSE=1,colorhex,`FFE4E1`,WESTRING_HEXPRESET_MISTYROSE ColorHexWHITE=1,colorhex,`FFFFFF`,WESTRING_HEXPRESET_WHITE ColorHexBLACK=1,colorhex,`000000`,WESTRING_HEXPRESET_BLACK ColorHexDARKSLATEGRAY=1,colorhex,`2F4F4F`,WESTRING_HEXPRESET_DARKSLATEGRAY ColorHexDARKSLATEGREY=1,colorhex,`2F4F4F`,WESTRING_HEXPRESET_DARKSLATEGREY ColorHexDIMGRAY=1,colorhex,`696969`,WESTRING_HEXPRESET_DIMGRAY ColorHexDIMGREY=1,colorhex,`696969`,WESTRING_HEXPRESET_DIMGREY ColorHexSLATEGRAY=1,colorhex,`708090`,WESTRING_HEXPRESET_SLATEGRAY ColorHexSLATEGREY=1,colorhex,`708090`,WESTRING_HEXPRESET_SLATEGREY ColorHexLIGHTSLATEGRAY=1,colorhex,`778899`,WESTRING_HEXPRESET_LIGHTSLATEGRAY ColorHexLIGHTSLATEGREY=1,colorhex,`778899`,WESTRING_HEXPRESET_LIGHTSLATEGREY ColorHexGRAY=1,colorhex,`BEBEBE`,WESTRING_HEXPRESET_GRAY ColorHexGREY=1,colorhex,`BEBEBE`,WESTRING_HEXPRESET_GREY ColorHexLIGHTGREY=1,colorhex,`D3D3D3`,WESTRING_HEXPRESET_LIGHTGREY ColorHexLIGHTGRAY=1,colorhex,`D3D3D3`,WESTRING_HEXPRESET_LIGHTGRAY ColorHexMIDNIGHTBLUE=1,colorhex,`191970`,WESTRING_HEXPRESET_MIDNIGHTBLUE ColorHexNAVY=1,colorhex,`000080`,WESTRING_HEXPRESET_NAVY ColorHexNAVYBLUE=1,colorhex,`000080`,WESTRING_HEXPRESET_NAVYBLUE ColorHexCORNFLOWERBLUE=1,colorhex,`6495ED`,WESTRING_HEXPRESET_CORNFLOWERBLUE ColorHexDARKSLATEBLUE=1,colorhex,`483D8B`,WESTRING_HEXPRESET_DARKSLATEBLUE ColorHexSLATEBLUE=1,colorhex,`6A5ACD`,WESTRING_HEXPRESET_SLATEBLUE ColorHexMEDIUMSLATEBLUE=1,colorhex,`7B68EE`,WESTRING_HEXPRESET_MEDIUMSLATEBLUE ColorHexLIGHTSLATEBLUE=1,colorhex,`8470FF`,WESTRING_HEXPRESET_LIGHTSLATEBLUE ColorHexMEDIUMBLUE=1,colorhex,`0000CD`,WESTRING_HEXPRESET_MEDIUMBLUE ColorHexROYALBLUE=1,colorhex,`4169E1`,WESTRING_HEXPRESET_ROYALBLUE ColorHexBLUE=1,colorhex,`0000FF`,WESTRING_HEXPRESET_BLUE ColorHexDODGERBLUE=1,colorhex,`1E90FF`,WESTRING_HEXPRESET_DODGERBLUE ColorHexDEEPSKYBLUE=1,colorhex,`00BFFF`,WESTRING_HEXPRESET_DEEPSKYBLUE ColorHexSKYBLUE=1,colorhex,`87CEEB`,WESTRING_HEXPRESET_SKYBLUE ColorHexLIGHTSKYBLUE=1,colorhex,`87CEFA`,WESTRING_HEXPRESET_LIGHTSKYBLUE ColorHexSTEELBLUE=1,colorhex,`4682B4`,WESTRING_HEXPRESET_STEELBLUE ColorHexLIGHTSTEELBLUE=1,colorhex,`B0C4DE`,WESTRING_HEXPRESET_LIGHTSTEELBLUE ColorHexLIGHTBLUE=1,colorhex,`ADD8E6`,WESTRING_HEXPRESET_LIGHTBLUE ColorHexPOWDERBLUE=1,colorhex,`B0E0E6`,WESTRING_HEXPRESET_POWDERBLUE ColorHexPALETURQUOISE=1,colorhex,`AFEEEE`,WESTRING_HEXPRESET_PALETURQUOISE ColorHexDARKTURQUOISE=1,colorhex,`00CED1`,WESTRING_HEXPRESET_DARKTURQUOISE ColorHexMEDIUMTURQUOISE=1,colorhex,`48D1CC`,WESTRING_HEXPRESET_MEDIUMTURQUOISE ColorHexTURQUOISE=1,colorhex,`40E0D0`,WESTRING_HEXPRESET_TURQUOISE ColorHexCYAN=1,colorhex,`00FFFF`,WESTRING_HEXPRESET_CYAN ColorHexLIGHTCYAN=1,colorhex,`E0FFFF`,WESTRING_HEXPRESET_LIGHTCYAN ColorHexCADETBLUE=1,colorhex,`5F9EA0`,WESTRING_HEXPRESET_CADETBLUE ColorHexMEDIUMAQUAMARINE=1,colorhex,`66CDAA`,WESTRING_HEXPRESET_MEDIUMAQUAMARINE ColorHexAQUAMARINE=1,colorhex,`7FFFD4`,WESTRING_HEXPRESET_AQUAMARINE ColorHexDARKGREEN=1,colorhex,`006400`,WESTRING_HEXPRESET_DARKGREEN ColorHexDARKOLIVEGREEN=1,colorhex,`556B2F`,WESTRING_HEXPRESET_DARKOLIVEGREEN ColorHexDARKSEAGREEN=1,colorhex,`8FBC8F`,WESTRING_HEXPRESET_DARKSEAGREEN ColorHexSEAGREEN=1,colorhex,`2E8B57`,WESTRING_HEXPRESET_SEAGREEN ColorHexMEDIUMSEAGREEN=1,colorhex,`3CB371`,WESTRING_HEXPRESET_MEDIUMSEAGREEN ColorHexLIGHTSEAGREEN=1,colorhex,`20B2AA`,WESTRING_HEXPRESET_LIGHTSEAGREEN ColorHexPALEGREEN=1,colorhex,`98FB98`,WESTRING_HEXPRESET_PALEGREEN ColorHexSPRINGGREEN=1,colorhex,`00FF7F`,WESTRING_HEXPRESET_SPRINGGREEN ColorHexLAWNGREEN=1,colorhex,`7CFC00`,WESTRING_HEXPRESET_LAWNGREEN ColorHexGREEN=1,colorhex,`00FF00`,WESTRING_HEXPRESET_GREEN ColorHexCHARTREUSE=1,colorhex,`7FFF00`,WESTRING_HEXPRESET_CHARTREUSE ColorHexMEDIUMSPRINGGREEN=1,colorhex,`00FA9A`,WESTRING_HEXPRESET_MEDIUMSPRINGGREEN ColorHexGREENYELLOW=1,colorhex,`ADFF2F`,WESTRING_HEXPRESET_GREENYELLOW ColorHexLIMEGREEN=1,colorhex,`32CD32`,WESTRING_HEXPRESET_LIMEGREEN ColorHexYELLOWGREEN=1,colorhex,`9ACD32`,WESTRING_HEXPRESET_YELLOWGREEN ColorHexFORESTGREEN=1,colorhex,`228B22`,WESTRING_HEXPRESET_FORESTGREEN ColorHexOLIVEDRAB=1,colorhex,`6B8E23`,WESTRING_HEXPRESET_OLIVEDRAB ColorHexDARKKHAKI=1,colorhex,`BDB76B`,WESTRING_HEXPRESET_DARKKHAKI ColorHexKHAKI=1,colorhex,`F0E68C`,WESTRING_HEXPRESET_KHAKI ColorHexPALEGOLDENROD=1,colorhex,`EEE8AA`,WESTRING_HEXPRESET_PALEGOLDENROD ColorHexLIGHTGOLDENRODYELLOW=1,colorhex,`FAFAD2`,WESTRING_HEXPRESET_LIGHTGOLDENRODYELLOW ColorHexLIGHTYELLOW=1,colorhex,`FFFFE0`,WESTRING_HEXPRESET_LIGHTYELLOW ColorHexYELLOW=1,colorhex,`FFFF00`,WESTRING_HEXPRESET_YELLOW ColorHexGOLD=1,colorhex,`FFD700`,WESTRING_HEXPRESET_GOLD ColorHexLIGHTGOLDENROD=1,colorhex,`EEDD82`,WESTRING_HEXPRESET_LIGHTGOLDENROD ColorHexGOLDENROD=1,colorhex,`DAA520`,WESTRING_HEXPRESET_GOLDENROD ColorHexDARKGOLDENROD=1,colorhex,`B8860B`,WESTRING_HEXPRESET_DARKGOLDENROD ColorHexROSYBROWN=1,colorhex,`BC8F8F`,WESTRING_HEXPRESET_ROSYBROWN ColorHexINDIAN=1,colorhex,`CD5C5C`,WESTRING_HEXPRESET_INDIAN ColorHexINDIANRED=1,colorhex,`CD5C5C`,WESTRING_HEXPRESET_INDIANRED ColorHexSADDLEBROWN=1,colorhex,`8B4513`,WESTRING_HEXPRESET_SADDLEBROWN ColorHexSIENNA=1,colorhex,`A0522D`,WESTRING_HEXPRESET_SIENNA ColorHexPERU=1,colorhex,`CD853F`,WESTRING_HEXPRESET_PERU ColorHexBURLYWOOD=1,colorhex,`DEB887`,WESTRING_HEXPRESET_BURLYWOOD ColorHexBEIGE=1,colorhex,`F5F5DC`,WESTRING_HEXPRESET_BEIGE ColorHexWHEAT=1,colorhex,`F5DEB3`,WESTRING_HEXPRESET_WHEAT ColorHexSANDYBROWN=1,colorhex,`F4A460`,WESTRING_HEXPRESET_SANDYBROWN ColorHexTAN=1,colorhex,`D2B48C`,WESTRING_HEXPRESET_TAN ColorHexCHOCOLATE=1,colorhex,`D2691E`,WESTRING_HEXPRESET_CHOCOLATE ColorHexFIREBRICK=1,colorhex,`B22222`,WESTRING_HEXPRESET_FIREBRICK ColorHexBROWN=1,colorhex,`A52A2A`,WESTRING_HEXPRESET_BROWN ColorHexDARKSALMON=1,colorhex,`E9967A`,WESTRING_HEXPRESET_DARKSALMON ColorHexSALMON=1,colorhex,`FA8072`,WESTRING_HEXPRESET_SALMON ColorHexLIGHTSALMON=1,colorhex,`FFA07A`,WESTRING_HEXPRESET_LIGHTSALMON ColorHexORANGE=1,colorhex,`FFA500`,WESTRING_HEXPRESET_ORANGE ColorHexDARKORANGE=1,colorhex,`FF8C00`,WESTRING_HEXPRESET_DARKORANGE ColorHexCORAL=1,colorhex,`FF7F50`,WESTRING_HEXPRESET_CORAL ColorHexLIGHTCORAL=1,colorhex,`F08080`,WESTRING_HEXPRESET_LIGHTCORAL ColorHexTOMATO=1,colorhex,`FF6347`,WESTRING_HEXPRESET_TOMATO ColorHexORANGERED=1,colorhex,`FF4500`,WESTRING_HEXPRESET_ORANGERED ColorHexRED=1,colorhex,`FF0000`,WESTRING_HEXPRESET_RED ColorHexHOTPINK=1,colorhex,`FF69B4`,WESTRING_HEXPRESET_HOTPINK ColorHexDEEPPINK=1,colorhex,`FF1493`,WESTRING_HEXPRESET_DEEPPINK ColorHexPINK=1,colorhex,`FFC0CB`,WESTRING_HEXPRESET_PINK ColorHexLIGHTPINK=1,colorhex,`FFB6C1`,WESTRING_HEXPRESET_LIGHTPINK ColorHexPALEVIOLETRED=1,colorhex,`DB7093`,WESTRING_HEXPRESET_PALEVIOLETRED ColorHexMAROON=1,colorhex,`B03060`,WESTRING_HEXPRESET_MAROON ColorHexMEDIUMVIOLETRED=1,colorhex,`C71585`,WESTRING_HEXPRESET_MEDIUMVIOLETRED ColorHexVIOLETRED=1,colorhex,`D02090`,WESTRING_HEXPRESET_VIOLETRED ColorHexMAGENTA=1,colorhex,`FF00FF`,WESTRING_HEXPRESET_MAGENTA ColorHexVIOLET=1,colorhex,`EE82EE`,WESTRING_HEXPRESET_VIOLET ColorHexPLUM=1,colorhex,`DDA0DD`,WESTRING_HEXPRESET_PLUM ColorHexORCHID=1,colorhex,`DA70D6`,WESTRING_HEXPRESET_ORCHID ColorHexMEDIUMORCHID=1,colorhex,`BA55D3`,WESTRING_HEXPRESET_MEDIUMORCHID ColorHexDARKORCHID=1,colorhex,`9932CC`,WESTRING_HEXPRESET_DARKORCHID ColorHexDARKVIOLET=1,colorhex,`9400D3`,WESTRING_HEXPRESET_DARKVIOLET ColorHexBLUEVIOLET=1,colorhex,`8A2BE2`,WESTRING_HEXPRESET_BLUEVIOLET ColorHexPURPLE=1,colorhex,`A020F0`,WESTRING_HEXPRESET_PURPLE ColorHexMEDIUMPURPLE=1,colorhex,`9370DB`,WESTRING_HEXPRESET_MEDIUMPURPLE ColorHexTHISTLE=1,colorhex,`D8BFD8`,WESTRING_HEXPRESET_THISTLE ColorHexDARKGREY=1,colorhex,`A9A9A9`,WESTRING_HEXPRESET_DARKGREY ColorHexDARKGRAY=1,colorhex,`A9A9A9`,WESTRING_HEXPRESET_DARKGRAY ColorHexDARKBLUE=1,colorhex,`00008B`,WESTRING_HEXPRESET_DARKBLUE ColorHexDARKCYAN=1,colorhex,`008B8B`,WESTRING_HEXPRESET_DARKCYAN ColorHexDARKMAGENTA=1,colorhex,`8B008B`,WESTRING_HEXPRESET_DARKMAGENTA ColorHexDARKRED=1,colorhex,`8B0000`,WESTRING_HEXPRESET_DARKRED ColorHexLIGHTGREEN=1,colorhex,`90EE90`,WESTRING_HEXPRESET_LIGHTGREEN Anim1=1,string,"`stand`",WESTRING_ANIM1 Anim2=1,string,"`walk`",WESTRING_ANIM2 Anim3=1,string,"`attack`",WESTRING_ANIM3 Anim4=1,string,"`death`",WESTRING_ANIM4 Anim5=1,string,"`decay`",WESTRING_ANIM5 Anim6=1,string,"`spell`",WESTRING_ANIM6 Anim7=1,string,"`dissipate`",WESTRING_ANIM7 Anim8=1,string,"`birth`",WESTRING_ANIM8 Anim9=1,string,"`morph`",WESTRING_ANIM9 ATag1=1,string,"`gold`",WESTRING_ATAG1 ATag2=1,string,"`lumber`",WESTRING_ATAG2 ATag3=1,string,"`ready`",WESTRING_ATAG3 ATag4=1,string,"`work`",WESTRING_ATAG4 ATag5=1,string,"`bone`",WESTRING_ATAG5 ATag6=1,string,"`flesh`",WESTRING_ATAG6 ATag7=1,string,"`victory`",WESTRING_ATAG7 ATag8=1,string,"`defend`",WESTRING_ATAG8 ATag9=1,string,"`spell`",WESTRING_ATAG9 ATag10=1,string,"`one`",WESTRING_ATAG10 ATag11=1,string,"`two`",WESTRING_ATAG11 ATag12=1,string,"`channel`",WESTRING_ATAG12 ATag13=1,string,"`alternate`",WESTRING_ATAG13 ATag14=1,string,"`hit`",WESTRING_ATAG14 ATag15=1,string,"`slam`",WESTRING_ATAG15 ATag16=1,string,"`throw`",WESTRING_ATAG16 ATag17=1,string,"`morph`",WESTRING_ATAG17 ATag18=1,string,"`fast`",WESTRING_ATAG18 ATag19=1,string,"`cinematic`",WESTRING_ATAG19 ATag20=1,string,"`upgrade`",WESTRING_ATAG20 ATag21=1,string,"`first`",WESTRING_ATAG21 ATag22=1,string,"`second`",WESTRING_ATAG22 ATag23=1,string,"`eat tree`",WESTRING_ATAG23 ATag24=1,string,"`itch head`",WESTRING_ATAG24 ATag25=1,string,"`stretch`",WESTRING_ATAG25 ATag26=1,string,"`talk gesture`",WESTRING_ATAG26 ATag27=1,string,"`wail`",WESTRING_ATAG27 ATag28=1,string,"`chain lightning`",WESTRING_ATAG28 AnimationAttack=0,string,`attack`,WESTRING_ANIMATION_ATTACK AnimationAttackAlternate=0,string,`attack alternate`,WESTRING_ANIMATION_ATTACKALTERNATE AnimationAttackOneAlternate=0,string,`attack one alternate`,WESTRING_ANIMATION_ATTACKONEALTERNATE AnimationAttackDefend=0,string,`attack defend`,WESTRING_ANIMATION_ATTACKDEFEND AnimationAttackGold=0,string,`attack gold`,WESTRING_ANIMATION_ATTACKGOLD AnimationAttackLumber=0,string,`attack lumber`,WESTRING_ANIMATION_ATTACKLUMBER AnimationAttackRange=0,string,`attack range`,WESTRING_ANIMATION_ATTACKRANGE AnimationAttackSlam=0,string,`attack slam`,WESTRING_ANIMATION_ATTACKSLAM AnimationAttackSlamAlternate=0,string,`attack slam alternate`,WESTRING_ANIMATION_ATTACKSLAMALTERNATE AnimationAttackSpell=0,string,`attack spell`,WESTRING_ANIMATION_ATTACKSPELL AnimationAttackSpellAlternate=0,string,`attack spell alternate`,WESTRING_ANIMATION_ATTACKSPELLALTERNATE AnimationAttackSpellSwim=0,string,`attack spell swim`,WESTRING_ANIMATION_ATTACKSPELLSWIM AnimationAttackStandReadyUpgradeSecond=0,string,`attack stand ready upgrade second`,WESTRING_ANIMATION_ATTACKSTANDREADYUPGRADESECOND AnimationAttackSwim=0,string,`attack swim`,WESTRING_ANIMATION_ATTACKSWIM AnimationAttackSwimSpell=0,string,`attack swim spell`,WESTRING_ANIMATION_ATTACKSWIMSPELL AnimationAttackTwoAlternate=0,string,`attack two alternate`,WESTRING_ANIMATION_ATTACKTWOALTERNATE AnimationAttackUpgrade=0,string,`attack upgrade`,WESTRING_ANIMATION_ATTACKUPGRADE AnimationAttackUpgradeFirst=0,string,`attack upgrade first`,WESTRING_ANIMATION_ATTACKUPGRADEFIRST AnimationAttackUpgradeSecond=0,string,`attack upgrade second`,WESTRING_ANIMATION_ATTACKUPGRADESECOND AnimationAttackWalkStandSpin=0,string,`attack walk stand spin`,WESTRING_ANIMATION_ATTACKWALKSTANDSPIN AnimationBirth=0,string,`birth`,WESTRING_ANIMATION_BIRTH AnimationBirthAlternate=0,string,`birth alternate`,WESTRING_ANIMATION_BIRTHALTERNATE AnimationBirthUpgradeFirst=0,string,`birth upgrade first`,WESTRING_ANIMATION_BIRTHUPGRADEFIRST AnimationBirthUpgradesecond=0,string,`birth upgrade second`,WESTRING_ANIMATION_BIRTHUPGRADESECOND AnimationDeath=0,string,`death`,WESTRING_ANIMATION_DEATH AnimationDeathAlternate=0,string,`death alternate`,WESTRING_ANIMATION_DEATHALTERNATE AnimationDeathSpell=0,string,`death spell`,WESTRING_ANIMATION_DEATHSPELL AnimationDeathSwim=0,string,`death swim`,WESTRING_ANIMATION_DEATHSWIM AnimationDeathUpgrade=0,string,`death upgrade`,WESTRING_ANIMATION_DEATHUPGRADE AnimationDecayAlternate=0,string,`decay alternate`,WESTRING_ANIMATION_DECAYALTERNATE AnimationDecayAlternateBone=0,string,`decay alternate bone`,WESTRING_ANIMATION_DECAYALTERNATEBONE AnimationDecayBone=0,string,`decay bone`,WESTRING_ANIMATION_DECAYBONE AnimationDecayFlesh=0,string,`decay flesh`,WESTRING_ANIMATION_DECAYFLESH AnimationDecayFleshAlternate=0,string,`decay flesh alternate`,WESTRING_ANIMATION_DECAYFLESHALTERNATE AnimationDecayUpgrade=0,string,`decay upgrade`,WESTRING_ANIMATION_DECAYUPGRADE AnimationDissipate=0,string,`dissipate`,WESTRING_ANIMATION_DISSIPATE AnimationDissipateAlternate=0,string,`dissipate alternate`,WESTRING_ANIMATION_DISSIPATEALTERNATE AnimationDissipateSwim=0,string,`dissipate swim`,WESTRING_ANIMATION_DISSIPATESWIM AnimationMorph=0,string,`morph`,WESTRING_ANIMATION_MORPH AnimationMorphAlternate=0,string,`morph alternate`,WESTRING_ANIMATION_MORPHALTERNATE AnimationMorphAlternateSwim=0,string,`morph alternate swim`,WESTRING_ANIMATION_MORPHALTERNATESWIM AnimationMorphDefend=0,string,`morph defend`,WESTRING_ANIMATION_MORPHDEFEND AnimationMorphSwim=0,string,`morph swim`,WESTRING_ANIMATION_MORPHSWIM AnimationSpell=0,string,`spell`,WESTRING_ANIMATION_SPELL AnimationSpellAlternate=0,string,`spell alternate`,WESTRING_ANIMATION_SPELLALTERNATE AnimationSpellAttack=0,string,`spell attack`,WESTRING_ANIMATION_SPELLATTACK AnimationSpellChainLightning=0,string,`spell chain lightning`,WESTRING_ANIMATION_SPELLCHAINLIGHTNING AnimationSpellChannel=0,string,`spell channel`,WESTRING_ANIMATION_SPELLCHANNEL AnimationSpellEatTree=0,string,`spell eat tree`,WESTRING_ANIMATION_SPELLEATTREE AnimationSpellMorph=0,string,`spell morph`,WESTRING_ANIMATION_SPELLMORPH AnimationSpellPuke=0,string,`spell puke`,WESTRING_ANIMATION_SPELLPUKE AnimationSpellSlam=0,string,`spell slam`,WESTRING_ANIMATION_SPELLSLAM AnimationSpellSwim=0,string,`spell swim`,WESTRING_ANIMATION_SPELLSWIM AnimationSpellThrow=0,string,`spell throw`,WESTRING_ANIMATION_SPELLTHROW AnimationSpellUpgrade=0,string,`spell upgrade`,WESTRING_ANIMATION_SPELLUPGRADE AnimationStand=0,string,`stand`,WESTRING_ANIMATION_STAND AnimationStandAlternate=0,string,`stand alternate`,WESTRING_ANIMATION_STANDALTERNATE AnimationStandAlternateSwim=0,string,`stand alternate swim`,WESTRING_ANIMATION_STANDALTERNATESWIM AnimationStandAlternateUpgradeFirstSecond=0,string,`stand alternate upgrade first second`,WESTRING_ANIMATION_STANDALTERNATEUPGRADEFIRSTSECOND AnimationStandBirthAlternateWorkUpgradeFirstSecond=0,string,`stand birth alternate work upgrade first second`,WESTRING_ANIMATION_STANDBIRTHALTERNATEWORKUPGRADESECOND AnimationStandChannel=0,string,`stand channel`,WESTRING_ANIMATION_STANDCHANNEL AnimationStandChannelLumber=0,string,`stand channel lumber`,WESTRING_ANIMATION_STANDCHANNELLUMBER AnimationStandCinematic=0,string,`stand cinematic`,WESTRING_ANIMATION_STANDCINEMATIC AnimationStandDefend=0,string,`stand defend`,WESTRING_ANIMATION_STANDDEFEND AnimationStandGold=0,string,`stand gold`,WESTRING_ANIMATION_STANDGOLD AnimationStandHit=0,string,`stand hit`,WESTRING_ANIMATION_STANDHIT AnimationStandLumber=0,string,`stand lumber`,WESTRING_ANIMATION_STANDLUMBER AnimationStandReady=0,string,`stand ready`,WESTRING_ANIMATION_STANDREADY AnimationStandReadyAlternate=0,string,`stand ready alternate`,WESTRING_ANIMATION_STANDREADYALTERNATE AnimationStandReadyAttack=0,string,`stand ready attack`,WESTRING_ANIMATION_STANDREADYATTACK AnimationStandReadyGold=0,string,`stand ready gold`,WESTRING_ANIMATION_STANDREADYGOLD AnimationStandReadyLumber=0,string,`stand ready lumber`,WESTRING_ANIMATION_STANDREADYLUMBER AnimationStandReadySwim=0,string,`stand ready swim`,WESTRING_ANIMATION_STANDREADYSWIM AnimationStandSwim=0,string,`stand swim`,WESTRING_ANIMATION_STANDSWIM AnimationStandUpgrade=0,string,`stand upgrade`,WESTRING_ANIMATION_STANDUPGRADE AnimationStandUpgradeFirst=0,string,`stand upgrade first`,WESTRING_ANIMATION_STANDUPGRADEFIRST AnimationStandUpgradeFirstSecond=0,string,`stand upgrade first second`,WESTRING_ANIMATION_STANDUPGRADEFIRSTSECOND AnimationStandUpgradeFirstReadyAttack=0,string,`stand upgrade first ready attack`,WESTRING_ANIMATION_STANDUPGRADEFIRSTREADYATTACK AnimationStandUpgradeSecond=0,string,`stand upgrade second`,WESTRING_ANIMATION_STANDUPGRADESECOND AnimationStandUpgradeThirdAttackReady=0,string,`stand upgrade third attack ready`,WESTRING_ANIMATION_STANDUPGRADETHIRDATTACKREADY AnimationStandVictory=0,string,`stand victory`,WESTRING_ANIMATION_STANDVICTORY AnimationStandWalkAlternate=0,string,`stand walk alternate`,WESTRING_ANIMATION_STANDWALKALTERNATE AnimationStandWork=0,string,`stand work`,WESTRING_ANIMATION_STANDWORK AnimationStandWorkAlternate=0,string,`stand work alternate`,WESTRING_ANIMATION_STANDWORKALTERNATE AnimationStandWorkGold=0,string,`stand work gold`,WESTRING_ANIMATION_STANDWORKGOLD AnimationStandWorkLumber=0,string,`stand work lumber`,WESTRING_ANIMATION_STANDWORKLUMBER AnimationStandWorkSwim=0,string,`stand work swim`,WESTRING_ANIMATION_STANDWORKSWIM AnimationStandWorkUpgradeFirst=0,string,`stand work upgrade first`,WESTRING_ANIMATION_STANDWORKUPGRADEFIRST AnimationStandWorkUpgradeSecond=0,string,`stand work upgrade second`,WESTRING_ANIMATION_STANDWORKUPGRADESECOND AnimationWalk=0,string,`walk`,WESTRING_ANIMATION_WALK AnimationWalkAlternate=0,string,`walk alternate`,WESTRING_ANIMATION_WALKALTERNATE AnimationWalkChannel=0,string,`walk channel`,WESTRING_ANIMATION_WALKCHANNEL AnimationWalkChannelFast=0,string,`walk channel fast`,WESTRING_ANIMATION_WALKCHANNELFAST AnimationWalkDefend=0,string,`walk defend`,WESTRING_ANIMATION_WALKDEFEND AnimationWalkFast=0,string,`walk fast`,WESTRING_ANIMATION_WALKFAST AnimationWalkGold=0,string,`walk gold`,WESTRING_ANIMATION_WALKGOLD AnimationWalkLumber=0,string,`walk lumber`,WESTRING_ANIMATION_WALKLUMBER AnimationWalkSwim=0,string,`walk swim`,WESTRING_ANIMATION_WALKSWIM AnimationWalkUpgrade=0,string,`walk upgrade`,WESTRING_ANIMATION_WALKUPGRADE HexPresetSNOW=0,string,`c|FFFAFA`,WESTRING_HEXPRESET_SNOW HexPresetGHOSTWHITE=0,string,`c|F8F8FF`,WESTRING_HEXPRESET_GHOSTWHITE HexPresetWHITESMOKE=0,string,`c|F5F5F5`,WESTRING_HEXPRESET_WHITESMOKE HexPresetGAINSBORO=0,string,`c|DCDCDC`,WESTRING_HEXPRESET_GAINSBORO HexPresetFLORALWHITE=0,string,`c|FFFAF0`,WESTRING_HEXPRESET_FLORALWHITE HexPresetOLDLACE=0,string,`c|FDF5E6`,WESTRING_HEXPRESET_OLDLACE HexPresetLINEN=0,string,`c|FAF0E6`,WESTRING_HEXPRESET_LINEN HexPresetANTIQUEWHITE=0,string,`c|FAEBD7`,WESTRING_HEXPRESET_ANTIQUEWHITE HexPresetPAPAYAWHIP=0,string,`c|FFEFD5`,WESTRING_HEXPRESET_PAPAYAWHIP HexPresetBLANCHEDALMOND=0,string,`c|FFEBCD`,WESTRING_HEXPRESET_BLANCHEDALMOND HexPresetBISQUE=0,string,`c|FFE4C4`,WESTRING_HEXPRESET_BISQUE HexPresetPEACHPUFF=0,string,`c|FFDAB9`,WESTRING_HEXPRESET_PEACHPUFF HexPresetNAVAJOWHITE=0,string,`c|FFDEAD`,WESTRING_HEXPRESET_NAVAJOWHITE HexPresetMOCCASIN=0,string,`c|FFE4B5`,WESTRING_HEXPRESET_MOCCASIN HexPresetCORNSILK=0,string,`c|FFF8DC`,WESTRING_HEXPRESET_CORNSILK HexPresetIVORY=0,string,`c|FFFFF0`,WESTRING_HEXPRESET_IVORY HexPresetLEMONCHIFFON=0,string,`c|FFFACD`,WESTRING_HEXPRESET_LEMONCHIFFON HexPresetSEASHELL=0,string,`c|FFF5EE`,WESTRING_HEXPRESET_SEASHELL HexPresetHONEYDEW=0,string,`c|F0FFF0`,WESTRING_HEXPRESET_HONEYDEW HexPresetMINTCREAM=0,string,`c|F5FFFA`,WESTRING_HEXPRESET_MINTCREAM HexPresetAZURE=0,string,`c|F0FFFF`,WESTRING_HEXPRESET_AZURE HexPresetALICEBLUE=0,string,`c|F0F8FF`,WESTRING_HEXPRESET_ALICEBLUE HexPresetLAVENDER=0,string,`c|E6E6FA`,WESTRING_HEXPRESET_LAVENDER HexPresetLAVENDERBLUSH=0,string,`c|FFF0F5`,WESTRING_HEXPRESET_LAVENDERBLUSH HexPresetMISTYROSE=0,string,`c|FFE4E1`,WESTRING_HEXPRESET_MISTYROSE HexPresetWHITE=0,string,`c|FFFFFF`,WESTRING_HEXPRESET_WHITE HexPresetBLACK=0,string,`c|000000`,WESTRING_HEXPRESET_BLACK HexPresetDARKSLATEGRAY=0,string,`c|2F4F4F`,WESTRING_HEXPRESET_DARKSLATEGRAY HexPresetDARKSLATEGREY=0,string,`c|2F4F4F`,WESTRING_HEXPRESET_DARKSLATEGREY HexPresetDIMGRAY=0,string,`c|696969`,WESTRING_HEXPRESET_DIMGRAY HexPresetDIMGREY=0,string,`c|696969`,WESTRING_HEXPRESET_DIMGREY HexPresetSLATEGRAY=0,string,`c|708090`,WESTRING_HEXPRESET_SLATEGRAY HexPresetSLATEGREY=0,string,`c|708090`,WESTRING_HEXPRESET_SLATEGREY HexPresetLIGHTSLATEGRAY=0,string,`c|778899`,WESTRING_HEXPRESET_LIGHTSLATEGRAY HexPresetLIGHTSLATEGREY=0,string,`c|778899`,WESTRING_HEXPRESET_LIGHTSLATEGREY HexPresetGRAY=0,string,`c|BEBEBE`,WESTRING_HEXPRESET_GRAY HexPresetGREY=0,string,`c|BEBEBE`,WESTRING_HEXPRESET_GREY HexPresetLIGHTGREY=0,string,`c|D3D3D3`,WESTRING_HEXPRESET_LIGHTGREY HexPresetLIGHTGRAY=0,string,`c|D3D3D3`,WESTRING_HEXPRESET_LIGHTGRAY HexPresetMIDNIGHTBLUE=0,string,`c|191970`,WESTRING_HEXPRESET_MIDNIGHTBLUE HexPresetNAVY=0,string,`c|000080`,WESTRING_HEXPRESET_NAVY HexPresetNAVYBLUE=0,string,`c|000080`,WESTRING_HEXPRESET_NAVYBLUE HexPresetCORNFLOWERBLUE=0,string,`c|6495ED`,WESTRING_HEXPRESET_CORNFLOWERBLUE HexPresetDARKSLATEBLUE=0,string,`c|483D8B`,WESTRING_HEXPRESET_DARKSLATEBLUE HexPresetSLATEBLUE=0,string,`c|6A5ACD`,WESTRING_HEXPRESET_SLATEBLUE HexPresetMEDIUMSLATEBLUE=0,string,`c|7B68EE`,WESTRING_HEXPRESET_MEDIUMSLATEBLUE HexPresetLIGHTSLATEBLUE=0,string,`c|8470FF`,WESTRING_HEXPRESET_LIGHTSLATEBLUE HexPresetMEDIUMBLUE=0,string,`c|0000CD`,WESTRING_HEXPRESET_MEDIUMBLUE HexPresetROYALBLUE=0,string,`c|4169E1`,WESTRING_HEXPRESET_ROYALBLUE HexPresetBLUE=0,string,`c|0000FF`,WESTRING_HEXPRESET_BLUE HexPresetDODGERBLUE=0,string,`c|1E90FF`,WESTRING_HEXPRESET_DODGERBLUE HexPresetDEEPSKYBLUE=0,string,`c|00BFFF`,WESTRING_HEXPRESET_DEEPSKYBLUE HexPresetSKYBLUE=0,string,`c|87CEEB`,WESTRING_HEXPRESET_SKYBLUE HexPresetLIGHTSKYBLUE=0,string,`c|87CEFA`,WESTRING_HEXPRESET_LIGHTSKYBLUE HexPresetSTEELBLUE=0,string,`c|4682B4`,WESTRING_HEXPRESET_STEELBLUE HexPresetLIGHTSTEELBLUE=0,string,`c|B0C4DE`,WESTRING_HEXPRESET_LIGHTSTEELBLUE HexPresetLIGHTBLUE=0,string,`c|ADD8E6`,WESTRING_HEXPRESET_LIGHTBLUE HexPresetPOWDERBLUE=0,string,`c|B0E0E6`,WESTRING_HEXPRESET_POWDERBLUE HexPresetPALETURQUOISE=0,string,`c|AFEEEE`,WESTRING_HEXPRESET_PALETURQUOISE HexPresetDARKTURQUOISE=0,string,`c|00CED1`,WESTRING_HEXPRESET_DARKTURQUOISE HexPresetMEDIUMTURQUOISE=0,string,`c|48D1CC`,WESTRING_HEXPRESET_MEDIUMTURQUOISE HexPresetTURQUOISE=0,string,`c|40E0D0`,WESTRING_HEXPRESET_TURQUOISE HexPresetCYAN=0,string,`c|00FFFF`,WESTRING_HEXPRESET_CYAN HexPresetLIGHTCYAN=0,string,`c|E0FFFF`,WESTRING_HEXPRESET_LIGHTCYAN HexPresetCADETBLUE=0,string,`c|5F9EA0`,WESTRING_HEXPRESET_CADETBLUE HexPresetMEDIUMAQUAMARINE=0,string,`c|66CDAA`,WESTRING_HEXPRESET_MEDIUMAQUAMARINE HexPresetAQUAMARINE=0,string,`c|7FFFD4`,WESTRING_HEXPRESET_AQUAMARINE HexPresetDARKGREEN=0,string,`c|006400`,WESTRING_HEXPRESET_DARKGREEN HexPresetDARKOLIVEGREEN=0,string,`c|556B2F`,WESTRING_HEXPRESET_DARKOLIVEGREEN HexPresetDARKSEAGREEN=0,string,`c|8FBC8F`,WESTRING_HEXPRESET_DARKSEAGREEN HexPresetSEAGREEN=0,string,`c|2E8B57`,WESTRING_HEXPRESET_SEAGREEN HexPresetMEDIUMSEAGREEN=0,string,`c|3CB371`,WESTRING_HEXPRESET_MEDIUMSEAGREEN HexPresetLIGHTSEAGREEN=0,string,`c|20B2AA`,WESTRING_HEXPRESET_LIGHTSEAGREEN HexPresetPALEGREEN=0,string,`c|98FB98`,WESTRING_HEXPRESET_PALEGREEN HexPresetSPRINGGREEN=0,string,`c|00FF7F`,WESTRING_HEXPRESET_SPRINGGREEN HexPresetLAWNGREEN=0,string,`c|7CFC00`,WESTRING_HEXPRESET_LAWNGREEN HexPresetGREEN=0,string,`c|00FF00`,WESTRING_HEXPRESET_GREEN HexPresetCHARTREUSE=0,string,`c|7FFF00`,WESTRING_HEXPRESET_CHARTREUSE HexPresetMEDIUMSPRINGGREEN=0,string,`c|00FA9A`,WESTRING_HEXPRESET_MEDIUMSPRINGGREEN HexPresetGREENYELLOW=0,string,`c|ADFF2F`,WESTRING_HEXPRESET_GREENYELLOW HexPresetLIMEGREEN=0,string,`c|32CD32`,WESTRING_HEXPRESET_LIMEGREEN HexPresetYELLOWGREEN=0,string,`c|9ACD32`,WESTRING_HEXPRESET_YELLOWGREEN HexPresetFORESTGREEN=0,string,`c|228B22`,WESTRING_HEXPRESET_FORESTGREEN HexPresetOLIVEDRAB=0,string,`c|6B8E23`,WESTRING_HEXPRESET_OLIVEDRAB HexPresetDARKKHAKI=0,string,`c|BDB76B`,WESTRING_HEXPRESET_DARKKHAKI HexPresetKHAKI=0,string,`c|F0E68C`,WESTRING_HEXPRESET_KHAKI HexPresetPALEGOLDENROD=0,string,`c|EEE8AA`,WESTRING_HEXPRESET_PALEGOLDENROD HexPresetLIGHTGOLDENRODYELLOW=0,string,`c|FAFAD2`,WESTRING_HEXPRESET_LIGHTGOLDENRODYELLOW HexPresetLIGHTYELLOW=0,string,`c|FFFFE0`,WESTRING_HEXPRESET_LIGHTYELLOW HexPresetYELLOW=0,string,`c|FFFF00`,WESTRING_HEXPRESET_YELLOW HexPresetGOLD=0,string,`c|FFD700`,WESTRING_HEXPRESET_GOLD HexPresetLIGHTGOLDENROD=0,string,`c|EEDD82`,WESTRING_HEXPRESET_LIGHTGOLDENROD HexPresetGOLDENROD=0,string,`c|DAA520`,WESTRING_HEXPRESET_GOLDENROD HexPresetDARKGOLDENROD=0,string,`c|B8860B`,WESTRING_HEXPRESET_DARKGOLDENROD HexPresetROSYBROWN=0,string,`c|BC8F8F`,WESTRING_HEXPRESET_ROSYBROWN HexPresetINDIAN=0,string,`c|CD5C5C`,WESTRING_HEXPRESET_INDIAN HexPresetINDIANRED=0,string,`c|CD5C5C`,WESTRING_HEXPRESET_INDIANRED HexPresetSADDLEBROWN=0,string,`c|8B4513`,WESTRING_HEXPRESET_SADDLEBROWN HexPresetSIENNA=0,string,`c|A0522D`,WESTRING_HEXPRESET_SIENNA HexPresetPERU=0,string,`c|CD853F`,WESTRING_HEXPRESET_PERU HexPresetBURLYWOOD=0,string,`c|DEB887`,WESTRING_HEXPRESET_BURLYWOOD HexPresetBEIGE=0,string,`c|F5F5DC`,WESTRING_HEXPRESET_BEIGE HexPresetWHEAT=0,string,`c|F5DEB3`,WESTRING_HEXPRESET_WHEAT HexPresetSANDYBROWN=0,string,`c|F4A460`,WESTRING_HEXPRESET_SANDYBROWN HexPresetTAN=0,string,`c|D2B48C`,WESTRING_HEXPRESET_TAN HexPresetCHOCOLATE=0,string,`c|D2691E`,WESTRING_HEXPRESET_CHOCOLATE HexPresetFIREBRICK=0,string,`c|B22222`,WESTRING_HEXPRESET_FIREBRICK HexPresetBROWN=0,string,`c|A52A2A`,WESTRING_HEXPRESET_BROWN HexPresetDARKSALMON=0,string,`c|E9967A`,WESTRING_HEXPRESET_DARKSALMON HexPresetSALMON=0,string,`c|FA8072`,WESTRING_HEXPRESET_SALMON HexPresetLIGHTSALMON=0,string,`c|FFA07A`,WESTRING_HEXPRESET_LIGHTSALMON HexPresetORANGE=0,string,`c|FFA500`,WESTRING_HEXPRESET_ORANGE HexPresetDARKORANGE=0,string,`c|FF8C00`,WESTRING_HEXPRESET_DARKORANGE HexPresetCORAL=0,string,`c|FF7F50`,WESTRING_HEXPRESET_CORAL HexPresetLIGHTCORAL=0,string,`c|F08080`,WESTRING_HEXPRESET_LIGHTCORAL HexPresetTOMATO=0,string,`c|FF6347`,WESTRING_HEXPRESET_TOMATO HexPresetORANGERED=0,string,`c|FF4500`,WESTRING_HEXPRESET_ORANGERED HexPresetRED=0,string,`c|FF0000`,WESTRING_HEXPRESET_RED HexPresetHOTPINK=0,string,`c|FF69B4`,WESTRING_HEXPRESET_HOTPINK HexPresetDEEPPINK=0,string,`c|FF1493`,WESTRING_HEXPRESET_DEEPPINK HexPresetPINK=0,string,`c|FFC0CB`,WESTRING_HEXPRESET_PINK HexPresetLIGHTPINK=0,string,`c|FFB6C1`,WESTRING_HEXPRESET_LIGHTPINK HexPresetPALEVIOLETRED=0,string,`c|DB7093`,WESTRING_HEXPRESET_PALEVIOLETRED HexPresetMAROON=0,string,`c|B03060`,WESTRING_HEXPRESET_MAROON HexPresetMEDIUMVIOLETRED=0,string,`c|C71585`,WESTRING_HEXPRESET_MEDIUMVIOLETRED HexPresetVIOLETRED=0,string,`c|D02090`,WESTRING_HEXPRESET_VIOLETRED HexPresetMAGENTA=0,string,`c|FF00FF`,WESTRING_HEXPRESET_MAGENTA HexPresetVIOLET=0,string,`c|EE82EE`,WESTRING_HEXPRESET_VIOLET HexPresetPLUM=0,string,`c|DDA0DD`,WESTRING_HEXPRESET_PLUM HexPresetORCHID=0,string,`c|DA70D6`,WESTRING_HEXPRESET_ORCHID HexPresetMEDIUMORCHID=0,string,`c|BA55D3`,WESTRING_HEXPRESET_MEDIUMORCHID HexPresetDARKORCHID=0,string,`c|9932CC`,WESTRING_HEXPRESET_DARKORCHID HexPresetDARKVIOLET=0,string,`c|9400D3`,WESTRING_HEXPRESET_DARKVIOLET HexPresetBLUEVIOLET=0,string,`c|8A2BE2`,WESTRING_HEXPRESET_BLUEVIOLET HexPresetPURPLE=0,string,`c|A020F0`,WESTRING_HEXPRESET_PURPLE HexPresetMEDIUMPURPLE=0,string,`c|9370DB`,WESTRING_HEXPRESET_MEDIUMPURPLE HexPresetTHISTLE=0,string,`c|D8BFD8`,WESTRING_HEXPRESET_THISTLE HexPresetDARKGREY=0,string,`c|A9A9A9`,WESTRING_HEXPRESET_DARKGREY HexPresetDARKGRAY=0,string,`c|A9A9A9`,WESTRING_HEXPRESET_DARKGRAY HexPresetDARKBLUE=0,string,`c|00008B`,WESTRING_HEXPRESET_DARKBLUE HexPresetDARKCYAN=0,string,`c|008B8B`,WESTRING_HEXPRESET_DARKCYAN HexPresetDARKMAGENTA=0,string,`c|8B008B`,WESTRING_HEXPRESET_DARKMAGENTA HexPresetDARKRED=0,string,`c|8B0000`,WESTRING_HEXPRESET_DARKRED HexPresetLIGHTGREEN=0,string,`c|90EE90`,WESTRING_HEXPRESET_LIGHTGREEN HexPresetEndColor=0,string,`r|`,WESTRING_HEXPRESET_ENDCOLOR LargeSmallOptionLarge=1,largesmalloption,true,WESTRING_LARGESMALLOPTIONLARGE LargeSmallOptionSmall=1,largesmalloption,false,WESTRING_LARGESMALLOPTIONSMALL BuildableOptionBuildable=1,buildableoption,false,WESTRING_BUILDABLEOPTIONBUILDABLE BuildableOptionUnbuildable=1,buildableoption,true,WESTRING_BUILDABLEOPTIONUNBUILDABLE DropOptionRemove=1,dropoption,true,WESTRING_DROPOPTIONREMOVE DropOptionDrop=1,dropoption,false,WESTRING_DROPOPTIONDROP UnitEventSummon=0,unitevent,EVENT_UNIT_SUMMON,WESTRING_UEVENT_SUMMON Player00=0,player,Player(0),WESTRING_PLAYER_00 Player01=0,player,Player(1),WESTRING_PLAYER_01 Player02=0,player,Player(2),WESTRING_PLAYER_02 Player03=0,player,Player(3),WESTRING_PLAYER_03 Player04=0,player,Player(4),WESTRING_PLAYER_04 Player05=0,player,Player(5),WESTRING_PLAYER_05 Player06=0,player,Player(6),WESTRING_PLAYER_06 Player07=0,player,Player(7),WESTRING_PLAYER_07 Player08=0,player,Player(8),WESTRING_PLAYER_08 Player09=0,player,Player(9),WESTRING_PLAYER_09 Player10=0,player,Player(10),WESTRING_PLAYER_10 Player11=0,player,Player(11),WESTRING_PLAYER_11 PlayerNA=0,player,Player(PLAYER_NEUTRAL_AGGRESSIVE),WESTRING_PLAYER_NA PlayerNV=0,player,Player(bj_PLAYER_NEUTRAL_VICTIM),WESTRING_PLAYER_NV PlayerNE=0,player,Player(bj_PLAYER_NEUTRAL_EXTRA),WESTRING_PLAYER_NE PlayerNP=0,player,Player(PLAYER_NEUTRAL_PASSIVE),WESTRING_PLAYER_NP Force00=0,force,bj_FORCE_PLAYER[0],WESTRING_FORCE_00 Force01=0,force,bj_FORCE_PLAYER[1],WESTRING_FORCE_01 Force02=0,force,bj_FORCE_PLAYER[2],WESTRING_FORCE_02 Force03=0,force,bj_FORCE_PLAYER[3],WESTRING_FORCE_03 Force04=0,force,bj_FORCE_PLAYER[4],WESTRING_FORCE_04 Force05=0,force,bj_FORCE_PLAYER[5],WESTRING_FORCE_05 Force06=0,force,bj_FORCE_PLAYER[6],WESTRING_FORCE_06 Force07=0,force,bj_FORCE_PLAYER[7],WESTRING_FORCE_07 Force08=0,force,bj_FORCE_PLAYER[8],WESTRING_FORCE_08 Force09=0,force,bj_FORCE_PLAYER[9],WESTRING_FORCE_09 Force10=0,force,bj_FORCE_PLAYER[10],WESTRING_FORCE_10 Force11=0,force,bj_FORCE_PLAYER[11],WESTRING_FORCE_11 ForceNA=0,force,bj_FORCE_PLAYER[PLAYER_NEUTRAL_AGGRESSIVE],WESTRING_FORCE_NA ForceNV=0,force,bj_FORCE_PLAYER[bj_PLAYER_NEUTRAL_VICTIM],WESTRING_FORCE_NV ForceNE=0,force,bj_FORCE_PLAYER[bj_PLAYER_NEUTRAL_EXTRA],WESTRING_FORCE_NE ForceNP=0,force,bj_FORCE_PLAYER[PLAYER_NEUTRAL_PASSIVE],WESTRING_FORCE_NP Color00=0,playercolor,PLAYER_COLOR_RED,WESTRING_UNITCOLOR_00 Color01=0,playercolor,PLAYER_COLOR_BLUE,WESTRING_UNITCOLOR_01 Color02=0,playercolor,PLAYER_COLOR_CYAN,WESTRING_UNITCOLOR_02 Color03=0,playercolor,PLAYER_COLOR_PURPLE,WESTRING_UNITCOLOR_03 Color04=0,playercolor,PLAYER_COLOR_YELLOW,WESTRING_UNITCOLOR_04 Color05=0,playercolor,PLAYER_COLOR_ORANGE,WESTRING_UNITCOLOR_05 Color06=0,playercolor,PLAYER_COLOR_GREEN,WESTRING_UNITCOLOR_06 Color07=0,playercolor,PLAYER_COLOR_PINK,WESTRING_UNITCOLOR_07 Color08=0,playercolor,PLAYER_COLOR_LIGHT_GRAY,WESTRING_UNITCOLOR_08 Color09=0,playercolor,PLAYER_COLOR_LIGHT_BLUE,WESTRING_UNITCOLOR_09 Color10=0,playercolor,PLAYER_COLOR_AQUA,WESTRING_UNITCOLOR_10 Color11=0,playercolor,PLAYER_COLOR_BROWN,WESTRING_UNITCOLOR_11 Color12=1,playercolor,ConvertPlayerColor(12),WESTRING_UNITCOLOR_12 RaceHuman=0,race,RACE_HUMAN,WESTRING_TRIGRACE_HUMAN RaceOrc=0,race,RACE_ORC,WESTRING_TRIGRACE_ORC RaceUndead=0,race,RACE_UNDEAD,WESTRING_TRIGRACE_UNDEAD RaceNightElf=0,race,RACE_NIGHTELF,WESTRING_TRIGRACE_NIGHTELF RaceDemon=0,race,RACE_DEMON,WESTRING_TRIGRACE_DEMON ItemTypeAny=1,itemtype,ITEM_TYPE_ANY,WESTRING_ITEMTYPE_ANY ItemTypePermanent=1,itemtype,ITEM_TYPE_PERMANENT,WESTRING_ITEMTYPE_PERMANENT ItemTypeCharged=1,itemtype,ITEM_TYPE_CHARGED,WESTRING_ITEMTYPE_CHARGED ItemTypePowerup=1,itemtype,ITEM_TYPE_POWERUP,WESTRING_ITEMTYPE_POWERUP ItemTypeArtifact=1,itemtype,ITEM_TYPE_ARTIFACT,WESTRING_ITEMTYPE_ARTIFACT ItemTypePurchasable=1,itemtype,ITEM_TYPE_PURCHASABLE,WESTRING_ITEMTYPE_PURCHASABLE ItemTypeCampaign=1,itemtype,ITEM_TYPE_CAMPAIGN,WESTRING_ITEMTYPE_CAMPAIGN ItemTypeMiscellaneous=1,itemtype,ITEM_TYPE_MISCELLANEOUS,WESTRING_ITEMTYPE_MISCELLANEOUS ItemTypeUnknown=1,itemtype,ITEM_TYPE_UNKNOWN,WESTRING_ITEMTYPE_UNKNOWN UnitNull=0,unit,null,WESTRING_TRIGUNIT_NULL UnitTypeNull=0,unitcode,0,WESTRING_TRIGUNITTYPE_NULL ItemNull=0,item,null,WESTRING_TRIGITEM_NULL DestructableNull=0,destructable,null,WESTRING_TRIGDESTRUCTABLE_NULL RectNull=0,rect,null,WESTRING_TRIGRECT_NULL SoundNull=0,sound,null,WESTRING_TRIGSOUND_NULL MusicFileMusic=0,musicfile,`music`,WESTRING_TRIGMUSICFILE_MUSIC LimitOpEqual=0,limitop,EQUAL,WESTRING_LIMITOP_EQUAL LimitOpNotEqual=0,limitop,NOT_EQUAL,WESTRING_LIMITOP_NOTEQUAL LimitOpLessThan=0,limitop,LESS_THAN,WESTRING_LIMITOP_LESSTHAN LimitOpLessThanOrEqual=0,limitop,LESS_THAN_OR_EQUAL,WESTRING_LIMITOP_LESSTHANOREQUAL LimitOpGreaterThan=0,limitop,GREATER_THAN,WESTRING_LIMITOP_GREATERTHAN LimitOpGreaterThanOrEqual=0,limitop,GREATER_THAN_OR_EQUAL,WESTRING_LIMITOP_GREATERTHANOREQUAL GameResultWin=0,playergameresult,PLAYER_GAME_RESULT_VICTORY,WESTRING_VICTORY GameResultLose=0,playergameresult,PLAYER_GAME_RESULT_DEFEAT,WESTRING_DEFEAT GameResultDraw=0,playergameresult,PLAYER_GAME_RESULT_TIE,WESTRING_DRAW MapFlagUseHandicaps=0,mapflag,MAP_USE_HANDICAPS,WESTRING_MAPFLAG_USEHANDICAPS MapFlagObservers=0,mapflag,MAP_OBSERVERS,WESTRING_MAPFLAG_OBSERVERS MapFlagObserversChat=0,mapflag,MAP_OBSERVERS_ON_DEATH,WESTRING_MAPFLAG_OBSERVERSONDEATH MapFlagResourceTradingLock=0,mapflag,MAP_LOCK_RESOURCE_TRADING,WESTRING_MAPFLAG_RESOURCETRADINGLOCK MapFlagResourceTradingAllies=0,mapflag,MAP_RESOURCE_TRADING_ALLIES_ONLY,WESTRING_MAPFLAG_RESOURCETRADINGALLIES MapFlagAllianceChangesLock=0,mapflag,MAP_LOCK_ALLIANCE_CHANGES,WESTRING_MAPFLAG_ALLIANCECHANGESLOCK MapFlagAllianceChangesHidden=0,mapflag,MAP_ALLIANCE_CHANGES_HIDDEN,WESTRING_MAPFLAG_ALLIANCECHANGESHIDDEN MapFlagMapReloaded=1,mapflag,MAP_RELOADED,WESTRING_MAPFLAG_MAPRELOADED MapFlagRandomHeroes=1,mapflag,MAP_RANDOM_HERO,WESTRING_MAPFLAG_RANDOM_HERO MapFlagRandomRaces=1,mapflag,MAP_RANDOM_RACES,WESTRING_MAPFLAG_RANDOM_RACES MapFlagFogHideTerrain=1,mapflag,MAP_FOG_HIDE_TERRAIN,WESTRING_MAPFLAG_FOG_HIDE_TERRAIN MapFlagFogMapExplored=1,mapflag,MAP_FOG_MAP_EXPLORED,WESTRING_MAPFLAG_FOG_MAP_EXPLORED MapFlagFogAlwaysVisible=1,mapflag,MAP_FOG_ALWAYS_VISIBLE,WESTRING_MAPFLAG_FOG_ALWAYS_VISIBLE PlayerStateGold=0,playerstate,PLAYER_STATE_RESOURCE_GOLD,WESTRING_PSTATE_GOLD PlayerStateLumber=0,playerstate,PLAYER_STATE_RESOURCE_LUMBER,WESTRING_PSTATE_LUMBER PlayerStateHeroTokens=0,playerstate,PLAYER_STATE_RESOURCE_HERO_TOKENS,WESTRING_PSTATE_HEROTOKENS PlayerStateGoldUpkeepRate=0,playerstate,PLAYER_STATE_GOLD_UPKEEP_RATE,WESTRING_PSTATE_UPKEEPGOLD PlayerStateLumberUpkeepRate=0,playerstate,PLAYER_STATE_LUMBER_UPKEEP_RATE,WESTRING_PSTATE_UPKEEPLUMBER PlayerStateGoldGathered=0,playerstate,PLAYER_STATE_GOLD_GATHERED,WESTRING_PSTATE_GOLDGATHERED PlayerStateLumberGathered=0,playerstate,PLAYER_STATE_LUMBER_GATHERED,WESTRING_PSTATE_LUMBER_GATHERED PlayerStateFoodUsed=0,playerstate,PLAYER_STATE_RESOURCE_FOOD_USED,WESTRING_PSTATE_FOODUSED PlayerStateFoodCap=0,playerstate,PLAYER_STATE_RESOURCE_FOOD_CAP,WESTRING_PSTATE_FOODCAP PlayerStateFoodLimit=0,playerstate,PLAYER_STATE_FOOD_CAP_CEILING,WESTRING_PSTATE_FOODCAPLIMIT PlayerStateGameResult=0,playerstate,PLAYER_STATE_GAME_RESULT,WESTRING_PSTATE_GAMERESULT PlayerScoreUnitsTrained=1,playerscore,PLAYER_SCORE_UNITS_TRAINED,WESTRING_PSCORE_UNITSTRAINED PlayerScoreUnitsKilled=1,playerscore,PLAYER_SCORE_UNITS_KILLED,WESTRING_PSCORE_UNITSKILLED PlayerScoreStructBuilt=1,playerscore,PLAYER_SCORE_STRUCT_BUILT,WESTRING_PSCORE_STRUCTBUILT PlayerScoreStructRazed=1,playerscore,PLAYER_SCORE_STRUCT_RAZED,WESTRING_PSCORE_STRUCTRAZED PlayerScoreTechPercent=1,playerscore,PLAYER_SCORE_TECH_PERCENT,WESTRING_PSCORE_TECHPERCENT PlayerScoreFoodProd=1,playerscore,PLAYER_SCORE_FOOD_MAXPROD,WESTRING_PSCORE_FOODPROD PlayerScoreFoodUsed=1,playerscore,PLAYER_SCORE_FOOD_MAXUSED,WESTRING_PSCORE_FOODUSED PlayerScoreHeroesKilled=1,playerscore,PLAYER_SCORE_HEROES_KILLED,WESTRING_PSCORE_HEROESKILLED PlayerScoreItemsGained=1,playerscore,PLAYER_SCORE_ITEMS_GAINED,WESTRING_PSCORE_ITEMSGAINED PlayerScoreMercsHired=1,playerscore,PLAYER_SCORE_MERCS_HIRED,WESTRING_PSCORE_MERCSHIRED PlayerScoreGoldTotal=1,playerscore,PLAYER_SCORE_GOLD_MINED_TOTAL,WESTRING_PSCORE_GOLDTOTAL PlayerScoreGoldUpkeep=1,playerscore,PLAYER_SCORE_GOLD_MINED_UPKEEP,WESTRING_PSCORE_GOLDUPKEEP PlayerScoreGoldLostUpkeep=1,playerscore,PLAYER_SCORE_GOLD_LOST_UPKEEP,WESTRING_PSCORE_GOLDLOSTUPKEEP PlayerScoreGoldLostTax=1,playerscore,PLAYER_SCORE_GOLD_LOST_TAX,WESTRING_PSCORE_GOLDLOSTTAX PlayerScoreGoldGiven=1,playerscore,PLAYER_SCORE_GOLD_GIVEN,WESTRING_PSCORE_GOLDGIVEN PlayerScoreGoldReceived=1,playerscore,PLAYER_SCORE_GOLD_RECEIVED,WESTRING_PSCORE_GOLDRECEIVED PlayerScoreLumberTotal=1,playerscore,PLAYER_SCORE_LUMBER_TOTAL,WESTRING_PSCORE_LUMBERTOTAL PlayerScoreLumberLostUpkeep=1,playerscore,PLAYER_SCORE_LUMBER_LOST_UPKEEP,WESTRING_PSCORE_LUMBERLOSTUPKEEP PlayerScoreLumberLostTax=1,playerscore,PLAYER_SCORE_LUMBER_LOST_TAX,WESTRING_PSCORE_LUMBERLOSTTAX PlayerScoreLumberGiven=1,playerscore,PLAYER_SCORE_LUMBER_GIVEN,WESTRING_PSCORE_LUMBERGIVEN PlayerScoreLumberReceived=1,playerscore,PLAYER_SCORE_LUMBER_RECEIVED,WESTRING_PSCORE_LUMBERECEIVED PlayerScoreUnitTotal=1,playerscore,PLAYER_SCORE_UNIT_TOTAL,WESTRING_PSCORE_UNITTOTAL PlayerScoreHeroTotal=1,playerscore,PLAYER_SCORE_HERO_TOTAL,WESTRING_PSCORE_HEROTOTAL PlayerScoreResourceTotal=1,playerscore,PLAYER_SCORE_RESOURCE_TOTAL,WESTRING_PSCORE_RESOURCETOTAL PlayerScoreTotal=1,playerscore,PLAYER_SCORE_TOTAL,WESTRING_PSCORE_TOTAL PlayerFlagUnfollowable=0,playerflag,PLAYER_STATE_UNFOLLOWABLE,WESTRING_PFLAG_UNFOLLOWABLE PlayerFlagGivesBounty=0,playerflag,PLAYER_STATE_GIVES_BOUNTY,WESTRING_PFLAG_GIVESBOUNTY PlayerFlagAlliedVictory=0,playerflag,PLAYER_STATE_ALLIED_VICTORY,WESTRING_PFLAG_ALLIEDVICTORY GateOperationClosed=0,gateoperation,bj_GATEOPERATION_CLOSE,WESTRING_GATEOPERATION_CLOSE GateOperationOpen=0,gateoperation,bj_GATEOPERATION_OPEN,WESTRING_GATEOPERATION_OPEN GateOperationDestroyed=0,gateoperation,bj_GATEOPERATION_DESTROY,WESTRING_GATEOPERATION_DESTROY ElevatorWallOpClose=1,elevatorwallop,false,WESTRING_ELEVATORWALLOP_CLOSE ElevatorWallOpOpen=1,elevatorwallop,true,WESTRING_ELEVATORWALLOP_OPEN ElevatorWallTypeAll=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_ALL,WESTRING_ELEVATORWALLTYPE_ALL ElevatorWallTypeEast=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_EAST,WESTRING_ELEVATORWALLTYPE_EAST ElevatorWallTypeNorth=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_NORTH,WESTRING_ELEVATORWALLTYPE_NORTH ElevatorWallTypeSouth=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_SOUTH,WESTRING_ELEVATORWALLTYPE_SOUTH ElevatorWallTypeWest=1,elevatorwalltype,bj_ELEVATOR_WALL_TYPE_WEST,WESTRING_ELEVATORWALLTYPE_WEST UseSkipOptionUse=0,useskipoption,true,WESTRING_USESKIPOPTION_USE UseSkipOptionSkip=0,useskipoption,false,WESTRING_USESKIPOPTION_SKIP SelDeselOptionSel=0,seldeseloption,true,WESTRING_SELDESELOPTION_SEL SelDeselOptionDesel=0,seldeseloption,false,WESTRING_SELDESELOPTION_DESEL AICaptainAttack=1,aicaptaintype,true,WESTRING_AICAPTAIN_ATTACK AICaptainDefense=1,aicaptaintype,false,WESTRING_AICAPTAIN_DEFENSE AICommandPop=1,aicommandpop,true,WESTRING_AICOMMAND_REMOVE AICommandLeave=1,aicommandpop,false,WESTRING_AICOMMAND_LEAVE CacheValueTypeBoolean=1,cachevaluetype,bj_GAMECACHE_BOOLEAN,WESTRING_CACHEVALUETYPE_BOOLEAN CacheValueTypeInteger=1,cachevaluetype,bj_GAMECACHE_INTEGER,WESTRING_CACHEVALUETYPE_INTEGER CacheValueTypeReal=1,cachevaluetype,bj_GAMECACHE_REAL,WESTRING_CACHEVALUETYPE_REAL CacheValueTypeUnit=1,cachevaluetype,bj_GAMECACHE_UNIT,WESTRING_CACHEVALUETYPE_UNIT CacheValueTypeString=1,cachevaluetype,bj_GAMECACHE_STRING,WESTRING_CACHEVALUETYPE_STRING MapControlNone=0,mapcontrol,MAP_CONTROL_NONE,WESTRING_MAPCONTROL_NONE MapControlUser=0,mapcontrol,MAP_CONTROL_USER,WESTRING_MAPCONTROL_USER MapControlComputer=0,mapcontrol,MAP_CONTROL_COMPUTER,WESTRING_MAPCONTROL_COMPUTER MapControlRescuable=0,mapcontrol,MAP_CONTROL_RESCUABLE,WESTRING_MAPCONTROL_RESCUABLE MapControlNeutral=0,mapcontrol,MAP_CONTROL_NEUTRAL,WESTRING_MAPCONTROL_NEUTRAL MapControlCreep=0,mapcontrol,MAP_CONTROL_CREEP,WESTRING_MAPCONTROL_CREEP PlayerSlotStateEmpty=0,playerslotstate,PLAYER_SLOT_STATE_EMPTY,WESTRING_PSLOT_EMPTY PlayerSlotStatePlaying=0,playerslotstate,PLAYER_SLOT_STATE_PLAYING,WESTRING_PSLOT_PLAYING PlayerSlotStateLeft=0,playerslotstate,PLAYER_SLOT_STATE_LEFT,WESTRING_PSLOT_LEFT PlayerUnitEventDeath=0,playerunitevent,EVENT_PLAYER_UNIT_DEATH,WESTRING_PUEVENT_DEATH PlayerUnitEventDecay=0,playerunitevent,EVENT_PLAYER_UNIT_DECAY,WESTRING_PUEVENT_DECAY PlayerUnitEventChangesOwner=1,playerunitevent,EVENT_PLAYER_UNIT_CHANGE_OWNER,WESTRING_PUEVENT_CHANGESOWNER PlayerUnitEventHero_Level=0,playerunitevent,EVENT_PLAYER_HERO_LEVEL,WESTRING_PUEVENT_HEROLEVEL PlayerUnitEventHero_Skill=0,playerunitevent,EVENT_PLAYER_HERO_SKILL,WESTRING_PUEVENT_HEROSKILL PlayerUnitEventHero_Revivable=0,playerunitevent,EVENT_PLAYER_HERO_REVIVABLE,WESTRING_PUEVENT_HEROREVIVABLE PlayerUnitEventHeroUseItem=0,playerunitevent,EVENT_PLAYER_UNIT_USE_ITEM,WESTRING_PUEVENT_HEROUSEITEM PlayerUnitEventHeroPickUpItem=0,playerunitevent,EVENT_PLAYER_UNIT_PICKUP_ITEM,WESTRING_PUEVENT_HEROPICKUPITEM PlayerUnitEventHeroDropItem=0,playerunitevent,EVENT_PLAYER_UNIT_DROP_ITEM,WESTRING_PUEVENT_HERODROPITEM PlayerUnitEventSell=1,playerunitevent,EVENT_PLAYER_UNIT_SELL,WESTRING_PUEVENT_SELL PlayerUnitEventSellItem=1,playerunitevent,EVENT_PLAYER_UNIT_SELL_ITEM,WESTRING_PUEVENT_SELLITEM PlayerUnitEventPawnItem=1,playerunitevent,EVENT_PLAYER_UNIT_PAWN_ITEM,WESTRING_PUEVENT_PAWNITEM PlayerUnitEventAttacked=0,playerunitevent,EVENT_PLAYER_UNIT_ATTACKED,WESTRING_PUEVENT_ATTACKED PlayerUnitEventRescued=0,playerunitevent,EVENT_PLAYER_UNIT_RESCUED,WESTRING_PUEVENT_RESCUED PlayerUnitEventSummoned=0,playerunitevent,EVENT_PLAYER_UNIT_SUMMON,WESTRING_PUEVENT_SUMMONED PlayerUnitEventSpellChannel=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_CHANNEL,WESTRING_PUEVENT_SPELLCHANNEL PlayerUnitEventSpellCast=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_CAST,WESTRING_PUEVENT_SPELLCAST PlayerUnitEventSpellEndCast=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_ENDCAST,WESTRING_PUEVENT_SPELLENDCAST PlayerUnitEventSpellEffect=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_EFFECT,WESTRING_PUEVENT_SPELLEFFECT PlayerUnitEventSpellFinish=1,playerunitevent,EVENT_PLAYER_UNIT_SPELL_FINISH,WESTRING_PUEVENT_SPELLFINISH PlayerUnitEventLoaded=0,playerunitevent,EVENT_PLAYER_UNIT_LOADED,WESTRING_PUEVENT_LOADED PlayerUnitEventTrain_Start=0,playerunitevent,EVENT_PLAYER_UNIT_TRAIN_START,WESTRING_PUEVENT_TRAINSTART PlayerUnitEventTrain_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_TRAIN_CANCEL,WESTRING_PUEVENT_TRAINCANCEL PlayerUnitEventTrain_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_TRAIN_FINISH,WESTRING_PUEVENT_TRAINFINISH PlayerUnitEventConstruct_Start=0,playerunitevent,EVENT_PLAYER_UNIT_CONSTRUCT_START,WESTRING_PUEVENT_CONSTRUCTSTART PlayerUnitEventConstruct_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL,WESTRING_PUEVENT_CONSTRUCTCANCEL PlayerUnitEventConstruct_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_CONSTRUCT_FINISH,WESTRING_PUEVENT_CONSTRUCTFINISH PlayerUnitEventReviveStart=0,playerunitevent,EVENT_PLAYER_HERO_REVIVE_START,WESTRING_PUEVENT_REVIVESTART PlayerUnitEventReviveCancel=0,playerunitevent,EVENT_PLAYER_HERO_REVIVE_CANCEL,WESTRING_PUEVENT_REVIVECANCEL PlayerUnitEventReviveFinish=0,playerunitevent,EVENT_PLAYER_HERO_REVIVE_FINISH,WESTRING_PUEVENT_REVIVEFINISH PlayerUnitEventUpgrade_Start=0,playerunitevent,EVENT_PLAYER_UNIT_UPGRADE_START,WESTRING_PUEVENT_UPGRADESTART PlayerUnitEventUpgrade_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_UPGRADE_CANCEL,WESTRING_PUEVENT_UPGRADECANCEL PlayerUnitEventUpgrade_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_UPGRADE_FINISH,WESTRING_PUEVENT_UPGRADEFINISH PlayerUnitEventResearch_Start=0,playerunitevent,EVENT_PLAYER_UNIT_RESEARCH_START,WESTRING_PUEVENT_RESEARCHSTART PlayerUnitEventResearch_Cancel=0,playerunitevent,EVENT_PLAYER_UNIT_RESEARCH_CANCEL,WESTRING_PUEVENT_RESEARCHCANCEL PlayerUnitEventResearch_Finish=0,playerunitevent,EVENT_PLAYER_UNIT_RESEARCH_FINISH,WESTRING_PUEVENT_RESEARCHFINISH PlayerUnitEventIssued_Unit_Order=0,playerunitevent,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER,WESTRING_PUEVENT_ISSUEDUNITORDER PlayerUnitEventIssued_Point_Order=0,playerunitevent,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER,WESTRING_PUEVENT_ISSUEDPOINTORDER PlayerUnitEventIssued_Order=0,playerunitevent,EVENT_PLAYER_UNIT_ISSUED_ORDER,WESTRING_PUEVENT_ISSUEDORDER UnitEventDeath=0,unitevent,EVENT_UNIT_DEATH,WESTRING_UEVENT_DEATH UnitEventDecay=0,unitevent,EVENT_UNIT_DECAY,WESTRING_UEVENT_DECAY UnitEventChangesOwner=1,unitevent,EVENT_UNIT_CHANGE_OWNER,WESTRING_UEVENT_CHANGESOWNER UnitEventDamaged=0,unitevent,EVENT_UNIT_DAMAGED,WESTRING_UEVENT_DAMAGED UnitEventHeroLevel=0,unitevent,EVENT_UNIT_HERO_LEVEL,WESTRING_UEVENT_HEROLEVEL UnitEventHeroSkill=0,unitevent,EVENT_UNIT_HERO_SKILL,WESTRING_UEVENT_HEROSKILL UnitEventHeroRevivable=0,unitevent,EVENT_UNIT_HERO_REVIVABLE,WESTRING_UEVENT_HEROREVIVABLE UnitEventHeroUseItem=0,unitevent,EVENT_UNIT_USE_ITEM,WESTRING_UEVENT_HEROUSEITEM UnitEventHeroPickUpItem=0,unitevent,EVENT_UNIT_PICKUP_ITEM,WESTRING_UEVENT_HEROPICKUPITEM UnitEventHeroDropItem=0,unitevent,EVENT_UNIT_DROP_ITEM,WESTRING_UEVENT_HERODROPITEM UnitEventSell=1,unitevent,EVENT_UNIT_SELL,WESTRING_UEVENT_SELL UnitEventSellItem=1,unitevent,EVENT_UNIT_SELL_ITEM,WESTRING_UEVENT_SELLITEM UnitEventPawnItem=1,unitevent,EVENT_UNIT_PAWN_ITEM,WESTRING_UEVENT_PAWNITEM UnitEventAttacked=0,unitevent,EVENT_UNIT_ATTACKED,WESTRING_UEVENT_ATTACKED UnitEventRescued=0,unitevent,EVENT_UNIT_RESCUED,WESTRING_UEVENT_RESCUED UnitEventSelected=0,unitevent,EVENT_UNIT_SELECTED,WESTRING_UEVENT_SELECTED UnitEventDeselected=0,unitevent,EVENT_UNIT_DESELECTED,WESTRING_UEVENT_DESELECTED UnitEventSpellChannel=1,unitevent,EVENT_UNIT_SPELL_CHANNEL,WESTRING_UEVENT_SPELLCHANNEL UnitEventSpellCast=1,unitevent,EVENT_UNIT_SPELL_CAST,WESTRING_UEVENT_SPELLCAST UnitEventSpellEndCast=1,unitevent,EVENT_UNIT_SPELL_ENDCAST,WESTRING_UEVENT_SPELLENDCAST UnitEventSpellEffect=1,unitevent,EVENT_UNIT_SPELL_EFFECT,WESTRING_UEVENT_SPELLEFFECT UnitEventSpellFinish=1,unitevent,EVENT_UNIT_SPELL_FINISH,WESTRING_UEVENT_SPELLFINISH UnitEventLoaded=0,unitevent,EVENT_UNIT_LOADED,WESTRING_UEVENT_LOADED UnitEventAcquiredTarget=0,unitevent,EVENT_UNIT_ACQUIRED_TARGET,WESTRING_UEVENT_ACQUIREDTARGET UnitEventTargetInRange=0,unitevent,EVENT_UNIT_TARGET_IN_RANGE,WESTRING_UEVENT_TARGETINRANGE UnitEventTrainStart=0,unitevent,EVENT_UNIT_TRAIN_START,WESTRING_UEVENT_TRAINSTART UnitEventTrainCancel=0,unitevent,EVENT_UNIT_TRAIN_CANCEL,WESTRING_UEVENT_TRAINCANCEL UnitEventTrainFinish=0,unitevent,EVENT_UNIT_TRAIN_FINISH,WESTRING_UEVENT_TRAINFINISH UnitEventReviveStart=0,unitevent,EVENT_UNIT_HERO_REVIVE_START,WESTRING_UEVENT_REVIVESTART UnitEventReviveCancel=0,unitevent,EVENT_UNIT_HERO_REVIVE_CANCEL,WESTRING_UEVENT_REVIVECANCEL UnitEventReviveFinish=0,unitevent,EVENT_UNIT_HERO_REVIVE_FINISH,WESTRING_UEVENT_REVIVEFINISH UnitEventUpgradeStart=0,unitevent,EVENT_UNIT_UPGRADE_START,WESTRING_UEVENT_UPGRADESTART UnitEventUpgradeCancel=0,unitevent,EVENT_UNIT_UPGRADE_CANCEL,WESTRING_UEVENT_UPGRADECANCEL UnitEventUpgradeFinish=0,unitevent,EVENT_UNIT_UPGRADE_FINISH,WESTRING_UEVENT_UPGRADEFINISH UnitEventResearchStart=0,unitevent,EVENT_UNIT_RESEARCH_START,WESTRING_UEVENT_RESEARCHSTART UnitEventResearchCancel=0,unitevent,EVENT_UNIT_RESEARCH_CANCEL,WESTRING_UEVENT_RESEARCHCANCEL UnitEventResearchFinish=0,unitevent,EVENT_UNIT_RESEARCH_FINISH,WESTRING_UEVENT_RESEARCHFINISH UnitEventIssueUnitOrder=0,unitevent,EVENT_UNIT_ISSUED_TARGET_ORDER,WESTRING_UEVENT_ISSUEUNITORDER UnitEventIssuePointOrder=0,unitevent,EVENT_UNIT_ISSUED_POINT_ORDER,WESTRING_UEVENT_ISSUEPOINTORDER UnitEventIssueOrder=0,unitevent,EVENT_UNIT_ISSUED_ORDER,WESTRING_UEVENT_ISSUEORDER UnitStateLife=0,unitstate,UNIT_STATE_LIFE,WESTRING_USTATE_LIFE UnitStateMaxLife=0,unitstate,UNIT_STATE_MAX_LIFE,WESTRING_USTATE_MAXLIFE UnitStateMana=0,unitstate,UNIT_STATE_MANA,WESTRING_USTATE_MANA UnitStateMaxMana=0,unitstate,UNIT_STATE_MAX_MANA,WESTRING_USTATE_MAXMANA KeyEventTypeDepress=1,keyeventtype,bj_KEYEVENTTYPE_DEPRESS,WESTRING_KEYEVENTTYPE_DEPRESS KeyEventTypeRelease=1,keyeventtype,bj_KEYEVENTTYPE_RELEASE,WESTRING_KEYEVENTTYPE_RELEASE KeyEventKeyLeft=1,keyeventkey,bj_KEYEVENTKEY_LEFT,WESTRING_KEYEVENTKEY_LEFT KeyEventKeyRight=1,keyeventkey,bj_KEYEVENTKEY_RIGHT,WESTRING_KEYEVENTKEY_RIGHT KeyEventKeyDown=1,keyeventkey,bj_KEYEVENTKEY_DOWN,WESTRING_KEYEVENTKEY_DOWN KeyEventKeyUp=1,keyeventkey,bj_KEYEVENTKEY_UP,WESTRING_KEYEVENTKEY_UP UnitTypeStructure=0,unittype,UNIT_TYPE_STRUCTURE,WESTRING_UNITTYPE_STRUCTURE UnitTypeHero=0,unittype,UNIT_TYPE_HERO,WESTRING_UNITTYPE_HERO UnitTypeGround=0,unittype,UNIT_TYPE_GROUND,WESTRING_UNITTYPE_GROUND UnitTypeFlying=0,unittype,UNIT_TYPE_FLYING,WESTRING_UNITTYPE_FLYING UnitTypeAttacksGround=0,unittype,UNIT_TYPE_ATTACKS_GROUND,WESTRING_UNITTYPE_ATTACKSGROUND UnitTypeAttacksFlying=0,unittype,UNIT_TYPE_ATTACKS_FLYING,WESTRING_UNITTYPE_ATTACKSFLYING UnitTypeMeleeAttacker=0,unittype,UNIT_TYPE_MELEE_ATTACKER,WESTRING_UNITTYPE_MELEEATTACKER UnitTypeRangedAttacker=0,unittype,UNIT_TYPE_RANGED_ATTACKER,WESTRING_UNITTYPE_RANGEDATTACKER UnitTypeSummoned=0,unittype,UNIT_TYPE_SUMMONED,WESTRING_UNITTYPE_SUMMONED UnitTypeUndead=0,unittype,UNIT_TYPE_UNDEAD,WESTRING_UNITTYPE_UNDEAD UnitTypeMechanical=0,unittype,UNIT_TYPE_MECHANICAL,WESTRING_UNITTYPE_MECHANICAL UnitTypeAncient=0,unittype,UNIT_TYPE_ANCIENT,WESTRING_UNITTYPE_ANCIENT UnitTypePeon=0,unittype,UNIT_TYPE_PEON,WESTRING_UNITTYPE_PEON UnitTypeTownHall=0,unittype,UNIT_TYPE_TOWNHALL,WESTRING_UNITTYPE_TOWNHALL UnitTypeSapper=0,unittype,UNIT_TYPE_SAPPER,WESTRING_UNITTYPE_SAPPER GameSpeedSlowest=0,gamespeed,MAP_SPEED_SLOWEST,WESTRING_GAMESPEED_SLOWEST GameSpeedSlow=0,gamespeed,MAP_SPEED_SLOW,WESTRING_GAMESPEED_SLOW GameSpeedNormal=0,gamespeed,MAP_SPEED_NORMAL,WESTRING_GAMESPEED_NORMAL GameSpeedFast=0,gamespeed,MAP_SPEED_FAST,WESTRING_GAMESPEED_FAST GameSpeedFastest=0,gamespeed,MAP_SPEED_FASTEST,WESTRING_GAMESPEED_FASTEST GameDifficultyEasy=0,gamedifficulty,MAP_DIFFICULTY_EASY,WESTRING_GAMEDIFFICULTY_EASY GameDifficultyNormal=0,gamedifficulty,MAP_DIFFICULTY_NORMAL,WESTRING_GAMEDIFFICULTY_NORMAL GameDifficultyHard=0,gamedifficulty,MAP_DIFFICULTY_HARD,WESTRING_GAMEDIFFICULTY_HARD AIDifficultyNewbie=0,aidifficulty,AI_DIFFICULTY_NEWBIE,WESTRING_AIDIFFICULTY_NEWBIE AIDifficultyNormal=0,aidifficulty,AI_DIFFICULTY_NORMAL,WESTRING_AIDIFFICULTY_NORMAL AIDifficultyInsane=0,aidifficulty,AI_DIFFICULTY_INSANE,WESTRING_AIDIFFICULTY_INSANE MapDensityNone=0,mapdensity,MAP_DENSITY_NONE,WESTRING_MAPDENSITY_NONE MapDensityLight=0,mapdensity,MAP_DENSITY_LIGHT,WESTRING_MAPDENSITY_LIGHT MapDensityMedium=0,mapdensity,MAP_DENSITY_MEDIUM,WESTRING_MAPDENSITY_MEDIUM MapDensityHeavy=0,mapdensity,MAP_DENSITY_HEAVY,WESTRING_MAPDENSITY_HEAVY AllianceSettingUnallied=0,alliancesetting,bj_ALLIANCE_UNALLIED,WESTRING_ALLIANCE_UNALLIED AllianceSettingUnalliedVision=0,alliancesetting,bj_ALLIANCE_UNALLIED_VISION,WESTRING_ALLIANCE_UNALLIEDVISION AllianceSettingNeutral=0,alliancesetting,bj_ALLIANCE_NEUTRAL,WESTRING_ALLIANCE_NEUTRAL AllianceSettingNeutralVision=1,alliancesetting,bj_ALLIANCE_NEUTRAL_VISION,WESTRING_ALLIANCE_NEUTRAL_VISION AllianceSettingAllied=0,alliancesetting,bj_ALLIANCE_ALLIED,WESTRING_ALLIANCE_ALLIED AllianceSettingAlliedVision=0,alliancesetting,bj_ALLIANCE_ALLIED_VISION,WESTRING_ALLIANCE_ALLIEDVISION AllianceSettingAlliedUnits=0,alliancesetting,bj_ALLIANCE_ALLIED_UNITS,WESTRING_ALLIANCE_ALLIEDUNITS AllianceSettingAlliedAdvUnits=0,alliancesetting,bj_ALLIANCE_ALLIED_ADVUNITS,WESTRING_ALLIANCE_ALLIEDADVUNITS AllianceTypePassive=0,alliancetype,ALLIANCE_PASSIVE,WESTRING_ALLIANCE_PASSIVE AllianceTypeSharedVision=0,alliancetype,ALLIANCE_SHARED_VISION,WESTRING_ALLIANCE_SHAREDVISION AllianceTypeSharedControl=0,alliancetype,ALLIANCE_SHARED_CONTROL,WESTRING_ALLIANCE_SHAREDCONTROL AllianceTypeSharedFullControl=0,alliancetype,ALLIANCE_SHARED_ADVANCED_CONTROL,WESTRING_ALLIANCE_SHAREDFULLCONTROL AllianceTypeXP=0,alliancetype,ALLIANCE_SHARED_XP,WESTRING_ALLIANCE_XP AllianceTypeSpells=0,alliancetype,ALLIANCE_SHARED_SPELLS,WESTRING_ALLIANCE_SPELLS AllianceTypeHelpRequest=0,alliancetype,ALLIANCE_HELP_REQUEST,WESTRING_ALLIANCE_HELPREQUEST AllianceTypeHelpResponse=0,alliancetype,ALLIANCE_HELP_RESPONSE,WESTRING_ALLIANCE_HELPRESPONSE CameraFieldTargetDistance=0,camerafield,CAMERA_FIELD_TARGET_DISTANCE,WESTRING_CAMERA_TARGETDISTANCE CameraFieldFarZ=0,camerafield,CAMERA_FIELD_FARZ,WESTRING_CAMERA_FARZ CameraFieldAOA=0,camerafield,CAMERA_FIELD_ANGLE_OF_ATTACK,WESTRING_CAMERA_AOA CameraFieldFOV=0,camerafield,CAMERA_FIELD_FIELD_OF_VIEW,WESTRING_CAMERA_FOV CameraFieldRoll=0,camerafield,CAMERA_FIELD_ROLL,WESTRING_CAMERA_ROLL CameraFieldRotation=0,camerafield,CAMERA_FIELD_ROTATION,WESTRING_CAMERA_ROTATION CameraFieldZOffset=1,camerafield,CAMERA_FIELD_ZOFFSET,WESTRING_CAMERA_ZOFFSET RarityControlFrequent=0,raritycontrol,RARITY_FREQUENT,WESTRING_RARITY_FREQUENT RarityControlRare=0,raritycontrol,RARITY_RARE,WESTRING_RARITY_RARE BlendModeNone=0,blendmode,BLEND_MODE_NONE,WESTRING_BLENDMODE_NONE BlendModeBlend=0,blendmode,BLEND_MODE_BLEND,WESTRING_BLENDMODE_BLEND BlendModeAdditive=0,blendmode,BLEND_MODE_ADDITIVE,WESTRING_BLENDMODE_ADDITIVE BlendModeModulate=0,blendmode,BLEND_MODE_MODULATE,WESTRING_BLENDMODE_MODULATE BlendModeModulate2x=0,blendmode,BLEND_MODE_MODULATE_2X,WESTRING_BLENDMODE_MODULATE_2X BlendModeKeyAlpha=0,blendmode,BLEND_MODE_KEYALPHA,WESTRING_BLENDMODE_KEYALPHA VolumeGroupAmbient=0,volumegroup,SOUND_VOLUMEGROUP_AMBIENTSOUNDS,WESTRING_VOLUMEGROUP_AMBIENTSOUNDS VolumeGroupSpells=0,volumegroup,SOUND_VOLUMEGROUP_SPELLS,WESTRING_VOLUMEGROUP_SPELLS VolumeGroupCombat=0,volumegroup,SOUND_VOLUMEGROUP_COMBAT,WESTRING_VOLUMEGROUP_COMBAT VolumeGroupFire=0,volumegroup,SOUND_VOLUMEGROUP_FIRE,WESTRING_VOLUMEGROUP_FIRE VolumeGroupMusic=0,volumegroup,SOUND_VOLUMEGROUP_MUSIC,WESTRING_VOLUMEGROUP_MUSIC VolumeGroupUnitMovement=0,volumegroup,SOUND_VOLUMEGROUP_UNITMOVEMENT,WESTRING_VOLUMEGROUP_UNITMOVEMENT VolumeGroupUnitSounds=0,volumegroup,SOUND_VOLUMEGROUP_UNITSOUNDS,WESTRING_VOLUMEGROUP_UNITSOUNDS VolumeGroupUI=0,volumegroup,SOUND_VOLUMEGROUP_UI,WESTRING_VOLUMEGROUP_UI FogStateMasked=0,fogstate,FOG_OF_WAR_MASKED,WESTRING_FOGSTATE_MASKED FogStateFogged=0,fogstate,FOG_OF_WAR_FOGGED,WESTRING_FOGSTATE_FOGGED FogStateVisible=0,fogstate,FOG_OF_WAR_VISIBLE,WESTRING_FOGSTATE_VISIBLE FogStyleLinear=0,fogstyle,0,WESTRING_FOGSTYLE_LINEAR FogStyleExp1=0,fogstyle,1,WESTRING_FOGSTYLE_EXP1 FogStyleExp2=0,fogstyle,2,WESTRING_FOGSTYLE_EXP2 TimedLifeBuffCodeAnimateDead=1,timedlifebuffcode,'BUan',WESTRING_TIMEDLIFEBUFFCODE_ANIMATEDEAD TimedLifeBuffCodePlagueWard=1,timedlifebuffcode,'Bapl',WESTRING_TIMEDLIFEBUFFCODE_PLAGUEWARD TimedLifeBuffCodeForceOfNature=1,timedlifebuffcode,'BEfn',WESTRING_TIMEDLIFEBUFFCODE_FORCEOFNATURE TimedLifeBuffCodeGeneric=1,timedlifebuffcode,'BTLF',WESTRING_TIMEDLIFEBUFFCODE_GENERIC TimedLifeBuffCodeHealingWard=1,timedlifebuffcode,'Bhwd',WESTRING_TIMEDLIFEBUFFCODE_HEALINGWARD TimedLifeBuffCodeRaiseDead=1,timedlifebuffcode,'Brai',WESTRING_TIMEDLIFEBUFFCODE_RAISEDEAD TimedLifeBuffCodeWaterElemental=1,timedlifebuffcode,'BHwe',WESTRING_TIMEDLIFEBUFFCODE_WATERELEMENTAL TimedLifeBuffCodeWaterSummoned=1,timedlifebuffcode,'BFig',WESTRING_TIMEDLIFEBUFFCODE_SUMMONED ItemStatusHidden=1,itemstatus,bj_ITEM_STATUS_HIDDEN,WESTRING_ITEMSTATUS_HIDDEN ItemStatusOwned=1,itemstatus,bj_ITEM_STATUS_OWNED,WESTRING_ITEMSTATUS_OWNED ItemStatusInvulnerable=1,itemstatus,bj_ITEM_STATUS_INVULNERABLE,WESTRING_ITEMSTATUS_INVULNERABLE ItemStatusPowerup=1,itemstatus,bj_ITEM_STATUS_POWERUP,WESTRING_ITEMSTATUS_POWERUP ItemStatusSellable=1,itemstatus,bj_ITEM_STATUS_SELLABLE,WESTRING_ITEMSTATUS_SELLABLE ItemStatusPawnable=1,itemstatus,bj_ITEM_STATUS_PAWNABLE,WESTRING_ITEMSTATUS_PAWNABLE ItemcodeStatusPowerup=1,itemcodestatus,bj_ITEMCODE_STATUS_POWERUP,WESTRING_ITEMCODESTATUS_POWERUP ItemcodeStatusSellable=1,itemcodestatus,bj_ITEMCODE_STATUS_SELLABLE,WESTRING_ITEMCODESTATUS_SELLABLE ItemcodeStatusPawnable=1,itemcodestatus,bj_ITEMCODE_STATUS_PAWNABLE,WESTRING_ITEMCODESTATUS_PAWNABLE MinimapPingStyleSimple=1,minimappingstyle,bj_MINIMAPPINGSTYLE_SIMPLE,WESTRING_MINIMAPPINGSTYLE_SIMPLE MinimapPingStyleFlashy=1,minimappingstyle,bj_MINIMAPPINGSTYLE_FLASHY,WESTRING_MINIMAPPINGSTYLE_FLASHY MinimapPingStyleAttack=1,minimappingstyle,bj_MINIMAPPINGSTYLE_ATTACK,WESTRING_MINIMAPPINGSTYLE_ATTACK CorpseTypeFlesh=1,corpsetype,bj_CORPSETYPE_FLESH,WESTRING_CORPSETYPE_FLESH CorpseTypeBone=1,corpsetype,bj_CORPSETYPE_BONE,WESTRING_CORPSETYPE_BONE StringCaseLower=1,stringcaseoption,false,WESTRING_STRINGCASE_LOWER StringCaseUpper=1,stringcaseoption,true,WESTRING_STRINGCASE_UPPER ChangeColorTrue=0,colorchangeoption,true,WESTRING_CHANGECOLOR_CHANGE ChangeColorFalse=0,colorchangeoption,false,WESTRING_CHANGECOLOR_RETAIN PlayerChangeColorChange=0,playerchangecoloroption,true,WESTRING_SETPLAYERCOLOR_CHANGE PlayerChangeColorRetain=0,playerchangecoloroption,false,WESTRING_SETPLAYERCOLOR_RETAIN ChatMatchTypeExact=0,chatmatchtype,true,WESTRING_CHATMATCH_EXACT ChatMatchTypeSubstring=0,chatmatchtype,false,WESTRING_CHATMATCH_SUBSTRING UnitFacingBoneHead=0,unitfacingbone,`bone_head`,WESTRING_UNITFACINGBONE_HEAD UnitFacingBoneChest=0,unitfacingbone,`bone_chest`,WESTRING_UNITFACINGBONE_CHEST InclusionInclude=0,includeoption,true,WESTRING_INCLUSION_INCLUDE InclusionExclude=0,includeoption,false,WESTRING_INCLUSION_EXCLUDE CameraApply=0,cameraapplyoption,true,WESTRING_CAMERAAPPLYOPTION_APPLY CameraApplyNoPan=0,cameraapplyoption,false,WESTRING_CAMERAAPPLYOPTION_APPLYNOPAN CameraOrientationNormal=0,cameraorientationoption,false,WESTRING_CAMERAORIENTATION_NORMAL CameraOrientationInherit=0,cameraorientationoption,true,WESTRING_CAMERAORIENTATION_INHERIT InvulnerabilityInvulnerable=0,invulnerableoption,true,WESTRING_INVULNERABILITY_INVULNERABLE InvulnerabilityVulnerable=0,invulnerableoption,false,WESTRING_INVULNERABILITY_VULNERABLE AvailabilityOptionAvailable=0,availabilityoption,true,WESTRING_AVAILABILITY_AVAILABLE AvailabilityOptionUnavailable=0,availabilityoption,false,WESTRING_AVAILABILITY_UNAVAILABLE ShowHideHide=0,showhideoption,false,WESTRING_SHOWHIDE_HIDE ShowHideShow=0,showhideoption,true,WESTRING_SHOWHIDE_SHOW Minimize=1,minimizeoption,true,WESTRING_MINIMIZEOPTION_MINIMIZE Maximize=1,minimizeoption,false,WESTRING_MINIMIZEOPTION_MAXIMIZE SkyModelNone=0,skymodelstring,null,WESTRING_SKYMODEL_NONE SkyModelSky08=0,skymodelstring,`Environment\\Sky\\BlizzardSky\\BlizzardSky.mdl`,WESTRING_SKYMODEL_SKY08 SkyModelSky02=0,skymodelstring,`Environment\\Sky\\DalaranSky\\DalaranSky.mdl`,WESTRING_SKYMODEL_SKY02 SkyModelSky06=0,skymodelstring,`Environment\\Sky\\FelwoodSky\\FelwoodSky.mdl`,WESTRING_SKYMODEL_SKY06 SkyModelSky07=0,skymodelstring,`Environment\\Sky\\FoggedSky\\FoggedSky.mdl`,WESTRING_SKYMODEL_SKY07 SkyModelSky01=0,skymodelstring,`Environment\\Sky\\Sky\\SkyLight.mdl`,WESTRING_SKYMODEL_SKY01 SkyModelSky03=0,skymodelstring,`Environment\\Sky\\LordaeronFallSky\\LordaeronFallSky.mdl`,WESTRING_SKYMODEL_SKY03 SkyModelSky04=0,skymodelstring,`Environment\\Sky\\LordaeronSummerSky\\LordaeronSummerSky.mdl`,WESTRING_SKYMODEL_SKY04 SkyModelSky05=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSky\\LordaeronWinterSky.mdl`,WESTRING_SKYMODEL_SKY05 SkyModelSky09=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyBrightGreen\\LordaeronWinterSkyBrightGreen.mdl`,WESTRING_SKYMODEL_SKY09 SkyModelSky10=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyPink\\LordaeronWinterSkyPink.mdl`,WESTRING_SKYMODEL_SKY10 SkyModelSky11=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyPurple\\LordaeronWinterSkyPurple.mdl`,WESTRING_SKYMODEL_SKY11 SkyModelSky12=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyRed\\LordaeronWinterSkyRed.mdl`,WESTRING_SKYMODEL_SKY12 SkyModelSky13=0,skymodelstring,`Environment\\Sky\\LordaeronWinterSkyYellow\\LordaeronWinterSkyYellow.mdl`,WESTRING_SKYMODEL_SKY13 SkyModelSky14=1,skymodelstring,`Environment\\Sky\\Outland_Sky\\Outland_Sky.mdl`,WESTRING_SKYMODEL_SKY14 SkyModelSky15=1,skymodelstring,`Environment\\Sky\\CustomSky\\CustomSky.mdl`,WESTRING_SKYMODEL_SKY15 CineFilterTextureWhite=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\White_mask.blp`,WESTRING_CINEFILTERTEX_WHITE CineFilterTextureBlack=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Black_mask.blp`,WESTRING_CINEFILTERTEX_BLACK CineFilterTextureHaze=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\HazeFilter_mask.blp`,WESTRING_CINEFILTERTEX_HAZE CineFilterTextureGroundFog=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\GroundFog_mask.blp`,WESTRING_CINEFILTERTEX_GROUNDFOG CineFilterTextureHazeAndFog=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\HazeAndFogFilter_Mask.blp`,WESTRING_CINEFILTERTEX_HAZEANDFOG CineFilterTextureDiagonal=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\DiagonalSlash_mask.blp`,WESTRING_CINEFILTERTEX_DIAGONAL CineFilterTextureDream=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\DreamFilter_Mask.blp`,WESTRING_CINEFILTERTEX_DREAM CineFilterTextureScope=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Scope_Mask.blp`,WESTRING_CINEFILTERTEX_SCOPE CineFilterTexturePow=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\SpecialPowMask.blp`,WESTRING_CINEFILTERTEX_POW CineFilterTextureSplat=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\SpecialSplatMask.blp`,WESTRING_CINEFILTERTEX_SPLAT CineFilterTexturePanda=0,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Panda-n-Cub.blp`,WESTRING_CINEFILTERTEX_PANDA CineFilterTextureCustom1=1,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Custom1.blp`,WESTRING_CINEFILTERTEX_CUSTOM1 CineFilterTextureCustom2=1,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Custom2.blp`,WESTRING_CINEFILTERTEX_CUSTOM2 CineFilterTextureCustom3=1,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Custom3.blp`,WESTRING_CINEFILTERTEX_CUSTOM3 CineFilterTextureCustom4=1,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Custom4.blp`,WESTRING_CINEFILTERTEX_CUSTOM4 CineFilterTextureCustom5=1,cinefiltertexture,`ReplaceableTextures\\CameraMasks\\Custom5.blp`,WESTRING_CINEFILTERTEX_CUSTOM5 MusicThemeArthas=1,musictheme,`Sound\\Music\\mp3Music\\ArthasTheme.mp3`,WESTRING_MUSICTHEME_ARTHAS MusicThemeBloodElf=1,musictheme,`Sound\\Music\\mp3Music\\BloodElfTheme.mp3`,WESTRING_MUSICTHEME_BLOODELF MusicThemeComradeship=0,musictheme,`Sound\\Music\\mp3Music\\Comradeship.mp3`,WESTRING_MUSICTHEME_COMRADESHIP MusicThemeCredits=0,musictheme,`Sound\\Music\\mp3Music\\Credits.mp3`,WESTRING_MUSICTHEME_CREDITS MusicThemeDarkAgents=0,musictheme,`Sound\\Music\\mp3Music\\DarkAgents.mp3`,WESTRING_MUSICTHEME_DARKAGENTS MusicThemeDarkVictory=0,musictheme,`Sound\\Music\\mp3Music\\DarkVictory.mp3`,WESTRING_MUSICTHEME_DARKVICTORY MusicThemeDoom=0,musictheme,`Sound\\Music\\mp3Music\\Doom.mp3`,WESTRING_MUSICTHEME_DOOM MusicThemeHeroicVictory=0,musictheme,`Sound\\Music\\mp3Music\\HeroicVictory.mp3`,WESTRING_MUSICTHEME_HEROIC_VICTORY MusicThemeHuman1=0,musictheme,`Sound\\Music\\mp3Music\\Human1.mp3`,WESTRING_MUSICTHEME_HUMAN1 MusicThemeHuman2=0,musictheme,`Sound\\Music\\mp3Music\\Human2.mp3`,WESTRING_MUSICTHEME_HUMAN2 MusicThemeHuman3=0,musictheme,`Sound\\Music\\mp3Music\\Human3.mp3`,WESTRING_MUSICTHEME_HUMAN3 MusicThemeHumanX1=1,musictheme,`Sound\\Music\\mp3Music\\HumanX1.mp3`,WESTRING_MUSICTHEME_HUMANX1 MusicThemeDefeatHuman=0,musictheme,`Sound\\Music\\mp3Music\\HumanDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_HUMAN MusicThemeVictoryHuman=0,musictheme,`Sound\\Music\\mp3Music\\HumanVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_HUMAN MusicThemeIllidan=1,musictheme,`Sound\\Music\\mp3Music\\IllidansTheme.mp3`,WESTRING_MUSICTHEME_ILLIDAN MusicThemeLichKing=1,musictheme,`Sound\\Music\\mp3Music\\LichKingTheme.mp3`,WESTRING_MUSICTHEME_LICHKING MusicThemeMainScreen=0,musictheme,`Sound\\Music\\mp3Music\\MainScreen.mp3`,WESTRING_MUSICTHEME_MAINSCREEN MusicThemeMainScreenX=1,musictheme,`Sound\\Music\\mp3Music\\War3XMainScreen.mp3`,WESTRING_MUSICTHEME_MAINSCREENX MusicThemeNaga=1,musictheme,`Sound\\Music\\mp3Music\\NagaTheme.mp3`,WESTRING_MUSICTHEME_NAGA MusicThemeNightElf1=0,musictheme,`Sound\\Music\\mp3Music\\NightElf1.mp3`,WESTRING_MUSICTHEME_NIGHTELF1 MusicThemeNightElf2=0,musictheme,`Sound\\Music\\mp3Music\\NightElf2.mp3`,WESTRING_MUSICTHEME_NIGHTELF2 MusicThemeNightElf3=0,musictheme,`Sound\\Music\\mp3Music\\NightElf3.mp3`,WESTRING_MUSICTHEME_NIGHTELF3 MusicThemeNightElfX1=1,musictheme,`Sound\\Music\\mp3Music\\NightElfX1.mp3`,WESTRING_MUSICTHEME_NIGHTELFX1 MusicThemeDefeatNightElf=0,musictheme,`Sound\\Music\\mp3Music\\NightElfDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_NIGHTELF MusicThemeVictoryNightElf=0,musictheme,`Sound\\Music\\mp3Music\\NightElfVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_NIGHTELF MusicThemeOrc1=0,musictheme,`Sound\\Music\\mp3Music\\Orc1.mp3`,WESTRING_MUSICTHEME_ORC1 MusicThemeOrc2=0,musictheme,`Sound\\Music\\mp3Music\\Orc2.mp3`,WESTRING_MUSICTHEME_ORC2 MusicThemeOrc3=0,musictheme,`Sound\\Music\\mp3Music\\Orc3.mp3`,WESTRING_MUSICTHEME_ORC3 MusicThemeOrcX1=1,musictheme,`Sound\\Music\\mp3Music\\OrcX1.mp3`,WESTRING_MUSICTHEME_ORCX1 MusicThemeDefeatOrc=0,musictheme,`Sound\\Music\\mp3Music\\OrcDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_ORC MusicThemeOrcTheme=1,musictheme,`Sound\\Music\\mp3Music\\OrcTheme.mp3`,WESTRING_MUSICTHEME_ORC_THEME MusicThemeVictoryOrc=0,musictheme,`Sound\\Music\\mp3Music\\OrcVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_ORC MusicThemePersuit=1,musictheme,`Sound\\Music\\mp3Music\\PursuitTheme.mp3`,WESTRING_MUSICTHEME_PURSUIT MusicThemeSadMystery=0,musictheme,`Sound\\Music\\mp3Music\\SadMystery.mp3`,WESTRING_MUSICTHEME_SADMYSTERY MusicThemeTension=0,musictheme,`Sound\\Music\\mp3Music\\Tension.mp3`,WESTRING_MUSICTHEME_TENSION MusicThemeTragicConfrontation=0,musictheme,`Sound\\Music\\mp3Music\\TragicConfrontation.mp3`,WESTRING_MUSICTHEME_TRAGICCONFRONTATION MusicThemeUndead1=0,musictheme,`Sound\\Music\\mp3Music\\Undead1.mp3`,WESTRING_MUSICTHEME_UNDEAD1 MusicThemeUndead2=0,musictheme,`Sound\\Music\\mp3Music\\Undead2.mp3`,WESTRING_MUSICTHEME_UNDEAD2 MusicThemeUndead3=0,musictheme,`Sound\\Music\\mp3Music\\Undead3.mp3`,WESTRING_MUSICTHEME_UNDEAD3 MusicThemeUndeadX1=1,musictheme,`Sound\\Music\\mp3Music\\UndeadX1.mp3`,WESTRING_MUSICTHEME_UNDEADX1 MusicThemeDefeatUndead=0,musictheme,`Sound\\Music\\mp3Music\\UndeadDefeat.mp3`,WESTRING_MUSICTHEME_DEFEAT_UNDEAD MusicThemeVictoryUndead=0,musictheme,`Sound\\Music\\mp3Music\\UndeadVictory.mp3`,WESTRING_MUSICTHEME_VICTORY_UNDEAD AmbientThemeDayA=0,ambientthemeday,`AshenvaleDay`,WESTRING_AMBIENTTHEMEDAY_A AmbientThemeDayB=0,ambientthemeday,`BarrensDay`,WESTRING_AMBIENTTHEMEDAY_B AmbientThemeDayK=1,ambientthemeday,`BlackCitadelDay`,WESTRING_AMBIENTTHEMEDAY_K AmbientThemeDayY=0,ambientthemeday,`CityScapeDay`,WESTRING_AMBIENTTHEMEDAY_Y AmbientThemeDayX=0,ambientthemeday,`DalaranDay`,WESTRING_AMBIENTTHEMEDAY_X AmbientThemeDayJ=1,ambientthemeday,`DalaranRuinsDay`,WESTRING_AMBIENTTHEMEDAY_J AmbientThemeDayD=0,ambientthemeday,`DungeonDay`,WESTRING_AMBIENTTHEMEDAY_D AmbientThemeDayC=0,ambientthemeday,`FelwoodDay`,WESTRING_AMBIENTTHEMEDAY_C AmbientThemeDayI=1,ambientthemeday,`IceCrownDay`,WESTRING_AMBIENTTHEMEDAY_I AmbientThemeDayF=0,ambientthemeday,`LordaeronFallDay`,WESTRING_AMBIENTTHEMEDAY_F AmbientThemeDayL=0,ambientthemeday,`LordaeronSummerDay`,WESTRING_AMBIENTTHEMEDAY_L AmbientThemeDayW=0,ambientthemeday,`LordaeronWinterDay`,WESTRING_AMBIENTTHEMEDAY_W AmbientThemeDayN=0,ambientthemeday,`NorthrendDay`,WESTRING_AMBIENTTHEMEDAY_N AmbientThemeDayO=1,ambientthemeday,`BlackCitadelDay`,WESTRING_AMBIENTTHEMEDAY_O AmbientThemeDayZ=1,ambientthemeday,`SunkenRuinsDay`,WESTRING_AMBIENTTHEMEDAY_Z AmbientThemeDayV=0,ambientthemeday,`VillageDay`,WESTRING_AMBIENTTHEMEDAY_V AmbientThemeDayQ=0,ambientthemeday,`VillageFallDay`,WESTRING_AMBIENTTHEMEDAY_Q AmbientThemeNightA=0,ambientthemenight,`AshenvaleNight`,WESTRING_AMBIENTTHEMENIGHT_A AmbientThemeNightB=0,ambientthemenight,`BarrensNight`,WESTRING_AMBIENTTHEMENIGHT_B AmbientThemeNightK=1,ambientthemenight,`BlackCitadelNight`,WESTRING_AMBIENTTHEMENIGHT_K AmbientThemeNightY=0,ambientthemenight,`CityScapeNight`,WESTRING_AMBIENTTHEMENIGHT_Y AmbientThemeNightX=0,ambientthemenight,`DalaranNight`,WESTRING_AMBIENTTHEMENIGHT_X AmbientThemeNightJ=1,ambientthemenight,`DalaranRuinsNight`,WESTRING_AMBIENTTHEMENIGHT_J AmbientThemeNightD=0,ambientthemenight,`DungeonNight`,WESTRING_AMBIENTTHEMENIGHT_D AmbientThemeNightC=0,ambientthemenight,`FelwoodNight`,WESTRING_AMBIENTTHEMENIGHT_C AmbientThemeNightI=1,ambientthemenight,`IceCrownNight`,WESTRING_AMBIENTTHEMENIGHT_I AmbientThemeNightF=0,ambientthemenight,`LordaeronFallNight`,WESTRING_AMBIENTTHEMENIGHT_F AmbientThemeNightL=0,ambientthemenight,`LordaeronSummerNight`,WESTRING_AMBIENTTHEMENIGHT_L AmbientThemeNightW=0,ambientthemenight,`LordaeronWinterNight`,WESTRING_AMBIENTTHEMENIGHT_W AmbientThemeNightN=0,ambientthemenight,`NorthrendNight`,WESTRING_AMBIENTTHEMENIGHT_N AmbientThemeNightO=1,ambientthemenight,`BlackCitadelNight`,WESTRING_AMBIENTTHEMENIGHT_O AmbientThemeNightZ=1,ambientthemenight,`SunkenRuinsNight`,WESTRING_AMBIENTTHEMENIGHT_Z AmbientThemeNightV=0,ambientthemenight,`VillageNight`,WESTRING_AMBIENTTHEMENIGHT_V AmbientThemeNightQ=0,ambientthemenight,`VillageFallNight`,WESTRING_AMBIENTTHEMENIGHT_Q UnitStateMethodAbsolute=0,unitstatemethod,bj_UNIT_STATE_METHOD_ABSOLUTE,WESTRING_UNITSTATEMETHOD_ABSOLUTE UnitStateMethodRelative=0,unitstatemethod,bj_UNIT_STATE_METHOD_RELATIVE,WESTRING_UNITSTATEMETHOD_RELATIVE UnitStateMethodDefaults=0,unitstatemethod,bj_UNIT_STATE_METHOD_DEFAULTS,WESTRING_UNITSTATEMETHOD_DEFAULTS UnitStateMethodMaximum=0,unitstatemethod,bj_UNIT_STATE_METHOD_MAXIMUM,WESTRING_UNITSTATEMETHOD_MAXIMUM CheckingIgnoringChecking=0,checkingignoringoption,true,WESTRING_CHECKINGIGNORINGOPTION_CHECKING CheckingIgnoringIgnoring=0,checkingignoringoption,false,WESTRING_CHECKINGIGNORINGOPTION_IGNORING PathingOn=0,pathingoption,true,WESTRING_PATHING_ON PathingOff=0,pathingoption,false,WESTRING_PATHING_OFF PawnableOptionPawnable=1,pawnableoption,true,WESTRING_PAWNABLEOPTION_PAWNABLE PawnableOptionUnpawnable=1,pawnableoption,false,WESTRING_PAWNABLEOPTION_UNPAWNABLE DropNoDropOptionDrop=0,dropnodropoption,true,WESTRING_DROPNODROPOPTION_DROP DropNoDropOptionNoDrop=0,dropnodropoption,false,WESTRING_DROPNODROPOPTION_NODROP DroppableOptionDrop=0,droppableoption,true,WESTRING_DROPPABLE_DROP DroppableOptionNoDrop=0,droppableoption,false,WESTRING_DROPPABLE_NODROP BeforeAfterBefore=0,beforeafteroption,false,WESTRING_BEFOREAFTER_BEFORE BeforeAfterAfter=0,beforeafteroption,true,WESTRING_BEFOREAFTER_AFTER OnOffOn=0,onoffoption,true,WESTRING_ONOFF_ON OnOffOff=0,onoffoption,false,WESTRING_ONOFF_OFF EnableDisableEnable=0,enabledisableoption,true,WESTRING_ENABLEDISABLE_ENABLE EnableDisableDisable=0,enabledisableoption,false,WESTRING_ENABLEDISABLE_DISABLE EnabledDisabledEnabled=0,enableddisabledoption,true,WESTRING_ENABLEDDISABLED_ENABLED EnabledDisabledDisabled=0,enableddisabledoption,false,WESTRING_ENABLEDDISABLED_DISABLED RescuableOptionRescuable=0,rescuableoption,true,WESTRING_RESCUABLEOPTION_RESCUABLE RescuableOptionUnrescuable=0,rescuableoption,false,WESTRING_RESCUABLEOPTION_UNRESCUABLE AllowDontAllow=0,allowdontoption,true,WESTRING_ALLOWDONTOPTION_ALLOW AllowDontDont=0,allowdontoption,false,WESTRING_ALLOWDONTOPTION_DONT FadeDontFade=0,fadedontoption,true,WESTRING_FADEDONTOPTION_FADE FadeDontDont=0,fadedontoption,false,WESTRING_FADEDONTOPTION_DONT AddSetToAdd=0,addsettooption,bj_TIMETYPE_ADD,WESTRING_ADDSETTOOPTION_ADD AddSetToSub=0,addsettooption,bj_TIMETYPE_SUB,WESTRING_ADDSETTOOPTION_SUB AddSetToSet=0,addsettooption,bj_TIMETYPE_SET,WESTRING_ADDSETTOOPTION_SET ModifyMethodAdd=1,modifymethod,bj_MODIFYMETHOD_ADD,WESTRING_MODIFYMETHOD_ADD ModifyMethodSub=1,modifymethod,bj_MODIFYMETHOD_SUB,WESTRING_MODIFYMETHOD_SUB ModifyMethodSet=1,modifymethod,bj_MODIFYMETHOD_SET,WESTRING_MODIFYMETHOD_SET WaitDontWait=0,waitdontoption,true,WESTRING_WAITDONTOPTION_WAIT WaitDontDont=0,waitdontoption,false,WESTRING_WAITDONTOPTION_DONT CraterTypeTemporary=1,cratertype,false,WESTRING_CRATERTYPE_TEMPORARY CraterTypePermanent=1,cratertype,true,WESTRING_CRATERTYPE_PERMANENT RippleTypeNormal=1,rippletype,false,WESTRING_RIPPLETYPE_NORMAL RippleTypeDepression=1,rippletype,true,WESTRING_RIPPLETYPE_DEPRESSION CreateRemoveCreate=0,createremoveoption,true,WESTRING_CREATEREMOVEOPTION_CREATE CreateRemoveRemove=0,createremoveoption,false,WESTRING_CREATEREMOVEOPTION_REMOVE AddRemoveAdd=0,addremoveoption,true,WESTRING_ADDREMOVEOPTION_ADD AddRemoveRemove=0,addremoveoption,false,WESTRING_ADDREMOVEOPTION_REMOVE QuestTypeReqDiscovered=0,questtypeoption,bj_QUESTTYPE_REQ_DISCOVERED,WESTRING_QUESTTYPE_REQ_DISCOVERED QuestTypeOptDiscovered=0,questtypeoption,bj_QUESTTYPE_OPT_DISCOVERED,WESTRING_QUESTTYPE_OPT_DISCOVERED QuestTypeReqUndiscovered=0,questtypeoption,bj_QUESTTYPE_REQ_UNDISCOVERED,WESTRING_QUESTTYPE_REQ_UNDISCOVERED QuestTypeOptUndiscovered=0,questtypeoption,bj_QUESTTYPE_OPT_UNDISCOVERED,WESTRING_QUESTTYPE_OPT_UNDISCOVERED QuestMessageTypeDiscovered=0,questmessagetype,bj_QUESTMESSAGE_DISCOVERED,WESTRING_QUESTMESSAGE_DISCOVERED QuestMessageTypeUpdated=0,questmessagetype,bj_QUESTMESSAGE_UPDATED,WESTRING_QUESTMESSAGE_UPDATED QuestMessageTypeCompleted=0,questmessagetype,bj_QUESTMESSAGE_COMPLETED,WESTRING_QUESTMESSAGE_COMPLETED QuestMessageTypeFailed=0,questmessagetype,bj_QUESTMESSAGE_FAILED,WESTRING_QUESTMESSAGE_FAILED QuestMessageTypeRequirement=0,questmessagetype,bj_QUESTMESSAGE_REQUIREMENT,WESTRING_QUESTMESSAGE_REQUIREMENT QuestMessageTypeMissionFailed=0,questmessagetype,bj_QUESTMESSAGE_MISSIONFAILED,WESTRING_QUESTMESSAGE_MISSIONFAILED QuestMessageTypeAlwaysHint=0,questmessagetype,bj_QUESTMESSAGE_ALWAYSHINT,WESTRING_QUESTMESSAGE_ALWAYSHINT QuestMessageTypeHint=0,questmessagetype,bj_QUESTMESSAGE_HINT,WESTRING_QUESTMESSAGE_HINT QuestMessageTypeSecret=0,questmessagetype,bj_QUESTMESSAGE_SECRET,WESTRING_QUESTMESSAGE_SECRET QuestMessageTypeWarning=1,questmessagetype,bj_QUESTMESSAGE_WARNING,WESTRING_QUESTMESSAGE_WARNING QuestMessageTypeUnitAcquired=0,questmessagetype,bj_QUESTMESSAGE_UNITACQUIRED,WESTRING_QUESTMESSAGE_UNITACQUIRED QuestMessageTypeUnitAvailable=0,questmessagetype,bj_QUESTMESSAGE_UNITAVAILABLE,WESTRING_QUESTMESSAGE_UNITAVAILABLE QuestMessageTypeItemAcquired=0,questmessagetype,bj_QUESTMESSAGE_ITEMACQUIRED,WESTRING_QUESTMESSAGE_ITEMACQUIRED HeroStatStr=1,herostat,bj_HEROSTAT_STR,WESTRING_HEROSTAT_STR HeroStatAgi=1,herostat,bj_HEROSTAT_AGI,WESTRING_HEROSTAT_AGI HeroStatInt=1,herostat,bj_HEROSTAT_INT,WESTRING_HEROSTAT_INT CompletionOptionCompleted=0,completionoption,true,WESTRING_COMPLETIONOPTION_COMPLETED CompletionOptionIncomplete=0,completionoption,false,WESTRING_COMPLETIONOPTION_INCOMPLETE FailureOptionFailed=0,failureoption,true,WESTRING_FAILUREOPTION_FAILED FailureOptionNotFailed=0,failureoption,false,WESTRING_FAILUREOPTION_NOTFAILED DiscoveredOptionDiscovered=0,discoveredoption,true,WESTRING_DISCOVEREDOPTION_DISCOVERED DiscoveredOptionUndiscovered=0,discoveredoption,false,WESTRING_DISCOVEREDOPTION_UNDISCOVERED PauseResumePause=0,pauseresumeoption,true,WESTRING_PAUSERESUMEOPTION_PAUSE PauseResumeResume=0,pauseresumeoption,false,WESTRING_PAUSERESUMEOPTION_RESUME PeriodicOptionOneTime=0,periodicoption,false,WESTRING_PERIODICOPTION_ONETIME PeriodicOptionPeriodic=0,periodicoption,true,WESTRING_PERIODICOPTION_PERIODIC LeaderboardSortByValue=0,leaderboardsortoption,bj_SORTTYPE_SORTBYVALUE,WESTRING_LEADERBOARDSORT_BYVALUE LeaderboardSortByPlayer=0,leaderboardsortoption,bj_SORTTYPE_SORTBYPLAYER,WESTRING_LEADERBOARDSORT_BYPLAYER LeaderboardSortByLabel=0,leaderboardsortoption,bj_SORTTYPE_SORTBYLABEL,WESTRING_LEADERBOARDSORT_BYLABEL AscendingOptionAscending=0,ascendingoption,true,WESTRING_ASCENDINGOPTION_ASCENDING AscendingOptionDescending=0,ascendingoption,false,WESTRING_ASCENDINGOPTION_DESCENDING SleepWakeOptionSleep=0,sleepwakeoption,true,WESTRING_SLEEPWAKEOPTION_SLEEP SleepWakeOptionWake=0,sleepwakeoption,false,WESTRING_SLEEPWAKEOPTION_WAKE PauseUnpauseOptionPause=0,pauseunpauseoption,true,WESTRING_PAUSEUNPAUSEOPTION_PAUSE PauseUnpauseOptionUnpause=0,pauseunpauseoption,false,WESTRING_PAUSEUNPAUSEOPTION_UNPAUSE ShareDontOptionShare=0,sharedontoption,true,WESTRING_SHAREDONTOPTION_SHARE ShareDontOptionDont=0,sharedontoption,false,WESTRING_SHAREDONTOPTION_DONT FadeTypeOptionFadeOutIn=0,fadetypeoption,bj_CINEFADETYPE_FADEOUTIN,WESTRING_FADETYPEOPTION_FADEOUTIN FadeTypeOptionFadeOut=0,fadetypeoption,bj_CINEFADETYPE_FADEOUT,WESTRING_FADETYPEOPTION_FADEOUT FadeTypeOptionFadeIn=0,fadetypeoption,bj_CINEFADETYPE_FADEIN,WESTRING_FADETYPEOPTION_FADEIN BuffTypeAll=0,bufftype,bj_REMOVEBUFFS_ALL,WESTRING_BUFFTYPE_ALL BuffTypeNonTLife=1,bufftype,bj_REMOVEBUFFS_NONTLIFE,WESTRING_BUFFTYPE_NONTLIFE BuffTypePositive=0,bufftype,bj_REMOVEBUFFS_POSITIVE,WESTRING_BUFFTYPE_POSITIVE BuffTypeNegative=0,bufftype,bj_REMOVEBUFFS_NEGATIVE,WESTRING_BUFFTYPE_NEGATIVE BuffPolarityPositive=1,buffpolarity,bj_BUFF_POLARITY_POSITIVE,WESTRING_BUFF_POLARITY_POSITIVE BuffPolarityNegative=1,buffpolarity,bj_BUFF_POLARITY_NEGATIVE,WESTRING_BUFF_POLARITY_NEGATIVE BuffPolarityEither=1,buffpolarity,bj_BUFF_POLARITY_EITHER,WESTRING_BUFF_POLARITY_EITHER BuffResistMagic=1,buffresist,bj_BUFF_RESIST_MAGIC,WESTRING_BUFF_RESIST_MAGIC BuffResistPhysical=1,buffresist,bj_BUFF_RESIST_PHYSICAL,WESTRING_BUFF_RESIST_PHYSICAL BuffResistEither=1,buffresist,bj_BUFF_RESIST_EITHER,WESTRING_BUFF_RESIST_EITHER BuffResistBoth=1,buffresist,bj_BUFF_RESIST_BOTH,WESTRING_BUFF_RESIST_BOTH CameraBoundsAdjustAdd=0,cameraboundsadjusttype,bj_CAMERABOUNDS_ADJUST_ADD,WESTRING_CAMERABOUNDSADJUST_ADD CameraBoundsAdjustSub=0,cameraboundsadjusttype,bj_CAMERABOUNDS_ADJUST_SUB,WESTRING_CAMERABOUNDSADJUST_SUB AvailableOptionAvailable=0,availableoption,true,WESTRING_AVAILABLEOPTION_AVAILABLE AvailableOptionUnavailable=0,availableoption,false,WESTRING_AVAILABLEOPTION_UNAVAILABLE ExplodeDontExplode=0,explodedontoption,true,WESTRING_EXPLODEDONTOPTION_EXPLODE ExplodeDontDont=0,explodedontoption,false,WESTRING_EXPLODEDONTOPTION_DONT SuspendResumeSuspend=0,suspendresumeoption,true,WESTRING_SUSPENDRESUMEOPTION_SUSPEND SuspendResumeResume=0,suspendresumeoption,true,WESTRING_SUSPENDRESUMEOPTION_RESUME GameEventTourneySoon=1,gameevent,EVENT_GAME_TOURNAMENT_FINISH_SOON,WESTRING_GAMEEVENT_TOURNAMENTFINISHSOON GameEventTourneyNow=1,gameevent,EVENT_GAME_TOURNAMENT_FINISH_NOW,WESTRING_GAMEEVENT_TOURNAMENTFINISHNOW MissionIndexT00=0,missionindex,bj_MISSION_INDEX_T00,WESTRING_MISSION_INDEX_T00 MissionIndexT01=0,missionindex,bj_MISSION_INDEX_T01,WESTRING_MISSION_INDEX_T01 MissionIndexH00=0,missionindex,bj_MISSION_INDEX_H00,WESTRING_MISSION_INDEX_H00 MissionIndexH01=0,missionindex,bj_MISSION_INDEX_H01,WESTRING_MISSION_INDEX_H01 MissionIndexH02=0,missionindex,bj_MISSION_INDEX_H02,WESTRING_MISSION_INDEX_H02 MissionIndexH03=0,missionindex,bj_MISSION_INDEX_H03,WESTRING_MISSION_INDEX_H03 MissionIndexH04=0,missionindex,bj_MISSION_INDEX_H04,WESTRING_MISSION_INDEX_H04 MissionIndexH05=0,missionindex,bj_MISSION_INDEX_H05,WESTRING_MISSION_INDEX_H05 MissionIndexH06=0,missionindex,bj_MISSION_INDEX_H06,WESTRING_MISSION_INDEX_H06 MissionIndexH07=0,missionindex,bj_MISSION_INDEX_H07,WESTRING_MISSION_INDEX_H07 MissionIndexH08=0,missionindex,bj_MISSION_INDEX_H08,WESTRING_MISSION_INDEX_H08 MissionIndexH09=0,missionindex,bj_MISSION_INDEX_H09,WESTRING_MISSION_INDEX_H09 MissionIndexH10=0,missionindex,bj_MISSION_INDEX_H10,WESTRING_MISSION_INDEX_H10 MissionIndexH11=0,missionindex,bj_MISSION_INDEX_H11,WESTRING_MISSION_INDEX_H11 MissionIndexU00=0,missionindex,bj_MISSION_INDEX_U00,WESTRING_MISSION_INDEX_U00 MissionIndexU01=0,missionindex,bj_MISSION_INDEX_U01,WESTRING_MISSION_INDEX_U01 MissionIndexU02=0,missionindex,bj_MISSION_INDEX_U02,WESTRING_MISSION_INDEX_U02 MissionIndexU03=0,missionindex,bj_MISSION_INDEX_U03,WESTRING_MISSION_INDEX_U03 MissionIndexU05=0,missionindex,bj_MISSION_INDEX_U05,WESTRING_MISSION_INDEX_U05 MissionIndexU07=0,missionindex,bj_MISSION_INDEX_U07,WESTRING_MISSION_INDEX_U07 MissionIndexU08=0,missionindex,bj_MISSION_INDEX_U08,WESTRING_MISSION_INDEX_U08 MissionIndexU09=0,missionindex,bj_MISSION_INDEX_U09,WESTRING_MISSION_INDEX_U09 MissionIndexU10=0,missionindex,bj_MISSION_INDEX_U10,WESTRING_MISSION_INDEX_U10 MissionIndexU11=0,missionindex,bj_MISSION_INDEX_U11,WESTRING_MISSION_INDEX_U11 MissionIndexO00=0,missionindex,bj_MISSION_INDEX_O00,WESTRING_MISSION_INDEX_O00 MissionIndexO01=0,missionindex,bj_MISSION_INDEX_O01,WESTRING_MISSION_INDEX_O01 MissionIndexO02=0,missionindex,bj_MISSION_INDEX_O02,WESTRING_MISSION_INDEX_O02 MissionIndexO03=0,missionindex,bj_MISSION_INDEX_O03,WESTRING_MISSION_INDEX_O03 MissionIndexO04=0,missionindex,bj_MISSION_INDEX_O04,WESTRING_MISSION_INDEX_O04 MissionIndexO05=0,missionindex,bj_MISSION_INDEX_O05,WESTRING_MISSION_INDEX_O05 MissionIndexO06=0,missionindex,bj_MISSION_INDEX_O06,WESTRING_MISSION_INDEX_O06 MissionIndexO07=0,missionindex,bj_MISSION_INDEX_O07,WESTRING_MISSION_INDEX_O07 MissionIndexO08=0,missionindex,bj_MISSION_INDEX_O08,WESTRING_MISSION_INDEX_O08 MissionIndexO09=0,missionindex,bj_MISSION_INDEX_O09,WESTRING_MISSION_INDEX_O09 MissionIndexO10=0,missionindex,bj_MISSION_INDEX_O10,WESTRING_MISSION_INDEX_O10 MissionIndexN00=0,missionindex,bj_MISSION_INDEX_N00,WESTRING_MISSION_INDEX_N00 MissionIndexN01=0,missionindex,bj_MISSION_INDEX_N01,WESTRING_MISSION_INDEX_N01 MissionIndexN02=0,missionindex,bj_MISSION_INDEX_N02,WESTRING_MISSION_INDEX_N02 MissionIndexN03=0,missionindex,bj_MISSION_INDEX_N03,WESTRING_MISSION_INDEX_N03 MissionIndexN04=0,missionindex,bj_MISSION_INDEX_N04,WESTRING_MISSION_INDEX_N04 MissionIndexN05=0,missionindex,bj_MISSION_INDEX_N05,WESTRING_MISSION_INDEX_N05 MissionIndexN06=0,missionindex,bj_MISSION_INDEX_N06,WESTRING_MISSION_INDEX_N06 MissionIndexN07=0,missionindex,bj_MISSION_INDEX_N07,WESTRING_MISSION_INDEX_N07 MissionIndexXN00=1,missionindex,bj_MISSION_INDEX_XN00,WESTRING_MISSION_INDEX_XN00 MissionIndexXN01=1,missionindex,bj_MISSION_INDEX_XN01,WESTRING_MISSION_INDEX_XN01 MissionIndexXN02=1,missionindex,bj_MISSION_INDEX_XN02,WESTRING_MISSION_INDEX_XN02 MissionIndexXN03=1,missionindex,bj_MISSION_INDEX_XN03,WESTRING_MISSION_INDEX_XN03 MissionIndexXN04=1,missionindex,bj_MISSION_INDEX_XN04,WESTRING_MISSION_INDEX_XN04 MissionIndexXN05=1,missionindex,bj_MISSION_INDEX_XN05,WESTRING_MISSION_INDEX_XN05 MissionIndexXN06=1,missionindex,bj_MISSION_INDEX_XN06,WESTRING_MISSION_INDEX_XN06 MissionIndexXN07=1,missionindex,bj_MISSION_INDEX_XN07,WESTRING_MISSION_INDEX_XN07 MissionIndexXN08=1,missionindex,bj_MISSION_INDEX_XN08,WESTRING_MISSION_INDEX_XN08 MissionIndexXN09=1,missionindex,bj_MISSION_INDEX_XN09,WESTRING_MISSION_INDEX_XN09 MissionIndexXN10=1,missionindex,bj_MISSION_INDEX_XN10,WESTRING_MISSION_INDEX_XN10 MissionIndexXH00=1,missionindex,bj_MISSION_INDEX_XH00,WESTRING_MISSION_INDEX_XH00 MissionIndexXH01=1,missionindex,bj_MISSION_INDEX_XH01,WESTRING_MISSION_INDEX_XH01 MissionIndexXH02=1,missionindex,bj_MISSION_INDEX_XH02,WESTRING_MISSION_INDEX_XH02 MissionIndexXH03=1,missionindex,bj_MISSION_INDEX_XH03,WESTRING_MISSION_INDEX_XH03 MissionIndexXH04=1,missionindex,bj_MISSION_INDEX_XH04,WESTRING_MISSION_INDEX_XH04 MissionIndexXH05=1,missionindex,bj_MISSION_INDEX_XH05,WESTRING_MISSION_INDEX_XH05 MissionIndexXH06=1,missionindex,bj_MISSION_INDEX_XH06,WESTRING_MISSION_INDEX_XH06 MissionIndexXH07=1,missionindex,bj_MISSION_INDEX_XH07,WESTRING_MISSION_INDEX_XH07 MissionIndexXH08=1,missionindex,bj_MISSION_INDEX_XH08,WESTRING_MISSION_INDEX_XH08 MissionIndexXH09=1,missionindex,bj_MISSION_INDEX_XH09,WESTRING_MISSION_INDEX_XH09 MissionIndexXU00=1,missionindex,bj_MISSION_INDEX_XU00,WESTRING_MISSION_INDEX_XU00 MissionIndexXU01=1,missionindex,bj_MISSION_INDEX_XU01,WESTRING_MISSION_INDEX_XU01 MissionIndexXU02=1,missionindex,bj_MISSION_INDEX_XU02,WESTRING_MISSION_INDEX_XU02 MissionIndexXU03=1,missionindex,bj_MISSION_INDEX_XU03,WESTRING_MISSION_INDEX_XU03 MissionIndexXU04=1,missionindex,bj_MISSION_INDEX_XU04,WESTRING_MISSION_INDEX_XU04 MissionIndexXU05=1,missionindex,bj_MISSION_INDEX_XU05,WESTRING_MISSION_INDEX_XU05 MissionIndexXU06=1,missionindex,bj_MISSION_INDEX_XU06,WESTRING_MISSION_INDEX_XU06 MissionIndexXU07=1,missionindex,bj_MISSION_INDEX_XU07,WESTRING_MISSION_INDEX_XU07 MissionIndexXU08=1,missionindex,bj_MISSION_INDEX_XU08,WESTRING_MISSION_INDEX_XU08 MissionIndexXU09=1,missionindex,bj_MISSION_INDEX_XU09,WESTRING_MISSION_INDEX_XU09 MissionIndexXU10=1,missionindex,bj_MISSION_INDEX_XU10,WESTRING_MISSION_INDEX_XU10 MissionIndexXU11=1,missionindex,bj_MISSION_INDEX_XU11,WESTRING_MISSION_INDEX_XU11 MissionIndexXU12=1,missionindex,bj_MISSION_INDEX_XU12,WESTRING_MISSION_INDEX_XU12 MissionIndexXU13=1,missionindex,bj_MISSION_INDEX_XU13,WESTRING_MISSION_INDEX_XU13 MissionIndexXO00=1,missionindex,bj_MISSION_INDEX_XO00,WESTRING_MISSION_INDEX_XO00 CampaignIndexT=0,campaignindex,bj_CAMPAIGN_INDEX_T,WESTRING_CAMPAIGN_INDEX_T CampaignIndexH=0,campaignindex,bj_CAMPAIGN_INDEX_H,WESTRING_CAMPAIGN_INDEX_H CampaignIndexU=0,campaignindex,bj_CAMPAIGN_INDEX_U,WESTRING_CAMPAIGN_INDEX_U CampaignIndexO=0,campaignindex,bj_CAMPAIGN_INDEX_O,WESTRING_CAMPAIGN_INDEX_O CampaignIndexN=0,campaignindex,bj_CAMPAIGN_INDEX_N,WESTRING_CAMPAIGN_INDEX_N CampaignIndexXN=1,campaignindex,bj_CAMPAIGN_INDEX_XN,WESTRING_CAMPAIGN_INDEX_XN CampaignIndexXH=1,campaignindex,bj_CAMPAIGN_INDEX_XH,WESTRING_CAMPAIGN_INDEX_XH CampaignIndexXU=1,campaignindex,bj_CAMPAIGN_INDEX_XU,WESTRING_CAMPAIGN_INDEX_XU CampaignIndexXO=1,campaignindex,bj_CAMPAIGN_INDEX_XO,WESTRING_CAMPAIGN_INDEX_XO CinematicIndexTOP=0,cinematicindex,bj_CINEMATICINDEX_TOP,WESTRING_CINEMATICTYPE_TOP CinematicIndexHOP=0,cinematicindex,bj_CINEMATICINDEX_HOP,WESTRING_CINEMATICTYPE_HOP CinematicIndexHED=0,cinematicindex,bj_CINEMATICINDEX_HED,WESTRING_CINEMATICTYPE_HED CinematicIndexUED=0,cinematicindex,bj_CINEMATICINDEX_UED,WESTRING_CINEMATICTYPE_UED CinematicIndexOED=0,cinematicindex,bj_CINEMATICINDEX_OED,WESTRING_CINEMATICTYPE_OED CinematicIndexNED=0,cinematicindex,bj_CINEMATICINDEX_NED,WESTRING_CINEMATICTYPE_NED CinematicIndexXOP=1,cinematicindex,bj_CINEMATICINDEX_XOP,WESTRING_CINEMATICTYPE_XOP CinematicIndexXED=1,cinematicindex,bj_CINEMATICINDEX_XED,WESTRING_CINEMATICTYPE_XED PlayerResourceGold=1,playerresource,PLAYER_STATE_RESOURCE_GOLD,WESTRING_PRESOURCE_GOLD PlayerResourceLumber=1,playerresource,PLAYER_STATE_RESOURCE_LUMBER,WESTRING_PRESOURCE_LUMBER UnitOrderClusterRockets=1,unitorderptarg,`clusterrockets`,WESTRING_UNITORDERPTARG_CLUSTERROCKETS UnitOrderSummonFactory=1,unitorderptarg,`summonfactory`,WESTRING_UNITORDERPTARG_SUMMONFACTORY HeroSkillEngineeringUpgrade=1,heroskillcode,'ANeg',WESTRING_HEROSKILL_ENGINEERINGUPGRADE HeroSkillClusterRockets=1,heroskillcode,'ANcs',WESTRING_HEROSKILL_CLUSTERROCKETS HeroSkillSummonFactory=1,heroskillcode,'ANsy',WESTRING_HEROSKILL_SUMMONFACTORY HeroSkillRoboGoblin=1,heroskillcode,'ANrg',WESTRING_HEROSKILL_ROBOGOBLIN InstantOrderGive=0,unitorderinstant,`dropitem`,WESTRING_INSTANTORDER_GIVE ItemOrderAttack=0,unitorderitarg,`attack`,WESTRING_UNITORDERITARGOLD_ATTACK ItemOrderAttackOnce=0,unitorderitarg,`attackonce`,WESTRING_UNITORDERITARGOLD_ATTONCE ItemOrderMoveTo=0,unitorderitarg,`move`,WESTRING_UNITORDERITARGOLD_MOVE ItemOrderPickUp=0,unitorderitarg,`getitem`,WESTRING_UNITORDERITARGOLD_PICKUP OrderCodeItemSlot0=0,ordercode,852002,WESTRING_UNITORDERUTARG_SLOT0 OrderCodeItemSlot1=0,ordercode,852003,WESTRING_UNITORDERUTARG_SLOT1 OrderCodeItemSlot2=0,ordercode,852004,WESTRING_UNITORDERUTARG_SLOT2 OrderCodeItemSlot3=0,ordercode,852005,WESTRING_UNITORDERUTARG_SLOT3 OrderCodeItemSlot4=0,ordercode,852006,WESTRING_UNITORDERUTARG_SLOT4 OrderCodeItemSlot5=0,ordercode,852007,WESTRING_UNITORDERUTARG_SLOT5 OrderCodeUseSlot0=0,ordercode,852008,WESTRING_UNITORDER_USESLOT0 OrderCodeUseSlot1=0,ordercode,852009,WESTRING_UNITORDER_USESLOT1 OrderCodeUseSlot2=0,ordercode,852010,WESTRING_UNITORDER_USESLOT2 OrderCodeUseSlot3=0,ordercode,852011,WESTRING_UNITORDER_USESLOT3 OrderCodeUseSlot4=0,ordercode,852012,WESTRING_UNITORDER_USESLOT4 OrderCodeUseSlot5=0,ordercode,852013,WESTRING_UNITORDER_USESLOT5 OrderCodeDoCancel=0,ordercode,851976,WESTRING_UNITORDERUTARG_CANCEL OrderCodeAttackUnit=0,ordercode,String2OrderIdBJ("attack"),WESTRING_UNITORDERUTARG_ATTACK OrderCodeAttackGround=0,ordercode,String2OrderIdBJ("attackground"),WESTRING_UNITORDERPTARG_ATTACKGROUND OrderCodeAttackUnitOnce=0,ordercode,String2OrderIdBJ("attackonce"),WESTRING_UNITORDERUTARG_ATTACKONCE OrderCodeAutoHarvestGold=0,ordercode,String2OrderIdBJ("autoharvestgold"),WESTRING_UNITORDERNOTARG_AUTOHARVESTGOLD OrderCodeAutoHarvestLumber=0,ordercode,String2OrderIdBJ("autoharvestlumber"),WESTRING_UNITORDERNOTARG_AUTOHARVESTLUMBER OrderCodeAwaken=1,ordercode,String2OrderIdBJ("awaken"),WESTRING_UNITORDERNOTARG_AWAKEN OrderCodeBoard=0,ordercode,String2OrderIdBJ("board"),WESTRING_UNITORDERUTARG_BOARD OrderCodeBuild=1,ordercode,String2OrderIdBJ("build"),WESTRING_UNITORDERNOTARG_BUILD OrderCodeForceBoard=0,ordercode,String2OrderIdBJ("forceboard"),WESTRING_UNITORDERUTARG_FORCEBOARD OrderCodeHarvest=0,ordercode,String2OrderIdBJ("harvest"),WESTRING_UNITORDERUTARG_HARVEST OrderCodeHoldPosition=0,ordercode,String2OrderIdBJ("holdposition"),WESTRING_UNITORDERNOTARG_HOLDPOSITION OrderCodeLevelup=1,ordercode,String2OrderIdBJ("levelup"),WESTRING_UNITORDERNOTARG_LEVELUP OrderCodeLoad=0,ordercode,String2OrderIdBJ("load"),WESTRING_UNITORDERUTARG_LOAD OrderCodeMoveUnit=0,ordercode,String2OrderIdBJ("move"),WESTRING_UNITORDERPTARG_MOVE OrderCodePatrol=0,ordercode,String2OrderIdBJ("patrol"),WESTRING_UNITORDERPTARG_PATROL OrderCodeReturnResources=0,ordercode,String2OrderIdBJ("returnresources"),WESTRING_UNITORDERNOTARG_RETURNRESOURCES OrderCodeRevive=0,ordercode,String2OrderIdBJ("revive"),WESTRING_UNITORDERUTARG_REVIVE OrderCodeSmart=1,ordercode,String2OrderIdBJ("smart"),WESTRING_UNITORDERUTARG_SMART OrderCodeSetRally=0,ordercode,String2OrderIdBJ("setrally"),WESTRING_UNITORDERPTARG_SETRALLY OrderCodeStop=0,ordercode,String2OrderIdBJ("stop"),WESTRING_UNITORDERNOTARG_STOP OrderCodeUnload=0,ordercode,String2OrderIdBJ("unload"),WESTRING_UNITORDERUTARG_UNLOAD OrderCodeUnloadAll=0,ordercode,String2OrderIdBJ("unloadall"),WESTRING_UNITORDERPTARG_UNLOADALL OrderCodeNull=0,ordercode,String2OrderIdBJ("(null)"),WESTRING_UNITORDERUTARG_NULL OrderCodeResumeHarvesting=0,ordercode,String2OrderIdBJ("resumeharvesting"),WESTRING_UNITORDERUTARG_RESUMEHARVESTING OrderCodeUnloadAllInstant=0,ordercode,String2OrderIdBJ("unloadallinstant"),WESTRING_UNITORDERPTARG_UNLOADALLINSTANT OrderCodeHumanBuild=1,ordercode,String2OrderIdBJ("humanbuild"),WESTRING_UNITORDERNOTARG_HUMANBUILD OrderCodeBlizzard=0,ordercode,String2OrderIdBJ("blizzard"),WESTRING_UNITORDERPTARG_BLIZZARD OrderCodeWaterElemental=0,ordercode,String2OrderIdBJ("waterelemental"),WESTRING_UNITORDERNOTARG_WATERELEMENTAL OrderCodeMassTeleport=0,ordercode,String2OrderIdBJ("massteleport"),WESTRING_UNITORDERUTARG_MASSTELEPORT OrderCodeBanish=1,ordercode,String2OrderIdBJ("banish"),WESTRING_UNITORDERUTARG_BANISH OrderCodeFlameStrike=1,ordercode,String2OrderIdBJ("flamestrike"),WESTRING_UNITORDERPTARG_FLAMESTRIKE OrderCodePhoenix=1,ordercode,String2OrderIdBJ("phoenix"),WESTRING_UNITORDERNOTARG_PHOENIX OrderCodeSiphonMana=1,ordercode,String2OrderIdBJ("drain"),WESTRING_UNITORDERUTARG_SIPHONMANA OrderCodeAerialShackles=1,ordercode,String2OrderIdBJ("magicleash"),WESTRING_UNITORDERUTARG_AERIALSHACKLES OrderCodeCloudOfFog=1,ordercode,String2OrderIdBJ("cloudoffog"),WESTRING_UNITORDERPTARG_CLOUDOFFOG OrderCodeDefend=0,ordercode,String2OrderIdBJ("defend"),WESTRING_UNITORDERNOTARG_DEFEND OrderCodeUnDefend=0,ordercode,String2OrderIdBJ("undefend"),WESTRING_UNITORDERNOTARG_UNDEFEND OrderCodeMilitiaOff=0,ordercode,String2OrderIdBJ("militiaoff"),WESTRING_UNITORDERNOTARG_MILITIAOFF OrderCodeFlare=0,ordercode,String2OrderIdBJ("flare"),WESTRING_UNITORDERPTARG_FLARE OrderCodeAvatar=0,ordercode,String2OrderIdBJ("avatar"),WESTRING_UNITORDERNOTARG_AVATAR OrderCodeThunderBolt=0,ordercode,String2OrderIdBJ("thunderbolt"),WESTRING_UNITORDERUTARG_THUNDERBOLT OrderCodeThunderClap=0,ordercode,String2OrderIdBJ("thunderclap"),WESTRING_UNITORDERNOTARG_THUNDERCLAP OrderCodeDivineShield=0,ordercode,String2OrderIdBJ("divineshield"),WESTRING_UNITORDERNOTARG_DIVINESHIELD OrderCodeUnDivineShield=0,ordercode,String2OrderIdBJ("undivineshield"),WESTRING_UNITORDERNOTARG_UNDIVINESHIELD OrderCodeHolyBolt=0,ordercode,String2OrderIdBJ("holybolt"),WESTRING_UNITORDERUTARG_HOLYBOLT OrderCodeResurrection=0,ordercode,String2OrderIdBJ("resurrection"),WESTRING_UNITORDERNOTARG_RESURRECTION OrderCodeMilitia=0,ordercode,String2OrderIdBJ("militia"),WESTRING_UNITORDERNOTARG_MILITIA OrderCodeRepair=0,ordercode,String2OrderIdBJ("repair"),WESTRING_UNITORDERUTARG_REPAIR OrderCodeRepairOn=0,ordercode,String2OrderIdBJ("repairon"),WESTRING_UNITORDERNOTARG_REPAIRON OrderCodeRepairOff=0,ordercode,String2OrderIdBJ("repairoff"),WESTRING_UNITORDERNOTARG_REPAIROFF OrderCodeHeal=0,ordercode,String2OrderIdBJ("heal"),WESTRING_UNITORDERUTARG_HEAL OrderCodeHealOn=0,ordercode,String2OrderIdBJ("healon"),WESTRING_UNITORDERNOTARG_HEALON OrderCodeHealOff=0,ordercode,String2OrderIdBJ("healoff"),WESTRING_UNITORDERNOTARG_HEALOFF OrderCodeDispel=0,ordercode,String2OrderIdBJ("dispel"),WESTRING_UNITORDERUTARG_DISPEL OrderCodeInnerFire=0,ordercode,String2OrderIdBJ("innerfire"),WESTRING_UNITORDERUTARG_INNERFIRE OrderCodeInnerFireOn=0,ordercode,String2OrderIdBJ("innerfireon"),WESTRING_UNITORDERNOTARG_INNERFIREON OrderCodeInnerFireOff=0,ordercode,String2OrderIdBJ("innerfireoff"),WESTRING_UNITORDERNOTARG_INNERFIREOFF OrderCodeInvisibility=0,ordercode,String2OrderIdBJ("invisibility"),WESTRING_UNITORDERUTARG_INVISIBILITY OrderCodePolymorph=0,ordercode,String2OrderIdBJ("polymorph"),WESTRING_UNITORDERUTARG_POLYMORPH OrderCodeSlow=0,ordercode,String2OrderIdBJ("slow"),WESTRING_UNITORDERUTARG_SLOW OrderCodeSlowOn=0,ordercode,String2OrderIdBJ("slowon"),WESTRING_UNITORDERNOTARG_SLOWON OrderCodeSlowOff=0,ordercode,String2OrderIdBJ("slowoff"),WESTRING_UNITORDERNOTARG_SLOWOFF OrderCodeControlMagic=1,ordercode,String2OrderIdBJ("controlmagic"),WESTRING_UNITORDERUTARG_CONTROLMAGIC OrderCodeSpellSteal=1,ordercode,String2OrderIdBJ("spellsteal"),WESTRING_UNITORDERNOTARG_SPELLSTEAL OrderCodeSpellStealOn=1,ordercode,String2OrderIdBJ("spellstealon"),WESTRING_UNITORDERNOTARG_SPELLSTEALON OrderCodeSpellStealOff=1,ordercode,String2OrderIdBJ("spellstealoff"),WESTRING_UNITORDERNOTARG_SPELLSTEALOFF OrderCodeTownBellOn=0,ordercode,String2OrderIdBJ("townbellon"),WESTRING_UNITORDERNOTARG_TOWNBELLON OrderCodeTownBellOff=0,ordercode,String2OrderIdBJ("townbelloff"),WESTRING_UNITORDERNOTARG_TOWNBELLOFF OrderCodeOrcBuild=1,ordercode,String2OrderIdBJ("orcbuild"),WESTRING_UNITORDERNOTARG_ORCBUILD OrderCodeBattleStations=0,ordercode,String2OrderIdBJ("battlestations"),WESTRING_UNITORDERNOTARG_BATTLESTATIONS OrderCodeStandDown=0,ordercode,String2OrderIdBJ("standdown"),WESTRING_UNITORDERNOTARG_STANDDOWN OrderCodeBloodlust=0,ordercode,String2OrderIdBJ("bloodlust"),WESTRING_UNITORDERUTARG_BLOODLUST OrderCodeBloodlustOn=0,ordercode,String2OrderIdBJ("bloodluston"),WESTRING_UNITORDERNOTARG_BLOODLUSTON OrderCodeBloodlustOff=0,ordercode,String2OrderIdBJ("bloodlustoff"),WESTRING_UNITORDERNOTARG_BLOODLUSTOFF OrderCodeChainLightning=0,ordercode,String2OrderIdBJ("chainlightning"),WESTRING_UNITORDERUTARG_CHAINLIGHTNING OrderCodeDevour=0,ordercode,String2OrderIdBJ("devour"),WESTRING_UNITORDERUTARG_DEVOUR OrderCodeDisenchant=1,ordercode,String2OrderIdBJ("disenchant"),WESTRING_UNITORDERPTARG_DISENCHANT OrderCodeEarthquake=0,ordercode,String2OrderIdBJ("earthquake"),WESTRING_UNITORDERPTARG_EARTHQUAKE OrderCodeEnsnare=0,ordercode,String2OrderIdBJ("ensnare"),WESTRING_UNITORDERUTARG_ENSNARE OrderCodeSentryWard=0,ordercode,String2OrderIdBJ("evileye"),WESTRING_UNITORDERPTARG_SENTRYWARD OrderCodeFarSight=0,ordercode,String2OrderIdBJ("farsight"),WESTRING_UNITORDERPTARG_FARSIGHT OrderCodeHealingWard=0,ordercode,String2OrderIdBJ("healingward"),WESTRING_UNITORDERPTARG_HEALINGWARD OrderCodeHealingWave=1,ordercode,String2OrderIdBJ("healingwave"),WESTRING_UNITORDERUTARG_HEALINGWAVE OrderCodeHex=1,ordercode,String2OrderIdBJ("hex"),WESTRING_UNITORDERUTARG_HEX OrderCodeLightningShield=0,ordercode,String2OrderIdBJ("lightningshield"),WESTRING_UNITORDERUTARG_LIGHTNINGSHIELD OrderCodeMirrorImage=0,ordercode,String2OrderIdBJ("mirrorimage"),WESTRING_UNITORDERNOTARG_MIRRORIMAGE OrderCodePurge=0,ordercode,String2OrderIdBJ("purge"),WESTRING_UNITORDERUTARG_PURGE OrderCodeRepair=0,ordercode,String2OrderIdBJ("repair"),WESTRING_UNITORDERUTARG_REPAIRO OrderCodeRepairOOn=0,ordercode,String2OrderIdBJ("repairon"),WESTRING_UNITORDERNOTARG_REPAIROON OrderCodeRepairOOff=0,ordercode,String2OrderIdBJ("repairoff"),WESTRING_UNITORDERNOTARG_REPAIROOFF OrderCodeSerpentWard=1,ordercode,String2OrderIdBJ("ward"),WESTRING_UNITORDERPTARG_SERPENTWARD OrderCodeShockwave=0,ordercode,String2OrderIdBJ("shockwave"),WESTRING_UNITORDERPTARG_SHOCKWAVE OrderCodeSpiritLink=1,ordercode,String2OrderIdBJ("spiritlink"),WESTRING_UNITORDERUTARG_SPIRITLINK OrderCodeSpiritWolf=0,ordercode,String2OrderIdBJ("spiritwolf"),WESTRING_UNITORDERNOTARG_FERALSPIRIT OrderCodeStasisTrap=0,ordercode,String2OrderIdBJ("stasistrap"),WESTRING_UNITORDERPTARG_STASISTRAP OrderCodeStomp=0,ordercode,String2OrderIdBJ("stomp"),WESTRING_UNITORDERNOTARG_WARSTOMP OrderCodeUnstableConcoction=1,ordercode,String2OrderIdBJ("unstableconcoction"),WESTRING_UNITORDERUTARG_UNSTABLECONCOCTION OrderCodeWhirlWind=0,ordercode,String2OrderIdBJ("whirlwind"),WESTRING_UNITORDERNOTARG_BLADESTORM OrderCodeWindWalk=0,ordercode,String2OrderIdBJ("windwalk"),WESTRING_UNITORDERNOTARG_WINDWALK OrderCodeBerserk=1,ordercode,String2OrderIdBJ("berserk"),WESTRING_UNITORDERNOTARG_BERSERK OrderCodeAncestralSpirit=1,ordercode,String2OrderIdBJ("ancestralspirit"),WESTRING_UNITORDERNOTARG_ANCESTRALSPIRIT OrderCodeEtherealForm=1,ordercode,String2OrderIdBJ("uncorporealform"),WESTRING_UNITORDERNOTARG_ETHEREALFORM OrderCodeCorporealForm=1,ordercode,String2OrderIdBJ("corporealform"),WESTRING_UNITORDERNOTARG_CORPOREALFORM OrderCodeVoodoo=1,ordercode,String2OrderIdBJ("voodoo"),WESTRING_UNITORDERNOTARG_VOODOO OrderCodeNightElfBuild=1,ordercode,String2OrderIdBJ("nightelfbuild"),WESTRING_UNITORDERNOTARG_NIGHTELFBUILD OrderCodeBlink=1,ordercode,String2OrderIdBJ("blink"),WESTRING_UNITORDERPTARG_BLINK OrderCodeRenew=0,ordercode,String2OrderIdBJ("renew"),WESTRING_UNITORDERUTARG_RENEW OrderCodeEntangle=0,ordercode,String2OrderIdBJ("entangle"),WESTRING_UNITORDERUTARG_ENTANGLE OrderCodeEntangleInstant=0,ordercode,String2OrderIdBJ("entangleinstant"),WESTRING_UNITORDERUTARG_ENTANGLEINSTANT OrderCodeReplenish=0,ordercode,String2OrderIdBJ("replenish"),WESTRING_UNITORDERUTARG_REPLENISH OrderCodeMountHippogryph=0,ordercode,String2OrderIdBJ("mounthippogryph"),WESTRING_UNITORDERUTARG_MOUNTHIPPOGRYPH OrderCodeLoadArcher=0,ordercode,String2OrderIdBJ("loadarcher"),WESTRING_UNITORDERUTARG_LOADARCHER OrderCodeAutoDispel=0,ordercode,String2OrderIdBJ("autodispel"),WESTRING_UNITORDERUTARG_AUTODISPEL OrderCodeFaerieFire=0,ordercode,String2OrderIdBJ("faeriefire"),WESTRING_UNITORDERUTARG_FAERIEFIRE OrderCodeCyclone=0,ordercode,String2OrderIdBJ("cyclone"),WESTRING_UNITORDERUTARG_CYCLONE OrderCodeRejuvination=0,ordercode,String2OrderIdBJ("rejuvination"),WESTRING_UNITORDERUTARG_REJUVINATION OrderCodeManaBurn=0,ordercode,String2OrderIdBJ("manaburn"),WESTRING_UNITORDERUTARG_MANABURN OrderCodeEntanglingRoots=0,ordercode,String2OrderIdBJ("entanglingroots"),WESTRING_UNITORDERUTARG_ENTANGLINGROOTS OrderCodeRoot=0,ordercode,String2OrderIdBJ("root"),WESTRING_UNITORDERPTARG_ROOT OrderCodeDetonate=0,ordercode,String2OrderIdBJ("detonate"),WESTRING_UNITORDERPTARG_DETONATE OrderCodeForceOfNature=0,ordercode,String2OrderIdBJ("forceofnature"),WESTRING_UNITORDERPTARG_FORCEOFNATURE OrderCodeStarfall=0,ordercode,String2OrderIdBJ("rainoffire"),WESTRING_UNITORDERPTARG_STARFALL OrderCodeConsumeTree=0,ordercode,String2OrderIdBJ("eattree"),WESTRING_unitorderdtarg_CONSUMETREE OrderCodeSentinel=0,ordercode,String2OrderIdBJ("sentinel"),WESTRING_unitorderdtarg_SENTINEL OrderCodeUnRoot=0,ordercode,String2OrderIdBJ("unroot"),WESTRING_UNITORDERNOTARG_UNROOT OrderCodeAmbush=0,ordercode,String2OrderIdBJ("ambush"),WESTRING_UNITORDERNOTARG_HIDE OrderCodeRenewOn=0,ordercode,String2OrderIdBJ("renewon"),WESTRING_UNITORDERNOTARG_RENEWON OrderCodeRenewOff=0,ordercode,String2OrderIdBJ("renewoff"),WESTRING_UNITORDERNOTARG_RENEWOFF OrderCodeAutoDispelOn=0,ordercode,String2OrderIdBJ("autodispelon"),WESTRING_UNITORDERNOTARG_AUTODISPELON OrderCodeAutoDispelOff=0,ordercode,String2OrderIdBJ("autodispeloff"),WESTRING_UNITORDERNOTARG_AUTODISPELOFF OrderCodeFaerieFireOn=0,ordercode,String2OrderIdBJ("faeriefireon"),WESTRING_UNITORDERNOTARG_FAERIEFIREON OrderCodeFaerieFireOff=0,ordercode,String2OrderIdBJ("faeriefireoff"),WESTRING_UNITORDERNOTARG_FAERIEFIREOFF OrderCodeRavenForm=0,ordercode,String2OrderIdBJ("ravenform"),WESTRING_UNITORDERNOTARG_RAVENFORM OrderCodeUnRavenForm=0,ordercode,String2OrderIdBJ("unravenform"),WESTRING_UNITORDERNOTARG_UNRAVENFORM OrderCodeRoar=0,ordercode,String2OrderIdBJ("roar"),WESTRING_UNITORDERNOTARG_ROAR OrderCodeBearForm=0,ordercode,String2OrderIdBJ("bearform"),WESTRING_UNITORDERNOTARG_BEARFORM OrderCodeUnBearForm=0,ordercode,String2OrderIdBJ("unbearform"),WESTRING_UNITORDERNOTARG_UNBEARFORM OrderCodeImmolation=0,ordercode,String2OrderIdBJ("immolation"),WESTRING_UNITORDERNOTARG_IMMOLATION OrderCodeUnImmolation=0,ordercode,String2OrderIdBJ("unimmolation"),WESTRING_UNITORDERNOTARG_UNIMMOLATION OrderCodeMetamorphosis=0,ordercode,String2OrderIdBJ("metamorphosis"),WESTRING_UNITORDERNOTARG_METAMORPHOSIS OrderCodeTranquility=0,ordercode,String2OrderIdBJ("tranquility"),WESTRING_UNITORDERNOTARG_TRANQUILITY OrderCodeSearingArrows=0,ordercode,String2OrderIdBJ("flamingarrows"),WESTRING_UNITORDERNOTARG_SEARINGARROWS OrderCodeUnSearingArrows=0,ordercode,String2OrderIdBJ("unflamingarrows"),WESTRING_UNITORDERNOTARG_UNSEARINGARROWS OrderCodeVengeance=1,ordercode,String2OrderIdBJ("vengeance"),WESTRING_UNITORDERUTARG_VENGEANCE OrderCodeScout=0,ordercode,String2OrderIdBJ("scout"),WESTRING_UNITORDERNOTARG_SCOUT OrderCodeShadowStrike=1,ordercode,String2OrderIdBJ("shadowstrike"),WESTRING_UNITORDERUTARG_SHADOWSTRIKE OrderCodeGrabTree=1,ordercode,String2OrderIdBJ("grabtree"),WESTRING_UNITORDERDTARG_GRABTREE OrderCodeAutoEntangle=1,ordercode,String2OrderIdBJ("autoentangle"),WESTRING_UNITORDERNOTARG_AUTOENTANGLE OrderCodeAutoEntangleInstant=1,ordercode,String2OrderIdBJ("autoentangleinstant"),WESTRING_UNITORDERNOTARG_AUTOENTANGLEINSTANT OrderCodeReplenish=0,ordercode,String2OrderIdBJ("recharge"),WESTRING_UNITORDERUTARG_REPLENISH OrderCodeReplenishOn=1,ordercode,String2OrderIdBJ("rechargeon"),WESTRING_UNITORDERNOTARG_REPLENISHON OrderCodeReplenishOff=1,ordercode,String2OrderIdBJ("rechargeoff"),WESTRING_UNITORDERNOTARG_REPLENISHOFF OrderCodeCoupleInstant1=1,ordercode,String2OrderIdBJ("coupleinstant"),WESTRING_UNITORDERNOTARG_COUPLEINSTANT1 OrderCodeCoupleInstant2=1,ordercode,String2OrderIdBJ("coupleinstant"),WESTRING_UNITORDERNOTARG_COUPLEINSTANT2 OrderCodeDecouple=1,ordercode,String2OrderIdBJ("decouple"),WESTRING_UNITORDERNOTARG_DECOUPLE OrderCodeTaunt=1,ordercode,String2OrderIdBJ("taunt"),WESTRING_UNITORDERNOTARG_TAUNT OrderCodeManaFlareOn=1,ordercode,String2OrderIdBJ("manaflareon"),WESTRING_UNITORDERNOTARG_MANAFLAREON OrderCodeManaFlareOff=1,ordercode,String2OrderIdBJ("manaflareoff"),WESTRING_UNITORDERNOTARG_MANAFLAREOFF OrderCodePhaseShift=1,ordercode,String2OrderIdBJ("phaseshift"),WESTRING_UNITORDERNOTARG_PHASESHIFT OrderCodePhaseShiftOn=1,ordercode,String2OrderIdBJ("phaseshifton"),WESTRING_UNITORDERNOTARG_PHASESHIFTON OrderCodePhaseShiftOff=1,ordercode,String2OrderIdBJ("phaseshiftoff"),WESTRING_UNITORDERNOTARG_PHASESHIFTOFF OrderCodeVengeanceInstant=1,ordercode,String2OrderIdBJ("vengeanceinstant"),WESTRING_UNITORDERNOTARG_VENGEANCEINSTANT OrderCodeVengeanceOn=1,ordercode,String2OrderIdBJ("vengeanceon"),WESTRING_UNITORDERNOTARG_VENGEANCEON OrderCodeVengeanceOff=1,ordercode,String2OrderIdBJ("vengeanceoff"),WESTRING_UNITORDERNOTARG_VENGEANCEOFF OrderCodeFanOfKnives=1,ordercode,String2OrderIdBJ("fanofknives"),WESTRING_UNITORDERNOTARG_FANOFKNIVES OrderCodeSpiritOfVengeance=1,ordercode,String2OrderIdBJ("spiritofvengeance"),WESTRING_UNITORDERNOTARG_SPIRITOFVENGEANCE OrderCodeUndeadBuild=1,ordercode,String2OrderIdBJ("undeadbuild"),WESTRING_UNITORDERNOTARG_UNDEADBUILD OrderCodeDevourMagic=1,ordercode,String2OrderIdBJ("devourmagic"),WESTRING_UNITORDERPTARG_DEVOURMAGIC OrderCodeRestoration=0,ordercode,String2OrderIdBJ("restoration"),WESTRING_UNITORDERUTARG_RESTORE OrderCodeSacrificeAcolyte=0,ordercode,String2OrderIdBJ("sacrifice"),WESTRING_UNITORDERUTARG_SACRIFICEACOLYTE OrderCodeSacrifice=0,ordercode,String2OrderIdBJ("sacrifice"),WESTRING_UNITORDERUTARG_SACRIFICE OrderCodeUnsummon=0,ordercode,String2OrderIdBJ("unsummon"),WESTRING_UNITORDERUTARG_UNSUMMON OrderCodeWeb=0,ordercode,String2OrderIdBJ("web"),WESTRING_UNITORDERUTARG_WEB OrderCodeRaiseDead=0,ordercode,String2OrderIdBJ("raisedead"),WESTRING_UNITORDERUTARG_RAISEDEAD OrderCodeUnholyFrenzy=0,ordercode,String2OrderIdBJ("unholyfrenzy"),WESTRING_UNITORDERUTARG_UNHOLYFRENZY OrderCodeCripple=0,ordercode,String2OrderIdBJ("cripple"),WESTRING_UNITORDERUTARG_CRIPPLE OrderCodeCurse=0,ordercode,String2OrderIdBJ("curse"),WESTRING_UNITORDERUTARG_CURSE OrderCodeAntiMagicShell=0,ordercode,String2OrderIdBJ("antimagicshell"),WESTRING_UNITORDERUTARG_ANTIMAGICSHELL OrderCodePossession=0,ordercode,String2OrderIdBJ("possession"),WESTRING_UNITORDERUTARG_POSSESSION OrderCodeDeathCoil=0,ordercode,String2OrderIdBJ("deathcoil"),WESTRING_UNITORDERUTARG_DEATHCOIL OrderCodeDeathPact=0,ordercode,String2OrderIdBJ("deathpact"),WESTRING_UNITORDERUTARG_DEATHPACT OrderCodeSleep=0,ordercode,String2OrderIdBJ("sleep"),WESTRING_UNITORDERUTARG_SLEEP OrderCodeFrostNova=0,ordercode,String2OrderIdBJ("frostnova"),WESTRING_UNITORDERUTARG_FROSTNOVA OrderCodeFrostArmor=0,ordercode,String2OrderIdBJ("frostarmor"),WESTRING_UNITORDERUTARG_FROSTARMOR OrderCodeFrostArmorOn=0,ordercode,String2OrderIdBJ("frostarmoron"),WESTRING_UNITORDERNOTARG_FROSTARMORON OrderCodeFrostArmorOff=0,ordercode,String2OrderIdBJ("frostarmoroff"),WESTRING_UNITORDERNOTARG_FROSTARMOROFF OrderCodeDarkRitual=0,ordercode,String2OrderIdBJ("darkritual"),WESTRING_UNITORDERUTARG_DARKRITUAL OrderCodeCarrionSwarm=0,ordercode,String2OrderIdBJ("carrionswarm"),WESTRING_UNITORDERPTARG_CARRIONSWARM OrderCodeDarkSummoning=0,ordercode,String2OrderIdBJ("dreadlordinferno"),WESTRING_UNITORDERPTARG_DARKSUMMONING OrderCodeDeathAndDecay=0,ordercode,String2OrderIdBJ("deathanddecay"),WESTRING_UNITORDERPTARG_DEATHANDDECAY OrderCodeRestorationOn=0,ordercode,String2OrderIdBJ("restorationon"),WESTRING_UNITORDERNOTARG_RESTOREON OrderCodeRestorationOff=0,ordercode,String2OrderIdBJ("restorationoff"),WESTRING_UNITORDERNOTARG_RESTOREOFF OrderCodeCannibalize=0,ordercode,String2OrderIdBJ("cannibalize"),WESTRING_UNITORDERNOTARG_CANNIBALIZE OrderCodeWebOn=0,ordercode,String2OrderIdBJ("webon"),WESTRING_UNITORDERNOTARG_WEBON OrderCodeWebOff=0,ordercode,String2OrderIdBJ("weboff"),WESTRING_UNITORDERNOTARG_WEBOFF OrderCodeLoadCorpse=0,ordercode,String2OrderIdBJ("loadcorpse"),WESTRING_UNITORDERNOTARG_LOADCORPSE OrderCodeUnloadAllCorpses=0,ordercode,String2OrderIdBJ("unloadallcorpses"),WESTRING_UNITORDERNOTARG_UNLOADALLCORPSES OrderCodeStoneForm=0,ordercode,String2OrderIdBJ("stoneform"),WESTRING_UNITORDERNOTARG_STONEFORM OrderCodeUnStoneForm=0,ordercode,String2OrderIdBJ("unstoneform"),WESTRING_UNITORDERNOTARG_UNSTONEFORM OrderCodeRaiseDeadOn=0,ordercode,String2OrderIdBJ("raisedeadon"),WESTRING_UNITORDERNOTARG_RAISEDEADON OrderCodeRaiseDeadOff=0,ordercode,String2OrderIdBJ("raisedeadoff"),WESTRING_UNITORDERNOTARG_RAISEDEADOFF OrderCodeCurseOn=0,ordercode,String2OrderIdBJ("curseon"),WESTRING_UNITORDERNOTARG_CURSEON OrderCodeCurseOff=0,ordercode,String2OrderIdBJ("curseoff"),WESTRING_UNITORDERNOTARG_CURSEOFF OrderCodeAnimateDead=0,ordercode,String2OrderIdBJ("animatedead"),WESTRING_UNITORDERNOTARG_ANIMATEDEAD OrderCodeAbsorbMana=1,ordercode,String2OrderIdBJ("absorb"),WESTRING_UNITORDERUTARG_ABSORBMANA OrderCodeFlamingAttack=1,ordercode,String2OrderIdBJ("flamingattacktarg"),WESTRING_UNITORDERUTARG_FLAMINGATTACK OrderCodeImpale=1,ordercode,String2OrderIdBJ("impale"),WESTRING_UNITORDERUTARG_IMPALE OrderCodeCarrionScarabs=1,ordercode,String2OrderIdBJ("carrionscarabs"),WESTRING_UNITORDERUTARG_CARRIONSCARABS OrderCodeBurrow=1,ordercode,String2OrderIdBJ("burrow"),WESTRING_UNITORDERNOTARG_BURROW OrderCodeUnBurrow=1,ordercode,String2OrderIdBJ("unburrow"),WESTRING_UNITORDERNOTARG_UNBURROW OrderCodeRaiseDeadInstant=1,ordercode,String2OrderIdBJ("instant"),WESTRING_UNITORDERNOTARG_RAISEDEAD OrderCodeFlamingAttackOn=1,ordercode,String2OrderIdBJ("flamingattack"),WESTRING_UNITORDERNOTARG_FLAMINGATTACKON OrderCodeFlamingAttackOff=1,ordercode,String2OrderIdBJ("unflamingattack"),WESTRING_UNITORDERNOTARG_FLAMINGATTACKOFF OrderCodeSphinxForm=1,ordercode,String2OrderIdBJ("avengerform"),WESTRING_UNITORDERNOTARG_SPHINXFORM OrderCodeReplenishLife=1,ordercode,String2OrderIdBJ("replenishlife"),WESTRING_UNITORDERNOTARG_REPLENISHLIFE OrderCodeReplenishLifeOn=1,ordercode,String2OrderIdBJ("replenishlifeon"),WESTRING_UNITORDERNOTARG_REPLENISHLIFEON OrderCodeReplenishLifeOff=1,ordercode,String2OrderIdBJ("replenishlifeoff"),WESTRING_UNITORDERNOTARG_REPLENISHLIFEOFF OrderCodeReplenishMana=1,ordercode,String2OrderIdBJ("replenishmana"),WESTRING_UNITORDERNOTARG_REPLENISHMANA OrderCodeReplenishManaOn=1,ordercode,String2OrderIdBJ("replenishmanaon"),WESTRING_UNITORDERNOTARG_REPLENISHMANAON OrderCodeReplenishManaOff=1,ordercode,String2OrderIdBJ("replenishmanaoff"),WESTRING_UNITORDERNOTARG_REPLENISHMANAOFF OrderCodeCarrionScarabsOn=1,ordercode,String2OrderIdBJ("carrionscarabson"),WESTRING_UNITORDERNOTARG_CARRIONSCARABSON OrderCodeCarrionScarabsOff=1,ordercode,String2OrderIdBJ("carrionscarabsoff"),WESTRING_UNITORDERNOTARG_CARRIONSCARABSOFF OrderCodeLocustSwarm=1,ordercode,String2OrderIdBJ("locustswarm"),WESTRING_UNITORDERNOTARG_LOCUSTSWARM OrderCodeNagaBuild=1,unitordernotarg,String2OrderIdBJ("nagabuild"),WESTRING_UNITORDERNOTARG_NAGABUILD OrderCodeBreathOfFrost=1,ordercode,String2OrderIdBJ("breathoffrost"),WESTRING_UNITORDERPTARG_BREATHOFFROST OrderCodeMonsoon=1,ordercode,String2OrderIdBJ("monsoon"),WESTRING_UNITORDERPTARG_MONSOON OrderCodeSelfDestruct=0,ordercode,String2OrderIdBJ("selfdestruct"),WESTRING_UNITORDERPTARG_SELFDESTRUCT OrderCodeRevenge=0,ordercode,String2OrderIdBJ("revenge"),WESTRING_UNITORDERNOTARG_REVENGE OrderCodeStampede=1,ordercode,String2OrderIdBJ("stampede"),WESTRING_UNITORDERPTARG_STAMPEDE OrderCodeSilence=1,ordercode,String2OrderIdBJ("silence"),WESTRING_UNITORDERPTARG_SILENCE OrderCodeTornado=1,ordercode,String2OrderIdBJ("tornado"),WESTRING_UNITORDERPTARG_TORNADO OrderCodeBreathOfFire=1,ordercode,String2OrderIdBJ("breathoffire"),WESTRING_UNITORDERPTARG_BREATHOFFIRE OrderCodeHeroRainOfFire=1,ordercode,String2OrderIdBJ("rainoffire"),WESTRING_UNITORDERPTARG_HERORAINOFFIRE OrderCodeCreepDevour=1,ordercode,String2OrderIdBJ("creepdevour"),WESTRING_UNITORDERUTARG_CREEPDEVOUR OrderCodeWateryMinion=1,ordercode,String2OrderIdBJ("wateryminion"),WESTRING_UNITORDERNOTARG_WATERYMINION OrderCodeSelfDestructOn=1,ordercode,String2OrderIdBJ("selfdestructon"),WESTRING_UNITORDERNOTARG_SELFDESTRUCTON OrderCodeSelfDestructOff=1,ordercode,String2OrderIdBJ("selfdestructoff"),WESTRING_UNITORDERNOTARG_SELFDESTRUCTOFF OrderCodeSummonGrizzly=1,ordercode,String2OrderIdBJ("summongrizzly"),WESTRING_UNITORDERNOTARG_SUMMONGRIZZLY OrderCodeSummonQuillbeast=1,ordercode,String2OrderIdBJ("summonquillbeast"),WESTRING_UNITORDERNOTARG_SUMMONQUILLBEAST OrderCodeSummonWarEagle=1,ordercode,String2OrderIdBJ("summonwareagle"),WESTRING_UNITORDERNOTARG_SUMMONWAREAGLE OrderCodeBlackArrow=1,ordercode,String2OrderIdBJ("blackarrow"),WESTRING_UNITORDERUTARG_BLACKARROW OrderCodeBlackArrowOn=1,ordercode,String2OrderIdBJ("blackarrowon"),WESTRING_UNITORDERNOTARG_BLACKARROWON OrderCodeBlackArrowOff=1,ordercode,String2OrderIdBJ("blackarrowoff"),WESTRING_UNITORDERNOTARG_BLACKARROWOFF OrderCodeColdArrowOn=1,ordercode,String2OrderIdBJ("coldarrows"),WESTRING_UNITORDERNOTARG_COLDARROWON OrderCodeColdArrowOff=1,ordercode,String2OrderIdBJ("uncoldarrows"),WESTRING_UNITORDERNOTARG_COLDARROWOFF OrderCodeManaShieldOn=1,ordercode,String2OrderIdBJ("manashieldon"),WESTRING_UNITORDERNOTARG_MANASHIELDON OrderCodeManaShieldOff=1,ordercode,String2OrderIdBJ("manashieldoff"),WESTRING_UNITORDERNOTARG_MANASHIELDOFF OrderCodeElementalFury=1,ordercode,String2OrderIdBJ("elementalfury"),WESTRING_UNITORDERNOTARG_ELEMENTALFURY OrderCodeHowlOfTerror=1,ordercode,String2OrderIdBJ("howlofterror"),WESTRING_UNITORDERNOTARG_HOWLOFTERROR OrderCodeDoom=1,ordercode,String2OrderIdBJ("doom"),WESTRING_UNITORDERUTARG_DOOM OrderCodeStrongDrink=1,ordercode,String2OrderIdBJ("strongdrink"),WESTRING_UNITORDERUTARG_STRONGDRINK OrderCodeCharm=1,ordercode,String2OrderIdBJ("charm"),WESTRING_UNITORDERUTARG_CHARM OrderCodeCreepThunderClap=0,ordercode,String2OrderIdBJ("creepthunderclap"),WESTRING_UNITORDERNOTARG_CREEPTHUNDERCLAP OrderCodeCreepThunderBolt=0,ordercode,String2OrderIdBJ("creepthunderbolt"),WESTRING_UNITORDERUTARG_CREEPTHUNDERBOLT OrderCodeForkedLightning=1,ordercode,String2OrderIdBJ("forkedlightning"),WESTRING_UNITORDERUTARG_FORKEDLIGHTNING OrderCodeChannel=1,ordercode,String2OrderIdBJ("channel"),WESTRING_UNITORDERNOTARG_CHANNEL OrderCodeFingerOfDeath=0,ordercode,String2OrderIdBJ("fingerofdeath"),WESTRING_UNITORDERUTARG_FINGEROFDEATH OrderCodeDarkConversion=0,ordercode,String2OrderIdBJ("darkconversion"),WESTRING_UNITORDERUTARG_DARKCONVERSION OrderCodeSoulPreservation=0,ordercode,String2OrderIdBJ("soulpreservation"),WESTRING_UNITORDERUTARG_SOULPRESERVATION OrderCodeDarkConversionFast=0,ordercode,String2OrderIdBJ("darkconversion"),WESTRING_UNITORDERUTARG_DARKCONVERSIONFAST OrderCodeDarkPortal=0,ordercode,String2OrderIdBJ("darkportal"),WESTRING_UNITORDERPTARG_DARKPORTAL OrderCodeRainOfChaos=0,ordercode,String2OrderIdBJ("rainoffire"),WESTRING_UNITORDERPTARG_RAINOFCHAOS OrderCodeRainOfFire=0,ordercode,String2OrderIdBJ("rainoffire"),WESTRING_UNITORDERPTARG_RAINOFFIRE OrderCodeInferno=0,ordercode,String2OrderIdBJ("inferno"),WESTRING_UNITORDERPTARG_INFERNO OrderCodeDarkSummoningOld=0,ordercode,String2OrderIdBJ("darksummoning"),WESTRING_UNITORDERPTARG_DARKSUMMONINGOLD OrderCodeMedivhRavenForm=0,ordercode,String2OrderIdBJ("ravenform"),WESTRING_UNITORDERNOTARG_MEDIVHRAVENFORM OrderCodeMedivhUnRavenForm=0,ordercode,String2OrderIdBJ("unravenform"),WESTRING_UNITORDERNOTARG_MEDIVHUNRAVENFORM OrderCodeRexxarBattleRoar=1,ordercode,String2OrderIdBJ("battleroar"),WESTRING_UNITORDERNOTARG_REXXARBATTLEROAR OrderCodeColdArrows=0,ordercode,String2OrderIdBJ("coldarrows"),WESTRING_UNITORDERNOTARG_COLDARROWS OrderCodeUnColdArrows=0,ordercode,String2OrderIdBJ("uncoldarrows"),WESTRING_UNITORDERNOTARG_UNCOLDARROWS UnitOrderDoCancel=0,unitordernotarg,851976,WESTRING_UNITORDERUTARG_CANCEL UnitOrderAttackUnit=0,unitorderutarg,`attack`,WESTRING_UNITORDERUTARG_ATTACK UnitOrderAttackUnitOnce=0,unitorderutarg,`attackonce`,WESTRING_UNITORDERUTARG_ATTACKONCE UnitOrderMoveUnit=0,unitorderutarg,`move`,WESTRING_UNITORDERUTARG_MOVE UnitOrderSmartUnit=1,unitorderutarg,`smart`,WESTRING_UNITORDERUTARG_SMART UnitOrderHarvest=0,unitorderutarg,`harvest`,WESTRING_UNITORDERUTARG_HARVEST UnitOrderRevive=0,unitorderutarg,`revive`,WESTRING_UNITORDERUTARG_REVIVE UnitOrderLoad=0,unitorderutarg,`load`,WESTRING_UNITORDERUTARG_LOAD UnitOrderUnload=0,unitorderutarg,`unload`,WESTRING_UNITORDERUTARG_UNLOAD UnitOrderBoard=0,unitorderutarg,`board`,WESTRING_UNITORDERUTARG_BOARD UnitOrderForceBoard=0,unitorderutarg,`forceboard`,WESTRING_UNITORDERUTARG_FORCEBOARD UnitOrderRepair=0,unitorderutarg,`repair`,WESTRING_UNITORDERUTARG_REPAIR UnitOrderInnerFire=0,unitorderutarg,`innerfire`,WESTRING_UNITORDERUTARG_INNERFIRE UnitOrderDispel=0,unitorderutarg,`dispel`,WESTRING_UNITORDERUTARG_DISPEL UnitOrderHeal=0,unitorderutarg,`heal`,WESTRING_UNITORDERUTARG_HEAL UnitOrderSlow=0,unitorderutarg,`slow`,WESTRING_UNITORDERUTARG_SLOW UnitOrderInvisibility=0,unitorderutarg,`invisibility`,WESTRING_UNITORDERUTARG_INVISIBILITY UnitOrderPolymorph=0,unitorderutarg,`polymorph`,WESTRING_UNITORDERUTARG_POLYMORPH UnitOrderControlMagic=1,unitorderutarg,`controlmagic`,WESTRING_UNITORDERUTARG_CONTROLMAGIC UnitOrderSpellSteal=1,unitorderutarg,`spellsteal`,WESTRING_UNITORDERUTARG_SPELLSTEAL UnitOrderAerialShackles=1,unitorderutarg,`magicleash`,WESTRING_UNITORDERUTARG_AERIALSHACKLES UnitOrderMassTeleport=0,unitorderutarg,`massteleport`,WESTRING_UNITORDERUTARG_MASSTELEPORT UnitOrderBanish=1,unitorderutarg,`banish`,WESTRING_UNITORDERUTARG_BANISH UnitOrderSiphonMana=1,unitorderutarg,`drain`,WESTRING_UNITORDERUTARG_SIPHONMANA UnitOrderThunderBolt=0,unitorderutarg,`thunderbolt`,WESTRING_UNITORDERUTARG_THUNDERBOLT UnitOrderHolyBolt=0,unitorderutarg,`holybolt`,WESTRING_UNITORDERUTARG_HOLYBOLT UnitOrderRepairO=0,unitorderutarg,`repair`,WESTRING_UNITORDERUTARG_REPAIRO UnitOrderEnsnare=0,unitorderutarg,`ensnare`,WESTRING_UNITORDERUTARG_ENSNARE UnitOrderUnstableConcoction=1,unitorderutarg,`unstableconcoction`,WESTRING_UNITORDERUTARG_UNSTABLECONCOCTION UnitOrderPurge=0,unitorderutarg,`purge`,WESTRING_UNITORDERUTARG_PURGE UnitOrderLightningShield=0,unitorderutarg,`lightningshield`,WESTRING_UNITORDERUTARG_LIGHTNINGSHIELD UnitOrderBloodlust=0,unitorderutarg,`bloodlust`,WESTRING_UNITORDERUTARG_BLOODLUST UnitOrderSpiritLink=1,unitorderutarg,`spiritlink`,WESTRING_UNITORDERUTARG_SPIRITLINK UnitOrderDevour=0,unitorderutarg,`devour`,WESTRING_UNITORDERUTARG_DEVOUR UnitOrderChainLightning=0,unitorderutarg,`chainlightning`,WESTRING_UNITORDERUTARG_CHAINLIGHTNING UnitOrderHealingWave=1,unitorderutarg,`healingwave`,WESTRING_UNITORDERUTARG_HEALINGWAVE UnitOrderHex=1,unitorderutarg,`hex`,WESTRING_UNITORDERUTARG_HEX UnitOrderAncestralSpiritTarg=1,unitorderutarg,`ancestralspirittarg`,WESTRING_UNITORDERUTARG_ANCESTRALSPIRIT UnitOrderRenew=0,unitorderutarg,`renew`,WESTRING_UNITORDERUTARG_RENEW UnitOrderEntangle=0,unitorderutarg,`entangle`,WESTRING_UNITORDERUTARG_ENTANGLE UnitOrderEntangleInstant=0,unitorderutarg,`entangleinstant`,WESTRING_UNITORDERUTARG_ENTANGLEINSTANT UnitOrderReplenish=0,unitorderutarg,`recharge`,WESTRING_UNITORDERUTARG_REPLENISH UnitOrderMountHippogryph=0,unitorderutarg,`mounthippogryph`,WESTRING_UNITORDERUTARG_MOUNTHIPPOGRYPH UnitOrderLoadArcher=0,unitorderutarg,`loadarcher`,WESTRING_UNITORDERUTARG_LOADARCHER UnitOrderAutoDispel=0,unitorderutarg,`autodispel`,WESTRING_UNITORDERUTARG_AUTODISPEL UnitOrderFaerieFire=0,unitorderutarg,`faeriefire`,WESTRING_UNITORDERUTARG_FAERIEFIRE UnitOrderCyclone=0,unitorderutarg,`cyclone`,WESTRING_UNITORDERUTARG_CYCLONE UnitOrderRejuvination=0,unitorderutarg,`rejuvination`,WESTRING_UNITORDERUTARG_REJUVINATION UnitOrderVengeance=1,unitorderutarg,`vengeance`,WESTRING_UNITORDERUTARG_VENGEANCE UnitOrderManaBurn=0,unitorderutarg,`manaburn`,WESTRING_UNITORDERUTARG_MANABURN UnitOrderEntanglingRoots=0,unitorderutarg,`entanglingroots`,WESTRING_UNITORDERUTARG_ENTANGLINGROOTS UnitOrderShadowStrike=1,unitorderutarg,`shadowstrike`,WESTRING_UNITORDERUTARG_SHADOWSTRIKE UnitOrderRestoration=0,unitorderutarg,`restoration`,WESTRING_UNITORDERUTARG_RESTORE UnitOrderSacrificeAcolyte=0,unitorderutarg,`sacrifice`,WESTRING_UNITORDERUTARG_SACRIFICEACOLYTE UnitOrderSacrifice=0,unitorderutarg,`requestsacrifice`,WESTRING_UNITORDERUTARG_SACRIFICE UnitOrderUnsummon=0,unitorderutarg,`unsummon`,WESTRING_UNITORDERUTARG_UNSUMMON UnitOrderWeb=0,unitorderutarg,`web`,WESTRING_UNITORDERUTARG_WEB UnitOrderRaiseDead=0,unitorderutarg,`raisedead`,WESTRING_UNITORDERUTARG_RAISEDEAD UnitOrderUnholyFrenzy=0,unitorderutarg,`unholyfrenzy`,WESTRING_UNITORDERUTARG_UNHOLYFRENZY UnitOrderCripple=0,unitorderutarg,`cripple`,WESTRING_UNITORDERUTARG_CRIPPLE UnitOrderCurse=0,unitorderutarg,`curse`,WESTRING_UNITORDERUTARG_CURSE UnitOrderAntiMagicShell=0,unitorderutarg,`antimagicshell`,WESTRING_UNITORDERUTARG_ANTIMAGICSHELL UnitOrderPossession=0,unitorderutarg,`possession`,WESTRING_UNITORDERUTARG_POSSESSION UnitOrderAbsorbMana=1,unitorderutarg,`absorb`,WESTRING_UNITORDERUTARG_ABSORBMANA UnitOrderFlamingAttack=1,unitorderutarg,`flamingattacktarg`,WESTRING_UNITORDERUTARG_FLAMINGATTACK UnitOrderImpale=1,unitorderutarg,`impale`,WESTRING_UNITORDERUTARG_IMPALE UnitOrderCarrionScarabs=1,unitorderutarg,`carrionscarabs`,WESTRING_UNITORDERUTARG_CARRIONSCARABS UnitOrderDeathCoil=0,unitorderutarg,`deathcoil`,WESTRING_UNITORDERUTARG_DEATHCOIL UnitOrderDeathPact=0,unitorderutarg,`deathpact`,WESTRING_UNITORDERUTARG_DEATHPACT UnitOrderSleep=0,unitorderutarg,`sleep`,WESTRING_UNITORDERUTARG_SLEEP UnitOrderFrostNova=0,unitorderutarg,`frostnova`,WESTRING_UNITORDERUTARG_FROSTNOVA UnitOrderFrostArmor=0,unitorderutarg,`frostarmor`,WESTRING_UNITORDERUTARG_FROSTARMOR UnitOrderDarkRitual=0,unitorderutarg,`darkritual`,WESTRING_UNITORDERUTARG_DARKRITUAL UnitOrderCreepDevour=1,unitorderutarg,`creepdevour`,WESTRING_UNITORDERUTARG_CREEPDEVOUR UnitOrderFirebolt=0,unitorderutarg,`firebolt`,WESTRING_UNITORDERUTARG_FIREBOLT UnitOrderCreepHeal=0,unitorderutarg,`creepheal`,WESTRING_UNITORDERUTARG_CREEPHEAL UnitOrderCreepThunderBolt=0,unitorderutarg,`creepthunderbolt`,WESTRING_UNITORDERUTARG_CREEPTHUNDERBOLT UnitOrderParasite=1,unitorderutarg,`parasite`,WESTRING_UNITORDERUTARG_PARASITE UnitOrderSelfDestructUnit=1,unitorderutarg,`selfdestruct`,WESTRING_UNITORDERUTARG_SELFDESTRUCT UnitOrderBlackArrow=1,unitorderutarg,`blackarrow`,WESTRING_UNITORDERUTARG_BLACKARROW UnitOrderCharm=1,unitorderutarg,`charm`,WESTRING_UNITORDERUTARG_CHARM UnitOrderLifeDrain=1,unitorderutarg,`drain`,WESTRING_UNITORDERUTARG_LIFEDRAIN UnitOrderColdArrow=1,unitorderutarg,`coldarrowstarg`,WESTRING_UNITORDERUTARG_COLDARROW UnitOrderForkedLightning=1,unitorderutarg,`forkedlightning`,WESTRING_UNITORDERUTARG_FORKEDLIGHTNING UnitOrderStrongDrink=1,unitorderutarg,`drunkenhaze`,WESTRING_UNITORDERUTARG_STRONGDRINK UnitOrderDoom=1,unitorderutarg,`doom`,WESTRING_UNITORDERUTARG_DOOM UnitOrderPoisonArrow=0,unitorderutarg,`poisonarrowstarg`,WESTRING_UNITORDERUTARG_POISONARROW UnitOrderIncinerateArrow=1,unitorderutarg,`incineratearrow`,WESTRING_UNITORDERUTARG_INCINERATEARROW UnitOrderFingerOfDeath=0,unitorderutarg,`fingerofdeath`,WESTRING_UNITORDERUTARG_FINGEROFDEATH UnitOrderDarkConversion=0,unitorderutarg,`darkconversion`,WESTRING_UNITORDERUTARG_DARKCONVERSION UnitOrderSoulPreservation=0,unitorderutarg,`soulpreservation`,WESTRING_UNITORDERUTARG_SOULPRESERVATION UnitOrderDarkConversionFast=0,unitorderutarg,`darkconversion`,WESTRING_UNITORDERUTARG_DARKCONVERSIONFAST UnitOrderAttack=0,unitorderptarg,`attack`,WESTRING_UNITORDERPTARG_ATTACK UnitOrderAttackGround=0,unitorderptarg,`attackground`,WESTRING_UNITORDERPTARG_ATTACKGROUND UnitOrderMove=0,unitorderptarg,`move`,WESTRING_UNITORDERPTARG_MOVE UnitOrderPatrol=0,unitorderptarg,`patrol`,WESTRING_UNITORDERPTARG_PATROL UnitOrderSmartPoint=1,unitorderptarg,`smart`,WESTRING_UNITORDERPTARG_SMART UnitOrderSetRally=0,unitorderptarg,`setrally`,WESTRING_UNITORDERPTARG_SETRALLY UnitOrderUnloadAll=0,unitorderptarg,`unloadall`,WESTRING_UNITORDERPTARG_UNLOADALL UnitOrderFlare=0,unitorderptarg,`flare`,WESTRING_UNITORDERPTARG_FLARE UnitOrderCloudOfFog=1,unitorderptarg,`cloudoffog`,WESTRING_UNITORDERPTARG_CLOUDOFFOG UnitOrderBlizzard=0,unitorderptarg,`blizzard`,WESTRING_UNITORDERPTARG_BLIZZARD UnitOrderFlameStrike=1,unitorderptarg,`flamestrike`,WESTRING_UNITORDERPTARG_FLAMESTRIKE UnitOrderSentryWard=0,unitorderptarg,`evileye`,WESTRING_UNITORDERPTARG_SENTRYWARD UnitOrderStasisTrap=0,unitorderptarg,`stasistrap`,WESTRING_UNITORDERPTARG_STASISTRAP UnitOrderHealingWard=0,unitorderptarg,`healingward`,WESTRING_UNITORDERPTARG_HEALINGWARD UnitOrderDisenchant=1,unitorderptarg,`disenchant`,WESTRING_UNITORDERPTARG_DISENCHANT UnitOrderFarSight=0,unitorderptarg,`farsight`,WESTRING_UNITORDERPTARG_FARSIGHT UnitOrderEarthquake=0,unitorderptarg,`earthquake`,WESTRING_UNITORDERPTARG_EARTHQUAKE UnitOrderSerpentWard=1,unitorderptarg,`ward`,WESTRING_UNITORDERPTARG_SERPENTWARD UnitOrderShockwave=0,unitorderptarg,`shockwave`,WESTRING_UNITORDERPTARG_SHOCKWAVE UnitOrderRoot=0,unitorderptarg,`root`,WESTRING_UNITORDERPTARG_ROOT UnitOrderDetonate=0,unitorderptarg,`detonate`,WESTRING_UNITORDERPTARG_DETONATE UnitOrderForceOfNature=0,unitorderptarg,`forceofnature`,WESTRING_UNITORDERPTARG_FORCEOFNATURE UnitOrderStarfall=0,unitorderptarg,`obsolete`,WESTRING_UNITORDERPTARG_STARFALL UnitOrderBlink=1,unitorderptarg,`blink`,WESTRING_UNITORDERPTARG_BLINK UnitOrderDevourMagic=1,unitorderptarg,`devourmagic`,WESTRING_UNITORDERPTARG_DEVOURMAGIC UnitOrderImpalePoint=1,unitorderptarg,`impale`,WESTRING_UNITORDERPTARG_IMPALE UnitOrderCarrionSwarm=0,unitorderptarg,`carrionswarm`,WESTRING_UNITORDERPTARG_CARRIONSWARM UnitOrderDarkSummoning=0,unitorderptarg,`dreadlordinferno`,WESTRING_UNITORDERPTARG_DARKSUMMONING UnitOrderDeathAndDecay=0,unitorderptarg,`deathanddecay`,WESTRING_UNITORDERPTARG_DEATHANDDECAY UnitOrderBreathOfFrost=1,unitorderptarg,`breathoffrost`,WESTRING_UNITORDERPTARG_BREATHOFFROST UnitOrderMonsoon=1,unitorderptarg,`monsoon`,WESTRING_UNITORDERPTARG_MONSOON UnitOrderSelfDestruct=0,unitorderptarg,`selfdestruct`,WESTRING_UNITORDERPTARG_SELFDESTRUCT UnitOrderStampede=1,unitorderptarg,`stampede`,WESTRING_UNITORDERPTARG_STAMPEDE UnitOrderSilence=1,unitorderptarg,`silence`,WESTRING_UNITORDERPTARG_SILENCE UnitOrderTornado=1,unitorderptarg,`tornado`,WESTRING_UNITORDERPTARG_TORNADO UnitOrderBreathOfFire=1,unitorderptarg,`breathoffire`,WESTRING_UNITORDERPTARG_BREATHOFFIRE UnitOrderHeroRainOfFire=1,unitorderptarg,`rainoffire`,WESTRING_UNITORDERPTARG_HERORAINOFFIRE UnitOrderDarkPortal=0,unitorderptarg,`darkportal`,WESTRING_UNITORDERPTARG_DARKPORTAL UnitOrderRainOfChaos=0,unitorderptarg,`rainoffire`,WESTRING_UNITORDERPTARG_RAINOFCHAOS UnitOrderRainOfFire=0,unitorderptarg,`rainoffire`,WESTRING_UNITORDERPTARG_RAINOFFIRE UnitOrderInferno=0,unitorderptarg,`inferno`,WESTRING_UNITORDERPTARG_INFERNO UnitOrderDarkSummoningOld=0,unitorderptarg,`darksummoning`,WESTRING_UNITORDERPTARG_DARKSUMMONINGOLD UnitOrderAttackDestructible=0,unitorderdtarg,`attack`,WESTRING_UNITORDERDTARG_ATTACK UnitOrderSmartDestructible=1,unitorderdtarg,`smart`,WESTRING_UNITORDERDTARG_SMART UnitOrderHarvestDestructible=0,unitorderdtarg,`harvest`,WESTRING_UNITORDERDTARG_HARVEST UnitOrderConsumeTree=0,unitorderdtarg,`eattree`,WESTRING_UNITORDERDTARG_CONSUMETREE UnitOrderSentinel=0,unitorderdtarg,`sentinel`,WESTRING_UNITORDERDTARG_SENTINEL UnitOrderGrabTree=1,unitorderdtarg,`grabtree`,WESTRING_UNITORDERDTARG_GRABTREE UnitOrderStop=0,unitordernotarg,`stop`,WESTRING_UNITORDERNOTARG_STOP UnitOrderHoldPosition=0,unitordernotarg,`holdposition`,WESTRING_UNITORDERNOTARG_HOLDPOSITION UnitOrderAutoHarvestGold=0,unitordernotarg,`autoharvestgold`,WESTRING_UNITORDERNOTARG_AUTOHARVESTGOLD UnitOrderAutoHarvestLumber=0,unitordernotarg,`autoharvestlumber`,WESTRING_UNITORDERNOTARG_AUTOHARVESTLUMBER UnitOrderReturnResources=0,unitordernotarg,`returnresources`,WESTRING_UNITORDERNOTARG_RETURNRESOURCES UnitOrderBuild=1,unitordernotarg,`build`,WESTRING_UNITORDERNOTARG_BUILD UnitOrderLevelup=1,unitordernotarg,`levelup`,WESTRING_UNITORDERNOTARG_LEVELUP UnitOrderHumanBuild=1,unitordernotarg,`humanbuild`,WESTRING_UNITORDERNOTARG_HUMANBUILD UnitOrderTownBellOn=0,unitordernotarg,`townbellon`,WESTRING_UNITORDERNOTARG_TOWNBELLON UnitOrderTownBellOff=0,unitordernotarg,`townbelloff`,WESTRING_UNITORDERNOTARG_TOWNBELLOFF UnitOrderMilitia=0,unitordernotarg,`militia`,WESTRING_UNITORDERNOTARG_MILITIA UnitOrderMilitiaOff=0,unitordernotarg,`militiaoff`,WESTRING_UNITORDERNOTARG_MILITIAOFF UnitOrderRepairOn=0,unitordernotarg,`repairon`,WESTRING_UNITORDERNOTARG_REPAIRON UnitOrderRepairOff=0,unitordernotarg,`repairoff`,WESTRING_UNITORDERNOTARG_REPAIROFF UnitOrderDefend=0,unitordernotarg,`defend`,WESTRING_UNITORDERNOTARG_DEFEND UnitOrderUnDefend=0,unitordernotarg,`undefend`,WESTRING_UNITORDERNOTARG_UNDEFEND UnitOrderHealOn=0,unitordernotarg,`healon`,WESTRING_UNITORDERNOTARG_HEALON UnitOrderHealOff=0,unitordernotarg,`healoff`,WESTRING_UNITORDERNOTARG_HEALOFF UnitOrderInnerFireOn=0,unitordernotarg,`innerfireon`,WESTRING_UNITORDERNOTARG_INNERFIREON UnitOrderInnerFireOff=0,unitordernotarg,`innerfireoff`,WESTRING_UNITORDERNOTARG_INNERFIREOFF UnitOrderSlowOn=0,unitordernotarg,`slowon`,WESTRING_UNITORDERNOTARG_SLOWON UnitOrderSlowOff=0,unitordernotarg,`slowoff`,WESTRING_UNITORDERNOTARG_SLOWOFF UnitOrderSpellStealOn=1,unitordernotarg,`spellstealon`,WESTRING_UNITORDERNOTARG_SPELLSTEALON UnitOrderSpellStealOff=1,unitordernotarg,`spellstealoff`,WESTRING_UNITORDERNOTARG_SPELLSTEALOFF UnitOrderWaterElemental=0,unitordernotarg,`waterelemental`,WESTRING_UNITORDERNOTARG_WATERELEMENTAL UnitOrderPhoenix=1,unitordernotarg,`phoenix`,WESTRING_UNITORDERNOTARG_PHOENIX UnitOrderThunderClap=0,unitordernotarg,`thunderclap`,WESTRING_UNITORDERNOTARG_THUNDERCLAP UnitOrderAvatar=0,unitordernotarg,`avatar`,WESTRING_UNITORDERNOTARG_AVATAR UnitOrderDivineShield=0,unitordernotarg,`divineshield`,WESTRING_UNITORDERNOTARG_DIVINESHIELD UnitOrderUnDivineShield=0,unitordernotarg,`undivineshield`,WESTRING_UNITORDERNOTARG_UNDIVINESHIELD UnitOrderResurrection=0,unitordernotarg,`resurrection`,WESTRING_UNITORDERNOTARG_RESURRECTION UnitOrderOrcBuild=1,unitordernotarg,`orcbuild`,WESTRING_UNITORDERNOTARG_ORCBUILD UnitOrderBattleStations=0,unitordernotarg,`battlestations`,WESTRING_UNITORDERNOTARG_BATTLESTATIONS UnitOrderStandDown=0,unitordernotarg,`standdown`,WESTRING_UNITORDERNOTARG_STANDDOWN UnitOrderRepairOOn=0,unitordernotarg,`repairon`,WESTRING_UNITORDERNOTARG_REPAIROON UnitOrderRepairOOff=0,unitordernotarg,`repairoff`,WESTRING_UNITORDERNOTARG_REPAIROOFF UnitOrderBerserk=1,unitordernotarg,`berserk`,WESTRING_UNITORDERNOTARG_BERSERK UnitOrderBloodlustOn=0,unitordernotarg,`bloodluston`,WESTRING_UNITORDERNOTARG_BLOODLUSTON UnitOrderBloodlustOff=0,unitordernotarg,`bloodlustoff`,WESTRING_UNITORDERNOTARG_BLOODLUSTOFF UnitOrderAncestralSpirit=1,unitordernotarg,`ancestralspirit`,WESTRING_UNITORDERNOTARG_ANCESTRALSPIRIT UnitOrderEtherealForm=1,unitordernotarg,`uncorporealform`,WESTRING_UNITORDERNOTARG_ETHEREALFORM UnitOrderCorporealForm=1,unitordernotarg,`corporealform`,WESTRING_UNITORDERNOTARG_CORPOREALFORM UnitOrderWindWalk=0,unitordernotarg,`windwalk`,WESTRING_UNITORDERNOTARG_WINDWALK UnitOrderMirrorImage=0,unitordernotarg,`mirrorimage`,WESTRING_UNITORDERNOTARG_MIRRORIMAGE UnitOrderWhirlWind=0,unitordernotarg,`whirlwind`,WESTRING_UNITORDERNOTARG_BLADESTORM UnitOrderSpiritWolf=0,unitordernotarg,`spiritwolf`,WESTRING_UNITORDERNOTARG_FERALSPIRIT UnitOrderVoodoo=1,unitordernotarg,`voodoo`,WESTRING_UNITORDERNOTARG_VOODOO UnitOrderStomp=0,unitordernotarg,`stomp`,WESTRING_UNITORDERNOTARG_WARSTOMP UnitOrderNightElfBuild=1,unitordernotarg,`nightelfbuild`,WESTRING_UNITORDERNOTARG_NIGHTELFBUILD UnitOrderUnRoot=0,unitordernotarg,`unroot`,WESTRING_UNITORDERNOTARG_UNROOT UnitOrderAutoEntangle=1,unitordernotarg,`autoentangle`,WESTRING_UNITORDERNOTARG_AUTOENTANGLE UnitOrderAutoEntangleInstant=1,unitordernotarg,`autoentangleinstant`,WESTRING_UNITORDERNOTARG_AUTOENTANGLEINSTANT UnitOrderReplenishOn=1,unitordernotarg,`rechargeon`,WESTRING_UNITORDERNOTARG_REPLENISHON UnitOrderReplenishOff=1,unitordernotarg,`rechargeoff`,WESTRING_UNITORDERNOTARG_REPLENISHOFF UnitOrderAmbush=0,unitordernotarg,`ambush`,WESTRING_UNITORDERNOTARG_HIDE UnitOrderRenewOn=0,unitordernotarg,`renewon`,WESTRING_UNITORDERNOTARG_RENEWON UnitOrderRenewOff=0,unitordernotarg,`renewoff`,WESTRING_UNITORDERNOTARG_RENEWOFF UnitOrderCoupleInstant1=1,unitordernotarg,`coupleinstant`,WESTRING_UNITORDERNOTARG_COUPLEINSTANT1 UnitOrderCoupleInstant2=1,unitordernotarg,`coupleinstant`,WESTRING_UNITORDERNOTARG_COUPLEINSTANT2 UnitOrderDecouple=1,unitordernotarg,`decouple`,WESTRING_UNITORDERNOTARG_DECOUPLE UnitOrderAutoDispelOn=0,unitordernotarg,`autodispelon`,WESTRING_UNITORDERNOTARG_AUTODISPELON UnitOrderAutoDispelOff=0,unitordernotarg,`autodispeloff`,WESTRING_UNITORDERNOTARG_AUTODISPELOFF UnitOrderFaerieFireOn=0,unitordernotarg,`faeriefireon`,WESTRING_UNITORDERNOTARG_FAERIEFIREON UnitOrderFaerieFireOff=0,unitordernotarg,`faeriefireoff`,WESTRING_UNITORDERNOTARG_FAERIEFIREOFF UnitOrderRavenForm=0,unitordernotarg,`ravenform`,WESTRING_UNITORDERNOTARG_RAVENFORM UnitOrderUnRavenForm=0,unitordernotarg,`unravenform`,WESTRING_UNITORDERNOTARG_UNRAVENFORM UnitOrderRoar=0,unitordernotarg,`roar`,WESTRING_UNITORDERNOTARG_ROAR UnitOrderBearForm=0,unitordernotarg,`bearform`,WESTRING_UNITORDERNOTARG_BEARFORM UnitOrderUnBearForm=0,unitordernotarg,`unbearform`,WESTRING_UNITORDERNOTARG_UNBEARFORM UnitOrderTaunt=1,unitordernotarg,`taunt`,WESTRING_UNITORDERNOTARG_TAUNT UnitOrderManaFlareOn=1,unitordernotarg,`manaflareon`,WESTRING_UNITORDERNOTARG_MANAFLAREON UnitOrderManaFlareOff=1,unitordernotarg,`manaflareoff`,WESTRING_UNITORDERNOTARG_MANAFLAREOFF UnitOrderPhaseShift=1,unitordernotarg,`phaseshift`,WESTRING_UNITORDERNOTARG_PHASESHIFT UnitOrderPhaseShiftOn=1,unitordernotarg,`phaseshifton`,WESTRING_UNITORDERNOTARG_PHASESHIFTON UnitOrderPhaseShiftOff=1,unitordernotarg,`phaseshiftoff`,WESTRING_UNITORDERNOTARG_PHASESHIFTOFF UnitOrderVengeanceInstant=1,unitordernotarg,`vengeanceinstant`,WESTRING_UNITORDERNOTARG_VENGEANCEINSTANT UnitOrderVengeanceOn=1,unitordernotarg,`vengeanceon`,WESTRING_UNITORDERNOTARG_VENGEANCEON UnitOrderVengeanceOff=1,unitordernotarg,`vengeanceoff`,WESTRING_UNITORDERNOTARG_VENGEANCEOFF UnitOrderImmolation=0,unitordernotarg,`immolation`,WESTRING_UNITORDERNOTARG_IMMOLATION UnitOrderUnImmolation=0,unitordernotarg,`unimmolation`,WESTRING_UNITORDERNOTARG_UNIMMOLATION UnitOrderMetamorphosis=0,unitordernotarg,`metamorphosis`,WESTRING_UNITORDERNOTARG_METAMORPHOSIS UnitOrderTranquility=0,unitordernotarg,`tranquility`,WESTRING_UNITORDERNOTARG_TRANQUILITY UnitOrderSearingArrows=0,unitordernotarg,`flamingarrows`,WESTRING_UNITORDERNOTARG_SEARINGARROWS UnitOrderUnSearingArrows=0,unitordernotarg,`unflamingarrows`,WESTRING_UNITORDERNOTARG_UNSEARINGARROWS UnitOrderScout=0,unitordernotarg,`scout`,WESTRING_UNITORDERNOTARG_SCOUT UnitOrderStarfall2=0,unitordernotarg,`starfall`,WESTRING_UNITORDERNOTARG_STARFALL UnitOrderFanOfKnives=1,unitordernotarg,`fanofknives`,WESTRING_UNITORDERNOTARG_FANOFKNIVES UnitOrderSpiritOfVengeance=1,unitordernotarg,`spiritofvengeance`,WESTRING_UNITORDERNOTARG_SPIRITOFVENGEANCE UnitOrderUndeadBuild=1,unitordernotarg,`undeadbuild`,WESTRING_UNITORDERNOTARG_UNDEADBUILD UnitOrderRestorationOn=0,unitordernotarg,`restorationon`,WESTRING_UNITORDERNOTARG_RESTOREON UnitOrderRestorationOff=0,unitordernotarg,`restorationoff`,WESTRING_UNITORDERNOTARG_RESTOREOFF UnitOrderCannibalize=0,unitordernotarg,`cannibalize`,WESTRING_UNITORDERNOTARG_CANNIBALIZE UnitOrderWebOn=0,unitordernotarg,`webon`,WESTRING_UNITORDERNOTARG_WEBON UnitOrderWebOff=0,unitordernotarg,`weboff`,WESTRING_UNITORDERNOTARG_WEBOFF UnitOrderBurrow=1,unitordernotarg,`burrow`,WESTRING_UNITORDERNOTARG_BURROW UnitOrderUnBurrow=1,unitordernotarg,`unburrow`,WESTRING_UNITORDERNOTARG_UNBURROW UnitOrderLoadCorpse=0,unitordernotarg,`loadcorpse`,WESTRING_UNITORDERNOTARG_LOADCORPSE UnitOrderUnloadAllCorpses=0,unitordernotarg,`unloadallcorpses`,WESTRING_UNITORDERNOTARG_UNLOADALLCORPSES UnitOrderStoneForm=0,unitordernotarg,`stoneform`,WESTRING_UNITORDERNOTARG_STONEFORM UnitOrderUnStoneForm=0,unitordernotarg,`unstoneform`,WESTRING_UNITORDERNOTARG_UNSTONEFORM UnitOrderRaiseDeadInstant=1,unitordernotarg,`instant`,WESTRING_UNITORDERNOTARG_RAISEDEAD UnitOrderRaiseDeadOn=0,unitordernotarg,`raisedeadon`,WESTRING_UNITORDERNOTARG_RAISEDEADON UnitOrderRaiseDeadOff=0,unitordernotarg,`raisedeadoff`,WESTRING_UNITORDERNOTARG_RAISEDEADOFF UnitOrderCurseOn=0,unitordernotarg,`curseon`,WESTRING_UNITORDERNOTARG_CURSEON UnitOrderCurseOff=0,unitordernotarg,`curseoff`,WESTRING_UNITORDERNOTARG_CURSEOFF UnitOrderFlamingAttackOn=1,unitordernotarg,`flamingattack`,WESTRING_UNITORDERNOTARG_FLAMINGATTACKON UnitOrderFlamingAttackOff=1,unitordernotarg,`unflamingattack`,WESTRING_UNITORDERNOTARG_FLAMINGATTACKOFF UnitOrderSphinxForm=1,unitordernotarg,`avengerform`,WESTRING_UNITORDERNOTARG_SPHINXFORM UnitOrderReplenishLife=1,unitordernotarg,`replenishlife`,WESTRING_UNITORDERNOTARG_REPLENISHLIFE UnitOrderReplenishLifeOn=1,unitordernotarg,`replenishlifeon`,WESTRING_UNITORDERNOTARG_REPLENISHLIFEON UnitOrderReplenishLifeOff=1,unitordernotarg,`replenishlifeoff`,WESTRING_UNITORDERNOTARG_REPLENISHLIFEOFF UnitOrderReplenishMana=1,unitordernotarg,`replenishmana`,WESTRING_UNITORDERNOTARG_REPLENISHMANA UnitOrderReplenishManaOn=1,unitordernotarg,`replenishmanaon`,WESTRING_UNITORDERNOTARG_REPLENISHMANAON UnitOrderReplenishManaOff=1,unitordernotarg,`replenishmanaoff`,WESTRING_UNITORDERNOTARG_REPLENISHMANAOFF UnitOrderCarrionScarabsOn=1,unitordernotarg,`carrionscarabson`,WESTRING_UNITORDERNOTARG_CARRIONSCARABSON UnitOrderCarrionScarabsOff=1,unitordernotarg,`carrionscarabsoff`,WESTRING_UNITORDERNOTARG_CARRIONSCARABSOFF UnitOrderCarrionScarabsInstant=1,unitordernotarg,`carrionscarabsinstant`,WESTRING_UNITORDERNOTARG_CARRIONSCARABS UnitOrderLocustSwarm=1,unitordernotarg,`locustswarm`,WESTRING_UNITORDERNOTARG_LOCUSTSWARM UnitOrderAnimateDead=0,unitordernotarg,`animatedead`,WESTRING_UNITORDERNOTARG_ANIMATEDEAD UnitOrderFrostArmorOn=0,unitordernotarg,`frostarmoron`,WESTRING_UNITORDERNOTARG_FROSTARMORON UnitOrderFrostArmorOff=0,unitordernotarg,`frostarmoroff`,WESTRING_UNITORDERNOTARG_FROSTARMOROFF UnitOrderNagaBuild=1,unitordernotarg,`nagabuild`,WESTRING_UNITORDERNOTARG_NAGABUILD UnitOrderCreepAnimateDead=0,unitordernotarg,`creepanimatedead`,WESTRING_UNITORDERNOTARG_CREEPANIMATEDEAD UnitOrderCreepHealOn=0,unitordernotarg,`creephealon`,WESTRING_UNITORDERNOTARG_CREEPHEALON UnitOrderCreepHealOff=0,unitordernotarg,`creephealoff`,WESTRING_UNITORDERNOTARG_CREEPHEALOFF UnitOrderRevenge=0,unitordernotarg,`revenge`,WESTRING_UNITORDERNOTARG_REVENGE UnitOrderCreepThunderClap=0,unitordernotarg,`creepthunderclap`,WESTRING_UNITORDERNOTARG_CREEPTHUNDERCLAP UnitOrderWateryMinion=1,unitordernotarg,`wateryminion`,WESTRING_UNITORDERNOTARG_WATERYMINION UnitOrderSelfDestructOn=1,unitordernotarg,`selfdestructon`,WESTRING_UNITORDERNOTARG_SELFDESTRUCTON UnitOrderSelfDestructOff=1,unitordernotarg,`selfdestructoff`,WESTRING_UNITORDERNOTARG_SELFDESTRUCTOFF UnitOrderSummonGrizzly=1,unitordernotarg,`summongrizzly`,WESTRING_UNITORDERNOTARG_SUMMONGRIZZLY UnitOrderSummonQuillbeast=1,unitordernotarg,`summonquillbeast`,WESTRING_UNITORDERNOTARG_SUMMONQUILLBEAST UnitOrderSummonWarEagle=1,unitordernotarg,`summonwareagle`,WESTRING_UNITORDERNOTARG_SUMMONWAREAGLE UnitOrderBlackArrowOn=1,unitordernotarg,`blackarrowon`,WESTRING_UNITORDERNOTARG_BLACKARROWON UnitOrderBlackArrowOff=1,unitordernotarg,`blackarrowoff`,WESTRING_UNITORDERNOTARG_BLACKARROWOFF UnitOrderColdArrowOn=1,unitordernotarg,`coldarrows`,WESTRING_UNITORDERNOTARG_COLDARROWON UnitOrderColdArrowOff=1,unitordernotarg,`uncoldarrows`,WESTRING_UNITORDERNOTARG_COLDARROWOFF UnitOrderManaShieldOn=1,unitordernotarg,`manashieldon`,WESTRING_UNITORDERNOTARG_MANASHIELDON UnitOrderManaShieldOff=1,unitordernotarg,`manashieldoff`,WESTRING_UNITORDERNOTARG_MANASHIELDOFF UnitOrderElementalFury=1,unitordernotarg,`elementalfury`,WESTRING_UNITORDERNOTARG_ELEMENTALFURY UnitOrderHowlOfTerror=1,unitordernotarg,`howlofterror`,WESTRING_UNITORDERNOTARG_HOWLOFTERROR UnitOrderPoisonArrows=0,unitordernotarg,`poisonarrows`,WESTRING_UNITORDERNOTARG_POISONARROWON UnitOrderUnPoisonArrows=0,unitordernotarg,`unpoisonarrows`,WESTRING_UNITORDERNOTARG_POISONARROWOFF UnitOrderChannel=1,unitordernotarg,`channel`,WESTRING_UNITORDERNOTARG_CHANNEL UnitOrderMedivhRavenForm=0,unitordernotarg,`ravenform`,WESTRING_UNITORDERNOTARG_MEDIVHRAVENFORM UnitOrderMedivhUnRavenForm=0,unitordernotarg,`unravenform`,WESTRING_UNITORDERNOTARG_MEDIVHUNRAVENFORM UnitOrderRexxarBattleRoar=1,unitordernotarg,`battleroar`,WESTRING_UNITORDERNOTARG_REXXARBATTLEROAR UnitOrderColdArrows=0,unitordernotarg,`coldarrows`,WESTRING_UNITORDERNOTARG_COLDARROWS UnitOrderUnColdArrows=0,unitordernotarg,`uncoldarrows`,WESTRING_UNITORDERNOTARG_UNCOLDARROWS HeroSkillBlizzard=0,heroskillcode,'AHbz',WESTRING_HEROSKILL_BLIZZARD HeroSkillWaterElemental=0,heroskillcode,'AHwe',WESTRING_HEROSKILL_WATERELEMENTAL HeroSkillBrillianceAura=0,heroskillcode,'AHab',WESTRING_HEROSKILL_BRILLIANCEAURA HeroSkillMassTeleport=0,heroskillcode,'AHmt',WESTRING_HEROSKILL_MASSTELEPORT HeroSkillFlameStrike=1,heroskillcode,'AHfs',WESTRING_HEROSKILL_FLAMESTRIKE HeroSkillBanish=1,heroskillcode,'AHbn',WESTRING_HEROSKILL_BANISH HeroSkillSiphonMana=1,heroskillcode,'AHdr',WESTRING_HEROSKILL_SIPHONMANA HeroSkillPhoenix=1,heroskillcode,'AHpx',WESTRING_HEROSKILL_PHOENIX HeroSkillStormBolt=0,heroskillcode,'AHtb',WESTRING_HEROSKILL_STORMBOLT HeroSkillThunderClap=0,heroskillcode,'AHtc',WESTRING_HEROSKILL_THUNDERCLAP HeroSkillBash=0,heroskillcode,'AHbh',WESTRING_HEROSKILL_BASH HeroSkillAvatar=0,heroskillcode,'AHav',WESTRING_HEROSKILL_AVATAR HeroSkillDivineShield=0,heroskillcode,'AHds',WESTRING_HEROSKILL_DIVINESHIELD HeroSkillHolyBolt=0,heroskillcode,'AHhb',WESTRING_HEROSKILL_HOLYBOLT HeroSkillDevotionAura=0,heroskillcode,'AHad',WESTRING_HEROSKILL_DEVOTIONAURA HeroSkillResurrection=0,heroskillcode,'AHre',WESTRING_HEROSKILL_RESURRECTION HeroSkillWindWalk=0,heroskillcode,'AOwk',WESTRING_HEROSKILL_WINDWALK HeroSkillMirrorImage=0,heroskillcode,'AOmi',WESTRING_HEROSKILL_MIRRORIMAGE HeroSkillCriticalStrike=0,heroskillcode,'AOcr',WESTRING_HEROSKILL_CRITICALSTRIKE HeroSkillWhirlwind=0,heroskillcode,'AOww',WESTRING_HEROSKILL_WHIRLWIND HeroSkillChainLightning=0,heroskillcode,'AOcl',WESTRING_HEROSKILL_CHAINLIGHTNING HeroSkillFarSight=0,heroskillcode,'AOfs',WESTRING_HEROSKILL_FARSIGHT HeroSkillSpiritWolf=0,heroskillcode,'AOsf',WESTRING_HEROSKILL_SPIRITWOLF HeroSkillEarthquake=0,heroskillcode,'AOeq',WESTRING_HEROSKILL_EARTHQUAKE HeroSkillHealingWave=1,heroskillcode,'AOhw',WESTRING_HEROSKILL_HEALINGWAVE HeroSkillHex=1,heroskillcode,'AOhx',WESTRING_HEROSKILL_HEX HeroSkillSerpentWard=1,heroskillcode,'AOsw',WESTRING_HEROSKILL_SERPENTWARD HeroSkillVoodoo=1,heroskillcode,'AOvd',WESTRING_HEROSKILL_VOODOO HeroSkillShockwave=0,heroskillcode,'AOsh',WESTRING_HEROSKILL_SHOCKWAVE HeroSkillWarStomp=0,heroskillcode,'AOws',WESTRING_HEROSKILL_WARSTOMP HeroSkillEnduranceAura=0,heroskillcode,'AOae',WESTRING_HEROSKILL_ENDURANCEAURA HeroSkillReincarnation=0,heroskillcode,'AOre',WESTRING_HEROSKILL_REINCARNATION HeroSkillImpale=1,heroskillcode,'AUim',WESTRING_HEROSKILL_IMPALE HeroSkillThornyShield=1,heroskillcode,'AUts',WESTRING_HEROSKILL_THORNYSHIELD HeroSkillCarrionScarabs=1,heroskillcode,'AUcb',WESTRING_HEROSKILL_CARRIONSCARABS HeroSkillLocustSwarm=1,heroskillcode,'AUls',WESTRING_HEROSKILL_LOCUSTSWARM HeroSkillDeathCoil=0,heroskillcode,'AUdc',WESTRING_HEROSKILL_DEATHCOIL HeroSkillDeathPact=0,heroskillcode,'AUdp',WESTRING_HEROSKILL_DEATHPACT HeroSkillUnholyAura=0,heroskillcode,'AUau',WESTRING_HEROSKILL_UNHOLYAURA HeroSkillAnimateDead=0,heroskillcode,'AUan',WESTRING_HEROSKILL_ANIMATEDEAD HeroSkillCarrionSwarm=0,heroskillcode,'AUcs',WESTRING_HEROSKILL_CARRIONSWARM HeroSkillSleep=0,heroskillcode,'AUsl',WESTRING_HEROSKILL_SLEEP HeroSkillVampiricAura=0,heroskillcode,'AUav',WESTRING_HEROSKILL_VAMPIRICAURA HeroSkillDarkSummoning=0,heroskillcode,'AUin',WESTRING_HEROSKILL_DARKSUMMONING HeroSkillFrostNova=0,heroskillcode,'AUfn',WESTRING_HEROSKILL_FROSTNOVA HeroSkillFrostArmor=0,heroskillcode,'AUfa',WESTRING_HEROSKILL_FROSTARMOR HeroSkillDarkRitual=0,heroskillcode,'AUdr',WESTRING_HEROSKILL_DARKRITUAL HeroSkillDeathAndDecay=0,heroskillcode,'AUdd',WESTRING_HEROSKILL_DEATHANDDECAY HeroSkillManaBurn=0,heroskillcode,'AEmb',WESTRING_HEROSKILL_MANABURN HeroSkillImmolation=0,heroskillcode,'AEim',WESTRING_HEROSKILL_IMMOLATION HeroSkillEvasion=0,heroskillcode,'AEev',WESTRING_HEROSKILL_EVASION HeroSkillMetamorphosis=0,heroskillcode,'AEme',WESTRING_HEROSKILL_METAMORPHOSIS HeroSkillEntanglingRoots=0,heroskillcode,'AEer',WESTRING_HEROSKILL_ENTANGLINGROOTS HeroSkillForceOfNature=0,heroskillcode,'AEfn',WESTRING_HEROSKILL_FORCEOFNATURE HeroSkillThornsAura=0,heroskillcode,'AEah',WESTRING_HEROSKILL_THORNSAURA HeroSkillTranquility=0,heroskillcode,'AEtq',WESTRING_HEROSKILL_TRANQUILITY HeroSkillScout=0,heroskillcode,'AEst',WESTRING_HEROSKILL_SCOUT HeroSkillSearingArrows=0,heroskillcode,'AHfa',WESTRING_HEROSKILL_SEARINGARROWS HeroSkillTrueshotAura=0,heroskillcode,'AEar',WESTRING_HEROSKILL_TRUESHOTAURA HeroSkillStarfall=0,heroskillcode,'AEsf',WESTRING_HEROSKILL_STARFALL HeroSkillFanOfKnives=1,heroskillcode,'AEfk',WESTRING_HEROSKILL_FANOFKNIVES HeroSkillBlink=1,heroskillcode,'AEbl',WESTRING_HEROSKILL_BLINK HeroSkillShadowTouch=1,heroskillcode,'AEsh',WESTRING_HEROSKILL_SHADOWTOUCH HeroSkillSpiritOfVengeance=1,heroskillcode,'AEsv',WESTRING_HEROSKILL_SPIRITOFVENGEANCE HeroSkillGrizzly=1,heroskillcode,'ANsg',WESTRING_HEROSKILL_GRIZZLY HeroSkillQuillbeast=1,heroskillcode,'ANsq',WESTRING_HEROSKILL_QUILLBEAST HeroSkillWarEagle=1,heroskillcode,'ANsw',WESTRING_HEROSKILL_WAREAGLE HeroSkillStampede=1,heroskillcode,'ANst',WESTRING_HEROSKILL_STAMPEDE HeroSkillSilence=1,heroskillcode,'ANsi',WESTRING_HEROSKILL_SILENCE HeroSkillBlackArrow=1,heroskillcode,'ANba',WESTRING_HEROSKILL_BLACKARROW HeroSkillLifeDrain=1,heroskillcode,'ANdr',WESTRING_HEROSKILL_LIFEDRAIN HeroSkillCharm=1,heroskillcode,'ANch',WESTRING_HEROSKILL_CHARM HeroSkillForkedLightning=1,heroskillcode,'ANfl',WESTRING_HEROSKILL_FORKEDLIGHTNING HeroSkillColdArrow=1,heroskillcode,'ANfa',WESTRING_HEROSKILL_COLDARROW HeroSkillManaShield=1,heroskillcode,'ANms',WESTRING_HEROSKILL_MANASHIELD HeroSkillTornado=1,heroskillcode,'ANto',WESTRING_HEROSKILL_TORNADO HeroSkillBreathOfFire=1,heroskillcode,'ANbf',WESTRING_HEROSKILL_BREATHOFFIRE HeroSkillStrongDrink=1,heroskillcode,'ANdh',WESTRING_HEROSKILL_STRONGDRINK HeroSkillDrunkenBrawler=1,heroskillcode,'ANdb',WESTRING_HEROSKILL_DRUNKENBRAWLER HeroSkillElementalFury=1,heroskillcode,'ANef',WESTRING_HEROSKILL_ELEMENTALFURY HeroSkillRainOfFire=1,heroskillcode,'ANrf',WESTRING_HEROSKILL_RAINOFFIRE HeroSkillHowlOfTerror=1,heroskillcode,'ANht',WESTRING_HEROSKILL_HOWLOFTERROR HeroSkillCleavingAttack=1,heroskillcode,'ANca',WESTRING_HEROSKILL_CLEAVINGATTACK HeroSkillDoom=1,heroskillcode,'ANdo',WESTRING_HEROSKILL_DOOM HeroSkillChainLightning2=1,heroskillcode,'AOcl',WESTRING_HEROSKILL_AKAMA_CHAINLIGHTNING HeroSkillSpiritBeast=1,heroskillcode,'ACs7',WESTRING_HEROSKILL_AKAMA_FERALSPIRIT HeroSkillShadowTouch2=1,heroskillcode,'AEsh',WESTRING_HEROSKILL_AKAMA_SHADOWTOUCH HeroSkillReincarnation2=1,heroskillcode,'ANr2',WESTRING_HEROSKILL_AKAMA_REINCARNATION HeroSkillDarkPortal=0,heroskillcode,'ANdp',WESTRING_HEROSKILL_DARKPORTAL HeroSkillRainOfChaos=0,heroskillcode,'ANrc',WESTRING_HEROSKILL_RAINOFCHAOS HeroSkillArchiBash=0,heroskillcode,'AHah',WESTRING_HEROSKILL_ARCHIBASH HeroSkillFingerOfDeath=0,heroskillcode,'ANfd',WESTRING_HEROSKILL_FINGEROFDEATH HeroSkillBalnaSleep=1,heroskillcode,'AUsl',WESTRING_HEROSKILL_BALNA_SLEEP HeroSkillBalnaVampiricAura=1,heroskillcode,'AUav',WESTRING_HEROSKILL_BALNA_VAMPIRICAURA HeroSkillBalnaRainOfChaos=1,heroskillcode,'ANr3',WESTRING_HEROSKILL_BALNA_RAINOFCHAOS HeroSkillBalnaFingerOfPain=1,heroskillcode,'ACf3',WESTRING_HEROSKILL_BALNA_FINGEROFPAIN HeroSkillBalnaEarthquake=1,heroskillcode,'AOeq',WESTRING_HEROSKILL_BALNA_EARTHQUAKE HeroSkillChenBreathOfFire=1,heroskillcode,'ANcf',WESTRING_HEROSKILL_CHEN_BREATHOFFIRE HeroSkillChenStrongDrink=1,heroskillcode,'Acdh',WESTRING_HEROSKILL_CHEN_STRONGDRINK HeroSkillChenDrunkenBrawler=1,heroskillcode,'Acdb',WESTRING_HEROSKILL_CHEN_DRUNKENBRAWLER HeroSkillChenElementalFury=1,heroskillcode,'Acef',WESTRING_HEROSKILL_CHEN_ELEMENTALFURY HeroSkillChenAttributeBonus=1,heroskillcode,'Aamk',WESTRING_HEROSKILL_CHEN_ATTRIBUTEBONUS HeroSkillDetheSleep=1,heroskillcode,'AUsl',WESTRING_HEROSKILL_DETHE_SLEEP HeroSkillDetheShadowTouch=1,heroskillcode,'AEsh',WESTRING_HEROSKILL_DETHE_SHADOWTOUCH HeroSkillDetheCarrionSwarm=1,heroskillcode,'AUcs',WESTRING_HEROSKILL_DETHE_CARRIONSWARM HeroSkillDetheDeathAndDecay=1,heroskillcode,'AUdd',WESTRING_HEROSKILL_DETHE_DEATHANDDECAY HeroSkillGaritShockwave=1,heroskillcode,'ANsh',WESTRING_HEROSKILL_GARIT_SHOCKWAVE HeroSkillGaritHolyLight=1,heroskillcode,'AHhb',WESTRING_HEROSKILL_GARIT_HOLYLIGHT HeroSkillGaritDevotionAura=1,heroskillcode,'AHad',WESTRING_HEROSKILL_GARIT_DEVOTIONAURA HeroSkillGaritAvatar=1,heroskillcode,'ANav',WESTRING_HEROSKILL_GARIT_AVATAR HeroSkillIllimorphosis=0,heroskillcode,'AEIl',WESTRING_HEROSKILL_ILLIMORPHOSIS HeroSkillEvilIllimorphosis=0,heroskillcode,'AEvi',WESTRING_HEROSKILL_EVILILLIMORPHOSIS HeroSkillMalganisSleep=0,heroskillcode,'ANdc',WESTRING_HEROSKILL_DARKCONVERSION HeroSkillSoulPreservation=0,heroskillcode,'ANsl',WESTRING_HEROSKILL_SOULPRESERVATION HeroSkillManarothReincarnation=0,heroskillcode,'ANrn',WESTRING_HEROSKILL_MANAROTHREINCARNATION HeroSkillRexxarGrizzly=1,heroskillcode,'Arsg',WESTRING_HEROSKILL_REXXAR_GRIZZLY HeroSkillRexxarQuillbeast=1,heroskillcode,'Arsq',WESTRING_HEROSKILL_REXXAR_QUILLBEAST HeroSkillRexxarStormBolt=1,heroskillcode,'ANsb',WESTRING_HEROSKILL_REXXAR_STORMBOLT HeroSkillRexxarStampede=1,heroskillcode,'Arsp',WESTRING_HEROSKILL_REXXAR_STAMPEDE HeroSkillRexxarAttributeBonus=1,heroskillcode,'Aamk',WESTRING_HEROSKILL_REXXAR_ATTRIBUTEBONUS HeroSkillRokhanHealingWave=1,heroskillcode,'ANhw',WESTRING_HEROSKILL_ROKHAN_HEALINGWAVE HeroSkillRokhanHex=1,heroskillcode,'ANhx',WESTRING_HEROSKILL_ROKHAN_HEX HeroSkillRokhanSerpentWard=1,heroskillcode,'Arsw',WESTRING_HEROSKILL_ROKHAN_SERPENTWARD HeroSkillRokhanVoodooSpirits=1,heroskillcode,'AOls',WESTRING_HEROSKILL_ROKHAN_VOODOOSPIRITS HeroSkillRokhanAttributeBonus=1,heroskillcode,'Aamk',WESTRING_HEROSKILL_ROKHAN_ATTRIBUTEBONUS HeroSkillColdArrows=0,heroskillcode,'AHca',WESTRING_HEROSKILL_COLDARROWS HeroSkillTichondriusInferno=0,heroskillcode,'SNin',WESTRING_HEROSKILL_TICHONDRIUSINFERNO HeroSkillVarimSleep=1,heroskillcode,'AUsl',WESTRING_HEROSKILL_VARIM_SLEEP HeroSkillVarimVampiricAura=1,heroskillcode,'AUav',WESTRING_HEROSKILL_VARIM_VAMPIRICAURA HeroSkillVarimRainOfFire=1,heroskillcode,'ANrf',WESTRING_HEROSKILL_VARIM_RAINOFFIRE HeroSkillVarimDoom=1,heroskillcode,'ANdo',WESTRING_HEROSKILL_VARIM_DOOM HeroSkillInfernal=0,heroskillcode,'ANin',WESTRING_HEROSKILL_INFERNAL HeroSkillMalganisSleepFast=0,heroskillcode,'SNdc',WESTRING_HEROSKILL_DARKCONVERSIONFAST HeroSkillDarkSummoningOld=0,heroskillcode,'AUds',WESTRING_HEROSKILL_DARKSUMMONINGOLD WeatherAshenvaleHeavyRain=0,weathereffectcode,'RAhr',WESTRING_WEATHER_ASHENVALEHEAVYRAIN WeatherAshenvaleLightRain=0,weathereffectcode,'RAlr',WESTRING_WEATHER_ASHENVALELIGHTRAIN WeatherDalaranShield=0,weathereffectcode,'MEds',WESTRING_WEATHER_DALARANSHIELD WeatherDungeonHeavyBlueFog=0,weathereffectcode,'FDbh',WESTRING_WEATHER_DUNGEONHEAVYBLUEFOG WeatherDungeonLightBlueFog=0,weathereffectcode,'FDbl',WESTRING_WEATHER_DUNGEONBLUEFOG WeatherDungeonHeavyGreenFog=0,weathereffectcode,'FDgh',WESTRING_WEATHER_DUNGEONHEAVYGREENFOG WeatherDungeonLightGreenFog=0,weathereffectcode,'FDgl',WESTRING_WEATHER_DUNGEONGREENFOG WeatherDungeonHeavyRedFog=0,weathereffectcode,'FDrh',WESTRING_WEATHER_DUNGEONHEAVYREDFOG WeatherDungeonLightRedFog=0,weathereffectcode,'FDrl',WESTRING_WEATHER_DUNGEONREDFOG WeatherDungeonHeavyWhiteFog=0,weathereffectcode,'FDwh',WESTRING_WEATHER_DUNGEONHEAVYWHITEFOG WeatherDungeonLightWhiteFog=0,weathereffectcode,'FDwl',WESTRING_WEATHER_DUNGEONWHITEFOG WeatherLordaeronHeavyRain=0,weathereffectcode,'RLhr',WESTRING_WEATHER_LORDAERONHEAVYRAIN WeatherLordaeronLightRain=0,weathereffectcode,'RLlr',WESTRING_WEATHER_LORDAERONLIGHTRAIN WeatherNorthrendBlizzard=0,weathereffectcode,'SNbs',WESTRING_WEATHER_NORTHRENDBLIZZARD WeatherNorthrendHeavySnow=0,weathereffectcode,'SNhs',WESTRING_WEATHER_NORTHRENDHEAVYSNOW WeatherNorthrendLightSnow=0,weathereffectcode,'SNls',WESTRING_WEATHER_NORTHRENDLIGHTSNOW WeatherOutlandWind=1,weathereffectcode,'WOcw',WESTRING_WEATHER_OUTLANDWIND WeatherOutlandWindLight=1,weathereffectcode,'WOlw',WESTRING_WEATHER_OUTLANDWINDLIGHT WeatherRaysOfLight=0,weathereffectcode,'LRaa',WESTRING_WEATHER_RAYSOFLIGHT WeatherRaysOfMoonlight=0,weathereffectcode,'LRma',WESTRING_WEATHER_RAYSOFMOONLIGHT WeatherHeavyWind=0,weathereffectcode,'WNcw',WESTRING_WEATHER_WIND AttackTypeNormal=1,attacktype,ATTACK_TYPE_NORMAL,WESTRING_UE_ATTACKTYPE_SPELLS AttackTypeMelee=1,attacktype,ATTACK_TYPE_MELEE,WESTRING_UE_ATTACKTYPE_NORMAL AttackTypePierce=1,attacktype,ATTACK_TYPE_PIERCE,WESTRING_UE_ATTACKTYPE_PIERCE AttackTypeSiege=1,attacktype,ATTACK_TYPE_SIEGE,WESTRING_UE_ATTACKTYPE_SIEGE AttackTypeMagic=1,attacktype,ATTACK_TYPE_MAGIC,WESTRING_UE_ATTACKTYPE_MAGIC AttackTypeChaos=1,attacktype,ATTACK_TYPE_CHAOS,WESTRING_UE_ATTACKTYPE_CHAOS AttackTypeHero=1,attacktype,ATTACK_TYPE_HERO,WESTRING_UE_ATTACKTYPE_HERO DamageTypeUnknown=1,damagetype,DAMAGE_TYPE_UNKNOWN,WESTRING_DAMAGE_TYPE_UNKNOWN DamageTypeNormal=1,damagetype,DAMAGE_TYPE_NORMAL,WESTRING_DAMAGE_TYPE_NORMAL DamageTypeEnhanced=1,damagetype,DAMAGE_TYPE_ENHANCED,WESTRING_DAMAGE_TYPE_ENHANCED DamageTypeFire=1,damagetype,DAMAGE_TYPE_FIRE,WESTRING_DAMAGE_TYPE_FIRE DamageTypeCold=1,damagetype,DAMAGE_TYPE_COLD,WESTRING_DAMAGE_TYPE_COLD DamageTypeLightning=1,damagetype,DAMAGE_TYPE_LIGHTNING,WESTRING_DAMAGE_TYPE_LIGHTNING DamageTypePoison=1,damagetype,DAMAGE_TYPE_POISON,WESTRING_DAMAGE_TYPE_POISON DamageTypeDisease=1,damagetype,DAMAGE_TYPE_DISEASE,WESTRING_DAMAGE_TYPE_DISEASE DamageTypeDivine=1,damagetype,DAMAGE_TYPE_DIVINE,WESTRING_DAMAGE_TYPE_DIVINE DamageTypeMagic=1,damagetype,DAMAGE_TYPE_MAGIC,WESTRING_DAMAGE_TYPE_MAGIC DamageTypeSonic=1,damagetype,DAMAGE_TYPE_SONIC,WESTRING_DAMAGE_TYPE_SONIC DamageTypeAcid=1,damagetype,DAMAGE_TYPE_ACID,WESTRING_DAMAGE_TYPE_ACID DamageTypeForce=1,damagetype,DAMAGE_TYPE_FORCE,WESTRING_DAMAGE_TYPE_FORCE DamageTypeDeath=1,damagetype,DAMAGE_TYPE_DEATH,WESTRING_DAMAGE_TYPE_DEATH DamageTypeMind=1,damagetype,DAMAGE_TYPE_MIND,WESTRING_DAMAGE_TYPE_MIND DamageTypePlant=1,damagetype,DAMAGE_TYPE_PLANT,WESTRING_DAMAGE_TYPE_PLANT DamageTypeDefensive=1,damagetype,DAMAGE_TYPE_DEFENSIVE,WESTRING_DAMAGE_TYPE_DEFENSIVE DamageTypeDemolition=1,damagetype,DAMAGE_TYPE_DEMOLITION,WESTRING_DAMAGE_TYPE_DEMOLITION DamageTypeSlowPoison=1,damagetype,DAMAGE_TYPE_SLOW_POISON,WESTRING_DAMAGE_TYPE_SLOW_POISON DamageTypeSpiritLink=1,damagetype,DAMAGE_TYPE_SPIRIT_LINK,WESTRING_DAMAGE_TYPE_SPIRIT_LINK DamageTypeShadowStrike=1,damagetype,DAMAGE_TYPE_SHADOW_STRIKE,WESTRING_DAMAGE_TYPE_SHADOW_STRIKE DamageTypeUniversal=1,damagetype,DAMAGE_TYPE_UNIVERSAL,WESTRING_DAMAGE_TYPE_UNIVERSAL WeaponTypeMetalLightChop=1,weapontype,WEAPON_TYPE_METAL_LIGHT_CHOP,WESTRING_UE_COMBATSOUND_METALLIGHTCHOP WeaponTypeMetalMediumChop=1,weapontype,WEAPON_TYPE_METAL_MEDIUM_CHOP,WESTRING_UE_COMBATSOUND_METALMEDIUMCHOP WeaponTypeMetalHeavyChop=1,weapontype,WEAPON_TYPE_METAL_HEAVY_CHOP,WESTRING_UE_COMBATSOUND_METALHEAVYCHOP WeaponTypeMetalLightSlice=1,weapontype,WEAPON_TYPE_METAL_LIGHT_SLICE,WESTRING_UE_COMBATSOUND_METALLIGHTSLICE WeaponTypeMetalMediumSlice=1,weapontype,WEAPON_TYPE_METAL_MEDIUM_SLICE,WESTRING_UE_COMBATSOUND_METALMEDIUMSLICE WeaponTypeMetalHeavySlice=1,weapontype,WEAPON_TYPE_METAL_HEAVY_SLICE,WESTRING_UE_COMBATSOUND_METALHEAVYSLICE WeaponTypeMetalMediumBash=1,weapontype,WEAPON_TYPE_METAL_MEDIUM_BASH,WESTRING_UE_COMBATSOUND_METALMEDIUMBASH WeaponTypeMetalHeavyBash=1,weapontype,WEAPON_TYPE_METAL_HEAVY_BASH,WESTRING_UE_COMBATSOUND_METALHEAVYBASH WeaponTypeWoodLightBash=1,weapontype,WEAPON_TYPE_WOOD_LIGHT_BASH,WESTRING_UE_COMBATSOUND_WOODLIGHTBASH WeaponTypeWoodMediumBash=1,weapontype,WEAPON_TYPE_WOOD_MEDIUM_BASH,WESTRING_UE_COMBATSOUND_WOODMEDIUMBASH WeaponTypeWoodHeavyBash=1,weapontype,WEAPON_TYPE_WOOD_HEAVY_BASH,WESTRING_UE_COMBATSOUND_WOODHEAVYBASH WeaponTypeAxeMediumChop=1,weapontype,WEAPON_TYPE_AXE_MEDIUM_CHOP,WESTRING_UE_COMBATSOUND_AXEMEDIUMCHOP WeaponTypeRockHeavyBash=1,weapontype,WEAPON_TYPE_ROCK_HEAVY_BASH,WESTRING_UE_COMBATSOUND_ROCKHEAVYBASH PathingTypeAny=0,pathingtype,PATHING_TYPE_ANY,WESTRING_PATHINGTYPE_ANY PathingTypeWalkability=0,pathingtype,PATHING_TYPE_WALKABILITY,WESTRING_PATHINGTYPE_WALKABILITY PathingTypeFlyability=0,pathingtype,PATHING_TYPE_FLYABILITY,WESTRING_PATHINGTYPE_FLYABILITY PathingTypeBuildability=0,pathingtype,PATHING_TYPE_BUILDABILITY,WESTRING_PATHINGTYPE_BUILDABILITY PathingTypePeonHarvestPathing=0,pathingtype,PATHING_TYPE_PEONHARVESTPATHING,WESTRING_PATHINGTYPE_PEONHARVESTPATHING PathingTypeBlightPathing=0,pathingtype,PATHING_TYPE_BLIGHTPATHING,WESTRING_PATHINGTYPE_BLIGHTPATHING PathingTypeFloatability=0,pathingtype,PATHING_TYPE_FLOATABILITY,WESTRING_PATHINGTYPE_FLOATABILITY PathingTypeAmphibiousPathing=0,pathingtype,PATHING_TYPE_AMPHIBIOUSPATHING,WESTRING_PATHINGTYPE_AMPHIBIOUSPATHING EffectTypeEffect=1,effecttype,EFFECT_TYPE_EFFECT,WESTRING_EFFECT_TYPE_EFFECT EffectTypeTarget=1,effecttype,EFFECT_TYPE_TARGET,WESTRING_EFFECT_TYPE_TARGET EffectTypeCaster=1,effecttype,EFFECT_TYPE_CASTER,WESTRING_EFFECT_TYPE_CASTER EffectTypeSpecial=1,effecttype,EFFECT_TYPE_SPECIAL,WESTRING_EFFECT_TYPE_SPECIAL EffectTypeAreaEffect=1,effecttype,EFFECT_TYPE_AREA_EFFECT,WESTRING_EFFECT_TYPE_AREA_EFFECT EffectTypeAOE=1,effecttype,EFFECT_TYPE_AREA_EFFECT,WESTRING_EFFECTTYPEOPTION_AREA_EFFECT EffectTypeMissile=1,effecttype,EFFECT_TYPE_MISSILE,WESTRING_EFFECT_TYPE_MISSILE EffectTypeLightning=1,effecttype,EFFECT_TYPE_LIGHTNING,WESTRING_EFFECT_TYPE_LIGHTNING SoundTypeEffect=1,soundtype,SOUND_TYPE_EFFECT,WESTRING_SOUND_TYPE_EFFECT SoundTypeEffectLooped=1,soundtype,SOUND_TYPE_EFFECT_LOOPED,WESTRING_SOUND_TYPE_EFFECT_LOOPED LightningCodeInit=1,lightningcode,"`INIT`",WESTRING_LIGHTNING_INIT LightningCodeClpb=1,lightningcode,"`CLPB`",WESTRING_LIGHTNING_CLPB LightningCodeClsb=1,lightningcode,"`CLSB`",WESTRING_LIGHTNING_CLSB LightningCodeMbur=1,lightningcode,"`MBUR`",WESTRING_LIGHTNING_MBUR LightningCodeChim=1,lightningcode,"`CHIM`",WESTRING_LIGHTNING_CHIM LightningCodeAfod=1,lightningcode,"`AFOD`",WESTRING_LIGHTNING_AFOD LightningCodeHwpb=1,lightningcode,"`HWPB`",WESTRING_LIGHTNING_HWPB LightningCodeHwsb=1,lightningcode,"`HWSB`",WESTRING_LIGHTNING_HWSB LightningCodeMfpb=1,lightningcode,"`MFPB`",WESTRING_LIGHTNING_MFPB LightningCodeDrab=1,lightningcode,"`DRAB`",WESTRING_LIGHTNING_DRAB LightningCodeDral=1,lightningcode,"`DRAL`",WESTRING_LIGHTNING_DRAL LightningCodeDram=1,lightningcode,"`DRAM`",WESTRING_LIGHTNING_DRAM LightningCodeFork=1,lightningcode,"`FORK`",WESTRING_LIGHTNING_FORK LightningCodeSplk=1,lightningcode,"`SPLK`",WESTRING_LIGHTNING_SPLK LightningCodeLeas=1,lightningcode,"`LEAS`",WESTRING_LIGHTNING_LEAS TerrainTypeLdrt=0,terraintype,'Ldrt',WESTRING_TERRAINTYPE_Ldrt TerrainTypeLdro=0,terraintype,'Ldro',WESTRING_TERRAINTYPE_Ldro TerrainTypeLdrg=0,terraintype,'Ldrg',WESTRING_TERRAINTYPE_Ldrg TerrainTypeLrok=0,terraintype,'Lrok',WESTRING_TERRAINTYPE_Lrok TerrainTypeLgrs=0,terraintype,'Lgrs',WESTRING_TERRAINTYPE_Lgrs TerrainTypeLgrd=0,terraintype,'Lgrd',WESTRING_TERRAINTYPE_Lgrd TerrainTypeFdrt=0,terraintype,'Fdrt',WESTRING_TERRAINTYPE_Fdrt TerrainTypeFdro=0,terraintype,'Fdro',WESTRING_TERRAINTYPE_Fdro TerrainTypeFdrg=0,terraintype,'Fdrg',WESTRING_TERRAINTYPE_Fdrg TerrainTypeFrok=0,terraintype,'Frok',WESTRING_TERRAINTYPE_Frok TerrainTypeFgrs=0,terraintype,'Fgrs',WESTRING_TERRAINTYPE_Fgrs TerrainTypeFgrd=0,terraintype,'Fgrd',WESTRING_TERRAINTYPE_Fgrd TerrainTypeWdrt=0,terraintype,'Wdrt',WESTRING_TERRAINTYPE_Wdrt TerrainTypeWdro=0,terraintype,'Wdro',WESTRING_TERRAINTYPE_Wdro TerrainTypeWsng=0,terraintype,'Wsng',WESTRING_TERRAINTYPE_Wsng TerrainTypeWrok=0,terraintype,'Wrok',WESTRING_TERRAINTYPE_Wrok TerrainTypeWgrs=0,terraintype,'Wgrs',WESTRING_TERRAINTYPE_Wgrs TerrainTypeWsnw=0,terraintype,'Wsnw',WESTRING_TERRAINTYPE_Wsnw TerrainTypeBdrt=0,terraintype,'Bdrt',WESTRING_TERRAINTYPE_Bdrt TerrainTypeBdrh=0,terraintype,'Bdrh',WESTRING_TERRAINTYPE_Bdrh TerrainTypeBdrr=0,terraintype,'Bdrr',WESTRING_TERRAINTYPE_Bdrr TerrainTypeBdrg=0,terraintype,'Bdrg',WESTRING_TERRAINTYPE_Bdrg TerrainTypeBdsr=0,terraintype,'Bdsr',WESTRING_TERRAINTYPE_Bdsr TerrainTypeBdsd=0,terraintype,'Bdsd',WESTRING_TERRAINTYPE_Bdsd TerrainTypeBflr=0,terraintype,'Bflr',WESTRING_TERRAINTYPE_Bflr TerrainTypeBgrr=0,terraintype,'Bgrr',WESTRING_TERRAINTYPE_Bgrr TerrainTypeAdrt=0,terraintype,'Adrt',WESTRING_TERRAINTYPE_Adrt TerrainTypeAdrd=0,terraintype,'Adrd',WESTRING_TERRAINTYPE_Adrd TerrainTypeAgrs=0,terraintype,'Agrs',WESTRING_TERRAINTYPE_Agrs TerrainTypeArck=0,terraintype,'Arck',WESTRING_TERRAINTYPE_Arck TerrainTypeAgrd=0,terraintype,'Agrd',WESTRING_TERRAINTYPE_Agrd TerrainTypeAvin=0,terraintype,'Avin',WESTRING_TERRAINTYPE_Avin TerrainTypeAdrg=0,terraintype,'Adrg',WESTRING_TERRAINTYPE_Adrg TerrainTypeAlvd=0,terraintype,'Alvd',WESTRING_TERRAINTYPE_Alvd TerrainTypeCdrt=0,terraintype,'Cdrt',WESTRING_TERRAINTYPE_Cdrt TerrainTypeCdrd=0,terraintype,'Cdrd',WESTRING_TERRAINTYPE_Cdrd TerrainTypeCpos=0,terraintype,'Cpos',WESTRING_TERRAINTYPE_Cpos TerrainTypeCrck=0,terraintype,'Crck',WESTRING_TERRAINTYPE_Crck TerrainTypeCvin=0,terraintype,'Cvin',WESTRING_TERRAINTYPE_Cvin TerrainTypeCgrs=0,terraintype,'Cgrs',WESTRING_TERRAINTYPE_Cgrs TerrainTypeClvg=0,terraintype,'Clvg',WESTRING_TERRAINTYPE_Clvg TerrainTypeNdrt=0,terraintype,'Ndrt',WESTRING_TERRAINTYPE_Ndrt TerrainTypeNdrd=0,terraintype,'Ndrd',WESTRING_TERRAINTYPE_Ndrd TerrainTypeNrck=0,terraintype,'Nrck',WESTRING_TERRAINTYPE_Nrck TerrainTypeNgrs=0,terraintype,'Ngrs',WESTRING_TERRAINTYPE_Ngrs TerrainTypeNice=0,terraintype,'Nice',WESTRING_TERRAINTYPE_Nice TerrainTypeNsnw=0,terraintype,'Nsnw',WESTRING_TERRAINTYPE_Nsnw TerrainTypeNsnr=0,terraintype,'Nsnr',WESTRING_TERRAINTYPE_Nsnr TerrainTypeYdrt=0,terraintype,'Ydrt',WESTRING_TERRAINTYPE_Ydrt TerrainTypeYdtr=0,terraintype,'Ydtr',WESTRING_TERRAINTYPE_Ydtr TerrainTypeYblm=0,terraintype,'Yblm',WESTRING_TERRAINTYPE_Yblm TerrainTypeYbtl=0,terraintype,'Ybtl',WESTRING_TERRAINTYPE_Ybtl TerrainTypeYsqd=0,terraintype,'Ysqd',WESTRING_TERRAINTYPE_Ysqd TerrainTypeYrtl=0,terraintype,'Yrtl',WESTRING_TERRAINTYPE_Yrtl TerrainTypeYgsb=0,terraintype,'Ygsb',WESTRING_TERRAINTYPE_Ygsb TerrainTypeYhdg=0,terraintype,'Yhdg',WESTRING_TERRAINTYPE_Yhdg TerrainTypeYwmb=0,terraintype,'Ywmb',WESTRING_TERRAINTYPE_Ywmb TerrainTypeVdrt=0,terraintype,'Vdrt',WESTRING_TERRAINTYPE_Vdrt TerrainTypeVdrr=0,terraintype,'Vdrr',WESTRING_TERRAINTYPE_Vdrr TerrainTypeVcrp=0,terraintype,'Vcrp',WESTRING_TERRAINTYPE_Vcrp TerrainTypeVcbp=0,terraintype,'Vcbp',WESTRING_TERRAINTYPE_Vcbp TerrainTypeVstp=0,terraintype,'Vstp',WESTRING_TERRAINTYPE_Vstp TerrainTypeVgrs=0,terraintype,'Vgrs',WESTRING_TERRAINTYPE_Vgrs TerrainTypeVrck=0,terraintype,'Vrck',WESTRING_TERRAINTYPE_Vrck TerrainTypeVgrt=0,terraintype,'Vgrt',WESTRING_TERRAINTYPE_Vgrt TerrainTypeQdrt=0,terraintype,'Qdrt',WESTRING_TERRAINTYPE_Qdrt TerrainTypeQdrr=0,terraintype,'Qdrr',WESTRING_TERRAINTYPE_Qdrr TerrainTypeQcrp=0,terraintype,'Qcrp',WESTRING_TERRAINTYPE_Qcrp TerrainTypeQcbp=0,terraintype,'Qcbp',WESTRING_TERRAINTYPE_Qcbp TerrainTypeQstp=0,terraintype,'Qstp',WESTRING_TERRAINTYPE_Qstp TerrainTypeQgrs=0,terraintype,'Qgrs',WESTRING_TERRAINTYPE_Qgrs TerrainTypeQrck=0,terraintype,'Qrck',WESTRING_TERRAINTYPE_Qrck TerrainTypeQgrt=0,terraintype,'Qgrt',WESTRING_TERRAINTYPE_Qgrt TerrainTypeXdrt=0,terraintype,'Xdrt',WESTRING_TERRAINTYPE_Xdrt TerrainTypeXdtr=0,terraintype,'Xdtr',WESTRING_TERRAINTYPE_Xdtr TerrainTypeXblm=0,terraintype,'Xblm',WESTRING_TERRAINTYPE_Xblm TerrainTypeXbtl=0,terraintype,'Xbtl',WESTRING_TERRAINTYPE_Xbtl TerrainTypeXsqd=0,terraintype,'Xsqd',WESTRING_TERRAINTYPE_Xsqd TerrainTypeXrtl=0,terraintype,'Xrtl',WESTRING_TERRAINTYPE_Xrtl TerrainTypeXgsb=0,terraintype,'Xgsb',WESTRING_TERRAINTYPE_Xgsb TerrainTypeXhdg=0,terraintype,'Xhdg',WESTRING_TERRAINTYPE_Xhdg TerrainTypeXwmb=0,terraintype,'Xwmb',WESTRING_TERRAINTYPE_Xwmb TerrainTypeDdrt=0,terraintype,'Ddrt',WESTRING_TERRAINTYPE_Ddrt TerrainTypeDbrk=0,terraintype,'Dbrk',WESTRING_TERRAINTYPE_Dbrk TerrainTypeDrds=0,terraintype,'Drds',WESTRING_TERRAINTYPE_Drds TerrainTypeDlvc=0,terraintype,'Dlvc',WESTRING_TERRAINTYPE_Dlvc TerrainTypeDlav=0,terraintype,'Dlav',WESTRING_TERRAINTYPE_Dlav TerrainTypeDdkr=0,terraintype,'Ddkr',WESTRING_TERRAINTYPE_Ddkr TerrainTypeDgrs=0,terraintype,'Dgrs',WESTRING_TERRAINTYPE_Dgrs TerrainTypeDsqd=0,terraintype,'Dsqd',WESTRING_TERRAINTYPE_Dsqd TerrainTypeGdrt=0,terraintype,'Gdrt',WESTRING_TERRAINTYPE_Gdrt TerrainTypeGbrk=0,terraintype,'Gbrk',WESTRING_TERRAINTYPE_Gbrk TerrainTypeGrds=0,terraintype,'Grds',WESTRING_TERRAINTYPE_Grds TerrainTypeGlvc=0,terraintype,'Glvc',WESTRING_TERRAINTYPE_Glvc TerrainTypeGlav=0,terraintype,'Glav',WESTRING_TERRAINTYPE_Glav TerrainTypeGdkr=0,terraintype,'Gdkr',WESTRING_TERRAINTYPE_Gdkr TerrainTypeGgrs=0,terraintype,'Ggrs',WESTRING_TERRAINTYPE_Ggrs TerrainTypeGsqd=0,terraintype,'Gsqd',WESTRING_TERRAINTYPE_Gsqd TerrainTypeZdrt=0,terraintype,'Zdrt',WESTRING_TERRAINTYPE_Zdrt TerrainTypeZdtr=0,terraintype,'Zdtr',WESTRING_TERRAINTYPE_Zdtr TerrainTypeZdrg=0,terraintype,'Zdrg',WESTRING_TERRAINTYPE_Zdrg TerrainTypeZbks=0,terraintype,'Zbks',WESTRING_TERRAINTYPE_Zbks TerrainTypeZsan=0,terraintype,'Zsan',WESTRING_TERRAINTYPE_Zsan TerrainTypeZbkl=0,terraintype,'Zbkl',WESTRING_TERRAINTYPE_Zbkl TerrainTypeZtil=0,terraintype,'Ztil',WESTRING_TERRAINTYPE_Ztil TerrainTypeZgrs=0,terraintype,'Zgrs',WESTRING_TERRAINTYPE_Zgrs TerrainTypeZvin=0,terraintype,'Zvin',WESTRING_TERRAINTYPE_Zvin TerrainTypeIdrt=0,terraintype,'Idrt',WESTRING_TERRAINTYPE_Idrt TerrainTypeIdtr=0,terraintype,'Idtr',WESTRING_TERRAINTYPE_Idtr TerrainTypeIdki=0,terraintype,'Idki',WESTRING_TERRAINTYPE_Idki TerrainTypeIbkb=0,terraintype,'Ibkb',WESTRING_TERRAINTYPE_Ibkb TerrainTypeIrbk=0,terraintype,'Irbk',WESTRING_TERRAINTYPE_Irbk TerrainTypeItbk=0,terraintype,'Itbk',WESTRING_TERRAINTYPE_Itbk TerrainTypeIice=0,terraintype,'Iice',WESTRING_TERRAINTYPE_Iice TerrainTypeIbsq=0,terraintype,'Ibsq',WESTRING_TERRAINTYPE_Ibsq TerrainTypeIsnw=0,terraintype,'Isnw',WESTRING_TERRAINTYPE_Isnw TerrainTypeOdrt=0,terraintype,'Odrt',WESTRING_TERRAINTYPE_Odrt TerrainTypeOdtr=0,terraintype,'Odtr',WESTRING_TERRAINTYPE_Odtr TerrainTypeOsmb=0,terraintype,'Osmb',WESTRING_TERRAINTYPE_Osmb TerrainTypeOfst=0,terraintype,'Ofst',WESTRING_TERRAINTYPE_Ofst TerrainTypeOlgb=0,terraintype,'Olgb',WESTRING_TERRAINTYPE_Olgb TerrainTypeOrok=0,terraintype,'Orok',WESTRING_TERRAINTYPE_Orok TerrainTypeOfsl=0,terraintype,'Ofsl',WESTRING_TERRAINTYPE_Ofsl TerrainTypeOaby=0,terraintype,'Oaby',WESTRING_TERRAINTYPE_Oaby TerrainTypeKdrt=0,terraintype,'Kdrt',WESTRING_TERRAINTYPE_Kdrt TerrainTypeKfsl=0,terraintype,'Kfsl',WESTRING_TERRAINTYPE_Kfsl TerrainTypeKdtr=0,terraintype,'Kdtr',WESTRING_TERRAINTYPE_Kdtr TerrainTypeKfst=0,terraintype,'Kfst',WESTRING_TERRAINTYPE_Kfst TerrainTypeKsmb=0,terraintype,'Ksmb',WESTRING_TERRAINTYPE_Ksmb TerrainTypeKlgb=0,terraintype,'Klgb',WESTRING_TERRAINTYPE_Klgb TerrainTypeKsqt=0,terraintype,'Ksqt',WESTRING_TERRAINTYPE_Ksqt TerrainTypeKdkt=0,terraintype,'Kdkt',WESTRING_TERRAINTYPE_Kdkt TerrainTypeJdrt=0,terraintype,'Jdrt',WESTRING_TERRAINTYPE_Jdrt TerrainTypeJdtr=0,terraintype,'Jdtr',WESTRING_TERRAINTYPE_Jdtr TerrainTypeJblm=0,terraintype,'Jblm',WESTRING_TERRAINTYPE_Jblm TerrainTypeJbtl=0,terraintype,'Jbtl',WESTRING_TERRAINTYPE_Jbtl TerrainTypeJsqd=0,terraintype,'Jsqd',WESTRING_TERRAINTYPE_Jsqd TerrainTypeJrtl=0,terraintype,'Jrtl',WESTRING_TERRAINTYPE_Jrtl TerrainTypeJgsb=0,terraintype,'Jgsb',WESTRING_TERRAINTYPE_Jgsb TerrainTypeJhdg=0,terraintype,'Jhdg',WESTRING_TERRAINTYPE_Jhdg TerrainTypeJwmb=0,terraintype,'Jwmb',WESTRING_TERRAINTYPE_Jwmb TerrainTypecAc2=0,terraintype,'cAc2',WESTRING_TERRAINTYPE_cAc2 TerrainTypecAc1=0,terraintype,'cAc1',WESTRING_TERRAINTYPE_cAc1 TerrainTypecBc2=0,terraintype,'cBc2',WESTRING_TERRAINTYPE_cBc2 TerrainTypecBc1=0,terraintype,'cBc1',WESTRING_TERRAINTYPE_cBc1 TerrainTypecKc1=0,terraintype,'cKc1',WESTRING_TERRAINTYPE_cKc1 TerrainTypecKc2=0,terraintype,'cKc2',WESTRING_TERRAINTYPE_cKc2 TerrainTypecYc2=0,terraintype,'cYc2',WESTRING_TERRAINTYPE_cYc2 TerrainTypecYc1=0,terraintype,'cYc1',WESTRING_TERRAINTYPE_cYc1 TerrainTypecXc2=0,terraintype,'cXc2',WESTRING_TERRAINTYPE_cXc2 TerrainTypecXc1=0,terraintype,'cXc1',WESTRING_TERRAINTYPE_cXc1 TerrainTypecJc2=0,terraintype,'cJc2',WESTRING_TERRAINTYPE_cJc2 TerrainTypecJc1=0,terraintype,'cJc1',WESTRING_TERRAINTYPE_cJc1 TerrainTypecDc2=0,terraintype,'cDc2',WESTRING_TERRAINTYPE_cDc2 TerrainTypecDc1=0,terraintype,'cDc1',WESTRING_TERRAINTYPE_cDc1 TerrainTypecCc2=0,terraintype,'cCc2',WESTRING_TERRAINTYPE_cCc2 TerrainTypecCc1=0,terraintype,'cCc1',WESTRING_TERRAINTYPE_cCc1 TerrainTypecIc2=0,terraintype,'cIc2',WESTRING_TERRAINTYPE_cIc2 TerrainTypecIc1=0,terraintype,'cIc1',WESTRING_TERRAINTYPE_cIc1 TerrainTypecFc2=0,terraintype,'cFc2',WESTRING_TERRAINTYPE_cFc2 TerrainTypecFc1=0,terraintype,'cFc1',WESTRING_TERRAINTYPE_cFc1 TerrainTypecLc2=0,terraintype,'cLc2',WESTRING_TERRAINTYPE_cLc2 TerrainTypecLc1=0,terraintype,'cLc1',WESTRING_TERRAINTYPE_cLc1 TerrainTypecWc2=0,terraintype,'cWc2',WESTRING_TERRAINTYPE_cWc2 TerrainTypecWc1=0,terraintype,'cWc1',WESTRING_TERRAINTYPE_cWc1 TerrainTypecNc2=0,terraintype,'cNc2',WESTRING_TERRAINTYPE_cNc2 TerrainTypecNc1=0,terraintype,'cNc1',WESTRING_TERRAINTYPE_cNc1 TerrainTypecOc1=0,terraintype,'cOc1',WESTRING_TERRAINTYPE_cOc1 TerrainTypecOc2=0,terraintype,'cOc2',WESTRING_TERRAINTYPE_cOc2 TerrainTypecZc2=0,terraintype,'cZc2',WESTRING_TERRAINTYPE_cZc2 TerrainTypecZc1=0,terraintype,'cZc1',WESTRING_TERRAINTYPE_cZc1 TerrainTypecGc2=0,terraintype,'cGc2',WESTRING_TERRAINTYPE_cGc2 TerrainTypecGc1=0,terraintype,'cGc1',WESTRING_TERRAINTYPE_cGc1 TerrainTypecVc2=0,terraintype,'cVc2',WESTRING_TERRAINTYPE_cVc2 TerrainTypecVc1=0,terraintype,'cVc1',WESTRING_TERRAINTYPE_cVc1 TerrainTypecQc2=0,terraintype,'cQc2',WESTRING_TERRAINTYPE_cQc2 TerrainTypecQc1=0,terraintype,'cQc1',WESTRING_TERRAINTYPE_cQc1 TerrainShapeCircle=0,terrainshape,0,WESTRING_TERRAINSHAPE_CIRCLE TerrainShapeSquare=0,terrainshape,1,WESTRING_TERRAINSHAPE_SQUARE LightningTypeCLPB=0,lightningtype,`CLPB`,WESTRING_LIGHTNINGTYPE_CLPB LightningTypeCLSB=0,lightningtype,`CLSB`,WESTRING_LIGHTNINGTYPE_CLSB LightningTypeMBUR=0,lightningtype,`MBUR`,WESTRING_LIGHTNINGTYPE_MBUR LightningTypeCHIM=0,lightningtype,`CHIM`,WESTRING_LIGHTNINGTYPE_CHIM LightningTypeAFOD=0,lightningtype,`AFOD`,WESTRING_LIGHTNINGTYPE_AFOD LightningTypeHWPB=0,lightningtype,`HWPB`,WESTRING_LIGHTNINGTYPE_HWPB LightningTypeHWSB=0,lightningtype,`HWSB`,WESTRING_LIGHTNINGTYPE_HWSB LightningTypeMFPB=0,lightningtype,`MFPB`,WESTRING_LIGHTNINGTYPE_MFPB LightningTypeDRAB=0,lightningtype,`DRAB`,WESTRING_LIGHTNINGTYPE_DRAB LightningTypeDRAL=0,lightningtype,`DRAL`,WESTRING_LIGHTNINGTYPE_DRAL LightningTypeDRAM=0,lightningtype,`DRAM`,WESTRING_LIGHTNINGTYPE_DRAM LightningTypeFORK=0,lightningtype,`FORK`,WESTRING_LIGHTNINGTYPE_FORK LightningTypeSPLK=0,lightningtype,`SPLK`,WESTRING_LIGHTNINGTYPE_SPLK LightningTypeLEAS=0,lightningtype,`LEAS`,WESTRING_LIGHTNINGTYPE_LEAS ImageTypeShadow=0,imagetype,0,WESTRING_IMAGETYPE_SHADOW ImageTypeSelection=0,imagetype,1,WESTRING_IMAGETYPE_SELECTION ImageTypeIndicator=0,imagetype,2,WESTRING_IMAGETYPE_INDICATOR ImageTypeOcclusionMark=0,imagetype,3,WESTRING_IMAGETYPE_OCCLUSIONMARK ImageTypeUbersplat=0,imagetype,4,WESTRING_IMAGETYPE_UBERSPLAT ImageTypeLast=0,imagetype,5,WESTRING_IMAGETYPE_LAST UbersplatTypeTEST=0,ubersplattype,`TEST`,WESTRING_UBERSPLAT_TEST UbersplatTypeLSDS=0,ubersplattype,`LSDS`,WESTRING_UBERSPLAT_LSDS UbersplatTypeLSDM=0,ubersplattype,`LSDM`,WESTRING_UBERSPLAT_LSDM UbersplatTypeLSDL=0,ubersplattype,`LSDL`,WESTRING_UBERSPLAT_LSDL UbersplatTypeHCRT=0,ubersplattype,`HCRT`,WESTRING_UBERSPLAT_HCRT UbersplatTypeUDSU=0,ubersplattype,`UDSU`,WESTRING_UBERSPLAT_UDSU UbersplatTypeDNCS=0,ubersplattype,`DNCS`,WESTRING_UBERSPLAT_DNCS UbersplatTypeHMTP=0,ubersplattype,`HMTP`,WESTRING_UBERSPLAT_HMTP UbersplatTypeSCTP=0,ubersplattype,`SCTP`,WESTRING_UBERSPLAT_SCTP UbersplatTypeAMRC=0,ubersplattype,`AMRC`,WESTRING_UBERSPLAT_AMRC UbersplatTypeDRKC=0,ubersplattype,`DRKC`,WESTRING_UBERSPLAT_DRKC UbersplatTypeDOSB=0,ubersplattype,`DOSB`,WESTRING_UBERSPLAT_DOSB UbersplatTypeDOMB=0,ubersplattype,`DOMB`,WESTRING_UBERSPLAT_DOMB UbersplatTypeDOLB=0,ubersplattype,`DOLB`,WESTRING_UBERSPLAT_DOLB UbersplatTypeDHSB=0,ubersplattype,`DHSB`,WESTRING_UBERSPLAT_DHSB UbersplatTypeDHMB=0,ubersplattype,`DHMB`,WESTRING_UBERSPLAT_DHMB UbersplatTypeDHLB=0,ubersplattype,`DHLB`,WESTRING_UBERSPLAT_DHLB UbersplatTypeDUSB=0,ubersplattype,`DUSB`,WESTRING_UBERSPLAT_DUSB UbersplatTypeDUMB=0,ubersplattype,`DUMB`,WESTRING_UBERSPLAT_DUMB UbersplatTypeDULB=0,ubersplattype,`DULB`,WESTRING_UBERSPLAT_DULB UbersplatTypeDNSB=0,ubersplattype,`DNSB`,WESTRING_UBERSPLAT_DNSB UbersplatTypeDNMB=0,ubersplattype,`DNMB`,WESTRING_UBERSPLAT_DNMB UbersplatTypeDNSA=0,ubersplattype,`DNSA`,WESTRING_UBERSPLAT_DNSA UbersplatTypeDNMA=0,ubersplattype,`DNMA`,WESTRING_UBERSPLAT_DNMA UbersplatTypeHSMA=0,ubersplattype,`HSMA`,WESTRING_UBERSPLAT_HSMA UbersplatTypeHMED=0,ubersplattype,`HMED`,WESTRING_UBERSPLAT_HMED UbersplatTypeHLAR=0,ubersplattype,`HLAR`,WESTRING_UBERSPLAT_HLAR UbersplatTypeOSMA=0,ubersplattype,`OSMA`,WESTRING_UBERSPLAT_OSMA UbersplatTypeOMED=0,ubersplattype,`OMED`,WESTRING_UBERSPLAT_OMED UbersplatTypeOLAR=0,ubersplattype,`OLAR`,WESTRING_UBERSPLAT_OLAR UbersplatTypeUSMA=0,ubersplattype,`USMA`,WESTRING_UBERSPLAT_USMA UbersplatTypeUMED=0,ubersplattype,`UMED`,WESTRING_UBERSPLAT_UMED UbersplatTypeULAR=0,ubersplattype,`ULAR`,WESTRING_UBERSPLAT_ULAR UbersplatTypeESMA=0,ubersplattype,`ESMA`,WESTRING_UBERSPLAT_ESMA UbersplatTypeEMDA=0,ubersplattype,`EMDA`,WESTRING_UBERSPLAT_EMDA UbersplatTypeESMB=0,ubersplattype,`ESMB`,WESTRING_UBERSPLAT_ESMB UbersplatTypeEMDB=0,ubersplattype,`EMDB`,WESTRING_UBERSPLAT_EMDB UbersplatTypeHTOW=0,ubersplattype,`HTOW`,WESTRING_UBERSPLAT_HTOW UbersplatTypeHCAS=0,ubersplattype,`HCAS`,WESTRING_UBERSPLAT_HCAS UbersplatTypeNGOL=0,ubersplattype,`NGOL`,WESTRING_UBERSPLAT_NGOL UbersplatTypeTHND=0,ubersplattype,`THND`,WESTRING_UBERSPLAT_THND UbersplatTypeNDGS=0,ubersplattype,`NDGS`,WESTRING_UBERSPLAT_NDGS UbersplatTypeCLTS=0,ubersplattype,`CLTS`,WESTRING_UBERSPLAT_CLTS UbersplatTypeHFS1=0,ubersplattype,`HFS1`,WESTRING_UBERSPLAT_HFS1 UbersplatTypeHFS2=0,ubersplattype,`HFS2`,WESTRING_UBERSPLAT_HFS2 UbersplatTypeUSBR=0,ubersplattype,`USBR`,WESTRING_UBERSPLAT_USBR UbersplatTypeNLAR=0,ubersplattype,`NLAR`,WESTRING_UBERSPLAT_NLAR UbersplatTypeNMED=0,ubersplattype,`NMED`,WESTRING_UBERSPLAT_NMED UbersplatTypeDPSW=0,ubersplattype,`DPSW`,WESTRING_UBERSPLAT_DPSW UbersplatTypeDPSE=0,ubersplattype,`DPSE`,WESTRING_UBERSPLAT_DPSE UbersplatTypeNVOL=0,ubersplattype,`NVOL`,WESTRING_UBERSPLAT_NVOL UbersplatTypeNVCR=0,ubersplattype,`NVCR`,WESTRING_UBERSPLAT_NVCR [TriggerEvents] MapInitializationEvent=0,nothing _MapInitializationEvent_Defaults= _MapInitializationEvent_Category=TC_NOTHING TriggerRegisterDeathEvent=0,destructable _TriggerRegisterDeathEvent_Defaults=_ _TriggerRegisterDeathEvent_Category=TC_DESTRUCT TriggerRegisterDestDeathInRegionEvent=1,rect _TriggerRegisterDestDeathInRegionEvent_Defaults=_ _TriggerRegisterDestDeathInRegionEvent_Category=TC_DESTRUCT TriggerRegisterDialogEventBJ=0,dialog _TriggerRegisterDialogEventBJ_Defaults=_ _TriggerRegisterDialogEventBJ_Category=TC_DIALOG TriggerRegisterGameStateEventTimeOfDay=0,limitop,real _TriggerRegisterGameStateEventTimeOfDay_Defaults=LimitOpEqual,12 _TriggerRegisterGameStateEventTimeOfDay_Limits=_,_,0,24 _TriggerRegisterGameStateEventTimeOfDay_Category=TC_GAME TriggerRegisterVariableEvent=0,VarAsString_Real,limitop,real _TriggerRegisterVariableEvent_Defaults=_,LimitOpEqual,0 _TriggerRegisterVariableEvent_Category=TC_GAME TriggerRegisterGameLoadedEventBJ=1,nothing _TriggerRegisterGameLoadedEventBJ_Defaults= _TriggerRegisterGameLoadedEventBJ_Category=TC_GAME TriggerRegisterGameSavedEventBJ=1,nothing _TriggerRegisterGameSavedEventBJ_Defaults= _TriggerRegisterGameSavedEventBJ_Category=TC_GAME TriggerRegisterShowSkillEventBJ=0,nothing _TriggerRegisterShowSkillEventBJ_Defaults= _TriggerRegisterShowSkillEventBJ_Category=TC_GAME TriggerRegisterBuildSubmenuEventBJ=0,nothing _TriggerRegisterBuildSubmenuEventBJ_Defaults= _TriggerRegisterBuildSubmenuEventBJ_Category=TC_GAME TriggerRegisterGameEvent=1,gameevent _TriggerRegisterGameEvent_Defaults=GameEventTourneyNow _TriggerRegisterGameEvent_Category=TC_GAME TriggerRegisterGameStateEvent=0,igamestate,limitop,integer _TriggerRegisterGameStateEvent_Defaults=IGamestateDisconnected,LimitOpEqual,1 _TriggerRegisterGameStateEvent_Category=TC_GAME TriggerRegisterPlayerChatEvent=0,player,string,chatmatchtype _TriggerRegisterPlayerChatEvent_Defaults=Player00,_,ChatMatchTypeExact _TriggerRegisterPlayerChatEvent_Category=TC_PLAYER TriggerRegisterPlayerEventEndCinematic=0,player _TriggerRegisterPlayerEventEndCinematic_Defaults=Player00 _TriggerRegisterPlayerEventEndCinematic_Category=TC_PLAYER TriggerRegisterPlayerSelectionEventBJ=0,player,seldeseloption _TriggerRegisterPlayerSelectionEventBJ_Defaults=Player00,SelDeselOptionSel _TriggerRegisterPlayerSelectionEventBJ_Category=TC_PLAYER TriggerRegisterPlayerKeyEventBJ=1,player,keyeventtype,keyeventkey _TriggerRegisterPlayerKeyEventBJ_Defaults=Player00,KeyEventTypeDepress,KeyEventKeyLeft _TriggerRegisterPlayerKeyEventBJ_Category=TC_PLAYER TriggerRegisterPlayerStateEvent=0,player,playerstate,limitop,real _TriggerRegisterPlayerStateEvent_Defaults=Player00,PlayerStateGold,LimitOpGreaterThanOrEqual,1000 _TriggerRegisterPlayerStateEvent_Category=TC_PLAYER TriggerRegisterPlayerEventAllianceChanged=0,player _TriggerRegisterPlayerEventAllianceChanged_Defaults=Player00 _TriggerRegisterPlayerEventAllianceChanged_Category=TC_PLAYER TriggerRegisterPlayerAllianceChange=0,player,alliancetype _TriggerRegisterPlayerAllianceChange_Defaults=Player00,AllianceTypePassive _TriggerRegisterPlayerAllianceChange_Category=TC_PLAYER TriggerRegisterPlayerEventVictory=0,player _TriggerRegisterPlayerEventVictory_Defaults=Player00 _TriggerRegisterPlayerEventVictory_Category=TC_PLAYER TriggerRegisterPlayerEventDefeat=0,player _TriggerRegisterPlayerEventDefeat_Defaults=Player00 _TriggerRegisterPlayerEventDefeat_Category=TC_PLAYER TriggerRegisterPlayerEventLeave=1,player _TriggerRegisterPlayerEventLeave_Defaults=Player00 _TriggerRegisterPlayerEventLeave_Category=TC_PLAYER TriggerRegisterPlayerEvent=0,player,playereventoption _TriggerRegisterPlayerEvent_Defaults=Player00,PlayerEventLeave _TriggerRegisterPlayerEvent_Category=TC_PLAYER TriggerRegisterTimerEventSingle=0,real _TriggerRegisterTimerEventSingle_Defaults=5 _TriggerRegisterTimerEventSingle_Limits=0,_ _TriggerRegisterTimerEventSingle_Category=TC_TIME TriggerRegisterTimerEventPeriodic=0,real _TriggerRegisterTimerEventPeriodic_Defaults=2 _TriggerRegisterTimerEventPeriodic_Limits=0,_ _TriggerRegisterTimerEventPeriodic_Category=TC_TIME TriggerRegisterTimerExpireEventBJ=0,timer _TriggerRegisterTimerExpireEventBJ_Defaults=_ _TriggerRegisterTimerExpireEventBJ_Category=TC_TIME TriggerRegisterTrackableHitEvent=0,trackable _TriggerRegisterTrackableHitEvent_Defaults=_ _TriggerRegisterTrackableHitEvent_Category=TC_TRACKABLE TriggerRegisterTrackableTrackEvent=0,trackable _TriggerRegisterTrackableTrackEvent_Defaults=_ _TriggerRegisterTrackableTrackEvent_Category=TC_TRACKABLE TriggerRegisterUnitEvent=0,unit,unitevent _TriggerRegisterUnitEvent_Defaults=_,UnitEventDeath _TriggerRegisterUnitEvent_Category=TC_UNIT TriggerRegisterPlayerUnitEventSimple=0,player,playerunitevent _TriggerRegisterPlayerUnitEventSimple_Defaults=Player00,PlayerUnitEventDeath _TriggerRegisterPlayerUnitEventSimple_Category=TC_UNIT TriggerRegisterAnyUnitEventBJ=1,playerunitevent _TriggerRegisterAnyUnitEventBJ_Defaults=PlayerUnitEventDeath _TriggerRegisterAnyUnitEventBJ_Category=TC_UNIT TriggerRegisterEnterRectSimple=0,rect _TriggerRegisterEnterRectSimple_Defaults=_ _TriggerRegisterEnterRectSimple_Category=TC_UNIT TriggerRegisterLeaveRectSimple=0,rect _TriggerRegisterLeaveRectSimple_Defaults=_ _TriggerRegisterLeaveRectSimple_Category=TC_UNIT TriggerRegisterUnitInRangeSimple=0,real,unit _TriggerRegisterUnitInRangeSimple_Defaults=256,_ _TriggerRegisterUnitInRangeSimple_Defaults=0,_,_,_ _TriggerRegisterUnitInRangeSimple_Category=TC_UNIT TriggerRegisterUnitLifeEvent=0,unit,limitop,real _TriggerRegisterUnitLifeEvent_Defaults=_,LimitOpLessThan,50 _TriggerRegisterUnitLifeEvent_Category=TC_UNIT TriggerRegisterUnitManaEvent=0,unit,limitop,real _TriggerRegisterUnitManaEvent_Defaults=_,LimitOpLessThan,50 _TriggerRegisterUnitManaEvent_Category=TC_UNIT TriggerRegisterEnterRegionSimple=0,region _TriggerRegisterEnterRegionSimple_Defaults=_ _TriggerRegisterEnterRegionSimple_Category=TC_UNIT TriggerRegisterLeaveRegionSimple=0,region _TriggerRegisterLeaveRegionSimple_Defaults=_ _TriggerRegisterLeaveRegionSimple_Category=TC_UNIT TriggerRegisterEnterRegion=1,region,boolexpr _TriggerRegisterEnterRegion_Defaults=_,_ _TriggerRegisterEnterRegion_Category=TC_UNIT TriggerRegisterLeaveRegion=1,region,boolexpr _TriggerRegisterLeaveRegion_Defaults=_,_ _TriggerRegisterLeaveRegion_Category=TC_UNIT TriggerRegisterUnitStateEvent=0,unit,unitstate,limitop,real _TriggerRegisterUnitStateEvent_Defaults=_,UnitStateLife,LimitOpGreaterThanOrEqual,100 _TriggerRegisterUnitStateEvent_Category=TC_UNIT [TriggerConditions] OperatorCompareBoolean=0,boolean,EqualNotEqualOperator,boolean _OperatorCompareBoolean_Defaults=IsUnitType,OperatorEqualENE,true _OperatorCompareBoolean_Category=TC_CONDITION _OperatorCompareBoolean_UseWithAI=1 _OperatorCompareBoolean_AIDefaults=true,OperatorEqualENE,true OperatorCompareAbilityId=1,abilcode,EqualNotEqualOperator,abilcode _OperatorCompareAbilityId_Defaults=GetSpellAbilityId,OperatorEqualENE,AUan _OperatorCompareAbilityId_Category=TC_CONDITION OperatorCompareBuffId=1,buffcode,EqualNotEqualOperator,buffcode _OperatorCompareBuffId_Defaults=_,OperatorEqualENE,_ _OperatorCompareBuffId_Category=TC_CONDITION OperatorCompareDestructible=0,destructable,EqualNotEqualOperator,destructable _OperatorCompareDestructible_Defaults=_,OperatorEqualENE,_ _OperatorCompareDestructible_Category=TC_CONDITION OperatorCompareDestructableCode=0,destructablecode,EqualNotEqualOperator,destructablecode _OperatorCompareDestructableCode_Defaults=GetDestructableTypeId,OperatorEqualENE,LTlt _OperatorCompareDestructableCode_Category=TC_CONDITION OperatorCompareButton=0,button,EqualNotEqualOperator,button _OperatorCompareButton_Defaults=GetClickedButtonBJ,OperatorEqualENE,_ _OperatorCompareButton_Category=TC_CONDITION OperatorCompareGameDifficulty=0,gamedifficulty,EqualNotEqualOperator,gamedifficulty _OperatorCompareGameDifficulty_Defaults=GetGameDifficulty,OperatorEqualENE,GameDifficultyNormal _OperatorCompareGameDifficulty_Category=TC_CONDITION OperatorCompareGameSpeed=0,gamespeed,EqualNotEqualOperator,gamespeed _OperatorCompareGameSpeed_Defaults=GetGameSpeed,OperatorEqualENE,GameSpeedNormal _OperatorCompareGameSpeed_Category=TC_CONDITION OperatorCompareGameState=0,gamestate,EqualNotEqualOperator,gamestate _OperatorCompareGameState_Defaults=GetEventGameState,OperatorEqualENE,GamestateDisconnected _OperatorCompareGameState_Category=TC_CONDITION OperatorCompareHeroSkill=0,heroskillcode,EqualNotEqualOperator,heroskillcode _OperatorCompareHeroSkill_Defaults=GetLearnedSkillBJ,OperatorEqualENE,HeroSkillBlizzard _OperatorCompareHeroSkill_Category=TC_CONDITION OperatorCompareInteger=0,integer,ComparisonOperator,integer _OperatorCompareInteger_Defaults=CountUnitsInGroup,OperatorEqual,0 _OperatorCompareInteger_Category=TC_CONDITION _OperatorCompareInteger_UseWithAI=1 _OperatorCompareInteger_AIDefaults=0,OperatorEqual,0 OperatorCompareItem=0,item,EqualNotEqualOperator,item _OperatorCompareItem_Defaults=_,OperatorEqualENE,_ _OperatorCompareItem_Category=TC_CONDITION OperatorCompareItemType=1,itemtype,EqualNotEqualOperator,itemtype _OperatorCompareItemType_Defaults=GetItemType,OperatorEqualENE,ItemTypePowerup _OperatorCompareItemType_Category=TC_CONDITION OperatorCompareItemCode=0,itemcode,EqualNotEqualOperator,itemcode _OperatorCompareItemCode_Defaults=GetItemTypeId,OperatorEqualENE,texp _OperatorCompareItemCode_Category=TC_CONDITION OperatorCompareMeleeDifficulty=1,aidifficulty,EqualNotEqualOperator,aidifficulty _OperatorCompareMeleeDifficulty_Defaults=GetAIDifficulty,OperatorEqualENE,AIDifficultyNormal _OperatorCompareMeleeDifficulty_Category=TC_CONDITION OperatorCompareOrderCode=0,ordercode,EqualNotEqualOperator,ordercode _OperatorCompareOrderCode_Defaults=GetIssuedOrderIdBJ,OperatorEqualENE,String2OrderIdBJ _OperatorCompareOrderCode_Category=TC_CONDITION OperatorComparePlayer=0,player,EqualNotEqualOperator,player _OperatorComparePlayer_Defaults=GetOwningPlayer,OperatorEqualENE,Player00 _OperatorComparePlayer_Category=TC_CONDITION OperatorComparePlayerColor=0,playercolor,EqualNotEqualOperator,playercolor _OperatorComparePlayerColor_Defaults=GetPlayerColor,OperatorEqualENE,Color00 _OperatorComparePlayerColor_Category=TC_CONDITION OperatorComparePlayerControl=0,mapcontrol,EqualNotEqualOperator,mapcontrol _OperatorComparePlayerControl_Defaults=GetPlayerController,OperatorEqualENE,MapControlUser _OperatorComparePlayerControl_Category=TC_CONDITION OperatorComparePlayerSlotStatus=0,playerslotstate,EqualNotEqualOperator,playerslotstate _OperatorComparePlayerSlotStatus_Defaults=GetPlayerSlotState,OperatorEqualENE,PlayerSlotStatePlaying _OperatorComparePlayerSlotStatus_Category=TC_CONDITION OperatorCompareRace=0,race,EqualNotEqualOperator,race _OperatorCompareRace_Defaults=GetPlayerRace,OperatorEqualENE,RaceHuman _OperatorCompareRace_Category=TC_CONDITION OperatorCompareReal=0,real,ComparisonOperator,real _OperatorCompareReal_Defaults=GetUnitStateSwap,OperatorGreaterEq,10 _OperatorCompareReal_Category=TC_CONDITION OperatorCompareString=0,string,EqualNotEqualOperator,string _OperatorCompareString_Defaults=GetEventPlayerChatString,OperatorEqualENE,_ _OperatorCompareString_Category=TC_CONDITION OperatorCompareTechCode=0,techcode,EqualNotEqualOperator,techcode _OperatorCompareTechCode_Defaults=GetResearched,OperatorEqualENE,_ _OperatorCompareTechCode_Category=TC_CONDITION OperatorCompareTerrainType=1,terraintype,EqualNotEqualOperator,terraintype _OperatorCompareTerrainType_Defaults=GetTerrainTypeBJ,OperatorEqualENE,TerrainTypeLdrt _OperatorCompareTerrainType_Category=TC_CONDITION OperatorCompareTrigger=0,trigger,EqualNotEqualOperator,trigger _OperatorCompareTrigger_Defaults=_,OperatorEqualENE,_ _OperatorCompareTrigger_Category=TC_CONDITION OperatorCompareUnit=0,unit,EqualNotEqualOperator,unit _OperatorCompareUnit_Defaults=GetTriggerUnit,OperatorEqualENE,_ _OperatorCompareUnit_Category=TC_CONDITION OperatorCompareUnitCode=0,unitcode,EqualNotEqualOperator,unitcode _OperatorCompareUnitCode_Defaults=GetUnitTypeId,OperatorEqualENE,hfoo _OperatorCompareUnitCode_Category=TC_CONDITION OperatorCompareEventId=0,eventid,EqualNotEqualOperator,eventid _OperatorCompareEventId_Defaults=GetTriggerEventId,OperatorEqualENE,_ _OperatorCompareEventId_Category=TC_CONDITION OperatorCompareTrackable=0,trackable,EqualNotEqualOperator,trackable _OperatorCompareTrackable_Defaults=GetTriggeringTrackable,OperatorEqualENE,_ _OperatorCompareTrackable_Category=TC_CONDITION OperatorCompareUbersplat=0,ubersplat,EqualNotEqualOperator,ubersplat _OperatorCompareUbersplat_Defaults=GetLastCreatedUbersplat,OperatorEqualENE,_ _OperatorCompareUbersplat_Category=TC_CONDITION OperatorCompareImage=0,image,EqualNotEqualOperator,image _OperatorCompareImage_Defaults=GetLastCreatedImage,OperatorEqualENE,_ _OperatorCompareImage_Category=TC_CONDITION OperatorCompareLightning=0,lightning,EqualNotEqualOperator,lightning _OperatorCompareLightning_Defaults=GetLastCreatedLightningBJ,OperatorEqualENE,_ _OperatorCompareLightning_Category=TC_CONDITION OperatorCompareTriggerAction=0,triggeraction,EqualNotEqualOperator,triggeraction _OperatorCompareTriggerAction_Defaults=_,OperatorEqualENE,_ _OperatorCompareTriggerAction_Category=TC_CONDITION OperatorCompareTriggerCondition=0,triggercondition,EqualNotEqualOperator,triggercondition _OperatorCompareTriggerCondition_Defaults=_,OperatorEqualENE,_ _OperatorCompareTriggerCondition_Category=TC_CONDITION OperatorComparePlayerState=0,playerstate,EqualNotEqualOperator,playerstate _OperatorComparePlayerState_Defaults=_,OperatorEqualENE,_ _OperatorComparePlayerState_Category=TC_CONDITION OperatorCompareUnitState=0,unitstate,EqualNotEqualOperator,unitstate _OperatorCompareUnitState_Defaults=_,OperatorEqualENE,_ _OperatorCompareUnitState_Category=TC_CONDITION OperatorCompareRegion=1,region,EqualNotEqualOperator,region _OperatorCompareRegion_Defaults=_,OperatorEqualENE,_ _OperatorCompareRegion_Category=TC_CONDITION GetBooleanAnd=0,boolcall,boolcall _GetBooleanAnd_Defaults=_,_ _GetBooleanAnd_Category=TC_CONDITION _GetBooleanAnd_UseWithAI=1 GetBooleanOr=0,boolcall,boolcall _GetBooleanOr_Defaults=_,_ _GetBooleanOr_Category=TC_CONDITION _GetBooleanOr_UseWithAI=1 AndMultiple=1,nothing _AndMultiple_Category=TC_CONDITION OrMultiple=1,nothing _OrMultiple_Category=TC_CONDITION =1,scriptcode _ _Defaults=true _ _Category=TC_CONDITION [TriggerActions] DoNothing=0,nothing _DoNothing_Defaults= _DoNothing_Category=TC_NOTHING CommentString=0,scriptcode _CommentString_Defaults=_ _CommentString_Category=TC_COMMENT CustomScriptCode=1,scriptcode _CustomScriptCode_Defaults=_ _CustomScriptCode_Category=TC_CUSTOM ExecuteFunc=0,string _ExecuteFunc_Defaults=DoNothing _ExecuteFunc_Category=TC_NOTHING TriggerSleepAction=0,real _TriggerSleepAction_Defaults=2 _TriggerSleepAction_Limits=0,_ _TriggerSleepAction_Category=TC_WAIT PolledWait=1,real _PolledWait_Defaults=2 _PolledWait_Limits=0,_ _PolledWait_Category=TC_WAIT WaitForCondition=1,boolexpr,real _WaitForCondition_Defaults=_,1 _WaitForCondition_Limits=_,_,0.1,_ _WaitForCondition_Category=TC_WAIT WaitForSoundBJ=0,sound,real _WaitForSoundBJ_Defaults=GetLastPlayedSound,0 _WaitForSoundBJ_Category=TC_WAIT SetVariable=0,AnyGlobal,Null _SetVariable_Defaults=_,_ _SetVariable_Category=TC_SETVARIABLE ReturnAction=0,nothing _ReturnAction_Defaults= _ReturnAction_Category=TC_SKIPACTIONS IfThenElseMultiple=1,nothing _IfThenElseMultiple_Category=TC_LOGIC IfThenElse=0,boolexpr,code,code _IfThenElse_Defaults=_,DoNothing,DoNothing _IfThenElse_Category=TC_LOGIC ForLoopAMultiple=1,integer,integer _ForLoopAMultiple_Defaults=1,10 _ForLoopAMultiple_Category=TC_FORLOOP ForLoopBMultiple=1,integer,integer _ForLoopBMultiple_Defaults=1,10 _ForLoopBMultiple_Category=TC_FORLOOP ForLoopVarMultiple=1,integervar,integer,integer _ForLoopVarMultiple_Defaults=_,1,10 _ForLoopVarMultiple_Category=TC_FORLOOP ForLoopA=0,integer,integer,code _ForLoopA_Defaults=1,10,DoNothing _ForLoopA_Category=TC_FORLOOP ForLoopB=0,integer,integer,code _ForLoopB_Defaults=1,10,DoNothing _ForLoopB_Category=TC_FORLOOP ForLoopVar=1,integervar,integer,integer,code _ForLoopVar_Defaults=_,1,10,DoNothing _ForLoopVar_Category=TC_FORLOOP StartMeleeAI=0,player,aiscript _StartMeleeAI_Defaults=Player00,"map.ai" _StartMeleeAI_Category=TC_AI StartCampaignAI=0,player,aiscript _StartCampaignAI_Defaults=Player00,"map.ai" _StartCampaignAI_Category=TC_AI CommandAI=0,player,integer,integer _CommandAI_Defaults=Player00,_,_ _CommandAI_Category=TC_AI RemoveGuardPosition=0,unit _RemoveGuardPosition_Defaults=_ _RemoveGuardPosition_Category=TC_AI RemoveAllGuardPositions=0,player _RemoveAllGuardPositions_Defaults=Player00 _RemoveAllGuardPositions_Category=TC_AI RecycleGuardPosition=0,unit _RecycleGuardPosition_Defaults=_ _RecycleGuardPosition_Category=TC_AI LockGuardPosition=1,unit _LockGuardPosition_Defaults=_ _LockGuardPosition_Category=TC_AI SetUnitAnimation=0,unit,string _SetUnitAnimation_Defaults=_,"stand" _SetUnitAnimation_Category=TC_ANIMATION SetUnitAnimationWithRarity=0,unit,string,raritycontrol _SetUnitAnimationWithRarity_Defaults=_,"stand",RarityControlFrequent _SetUnitAnimationWithRarity_Category=TC_ANIMATION QueueUnitAnimationBJ=0,unit,string _QueueUnitAnimationBJ_Defaults=_,"stand" _QueueUnitAnimationBJ_Category=TC_ANIMATION ResetUnitAnimation=0,unit _ResetUnitAnimation_Defaults=_ _ResetUnitAnimation_Category=TC_ANIMATION AddUnitAnimationPropertiesBJ=0,addremoveoption,string,unit _AddUnitAnimationPropertiesBJ_Defaults=AddRemoveAdd,"gold",_ _AddUnitAnimationPropertiesBJ_Category=TC_ANIMATION SetUnitLookAt=0,unit,unitfacingbone,unit,real,real,real _SetUnitLookAt_Defaults=_,UnitFacingBoneHead,_,0,0,90 _SetUnitLookAt_Category=TC_ANIMATION ResetUnitLookAt=0,unit _ResetUnitLookAt_Defaults=_ _ResetUnitLookAt_Category=TC_ANIMATION SetUnitScalePercent=0,unit,real,real,real _SetUnitScalePercent_Defaults=_,100,100,100 _SetUnitScalePercent_Limits=_,_,0,_,0,_,0,_ _SetUnitScalePercent_Category=TC_ANIMATION SetUnitVertexColorBJ=0,unit,real,real,real,real _SetUnitVertexColorBJ_Defaults=_,100,100,100,0 _SetUnitVertexColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _SetUnitVertexColorBJ_Category=TC_ANIMATION SetUnitTimeScalePercent=0,unit,real _SetUnitTimeScalePercent_Defaults=_,100 _SetUnitTimeScalePercent_Limits=_,_,0,_ _SetUnitTimeScalePercent_Category=TC_ANIMATION SetUnitTurnSpeedBJ=0,unit,real _SetUnitTurnSpeedBJ_Defaults=GetTriggerUnit,0.5 _SetUnitTurnSpeedBJ_Limits=_,_,0,1 _SetUnitTurnSpeedBJ_Category=TC_ANIMATION SetUnitBlendTimeBJ=0,unit,real _SetUnitBlendTimeBJ_Defaults=GetTriggerUnit,_ _SetUnitBlendTimeBJ_Category=TC_ANIMATION SetUnitFlyHeightBJ=0,unit,real,real _SetUnitFlyHeightBJ_Defaults=GetTriggerUnit,_,_ _SetUnitFlyHeightBJ_Category=TC_ANIMATION SetUnitPropWindowBJ=0,unit,real _SetUnitPropWindowBJ_Defaults=GetTriggerUnit,_ _SetUnitPropWindowBJ_Category=TC_ANIMATION SetDestructableAnimationBJ=0,destructable,string _SetDestructableAnimationBJ_Defaults=_,"stand" _SetDestructableAnimationBJ_Category=TC_ANIMATION QueueDestructableAnimationBJ=0,destructable,string _QueueDestructableAnimationBJ_Defaults=_,"stand" _QueueDestructableAnimationBJ_Category=TC_ANIMATION SetDestAnimationSpeedPercent=1,destructable,real _SetDestAnimationSpeedPercent_Defaults=_,100 _SetDestAnimationSpeedPercent_Category=TC_ANIMATION SetDoodadAnimationRectBJ=0,string,doodadcode,rect _SetDoodadAnimationRectBJ_Defaults="death",_,GetPlayableMapRect _SetDoodadAnimationRectBJ_Category=TC_ANIMATION SetDoodadAnimationBJ=0,string,doodadcode,real,location _SetDoodadAnimationBJ_Defaults="death",_,128,GetRectCenter _SetDoodadAnimationBJ_Category=TC_ANIMATION SetUnitAnimationByIndex=1,unit,integer _SetUnitAnimationByIndex_Defaults=GetTriggerUnit,1 _SetUnitAnimationByIndex_Category=TC_ANIMATION CameraSetupApplyForPlayer=0,cameraapplyoption,camerasetup,player,real _CameraSetupApplyForPlayer_Defaults=CameraApply,_,Player00,0 _CameraSetupApplyForPlayer_Limits=_,_,_,_,_,_,0,_ _CameraSetupApplyForPlayer_Category=TC_CAMERA PanCameraToTimedLocForPlayer=0,player,location,real _PanCameraToTimedLocForPlayer_Defaults=Player00,GetRectCenter,0 _PanCameraToTimedLocForPlayer_Limits=_,_,_,_,0,_ _PanCameraToTimedLocForPlayer_Category=TC_CAMERA PanCameraToTimedLocWithZForPlayer=0,player,location,real,real _PanCameraToTimedLocWithZForPlayer_Defaults=Player00,GetRectCenter,0,0 _PanCameraToTimedLocWithZForPlayer_Limits=_,_,_,_,_,_,0,_ _PanCameraToTimedLocWithZForPlayer_Category=TC_CAMERA SmartCameraPanBJ=0,player,location,real _SmartCameraPanBJ_Defaults=Player00,GetRectCenter,0.5 _SmartCameraPanBJ_Limits=_,_,_,_,0,_ _SmartCameraPanBJ_Category=TC_CAMERA SetCameraFieldForPlayer=0,player,camerafield,real,real _SetCameraFieldForPlayer_Defaults=Player00,CameraFieldTargetDistance,CameraSetupGetFieldSwap,0 _SetCameraFieldForPlayer_Limits=_,_,_,_,_,_,0,_ _SetCameraFieldForPlayer_Category=TC_CAMERA RotateCameraAroundLocBJ=1,real,location,player,real _RotateCameraAroundLocBJ_Defaults=90,GetRectCenter,Player00,2 _RotateCameraAroundLocBJ_Limits=_,_,_,_,_,_,0,_ _RotateCameraAroundLocBJ_Category=TC_CAMERA SetCameraTargetControllerNoZForPlayer=0,player,unit,real,real,cameraorientationoption _SetCameraTargetControllerNoZForPlayer_Defaults=Player00,GetTriggerUnit,0,0,CameraOrientationNormal _SetCameraTargetControllerNoZForPlayer_Category=TC_CAMERA SetCameraOrientControllerForPlayerBJ=0,player,unit,real,real _SetCameraOrientControllerForPlayerBJ_Defaults=Player00,GetTriggerUnit,0,0 _SetCameraOrientControllerForPlayerBJ_Category=TC_CAMERA SetCinematicCameraForPlayer=0,player,modelfile _SetCinematicCameraForPlayer_Defaults=Player00,"cinematic.mdl" _SetCinematicCameraForPlayer_Category=TC_CAMERA StopCameraForPlayerBJ=0,player _StopCameraForPlayerBJ_Defaults=Player00 _StopCameraForPlayerBJ_Category=TC_CAMERA ResetToGameCameraForPlayer=0,player,real _ResetToGameCameraForPlayer_Defaults=Player00,0 _ResetToGameCameraForPlayer_Limits=_,_,0,_ _ResetToGameCameraForPlayer_Category=TC_CAMERA CameraSetSmoothingFactorBJ=0,real _CameraSetSmoothingFactorBJ_Defaults=1 _CameraSetSmoothingFactorBJ_Limits=0,_ _CameraSetSmoothingFactorBJ_Category=TC_CAMERA CameraResetSmoothingFactorBJ=0,nothing _CameraResetSmoothingFactorBJ_Defaults= _CameraResetSmoothingFactorBJ_Category=TC_CAMERA CameraSetSourceNoiseForPlayer=0,player,real,real _CameraSetSourceNoiseForPlayer_Defaults=Player00,10,0.1 _CameraSetSourceNoiseForPlayer_Category=TC_CAMERA CameraSetTargetNoiseForPlayer=0,player,real,real _CameraSetTargetNoiseForPlayer_Defaults=Player00,10,0.1 _CameraSetTargetNoiseForPlayer_Category=TC_CAMERA CameraSetEQNoiseForPlayer=1,player,real _CameraSetEQNoiseForPlayer_Defaults=Player00,3 _CameraSetEQNoiseForPlayer_Limits=_,_,0,_ _CameraSetEQNoiseForPlayer_Category=TC_CAMERA CameraClearNoiseForPlayer=0,player _CameraClearNoiseForPlayer_Defaults=Player00 _CameraClearNoiseForPlayer_Category=TC_CAMERA AdjustCameraBoundsForPlayerBJ=0,cameraboundsadjusttype,player,real,real,real,real _AdjustCameraBoundsForPlayerBJ_Defaults=CameraBoundsAdjustAdd,Player00,0,0,0,0 _AdjustCameraBoundsForPlayerBJ_Category=TC_CAMERA SetCameraBoundsToRectForPlayerBJ=0,player,rect _SetCameraBoundsToRectForPlayerBJ_Defaults=Player00,_ _SetCameraBoundsToRectForPlayerBJ_Category=TC_CAMERA SetCameraQuickPositionLocForPlayer=0,player,location _SetCameraQuickPositionLocForPlayer_Defaults=Player00,GetRectCenter _SetCameraQuickPositionLocForPlayer_Category=TC_CAMERA TransmissionFromUnitWithNameBJ=0,force,unit,StringExt,sound,StringExt,addsettooption,real,waitdontoption _TransmissionFromUnitWithNameBJ_Defaults=GetPlayersAll,_,_,SoundNull,_,AddSetToAdd,0,WaitDontWait _TransmissionFromUnitWithNameBJ_Category=TC_CINEMATIC TransmissionFromUnitTypeWithNameBJ=0,force,player,unitcode,StringExt,location,sound,StringExt,addsettooption,real,waitdontoption _TransmissionFromUnitTypeWithNameBJ_Defaults=GetPlayersAll,Player00,hfoo,_,GetRectCenter,SoundNull,_,AddSetToAdd,0,WaitDontWait _TransmissionFromUnitTypeWithNameBJ_Category=TC_CINEMATIC ForceCinematicSubtitlesBJ=1,onoffoption _ForceCinematicSubtitlesBJ_Defaults=OnOffOn _ForceCinematicSubtitlesBJ_Category=TC_CINEMATIC CinematicModeBJ=0,onoffoption,force _CinematicModeBJ_Defaults=OnOffOn,GetPlayersAll _CinematicModeBJ_Category=TC_CINEMATIC CinematicModeExBJ=1,onoffoption,force,real _CinematicModeExBJ_Defaults=OnOffOn,GetPlayersAll,0.2 _CinematicModeExBJ_Category=TC_CINEMATIC CinematicFadeBJ=0,fadetypeoption,real,cinefiltertexture,real,real,real,real _CinematicFadeBJ_Defaults=FadeTypeOptionFadeOutIn,2,CineFilterTextureWhite,0,0,0,0 _CinematicFadeBJ_Limits=_,_,0,_,_,_,0,100,0,100,0,100,0,100 _CinematicFadeBJ_Category=TC_CINEMATIC CinematicFilterGenericBJ=0,real,blendmode,cinefiltertexture,real,real,real,real,real,real,real,real _CinematicFilterGenericBJ_Defaults=2,BlendModeBlend,CineFilterTextureWhite,100,100,100,100,0,0,0,0 _CinematicFilterGenericBJ_Limits=0,_,_,_,_,_,0,100,0,100,0,100,0,100,0,100,0,100,0,100,0,100 _CinematicFilterGenericBJ_Category=TC_CINEMATIC DisplayCineFilterBJ=0,showhideoption _DisplayCineFilterBJ_Defaults=ShowHideHide _DisplayCineFilterBJ_Category=TC_CINEMATIC PingMinimapLocForForce=0,force,location,real _PingMinimapLocForForce_Defaults=GetPlayersAll,GetRectCenter,1 _PingMinimapLocForForce_Limits=_,_,_,_,0,_ _PingMinimapLocForForce_Category=TC_CINEMATIC PingMinimapLocForForceEx=1,force,location,real,minimappingstyle,real,real,real _PingMinimapLocForForceEx_Defaults=GetPlayersAll,GetRectCenter,1,MinimapPingStyleSimple,100,100,100 _PingMinimapLocForForceEx_Limits=_,_,_,_,0,_,_,_,0,100,0,100,0,100 _PingMinimapLocForForceEx_Category=TC_CINEMATIC UnitAddIndicatorBJ=0,unit,real,real,real,real _UnitAddIndicatorBJ_Defaults=_,100,100,100,0 _UnitAddIndicatorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _UnitAddIndicatorBJ_Category=TC_CINEMATIC DestructableAddIndicatorBJ=0,destructable,real,real,real,real _DestructableAddIndicatorBJ_Defaults=_,100,100,100,0 _DestructableAddIndicatorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _DestructableAddIndicatorBJ_Category=TC_CINEMATIC ItemAddIndicatorBJ=0,item,real,real,real,real _ItemAddIndicatorBJ_Defaults=_,100,100,100,0 _ItemAddIndicatorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _ItemAddIndicatorBJ_Category=TC_CINEMATIC ClearTextMessagesBJ=0,force _ClearTextMessagesBJ_Defaults=GetPlayersAll _ClearTextMessagesBJ_Category=TC_CINEMATIC ShowInterfaceForceOff=0,force,real _ShowInterfaceForceOff_Defaults=GetPlayersAll,2 _ShowInterfaceForceOff_Limits=_,_,0,_ _ShowInterfaceForceOff_Category=TC_CINEMATIC ShowInterfaceForceOn=0,force,real _ShowInterfaceForceOn_Defaults=GetPlayersAll,2 _ShowInterfaceForceOn_Limits=_,_,0,_ _ShowInterfaceForceOn_Category=TC_CINEMATIC SetUserControlForceOff=0,force _SetUserControlForceOff_Defaults=GetPlayersAll _SetUserControlForceOff_Category=TC_CINEMATIC SetUserControlForceOn=0,force _SetUserControlForceOn_Defaults=GetPlayersAll _SetUserControlForceOn_Category=TC_CINEMATIC EnableOcclusionBJ=0,enabledisableoption,force _EnableOcclusionBJ_Defaults=EnableDisableDisable,GetPlayersAll _EnableOcclusionBJ_Category=TC_CINEMATIC EnableWorldFogBoundaryBJ=0,enabledisableoption,force _EnableWorldFogBoundaryBJ_Defaults=EnableDisableDisable,GetPlayersAll _EnableWorldFogBoundaryBJ_Category=TC_CINEMATIC PlayCinematic=1,string _PlayCinematic_Defaults="HumanEd" _PlayCinematic_Category=TC_CINEMATIC StartTimerBJ=0,timer,periodicoption,real _StartTimerBJ_Defaults=_,PeriodicOptionOneTime,30 _StartTimerBJ_Limits=_,_,_,_,0,_ _StartTimerBJ_Category=TC_TIMER PauseTimerBJ=0,pauseresumeoption,timer _PauseTimerBJ_Defaults=PauseResumePause,GetLastCreatedTimerBJ _PauseTimerBJ_Category=TC_TIMER CreateTimerDialogBJ=0,timer,StringExt _CreateTimerDialogBJ_Defaults=GetLastCreatedTimerBJ,_ _CreateTimerDialogBJ_Category=TC_TIMER DestroyTimerDialogBJ=0,timerdialog _DestroyTimerDialogBJ_Defaults=GetLastCreatedTimerDialogBJ _DestroyTimerDialogBJ_Category=TC_TIMER TimerDialogDisplayForPlayerBJ=1,showhideoption,timerdialog,player _TimerDialogDisplayForPlayerBJ_Defaults=ShowHideHide,GetLastCreatedTimerDialogBJ,Player00 _TimerDialogDisplayForPlayerBJ_Category=TC_TIMER TimerDialogDisplayBJ=0,showhideoption,timerdialog _TimerDialogDisplayBJ_Defaults=ShowHideHide,GetLastCreatedTimerDialogBJ _TimerDialogDisplayBJ_Category=TC_TIMER TimerDialogSetTitleBJ=0,timerdialog,StringExt _TimerDialogSetTitleBJ_Defaults=GetLastCreatedTimerDialogBJ,_ _TimerDialogSetTitleBJ_Category=TC_TIMER TimerDialogSetTitleColorBJ=0,timerdialog,real,real,real,real _TimerDialogSetTitleColorBJ_Defaults=GetLastCreatedTimerDialogBJ,100,80,20,0 _TimerDialogSetTitleColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _TimerDialogSetTitleColorBJ_Category=TC_TIMER TimerDialogSetTimeColorBJ=0,timerdialog,real,real,real,real _TimerDialogSetTimeColorBJ_Defaults=GetLastCreatedTimerDialogBJ,100,80,20,0 _TimerDialogSetTimeColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _TimerDialogSetTimeColorBJ_Category=TC_TIMER CreateDestructableLoc=0,destructablecode,location,real,real,integer _CreateDestructableLoc_Defaults=LTlt,GetRectCenter,GetRandomDirectionDeg,1,0 _CreateDestructableLoc_Limits=_,_,_,_,_,_,0,_,0,_ _CreateDestructableLoc_Category=TC_DESTRUCT CreateDeadDestructableLocBJ=0,destructablecode,location,real,real,integer _CreateDeadDestructableLocBJ_Defaults=LTlt,GetRectCenter,GetRandomDirectionDeg,1,0 _CreateDeadDestructableLocBJ_Limits=_,_,_,_,_,_,0,_,0,_ _CreateDeadDestructableLocBJ_Category=TC_DESTRUCT KillDestructable=0,destructable _KillDestructable_Defaults=GetLastCreatedDestructable _KillDestructable_Category=TC_DESTRUCT RemoveDestructable=0,destructable _RemoveDestructable_Defaults=GetLastCreatedDestructable _RemoveDestructable_Category=TC_DESTRUCT DestructableRestoreLife=0,destructable,real,showhideoption _DestructableRestoreLife_Defaults=GetLastCreatedDestructable,GetDestructableMaxLife,ShowHideShow _DestructableRestoreLife_Category=TC_DESTRUCT ShowDestructableBJ=1,showhideoption,destructable _ShowDestructableBJ_Defaults=ShowHideHide,GetLastCreatedDestructable _ShowDestructableBJ_Category=TC_DESTRUCT SetDestructableLifePercentBJ=0,destructable,real _SetDestructableLifePercentBJ_Defaults=GetLastCreatedDestructable,100 _SetDestructableLifePercentBJ_Limits=_,_,0,100 _SetDestructableLifePercentBJ_Category=TC_DESTRUCT SetDestructableLife=0,destructable,real _SetDestructableLife_Defaults=GetLastCreatedDestructable,GetDestructableMaxLife _SetDestructableLife_Limits=_,_,0,_ _SetDestructableLife_Category=TC_DESTRUCT SetDestructableMaxLifeBJ=0,destructable,real _SetDestructableMaxLifeBJ_Defaults=GetLastCreatedDestructable,100 _SetDestructableMaxLifeBJ_Limits=_,_,0,_ _SetDestructableMaxLifeBJ_Category=TC_DESTRUCT ModifyGateBJ=0,gateoperation,destructable _ModifyGateBJ_Defaults=GateOperationOpen,_ _ModifyGateBJ_Category=TC_DESTRUCT ChangeElevatorWalls=1,elevatorwallop,elevatorwalltype,destructable _ChangeElevatorWalls_Defaults=ElevatorWallOpClose,ElevatorWallTypeAll,_ _ChangeElevatorWalls_Category=TC_DESTRUCT ChangeElevatorHeight=1,destructable,integer _ChangeElevatorHeight_Defaults=_,1 _ChangeElevatorHeight_Limits=_,_,1,3 _ChangeElevatorHeight_Category=TC_DESTRUCT SetDestructableInvulnerableBJ=0,destructable,invulnerableoption _SetDestructableInvulnerableBJ_Defaults=GetLastCreatedDestructable,InvulnerabilityInvulnerable _SetDestructableInvulnerableBJ_Category=TC_DESTRUCT SetDestructableOccluderHeight=1,destructable,real _SetDestructableOccluderHeight_Defaults=_,128 _SetDestructableOccluderHeight_Category=TC_DESTRUCT EnumDestructablesInRectAllMultiple=1,rect _EnumDestructablesInRectAllMultiple_Defaults=GetPlayableMapRect _EnumDestructablesInRectAllMultiple_Category=TC_DESTRUCT _EnumDestructablesInRectAllMultiple_ScriptName=EnumDestructablesInRectAll EnumDestructablesInCircleBJMultiple=1,real,location _EnumDestructablesInCircleBJMultiple_Defaults=256,GetRectCenter _EnumDestructablesInCircleBJMultiple_Category=TC_DESTRUCT _EnumDestructablesInCircleBJMultiple_ScriptName=EnumDestructablesInCircleBJ EnumDestructablesInRectAll=0,rect,code _EnumDestructablesInRectAll_Defaults=GetPlayableMapRect,DoNothing _EnumDestructablesInRectAll_Category=TC_DESTRUCT EnumDestructablesInCircleBJ=0,real,location,code _EnumDestructablesInCircleBJ_Defaults=256,GetRectCenter,DoNothing _EnumDestructablesInCircleBJ_Category=TC_DESTRUCT DialogDisplayBJ=0,showhideoption,dialog,player _DialogDisplayBJ_Defaults=ShowHideShow,_,Player00 _DialogDisplayBJ_Category=TC_DIALOG DialogSetMessageBJ=0,dialog,StringExt _DialogSetMessageBJ_Defaults=_,_ _DialogSetMessageBJ_Category=TC_DIALOG DialogAddButtonBJ=0,dialog,StringExt _DialogAddButtonBJ_Defaults=_,_ _DialogAddButtonBJ_Category=TC_DIALOG DialogAddButton=0,dialog,string,integer _DialogAddButton_Defaults=_,_,65 _DialogAddButton_Category=TC_DIALOG DialogClearBJ=0,dialog _DialogClearBJ_Defaults=_ _DialogClearBJ_Category=TC_DIALOG DialogAddQuitButton=1,dialog,showhideoption,string,integer _DialogAddQuitButton_Defaults=_,ShowHideHide,_,_ _DialogAddQuitButton_Category=TC_DIALOG AddWeatherEffectSaveLast=0,rect,weathereffectcode _AddWeatherEffectSaveLast_Defaults=GetPlayableMapRect,WeatherAshenvaleHeavyRain _AddWeatherEffectSaveLast_Category=TC_ENVIRONMENT EnableWeatherEffect=0,weathereffect,onoffoption _EnableWeatherEffect_Defaults=GetLastCreatedWeatherEffect,OnOffOn _EnableWeatherEffect_Category=TC_ENVIRONMENT RemoveWeatherEffectBJ=0,weathereffect _RemoveWeatherEffectBJ_Defaults=GetLastCreatedWeatherEffect _RemoveWeatherEffectBJ_Category=TC_ENVIRONMENT TerrainDeformationCraterBJ=1,real,cratertype,location,real,real _TerrainDeformationCraterBJ_Defaults=0.5,CraterTypeTemporary,GetRectCenter,512,64 _TerrainDeformationCraterBJ_Limits=0.01,_,_,_,_,_,1,_,_,_ _TerrainDeformationCraterBJ_Category=TC_ENVIRONMENT TerrainDeformationRippleBJ=1,real,rippletype,location,real,real,real,real,real _TerrainDeformationRippleBJ_Defaults=4,RippleTypeNormal,GetRectCenter,1024,1024,64,1,512 _TerrainDeformationRippleBJ_Limits=0.01,_,_,_,_,_,0,_,1,_,_,_,0.01,_,1,_ _TerrainDeformationRippleBJ_Category=TC_ENVIRONMENT TerrainDeformationWaveBJ=1,real,location,location,real,real,real _TerrainDeformationWaveBJ_Defaults=0.5,GetRectCenter,GetRectCenter,256,96,0 _TerrainDeformationWaveBJ_Limits=0.01,_,_,_,_,_,0,_,_,_,0,_ _TerrainDeformationWaveBJ_Category=TC_ENVIRONMENT TerrainDeformationRandomBJ=1,real,location,real,real,real,real _TerrainDeformationRandomBJ_Defaults=4,GetRectCenter,512,-32,32,0.1 _TerrainDeformationRandomBJ_Limits=0.01,_,_,_,0,_,_,_,_,_,0.01,_ _TerrainDeformationRandomBJ_Category=TC_ENVIRONMENT TerrainDeformationStopBJ=1,terraindeformation,real _TerrainDeformationStopBJ_Defaults=GetLastCreatedTerrainDeformation,0 _TerrainDeformationStopBJ_Limits=_,_,0,_ _TerrainDeformationStopBJ_Category=TC_ENVIRONMENT TerrainDeformStopAll=1,nothing _TerrainDeformStopAll_Defaults= _TerrainDeformStopAll_Category=TC_ENVIRONMENT SetWaterDeforms=1,onoffoption _SetWaterDeforms_Defaults=OnOffOn _SetWaterDeforms_Category=TC_ENVIRONMENT SetTerrainTypeBJ=1,location,terraintype,integer,integer,terrainshape _SetTerrainTypeBJ_Defaults=GetRectCenter,TerrainTypeLdrt,-1,1,TerrainShapeCircle _SetTerrainTypeBJ_Category=TC_ENVIRONMENT SetTerrainPathableBJ=1,location,pathingtype,onoffoption _SetTerrainPathableBJ_Defaults=GetRectCenter,PathingTypeWalkability,OnOffOn _SetTerrainPathableBJ_Category=TC_ENVIRONMENT SetWaterBaseColorBJ=1,real,real,real,real _SetWaterBaseColorBJ_Defaults=100,100,100,0 _SetWaterBaseColorBJ_Limits=0,100,0,100,0,100,0,100 _SetWaterBaseColorBJ_Category=TC_ENVIRONMENT SetSkyModel=0,skymodelstring _SetSkyModel_Defaults=SkyModelNone _SetSkyModel_Category=TC_ENVIRONMENT SetTerrainFogExBJ=0,fogstyle,real,real,real,real,real,real _SetTerrainFogExBJ_Defaults=FogStyleLinear,1000,8000,0,100,100,100 _SetTerrainFogExBJ_Limits=_,_,0,_,0,_,0,_,0,100,0,100,0,100 _SetTerrainFogExBJ_Category=TC_ENVIRONMENT ResetTerrainFogBJ=0,nothing _ResetTerrainFogBJ_Defaults= _ResetTerrainFogBJ_Category=TC_ENVIRONMENT SetBlightRectBJ=0,createremoveoption,player,rect _SetBlightRectBJ_Defaults=CreateRemoveCreate,Player00,GetPlayableMapRect _SetBlightRectBJ_Category=TC_ENVIRONMENT SetBlightRadiusLocBJ=0,createremoveoption,player,location,real _SetBlightRadiusLocBJ_Defaults=CreateRemoveCreate,Player00,GetRectCenter,512 _SetBlightRadiusLocBJ_Limits=_,_,_,_,_,_,0,_ _SetBlightRadiusLocBJ_Category=TC_ENVIRONMENT CreateImageBJ=1,string,real,location,real,imagetype _CreateImageBJ_Defaults=_,1,GetRectCenter,0,ImageTypeIndicator _CreateImageBJ_Category=TC_IMAGE DestroyImage=1,image _DestroyImage_Defaults=GetLastCreatedImage _DestroyImage_Category=TC_IMAGE ShowImageBJ=1,showhideoption,image _ShowImageBJ_Defaults=ShowHideShow,GetLastCreatedImage _ShowImageBJ_Category=TC_IMAGE SetImageConstantHeight=1,image,enabledisableoption,real _SetImageConstantHeight_Defaults=GetLastCreatedImage,EnableDisableEnable,0 _SetImageConstantHeight_Category=TC_IMAGE SetImagePositionBJ=1,image,location,real _SetImagePositionBJ_Defaults=GetLastCreatedImage,GetRectCenter,0 _SetImagePositionBJ_Category=TC_IMAGE SetImageColorBJ=1,image,real,real,real,real _SetImageColorBJ_Defaults=GetLastCreatedImage,100,100,100,0 _SetImageColorBJ_Category=TC_IMAGE SetImageRender=1,image,enabledisableoption _SetImageRender_Defaults=GetLastCreatedImage,EnableDisableEnable _SetImageRender_Category=TC_IMAGE SetImageRenderAlways=1,image,enabledisableoption _SetImageRenderAlways_Defaults=GetLastCreatedImage,EnableDisableEnable _SetImageRenderAlways_Category=TC_IMAGE SetImageAboveWater=1,image,enabledisableoption,enabledisableoption _SetImageAboveWater_Defaults=GetLastCreatedImage,EnableDisableEnable,EnableDisableEnable _SetImageAboveWater_Category=TC_IMAGE SetImageType=1,image,imagetype _SetImageType_Defaults=GetLastCreatedImage,ImageTypeIndicator _SetImageType_Category=TC_IMAGE CreateUbersplatBJ=1,location,ubersplattype,real,real,real,real,enabledisableoption,enabledisableoption _CreateUberSplatBJ_Defaults=GetRectCenter,UbersplatTypeTEST,100,100,100,0,EnableDisableDisable,EnableDisableDisable _CreateUberSplatBJ_Category=TC_UBERSPLAT DestroyUbersplat=1,ubersplat _DestroyUbersplat_Defaults=GetLastCreatedUbersplat _DestroyUbersplat_Category=TC_UBERSPLAT ResetUbersplat=1,ubersplat _ResetUbersplat_Defaults=GetLastCreatedUbersplat _ResetUbersplat_Category=TC_UBERSPLAT FinishUbersplat=1,ubersplat _FinishUbersplat_Defaults=GetLastCreatedUbersplat _FinishUbersplat_Category=TC_UBERSPLAT ShowUbersplatBJ=1,showhideoption,ubersplat _ShowUbersplatBJ_Defaults=ShowHideShow,GetLastCreatedUbersplat _ShowUbersplatBJ_Category=TC_UBERSPLAT SetUbersplatRender=1,ubersplat,enabledisableoption _SetUbersplatRender_Defaults=GetLastCreatedUbersplat,EnableDisableEnable _SetUbersplatRender_Category=TC_UBERSPLAT SetUbersplatRenderAlways=1,ubersplat,enabledisableoption _SetUbersplatRenderAlways_Defaults=GetLastCreatedUbersplat,EnableDisableEnable _SetUbersplatRenderAlways_Category=TC_UBERSPLAT CreateTextTagLocBJ=1,StringExt,location,real,real,real,real,real,real _CreateTextTagLocBJ_Defaults=_,GetRectCenter,0,10,100,100,100,0 _CreateTextTagLocBJ_Limits=_,_,_,_,_,_,1,_,0,100,0,100,0,100,0,100 _CreateTextTagLocBJ_Category=TC_TEXTTAG CreateTextTagUnitBJ=1,StringExt,unit,real,real,real,real,real,real _CreateTextTagUnitBJ_Defaults=_,_,0,10,100,100,100,0 _CreateTextTagUnitBJ_Limits=_,_,_,_,_,_,1,_,0,100,0,100,0,100,0,100 _CreateTextTagUnitBJ_Category=TC_TEXTTAG DestroyTextTagBJ=1,texttag _DestroyTextTagBJ_Defaults=GetLastCreatedTextTag _DestroyTextTagBJ_Category=TC_TEXTTAG ShowTextTagForceBJ=1,showhideoption,texttag,force _ShowTextTagForceBJ_Defaults=ShowHideShow,GetLastCreatedTextTag,GetPlayersAll _ShowTextTagForceBJ_Category=TC_TEXTTAG SetTextTagVelocityBJ=1,texttag,real,real _SetTextTagVelocityBJ_Defaults=GetLastCreatedTextTag,64,90 _SetTextTagVelocityBJ_Category=TC_TEXTTAG SetTextTagColorBJ=1,texttag,real,real,real,real _SetTextTagColorBJ_Defaults=GetLastCreatedTextTag,100,100,100,0 _SetTextTagColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _SetTextTagColorBJ_Category=TC_TEXTTAG SetTextTagPosBJ=1,texttag,location,real _SetTextTagPosBJ_Defaults=GetLastCreatedTextTag,GetRectCenter,0 _SetTextTagPosBJ_Category=TC_TEXTTAG SetTextTagPosUnitBJ=1,texttag,unit,real _SetTextTagPosUnitBJ_Defaults=GetLastCreatedTextTag,_,0 _SetTextTagPosUnitBJ_Category=TC_TEXTTAG SetTextTagTextBJ=1,texttag,StringExt,real _SetTextTagTextBJ_Defaults=GetLastCreatedTextTag,_,10 _SetTextTagTextBJ_Category=TC_TEXTTAG SetTextTagSuspendedBJ=1,texttag,enabledisableoption _SetTextTagSuspendedBJ_Defaults=GetLastCreatedTextTag,EnableDisableEnable _SetTextTagSuspendedBJ_Category=TC_TEXTTAG SetTextTagPermanentBJ=1,texttag,enabledisableoption _SetTextTagPermanentBJ_Defaults=GetLastCreatedTextTag,EnableDisableEnable _SetTextTagPermanentBJ_Category=TC_TEXTTAG SetTextTagAgeBJ=1,texttag,real _SetTextTagAgeBJ_Defaults=GetLastCreatedTextTag,0 _SetTextTagAgeBJ_Category=TC_TEXTTAG SetTextTagLifespanBJ=1,texttag,real _SetTextTagLifespanBJ_Defaults=GetLastCreatedTextTag,5 _SetTextTagLifespanBJ_Category=TC_TEXTTAG SetTextTagFadepointBJ=1,texttag,real _SetTextTagFadepointBJ_Defaults=GetLastCreatedTextTag,4 _SetTextTagFadepointBJ_Category=TC_TEXTTAG DisplayTextToForce=0,force,StringExt _DisplayTextToForce_Defaults=GetPlayersAll,_ _DisplayTextToForce_Category=TC_GAME DisplayTextToPlayer=0,player,real,real,StringExt _DisplayTextToPlayer_Defaults=Player00,0,0,_ _DisplayTextToPlayer_Category=TC_GAME DisplayTimedTextToForce=0,force,real,StringExt _DisplayTimedTextToForce_Defaults=GetPlayersAll,30,_ _DisplayTimedTextToForce_Limits=_,_,0,_,_,_ _DisplayTimedTextToForce_Category=TC_GAME DisplayTimedTextToPlayer=0,player,real,real,real,StringExt _DisplayTimedTextToPlayer_Defaults=Player00,0,0,30,_ _DisplayTimedTextToPlayer_Limits=_,_,_,_,_,_,0,_,_,_ _DisplayTimedTextToPlayer_Category=TC_GAME PauseGameOn=0,nothing _PauseGameOn_Defaults= _PauseGameOn_Category=TC_GAME PauseGameOff=0,nothing _PauseGameOff_Defaults= _PauseGameOff_Category=TC_GAME SetGameSpeed=0,gamespeed _SetGameSpeed_Defaults=GameSpeedNormal _SetGameSpeed_Category=TC_GAME LockGameSpeedBJ=0,nothing _LockGameSpeedBJ_Defaults= _LockGameSpeedBJ_Category=TC_GAME UnlockGameSpeedBJ=0,nothing _UnlockGameSpeedBJ_Defaults= _UnlockGameSpeedBJ_Category=TC_GAME SetMapFlag=0,mapflag,onoffoption _SetMapFlag_Defaults=MapFlagUseHandicaps,OnOffOn _SetMapFlag_Category=TC_GAME SetTimeOfDay=0,real _SetTimeOfDay_Defaults=12 _SetTimeOfDay_Limits=0,24 _SetTimeOfDay_Category=TC_GAME SetTimeOfDayScalePercentBJ=0,real _SetTimeOfDayScalePercentBJ_Defaults=100 _SetTimeOfDayScalePercentBJ_Defaults=0,_ _SetTimeOfDayScalePercentBJ_Category=TC_GAME UseTimeOfDayBJ=0,onoffoption _UseTimeOfDayBJ_Defaults=OnOffOff _UseTimeOfDayBJ_Category=TC_GAME ShareEverythingWithTeam=0,player _ShareEverythingWithTeam_Defaults=Player00 _ShareEverythingWithTeam_Category=TC_GAME MakeUnitsPassiveForPlayer=0,player _MakeUnitsPassiveForPlayer_Defaults=Player00 _MakeUnitsPassiveForPlayer_Category=TC_GAME SetNextLevelBJ=0,string _SetNextLevelBJ_Defaults="Maps\MapName.w3m" _SetNextLevelBJ_Category=TC_GAME CustomVictoryBJ=0,player,useskipoption,useskipoption _CustomVictoryBJ_Defaults=Player00,UseSkipOptionUse,UseSkipOptionUse _CustomVictoryBJ_Category=TC_GAME CustomDefeatBJ=0,player,StringExt _CustomDefeatBJ_Defaults=Player00,WESTRING_PEVENT_DEFEAT_MSG _CustomDefeatBJ_Category=TC_GAME LoadGameBJ=1,anyfile,useskipoption _LoadGameBJ_Defaults="LoadFile.w3z",UseSkipOptionSkip _LoadGameBJ_Category=TC_GAME SaveAndLoadGameBJ=1,anyfile,anyfile,useskipoption _SaveAndLoadGameBJ_Defaults="SaveFile.w3z","LoadFile.w3z",UseSkipOptionSkip _SaveAndLoadGameBJ_Category=TC_GAME SaveAndChangeLevelBJ=1,anyfile,anyfile,useskipoption _SaveAndChangeLevelBJ_Defaults="SaveFile.w3z","Maps\MapName.w3x",UseSkipOptionSkip _SaveAndChangeLevelBJ_Category=TC_GAME RenameSaveDirectoryBJ=1,anyfile,anyfile _RenameSaveDirectoryBJ_Defaults=_,_ _RenameSaveDirectoryBJ_Category=TC_GAME RemoveSaveDirectoryBJ=1,anyfile _RemoveSaveDirectoryBJ_Defaults=_ _RemoveSaveDirectoryBJ_Category=TC_GAME CopySaveGameBJ=1,anyfile,anyfile _CopySaveGameBJ_Defaults=_,_ _CopySaveGameBJ_Category=TC_GAME SetCampaignMenuRaceBJ=0,campaignindex _SetCampaignMenuRaceBJ_Defaults=CampaignIndexH _SetCampaignMenuRaceBJ_Category=TC_GAME SetMissionAvailableBJ=0,enabledisableoption,missionindex _SetMissionAvailableBJ_Defaults=EnableDisableEnable,MissionIndexH01 _SetMissionAvailableBJ_Category=TC_GAME SetCampaignAvailableBJ=0,enabledisableoption,campaignindex _SetCampaignAvailableBJ_Defaults=EnableDisableEnable,CampaignIndexH _SetCampaignAvailableBJ_Category=TC_GAME SetCinematicAvailableBJ=0,enabledisableoption,cinematicindex _SetCinematicAvailableBJ_Defaults=EnableDisableEnable,CinematicIndexHED _SetCinematicAvailableBJ_Category=TC_GAME ShowCustomCampaignButton=1,showhideoption,integer _ShowCustomCampaignButton_Defaults=ShowHideShow,1 _ShowCustomCampaignButton_Limits=_,_,1,_ _ShowCustomCampaignButton_Category=TC_GAME SetAllyColorFilterState=1,integer _SetAllyColorFilterState_Defaults=0 _SetAllyColorFilterState_Limits=0,2 _SetAllyColorFilterState_Category=TC_GAME SetCreepCampFilterState=1,showhideoption _SetCreepCampFilterState_Defaults=ShowHideHide _SetCreepCampFilterState_Category=TC_GAME EnableMinimapFilterButtons=1,enabledisableoption,enabledisableoption _EnableMinimapFilterButtons_Defaults=EnableDisableDisable,EnableDisableDisable _EnableMinimapFilterButtons_Category=TC_GAME EnableDragSelect=0,enabledisableoption,enabledisableoption _EnableDragSelect_Defaults=EnableDisableEnable,EnableDisableEnable _EnableDragSelect_Category=TC_GAME EnablePreSelect=0,enabledisableoption,enabledisableoption _EnablePreSelect_Defaults=EnableDisableEnable,EnableDisableEnable _EnablePreSelect_Category=TC_GAME EnableSelect=0,enabledisableoption,enabledisableoption _EnableSelect_Defaults=EnableDisableEnable,EnableDisableEnable _EnableSelect_Category=TC_GAME ForceUIKeyBJ=0,player,string _ForceUIKeyBJ_Defaults=Player00,"A" _ForceUIKeyBJ_Category=TC_GAME ForceUICancelBJ=0,player _ForceUICancelBJ_Defaults=Player00 _ForceUICancelBJ_Category=TC_GAME Preload=0,anyfile _Preload_Defaults=_ _Preload_Category=TC_GAME PreloadEnd=0,real _PreloadEnd_Defaults=0.5 _PreloadEnd_Category=TC_GAME Preloader=0,preloadfile _Preloader_Defaults= _Preloader_Category=TC_GAME EndGame=1,useskipoption _EndGame_Defaults=UseSkipOptionSkip _EndGame_Category=TC_GAME ChangeLevel=1,string,useskipoption _ChangeLevel_Defaults="Maps\MyMap.w3m",UseSkipOptionSkip _ChangeLevel_Category=TC_GAME RestartGame=1,useskipoption _RestartGame_Defaults=UseSkipOptionSkip _RestartGame_Category=TC_GAME DisableRestartMission=1,boolean _DisableRestartMission_Defaults=true _DisableRestartMission_Category=TC_GAME DoNotSaveReplay=1,nothing _DoNotSaveReplay_Defaults= _DoNotSaveReplay_Category=TC_GAME EnableUserUI=0,enabledisableoption _EnableUserUI_Defaults=EnableDisableEnable _EnableUserUI_Category=TC_GAME SetIntegerGameState=0,igamestate,integer _SetIntegerGameState_Defaults=IGamestateDivineIntervention,1 _SetIntegerGameState_Category=TC_GAME InitGameCacheBJ=0,string _InitGameCacheBJ_Defaults="MapName.w3v" _InitGameCacheBJ_Category=TC_GAMECACHE SaveGameCacheBJ=0,gamecache _SaveGameCacheBJ_Defaults=GetLastCreatedGameCacheBJ _SaveGameCacheBJ_Category=TC_GAMECACHE StoreUnitBJ=0,unit,string,string,gamecache _StoreUnitBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreUnitBJ_Category=TC_GAMECACHE StoreRealBJ=0,real,string,string,gamecache _StoreRealBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreRealBJ_Category=TC_GAMECACHE StoreIntegerBJ=0,integer,string,string,gamecache _StoreIntegerBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreIntegerBJ_Category=TC_GAMECACHE StoreBooleanBJ=0,boolean,string,string,gamecache _StoreBooleanBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreBooleanBJ_Category=TC_GAMECACHE StoreStringBJ=1,string,string,string,gamecache _StoreStringBJ_Defaults=_,_,"Category",GetLastCreatedGameCacheBJ _StoreStringBJ_Category=TC_GAMECACHE RestoreUnitLocFacingAngleBJ=0,string,string,gamecache,player,location,real _RestoreUnitLocFacingAngleBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ,Player00,GetRectCenter,0 _RestoreUnitLocFacingAngleBJ_Category=TC_GAMECACHE RestoreUnitLocFacingPointBJ=0,string,string,gamecache,player,location,location _RestoreUnitLocFacingPointBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ,Player00,GetRectCenter,GetUnitLoc _RestoreUnitLocFacingPointBJ_Category=TC_GAMECACHE ReloadGameCachesFromDisk=1,nothing _ReloadGameCachesFromDisk_Defaults= _ReloadGameCachesFromDisk_Category=TC_GAMECACHE FlushGameCacheBJ=1,gamecache _FlushGameCacheBJ_Defaults=GetLastCreatedGameCacheBJ _FlushGameCacheBJ_Category=TC_GAMECACHE FlushStoredMissionBJ=1,string,gamecache _FlushStoredMissionBJ_Defaults="Category",GetLastCreatedGameCacheBJ _FlushStoredMissionBJ_Category=TC_GAMECACHE FlushStoredInteger=1,gamecache,string,string _FlushStoredInteger_Defaults=_,_,_ _FlushStoredInteger_Category=TC_GAMECACHE FlushStoredBoolean=1,gamecache,string,string _FlushStoredBoolean_Defaults=_,_,_ _FlushStoredBoolean_Category=TC_GAMECACHE FlushStoredReal=1,gamecache,string,string _FlushStoredReal_Defaults=_,_,_ _FlushStoredReal_Category=TC_GAMECACHE FlushStoredUnit=1,gamecache,string,string _FlushStoredUnit_Defaults=_,_,_ _FlushStoredUnit_Category=TC_GAMECACHE FlushStoredString=1,gamecache,string,string _FlushStoredString_Defaults=_,_,_ _FlushStoredString_Category=TC_GAMECACHE SelectHeroSkill=0,unit,heroskillcode _SelectHeroSkill_Defaults=GetTriggerUnit,HeroSkillBlizzard _SelectHeroSkill_Category=TC_HERO SelectHeroSkill2=0,unit,abilcode _SelectHeroSkill2_Defaults=GetTriggerUnit,_ _SelectHeroSkill2_ScriptName=SelectHeroSkill _SelectHeroSkill2_Category=TC_HERO SetHeroLevel=0,unit,integer,showhideoption _SetHeroLevel_Defaults=GetTriggerUnit,2,ShowHideHide _SetHeroLevel_Limits=_,_,1,_,_,_ _SetHeroLevel_Category=TC_HERO _SetHeroLevel_ScriptName=SetHeroLevelBJ SetHeroXP=0,unit,integer,showhideoption _SetHeroXP_Defaults=GetTriggerUnit,4000,ShowHideHide _SetHeroXP_Limits=_,_,0,_,_,_ _SetHeroXP_Category=TC_HERO AddHeroXPSwapped=0,integer,unit,showhideoption _AddHeroXPSwapped_Defaults=1000,GetTriggerUnit,ShowHideHide _AddHeroXPSwapped_Category=TC_HERO SuspendHeroXPBJ=0,enabledisableoption,unit _SuspendHeroXPBJ_Defaults=EnableDisableDisable,GetTriggerUnit _SuspendHeroXPBJ_Category=TC_HERO SetPlayerHandicapXPBJ=0,player,real _SetPlayerHandicapXPBJ_Defaults=Player00,100 _SetPlayerHandicapXPBJ_Limits=_,_,0,_ _SetPlayerHandicapXPBJ_Category=TC_HERO ReviveHeroLoc=0,unit,location,showhideoption _ReviveHeroLoc_Defaults=_,GetRectCenter,ShowHideHide _ReviveHeroLoc_Category=TC_HERO ModifyHeroStat=1,herostat,unit,modifymethod,integer _ModifyHeroStat_Defaults=HeroStatStr,_,ModifyMethodAdd,10 _ModifyHeroStat_Category=TC_HERO SetHeroAgi=0,unit,integer,permanentoption _SetHeroAgi_Defaults=GetTriggerUnit,0,PermanentPerm _SetHeroAgi_Category=TC_HERO SetHeroInt=0,unit,integer,permanentoption _SetHeroInt_Defaults=GetTriggerUnit,0,PermanentPerm _SetHeroInt_Category=TC_HERO SetHeroStr=0,unit,integer,permanentoption _SetHeroStr_Defaults=GetTriggerUnit,0,PermanentPerm _SetHeroStr_Category=TC_HERO ModifyHeroSkillPoints=1,unit,modifymethod,integer _ModifyHeroSkillPoints_Defaults=_,ModifyMethodAdd,1 _ModifyHeroSkillPoints_Category=TC_HERO SetReservedLocalHeroButtons=1,integer _SetReservedLocalHeroButtons_Defaults=3 _SetReservedLocalHeroButtons_Limits=0,6 _SetReservedLocalHeroButtons_Category=TC_HERO UnitAddItemSwapped=0,item,unit _UnitAddItemSwapped_Defaults=GetLastCreatedItem,GetTriggerUnit _UnitAddItemSwapped_Category=TC_HERO UnitAddItemByIdSwapped=0,itemcode,unit _UnitAddItemByIdSwapped_Defaults=texp,GetTriggerUnit _UnitAddItemByIdSwapped_Category=TC_HERO UnitRemoveItemSwapped=0,item,unit _UnitRemoveItemSwapped_Defaults=_,_ _UnitRemoveItemSwapped_Category=TC_HERO UnitRemoveItemFromSlotSwapped=0,integer,unit _UnitRemoveItemFromSlotSwapped_Defaults=1,_ _UnitRemoveItemFromSlotSwapped_Limits=1,6,_,_ _UnitRemoveItemFromSlotSwapped_Category=TC_HERO UnitUseItemTarget=0,unit,item,unit _UnitUseItemTarget_Defaults=_,GetLastCreatedItem,_ _UnitUseItemTarget_Category=TC_HERO UnitUseItemPointLoc=0,unit,item,location _UnitUseItemPointLoc_Defaults=_,GetLastCreatedItem,GetRectCenter _UnitUseItemPointLoc_Category=TC_HERO UnitUseItemDestructable=0,unit,item,destructable _UnitUseItemDestructable_Defaults=_,GetLastCreatedItem,_ _UnitUseItemDestructable_Category=TC_HERO UnitUseItem=0,unit,item _UnitUseItem_Defaults=_,GetLastCreatedItem _UnitUseItem_Category=TC_HERO IssueInstantTargetOrder=1,unit,unitorderinstant,unit,item _IssueInstantTargetOrder_Defaults=GetTriggerUnit,InstantOrderGive,GetLastCreatedUnit,UnitItemInSlotBJ _IssueInstantTargetOrder_Category=TC_HERO CreateItemLoc=0,itemcode,location _CreateItemLoc_Defaults=texp,GetRectCenter _CreateItemLoc_Category=TC_ITEM RemoveItem=0,item _RemoveItem_Defaults=GetLastCreatedItem _RemoveItem_Category=TC_ITEM SetItemVisibleBJ=1,showhideoption,item _SetItemVisibleBJ_Defaults=ShowHideHide,GetLastCreatedItem _SetItemVisibleBJ_Category=TC_ITEM SetItemPositionLoc=0,item,location _SetItemPositionLoc_Defaults=GetLastCreatedItem,GetRectCenter _SetItemPositionLoc_Category=TC_ITEM SetItemLifeBJ=0,item,real _SetItemLifeBJ_Defaults=GetLastCreatedItem,50 _SetItemLifeBJ_Limits=_,_,0,_ _SetItemLifeBJ_Category=TC_ITEM SetItemCharges=1,item,integer _SetItemCharges_Defaults=GetLastCreatedItem,1 _SetItemCharges_Limits=_,_,0,_ _SetItemCharges_Category=TC_ITEM SetItemInvulnerableBJ=0,item,invulnerableoption _SetItemInvulnerableBJ_Defaults=GetLastCreatedItem,InvulnerabilityInvulnerable _SetItemInvulnerableBJ_Category=TC_ITEM SetItemPawnable=1,item,pawnableoption _SetItemPawnable_Defaults=GetLastCreatedItem,PawnableOptionPawnable _SetItemPawnable_Category=TC_ITEM SetItemDroppableBJ=0,item,dropnodropoption _SetItemDroppableBJ_Defaults=GetLastCreatedItem,DropNoDropOptionNoDrop _SetItemDroppableBJ_Category=TC_ITEM SetItemDropOnDeathBJ=0,item,droppableoption _SetItemDropOnDeathBJ_Defaults=GetLastCreatedItem,DroppableOptionDrop _SetItemDropOnDeathBJ_Category=TC_ITEM SetItemPlayerBJ=0,item,player,colorchangeoption _SetItemPlayerBJ_Defaults=GetLastCreatedItem,Player00,ChangeColorTrue _SetItemPlayerBJ_Category=TC_ITEM SetItemUserData=1,item,integer _SetItemUserData_Defaults=_,0 _SetItemUserData_Category=TC_ITEM EnumItemsInRectBJMultiple=1,rect _EnumItemsInRectBJMultiple_Defaults=GetPlayableMapRect _EnumItemsInRectBJMultiple_Category=TC_ITEM _EnumItemsInRectBJMultiple_ScriptName=EnumItemsInRectBJ EnumItemsInRectBJ=1,rect,code _EnumItemsInRectBJ_Defaults=GetPlayableMapRect,DoNothing _EnumItemsInRectBJ_Category=TC_ITEM RandomDistAddItem=1,integer,integer _RandomDistAddItem_Defaults=_,_ _RandomDistAddItem_Category=TC_ITEM RandomDistReset=1,nothing _RandomDistReset_Defaults= _RandomDistReset_Category=TC_ITEM CreateLeaderboardBJ=0,force,StringExt _CreateLeaderboardBJ_Defaults=GetPlayersAll,_ _CreateLeaderboardBJ_Category=TC_LEADERBOARD DestroyLeaderboardBJ=0,leaderboard _DestroyLeaderboardBJ_Defaults=GetLastCreatedLeaderboard _DestroyLeaderboardBJ_Category=TC_LEADERBOARD LeaderboardSortItemsBJ=0,leaderboard,leaderboardsortoption,ascendingoption _LeaderboardSortItemsBJ_Defaults=GetLastCreatedLeaderboard,LeaderboardSortByValue,AscendingOptionDescending _LeaderboardSortItemsBJ_Category=TC_LEADERBOARD LeaderboardDisplayBJ=0,showhideoption,leaderboard _LeaderboardDisplayBJ_Defaults=ShowHideHide,GetLastCreatedLeaderboard _LeaderboardDisplayBJ_Category=TC_LEADERBOARD LeaderboardSetLabelBJ=0,leaderboard,StringExt _LeaderboardSetLabelBJ_Defaults=GetLastCreatedLeaderboard,_ _LeaderboardSetLabelBJ_Category=TC_LEADERBOARD LeaderboardSetLabelColorBJ=0,leaderboard,real,real,real,real _LeaderboardSetLabelColorBJ_Defaults=GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetLabelColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _LeaderboardSetLabelColorBJ_Category=TC_LEADERBOARD LeaderboardSetValueColorBJ=0,leaderboard,real,real,real,real _LeaderboardSetValueColorBJ_Defaults=GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetValueColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _LeaderboardSetValueColorBJ_Category=TC_LEADERBOARD LeaderboardSetStyleBJ=0,leaderboard,showhideoption,showhideoption,showhideoption,showhideoption _LeaderboardSetStyleBJ_Defaults=GetLastCreatedLeaderboard,ShowHideShow,ShowHideShow,ShowHideShow,ShowHideShow _LeaderboardSetStyleBJ_Category=TC_LEADERBOARD LeaderboardAddItemBJ=0,player,leaderboard,StringExt,integer _LeaderboardAddItemBJ_Defaults=Player00,GetLastCreatedLeaderboard,_,0 _LeaderboardAddItemBJ_Category=TC_LEADERBOARD LeaderboardRemovePlayerItemBJ=0,player,leaderboard _LeaderboardRemovePlayerItemBJ_Defaults=Player00,GetLastCreatedLeaderboard _LeaderboardRemovePlayerItemBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemLabelBJ=0,player,leaderboard,StringExt _LeaderboardSetPlayerItemLabelBJ_Defaults=Player00,GetLastCreatedLeaderboard,_ _LeaderboardSetPlayerItemLabelBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemLabelColorBJ=0,player,leaderboard,real,real,real,real _LeaderboardSetPlayerItemLabelColorBJ_Defaults=Player00,GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetPlayerItemLabelColorBJ_Limits=_,_,_,_,0,100,0,100,0,100,0,100 _LeaderboardSetPlayerItemLabelColorBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemValueBJ=0,player,leaderboard,integer _LeaderboardSetPlayerItemValueBJ_Defaults=Player00,GetLastCreatedLeaderboard,0 _LeaderboardSetPlayerItemValueBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemValueColorBJ=0,player,leaderboard,real,real,real,real _LeaderboardSetPlayerItemValueColorBJ_Defaults=Player00,GetLastCreatedLeaderboard,100,80,20,0 _LeaderboardSetPlayerItemValueColorBJ_Limits=_,_,_,_,0,100,0,100,0,100,0,100 _LeaderboardSetPlayerItemValueColorBJ_Category=TC_LEADERBOARD LeaderboardSetPlayerItemStyleBJ=0,player,leaderboard,showhideoption,showhideoption,showhideoption _LeaderboardSetPlayerItemStyleBJ_Defaults=Player00,GetLastCreatedLeaderboard,ShowHideShow,ShowHideShow,ShowHideShow _LeaderboardSetPlayerItemStyleBJ_Category=TC_LEADERBOARD MoveLocation=0,location,real,real _MoveLocation_Defaults=_,GetLocationX,GetLocationY _MoveLocation_Category=TC_LOCATION RemoveLocation=0,location _RemoveLocation_Default=_ _RemoveLocation_Category=TC_LOCATION MeleeStartingVisibility=0,nothing _MeleeStartingVisibility_Defaults= _MeleeStartingVisibility_Category=TC_MELEE MeleeStartingHeroLimit=0,nothing _MeleeStartingHeroLimit_Defaults= _MeleeStartingHeroLimit_Category=TC_MELEE MeleeGrantHeroItems=0,nothing _MeleeGrantHeroItems_Defaults= _MeleeGrantHeroItems_Category=TC_MELEE MeleeStartingResources=0,nothing _MeleeStartingResources_Defaults= _MeleeStartingResources_Category=TC_MELEE MeleeClearExcessUnits=0,nothing _MeleeClearExcessUnits_Defaults= _MeleeClearExcessUnits_Category=TC_MELEE MeleeStartingUnits=0,nothing _MeleeStartingUnits_Defaults= _MeleeStartingUnits_Category=TC_MELEE MeleeStartingAI=0,nothing _MeleeStartingAI_Defaults= _MeleeStartingAI_Category=TC_MELEE MeleeInitVictoryDefeat=0,nothing _MeleeInitVictoryDefeat_Defaults= _MeleeInitVictoryDefeat_Category=TC_MELEE MeleeStartingUnitsForPlayer=1,race,player,location,includeoption _MeleeStartingUnitsForPlayer_Defaults=RaceHuman,Player00,GetPlayerStartLocationLoc,InclusionInclude _MeleeStartingUnitsForPlayer_Category=TC_MELEE CreateMultiboardBJ=1,integer,integer,StringExt _CreateMultiboardBJ_Defaults=1,1,_ _CreateMultiboardBJ_Limits=1,_,1,_,_,512 _CreateMultiboardBJ_Category=TC_MULTIBOARD DestroyMultiboardBJ=1,multiboard _DestroyMultiboardBJ_Defaults=GetLastCreatedMultiboard _DestroyMultiboardBJ_Category=TC_MULTIBOARD _DestroyMultiboardBJ_ScriptName=DestroyMultiboard MultiboardDisplayBJ=1,showhideoption,multiboard _MultiboardDisplayBJ_Defaults=ShowHideHide,GetLastCreatedMultiboard _MultiboardDisplayBJ_Category=TC_MULTIBOARD MultiboardAllowDisplayBJ=1,showhideoption _MultiboardAllowDisplayBJ_Defaults=ShowHideHide _MultiboardAllowDisplayBJ_Category=TC_MULTIBOARD MultiboardMinimizeBJ=1,minimizeoption,multiboard _MultiboardMinimizeBJ_Defaults=Minimize,GetLastCreatedMultiboard _MultiboardMinimizeBJ_Category=TC_MULTIBOARD MultiboardClear=1,multiboard _MultiboardClear_Defaults=GetLastCreatedMultiboard _MultiboardClear_Category=TC_MULTIBOARD MultiboardSetTitleText=1,multiboard,StringExt _MultiboardSetTitleText_Defaults=GetLastCreatedMultiboard,_ _MultiboardSetTitleText_Limits=_,_,_,512 _MultiboardSetTitleText_Category=TC_MULTIBOARD MultiboardSetTitleTextColorBJ=1,multiboard,real,real,real,real _MultiboardSetTitleTextColorBJ_Defaults=GetLastCreatedMultiboard,100,80,20,0 _MultiboardSetTitleTextColorBJ_Limits=_,_,0,100,0,100,0,100,0,100 _MultiboardSetTitleTextColorBJ_Category=TC_MULTIBOARD MultiboardSetRowCount=1,multiboard,integer _MultiboardSetRowCount_Defaults=GetLastCreatedMultiboard,1 _MultiboardSetRowCount_Limits=_,_,1,_ _MultiboardSetRowCount_Category=TC_MULTIBOARD MultiboardSetColumnCount=1,multiboard,integer _MultiboardSetColumnCount_Defaults=GetLastCreatedMultiboard,1 _MultiboardSetColumnCount_Limits=_,_,1,_ _MultiboardSetColumnCount_Category=TC_MULTIBOARD MultiboardSetItemStyleBJ=1,multiboard,integer,integer,showhideoption,showhideoption _MultiboardSetItemStyleBJ_Defaults=GetLastCreatedMultiboard,1,1,ShowHideShow,ShowHideShow _MultiboardSetItemStyleBJ_Limits=_,_,0,_,0,_,_,_,_,_ _MultiboardSetItemStyleBJ_Category=TC_MULTIBOARD MultiboardSetItemValueBJ=1,multiboard,integer,integer,StringExt _MultiboardSetItemValueBJ_Defaults=GetLastCreatedMultiboard,1,1,_ _MultiboardSetItemValueBJ_Limits=_,_,0,_,0,_,_,128 _MultiboardSetItemValueBJ_Category=TC_MULTIBOARD MultiboardSetItemColorBJ=1,multiboard,integer,integer,real,real,real,real _MultiboardSetItemColorBJ_Defaults=GetLastCreatedMultiboard,1,1,100,80,20,0 _MultiboardSetItemColorBJ_Limits=_,_,0,_,0,_,0,100,0,100,0,100,0,100 _MultiboardSetItemColorBJ_Category=TC_MULTIBOARD MultiboardSetItemWidthBJ=1,multiboard,integer,integer,real _MultiboardSetItemWidthBJ_Defaults=GetLastCreatedMultiboard,1,1,3 _MultiboardSetItemWidthBJ_Limits=_,_,0,_,0,_,0,100 _MultiboardSetItemWidthBJ_Category=TC_MULTIBOARD MultiboardSetItemIconBJ=1,multiboard,integer,integer,imagefile _MultiboardSetItemIconBJ_Defaults=GetLastCreatedMultiboard,1,1,"UI\Feedback\Resources\ResourceGold.blp" _MultiboardSetItemIconBJ_Limits=_,_,0,_,0,_,_,_ _MultiboardSetItemIconBJ_Category=TC_MULTIBOARD MultiboardSetItemsValueColor=1,multiboard,integer,integer,integer,integer _MultiboardSetItemsValueColor_Defaults=_,100,100,100,0 _MultiboardSetItemsValueColor_Category=TC_MULTIBOARD MultiboardSetItemValueColor=1,multiboarditem,integer,integer,integer,integer _MultiboardSetItemValueColor_Defaults=_,100,100,100,0 _MultiboardSetItemValueColor_Category=TC_MULTIBOARD AddResourceAmountBJ=0,integer,unit _AddResourceAmountBJ_Defaults=5000,_ _AddResourceAmountBJ_Category=TC_NEUTRALBUILDING SetResourceAmount=0,unit,integer _SetResourceAmount_Defaults=_,12500 _SetResourceAmount_Limits=_,_,0,_ _SetResourceAmount_Category=TC_NEUTRALBUILDING BlightGoldMineForPlayer=0,unit,player _BlightGoldMineForPlayer_Defaults=_,Player00 _BlightGoldMineForPlayer_Category=TC_NEUTRALBUILDING WaygateActivateBJ=0,enabledisableoption,unit _WaygateActivateBJ_Defaults=EnableDisableEnable,_ _WaygateActivateBJ_Category=TC_NEUTRALBUILDING WaygateSetDestinationLocBJ=0,unit,location _WaygateSetDestinationLocBJ_Defaults=_,GetRectCenter _WaygateSetDestinationLocBJ_Category=TC_NEUTRALBUILDING SetAltMinimapIcon=1,imagefile _SetAltMinimapIcon_Defaults="UI\Minimap\Minimap-Tower" _SetAltMinimapIcon_Category=TC_NEUTRALBUILDING UnitSetUsesAltIconBJ=1,onoffoption,unit _UnitSetUsesAltIconBJ_Defaults=OnOffOn,_ _UnitSetUsesAltIconBJ_Category=TC_NEUTRALBUILDING AddItemToStockBJ=1,itemcode,unit,integer,integer _AddItemToStockBJ_Defaults=texp,GetTriggerUnit,0,1 _AddItemToStockBJ_Category=TC_NEUTRALBUILDING AddItemToAllStock=1,itemcode,integer,integer _AddItemToAllStock_Defaults=texp,0,1 _AddItemToAllStock_Category=TC_NEUTRALBUILDING AddUnitToStockBJ=1,unitcode,unit,integer,integer _AddUnitToStockBJ_Defaults=hfoo,GetTriggerUnit,0,1 _AddUnitToStockBJ_Category=TC_NEUTRALBUILDING AddUnitToAllStock=1,unitcode,integer,integer _AddUnitToAllStock_Defaults=hfoo,0,1 _AddUnitToAllStock_Category=TC_NEUTRALBUILDING RemoveItemFromStockBJ=1,itemcode,unit _RemoveItemFromStockBJ_Defaults=texp,GetTriggerUnit _RemoveItemFromStockBJ_Category=TC_NEUTRALBUILDING RemoveItemFromAllStock=1,itemcode _RemoveItemFromAllStock_Defaults=texp _RemoveItemFromAllStock_Category=TC_NEUTRALBUILDING RemoveUnitFromStockBJ=1,unitcode,unit _RemoveUnitFromStockBJ_Defaults=hfoo,GetTriggerUnit _RemoveUnitFromStockBJ_Category=TC_NEUTRALBUILDING RemoveUnitFromAllStock=1,unitcode _RemoveUnitFromAllStock_Defaults=hfoo _RemoveUnitFromAllStock_Category=TC_NEUTRALBUILDING SetItemTypeSlots=1,unit,integer _SetItemTypeSlots_Defaults=GetTriggerUnit,6 _SetItemTypeSlots_Category=TC_NEUTRALBUILDING SetAllItemTypeSlots=1,integer _SetAllItemTypeSlots_Defaults=6 _SetAllItemTypeSlots_Category=TC_NEUTRALBUILDING SetUnitTypeSlots=1,unit,integer _SetUnitTypeSlots_Defaults=GetTriggerUnit,6 _SetUnitTypeSlots_Category=TC_NEUTRALBUILDING SetAllUnitTypeSlots=1,integer _SetAllUnitTypeSlots_Defaults=6 _SetAllUnitTypeSlots_Category=TC_NEUTRALBUILDING SetPlayerState=0,player,playerstate,integer _SetPlayerState_Defaults=Player00,PlayerStateGold,750 _SetPlayerState_Category=TC_PLAYER _SetPlayerState_ScriptName=SetPlayerStateBJ AdjustPlayerStateBJ=0,integer,player,playerstate _AdjustPlayerStateBJ_Defaults=1000,Player00,PlayerStateGold _AdjustPlayerStateBJ_Category=TC_PLAYER SetPlayerFlagBJ=0,playerflag,onoffoption,player _SetPlayerFlagBJ_Defaults=PlayerFlagGivesBounty,OnOffOff,PlayerNA _SetPlayerFlagBJ_Category=TC_PLAYER SetPlayerTaxRateBJ=1,integer,playerresource,player,player, _SetPlayerTaxRateBJ_Defaults=0,PlayerResourceGold,Player00,Player01 _SetPlayerTaxRateBJ_Limits=0,100,_,_,_,_,_,_ _SetPlayerTaxRateBJ_Category=TC_PLAYER EnableCreepSleepBJ=1,enabledisableoption _EnableCreepSleepBJ_Defaults=EnableDisableDisable _EnableCreepSleepBJ_Category=TC_PLAYER SetPlayerAllianceStateBJ=0,player,player,alliancesetting _SetPlayerAllianceStateBJ_Defaults=Player00,Player01,AllianceSettingAlliedVision _SetPlayerAllianceStateBJ_Category=TC_PLAYER SetPlayerAllianceBJ=0,player,alliancetype,onoffoption,player _SetPlayerAllianceBJ_Defaults=Player00,AllianceTypePassive,OnOffOn,Player01 _SetPlayerAllianceBJ_Category=TC_PLAYER SetPlayerAbilityAvailableBJ=0,enabledisableoption,abilcode,player _SetPlayerAbilityAvailableBJ_Defaults=EnableDisableDisable,_,Player00 _SetPlayerAbilityAvailableBJ_Category=TC_PLAYER SetPlayerUnitAvailableBJ=0,unitcode,availabilityoption,player _SetPlayerUnitAvailableBJ_Defaults=hfoo,AvailabilityOptionAvailable,Player00 _SetPlayerUnitAvailableBJ_Category=TC_PLAYER SetPlayerUnitMaxAllowed=1,unitcode,integer,player _SetPlayerUnitMaxAllowed_Defaults=hfoo,1,Player00 _SetPlayerUnitMaxAllowed_Limits=_,_,-1,_,_,_ _SetPlayerUnitMaxAllowed_Category=TC_PLAYER _SetPlayerUnitMaxAllowed_ScriptName=SetPlayerTechMaxAllowedSwap SetPlayerMaxHeroesAllowed=1,integer,player _SetPlayerMaxHeroesAllowed_Defaults=3,Player00 _SetPlayerMaxHeroesAllowed_Limits=-1,_,_,_ _SetPlayerMaxHeroesAllowed_Category=TC_PLAYER SetPlayerTechResearchedSwap=0,techcode,integer,player _SetPlayerTechResearchedSwap_Defaults=_,0,Player00 _SetPlayerTechResearchedSwap_Limits=_,_,0,_,_,_ _SetPlayerTechResearchedSwap_Category=TC_PLAYER SetPlayerTechMaxAllowedSwap=0,techcode,integer,player _SetPlayerTechMaxAllowedSwap_Defaults=_,0,Player00 _SetPlayerTechMaxAllowedSwap_Limits=_,_,0,_,_,_ _SetPlayerTechMaxAllowedSwap_Category=TC_PLAYER SetPlayerTechMaxAllowed=0,player,unitcode,integer _SetPlayerTechMaxAllowed_Defaults=Player00,hfoo,0 _SetPlayerTechMaxAllowed_Limits=_,_,_,_,0,_ _SetPlayerTechMaxAllowed_Category=TC_PLAYER SetPlayerColorBJ=0,player,playercolor,playerchangecoloroption _SetPlayerColorBJ_Defaults=Player00,Color00,PlayerChangeColorChange _SetPlayerColorBJ_Category=TC_PLAYER SetPlayerHandicapBJ=0,player,real _SetPlayerHandicapBJ_Defaults=Player00,100 _SetPlayerHandicapBJ_Limits=_,_,1,10000 _SetPlayerHandicapBJ_Category=TC_PLAYER SetPlayerOnScoreScreenBJ=0,showhideoption,player _SetPlayerOnScoreScreenBJ_Defaults=ShowHideHide,Player00 _SetPlayerOnScoreScreenBJ_Category=TC_PLAYER SetPlayerName=1,player,StringExt _SetPlayerName_Defaults=Player00,_ _SetPlayerName_Category=TC_PLAYER IssueNeutralImmediateOrderById=1,player,unit,unitcode _IssueNeutralImmediateOrderById_Defaults=Player00,_,nzep _IssueNeutralImmediateOrderById_Category=TC_PLAYER ForForceMultiple=1,force _ForForceMultiple_Defaults=GetPlayersAll _ForForceMultiple_Category=TC_PLAYERGROUP _ForForceMultiple_ScriptName=ForForce ForForce=0,force,code _ForForce_Defaults=GetPlayersAll,DoNothing _ForForce_Category=TC_PLAYERGROUP ForceAddPlayerSimple=0,player,force _ForceAddPlayerSimple_Defaults=Player00,_ _ForceAddPlayerSimple_Category=TC_PLAYERGROUP ForceRemovePlayerSimple=0,player,force _ForceRemovePlayerSimple_Defaults=Player00,_ _ForceRemovePlayerSimple_Category=TC_PLAYERGROUP ForceClear=0,force _ForceClear_Defaults=_ _ForceClear_Category=TC_PLAYERGROUP SetForceAllianceStateBJ=1,force,force,alliancesetting _SetForceAllianceStateBJ_Defaults=GetPlayersAll,GetPlayersAll,AllianceSettingAlliedVision _SetForceAllianceStateBJ_Category=TC_PLAYERGROUP QuestMessageBJ=0,force,questmessagetype,StringExt _QuestMessageBJ_Defaults=GetPlayersAll,QuestMessageTypeUpdated,_ _QuestMessageBJ_Category=TC_QUEST CreateQuestBJ=0,questtypeoption,StringExt,StringExt,imagefile _CreateQuestBJ_Defaults=QuestTypeReqDiscovered,_,_,"ReplaceableTextures\CommandButtons\BTNAmbush.blp" _CreateQuestBJ_Limits=_,_,_,24,_,_,_,_ _CreateQuestBJ_Category=TC_QUEST DestroyQuestBJ=0,quest _DestroyQuestBJ_Defaults=GetLastCreatedQuestBJ _DestroyQuestBJ_Category=TC_QUEST _DestroyQuestBJ_ScriptName=DestroyQuest QuestSetEnabledBJ=0,enabledisableoption,quest _QuestSetEnabledBJ_Defaults=EnableDisableDisable,GetLastCreatedQuestBJ _QuestSetEnabledBJ_Category=TC_QUEST QuestSetCompletedBJ=0,quest,completionoption _QuestSetCompletedBJ_Defaults=GetLastCreatedQuestBJ,CompletionOptionCompleted _QuestSetCompletedBJ_Category=TC_QUEST _QuestSetCompletedBJ_ScriptName=QuestSetCompleted QuestSetFailedBJ=0,quest,failureoption _QuestSetFailedBJ_Defaults=GetLastCreatedQuestBJ,FailureOptionFailed _QuestSetFailedBJ_Category=TC_QUEST _QuestSetFailedBJ_ScriptName=QuestSetFailed QuestSetDiscoveredBJ=0,quest,discoveredoption _QuestSetDiscoveredBJ_Defaults=GetLastCreatedQuestBJ,DiscoveredOptionDiscovered _QuestSetDiscoveredBJ_Category=TC_QUEST _QuestSetDiscoveredBJ_ScriptName=QuestSetDiscovered QuestSetTitleBJ=0,quest,StringExt _QuestSetTitleBJ_Defaults=GetLastCreatedQuestBJ,_ _QuestSetTitleBJ_Category=TC_QUEST _QuestSetTitleBJ_ScriptName=QuestSetTitle QuestSetDescriptionBJ=0,quest,StringExt _QuestSetDescriptionBJ_Defaults=GetLastCreatedQuestBJ,_ _QuestSetDescriptionBJ_Category=TC_QUEST _QuestSetDescriptionBJ_ScriptName=QuestSetDescription CreateQuestItemBJ=0,quest,StringExt _CreateQuestItemBJ_Defaults=GetLastCreatedQuestBJ,_ _CreateQuestItemBJ_Category=TC_QUEST QuestItemSetCompletedBJ=0,questitem,completionoption _QuestItemSetCompletedBJ_Defaults=GetLastCreatedQuestItemBJ,CompletionOptionCompleted _QuestItemSetCompletedBJ_Category=TC_QUEST _QuestItemSetCompletedBJ_ScriptName=QuestItemSetCompleted QuestItemSetDescriptionBJ=0,questitem,StringExt _QuestItemSetDescriptionBJ_Defaults=GetLastCreatedQuestItemBJ,_ _QuestItemSetDescriptionBJ_Category=TC_QUEST _QuestItemSetDescriptionBJ_ScriptName=QuestItemSetDescription CreateDefeatConditionBJ=0,StringExt _CreateDefeatConditionBJ_Defaults=_ _CreateDefeatConditionBJ_Category=TC_QUEST DestroyDefeatConditionBJ=0,defeatcondition _DestroyDefeatConditionBJ_Defaults=GetLastCreatedDefeatConditionBJ _DestroyDefeatConditionBJ_Category=TC_QUEST _DestroyDefeatConditionBJ_ScriptName=DestroyDefeatCondition DefeatConditionSetDescriptionBJ=0,defeatcondition,StringExt _DefeatConditionSetDescriptionBJ_Defaults=GetLastCreatedDefeatConditionBJ,_ _DefeatConditionSetDescriptionBJ_Category=TC_QUEST _DefeatConditionSetDescriptionBJ_ScriptName=DefeatConditionSetDescription FlashQuestDialogButtonBJ=0,nothing _FlashQuestDialogButtonBJ_Defaults= _FlashQuestDialogButtonBJ_Category=TC_QUEST _FlashQuestDialogButtonBJ_ScriptName=FlashQuestDialogButton MoveRectTo=0,rect,real,real _MoveRectTo_Defaults=_,GetLocationX,GetLocationY _MoveRectTo_Category=TC_REGION MoveRectToLoc=0,rect,location _MoveRectToLoc_Defaults=_,GetRectCenter _MoveRectToLoc_Category=TC_REGION RemoveRect=0,rect _RemoveRect_Defaults= _RemoveRect_Category=TC_REGION RegionAddCell=1,region,real,real _RegionAddCell_Defaults=_,_,_ _RegionAddCell_Category=TC_RECTANGLE RegionAddCellAtLoc=1,region,location _RegionAddCellAtLoc_Defaults=_,_ _RegionAddCellAtLoc_Category=TC_RECTANGLE RegionAddRect=1,region,rect _RegionAddRect_Defaults=_,_ _RegionAddRect_Category=TC_RECTANGLE RegionClearCell=1,region,real,real _RegionClearCell_Defaults=_,_,_ _RegionClearCell_Category=TC_RECTANGLE RegionClearCellAtLoc=1,region,location _RegionClearCellAtLoc_Defaults=_,_ _RegionClearCellAtLoc_Category=TC_RECTANGLE RegionClearRect=1,region,rect _RegionClearRect_Defaults=_,_ _RegionClearRect_Category=TC_RECTANGLE RemoveRegion=0,region _RemoveRegion_Defaults= _RemoveRegion_Category=TC_RECTANGLE ClearSelectionForPlayer=1,player _ClearSelectionForPlayer_Defaults=Player00 _ClearSelectionForPlayer_Category=TC_UNITSEL SelectGroupForPlayerBJ=1,group,player _SelectGroupForPlayerBJ_Defaults=_,Player00 _SelectGroupForPlayerBJ_Category=TC_UNITSEL SelectUnitForPlayerSingle=1,unit,player _SelectUnitForPlayerSingle_Defaults=GetTriggerUnit,Player00 _SelectUnitForPlayerSingle_Category=TC_UNITSEL SelectUnitAddForPlayer=1,unit,player _SelectUnitAddForPlayer_Defaults=GetTriggerUnit,Player00 _SelectUnitAddForPlayer_Category=TC_UNITSEL SelectUnitRemoveForPlayer=1,unit,player _SelectUnitRemoveForPlayer_Defaults=GetTriggerUnit,Player00 _SelectUnitRemoveForPlayer_Category=TC_UNITSEL ClearSelection=0,nothing _ClearSelection_Defaults= _ClearSelection_Category=TC_UNITSEL SelectGroupBJ=0,group _SelectGroupBJ_Defaults=_ _SelectGroupBJ_Category=TC_UNITSEL SelectUnitSingle=0,unit _SelectUnitSingle_Defaults=GetTriggerUnit _SelectUnitSingle_Category=TC_UNITSEL SelectUnitAdd=0,unit _SelectUnitAdd_Defaults=GetTriggerUnit _SelectUnitAdd_Category=TC_UNITSEL SelectUnitRemove=0,unit _SelectUnitRemove_Defaults=GetTriggerUnit _SelectUnitRemove_Category=TC_UNITSEL SyncSelections=0,nothing _SyncSelections_Defaults= _SyncSelections_Category=TC_UNITSEL PlaySoundBJ=0,sound _PlaySoundBJ_Defaults=_ _PlaySoundBJ_Category=TC_SOUND PlaySoundAtPointBJ=1,sound,real,location,real _PlaySoundAtPointBJ_Defaults=_,100,GetRectCenter,0 _PlaySoundAtPointBJ_Limits=_,_,0,100,_,_,_,_ _PlaySoundAtPointBJ_Category=TC_SOUND PlaySoundOnUnitBJ=1,sound,real,unit _PlaySoundOnUnitBJ_Defaults=_,100,_ _PlaySoundOnUnitBJ_Limits=_,_,0,100,_,_ _PlaySoundOnUnitBJ_Category=TC_SOUND PlaySoundFromOffsetBJ=1,sound,real,real _PlaySoundFromOffsetBJ_Defaults=_,100,0,0 _PlaySoundFromOffsetBJ_Limits=_,_,0,100,0,_,0,_ _PlaySoundFromOffsetBJ_Category=TC_SOUND StopSoundBJ=0,sound,fadedontoption _StopSoundBJ_Defaults=_,FadeDontFade _StopSoundBJ_Category=TC_SOUND KillSoundWhenDoneBJ=0,sound _KillSoundWhenDoneBJ_Defaults=_ _KillSoundWhenDoneBJ_Category=TC_SOUND SetSoundVolumeBJ=0,sound,real _SetSoundVolumeBJ_Defaults=_,100 _SetSoundVolumeBJ_Limits=_,_,0,100 _SetSoundVolumeBJ_Category=TC_SOUND SetSoundOffsetBJ=1,real,sound _SetSoundOffsetBJ_Defaults=0,_ _SetSoundOffsetBJ_Limits=0,_,_,_ _SetSoundOffsetBJ_Category=TC_SOUND SetSoundDistanceCutoffBJ=0,sound,real _SetSoundDistanceCutoffBJ_Defaults=_,_ _SetSoundDistanceCutoffBJ_Category=TC_SOUND SetSoundPitchBJ=0,sound,real _SetSoundPitchBJ_Defaults=_,_ _SetSoundPitchBJ_Category=TC_SOUND AttachSoundToUnitBJ=0,sound,unit _AttachSoundToUnitBJ_Defaults=_,_ _AttachSoundToUnitBJ_Category=TC_SOUND SetSoundPositionLocBJ=0,sound,location,real _SetSoundPositionLocBJ_Defaults=_,GetRectCenter,0 _SetSoundPositionLocBJ_Category=TC_SOUND SetSoundDistances=0,sound,real,real _SetSoundDistances_Defaults=_,_,_ _SetSoundDistances_Limits=_,_,0,_,0,_ _SetSoundDistances_Category=TC_SOUND SetStackedSoundBJ=0,addremoveoption,sound,rect _SetStackedSoundBJ_Defaults=AddRemoveAdd,_,_ _SetStackedSoundBJ_Category=TC_SOUND SetAmbientDaySound=0,ambientthemeday _SetAmbientDaySound_Defaults=AmbientThemeDayL _SetAmbientDaySound_Category=TC_SOUND SetAmbientNightSound=0,ambientthemenight _SetAmbientNightSound_Defaults=AmbientThemeNightL _SetAmbientNightSound_Category=TC_SOUND EnableDawnDusk=0,enabledisableoption _EnableDawnDusk_Defaults=EnableDisableEnable _EnableDawnDusk_Category=TC_SOUND SetMapMusicIndexedBJ=0,musicfile,integer _SetMapMusicIndexedBJ_Defaults=MusicFileMusic,0 _SetMapMusicIndexedBJ_Category=TC_SOUND SetMapMusicRandomBJ=0,musicfile _SetMapMusicRandomBJ_Defaults=MusicFileMusic _SetMapMusicRandomBJ_Category=TC_SOUND ClearMapMusicBJ=0,nothing _ClearMapMusicBJ_Defaults= _ClearMapMusicBJ_Category=TC_SOUND PlayMusicBJ=0,musicfile _PlayMusicBJ_Defaults=_ _PlayMusicBJ_Category=TC_SOUND PlayMusicExBJ=1,musicfile,real,real _PlayMusicExBJ_Defaults=_,0,0 _PlayMusicExBJ_Limits=_,_,0,_,0,_ _PlayMusicExBJ_Category=TC_SOUND PlayThematicMusicBJ=0,musictheme _PlayThematicMusicBJ_Defaults=MusicThemeHeroicVictory _PlayThematicMusicBJ_Category=TC_SOUND PlayThematicMusicExBJ=1,musictheme,real _PlayThematicMusicExBJ_Defaults=MusicThemeHeroicVictory,0 _PlayThematicMusicExBJ_Limits=_,_,0,_ _PlayThematicMusicExBJ_Category=TC_SOUND EndThematicMusicBJ=0,nothing _EndThematicMusicBJ_Defaults= _EndThematicMusicBJ_Category=TC_SOUND StopMusicBJ=0,fadedontoption _StopMusicBJ_Defaults=FadeDontFade _StopMusicBJ_Category=TC_SOUND ResumeMusicBJ=0,nothing _ResumeMusicBJ_Defaults= _ResumeMusicBJ_Category=TC_SOUND SetMusicVolumeBJ=0,real _SetMusicVolumeBJ_Defaults=100 _SetMusicVolumeBJ_Limits=0,100 _SetMusicVolumeBJ_Category=TC_SOUND SetMusicOffsetBJ=1,real _SetMusicOffsetBJ_Defaults=0 _SetMusicOffsetBJ_Limits=0,_ _SetMusicOffsetBJ_Category=TC_SOUND SetThematicMusicOffsetBJ=1,real _SetThematicMusicOffsetBJ_Defaults=0 _SetThematicMusicOffsetBJ_Limits=0,_ _SetThematicMusicOffsetBJ_Category=TC_SOUND VolumeGroupSetVolumeBJ=0,volumegroup,real _VolumeGroupSetVolumeBJ_Defaults=VolumeGroupMusic,100 _VolumeGroupSetVolumeBJ_Limits=_,_,0,100 _VolumeGroupSetVolumeBJ_Category=TC_SOUND SetCineModeVolumeGroupsBJ=0,nothing _SetCineModeVolumeGroupsBJ_Defaults= _SetCineModeVolumeGroupsBJ_Category=TC_SOUND SetSpeechVolumeGroupsBJ=0,nothing _SetSpeechVolumeGroupsBJ_Defaults= _SetSpeechVolumeGroupsBJ_Category=TC_SOUND VolumeGroupResetBJ=0,nothing _VolumeGroupResetBJ_Defaults= _VolumeGroupResetBJ_Category=TC_SOUND AddSpecialEffectLocBJ=0,location,modelfile _AddSpecialEffectLocBJ_Defaults=GetRectCenter,"Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl" _AddSpecialEffectLocBJ_Category=TC_SPECIALEFFECT AddSpecialEffectTargetUnitBJ=0,string,unit,modelfile _AddSpecialEffectTargetUnitBJ_Defaults="overhead",GetTriggerUnit,"Abilities\Spells\Other\TalkToMe\TalkToMe.mdl" _AddSpecialEffectTargetUnitBJ_Category=TC_SPECIALEFFECT DestroyEffectBJ=0,effect _DestroyEffectBJ_Defaults=GetLastCreatedEffectBJ _DestroyEffectBJ_Category=TC_SPECIALEFFECT AddLightningLoc=0,lightningtype,location,location _AddLightningLoc_Defaults=_ _AddLightningLoc_Category=TC_LIGHTNING AddLightningEx=0,lightningtype,boolean,real,real,real,real,real,real _AddLightningEx_Defaults=LightningTypeCLPB,true,_ _AddLightningEx_Category=TC_LIGHTNING DestroyLightningBJ=0,lightning _DestroyLightningBJ_Defaults=GetLastCreatedLightningBJ _DestroyLightningBJ_Category=TC_LIGHTNING _DestroyLightningBJ_ScriptName=DestroyLightning MoveLightningLoc=0,lightning,location,location _MoveLightningLoc_Defaults=_ _MoveLightningLoc_Category=TC_LIGHTNING MoveLightningEx=0,lightning,boolean,real,real,real,real,real,real _MoveLightningEx_Defaults=_ _MoveLightningEx_Category=TC_LIGHTNING SetLightningColorBJ=0,lightning,real,real,real,real _SetLightningColorBJ_Defaults=_,1,1,1,1 _SetLightningColorBJ_Category=TC_LIGHTNING DestroyTrigger=0,trigger _DestroyTrigger_Defaults=GetTriggeringTrigger _DestroyTrigger_Category=TC_TRIGGER DisableTrigger=0,trigger _DisableTrigger_Defaults=GetTriggeringTrigger _DisableTrigger_Category=TC_TRIGGER EnableTrigger=0,trigger _EnableTrigger_Defaults=GetTriggeringTrigger _EnableTrigger_Category=TC_TRIGGER ConditionalTriggerExecute=0,trigger _ConditionalTriggerExecute_Defaults=_ _ConditionalTriggerExecute_Category=TC_TRIGGER TriggerExecute=0,trigger _TriggerExecute_Defaults=_ _TriggerExecute_Category=TC_TRIGGER QueuedTriggerAddBJ=0,trigger,checkingignoringoption _QueuedTriggerAddBJ_Defaults=_,CheckingIgnoringChecking _QueuedTriggerAddBJ_Category=TC_TRIGGER QueuedTriggerRemoveBJ=0,trigger _QueuedTriggerRemoveBJ_Defaults=GetTriggeringTrigger _QueuedTriggerRemoveBJ_Category=TC_TRIGGER QueuedTriggerClearBJ=0,nothing _QueuedTriggerClearBJ_Defaults= _QueuedTriggerClearBJ_Category=TC_TRIGGER QueuedTriggerClearInactiveBJ=0,nothing _QueuedTriggerClearInactiveBJ_Defaults= _QueuedTriggerClearInactiveBJ_Category=TC_TRIGGER TriggerRemoveCondition=0,trigger,triggercondition _TriggerRemoveCondition_Defaults=GetTriggeringTrigger,_ _TriggerRemoveCondition_Category=TC_TRIGGER TriggerClearConditions=0,trigger _TriggerClearConditions_Defaults=GetTriggeringTrigger _TriggerClearConditions_Category=TC_TRIGGER TriggerRemoveAction=0,trigger,triggeraction _TriggerRemoveAction_Defaults=GetTriggeringTrigger,_ _TriggerRemoveAction_Category=TC_TRIGGER TriggerClearActions=0,trigger _TriggerClearActions_Defaults=GetTriggeringTrigger _TriggerClearActions_Category=TC_TRIGGER ResetTrigger=0,trigger _ResetTrigger_Defaults=GetTriggeringTrigger _ResetTrigger_Category=TC_TRIGGER AddTriggerEvent=1,trigger,eventcall _AddTriggerEvent_Defaults=GetTriggeringTrigger,_ _AddTriggerEvent_Category=TC_TRIGGER TriggerAddCondition=1,trigger,boolexpr _TriggerAddCondition_Defaults=_,_ _TriggerAddCondition_Category=TC_TRIGGER TriggerAddAction=1,trigger,code _TriggerAddAction_Defaults=_,_ _TriggerAddAction_Category=TC_TRIGGER QueuedTriggerRemoveByIndex=0,integer _QueuedTriggerRemoveByIndex_Defaults=0 _QueuedTriggerRemoveByIndex_Category=TC_TRIGGER CreateNUnitsAtLoc=0,integer,unitcode,player,location,real _CreateNUnitsAtLoc_Defaults=1,hfoo,Player00,GetRectCenter,RealUnitFacing _CreateNUnitsAtLoc_Limits=1,_,_,_,_,_,_,_,0,360 _CreateNUnitsAtLoc_Category=TC_UNIT CreateNUnitsAtLocFacingLocBJ=0,integer,unitcode,player,location,location _CreateNUnitsAtLocFacingLocBJ_Defaults=1,hfoo,Player00,GetRectCenter,GetUnitLoc _CreateNUnitsAtLocFacingLocBJ_Limits=1,_,_,_,_,_,_,_,_,_ _CreateNUnitsAtLocFacingLocBJ_Category=TC_UNIT CreateCorpseLocBJ=0,unitcode,player,location _CreateCorpseLocBJ_Defaults=hfoo,Player00,GetRectCenter _CreateCorpseLocBJ_Category=TC_UNIT CreatePermanentCorpseLocBJ=1,corpsetype,unitcode,player,location,real _CreatePermanentCorpseLocBJ_Defaults=CorpseTypeBone,hfoo,Player00,GetRectCenter,GetRandomDirectionDeg _CreatePermanentCorpseLocBJ_Limits=_,_,_,_,_,_,_,_,0,360 _CreatePermanentCorpseLocBJ_Category=TC_UNIT KillUnit=0,unit _KillUnit_Defaults=GetTriggerUnit _KillUnit_Category=TC_UNIT RemoveUnit=0,unit _RemoveUnit_Defaults=GetTriggerUnit _RemoveUnit_Category=TC_UNIT ExplodeUnitBJ=0,unit _ExplodeUnitBJ_Defaults=GetTriggerUnit _ExplodeUnitBJ_Category=TC_UNIT ReplaceUnitBJ=0,unit,unitcode,unitstatemethod _ReplaceUnitBJ_Defaults=GetTriggerUnit,hfoo,UnitStateMethodRelative _ReplaceUnitBJ_Category=TC_UNIT ShowUnitHide=0,unit _ShowUnitHide_Defaults=_ _ShowUnitHide_Category=TC_UNIT ShowUnitShow=0,unit _ShowUnitShow_Defaults=_ _ShowUnitShow_Category=TC_UNIT SetUnitColor=0,unit,playercolor _SetUnitColor_Defaults=GetTriggerUnit,Color00 _SetUnitColor_Category=TC_UNIT SetUnitOwner=0,unit,player,colorchangeoption _SetUnitOwner_Defaults=_,Player00,ChangeColorTrue _SetUnitOwner_Category=TC_UNIT UnitShareVisionBJ=0,sharedontoption,unit,player _UnitShareVisionBJ_Defaults=ShareDontOptionShare,GetTriggerUnit,Player00 _UnitShareVisionBJ_Category=TC_UNIT SetUnitPositionLoc=0,unit,location _SetUnitPositionLoc_Defaults=GetTriggerUnit,GetRectCenter _SetUnitPositionLoc_Category=TC_UNIT SetUnitPositionLocFacingBJ=0,unit,location,real _SetUnitPositionLocFacingBJ_Defaults=GetTriggerUnit,GetRectCenter,RealUnitFacing _SetUnitPositionLocFacingBJ_Category=TC_UNIT SetUnitPositionLocFacingLocBJ=0,unit,location,location _SetUnitPositionLocFacingLocBJ_Defaults=GetTriggerUnit,GetRectCenter,GetUnitLoc _SetUnitPositionLocFacingLocBJ_Category=TC_UNIT SetUnitRallyPoint=1,unit,location _SetUnitRallyPoint_Defaults=GetTriggerUnit,GetRectCenter _SetUnitRallyPoint_Category=TC_UNIT SetUnitRallyUnit=1,unit,unit _SetUnitRallyUnit_Defaults=GetTriggerUnit,_ _SetUnitRallyUnit_Category=TC_UNIT SetUnitRallyDestructable=1,unit,destructable _SetUnitRallyDestructable_Defaults=GetTriggerUnit,_ _SetUnitRallyDestructable_Category=TC_UNIT SetUnitLifePercentBJ=0,unit,real _SetUnitLifePercentBJ_Defaults=GetTriggerUnit,100 _SetUnitLifePercentBJ_Limits=_,_,0,100 _SetUnitLifePercentBJ_Category=TC_UNIT SetUnitManaPercentBJ=0,unit,real _SetUnitManaPercentBJ_Defaults=GetTriggerUnit,100 _SetUnitManaPercentBJ_Limits=_,_,0,100 _SetUnitManaPercentBJ_Category=TC_UNIT SetUnitLifeBJ=0,unit,real _SetUnitLifeBJ_Defaults=GetTriggerUnit,GetUnitStateSwap _SetUnitLifeBJ_Defaults=_,_,0,_ _SetUnitLifeBJ_Category=TC_UNIT SetUnitManaBJ=0,unit,real _SetUnitManaBJ_Defaults=GetTriggerUnit,0 _SetUnitManaBJ_Limits=_,_,0,_ _SetUnitManaBJ_Category=TC_UNIT UnitIgnoreAlarm=1,unit,boolean _UnitIgnoreAlarm_Defaults=_,true _UnitIgnoreAlarm_Category=TC_UNIT SetUnitInvulnerable=0,unit,invulnerableoption _SetUnitInvulnerable_Defaults=GetTriggerUnit,InvulnerabilityInvulnerable _SetUnitInvulnerable_Category=TC_UNIT PauseUnitBJ=0,pauseunpauseoption,unit _PauseUnitBJ_Defaults=PauseUnpauseOptionPause,GetTriggerUnit _PauseUnitBJ_Category=TC_UNIT PauseAllUnitsBJ=0,pauseunpauseoption _PauseAllUnitsBJ_Defaults=PauseUnpauseOptionPause _PauseAllUnitsBJ_Category=TC_UNIT UnitPauseTimedLifeBJ=1,pauseunpauseoption,unit _UnitPauseTimedLifeBJ_Defaults=PauseUnpauseOptionPause,GetTriggerUnit _UnitPauseTimedLifeBJ_Category=TC_UNIT UnitApplyTimedLifeBJ=1,real,timedlifebuffcode,unit _UnitApplyTimedLifeBJ_Defaults=60,TimedLifeBuffCodeGeneric,GetTriggerUnit _UnitApplyTimedLifeBJ_Limits=0,_,_,_,_,_ _UnitApplyTimedLifeBJ_Category=TC_UNIT UnitApplyTimedLifeB=0,unit,buffcode,integer _UnitApplyTimedLifeB_Defaults=GetTriggerUnit,_,60 _UnitApplyTimedLifeB_ScriptName=UnitApplyTimedLife _UnitApplyTimedLifeB_Category=TC_UNIT SetUnitExplodedBJ=0,unit,explodedontoption _SetUnitExplodedBJ_Defaults=GetTriggerUnit,ExplodeDontExplode _SetUnitExplodedBJ_Category=TC_UNIT UnitSuspendDecayBJ=0,suspendresumeoption,unit _UnitSuspendDecayBJ_Defaults=SuspendResumeSuspend,GetTriggerUnit _UnitSuspendDecayBJ_Category=TC_UNIT UnitResetCooldown=1,unit _UnitResetCooldown_Defaults=GetTriggerUnit _UnitResetCooldown_Category=TC_UNIT UnitSetConstructionProgress=1,unit,integer _UnitSetConstructionProgress_Defaults=GetTriggerUnit,50 _UnitSetConstructionProgress_Limits=_,_,0,100 _UnitSetConstructionProgress_Category=TC_UNIT UnitSetUpgradeProgress=1,unit,integer _UnitSetUpgradeProgress_Defaults=GetTriggerUnit,50 _UnitSetUpgradeProgress_Limits=_,_,0,100 _UnitSetUpgradeProgress_Category=TC_UNIT UnitAddSleepPerm=0,unit,sleepwakeoption _UnitAddSleepPerm_Defaults=GetTriggerUnit,SleepWakeOptionSleep _UnitAddSleepPerm_Category=TC_UNIT UnitSetCanSleepBJ=0,unit,sleepwakeoption _UnitSetCanSleepBJ_Defaults=GetTriggerUnit,SleepWakeOptionSleep _UnitSetCanSleepBJ_Category=TC_UNIT UnitWakeUpBJ=0,unit _UnitWakeUpBJ_Defaults=GetTriggerUnit _UnitWakeUpBJ_Category=TC_UNIT UnitGenerateAlarms=1,unit,onoffoption _UnitGenerateAlarms_Defaults=GetTriggerUnit,OnOffOff _UnitGenerateAlarms_Category=TC_UNIT RescueUnitBJ=0,unit,player,colorchangeoption _RescueUnitBJ_Defaults=_,Player00,ChangeColorTrue _RescueUnitBJ_Category=TC_UNIT MakeUnitRescuableToForceBJ=0,unit,rescuableoption,force _MakeUnitRescuableToForceBJ_Defaults=_,RescuableOptionRescuable,Force00 _MakeUnitRescuableToForceBJ_Category=TC_UNIT SetUnitRescueRange=0,unit,real _SetUnitRescueRange_Defaults=_,384 _SetUnitRescueRange_Limits=_,_,0,_ _SetUnitRescueRange_Category=TC_UNIT SetRescueUnitColorChangeBJ=0,colorchangeoption _SetRescueUnitColorChangeBJ_Defaults=ChangeColorFalse _SetRescueUnitColorChangeBJ_Category=TC_UNIT SetRescueBuildingColorChangeBJ=0,colorchangeoption _SetRescueBuildingColorChangeBJ_Defaults=ChangeColorFalse _SetRescueBuildingColorChangeBJ_Category=TC_UNIT SetUnitUseFoodBJ=1,enabledisableoption,unit _SetUnitUseFoodBJ_Defaults=EnableDisableDisable,_ _SetUnitUseFoodBJ_Category=TC_UNIT SetUnitFacingToFaceUnitTimed=0,unit,unit,real _SetUnitFacingToFaceUnitTimed_Defaults=_,_,0 _SetUnitFacingToFaceUnitTimed_Limits=_,_,_,_,0,_ _SetUnitFacingToFaceUnitTimed_Category=TC_UNIT SetUnitFacingToFaceLocTimed=0,unit,location,real _SetUnitFacingToFaceLocTimed_Defaults=_,GetRectCenter,0 _SetUnitFacingToFaceLocTimed_Limits=_,_,_,_,0,_ _SetUnitFacingToFaceLocTimed_Category=TC_UNIT SetUnitFacingTimed=0,unit,real,real _SetUnitFacingTimed_Defaults=_,RealUnitFacing,0 _SetUnitFacingTimed_Limits=_,_,_,_,0,_ _SetUnitFacingTimed_Category=TC_UNIT SetUnitMoveSpeed=0,unit,real _SetUnitMoveSpeed_Defaults=_,GetUnitDefaultMoveSpeed _SetUnitMoveSpeed_Category=TC_UNIT SetUnitPathing=0,unit,pathingoption _SetUnitPathing_Defaults=_,PathingOff _SetUnitPathing_Category=TC_UNIT SetUnitAcquireRangeBJ=0,unit,real _SetUnitAcquireRangeBJ_Defaults=_,_ _SetUnitAcquireRangeBJ_Category=TC_UNIT SetUnitUserData=1,unit,integer _SetUnitUserData_Defaults=_,0 _SetUnitUserData_Category=TC_UNIT UnitRemoveBuffsBJ=0,bufftype,unit _UnitRemoveBuffsBJ_Defaults=BuffTypeAll,GetTriggerUnit _UnitRemoveBuffsBJ_Category=TC_UNIT UnitRemoveBuffsExBJ=1,buffpolarity,buffresist,unit,includeoption,includeoption _UnitRemoveBuffsExBJ_Defaults=BuffPolarityEither,BuffResistEither,GetTriggerUnit,InclusionInclude,InclusionInclude _UnitRemoveBuffsExBJ_Category=TC_UNIT UnitRemoveBuffBJ=1,buffcode,unit _UnitRemoveBuffBJ_Defaults=_,GetTriggerUnit _UnitRemoveBuffBJ_Category=TC_UNIT UnitAddAbilityBJ=1,abilcode,unit _UnitAddAbilityBJ_Defaults=_,GetTriggerUnit _UnitAddAbilityBJ_Category=TC_UNIT UnitRemoveAbilityBJ=0,abilcode,unit _UnitRemoveAbilityBJ_Defaults=_,GetTriggerUnit _UnitRemoveAbilityBJ_Category=TC_UNIT UnitAddTypeBJ=1,unittype,unit _UnitAddTypeBJ_Defaults=UnitTypeMechanical,GetTriggerUnit _UnitAddTypeBJ_Category=TC_UNIT UnitRemoveTypeBJ=1,unittype,unit _UnitRemoveTypeBJ_Defaults=UnitTypeMechanical,GetTriggerUnit _UnitRemoveTypeBJ_Category=TC_UNIT UnitMakeAbilityPermanentBJ=0,unit,permanentoption,abilcode _UnitMakeAbilityPermanentBJ_Defaults=GetTriggerUnit,PermanentPerm,_ _UnitMakeAbilityPermanentBJ_Category=TC_UNIT _UnitMakeAbilityPermanentBJ_ScriptName=UnitMakeAbilityPermanent IssueTargetOrder=0,unit,unitorderutarg,unit _IssueTargetOrder_Defaults=_,UnitOrderAttackUnit,_ _IssueTargetOrder_Category=TC_UNIT _IssueTargetOrder_ScriptName=IssueTargetOrderBJ IssueTargetOrderBJ=0,unit,string,unit _IssueTargetOrderBJ_Defaults=_,"attack",_ _IssueTargetOrderBJ_Category=TC_UNIT _IssueTargetOrderBJ_ScriptName=IssueTargetOrder IssueTargetOrderById=0,unit,ordercode,unit _IssueTargetOrderById_Defaults=_,OrderCodeAttackUnit,_ _IssueTargetOrderById_Category=TC_UNIT IssuePointOrderLoc=0,unit,unitorderptarg,location _IssuePointOrderLoc_Defaults=_,UnitOrderMove,GetRectCenter _IssuePointOrderLoc_Category=TC_UNIT _IssuePointOrderLoc_ScriptName=IssuePointOrderLocBJ IssuePointOrderLocBJ=0,unit,string,location _IssuePointOrderLocBJ_Defaults=_,"move",GetRectCenter _IssuePointOrderLocBJ_Category=TC_UNIT _IssuePointOrderLocBJ_ScriptName=IssuePointOrderLoc IssuePointOrderByIdLoc=0,unit,ordercode,location _IssuePointOrderByIdLoc_Defaults=_,OrderCodeMoveUnit,GetRectCenter _IssuePointOrderByIdLoc_Category=TC_UNIT IssueTargetDestructableOrder=0,unit,unitorderdtarg,destructable _IssueTargetDestructableOrder_Defaults=_,UnitOrderHarvestDestructible,_ _IssueTargetDestructableOrder_Category=TC_UNIT IssueTargetOrderD=0,unit,string,destructable _IssueTargetOrderD_Defaults=_,"harvest",_ _IssueTargetOrderD_Category=TC_UNIT _IssueTargetOrderD_ScriptName=IssueTargetOrder IssueTargetOrderByIdD=0,unit,ordercode,destructable _IssueTargetOrderByIdD_Defaults=_,OrderCodeHarvest,_ _IssueTargetOrderByIdD_Category=TC_UNIT _IssueTargetOrderByIdD_Scriptname=IssueTargetOrderById IssueTargetItemOrder=0,unit,unitorderitarg,item _IssueTargetItemOrder_Defaults=_,UnitOrderSmartItem,_ _IssueTargetItemOrder_Category=TC_UNIT IssueItemTargetOrderS=0,unit,string,item _IssueItemTargetOrderS_Defaults=_,"smart",_ _IssueItemTargetOrderS_Category=TC_UNIT _IssueItemTargetOrderS_ScriptName=IssueTargetOrderBJ IssueItemTargetOrderId=0,unit,ordercode,item _IssueItemTargetOrderId_Defaults=_,OrderCodeAttackUnit,_ _IssueItemTargetOrderId_Category=TC_UNIT _IssueItemTargetOrderId_Scriptname=IssueTargetOrderById IssueImmediateOrder=0,unit,unitordernotarg _IssueImmediateOrder_Defaults=_,UnitOrderStop _IssueImmediateOrder_Category=TC_UNIT _IssueImmediateOrder_ScriptName=IssueImmediateOrderBJ IssueImmediateOrderBJ=0,unit,string _IssueImmediateOrderBJ_Defaults=_,"stop" _IssueImmediateOrderBJ_Category=TC_UNIT _IssueImmediateOrderBJ_ScriptName=IssueImmediateOrder IssueImmediateOrderById=0,unit,ordercode _IssueImmediateOrderById_Defaults=_,OrderCodeStop _IssueImmediateOrderById_Category=TC_UNIT IssueTrainOrderByIdBJ=0,unit,unitcode _IssueTrainOrderByIdBJ_Defaults=_,hfoo _IssueTrainOrderByIdBJ_Category=TC_UNIT IssueUpgradeOrderByIdBJ=0,unit,techcode _IssueUpgradeOrderByIdBJ_Defaults=_,Rhde _IssueUpgradeOrderByIdBJ_Category=TC_UNIT IssueBuildOrderByIdLocBJ=0,unit,unitcode,location _IssueBuildOrderByIdLocBJ_Defaults=_,hbar,GetRectCenter _IssueBuildOrderByIdLocBJ_Category=TC_UNIT UnitDropItemPointLoc=1,unit,item,location _UnitDropItemPointLoc_Defaults=_,GetLastCreatedItem,GetRectCenter _UnitDropItemPointLoc_Category=TC_UNIT UnitDropItemSlotBJ=1,unit,item,integer _UnitDropItemSlotBJ_Defaults=_,GetLastCreatedItem,1 _UnitDropItemSlotBJ_Limits=_,_,_,_,1,6 _UnitDropItemSlotBJ_Category=TC_UNIT UnitDropItemTargetBJ=1,unit,item,unit _UnitDropItemTargetBJ_Defaults=_,GetLastCreatedItem,_ _UnitDropItemTargetBJ_Category=TC_UNIT UnitDamagePointLoc=1,unit,real,real,location,real,attacktype,damagetype _UnitDamagePointLoc_Defaults=GetTriggerUnit,0,500,GetRectCenter,100,AttackTypeNormal,DamageTypeNormal _UnitDamagePointLoc_Category=TC_UNIT UnitDamageTargetBJ=1,unit,unit,real,attacktype,damagetype _UnitDamageTargetBJ_Defaults=GetTriggerUnit,GetTriggerUnit,500,AttackTypeNormal,DamageTypeNormal _UnitDamageTargetBJ_Category=TC_UNIT DecUnitAbilityLevelSwapped=1,abilcode,unit _DecUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit,1 _DecUnitAbilityLevelSwapped_Category=TC_UNIT IncUnitAbilityLevelSwapped=1,abilcode,unit _IncUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit _IncUnitAbilityLevelSwapped_Category=TC_UNIT SetUnitAbilityLevelSwapped=1,abilcode,unit,integer _SetUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit _SetUnitAbilityLevelSwapped_Limits=_,_,_,_,1,_ _SetUnitAbilityLevelSwapped_Category=TC_UNIT ForGroupMultiple=1,group _ForGroupMultiple_Defaults=GetUnitsInRectAll _ForGroupMultiple_Category=TC_UNITGROUP _ForGroupMultiple_ScriptName=ForGroupBJ ForGroup=0,group,code _ForGroup_Defaults=GetUnitsInRectAll,DoNothing _ForGroup_Category=TC_UNITGROUP _ForGroup_ScriptName=ForGroupBJ GroupAddUnitSimple=0,unit,group _GroupAddUnitSimple_Defaults=GetTriggerUnit,_ _GroupAddUnitSimple_Category=TC_UNITGROUP GroupAddGroup=0,group,group _GroupAddGroup_Defaults=_,_ _GroupAddGroup_Category=TC_UNITGROUP GroupRemoveUnitSimple=0,unit,group _GroupRemoveUnitSimple_Defaults=GetTriggerUnit,_ _GroupRemoveUnitSimple_Category=TC_UNITGROUP GroupRemoveGroup=0,group,group _GroupRemoveGroup_Defaults=_,_ _GroupRemoveGroup_Category=TC_UNITGROUP DestroyGroup=0,group _DestroyGroup_Defaults=_ _DestroyGroup_Category=TC_UNITGROUP GroupClear=0,group _GroupClear_Defaults=_ _GroupClear_Category=TC_UNITGROUP GroupTargetOrder=0,group,unitorderutarg,unit _GroupTargetOrder_Defaults=GetUnitsInRectAll,UnitOrderAttackUnit,_ _GroupTargetOrder_Category=TC_UNITGROUP _GroupTargetOrder_ScriptName=GroupTargetOrderBJ GroupTargetOrderBJ=0,group,string,unit _GroupTargetOrderBJ_Defaults=GetUnitsInRectAll,"attack",_ _GroupTargetOrderBJ_Category=TC_UNITGROUP _GroupTargetOrderBJ_ScriptName=GroupTargetOrder GroupTargetOrderById=0,group,ordercode,unit _GroupTargetOrderById_Defaults=GetUnitsInRectAll,OrderCodeAttackUnit,_ _GroupTargetOrderById_Category=TC_UNITGROUP GroupPointOrderLoc=0,group,unitorderptarg,location _GroupPointOrderLoc_Defaults=GetUnitsInRectAll,UnitOrderMove,GetRectCenter _GroupPointOrderLoc_Category=TC_UNITGROUP _GroupPointOrderLoc_ScriptName=GroupPointOrderLocBJ GroupPointOrderLocBJ=0,group,string,location _GroupPointOrderLocBJ_Defaults=GetUnitsInRectAll,"move",GetRectCenter _GroupPointOrderLocBJ_Category=TC_UNITGROUP _GroupPointOrderLocBJ_ScriptName=GroupPointOrderLoc GroupPointOrderByIdLoc=0,group,ordercode,location _GroupPointOrderByIdLoc_Defaults=GetUnitsInRectAll,OrderCodeMoveUnit,GetRectCenter _GroupPointOrderByIdLoc_Category=TC_UNITGROUP GroupTargetDestructableOrder=0,group,unitorderdtarg,destructable _GroupTargetDestructableOrder_Defaults=GetUnitsInRectAll,UnitOrderHarvestDestructible,_ _GroupTargetDestructableOrder_Category=TC_UNITGROUP GroupTargetDestructableOrderS=0,group,string,destructable _GroupTargetDestructableOrderS_Defaults=GetUnitsInRectAll,"harvest",_ _GroupTargetDestructableOrderS_ScriptName=GroupTargetOrder _GroupTargetDestructableOrderS_Category=TC_UNITGROUP GroupTargetOrderByIdD=0,group,ordercode,destructable _GroupTargetOrderByIdD_Defaults=GetUnitsInRectAll,OrderCodeHarvest,_ _GroupTargetOrderByIdD_ScriptName=GroupTargetOrderById _GroupTargetOrderByIdD_Category=TC_UNITGROUP GroupTargetItemOrder=0,group,unitorderitarg,item _GroupTargetItemOrder_Defaults=GetUnitsInRectAll,UnitOrderAttackItem,_ _GroupTargetItemOrder_Category=TC_UNITGROUP GroupItemTargetOrderBJ=0,group,string,item _GroupItemTargetOrderBJ_Defaults=GetUnitsInRectAll,"smart",_ _GroupItemTargetOrderBJ_Category=TC_UNITGROUP _GroupItemTargetOrderBJ_ScriptName=GroupTargetOrder GroupItemTargetOrderById=0,group,ordercode,item _GroupItemTargetOrderById_Defaults=GetUnitsInRectAll,OrderCodeSmart,_ _GroupItemTargetOrderById_Category=TC_UNITGROUP _GroupItemTargetOrderById_ScriptName=GroupTargetOrderById GroupImmediateOrder=0,group,unitordernotarg _GroupImmediateOrder_Defaults=GetUnitsInRectAll,UnitOrderStop _GroupImmediateOrder_Category=TC_UNITGROUP _GroupImmediateOrder_ScriptName=GroupImmediateOrderBJ GroupImmediateOrderBJ=0,group,string _GroupImmediateOrderBJ_Defaults=GetUnitsInRectAll,"stop" _GroupImmediateOrderBJ_Category=TC_UNITGROUP _GroupImmediateOrderBJ_ScriptName=GroupImmediateOrder GroupImmediateOrderById=0,group,ordercode _GroupImmediateOrderById_Defaults=GetUnitsInRectAll,OrderCodeStop _GroupImmediateOrderById_Category=TC_UNITGROUP GroupTrainOrderByIdBJ=0,group,unitcode _GroupTrainOrderByIdBJ_Defaults=GetUnitsInRectAll,hfoo _GroupTrainOrderByIdBJ_Category=TC_UNITGROUP GroupEnumUnitsOfType=1,group,unituiname,boolexpr _GroupEnumUnitsOfType_Defaults=_,UnitUINamearchmage,_ _GroupEnumUnitsOfType_Category=TC_UNITGROUP GroupEnumUnitsOfTypeCounted=1,group,unituiname,boolexpr,integer _GroupEnumUnitsOfTypeCounted_Defaults=_,UnitUINamearchmage,_,12 _GroupEnumUnitsOfTypeCounted_Category=TC_UNITGROUP GroupEnumUnitsOfPlayer=1,group,player,boolexpr _GroupEnumUnitsOfPlayer_Defaults=_,Player00,_ _GroupEnumUnitsOfPlayer_Category=TC_UNITGROUP GroupEnumUnitsInRect=1,group,rect,boolexpr _GroupEnumUnitsInRect_Defaults=_,GetEntireMapRect,_ _GroupEnumUnitsInRect_Category=TC_UNITGROUP GroupEnumUnitsInRectCounted=1,group,rect,boolexpr,integer _GroupEnumUnitsInRectCounted_Defaults=_,GetEntireMapRect,_,12 _GroupEnumUnitsInRectCounted_Category=TC_UNITGROUP GroupEnumUnitsInRangeOfLoc=1,group,location,real,boolexpr _GroupEnumUnitsInRangeOfLoc_Defaults=_,GetRectCenter,500,_ _GroupEnumUnitsInRangeOfLoc_Category=TC_UNITGROUP GroupEnumUnitsInRangeOfLocCounted=1,group,location,real,boolexpr,integer _GroupEnumUnitsInRangeOfLocCounted_Defaults=_,GetRectCenter,500,_,12 _GroupEnumUnitsInRangeOfLocCounted_Category=TC_UNITGROUP GroupEnumUnitsSelected=1,group,player,boolexpr _GroupEnumUnitsSelected_Defaults=_,Player00,_ _GroupEnumUnitsSelected_Category=TC_UNITGROUP FogEnableOn=0,nothing _FogEnableOn_Defaults= _FogEnableOn_Category=TC_VISIBILITY FogEnableOff=0,nothing _FogEnableOff_Defaults= _FogEnableOff_Category=TC_VISIBILITY FogMaskEnableOn=0,nothing _FogMaskEnableOn_Defaults= _FogMaskEnableOn_Category=TC_VISIBILITY FogMaskEnableOff=0,nothing _FogMaskEnableOff_Defaults= _FogMaskEnableOff_Category=TC_VISIBILITY CreateFogModifierRectBJ=0,enableddisabledoption,player,fogstate,rect _CreateFogModifierRectBJ_Defaults=EnabledDisabledEnabled,Player00,FogStateVisible,GetPlayableMapRect _CreateFogModifierRectBJ_Category=TC_VISIBILITY CreateFogModifierRadiusLocBJ=0,enableddisabledoption,player,fogstate,location,real _CreateFogModifierRadiusLocBJ_Defaults=EnabledDisabledEnabled,Player00,FogStateVisible,GetRectCenter,512 _CreateFogModifierRadiusLocBJ_Defaults=_,_,_,_,_,_,_,_,0,_ _CreateFogModifierRadiusLocBJ_Category=TC_VISIBILITY FogModifierStart=0,fogmodifier _FogModifierStart_Defaults=GetLastCreatedFogModifier _FogModifierStart_Category=TC_VISIBILITY FogModifierStop=0,fogmodifier _FogModifierStop_Defaults=GetLastCreatedFogModifier _FogModifierStop_Category=TC_VISIBILITY DestroyFogModifier=0,fogmodifier _DestroyFogModifier_Defaults=GetLastCreatedFogModifier _DestroyFogModifier_Category=TC_VISIBILITY CreateDestructableZA=0,destructablecode,real,real,real,real,real,integer _CreateDestructableZA_Defaults=LTlt,GetLocationX,GetLocationY,0,GetRandomDirectionDeg,1,0 _CreateDestructableZA_Limits=_,_,_,_,_,_,_,_,_,_,0,_,0,_ _CreateDestructableZA_ScriptName=CreateDestructableZ _CreateDestructableZA_Category=TC_COMPATIBILITY CreateDeadDestructableZA=0,destructablecode,real,real,real,real,real,integer _CreateDeadDestructableZA_Defaults=LTlt,GetLocationX,GetLocationY,0,GetRandomDirectionDeg,1,0 _CreateDeadDestructableZA_Limits=_,_,_,_,_,_,_,_,_,_,0,_,0,_ _CreateDeadDestructableZA_ScriptName=CreateDeadDestructableZ _CreateDeadDestructableZA_Category=TC_COMPATIBILITY DialogAddButtonWithHotkeyBJ=0,dialog,string,integer _DialogAddButtonWithHotkeyBJ_Defaults=_,_,_ _DialogAddButtonWithHotkeyBJ_Category=TC_COMPATIBILITY CreateTrackable=1,modelfile,real,real,real _CreateTrackable_Defaults="units\nightelf\Wisp\Wisp.mdl",_,_,0 _CreateTrackable_Category=TC_COMPATIBILITY MultiboardDisplay=1,multiboard,showhideoption _MultiboardDisplay_Defaults=CreateMultiboard,ShowHideShow _MultiboardDisplay_Category=TC_COMPATIBILITY DestroyMultiboard=1,multiboard _DestroyMultiboard_Defaults=_ _DestroyMultiboard_Category=TC_COMPATIBILITY MultiboardMinimize=1,multiboard,minimizeoption _MultiboardMinimize_Defaults=_,true _MultiboardMinimize_Category=TC_COMPATIBILITY MultiboardSetTitleTextColor=1,multiboard,integer,integer,integer,integer _MultiboardSetTitleTextColor_Defaults=_,100,100,100,0 _MultiboardSetTitleTextColor_Category=TC_COMPATIBILITY MultiboardSetItemsStyle=1,multiboard,showhideoption,showhideoption _MultiboardSetItemsStyle_Defaults=_,ShowHideShow,ShowHideShow _MultiboardSetItemsStyle_Category=TC_COMPATIBILITY MultiboardSetItemsValue=1,multiboard,StringExt _MultiboardSetItemsValue_Defaults=_,_ _MultiboardSetItemsValue_Category=TC_COMPATIBILITY MultiboardSetItemsWidth=1,multiboard,real _MultiboardSetItemsWidth_Defaults=_,_ _MultiboardSetItemsWidth_Category=TC_COMPATIBILITY MultiboardSetItemsIcon=1,multiboard,imagefile _MultiboardSetItemsIcon_Defaults=_,_ _MultiboardSetItemsIcon_Category=TC_COMPATIBILITY MultiboardReleaseItem=1,multiboarditem _MultiboardReleaseItem_Defaults=MultiboardGetItem _MultiboardReleaseItem_Category=TC_COMPATIBILITY MultiboardSetItemStyle=1,multiboarditem,showhideoption,showhideoption _MultiboardSetItemStyle_Defaults=_,ShowHideShow,ShowHideShow _MultiboardSetItemStyle_Category=TC_COMPATIBILITY MultiboardSetItemValue=1,multiboarditem,StringExt _MultiboardSetItemValue_Defaults=_,_ _MultiboardSetItemValue_Category=TC_COMPATIBILITY MultiboardSetItemWidth=1,multiboarditem,real _MultiboardSetItemWidth_Defaults=_,_ _MultiboardSetItemWidth_Category=TC_COMPATIBILITY MultiboardSetItemIcon=1,multiboarditem,imagefile _MultiboardSetItemIcon_Defaults=_,_ _MultiboardSetItemIcon_Category=TC_COMPATIBILITY AddSpellEffectByIdLoc=0,abilcode,effecttype,location _AddSpellEffectByIdLoc_Defaults=_,EffectTypeCaster,GetRectCenter _AddSpellEffectByIdLoc_Category=TC_COMPATIBILITY AddSpellEffectTargetById=0,abilcode,effecttype,unit,string _AddSpellEffectTargetById_Defaults=_,EffectTypeCaster,GetLastCreatedUnit,"overhead" _AddSpellEffectTargetById_Category=TC_COMPATIBILITY AddSpellEffectByIdLocB=0,buffcode,effecttypebuff,location _AddSpellEffectByIdLocB_Defaults=_,EffectTypeTargetBuff,GetRectCenter _AddSpellEffectByIdLocB_Category=TC_COMPATIBILITY _AddSpellEffectByIdLocB_ScriptName=AddSpellEffectByIdLoc AddSpellEffectTargetByIdB=0,buffcode,effecttypebuff,unit,string _AddSpellEffectTargetByIdB_Defaults=_,EffectTypeTargetBuff,GetLastCreatedUnit,"overhead" _AddSpellEffectTargetByIdB_Category=TC_COMPATIBILITY _AddSpellEffectTargetByIdB_ScriptName=AddSpellEffectTargetById UnitApplyTimedLife=0,unit,integer,integer _UnitApplyTimedLife_Defaults=GetLastCreatedUnit,1,60 _UnitApplyTimedLife_Category=TC_COMPATIBILITY IssueItemTargetOrder=0,unit,unitorderitarg,item _IssueItemTargetOrder_Defaults=_,ItemOrderPickUp,_ _IssueItemTargetOrder_Category=TC_COMPATIBILITY _IssueItemTargetOrder_ScriptName=IssueTargetOrderBJ GroupItemTargetOrder=0,group,unitorderitarg,item _GroupItemTargetOrder_Defaults=GetUnitsInRectAll,ItemOrderPickUp,_ _GroupItemTargetOrder_Category=TC_COMPATIBILITY _GroupItemTargetOrder_ScriptName=GroupTargetOrder [TriggerCalls] IsDestructableAliveBJ=0,0,boolean,destructable _IsDestructableAliveBJ_Defaults=GetLastCreatedDestructable _IsDestructableAliveBJ_Category=TC_DESTRUCT IsDestructableDeadBJ=0,0,boolean,destructable _IsDestructableDeadBJ_Defaults=GetLastCreatedDestructable _IsDestructableDeadBJ_Category=TC_DESTRUCT IsDestructableInvulnerableBJ=0,0,boolean,destructable _IsDestructableInvulnerableBJ_Defaults=GetLastCreatedDestructable _IsDestructableInvulnerableBJ_Category=TC_DESTRUCT IsPointBlightedBJ=1,1,boolean,location _IsPointBlightedBJ_Defaults=GetRectCenter _IsPointBlightedBJ_Category=TC_ENVIRONMENT IsMapFlagSet=0,1,boolean,mapflag _IsMapFlagSet_Defaults=MapFlagUseHandicaps _IsMapFlagSet_Category=TC_GAME IsCustomCampaignButtonVisibile=1,0,boolean,integer _IsCustomCampaignButtonVisibile_Defaults=1 _IsCustomCampaignButtonVisibile_Limits=1,_ _IsCustomCampaignButtonVisibile_Category=TC_GAME GetCreepCampFilterState=1,1,boolean _GetCreepCampFilterState_Category=TC_GAME SaveGameExists=1,0,boolean,anyfile _SaveGameExists_Defaults=_ _SaveGameExists_Category=TC_GAME GetStoredBooleanBJ=0,0,boolean,string,string,gamecache _GetStoredBooleanBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredBooleanBJ_Category=TC_GAMECACHE HaveStoredValue=1,0,boolean,string,cachevaluetype,string,gamecache _HaveStoredValue_Defaults=_,CacheValueTypeUnit,"Category",GetLastCreatedGameCacheBJ _HaveStoredValue_Category=TC_GAMECACHE UnitHasItem=0,1,boolean,unit,item _UnitHasItem_Defaults=GetTriggerUnit,GetLastCreatedItem _UnitHasItem_Category=TC_HERO UnitHasItemOfTypeBJ=0,1,boolean,unit,itemcode _UnitHasItemOfTypeBJ_Defaults=GetTriggerUnit,texp _UnitHasItemOfTypeBJ_Category=TC_HERO IsSuspendedXP=0,0,boolean,unit _IsSuspendedXP_Defaults=GetTriggerUnit _IsSuspendedXP_Category=TC_HERO CheckItemStatus=1,0,boolean,item,itemstatus _CheckItemStatus_Defaults=GetLastCreatedItem,ItemStatusHidden _CheckItemStatus_Category=TC_ITEM CheckItemcodeStatus=1,0,boolean,itemcode,itemcodestatus _CheckItemcodeStatus_Defaults=GetItemTypeId,ItemcodeStatusPowerup _CheckItemcodeStatus_Category=TC_ITEM IsItemHiddenBJ=1,0,boolean,item _IsItemHiddenBJ_Defaults=GetLastCreatedItem _IsItemHiddenBJ_Category=TC_ITEM IsItemOwned=1,0,boolean,item _IsItemOwned_Defaults=GetLastCreatedItem _IsItemOwned_Category=TC_ITEM RectContainsItem=1,1,boolean,item,rect _RectContainsItem_Defaults=GetLastCreatedItem,GetRectCenter _RectContainsItem_Category=TC_ITEM IsItemInvulnerable=0,0,boolean,item _IsItemInvulnerable_Defaults=GetLastCreatedItem _IsItemInvulnerable_Category=TC_ITEM LeaderboardHasPlayerItemBJ=0,0,boolean,leaderboard,player _LeaderboardHasPlayerItemBJ_Defaults=GetLastCreatedLeaderboard,Player00 _LeaderboardHasPlayerItemBJ_Category=TC_LEADERBOARD IsMultiboardDisplayed=1,0,boolean,multiboard _IsMultiboardDisplayed_Defaults=GetLastCreatedMultiboard _IsMultiboardDisplayed_Category=TC_MULTIBOARD IsMultiboardMinimized=1,0,boolean,multiboard _IsMultiboardMinimized_Defaults=GetLastCreatedMultiboard _IsMultiboardMinimized_Category=TC_MULTIBOARD WaygateIsActiveBJ=0,0,boolean,unit _WaygateIsActiveBJ_Defaults=_ _WaygateIsActiveBJ_Category=TC_NEUTRALBUILDING IsPlayerFlagSetBJ=0,0,boolean,playerflag,player _IsPlayerFlagSetBJ_Defaults=PlayerFlagGivesBounty,PlayerNA _IsPlayerFlagSetBJ_Category=TC_PLAYER IsPlayerAlly=0,1,boolean,player,player _IsPlayerAlly_Defaults=GetTriggerPlayer,Player00 _IsPlayerAlly_Category=TC_PLAYER IsPlayerEnemy=0,1,boolean,player,player _IsPlayerEnemy_Defaults=GetTriggerPlayer,Player00 _IsPlayerEnemy_Category=TC_PLAYER GetPlayerAlliance=0,1,boolean,player,player,alliancetype _GetPlayerAlliance_Defaults=GetTriggerPlayer,Player00,AllianceTypePassive _GetPlayerAlliance_Category=TC_PLAYER IsPlayerInForce=0,1,boolean,player,force _IsPlayerInForce_Defaults=Player00,GetPlayersAll _IsPlayerInForce_Category=TC_PLAYER IsQuestItemCompleted=0,0,boolean,questitem _IsQuestItemCompleted_Defaults=GetLastCreatedQuestItemBJ _IsQuestItemCompleted_Category=TC_QUEST IsQuestEnabled=0,0,boolean,quest _IsQuestEnabled_Defaults=GetLastCreatedQuestBJ _IsQuestEnabled_Category=TC_QUEST IsQuestCompleted=0,0,boolean,quest _IsQuestCompleted_Defaults=GetLastCreatedQuestBJ _IsQuestCompleted_Category=TC_QUEST IsQuestFailed=0,0,boolean,quest _IsQuestFailed_Defaults=GetLastCreatedQuestBJ _IsQuestFailed_Category=TC_QUEST IsQuestDiscovered=0,0,boolean,quest _IsQuestDiscovered_Defaults=GetLastCreatedQuestBJ _IsQuestDiscovered_Category=TC_QUEST IsQuestRequired=0,0,boolean,quest _IsQuestRequired_Defaults=GetLastCreatedQuestBJ _IsQuestRequired_Category=TC_QUEST RectContainsLoc=0,1,boolean,rect,location _RectContainsLoc_Defaults=GetPlayableMapRect,GetRectCenter _RectContainsLoc_Category=TC_REGION IsTriggerEnabled=0,1,boolean,trigger _IsTriggerEnabled_Defaults=GetTriggeringTrigger _IsTriggerEnabled_Category=TC_TRIGGER TriggerEvaluate=0,1,boolean,trigger _TriggerEvaluate_Defaults=_ _TriggerEvaluate_Category=TC_TRIGGER IsTriggerQueuedBJ=0,0,boolean,trigger _IsTriggerQueuedBJ_Defaults=_ _IsTriggerQueuedBJ_Category=TC_TRIGGER IsTriggerQueueEmptyBJ=0,0,boolean _IsTriggerQueueEmptyBJ_Defaults= _IsTriggerQueueEmptyBJ_Category=TC_TRIGGER IsUnitType=0,1,boolean,unit,unittype _IsUnitType_Defaults=GetTriggerUnit,UnitTypeStructure _IsUnitType_Category=TC_UNIT IsUnitIdType=1,1,boolean,unitcode,unittype _IsUnitIdType_Defaults=GetUnitTypeId,UnitTypeStructure _IsUnitIdType_Category=TC_UNIT IsUnitInGroup=0,1,boolean,unit,group _IsUnitInGroup_Defaults=GetTriggerUnit,GetUnitsInRectAll _IsUnitInGroup_Category=TC_UNIT RectContainsUnit=0,1,boolean,rect,unit _RectContainsUnit_Defaults=GetPlayableMapRect,GetTriggerUnit _RectContainsUnit_Category=TC_UNIT IsUnitAliveBJ=0,0,boolean,unit _IsUnitAliveBJ_Defaults=GetTriggerUnit _IsUnitAliveBJ_Category=TC_UNIT IsUnitDeadBJ=0,0,boolean,unit _IsUnitDeadBJ_Defaults=GetTriggerUnit _IsUnitDeadBJ_Category=TC_UNIT IsUnitPausedBJ=0,0,boolean,unit _IsUnitPausedBJ_Defaults=GetTriggerUnit _IsUnitPausedBJ_Category=TC_UNIT IsUnitHiddenBJ=0,0,boolean,unit _IsUnitHiddenBJ_Defaults=GetTriggerUnit _IsUnitHiddenBJ_Category=TC_UNIT IsUnitIllusionBJ=0,0,boolean,unit _IsUnitIllusionBJ_Defaults=GetTriggerUnit _IsUnitIllusionBJ_Category=TC_UNIT UnitCanSleepPerm=0,0,boolean,unit _UnitCanSleepPerm_Defaults=GetTriggerUnit _UnitCanSleepPerm_Category=TC_UNIT UnitCanSleepBJ=0,0,boolean,unit _UnitCanSleepBJ_Defaults=GetTriggerUnit _UnitCanSleepBJ_Category=TC_UNIT UnitIsSleepingBJ=0,0,boolean,unit _UnitIsSleepingBJ_Defaults=GetTriggerUnit _UnitIsSleepingBJ_Category=TC_UNIT DoesUnitGenerateAlarms=1,0,boolean,unit _DoesUnitGenerateAlarms_Defaults=GetTriggerUnit _DoesUnitGenerateAlarms_Category=TC_UNIT IsUnitLoadedBJ=0,0,boolean,unit _IsUnitLoadedBJ_Defaults=GetTriggerUnit _IsUnitLoadedBJ_Category=TC_UNIT IsUnitInTransportBJ=0,0,boolean,unit,unit _IsUnitInTransportBJ_Defaults=GetTriggerUnit,_ _IsUnitInTransportBJ_Category=TC_UNIT IsUnitSelected=0,1,boolean,unit,player _IsUnitSelected_Defaults=GetTriggerUnit,Player00 _IsUnitSelected_Category=TC_UNIT IsUnitAlly=0,1,boolean,unit,player _IsUnitAlly_Defaults=GetTriggerUnit,Player00 _IsUnitAlly_Category=TC_UNIT IsUnitEnemy=0,1,boolean,unit,player _IsUnitEnemy_Defaults=GetTriggerUnit,Player00 _IsUnitEnemy_Category=TC_UNIT UnitHasBuffBJ=1,1,boolean,unit,buffcode _UnitHasBuffBJ_Defaults=GetTriggerUnit,_ _UnitHasBuffBJ_Category=TC_UNIT IsUnitGroupEmptyBJ=0,1,boolean,group _IsUnitGroupEmptyBJ_Defaults=_ _IsUnitGroupEmptyBJ_Category=TC_UNITGROUP IsUnitGroupInRectBJ=0,1,boolean,group,rect _IsUnitGroupInRectBJ_Defaults=_ _IsUnitGroupInRectBJ_Category=TC_UNITGROUP IsUnitGroupDeadBJ=0,1,boolean,group _IsUnitGroupDeadBJ_Defaults=_ _IsUnitGroupDeadBJ_Category=TC_UNITGROUP IsFogEnabled=0,1,boolean _IsFogEnabled_Defaults= _IsFogEnabled_Category=TC_VISIBILITY IsFogMaskEnabled=0,1,boolean _IsFogMaskEnabled_Defaults= _IsFogMaskEnabled_Category=TC_VISIBILITY IsUnitVisible=0,1,boolean,unit,player _IsUnitVisible_Defaults=GetTriggerUnit,Player00 _IsUnitVisible_Category=TC_VISIBILITY IsUnitInvisible=0,1,boolean,unit,player _IsUnitInvisible_Defaults=GetTriggerUnit,Player00 _IsUnitInvisible_Category=TC_VISIBILITY IsUnitFogged=0,1,boolean,unit,player _IsUnitFogged_Defaults=GetTriggerUnit,Player00 _IsUnitFogged_Category=TC_VISIBILITY IsUnitMasked=0,1,boolean,unit,player _IsUnitMasked_Defaults=GetTriggerUnit,Player00 _IsUnitMasked_Category=TC_VISIBILITY IsLocationVisibleToPlayer=0,1,boolean,location,player _IsLocationVisibleToPlayer_Defaults=GetRectCenter,Player00 _IsLocationVisibleToPlayer_Category=TC_VISIBILITY IsLocationFoggedToPlayer=0,1,boolean,location,player _IsLocationFoggedToPlayer_Defaults=GetRectCenter,Player00 _IsLocationFoggedToPlayer_Category=TC_VISIBILITY IsLocationMaskedToPlayer=0,1,boolean,location,player _IsLocationMaskedToPlayer_Defaults=GetRectCenter,Player00 _IsLocationMaskedToPlayer_Category=TC_VISIBILITY OperatorInt=0,1,integer,integer,ArithmeticOperator,integer _OperatorInt_Defaults=_,OperatorAdd,1 _OperatorInt_Category=TC_ARITHMETIC _OperatorInt_UseWithAI=1 GetForLoopIndexA=0,0,integer _GetForLoopIndexA_Defaults= _GetForLoopIndexA_Category=TC_FORLOOP GetForLoopIndexB=0,0,integer _GetForLoopIndexB_Defaults= _GetForLoopIndexB_Category=TC_FORLOOP StringLength=1,1,integer,string _StringLength_Defaults=GetEventPlayerChatString _StringLength_Category=TC_NOTHING R2I=0,1,integer,real _R2I_Defaults=GetUnitStateSwap _R2I_Category=TC_CONVERSION S2I=0,1,integer,string _S2I_Defaults=GetEventPlayerChatString _S2I_Category=TC_CONVERSION GetElevatorHeight=1,1,integer,destructable _GetElevatorHeight_Defaults=_ _GetElevatorHeight_Category=TC_DESTRUCT GetTerrainCliffLevelBJ=1,1,integer,location _GetTerrainCliffLevelBJ_Defaults=GetRectCenter _GetTerrainCliffLevelBJ_Category=TC_ENVIRONMENT GetTerrainTypeBJ=1,1,terraintype,location _GetTerrainTypeBJ_Defaults=GetRectCenter _GetTerrainTypeBJ_Category=TC_ENVIRONMENT GetTerrainVarianceBJ=1,1,integer,location _GetTerrainVarianceBJ_Defaults=GetRectCenter _GetTerrainVarianceBJ_Category=TC_ENVIRONMENT IsTerrainPathableBJ=1,1,integer,location,pathingtype _IsTerrainPathableBJ_Defaults=GetRectCenter,PathingTypeAny _IsTerrainPathableBJ_Category=TC_ENVIRONMENT GetLearnedSkillLevel=0,0,integer _GetLearnedSkillLevel_Defaults= _GetLearnedSkillLevel_Category=TC_EVENTRESPONSE GetPlayers=0,1,integer _GetPlayers_Defaults= _GetPlayers_Category=TC_GAME GetTeams=0,1,integer _GetTeams_Defaults= _GetTeams_Category=TC_GAME GetAllyColorFilterState=1,1,integer _GetAllyColorFilterState_Defaults= _GetAllyColorFilterState_Category=TC_GAME GetTournamentFinishNowRule=1,0,integer _GetTournamentFinishNowRule_Defaults= _GetTournamentFinishNowRule_Category=TC_GAME GetTournamentScore=1,0,integer,player _GetTournamentScore_Defaults=Player00 _GetTournamentScore_Category=TC_GAME GetStoredIntegerBJ=0,0,integer,string,string,gamecache _GetStoredIntegerBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredIntegerBJ_Category=TC_GAMECACHE GetHeroLevel=0,1,integer,unit _GetHeroLevel_Defaults=GetTriggerUnit _GetHeroLevel_Category=TC_HERO GetHeroXP=0,1,integer,unit _GetHeroXP_Defaults=GetTriggerUnit _GetHeroXP_Category=TC_HERO GetHeroStatBJ=1,1,integer,herostat,unit,includeoption _GetHeroStatBJ_Defaults=HeroStatStr,_,InclusionExclude _GetHeroStatBJ_Category=TC_HERO GetHeroSkillPoints=1,1,integer,unit _GetHeroSkillPoints_Defaults=_ _GetHeroSkillPoints_Category=TC_HERO GetItemLevel=1,1,integer,item _GetItemLevel_Defaults=GetLastCreatedItem _GetItemLevel_Category=TC_ITEM GetItemCharges=1,1,integer,item _GetItemCharges_Defaults=GetLastCreatedItem _GetItemCharges_Category=TC_ITEM GetItemUserData=1,1,integer,item _GetItemUserData_Defaults=_ _GetItemUserData_Category=TC_ITEM LeaderboardGetPlayerIndexBJ=0,0,integer,player,leaderboard _LeaderboardGetPlayerIndexBJ_Defaults=Player00,GetLastCreatedLeaderboard _LeaderboardGetPlayerIndexBJ_Category=TC_LEADERBOARD GetRandomInt=0,1,integer,integer,integer _GetRandomInt_Defaults=1,10 _GetRandomInt_Category=TC_MATH IMinBJ=0,1,integer,integer,integer _IMinBJ_Defaults=_,_ _IMinBJ_Category=TC_MATH IMaxBJ=0,1,integer,integer,integer _IMaxBJ_Defaults=_,_ _IMaxBJ_Category=TC_MATH IAbsBJ=0,1,integer,integer _IAbsBJ_Defaults=_ _IAbsBJ_Category=TC_MATH ISignBJ=0,1,integer,integer _ISignBJ_Defaults=_ _ISignBJ_Category=TC_MATH ModuloInteger=0,1,integer,integer,integer _ModuloInteger_Defaults=_,_ _ModuloInteger_Category=TC_MATH MultiboardGetRowCount=1,1,integer,multiboard _MultiboardGetRowCount_Defaults=GetLastCreatedMultiboard _MultiboardGetRowCount_Category=TC_MULTIBOARD MultiboardGetColumnCount=1,1,integer,multiboard _MultiboardGetColumnCount_Defaults=GetLastCreatedMultiboard _MultiboardGetColumnCount_Category=TC_MULTIBOARD GetResourceAmount=0,1,integer,unit _GetResourceAmount_Defaults=_ _GetResourceAmount_Category=TC_NEUTRALBUILDING GetPlayerState=0,1,integer,player,playerstate _GetPlayerState_Defaults=Player00,PlayerStateGold _GetPlayerState_Category=TC_PLAYER GetPlayerTaxRateBJ=1,1,integer,playerresource,player,player _GetPlayerTaxRateBJ_Defaults=PlayerResourceGold,Player00,Player01 _GetPlayerTaxRateBJ_Category=TC_PLAYER GetPlayerScore=1,1,integer,player,playerscore _GetPlayerScore_Defaults=Player00,PlayerScoreTotal _GetPlayerScore_Category=TC_PLAYER GetConvertedPlayerId=0,1,integer,player _GetConvertedPlayerId_Defaults=GetTriggerPlayer _GetConvertedPlayerId_Category=TC_PLAYER GetPlayerStructureCount=0,1,integer,player,includeoption _GetPlayerStructureCount_Defaults=Player00,InclusionExclude _GetPlayerStructureCount_Category=TC_PLAYER GetPlayerUnitCount=0,1,integer,player,includeoption _GetPlayerUnitCount_Defaults=Player00,InclusionExclude _GetPlayerUnitCount_Category=TC_PLAYER GetPlayerTechCountSimple=0,1,integer,techcode,player _GetPlayerTechCountSimple_Defaults=_,Player00 _GetPlayerTechCountSimple_Category=TC_PLAYER GetPlayerTechMaxAllowedSwap=0,1,integer,techcode,player _GetPlayerTechMaxAllowedSwap_Defaults=_,Player00 _GetPlayerTechMaxAllowedSwap_Category=TC_PLAYER GetPlayerTeam=0,1,integer,player _GetPlayerTeam_Defaults=Player00 _GetPlayerTeam_Category=TC_PLAYER CountPlayersInForceBJ=0,1,integer,force _CountPlayersInForceBJ_Defaults=GetPlayersByMapControl _CountPlayersInForceBJ_Category=TC_PLAYER CountUnitsInGroup=0,1,integer,group _CountUnitsInGroup_Defaults=GetUnitsInRectAll _CountUnitsInGroup_Category=TC_UNIT CountLivingPlayerUnitsOfTypeId=1,1,integer,unitcode,player _CountLivingPlayerUnitsOfTypeId_Defaults=hfoo,Player00 _CountLivingPlayerUnitsOfTypeId_Category=TC_UNIT GetUnitFoodUsed=0,1,integer,unit _GetUnitFoodUsed_Defaults=GetTriggerUnit _GetUnitFoodUsed_Category=TC_UNIT GetUnitFoodMade=0,1,integer,unit _GetUnitFoodMade_Defaults=GetTriggerUnit _GetUnitFoodMade_Category=TC_UNIT GetFoodUsed=1,1,integer,unitcode _GetFoodUsed_Defaults=hfoo _GetFoodUsed_Category=TC_UNIT GetFoodMade=0,1,integer,unitcode _GetFoodMade_Defaults=hfoo _GetFoodMade_Category=TC_UNIT GetUnitPointValue=0,1,integer,unit _GetUnitPointValue_Defaults=GetTriggerUnit _GetUnitPointValue_Category=TC_UNIT GetUnitPointValueByType=0,1,integer,unitcode _GetUnitPointValueByType_Defaults=hfoo _GetUnitPointValueByType_Category=TC_UNIT GetUnitUserData=1,1,integer,unit _GetUnitUserData_Defaults=_ _GetUnitUserData_Category=TC_UNIT GetUnitLevel=1,1,integer,unit _GetUnitLevel_Defaults=GetTriggerUnit _GetUnitLevel_Category=TC_UNIT GetUnitAbilityLevelSwapped=1,1,integer,abilcode,unit _GetUnitAbilityLevelSwapped_Defaults=_,GetTriggerUnit _GetUnitAbilityLevelSwapped_Category=TC_UNIT UnitInventoryCount=1,1,integer,unit _UnitInventoryCount_Defaults=GetTriggerUnit _UnitInventoryCount_Category=TC_UNIT UnitCountBuffsExBJ=1,1,integer,buffpolarity,buffresist,unit,includeoption,includeoption _UnitCountBuffsExBJ_Defaults=BuffPolarityEither,BuffResistEither,GetTriggerUnit,InclusionInclude,InclusionInclude _UnitCountBuffsExBJ_Category=TC_UNIT GetTriggerEvalCount=0,1,integer,trigger _GetTriggerEvalCount_Defaults=GetTriggeringTrigger _GetTriggerEvalCount_Category=TC_TRIGGER GetTriggerExecCount=0,1,integer,trigger _GetTriggerExecCount_Defaults=GetTriggeringTrigger _GetTriggerExecCount_Category=TC_TRIGGER QueuedTriggerCountBJ=0,0,integer _QueuedTriggerCountBJ_Defaults= _QueuedTriggerCountBJ_Category=TC_TRIGGER OperatorReal=0,1,real,real,ArithmeticOperator,real _OperatorReal_Defaults=1,OperatorAdd,1 _OperatorReal_Category=TC_ARITHMETIC GetLocationX=0,1,real,location _GetLocationX_Defaults=GetRectCenter _GetLocationX_Category=TC_NOTHING GetLocationY=0,1,real,location _GetLocationY_Defaults=GetRectCenter _GetLocationY_Category=TC_NOTHING CameraSetupGetFieldSwap=0,1,real,camerafield,camerasetup _CameraSetupGetFieldSwap_Defaults=CameraFieldTargetDistance,_ _CameraSetupGetFieldSwap_Category=TC_CAMERA GetCameraField=0,1,real,camerafield _GetCameraField_Defaults=CameraFieldTargetDistance _GetCameraField_Category=TC_CAMERA GetCameraTargetPositionX=0,1,real _GetCameraTargetPositionX_Defaults= _GetCameraTargetPositionX_Category=TC_CAMERA GetCameraTargetPositionY=0,1,real _GetCameraTargetPositionY_Defaults= _GetCameraTargetPositionY_Category=TC_CAMERA GetCameraTargetPositionZ=0,1,real _GetCameraTargetPositionZ_Defaults= _GetCameraTargetPositionZ_Category=TC_CAMERA GetCameraEyePositionX=0,1,real _GetCameraEyePositionX_Defaults= _GetCameraEyePositionX_Category=TC_CAMERA GetCameraEyePositionY=0,1,real _GetCameraEyePositionY_Defaults= _GetCameraEyePositionY_Category=TC_CAMERA GetCameraEyePositionZ=0,1,real _GetCameraEyePositionZ_Defaults= _GetCameraEyePositionZ_Category=TC_CAMERA GetLastTransmissionDurationBJ=0,1,real _GetLastTransmissionDurationBJ_Defaults= _GetLastTransmissionDurationBJ_Category=TC_CINEMATIC I2R=0,1,real,integer _I2R_Defaults=GetUnitPointValueByType _I2R_Category=TC_CONVERSION S2R=0,1,real,string _S2R_Defaults=GetEventPlayerChatString _S2R_Category=TC_CONVERSION Deg2Rad=0,1,real,real _Deg2Rad_Defaults=0 _Deg2Rad_Category=TC_CONVERSION Rad2Deg=0,1,real,real _Rad2Deg_Defaults=0 _Rad2Deg_Category=TC_CONVERSION TimerGetElapsed=0,1,real,timer _TimerGetElapsed_Defaults=_ _TimerGetElapsed_Category=TC_TIMER TimerGetRemaining=0,1,real,timer _TimerGetRemaining_Defaults=_ _TimerGetRemaining_Category=TC_TIMER TimerGetTimeout=0,1,real,timer _TimerGetTimeout_Defaults=_ _TimerGetTimeout_Category=TC_TIMER GetDestructableLife=0,1,real,destructable _GetDestructableLife_Defaults=GetLastCreatedDestructable _GetDestructableLife_Category=TC_DESTRUCT GetDestructableMaxLife=0,1,real,destructable _GetDestructableMaxLife_Defaults=GetLastCreatedDestructable _GetDestructableMaxLife_Category=TC_DESTRUCT GetDestructableOccluderHeight=1,1,real,destructable _GetDestructableOccluderHeight_Defaults=GetLastCreatedDestructable _GetDestructableOccluderHeight_Category=TC_DESTRUCT GetEventDamage=0,0,real _GetEventDamage_Defaults= _GetEventDamage_Category=TC_EVENTRESPONSE GetTournamentFinishSoonTimeRemaining=1,0,real _GetTournamentFinishSoonTimeRemaining_Defaults= _GetTournamentFinishSoonTimeRemaining_Category=TC_EVENTRESPONSE GetTimeOfDay=0,1,real _GetTimeOfDay_Defaults= _GetTimeOfDay_Category=TC_GAME GetTimeOfDayScalePercentBJ=0,1,real _GetTimeOfDayScalePercentBJ_Defaults= _GetTimeOfDayScalePercentBJ_Category=TC_GAME GetStoredRealBJ=0,0,real,string,string,gamecache _GetStoredRealBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredRealBJ_Category=TC_GAMECACHE GetItemLifeBJ=0,0,real,item _GetItemLifeBJ_Defaults=GetLastCreatedItem _GetItemLifeBJ_Category=TC_ITEM GetRandomReal=0,1,real,real,real _GetRandomReal_Defaults=0,1 _GetRandomReal_Category=TC_MATH GetRandomDirectionDeg=0,1,real _GetRandomDirectionDeg_Defaults= _GetRandomDirectionDeg_Category=TC_MATH GetRandomPercentageBJ=0,1,real _GetRandomPercentageBJ_Defaults= _GetRandomPercentageBJ_Category=TC_MATH DistanceBetweenPoints=0,1,real,location,location _DistanceBetweenPoints_Defaults=GetUnitLoc,GetUnitLoc _DistanceBetweenPoints_Category=TC_MATH AngleBetweenPoints=0,1,real,location,location _AngleBetweenPoints_Defaults=GetUnitLoc,GetUnitLoc _AngleBetweenPoints_Category=TC_MATH RMinBJ=0,1,real,real,real _RMinBJ_Defaults=_,_ _RMinBJ_Category=TC_MATH RMaxBJ=0,1,real,real,real _RMaxBJ_Defaults=_,_ _RMaxBJ_Category=TC_MATH RAbsBJ=0,1,real,real _RAbsBJ_Defaults=_ _RAbsBJ_Category=TC_MATH RSignBJ=0,1,real,real _RSignBJ_Defaults=_ _RSignBJ_Category=TC_MATH ModuloReal=0,1,real,real,real _ModuloReal_Defaults=_,_ _ModuloReal_Category=TC_MATH Pow=0,1,real,real,real _Pow_Defaults=_,_ _Pow_Category=TC_MATH SquareRoot=0,1,real,real _SquareRoot_Defaults=_ _SquareRoot_Limits=0,_ _SquareRoot_Category=TC_MATH SinBJ=0,1,real,real _SinBJ_Defaults=GetUnitFacing _SinBJ_Category=TC_MATH CosBJ=0,1,real,real _CosBJ_Defaults=GetUnitFacing _CosBJ_Category=TC_MATH TanBJ=0,1,real,real _TanBJ_Defaults=GetUnitFacing _TanBJ_Category=TC_MATH AsinBJ=0,1,real,real _AsinBJ_Defaults=_ _AsinBJ_Limits=-1,1 _AsinBJ_Category=TC_MATH AcosBJ=0,1,real,real _AcosBJ_Defaults=_ _AcosBJ_Limits=-1,1 _AcosBJ_Category=TC_MATH AtanBJ=0,1,real,real _AtanBJ_Defaults=_ _AtanBJ_Category=TC_MATH Atan2BJ=0,1,real,real,real _Atan2BJ_Defaults=_,_ _Atan2BJ_Category=TC_MATH GetPlayerHandicapXPBJ=0,0,real,player _GetPlayerHandicapXPBJ_Defaults=Player00 _GetPlayerHandicapXPBJ_Category=TC_PLAYER GetPlayerHandicapBJ=0,0,real,player _GetPlayerHandicapBJ_Defaults=Player00 _GetPlayerHandicapBJ_Category=TC_PLAYER GetLocationZ=1,1,real,location _GetLocationZ_Defaults=GetUnitLoc _GetLocationZ_Category=TC_LOCATION GetRectCenterX=0,1,real,rect _GetRectCenterX_Defaults=GetPlayableMapRect _GetRectCenterX_Category=TC_REGION GetRectCenterY=0,1,real,rect _GetRectCenterY_Defaults=GetPlayableMapRect _GetRectCenterY_Category=TC_REGION GetRectMinX=0,1,real,rect _GetRectMinX_Defaults=GetPlayableMapRect _GetRectMinX_Category=TC_REGION GetRectMinY=0,1,real,rect _GetRectMinY_Defaults=GetPlayableMapRect _GetRectMinY_Category=TC_REGION GetRectMaxX=0,1,real,rect _GetRectMaxX_Defaults=GetPlayableMapRect _GetRectMaxX_Category=TC_REGION GetRectMaxY=0,1,real,rect _GetRectMaxY_Defaults=GetPlayableMapRect _GetRectMaxY_Category=TC_REGION GetRectWidthBJ=0,1,real,rect _GetRectWidthBJ_Defaults=_ _GetRectWidthBJ_Category=TC_REGION GetRectHeightBJ=0,1,real,rect _GetRectHeightBJ_Defaults=_ _GetRectHeightBJ_Category=TC_REGION GetSoundDurationBJ=0,1,real,sound _GetSoundDurationBJ_Defaults=GetLastPlayedSound _GetSoundDurationBJ_Category=TC_SOUND GetSoundFileDurationBJ=0,1,real,musicfile _GetSoundFileDurationBJ_Defaults=GetLastPlayedMusic _GetSoundFileDurationBJ_Category=TC_SOUND GetUnitStateSwap=0,1,real,unitstate,unit _GetUnitStateSwap_Defaults=UnitStateLife,GetTriggerUnit _GetUnitStateSwap_Category=TC_UNIT GetUnitLifePercent=1,1,real,unit _GetUnitLifePercent_Defaults=GetTriggerUnit _GetUnitLifePercent_Category=TC_UNIT GetUnitManaPercent=1,1,real,unit _GetUnitManaPercent_Defaults=GetTriggerUnit _GetUnitManaPercent_Category=TC_UNIT GetUnitFacing=0,1,real,unit _GetUnitFacing_Defaults=GetTriggerUnit _GetUnitFacing_Category=TC_UNIT GetUnitMoveSpeed=0,1,real,unit _GetUnitMoveSpeed_Defaults=GetTriggerUnit _GetUnitMoveSpeed_Category=TC_UNIT GetUnitDefaultMoveSpeed=0,1,real,unit _GetUnitDefaultMoveSpeed_Defaults=GetTriggerUnit _GetUnitDefaultMoveSpeed_Category=TC_UNIT GetUnitAcquireRange=0,1,real,unit _GetUnitAcquireRange_Defaults=GetTriggerUnit _GetUnitAcquireRange_Category=TC_UNIT GetUnitDefaultAcquireRange=0,1,real,unit _GetUnitDefaultAcquireRange_Defaults=GetTriggerUnit _GetUnitDefaultAcquireRange_Category=TC_UNIT GetUnitTurnSpeed=0,1,real,unit _GetUnitTurnSpeed_Defaults=GetTriggerUnit _GetUnitTurnSpeed_Category=TC_UNIT GetUnitDefaultTurnSpeed=0,1,real,unit _GetUnitDefaultTurnSpeed_Defaults=GetTriggerUnit _GetUnitDefaultTurnSpeed_Category=TC_UNIT GetUnitPropWindowBJ=0,1,real,unit _GetUnitPropWindowBJ_Defaults=GetTriggerUnit _GetUnitPropWindowBJ_Category=TC_UNIT GetUnitDefaultPropWindowBJ=0,1,real,unit _GetUnitDefaultPropWindowBJ_Defaults=GetTriggerUnit _GetUnitDefaultPropWindowBJ_Category=TC_UNIT GetUnitFlyHeight=0,1,real,unit _GetUnitFlyHeight_Defaults=GetTriggerUnit _GetUnitFlyHeight_Category=TC_UNIT GetUnitDefaultFlyHeight=0,1,real,unit _GetUnitDefaultFlyHeight_Defaults=GetTriggerUnit _GetUnitDefaultFlyHeight_Category=TC_UNIT OperatorString=0,1,string,string,string _OperatorString_Defaults=_,_ _OperatorString_Category=TC_NOTHING SubStringBJ=0,1,string,string,integer,integer _SubStringBJ_Defaults=_,1,5 _SubStringBJ_Category=TC_NOTHING GetAbilityName=1,1,string,abilcode _GetAbilityName_Defaults=_ _GetAbilityName_Category=TC_NOTHING _GetAbilityName_ScriptName=GetObjectName I2S=0,1,string,integer _I2S_Defaults=GetConvertedPlayerId _I2S_Category=TC_CONVERSION R2S=0,1,string,real _R2S_Defaults=GetUnitStateSwap _R2S_Category=TC_CONVERSION R2SW=0,1,string,real,integer,integer _R2SW_Defaults=GetUnitStateSwap,1,2 _R2SW_Limits=_,_,0,_,0,_ _R2SW_Category=TC_CONVERSION OrderId2StringBJ=0,1,string,ordercode _OrderId2StringBJ_Defaults=GetIssuedOrderIdBJ _OrderId2StringBJ_Category=TC_CONVERSION UnitId2StringBJ=0,1,string,unitcode _UnitId2StringBJ_Defaults=GetUnitTypeId _UnitId2StringBJ_Category=TC_CONVERSION StringIdentity=1,0,string,StringExt _StringIdentity_Defaults=_ _StringIdentity_Category=TC_CONVERSION StringCase=1,1,string,StringExt,stringcaseoption _StringCase_Defaults=_,StringCaseLower _StringCase_Category=TC_CONVERSION GetDestructableName=1,1,string,destructable _GetDestructableName_Defaults=GetLastCreatedDestructable _GetDestructableName_Category=TC_DESTRUCT GetEventPlayerChatString=0,0,string _GetEventPlayerChatString_Defaults= _GetEventPlayerChatString_Category=TC_EVENTRESPONSE GetEventPlayerChatStringMatched=0,0,string _GetEventPlayerChatStringMatched_Defaults= _GetEventPlayerChatStringMatched_Category=TC_EVENTRESPONSE GetSaveBasicFilename=1,0,string _GetSaveBasicFilename_Defaults= _GetSaveBasicFilename_Category=TC_EVENTRESPONSE GetStoredStringBJ=1,0,string,string,string,gamecache _GetStoredStringBJ_Defaults=_,"Category",GetLastCreatedGameCacheBJ _GetStoredStringBJ_Category=TC_GAMECACHE GetHeroProperName=1,1,string,unit _GetHeroProperName_Defaults=GetTriggerUnit _GetHeroProperName_Category=TC_HERO GetItemName=1,1,string,item _GetItemName_Defaults=GetLastCreatedItem _GetItemName_Category=TC_ITEM MultiboardGetTitleText=1,1,string,multiboard _MultiboardGetTitleText_Defaults=GetLastCreatedMultiboard _MultiboardGetTitleText_Category=TC_MULTIBOARD GetPlayerName=0,1,string,player _GetPlayerName_Defaults=GetTriggerPlayer _GetPlayerName_Category=TC_PLAYER GetUnitName=0,1,string,unit _GetUnitName_Defaults=GetTriggerUnit _GetUnitName_Category=TC_UNIT GetRectCenter=0,1,location,rect _GetRectCenter_Defaults=GetPlayableMapRect _GetRectCenter_Category=TC_NOTHING GetRandomLocInRect=0,1,location,rect _GetRandomLocInRect_Defaults=GetPlayableMapRect _GetRandomLocInRect_Category=TC_NOTHING OffsetLocation=0,1,location,location,real,real _OffsetLocation_Defaults=GetRectCenter,0,0 _OffsetLocation_Category=TC_NOTHING PolarProjectionBJ=0,1,location,location,real,real _PolarProjectionBJ_Defaults=GetRectCenter,256,0 _PolarProjectionBJ_Category=TC_NOTHING CameraSetupGetDestPositionLoc=0,1,location,camerasetup _CameraSetupGetDestPositionLoc_Defaults=_ _CameraSetupGetDestPositionLoc_Category=TC_CAMERA GetCameraTargetPositionLoc=0,1,location _GetCameraTargetPositionLoc_Defaults= _GetCameraTargetPositionLoc_Category=TC_CAMERA GetCameraEyePositionLoc=0,1,location _GetCameraEyePositionLoc_Defaults= _GetCameraEyePositionLoc_Category=TC_CAMERA Location=0,1,location,real,real _Location_Defaults=0,0 _Location_Category=TC_CONVERSION GetDestructableLoc=0,1,location,destructable _GetDestructableLoc_Defaults=GetLastCreatedDestructable _GetDestructableLoc_Category=TC_DESTRUCT GetOrderPointLoc=0,0,location _GetOrderPointLoc_Defaults= _GetOrderPointLoc_Category=TC_EVENTRESPONSE GetSpellTargetLoc=1,0,location _GetSpellTargetLoc_Defaults= _GetSpellTargetLoc_Category=TC_EVENTRESPONSE GetItemLoc=0,1,location,item _GetItemLoc_Defaults=GetLastCreatedItem _GetItemLoc_Category=TC_ITEM WaygateGetDestinationLocBJ=0,0,location,unit _WaygateGetDestinationLocBJ_Defaults=_ _WaygateGetDestinationLocBJ_Category=TC_NEUTRALBUILDING GetPlayerStartLocationLoc=0,1,location,player _GetPlayerStartLocationLoc_Defaults=Player00 _GetPlayerStartLocationLoc_Category=TC_PLAYER GetUnitLoc=0,1,location,unit _GetUnitLoc_Defaults=GetTriggerUnit _GetUnitLoc_Category=TC_UNIT GetUnitRallyPoint=1,1,location,unit _GetUnitRallyPoint_Defaults=GetTriggerUnit _GetUnitRallyPoint_Category=TC_UNIT GetCurrentCameraBoundsMapRectBJ=0,1,rect _GetCurrentCameraBoundsMapRectBJ_Defaults= _GetCurrentCameraBoundsMapRectBJ_Category=TC_NOTHING GetCameraBoundsMapRect=0,1,rect _GetCameraBoundsMapRect_Defaults= _GetCameraBoundsMapRect_Category=TC_NOTHING GetPlayableMapRect=0,1,rect _GetPlayableMapRect_Defaults= _GetPlayableMapRect_Category=TC_NOTHING GetEntireMapRect=0,1,rect _GetEntireMapRect_Defaults= _GetEntireMapRect_Category=TC_NOTHING OffsetRectBJ=0,0,rect,rect,real,real _OffsetRectBJ_Defaults=_,0,0 _OffsetRectBJ_Category=TC_NOTHING RectFromCenterSizeBJ=0,1,rect,location,real,real _RectFromCenterSizeBJ_Defaults=GetUnitLoc,_,_ _RectFromCenterSizeBJ_Category=TC_CONVERSION Rect=0,1,rect,real,real,real,real _Rect_Defaults=0,0,0,0 _Rect_Category=TC_CONVERSION RectFromLoc=0,1,rect,location,location _RectFromLoc_Defaults=Location,Location _RectFromLoc_Category=TC_CONVERSION GetLastCreatedUnit=0,0,unit _GetLastCreatedUnit_Defaults= _GetLastCreatedUnit_Category=TC_LAST GetLastRestoredUnitBJ=0,0,unit _GetLastRestoredUnitBJ_Defaults= _GetLastRestoredUnitBJ_Category=TC_LAST GetLastReplacedUnitBJ=0,0,unit _GetLastReplacedUnitBJ_Defaults= _GetLastReplacedUnitBJ_Category=TC_LAST GetLastHauntedGoldMine=0,0,unit _GetLastHauntedGoldMine_Defaults= _GetLastHauntedGoldMine_Category=TC_LAST GetEnumUnit=0,0,unit _GetEnumUnit_Defaults= _GetEnumUnit_Category=TC_NOTHING GetFilterUnit=0,0,unit _GetFilterUnit_Defaults= _GetFilterUnit_Category=TC_NOTHING GroupPickRandomUnit=0,0,unit,group _GroupPickRandomUnit_Defaults=_ _GroupPickRandomUnit_Category=TC_NOTHING GetAttackedUnitBJ=0,0,unit _GetAttackedUnitBJ_Defaults= _GetAttackedUnitBJ_Category=TC_EVENTRESPONSE GetAttacker=0,0,unit _GetAttacker_Defaults= _GetAttacker_Category=TC_EVENTRESPONSE GetBuyingUnit=1,0,unit _GetBuyingUnit_Defaults= _GetBuyingUnit_Category=TC_EVENTRESPONSE GetCancelledStructure=0,0,unit _GetCancelledStructure_Defaults= _GetCancelledStructure_Category=TC_EVENTRESPONSE GetSpellAbilityUnit=1,0,unit _GetSpellAbilityUnit_Defaults= _GetSpellAbilityUnit_Category=TC_EVENTRESPONSE GetConstructingStructure=0,0,unit _GetConstructingStructure_Defaults= _GetConstructingStructure_Category=TC_EVENTRESPONSE GetConstructedStructure=0,0,unit _GetConstructedStructure_Defaults= _GetConstructedStructure_Category=TC_EVENTRESPONSE GetDecayingUnit=0,0,unit _GetDecayingUnit_Defaults= _GetDecayingUnit_Category=TC_EVENTRESPONSE GetDyingUnit=0,0,unit _GetDyingUnit_Defaults= _GetDyingUnit_Category=TC_EVENTRESPONSE GetEnteringUnit=0,0,unit _GetEnteringUnit_Defaults= _GetEnteringUnit_Category=TC_EVENTRESPONSE GetManipulatingUnit=0,0,unit _GetManipulatingUnit_Defaults= _GetManipulatingUnit_Category=TC_EVENTRESPONSE GetKillingUnitBJ=0,0,unit _GetKillingUnitBJ_Defaults= _GetKillingUnitBJ_Category=TC_EVENTRESPONSE GetLearningUnit=0,0,unit _GetLearningUnit_Defaults= _GetLearningUnit_Category=TC_EVENTRESPONSE GetLeavingUnit=0,0,unit _GetLeavingUnit_Defaults= _GetLeavingUnit_Category=TC_EVENTRESPONSE GetLevelingUnit=0,0,unit _GetLevelingUnit_Defaults= _GetLevelingUnit_Category=TC_EVENTRESPONSE GetLoadedUnitBJ=0,0,unit _GetLoadedUnitBJ_Defaults= _GetLoadedUnitBJ_Category=TC_EVENTRESPONSE GetOrderedUnit=0,0,unit _GetOrderedUnit_Defaults= _GetOrderedUnit_Category=TC_EVENTRESPONSE GetChangingUnit=1,0,unit _GetChangingUnit_Defaults= _GetChangingUnit_Category=TC_EVENTRESPONSE GetResearchingUnit=0,0,unit _GetResearchingUnit_Defaults= _GetResearchingUnit_Category=TC_EVENTRESPONSE GetRevivableUnit=0,0,unit _GetRevivableUnit_Defaults= _GetRevivableUnit_Category=TC_EVENTRESPONSE GetRevivingUnit=0,0,unit _GetRevivingUnit_Defaults= _GetRevivingUnit_Category=TC_EVENTRESPONSE GetSellingUnit=1,0,unit _GetSellingUnit_Defaults= _GetSellingUnit_Category=TC_EVENTRESPONSE GetSoldUnit=1,0,unit _GetSoldUnit_Defaults= _GetSoldUnit_Category=TC_EVENTRESPONSE GetSummonedUnit=0,0,unit _GetSummonedUnit_Defaults= _GetSummonedUnit_Category=TC_EVENTRESPONSE GetSummoningUnit=0,0,unit _GetSummoningUnit_Defaults= _GetSummoningUnit_Category=TC_EVENTRESPONSE GetOrderTargetUnit=0,0,unit _GetOrderTargetUnit_Defaults= _GetOrderTargetUnit_Category=TC_EVENTRESPONSE GetSpellTargetUnit=1,0,unit _GetSpellTargetUnit_Defaults= _GetSpellTargetUnit_Category=TC_EVENTRESPONSE GetEventTargetUnit=0,0,unit _GetEventTargetUnit_Defaults= _GetEventTargetUnit_Category=TC_EVENTRESPONSE GetTrainedUnit=0,0,unit _GetTrainedUnit_Defaults= _GetTrainedUnit_Category=TC_EVENTRESPONSE GetTransportUnitBJ=0,0,unit _GetTransportUnitBJ_Defaults= _GetTransportUnitBJ_Category=TC_EVENTRESPONSE GetTriggerUnit=0,0,unit _GetTriggerUnit_Defaults= _GetTriggerUnit_Category=TC_EVENTRESPONSE GetUnitRallyUnit=1,0,unit,unit _GetUnitRallyUnit_Defaults=GetTriggerUnit _GetUnitRallyUnit_Category=TC_UNIT GetUnitTypeId=0,1,unitcode,unit _GetUnitTypeId_Defaults=GetTriggerUnit _GetUnitTypeId_Category=TC_NOTHING ChooseRandomCreepBJ=0,1,unitcode,integer _ChooseRandomCreepBJ_Defaults=1 _ChooseRandomCreepBJ_Limits=-1,10 _ChooseRandomCreepBJ_Category=TC_NOTHING ChooseRandomNPBuildingBJ=0,1,unitcode _ChooseRandomNPBuildingBJ_Defaults= _ChooseRandomNPBuildingBJ_Category=TC_NOTHING String2UnitIdBJ=0,1,unitcode,string _String2UnitIdBJ_Defaults=footman _String2UnitIdBJ_Category=TC_CONVERSION GetTrainedUnitType=0,0,unitcode _GetTrainedUnitType_Defaults= _GetTrainedUnitType_Category=TC_EVENTRESPONSE String2OrderIdBJ=0,0,ordercode,string _String2OrderIdBJ_Defaults=stop _String2OrderIdBJ_Category=TC_CONVERSION UnitId2OrderIdBJ=0,0,ordercode,unitcode _UnitId2OrderIdBJ_Defaults=hfoo _UnitId2OrderIdBJ_Category=TC_CONVERSION GetIssuedOrderIdBJ=0,0,ordercode _GetIssuedOrderIdBJ_Defaults= _GetIssuedOrderIdBJ_Category=TC_EVENTRESPONSE GetUnitCurrentOrder=1,0,ordercode,unit _GetUnitCurrentOrder_Defaults=GetTriggerUnit _GetUnitCurrentOrder_Category=TC_UNIT GetLastCreatedDestructable=0,0,destructable _GetLastCreatedDestructable_Defaults= _GetLastCreatedDestructable_Category=TC_LAST RandomDestructableInRectSimpleBJ=0,0,destructable,rect _RandomDestructableInRectSimpleBJ_Defaults=_ _RandomDestructableInRectSimpleBJ_Category=TC_NOTHING RandomDestructableInRectBJ=0,0,destructable,rect,boolexpr _RandomDestructableInRectBJ_Defaults=_,_ _RandomDestructableInRectBJ_Category=TC_NOTHING GetEnumDestructable=0,0,destructable _GetEnumDestructable_Defaults= _GetEnumDestructable_Category=TC_NOTHING GetFilterDestructable=0,0,destructable _GetFilterDestructable_Defaults= _GetFilterDestructable_Category=TC_NOTHING GetDyingDestructable=0,0,destructable _GetDyingDestructable_Defaults= _GetDyingDestructable_Category=TC_EVENTRESPONSE GetOrderTargetDestructable=0,0,destructable _GetOrderTargetDestructable_Defaults= _GetOrderTargetDestructable_Category=TC_EVENTRESPONSE GetSpellTargetDestructable=1,0,destructable _GetSpellTargetDestructable_Defaults= _GetSpellTargetDestructable_Category=TC_EVENTRESPONSE GetUnitRallyDestructable=1,0,destructable,unit _GetUnitRallyDestructable_Defaults=GetTriggerUnit _GetUnitRallyDestructable_Category=TC_UNIT GetDestructableTypeId=0,1,destructablecode,destructable _GetDestructableTypeId_Defaults=GetLastCreatedDestructable _GetDestructableTypeId_Category=TC_NOTHING GetLastCreatedItem=0,0,item _GetLastCreatedItem_Defaults= _GetLastCreatedItem_Category=TC_LAST GetLastRemovedItem=0,0,item _GetLastRemovedItem_Defaults= _GetLastRemovedItem_Category=TC_LAST RandomItemInRectSimpleBJ=1,0,item,rect _RandomItemInRectSimpleBJ_Defaults=_ _RandomItemInRectSimpleBJ_Category=TC_NOTHING RandomItemInRectBJ=1,0,item,rect,boolexpr _RandomItemInRectBJ_Defaults=_,_ _RandomItemInRectBJ_Category=TC_NOTHING GetEnumItem=1,0,item _GetEnumItem_Defaults= _GetEnumItem_Category=TC_NOTHING GetFilterItem=1,0,item _GetFilterItem_Defaults= _GetFilterItem_Category=TC_NOTHING UnitItemInSlotBJ=0,0,item,unit,integer _UnitItemInSlotBJ_Defaults=_,1 _UnitItemInSlotBJ_Limits=_,_,1,6 _UnitItemInSlotBJ_Category=TC_NOTHING GetItemOfTypeFromUnitBJ=0,0,item,unit,itemcode _GetItemOfTypeFromUnitBJ_Defaults=_,texp _GetItemOfTypeFromUnitBJ_Category=TC_NOTHING GetManipulatedItem=0,0,item _GetManipulatedItem_Defaults= _GetManipulatedItem_Category=TC_EVENTRESPONSE GetSoldItem=1,0,item _GetSoldItem_Defaults= _GetSoldItem_Category=TC_EVENTRESPONSE GetOrderTargetItem=0,0,item _GetOrderTargetItem_Defaults= _GetOrderTargetItem_Category=TC_EVENTRESPONSE GetSpellTargetItem=1,0,item _GetSpellTargetItem_Defaults= _GetSpellTargetItem_Category=TC_EVENTRESPONSE GetItemType=1,1,itemtype,item _GetItemType_Defaults=GetLastCreatedItem _GetItemType_Category=TC_NOTHING GetItemTypeId=0,1,itemcode,item _GetItemTypeId_Defaults=GetLastCreatedItem _GetItemTypeId_Category=TC_NOTHING ChooseRandomItemBJ=0,1,itemcode,integer _ChooseRandomItemBJ_Defaults=1 _ChooseRandomItemBJ_Limits=-1,10 _ChooseRandomItemBJ_Category=TC_NOTHING ChooseRandomItemExBJ=1,1,itemcode,integer,itemtype _ChooseRandomItemExBJ_Defaults=1,ItemTypeAny _ChooseRandomItemExBJ_Limits=-1,8,_,_ _ChooseRandomItemExBJ_Category=TC_NOTHING GetResearched=0,1,techcode _GetResearched_Defaults= _GetResearched_Category=TC_EVENTRESPONSE GetSpellAbilityId=1,0,abilcode _GetSpellAbilityId_Defaults= _GetSpellAbilityId_Category=TC_EVENTRESPONSE GetLearnedSkillBJ=0,0,heroskillcode _GetLearnedSkillBJ_Defaults= _GetLearnedSkillBJ_Category=TC_EVENTRESPONSE GetEnumPlayer=0,0,player _GetEnumPlayer_Defaults= _GetEnumPlayer_Category=TC_NOTHING GetFilterPlayer=0,0,player _GetFilterPlayer_Defaults= _GetFilterPlayer_Category=TC_NOTHING GetOwningPlayer=0,1,player,unit _GetOwningPlayer_Defaults=GetTriggerUnit _GetOwningPlayer_Category=TC_NOTHING GetItemPlayer=0,1,player,item _GetItemPlayer_Defaults=GetLastCreatedItem _GetItemPlayer_Category=TC_NOTHING ForcePickRandomPlayer=0,0,player,force _ForcePickRandomPlayer_Defaults=_ _ForcePickRandomPlayer_Category=TC_NOTHING ConvertedPlayer=0,1,player,integer _ConvertedPlayer_Defaults=1 _ConvertedPlayer_Limits=1,16 _ConvertedPlayer_Category=TC_CONVERSION GetChangingUnitPrevOwner=1,0,player _GetChangingUnitPrevOwner_Defaults= _GetChangingUnitPrevOwner_Category=TC_EVENTRESPONSE GetTriggerPlayer=0,0,player _GetTriggerPlayer_Defaults= _GetTriggerPlayer_Category=TC_EVENTRESPONSE LeaderboardGetIndexedPlayerBJ=1,0,player,integer,leaderboard _LeaderboardGetIndexedPlayerBJ_Defaults=1,GetLastCreatedLeaderboard _LeaderboardGetIndexedPlayerBJ_Limits=1,16 _LeaderboardGetIndexedPlayerBJ_Category=TC_LEADERBOARD GetLastCreatedGroup=0,0,group _GetLastCreatedGroup_Defaults= _GetLastCreatedGroup_Category=TC_LAST GetRandomSubGroup=1,0,group,integer,group _GetRandomSubGroup_Defaults=4,GetUnitsInRectAll _GetRandomSubGroup_Category=TC_NOTHING GetUnitsInRectAll=0,0,group,rect _GetUnitsInRectAll_Defaults=GetPlayableMapRect _GetUnitsInRectAll_Category=TC_NOTHING GetUnitsInRectOfPlayer=0,0,group,rect,player _GetUnitsInRectOfPlayer_Defaults=GetPlayableMapRect,Player00 _GetUnitsInRectOfPlayer_Category=TC_NOTHING GetUnitsInRectMatching=0,0,group,rect,boolexpr _GetUnitsInRectMatching_Defaults=GetPlayableMapRect,_ _GetUnitsInRectMatching_Category=TC_NOTHING GetUnitsInRangeOfLocAll=0,0,group,real,location _GetUnitsInRangeOfLocAll_Defaults=512,GetRectCenter _GetUnitsInRangeOfLocAll_Limits=0,_,_,_ _GetUnitsInRangeOfLocAll_Category=TC_NOTHING GetUnitsInRangeOfLocMatching=0,0,group,real,location,boolexpr _GetUnitsInRangeOfLocMatching_Defaults=512,GetRectCenter,_ _GetUnitsInRangeOfLocMatching_Limits=0,_,_,_,_,_ _GetUnitsInRangeOfLocMatching_Category=TC_NOTHING GetUnitsOfPlayerAll=0,0,group,player _GetUnitsOfPlayerAll_Defaults=Player00 _GetUnitsOfPlayerAll_Category=TC_NOTHING GetUnitsOfPlayerAndTypeId=0,0,group,player,unitcode _GetUnitsOfPlayerAndTypeId_Defaults=Player00,hfoo _GetUnitsOfPlayerAndTypeId_Category=TC_NOTHING GetUnitsOfPlayerMatching=0,0,group,player,boolexpr _GetUnitsOfPlayerMatching_Defaults=Player00,_ _GetUnitsOfPlayerMatching_Category=TC_NOTHING GetUnitsOfTypeIdAll=0,0,group,unitcode _GetUnitsOfTypeIdAll_Defaults=hfoo _GetUnitsOfTypeIdAll_Category=TC_NOTHING GetUnitsSelectedAll=0,0,group,player _GetUnitsSelectedAll_Defaults=Player00 _GetUnitsSelectedAll_Category=TC_NOTHING GetPlayersAll=0,0,force _GetPlayersAll_Defaults= _GetPlayersAll_Category=TC_NOTHING GetPlayersByMapControl=0,0,force,mapcontrol _GetPlayersByMapControl_Defaults=MapControlComputer _GetPlayersByMapControl_Category=TC_NOTHING GetPlayersMatching=0,0,force,boolexpr _GetPlayersMatching_Defaults=_ _GetPlayersMatching_Category=TC_NOTHING GetPlayersAllies=0,0,force,player _GetPlayersAllies_Defaults=Player00 _GetPlayersAllies_Category=TC_NOTHING GetPlayersEnemies=0,0,force,player _GetPlayersEnemies_Defaults=Player00 _GetPlayersEnemies_Category=TC_NOTHING GetForceOfPlayer=0,0,force,player _GetForceOfPlayer_Defaults=Player00 _GetForceOfPlayer_Category=TC_NOTHING GetPlayerRace=0,1,race,player _GetPlayerRace_Defaults=Player00 _GetPlayerRace_Category=TC_NOTHING GetUnitRace=0,1,race,unit _GetUnitRace_Defaults=GetTriggerUnit _GetUnitRace_Category=TC_NOTHING GetCurrentCameraSetup=0,0,camerasetup _GetCurrentCameraSetup_Defaults= _GetCurrentCameraSetup_Category=TC_NOTHING GetLastCreatedFogModifier=0,0,fogmodifier _GetLastCreatedFogModifier_Defaults= _GetLastCreatedFogModifier_Category=TC_LAST GetTriggeringTrigger=0,0,trigger _GetTriggeringTrigger_Defaults= _GetTriggeringTrigger_Category=TC_NOTHING GetGameDifficulty=0,1,gamedifficulty _GetGameDifficulty_Defaults= _GetGameDifficulty_Category=TC_NOTHING GetAIDifficulty=1,1,aidifficulty,player _GetAIDifficulty_Defaults=Player00 _GetAIDifficulty_Category=TC_NOTHING GetGameSpeed=0,1,gamespeed _GetGameSpeed_Defaults= _GetGameSpeed_Category=TC_NOTHING GetPlayerController=0,1,mapcontrol,player _GetPlayerController_Defaults=Player00 _GetPlayerController_Category=TC_NOTHING GetPlayerColor=0,1,playercolor,player _GetPlayerColor_Defaults=Player00 _GetPlayerColor_Category=TC_NOTHING GetPlayerSlotState=0,1,playerslotstate,player _GetPlayerSlotState_Defaults=Player00 _GetPlayerSlotState_Category=TC_NOTHING GetLastCreatedEffectBJ=0,0,effect _GetLastCreatedEffectBJ_Defaults= _GetLastCreatedEffectBJ_Category=TC_LAST GetLastCreatedImage=0,0,image _GetLastCreatedImage_Defaults= _GetLastCreatedImage_Category=TC_LAST GetLastCreatedUbersplat=0,0,ubersplat _GetLastCreatedUbersplat_Defaults= _GetLastCreatedUbersplat_Category=TC_LAST GetLastCreatedWeatherEffect=0,0,weathereffect _GetLastCreatedWeatherEffect_Defaults= _GetLastCreatedWeatherEffect_Category=TC_LAST GetLastCreatedTerrainDeformation=1,0,terraindeformation _GetLastCreatedTerrainDeformation_Defaults= _GetLastCreatedTerrainDeformation_Category=TC_LAST GetLastPlayedSound=0,0,sound _GetLastPlayedSound_Defaults= _GetLastPlayedSound_Category=TC_LAST GetLastPlayedMusic=0,0,musicfile _GetLastPlayedMusic_Defaults= _GetLastPlayedMusic_Category=TC_LAST GetLastCreatedQuestBJ=0,0,quest _GetLastCreatedQuestBJ_Defaults= _GetLastCreatedQuestBJ_Category=TC_LAST GetLastCreatedQuestItemBJ=0,0,questitem _GetLastCreatedQuestItemBJ_Defaults= _GetLastCreatedQuestItemBJ_Category=TC_LAST GetLastCreatedDefeatConditionBJ=0,0,defeatcondition _GetLastCreatedDefeatConditionBJ_Defaults= _GetLastCreatedDefeatConditionBJ_Category=TC_LAST GetClickedDialogBJ=0,0,dialog _GetClickedDialogBJ_Defaults= _GetClickedDialogBJ_Category=TC_EVENTRESPONSE GetLastCreatedButtonBJ=0,0,button _GetLastCreatedButtonBJ_Defaults= _GetLastCreatedButtonBJ_Category=TC_LAST GetClickedButtonBJ=0,0,button _GetClickedButtonBJ_Defaults= _GetClickedButtonBJ_Category=TC_EVENTRESPONSE GetLastCreatedLeaderboard=0,0,leaderboard _GetLastCreatedLeaderboard_Defaults= _GetLastCreatedLeaderboard_Category=TC_LAST PlayerGetLeaderboardBJ=0,0,leaderboard,player _PlayerGetLeaderboardBJ_Defaults=Player00 _PlayerGetLeaderboardBJ_Category=TC_NOTHING GetLastCreatedMultiboard=1,0,multiboard _GetLastCreatedMultiboard_Defaults= _GetLastCreatedMultiboard_Category=TC_LAST GetLastCreatedTimerBJ=0,0,timer _GetLastCreatedTimerBJ_Defaults= _GetLastCreatedTimerBJ_Category=TC_LAST GetExpiredTimer=0,0,timer _GetExpiredTimer_Defaults= _GetExpiredTimer_Category=TC_EVENTRESPONSE GetLastCreatedTimerDialogBJ=0,0,timerdialog _GetLastCreatedTimerDialogBJ_Defaults= _GetLastCreatedTimerDialogBJ_Category=TC_LAST GetLastCreatedGameCacheBJ=0,0,gamecache _GetLastCreatedGameCacheBJ_Defaults= _GetLastCreatedGameCacheBJ_Category=TC_LAST GetLastCreatedTextTag=1,0,texttag _GetLastCreatedTextTag_Defaults= _GetLastCreatedTextTag_Category=TC_LAST GetLocalPlayer=1,0,player _GetLocalPlayer_Defaults= _GetLocalPlayer_Category=TC_PLAYER GetEventDetectingPlayer=0,0,player _GetEventDetectingPlayer_Defaults= _GetEventDetectingPlayer_Category=TC_EVENTRESPONSE GetWinningPlayer=1,0,player _GetWinningPlayer_Defaults= _GetWinningPlayer_Category=TC_EVENTRESPONSE GetUnitX=0,1,real,unit _GetUnitX_Defaults=GetTriggerUnit _GetUnitX_Category=TC_UNIT GetUnitY=0,1,real,unit _GetUnitY_Defaults=GetTriggerUnit _GetUnitY_Category=TC_UNIT CreateTimerBJ=0,1,timer,periodicoption,real _CreateTimerBJ_Defaults=PeriodicOptionOneTime,30 _CreateTimerBJ_Categor=TC_TIMER CreateTrigger=0,1,trigger _CreateTrigger_Defaults= _CreateTrigger_Category=TC_TRIGGER CreateDestructableZ=0,0,destructable,destructablecode,real,real,real,real,real,integer _CreateDestructableZ_Defaults=LTlt,GetLocationX,GetLocationY,0,GetRandomDirectionDeg,1,0 _CreateDestructableZ_Limits=_,_,_,_,_,_,_,_,_,_,0,_,0,_ _CreateDestructableZ_Category=TC_DESTRUCT CreateDeadDestructableZ=0,0,destructable,destructablecode,real,real,real,real,real,integer _CreateDeadDestructableZ_Defaults=LTlt,GetLocationX,GetLocationY,0,GetRandomDirectionDeg,1,0 _CreateDeadDestructableZ_Limits=_,_,_,_,_,_,_,_,_,_,0,_,0,_ _CreateDeadDestructableZ_Category=TC_DESTRUCT GetTriggerEventId=0,1,eventid _GetTriggerEventId_Defaults=_ _GetTriggerEventId_Category=TC_TRIGGER QueuedTriggerGetIndex=0,0,integer,trigger _QueuedTriggerGetIndex_Defaults=_ _QueuedTriggerGetIndex_Category=TC_TRIGGER IntegerTertiaryOp=0,1,integer,boolean,integer,integer _IntegerTertiaryOp_Defaults=_,_,_ _IntegerTertiaryOp_Category=TC_MATH IsLocationInRegion=1,2,boolean,region,location _IsLocationInRegion_Defaults=_,_ _IsLocationInRegion_Category=TC_REGION IsUnitInRegion=1,2,boolean,region,unit _IsUnitInRegion_Defaults=_,_ _IsUnitInRegion_Category=TC_REGION IsPointInRegion=0,1,boolean,region,real,real _IsPointInRegion_Defaults=GetTriggeringRegion,GetLocationX,GetLocationY _IsPointInRegion_Category=TC_REGION CompareRectsBJ=0,1,boolean,rect,rect _CompareRectsBJ_Defaults=GetPlayableMapRect,GetPlayableMapRect _CompareRectsBJ_Category=TC_REGION IsUnitInForce=0,1,boolean,unit,force _IsUnitInForce_Defaults=GetTriggerUnit,_ _IsUnitInForce_Category=TC_UNIT IsUnitOwnedByPlayer=0,1,boolean,unit,player _IsUnitOwnedByPlayer_Defaults=GetTriggerUnit,Player00 _IsUnitOwnedByPlayer_Category=TC_UNIT IsUnitInRange=0,1,boolean,unit,unit,real _IsUnitInRange_Defaults=GetTriggerUnit,_,500 _IsUnitInRange_Category=TC_UNIT IsUnitInRangeLoc=0,1,boolean,unit,location,real _IsUnitInRangeLoc_Defaults=GetTriggerUnit,_,500 _IsUnitInRangeLoc_Category=TC_UNIT CreateUnit=0,0,unit,player,unitcode,real,real,real _CreateUnit_Defaults=Player00,hfoo,GetLocationX,GetLocationY,0 _CreateUnit_Category=TC_UNIT CreateUnitAtLoc=0,0,unit,player,unitcode,location,real _CreateUnitAtLoc_Defaults=Player00,hfoo,GetRectCenter,0 _CreateUnitAtLoc_Category=TC_UNIT GetRescuer=1,0,unit _GetRescuer_Defaults= _GetRescuer_Category=TC_EVENTRESPONSE GetEventUnitState=1,0,unitstate _GetEventUnitState_Defaults= _GetEventUnitState_Category=TC_EVENTRESPONSE GetEventPlayerState=1,0,playerstate _GetEventPlayerState_Defaults= _GetEventPlayerState_Category=TC_EVENTRESPONSE DialogCreate=1,0,dialog _DialogCreate_Defaults= _DialogCreate_Category=TC_DIALOG CreateForce=1,1,force _CreateForce_Defaults= _CreateForce_Category=TC_PLAYERGROUP CreateGroup=1,1,group _CreateGroup_Defaults= _CreateGroup_Category=TC_UNITGROUP GetTriggeringRegion=1,1,region _GetTriggeringRegion_Defaults _GetTriggeringRegion_Category=TC_RECTANGLE CreateRegion=1,0,region _CreateRegion_Defaults= _CreateRegion_Category=TC_RECTANGLE GetPlayerTypedUnitCount=1,1,integer,player,unituiname,boolean,boolean _GetPlayerTypedUnitCount_Defaults=Player00,"townhall",true,true _GetPlayerTypedUnitCount_Category=TC_UNIT RandomDistChoose=1,0,itemcode _RandomDistChoose_Defaults= _RandomDistChoose_Category=TC_ITEM GetDetectedUnit=1,0,unit _GetDetectedUnit_Defaults= _GetDetectedUnit_Category=TC_EVENTRESPONSE LeaderboardGetLabelText=0,0,string,leaderboard _LeaderboardGetLabelText_Defaults=GetLastCreatedLeaderboard _LeaderboardGetLabelText_Category=TC_LEADERBOARD UnitIgnoreAlarmToggled=1,1,boolean,unit _UnitIgnoreAlarmToggled_Defaults=_ _UnitIgnoreAlarmToggled_Category=TC_UNIT UnitInventorySizeBJ=1,1,integer,unit _UnitInventorySizeBJ_Defaults=GetTriggerUnit _UnitInventorySizeBJ_Category=TC_UNIT GetLastCreatedLightningBJ=0,0,lightning _GetLastCreatedLightningBJ_Defaults= _GetLastCreatedLightningBJ_Category=TC_LAST GetLightningColorABJ=1,0,real,lightning _GetLightningColorABJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorABJ_Category=TC_SPECIALEFFECT _GetLightningColorABJ_ScriptName=GetLightningColorA GetLightningColorRBJ=1,0,real,lightning _GetLightningColorRBJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorRBJ_Category=TC_SPECIALEFFECT _GetLightningColorRBJ_ScriptName=GetLightningColorR GetLightningColorGBJ=1,0,real,lightning _GetLightningColorGBJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorGBJ_Category=TC_SPECIALEFFECT _GetLightningColorGBJ_ScriptName=GetLightningColorG GetLightningColorBBJ=1,0,real,lightning _GetLightningColorBBJ_Defaults=GetLastCreatedLightningBJ _GetLightningColorBBJ_Category=TC_SPECIALEFFECT _GetLightningColorBBJ_ScriptName=GetLightningColorB GetEventDamageSource=1,0,unit _GetEventDamageSource_Defaults= _GetEventDamageSource_Category=TC_EVENTRESPONSE GetAbilityEffectBJ=1,1,string,string,effecttype,integer _GetAbilityEffectBJ_Defaults="blizzard",EffectTypeEffect,0 _GetAbilityEffectBJ_Category=TC_NOTHING _GetAbilityEffectBJ_ScriptName=GetAbilityEffect GetAbilitySoundBJ=1,1,string,string,soundtype _GetAbilitySoundBJ_Defaults="blizzard",SoundTypeEffect _GetAbilitySoundBJ_Category=TC_NOTHING _GetAbilitySoundBJ_ScriptName=GetAbilitySound GetAbilityEffectById=1,1,string,buffcode,effecttypebuff,integer _GetAbilityEffectById_Defaults=_,EffectTypeEffectBuff,0 _GetAbilityEffectById_Category=TC_NOTHING GetAbilitySoundById=1,1,string,abilcode,soundtype _GetAbilitySoundById_Defaults=_,SoundTypeEffect _GetAbilitySoundById_Category=TC_NOTHING GetTriggerName=0,1,string _GetTriggerName_Defaults= _GetTriggerName_Category=TC_TRIGGER HaveStoredInteger=1,1,boolean,gamecache,string,string _HaveStoredInteger_Defaults=_,_,_ _HaveStoredInteger_Category=TC_GAMECACHE HaveStoredBoolean=1,1,boolean,gamecache,string,string _HaveStoredBoolean_Defaults=_,_,_ _HaveStoredBoolean_Category=TC_GAMECACHE HaveStoredReal=1,1,boolean,gamecache,string,string _HaveStoredReal_Defaults=_,_,_ _HaveStoredReal_Category=TC_GAMECACHE HaveStoredUnit=1,1,boolean,gamecache,string,string _HaveStoredUnit_Defaults=_,_,_ _HaveStoredUnit_Category=TC_GAMECACHE HaveStoredString=1,1,boolean,gamecache,string,string _HaveStoredString_Defaults=_,_,_ _HaveStoredString_Category=TC_GAMECACHE exitwhen=0,1,scriptcode,boolcall _exitwhen_Defaults= _exitwhen_Category=TC_CUSTOM AddSpecialEffectLoc=0,0,effect,modelfile,location _AddSpecialEffectLoc_Defaults= _AddSpecialEffectLoc_Category=TC_SPECIALEFFECT AddSpecialEffect=0,0,effect,modelfile,real,real _AddSpecialEffect_Defaults= _AddSpecialEffect_Category=TC_SPECIALEFFECT AddSpecialEffectTarget=0,0,effect,modelfile,unit,string _AddSpecialEffectTarget_Defaults= _AddSpecialEffectTarget_Category=TC_SPECIALEFFECT CreateTrackable=0,1,trackable,modelfile,real,real,real _CreateTrackable_Defaults="units\nightelf\Wisp\Wisp.mdl",_,_,0 _CreateTrackable_Category=TC_TRACKABLE GetTriggeringTrackable=0,0,trackable _GetTriggeringTrackable_Defaults= _GetTriggeringTrackable_Category=TC_TRACKABLE LeaderboardGetItemCount=0,0,integer,leaderboard _LeaderboardGetItemCount_Defaults=GetLastCreatedLeaderboard _LeaderboardGetItemCount_Category=TC_LEADERBOARD FirstOfGroup=0,0,unit,group _FirstOfGroup_Defaults=_ _FirstOfGroup_Category=TC_UNITGROUP CreateItemLoc=0,1,item,itemcode,location _CreateItemLoc_Defaults=texp,GetRectCenter _CreateItemLoc_Category=TC_ITEM GetEventGameState=1,0,gamestate _GetEventGameState_Defaults= _GetEventGameState_Category=TC_EVENTRESPONSE GetIntegerGameState=0,1,integer,igamestate _GetIntegerGameState_Defaults=IGamestateDisconnected _GetIntegerGameState_Category=TC_GAME IsTimerDialogDisplayed=0,1,boolean,timerdialog _IsTimerDialogDisplayed_Defaults=GetLastCreatedTimerDialogBJ _IsTimerDialogDisplayed_Category=TC_TIMER QueuedTriggerRemoveByIndex=0,0,boolean,integer _QueuedTriggerRemoveByIndex_Defaults=0 _QueuedTriggerRemoveByIndex_Category=TC_RETURNSUCCESS ReviveHeroLoc=0,0,boolean,unit,location,showhideoption _ReviveHeroLoc_Defaults=_,GetRectCenter,ShowHideHide _ReviveHeroLoc_Category=TC_RETURNSUCCESS UnitMakeAbilityPermanent=0,0,boolean,unit,permanentoption,abilcode _UnitMakeAbilityPermanent_Defaults=GetTriggerUnit,PermanentPerm,_ _UnitMakeAbilityPermanent_Category=TC_RETURNSUCCESS UnitAddAbilityBJ=0,0,boolean,abilcode,unit _UnitAddAbilityBJ_Defaults=_,GetTriggerUnit _UnitAddAbilityBJ_Category=TC_RETURNSUCCESS UnitRemoveAbilityBJ=0,0,boolean,abilcode,unit _UnitRemoveAbilityBJ_Defaults=_,GetTriggerUnit _UnitRemoveAbilityBJ_Category=TC_RETURNSUCCESS UnitRemoveBuffBJ=0,0,boolean,buffcode,unit _UnitRemoveBuffBJ_Defaults=_,GetTriggerUnit _UnitRemoveBuffBJ_Category=TC_RETURNSUCCESS UnitAddItemSwapped=0,0,boolean,item,unit _UnitAddItemSwapped_Defaults=GetLastCreatedItem,GetTriggerUnit _UnitAddItemSwapped_Category=TC_RETURNSUCCESS UnitAddItemByIdSwapped=0,0,boolean,itemcode,unit _UnitAddItemByIdSwapped_Defaults=texp,GetTriggerUnit _UnitAddItemByIdSwapped_Category=TC_RETURNSUCCESS UnitUseItem=0,0,boolean,unit,item _UnitUseItem_Defaults=_,GetLastCreatedItem _UnitUseItem_Category=TC_RETURNSUCCESS UnitUseItemTarget=0,0,boolean,unit,item,unit _UnitUseItemTarget_Defaults=_,GetLastCreatedItem,_ _UnitUseItemTarget_Category=TC_RETURNSUCCESS UnitUseItemPointLoc=0,0,boolean,unit,item,location _UnitUseItemPointLoc_Defaults=_,GetLastCreatedItem,GetRectCenter _UnitUseItemPointLoc_Category=TC_RETURNSUCCESS UnitUseItemDestructable=0,0,boolean,unit,item,destructable _UnitUseItemDestructable_Defaults=_,GetLastCreatedItem,_ _UnitUseItemDestructable_Category=TC_RETURNSUCCESS IssueInstantTargetOrder=1,0,boolean,unit,unitorderinstant,unit,item _IssueInstantTargetOrder_Defaults=GetTriggerUnit,InstantOrderGive,GetLastCreatedUnit,UnitItemInSlotBJ _IssueInstantTargetOrder_Category=TC_RETURNSUCCESS IssueImmediateOrder=0,0,boolean,unit,unitordernotarg _IssueImmediateOrder_Defaults=_,UnitOrderStop _IssueImmediateOrder_Category=TC_RETURNSUCCESS IssuePointOrderLoc=0,0,boolean,unit,unitorderptarg,location _IssuePointOrderLoc_Defaults=_,UnitOrderMove,GetRectCenter _IssuePointOrderLoc_Category=TC_RETURNSUCCESS IssueTargetOrder=0,0,boolean,unit,unitorderutarg,unit _IssueTargetOrder_Defaults=_,UnitOrderAttackUnit,_ _IssueTargetOrder_Category=TC_RETURNSUCCESS IssueTargetDestructableOrder=0,0,boolean,unit,unitorderdtarg,destructable _IssueTargetDestructableOrder_Defaults=_,UnitOrderHarvestDestructible,_ _IssueTargetDestructableOrder_Category=TC_RETURNSUCCESS IssueTargetOrderBJ=0,0,boolean,unit,unitorderitarg,item _IssueTargetOrderBJ_Defaults=_,ItemOrderPickUp,_ _IssueTargetOrderBJ_Category=TC_RETURNSUCCESS IssueBuildOrderByIdLocBJ=0,0,boolean,unit,unitcode,location _IssueBuildOrderByIdLocBJ_Defaults=_,hbar,GetRectCenter _IssueBuildOrderByIdLocBJ_Category=TC_RETURNSUCCESS IssueTrainOrderByIdBJ=0,0,boolean,unit,unitcode _IssueTrainOrderByIdBJ_Defaults=_,hfoo _IssueTrainOrderByIdBJ_Category=TC_RETURNSUCCESS IssueUpgradeOrderByIdBJ=0,0,boolean,unit,techcode _IssueUpgradeOrderByIdBJ_Defaults=_,Rhde _IssueUpgradeOrderByIdBJ_Category=TC_RETURNSUCCESS GroupTargetOrder=0,0,boolean,group,unitorderutarg,unit _GroupTargetOrder_Defaults=GetUnitsInRectAll,UnitOrderAttackUnit,_ _GroupTargetOrder_Category=TC_RETURNSUCCESS GroupTargetDestructableOrder=0,0,boolean,group,unitorderdtarg,destructable _GroupTargetDestructableOrder_Defaults=GetUnitsInRectAll,UnitOrderHarvestDestructible,_ _GroupTargetDestructableOrder_Category=TC_RETURNSUCCESS GroupTargetOrderBJ=0,0,boolean,group,unitorderutarg,item _GroupTargetOrderBJ_Defaults=GetUnitsInRectAll,ItemOrderPickUp,_ _GroupTargetOrderBJ_Category=TC_RETURNSUCCESS GroupPointOrderLoc=0,0,boolean,group,unitorderptarg,location _GroupPointOrderLoc_Defaults=GetUnitsInRectAll,UnitOrderMove,GetRectCenter _GroupPointOrderLoc_Category=TC_RETURNSUCCESS GroupImmediateOrder=0,0,boolean,group,unitordernotarg _GroupImmediateOrder_Defaults=GetUnitsInRectAll,UnitOrderStop _GroupImmediateOrder_Category=TC_RETURNSUCCESS GroupTrainOrderByIdBJ=0,0,boolean,group,unitcode _GroupTrainOrderByIdBJ_Defaults=GetUnitsInRectAll,hfoo _GroupTrainOrderByIdBJ_Category=TC_RETURNSUCCESS IssueNeutralImmediateOrderById=1,0,boolean,player,unit,unitcode _IssueNeutralImmediateOrderById_Defaults=Player00,_,nzep _IssueNeutralImmediateOrderById_Category=TC_RETURNSUCCESS GetUnitAbilityLevel=0,1,integer,unit,buffcode _GetUnitAbilityLevel_Defaults=GetTriggerUnit,_ _GetUnitAbilityLevel_Category=TC_COMPATIBILITY AddSpellEffectByIdLoc=0,0,effect,abilcode,effecttype,location _AddSpellEffectByIdLoc_Defaults=_,EffectTypeTarget,GetRectCenter _AddSpellEffectByIdLoc_Category=TC_COMPATIBILITY AddSpellEffectById=0,0,effect,abilcode,effecttype,real,real _AddSpellEffectById_Defaults=_,EffectTypeTarget,0,0 _AddSpellEffectById_Category=TC_COMPATIBILITY AddSpellEffectTargetById=0,0,effect,abilcode,effecttype,unit,string _AddSpellEffectTargetById_Defaults=_,EffectTypeTarget,GetLastCreatedUnit,"origin" _AddSpellEffectTargetById_Category=TC_COMPATIBILITY CreateMultiboard=1,0,multiboard _CreateMultiboard_Defaults= _CreateMultiboard_Category=TC_COMPATIBILITY MultiboardGetItem=1,0,multiboarditem,multiboard,integer,integer _MultiboardGetItem_Defaults=CreateMultiboard,_,_ _MultiboardGetItem_Category=TC_COMPATIBILITY TriggerRegisterVariableEvent=0,1,event,trigger,AnyGlobal,limitop,null _TriggerRegisterVariableEvent_Defaults=GetTriggeringTrigger,_,LimitOpEqual,_ _TriggerRegisterVariableEvent_Category=TC_COMPATIBILITY TriggerRegisterTimerExpireEvent=0,1,event,trigger,timer _TriggerRegisterTimerExpireEvent_Defaults=GetTriggeringTrigger,_ _TriggerRegisterTimerExpireEvent_Category=TC_COMPATIBILITY TriggerRegisterDialogEvent=0,1,event,trigger,dialog _TriggerRegisterDialogEvent_Defaults=GetTriggeringTrigger,_ _TriggerRegisterDialogEvent_Category=TC_COMPATIBILITY TriggerRegisterDialogButtonEvent=0,1,event,trigger,button _TriggerRegisterDialogButtonEvent_Defaults=GetTriggeringTrigger,_ _TriggerRegisterDialogButtonEvent_Category=TC_COMPATIBILITY TriggerRegisterGameEvent=0,1,event,trigger,gameeventoption _TriggerRegisterGameEvent_Defaults=GetTriggeringTrigger,GameEventBuildSubMenu _TriggerRegisterGameEvent_Category=TC_COMPATIBILITY TriggerRegisterEnterRegion=0,1,event,trigger,region,boolexpr _TriggerRegisterEnterRegion_Defaults=GetTriggeringTrigger,_,_ _TriggerRegisterEnterRegion_Category=TC_COMPATIBILITY TriggerRegisterLeaveRegion=0,1,event,trigger,region,boolexpr _TriggerRegisterLeaveRegion_Defaults=GetTriggeringTrigger,_,_ _TriggerRegisterLeaveRegion_Category=TC_COMPATIBILITY TriggerRegisterPlayerEvent=0,1,event,trigger,player,playereventoption _TriggerRegisterPlayerEvent_Defaults=GetTriggeringTrigger,Player00,PlayerEventLeave _TriggerRegisterPlayerEvent_Category=TC_COMPATIBILITY TriggerRegisterPlayerUnitEventSimple=0,1,event,trigger,player,playerunitevent _TriggerRegisterPlayerUnitEventSimple_Defaults=GetTriggeringTrigger,Player00,PlayerUnitEventDeath _TriggerRegisterPlayerUnitEventSimple_Category=TC_COMPATIBILITY TriggerRegisterPlayerUnitEvent=0,1,event,trigger,player,playerunitevent,boolexpr _TriggerRegisterPlayerUnitEvent_Defaults=GetTriggeringTrigger,Player00,PlayerUnitEventDeath,_ _TriggerRegisterPlayerUnitEvent_Category=TC_COMPATIBILITY TriggerRegisterPlayerStateEvent=0,1,event,trigger,player,playerstate,limitop,real _TriggerRegisterPlayerStateEvent_Defaults=GetTriggeringTrigger,Player00,PlayerStateGold,LimitOpGreaterThanOrEqual,1000 _TriggerRegisterPlayerStateEvent_Category=TC_COMPATIBILITY TriggerRegisterPlayerChatEvent=0,1,event,trigger,player,string,chatmatchtype _TriggerRegisterPlayerChatEvent_Defaults=GetTriggeringTrigger,Player00,_,ChatMatchTypeExact _TriggerRegisterPlayerChatEvent_Category=TC_COMPATIBILITY TriggerRegisterDeathEvent=0,1,event,trigger,destructable _TriggerRegisterDeathEvent_Defaults=GetTriggeringTrigger,_ _TriggerRegisterDeathEvent_Category=TC_COMPATIBILITY TriggerRegisterUnitStateEvent=0,1,event,trigger,unit,unitstate,limitop,real _TriggerRegisterUnitStateEvent_Defaults=GetTriggeringTrigger,_,UnitStateLife,LimitOpGreaterThanOrEqual,100 _TriggerRegisterUnitStateEvent_Category=TC_COMPATIBILITY TriggerRegisterUnitEvent=0,1,event,trigger,unit,unitevent _TriggerRegisterUnitEvent_Defaults=GetTriggeringTrigger,_,UnitEventDeath _TriggerRegisterUnitEvent_Category=TC_COMPATIBILITY TriggerRegisterUnitInRangeSimple=0,1,event,trigger,real,unit _TriggerRegisterUnitInRangeSimple_Defaults=GetTriggeringTrigger,100,_ _TriggerRegisterUnitInRangeSimple_Defaults=GetTriggeringTrigger,100,_,_,_ _TriggerRegisterUnitInRangeSimple_Category=TC_COMPATIBILITY TriggerAddAction=0,1,triggeraction,trigger,code _TriggerAddAction_Defaults=GetTriggeringTrigger,_ _TriggerAddAction_Category=TC_COMPATIBILITY TriggerAddCondition=0,1,triggercondition,trigger,boolexpr _TriggerAddCondition_Defaults=GetTriggeringTrigger,_ _TriggerAddCondition_Category=TC_COMPATIBILITY [DefaultTriggerCategories] NumCategories=1 Category01=WESTRING_INITIALIZATION [DefaultTriggers] NumTriggers=1 Trigger01Name=WESTRING_MELEEINITIALIZATION Trigger01Comment=WESTRING_MELEEINITIALIZATION_COMMENT Trigger01Category=1 Trigger01Events=1 Trigger01Event01=MapInitializationEvent Trigger01Conditions=0 Trigger01Actions=8 Trigger01Action01=MeleeStartingVisibility Trigger01Action02=MeleeStartingHeroLimit Trigger01Action03=MeleeGrantHeroItems Trigger01Action04=MeleeStartingResources Trigger01Action05=MeleeClearExcessUnits Trigger01Action06=MeleeStartingUnits Trigger01Action07=MeleeStartingAI Trigger01Action08=MeleeInitVictoryDefeat ================================================ FILE: clients/weu/TriggerDataYDWE.txt ================================================ //*************************************************************************** [TriggerCategories] // Defines categories for organizing trigger functions // Key: Arbitrary category identifier // Value 0: Display text // Value 1: Icon image file // Value 2: Optional flag (defaults to 0) indicating to disable display of category name // //最萌小汐 TC_MU_BAKA=专用库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_BASE=基础库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_EVENT=事件库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_MATH=数学库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_STRING=字符串库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_UNIT=单位库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_ITEM=物品库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_TEXT=漂浮文字库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_EFFECT=特效库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_SOUND=音效库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_PROCESS=过程库,ReplaceableTextures\WorldEditUI\Actions-Game TC_MU_MOVER=弹幕库,ReplaceableTextures\WorldEditUI\Actions-Game TC_ARITHMETIC=WESTRING_TRIGCAT_ARITHMETIC,ReplaceableTextures\WorldEditUI\Actions-AI,1 TC_NOTHING=WESTRING_TRIGCAT_NOTHING,ReplaceableTextures\CommandButtons\BTNPillage.blp,1 TC_COMMENT=WESTRING_TRIGCAT_COMMENT,ReplaceableTextures\WorldEditUI\Actions-Comment,1 TC_CUSTOM=WESTRING_TRIGCAT_CUSTOM,ReplaceableTextures\CommandButtons\BTNSpellSteal.blp,1 TC_CONDITION=WESTRING_TRIGCAT_CONDITION,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_WAIT=WESTRING_TRIGCAT_WAIT,ReplaceableTextures\WorldEditUI\Actions-Wait,1 TC_SETVARIABLE=WESTRING_TRIGCAT_SETVARIABLE,ReplaceableTextures\WorldEditUI\Actions-SetVariables,1 TC_SKIPACTIONS=WESTRING_TRIGCAT_SKIPACTIONS,ReplaceableTextures\CommandButtons\BTNTemp.blp,1 TC_LOGIC=WESTRING_TRIGCAT_LOGIC,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_FORLOOP=WESTRING_TRIGCAT_FORLOOP,ReplaceableTextures\WorldEditUI\Actions-Logical,1 TC_LAST=WESTRING_TRIGCAT_LAST,ReplaceableTextures\WorldEditUI\Actions-SetVariables,1 TC_YDAB=技能[YDWE],ReplaceableTextures\CommandButtons\BTNImmolationOn.blp TC_YDST=系统[YDWE],ReplaceableTextures\CommandButtons\BTNMetamorphosis.blp TC_YDFC=函数[YDWE],ReplaceableTextures\CommandButtons\BTNEvasion.blp TC_YDLD=存储[YDWE],ReplaceableTextures\CommandButtons\BTNLoad.blp TC_YDSE=特效[YDWE],ReplaceableTextures\PassiveButtons\PASBTNFeedBack.blp TC_YDLC=变量[YDWE],ReplaceableTextures\WorldEditUI\Editor-ScriptVariable.blp,1 TC_YDAI=AI[YDWE],ReplaceableTextures\CommandButtons\BTNHeroTinker.blp TC_YDET=事件[YDWE],UI\Widgets\ToolTips\Human\ToolTipStonesIcon.blp TC_YDBF=逆天[YDWE],ReplaceableTextures\CommandButtons\BTNInfernal.blp TC_YDSL=存档[YDWE],ReplaceableTextures\CommandButtons\BTNTome.blp TC_SCRIPTSET=电影 ================================================ FILE: clients/weu/index.js ================================================ import WeuConverter from './components/weuconverter'; const converter = new WeuConverter(document.body); document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); }); document.addEventListener('drop', e => { e.preventDefault(); converter.convertFile(e.dataTransfer.files[0]); }); ================================================ FILE: package.json ================================================ { "name": "mdx-m3-viewer", "version": "5.13.0", "description": "A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.", "main": "dist/cjs/index.js", "types": "dist/cjs/index.d.ts", "scripts": { "build": "webpack --mode=production", "dev": "webpack -w --mode=development", "serve": "webpack serve", "prepublishOnly": "node clean.js && tsc && webpack --mode=production --env=umd" }, "repository": { "type": "git", "url": "https://github.com/flowtsohg/mdx-m3-viewer.git" }, "author": "Chananya Freiman", "license": "MIT", "bugs": { "url": "https://github.com/flowtsohg/mdx-m3-viewer/issues" }, "homepage": "https://github.com/flowtsohg/mdx-m3-viewer#readme", "dependencies": { "fengari": "^0.1.4", "gl-matrix": "3.3.0", "pako": "^2.0.3", "tga-js": "^1.1.1" }, "devDependencies": { "@types/node": "^12.12.17", "@types/pako": "^1.0.2", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "eslint": "^7.29.0", "ts-loader": "^9.2.3", "typescript": "^4.3.5", "webpack": "^5.0.0", "webpack-cli": "^4.7.2", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: src/common/arrayunique.ts ================================================ /** * Returns an array that only contains unique values found in the source array. */ export default function unique(a: T[]): T[] { return a.reverse().filter((e, i, arr) => { return arr.indexOf(e, i + 1) === -1; }).reverse(); } ================================================ FILE: src/common/audio.ts ================================================ let audioContext: OfflineAudioContext; // Some browsers don't have OfflineAudioContext or AudioContext. if (typeof OfflineAudioContext === 'function') { audioContext = new OfflineAudioContext(1, 1, 48000); } /** * A context-less decodeAudioData(). */ export async function decodeAudioData(buffer: ArrayBuffer): Promise { if (audioContext) { return audioContext.decodeAudioData(buffer); } return; } ================================================ FILE: src/common/binarystream.ts ================================================ import { bytesOf } from './bytesof'; import { boundIndexOf } from './searches'; import { uint8ToInt8, uint8ToInt16, uint8ToInt32, uint8ToUint16, uint8ToUint32, uint8ToFloat32, uint8ToFloat64, int8ToUint8, int16ToUint8, int32ToUint8, uint16ToUint8, uint32ToUint8, float32ToUint8, float64ToUint8 } from './typecast'; import { decodeUtf8, encodeUtf8 } from './utf8'; // Memory for all of the xxxToUint type casts. const uint8 = new Uint8Array(8); /** * A binary stream. */ export default class BinaryStream { buffer: ArrayBuffer; uint8array: Uint8Array; index = 0; byteLength: number; remaining: number; constructor(buffer: ArrayBuffer | Uint8Array, byteOffset?: number, byteLength?: number) { const bytes = bytesOf(buffer); // For browsers not supporting the spec. // Once upon a time I reported this issue on the Firefox tracker. // Seems like Safari needs an issue report too. byteOffset = byteOffset || 0; byteLength = byteLength || bytes.length; this.buffer = buffer; this.uint8array = bytes.subarray(byteOffset, byteOffset + byteLength); this.byteLength = byteLength; this.remaining = byteLength; } /** * Create a subreader of this reader, at its position, with the given byte length. */ substream(byteLength: number): BinaryStream { if (this.remaining < byteLength) { throw new Error(`ByteStream: substream: want ${byteLength} bytes but have ${this.remaining}`); } const index = this.index; this.index += byteLength; return new BinaryStream(this.uint8array.subarray(index, index + byteLength)); } /** * Skip a number of bytes. */ skip(bytes: number): void { if (this.remaining < bytes) { throw new Error(`ByteStream: skip: premature end - want ${bytes} bytes but have ${this.remaining}`); } this.index += bytes; this.remaining -= bytes; } /** * Set the reader's index. */ seek(index: number): void { this.index = index; this.remaining = this.byteLength - index; } /** * Read a UTF8 string with the given number of bytes. * * The entire size will be read, however the string returned is NULL terminated in its memory block. * * For example, the MDX format has many strings that have a constant maximum size, where any bytes after the string are NULLs. * Such strings will be loaded correctly given the maximum size. */ read(bytes: number): string { if (this.remaining < bytes) { throw new Error(`ByteStream: read: premature end - want ${bytes} bytes but have ${this.remaining}`); } const uint8array = this.uint8array; const start = this.index; let end = boundIndexOf(uint8array, 0, start, bytes); if (end === -1) { end = start + bytes; } this.index += bytes; this.remaining -= bytes; return decodeUtf8(uint8array.subarray(start, end)); } /** * Read a UTF8 NULL terminated string. */ readNull(): string { if (this.remaining < 1) { throw new Error(`ByteStream: readNull: premature end - want at least 1 byte but have 0`); } const uint8array = this.uint8array; const start = this.index; let end = uint8array.indexOf(0, start); if (end === -1) { end = uint8array.length - 1; } const bytes = end - start + 1; this.index += bytes; this.remaining -= bytes; return decodeUtf8(uint8array.subarray(start, end)); } /** * Read a binary string with the given number of bytes. */ readBinary(bytes: number): string { if (this.remaining < bytes) { throw new Error(`ByteStream: readBinary: premature end - want ${bytes} bytes but have ${this.remaining}`); } const uint8array = this.uint8array; const index = this.index; let data = ''; for (let i = 0; i < bytes; i++) { data += String.fromCharCode(uint8array[index + i]); } this.index += bytes; this.remaining -= bytes; return data; } /** * Read a 8 bit signed integer. */ readInt8(): number { if (this.remaining < 1) { throw new Error(`ByteStream: readInt8: premature end - want 1 byte but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToInt8(uint8array[index]); this.index += 1; this.remaining -= 1; return data; } /** * Read a 16 bit signed integer. */ readInt16(): number { if (this.remaining < 2) { throw new Error(`ByteStream: readInt16: premature end - want 2 bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToInt16(uint8array[index], uint8array[index + 1]); this.index += 2; this.remaining -= 2; return data; } /** * Read a 32 bit signed integer. */ readInt32(): number { if (this.remaining < 4) { throw new Error(`ByteStream: readInt32: premature end - want 4 bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToInt32(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3]); this.index += 4; this.remaining -= 4; return data; } /** * Read a 8 bit unsigned integer. */ readUint8(): number { if (this.remaining < 1) { throw new Error(`ByteStream: readUint8: premature end - want 1 byte but have ${this.remaining}`); } const data = this.uint8array[this.index]; this.index += 1; this.remaining -= 1; return data; } /** * Read a 16 bit unsigned integer. */ readUint16(): number { if (this.remaining < 2) { throw new Error(`ByteStream: readUint16: premature end - want 2 bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToUint16(uint8array[index], uint8array[index + 1]); this.index += 2; this.remaining -= 2; return data; } /** * Read a 32 bit unsigned integer. */ readUint32(): number { if (this.remaining < 4) { throw new Error(`ByteStream: readUint32: premature end - want 4 bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToUint32(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3]); this.index += 4; this.remaining -= 4; return data; } /** * Read a 32 bit float. */ readFloat32(): number { if (this.remaining < 4) { throw new Error(`ByteStream: readFloat32: premature end - want 4 bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToFloat32(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3]); this.index += 4; this.remaining -= 4; return data; } /** * Read a 64 bit float. */ readFloat64(): number { if (this.remaining < 8) { throw new Error(`ByteStream: readFloat64: premature end - want 8 bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; const data = uint8ToFloat64(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3], uint8array[index + 4], uint8array[index + 5], uint8array[index + 6], uint8array[index + 7]); this.index += 8; this.remaining -= 8; return data; } /** * Read an array of 8 bit signed integers. */ readInt8Array(view: number | Int8Array): Int8Array { if (!ArrayBuffer.isView(view)) { view = new Int8Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readInt8Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { view[i] = uint8ToInt8(uint8array[index + i]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 16 bit signed integers. */ readInt16Array(view: number | Int16Array): Int16Array { if (!ArrayBuffer.isView(view)) { view = new Int16Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readInt16Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 2; view[i] = uint8ToInt16(uint8array[offset], uint8array[offset + 1]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 32 bit signed integers. */ readInt32Array(view: number | Int32Array): Int32Array { if (!ArrayBuffer.isView(view)) { view = new Int32Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readInt32Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 4; view[i] = uint8ToInt32(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 8 bit unsigned integers. */ readUint8Array(view: number | Uint8Array): Uint8Array { if (!ArrayBuffer.isView(view)) { view = new Uint8Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readUint8Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { view[i] = uint8array[index + i]; } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 16 bit unsigned integers. */ readUint16Array(view: number | Uint16Array): Uint16Array { if (!ArrayBuffer.isView(view)) { view = new Uint16Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readUint16Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 2; view[i] = uint8ToUint16(uint8array[offset], uint8array[offset + 1]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 32 bit unsigned integers. */ readUint32Array(view: number | Uint32Array): Uint32Array { if (!ArrayBuffer.isView(view)) { view = new Uint32Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readUint32Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 4; view[i] = uint8ToUint32(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 32 bit floats. */ readFloat32Array(view: number | Float32Array): Float32Array { if (!ArrayBuffer.isView(view)) { view = new Float32Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readFloat32Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 4; view[i] = uint8ToFloat32(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Read an array of 64 bit floats. */ readFloat64Array(view: number | Float64Array): Float64Array { if (!ArrayBuffer.isView(view)) { view = new Float64Array(view); } if (this.remaining < view.byteLength) { throw new Error(`ByteStream: readFloat64Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`); } const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 8; view[i] = uint8ToFloat64(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3], uint8array[offset + 4], uint8array[offset + 5], uint8array[offset + 6], uint8array[offset + 7]); } this.index += view.byteLength; this.remaining -= view.byteLength; return view; } /** * Write a UTF8 string. * * Returns the number of bytes that were written, */ write(utf8: string): number { const bytes = encodeUtf8(utf8); this.writeUint8Array(bytes); return bytes.length; } /** * Write a UTF8 string as a NULL terminated string. * * Returns the number of bytes that were written, including the terminating NULL. */ writeNull(utf8: string): number { const bytes = this.write(utf8); this.index++; this.remaining--; return bytes + 1; } /** * Write a binary string. */ writeBinary(value: string): void { const index = this.index; const uint8array = this.uint8array; const count = value.length; for (let i = 0; i < count; i++) { uint8array[index + i] = value.charCodeAt(i); } this.index += count; } /** * Write a 8 bit signed integer. */ writeInt8(value: number): void { this.uint8array[this.index] = int8ToUint8(value); this.index += 1; } /** * Write a 16 bit signed integer. */ writeInt16(value: number): void { const index = this.index; const uint8array = this.uint8array; int16ToUint8(uint8, value); uint8array[index] = uint8[0]; uint8array[index + 1] = uint8[1]; this.index += 2; } /** * Write a 32 bit signed integer. */ writeInt32(value: number): void { const index = this.index; const uint8array = this.uint8array; int32ToUint8(uint8, value); uint8array[index] = uint8[0]; uint8array[index + 1] = uint8[1]; uint8array[index + 2] = uint8[2]; uint8array[index + 3] = uint8[3]; this.index += 4; } /** * Write a 8 bit unsigned integer. */ writeUint8(value: number): void { this.uint8array[this.index] = value; this.index += 1; } /** * Write a 16 bit unsigned integer. */ writeUint16(value: number): void { const index = this.index; const uint8array = this.uint8array; uint16ToUint8(uint8, value); uint8array[index] = uint8[0]; uint8array[index + 1] = uint8[1]; this.index += 2; } /** * Write a 32 bit unsigned integer. */ writeUint32(value: number): void { const index = this.index; const uint8array = this.uint8array; uint32ToUint8(uint8, value); uint8array[index] = uint8[0]; uint8array[index + 1] = uint8[1]; uint8array[index + 2] = uint8[2]; uint8array[index + 3] = uint8[3]; this.index += 4; } /** * Write a 32 bit float. */ writeFloat32(value: number): void { const index = this.index; const uint8array = this.uint8array; float32ToUint8(uint8, value); uint8array[index] = uint8[0]; uint8array[index + 1] = uint8[1]; uint8array[index + 2] = uint8[2]; uint8array[index + 3] = uint8[3]; this.index += 4; } /** * Write a 64 bit float. */ writeFloat64(value: number): void { const index = this.index; const uint8array = this.uint8array; float64ToUint8(uint8, value); uint8array[index] = uint8[0]; uint8array[index + 1] = uint8[1]; uint8array[index + 2] = uint8[2]; uint8array[index + 3] = uint8[3]; uint8array[index + 4] = uint8[4]; uint8array[index + 5] = uint8[5]; uint8array[index + 6] = uint8[6]; uint8array[index + 7] = uint8[7]; this.index += 8; } /** * Write an array of 8 bit signed integers. */ writeInt8Array(view: Int8Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { uint8array[index + i] = int8ToUint8(view[i]); } this.index += view.byteLength; } /** * Write an array of 16 bit signed integers. */ writeInt16Array(view: Int16Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 2; int16ToUint8(uint8, view[i]); uint8array[offset] = uint8[0]; uint8array[offset + 1] = uint8[1]; } this.index += view.byteLength; } /** * Write an array of 32 bit signed integers. */ writeInt32Array(view: Int32Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 4; int32ToUint8(uint8, view[i]); uint8array[offset] = uint8[0]; uint8array[offset + 1] = uint8[1]; uint8array[offset + 2] = uint8[2]; uint8array[offset + 3] = uint8[3]; } this.index += view.byteLength; } /** * Write an array of 8 bit unsigned integers. */ writeUint8Array(view: Uint8Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { uint8array[index + i] = view[i]; } this.index += view.byteLength; } /** * Write an array of 16 bit unsigned integers. */ writeUint16Array(view: Uint16Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 2; uint16ToUint8(uint8, view[i]); uint8array[offset] = uint8[0]; uint8array[offset + 1] = uint8[1]; } this.index += view.byteLength; } /** * Write an array of 32 bit unsigned integers. */ writeUint32Array(view: Uint32Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 4; uint32ToUint8(uint8, view[i]); uint8array[offset] = uint8[0]; uint8array[offset + 1] = uint8[1]; uint8array[offset + 2] = uint8[2]; uint8array[offset + 3] = uint8[3]; } this.index += view.byteLength; } /** * Write an array of 32 bit floats. */ writeFloat32Array(view: Float32Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 4; float32ToUint8(uint8, view[i]); uint8array[offset] = uint8[0]; uint8array[offset + 1] = uint8[1]; uint8array[offset + 2] = uint8[2]; uint8array[offset + 3] = uint8[3]; } this.index += view.byteLength; } /** * Write an array of 64 bit floats. */ writeFloat64Array(view: Float64Array): void { const index = this.index; const uint8array = this.uint8array; for (let i = 0, l = view.length; i < l; i++) { const offset = index + i * 8; float64ToUint8(uint8, view[i]); uint8array[offset] = uint8[0]; uint8array[offset + 1] = uint8[1]; uint8array[offset + 2] = uint8[2]; uint8array[offset + 3] = uint8[3]; uint8array[offset + 4] = uint8[4]; uint8array[offset + 5] = uint8[5]; uint8array[offset + 6] = uint8[6]; uint8array[offset + 7] = uint8[7]; } this.index += view.byteLength; } } ================================================ FILE: src/common/bitstream.ts ================================================ import { bytesOf } from './bytesof'; /** * A bit stream. */ export default class BitStream { buffer: ArrayBuffer; uint8array: Uint8Array; index = 0; byteLength: number; bitBuffer = 0; bits = 0; constructor(buffer: ArrayBuffer | Uint8Array, byteOffset?: number, byteLength?: number) { const bytes = bytesOf(buffer); // For browsers not supporting the spec. // Once upon a time I reported this issue on the Firefox tracker. // Seems like Safari needs an issue report too. byteOffset = byteOffset || 0; byteLength = byteLength || bytes.length; this.buffer = buffer; this.uint8array = bytes.subarray(byteOffset, byteOffset + byteLength); this.byteLength = buffer.byteLength; } /** * Peek a number of bits. */ peekBits(bits: number): number { this.loadBits(bits); return this.bitBuffer & ((1 << bits) - 1); } /** * Read a number of bits. */ readBits(bits: number): number { const data = this.peekBits(bits); this.bitBuffer >>>= bits; this.bits -= bits; return data; } /** * Skip a number of bits. */ skipBits(bits: number): void { this.loadBits(bits); this.bitBuffer >>>= bits; this.bits -= bits; } /** * Load more bits into the buffer. */ loadBits(bits: number): void { while (this.bits < bits) { this.bitBuffer += this.uint8array[this.index] << this.bits; this.bits += 8; this.index += 1; } } } ================================================ FILE: src/common/bytesof.ts ================================================ import { encodeUtf8 } from './utf8'; /** * Return the given buffer as a Uint8Array. * * Strings are encoded as UTF8. */ export function bytesOf(buffer: ArrayBuffer | Uint8Array | string | number[]): Uint8Array { if (buffer instanceof Uint8Array) { return buffer; } else if (typeof buffer === 'string') { return encodeUtf8(buffer); } else { return new Uint8Array(buffer); } } ================================================ FILE: src/common/canvas.ts ================================================ let canvas: HTMLCanvasElement; let ctx: CanvasRenderingContext2D; let canvas2: HTMLCanvasElement; let ctx2: CanvasRenderingContext2D; // Only create the canvases and contexts in browsers. if (typeof window === 'object') { canvas = document.createElement('canvas'); ctx = canvas.getContext('2d'); canvas2 = document.createElement('canvas'); ctx2 = canvas2.getContext('2d'); } export function blobToImage(blob: Blob): Promise { return new Promise((resolve, reject) => { const url = URL.createObjectURL(blob); const image = new Image(); image.onload = (): void => { resolve(image); }; image.onerror = (e): void => { reject(e); }; image.src = url; }); } export function blobToImageData(blob: Blob): Promise { return new Promise((resolve, reject) => { const url = URL.createObjectURL(blob); const image = new Image(); image.onload = (): void => { URL.revokeObjectURL(url); canvas.width = image.width; canvas.height = image.height; ctx.drawImage(image, 0, 0); resolve(ctx.getImageData(0, 0, image.width, image.height)); }; image.onerror = (e): void => { reject(e); }; image.src = url; }); } export function imageDataToBlob(imageData: ImageData): Promise { return new Promise((resolve: BlobCallback) => { canvas.width = imageData.width; canvas.height = imageData.height; ctx.putImageData(imageData, 0, 0); canvas.toBlob((blob) => { resolve(blob); }); }); } export function imageDataToDataUrl(imageData: ImageData): string { canvas.width = imageData.width; canvas.height = imageData.height; ctx.putImageData(imageData, 0, 0); return canvas.toDataURL(); } export function imageDataToImage(imageData: ImageData): HTMLImageElement { const image = new Image(); image.src = imageDataToDataUrl(imageData); return image; } export function imageToImageData(image: TexImageSource): ImageData { const width = image.width; const height = image.height; canvas.width = width; canvas.height = height; ctx.drawImage(image, 0, 0); return ctx.getImageData(0, 0, width, height); } export function resizeImageData(data: TexImageSource, width: number, height: number): ImageData { if (data instanceof ImageData) { canvas.width = data.width; canvas.height = data.height; ctx.putImageData(data, 0, 0); canvas2.width = width; canvas2.height = height; ctx2.drawImage(canvas, 0, 0, width, height); return ctx2.getImageData(0, 0, width, height); } else { canvas.width = width; canvas.height = height; ctx.drawImage(data, 0, 0, width, height); return ctx.getImageData(0, 0, width, height); } } ================================================ FILE: src/common/convertbitrange.ts ================================================ /** * Returns a number, which when multiplied with a number of fromBits bits, will convert it to a toBits bits number. * * For example, 7 * convertBitRange(3, 8) == 255. * * In other words, if we look at the bits, 111 is the same to 3 bits as 11111111 is to 8 bits. */ export default function convertBitRange(fromBits: number, toBits: number): number { return ((1 << toBits) - 1) / ((1 << fromBits) - 1); } ================================================ FILE: src/common/dxt.ts ================================================ import convertBitRange from './convertbitrange'; const dxt4to8 = convertBitRange(4, 8); const dxt5to8 = convertBitRange(5, 8); const dxt6to8 = convertBitRange(6, 8); const dx1colors = new Uint8Array(16); const dx3colors = new Uint8Array(12); const dx5alphas = new Uint8Array(8); const red = new Uint8Array(8); const green = new Uint8Array(8); function dx1Colors(out: Uint8Array, color0: number, color1: number): void { const r0 = ((color0 >> 11) & 31) * dxt5to8; const g0 = ((color0 >> 5) & 63) * dxt6to8; const b0 = (color0 & 31) * dxt5to8; const r1 = ((color1 >> 11) & 31) * dxt5to8; const g1 = ((color1 >> 5) & 63) * dxt6to8; const b1 = (color1 & 31) * dxt5to8; // Minimum and maximum colors. out[0] = r0; out[1] = g0; out[2] = b0; out[3] = 255; out[4] = r1; out[5] = g1; out[6] = b1; out[7] = 255; // Interpolated colors. if (color0 > color1) { out[8] = (5 * r0 + 3 * r1) >> 3; out[9] = (5 * g0 + 3 * g1) >> 3; out[10] = (5 * b0 + 3 * b1) >> 3; out[11] = 255; out[12] = (5 * r1 + 3 * r0) >> 3; out[13] = (5 * g1 + 3 * g0) >> 3; out[14] = (5 * b1 + 3 * b0) >> 3; out[15] = 255; } else { out[8] = (r0 + r1) >> 1; out[9] = (g0 + g1) >> 1; out[10] = (b0 + b1) >> 1; out[11] = 255; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 0; } } function dx3Colors(out: Uint8Array, color0: number, color1: number): void { const r0 = ((color0 >> 11) & 31) * dxt5to8; const g0 = ((color0 >> 5) & 63) * dxt6to8; const b0 = (color0 & 31) * dxt5to8; const r1 = ((color1 >> 11) & 31) * dxt5to8; const g1 = ((color1 >> 5) & 63) * dxt6to8; const b1 = (color1 & 31) * dxt5to8; // Minimum and maximum colors. out[0] = r0; out[1] = g0; out[2] = b0; out[3] = r1; out[4] = g1; out[5] = b1; // Interpolated colors. out[6] = (5 * r0 + 3 * r1) >> 3; out[7] = (5 * g0 + 3 * g1) >> 3; out[8] = (5 * b0 + 3 * b1) >> 3; out[9] = (5 * r1 + 3 * r0) >> 3; out[10] = (5 * g1 + 3 * g0) >> 3; out[11] = (5 * b1 + 3 * b0) >> 3; } function dx5Alphas(out: Uint8Array, alpha0: number, alpha1: number): void { // Minimum and maximum alphas. out[0] = alpha0; out[1] = alpha1; // Interpolated alphas. if (alpha0 > alpha1) { out[2] = (54 * alpha0 + 9 * alpha1) >> 6; out[3] = (45 * alpha0 + 18 * alpha1) >> 6; out[4] = (36 * alpha0 + 27 * alpha1) >> 6; out[5] = (27 * alpha0 + 36 * alpha1) >> 6; out[6] = (18 * alpha0 + 45 * alpha1) >> 6; out[7] = (9 * alpha0 + 54 * alpha1) >> 6; } else { out[2] = (12 * alpha0 + 3 * alpha1) >> 4; out[3] = (9 * alpha0 + 6 * alpha1) >> 4; out[4] = (6 * alpha0 + 9 * alpha1) >> 4; out[5] = (3 * alpha0 + 12 * alpha1) >> 4; out[6] = 0; out[7] = 255; } } function rgColors(out: Uint8Array, color0: number, color1: number): void { // Minimum and maximum red colors. out[0] = color0; out[1] = color1; // Interpolated red colors. if (color0 > color1) { out[2] = (6 * color0 + 1 * color1) / 7; out[3] = (5 * color0 + 2 * color1) / 7; out[4] = (4 * color0 + 3 * color1) / 7; out[5] = (3 * color0 + 4 * color1) / 7; out[6] = (2 * color0 + 5 * color1) / 7; out[7] = (1 * color0 + 6 * color1) / 7; } else { out[2] = (4 * color0 + 1 * color1) / 5; out[3] = (3 * color0 + 2 * color1) / 5; out[4] = (2 * color0 + 3 * color1) / 5; out[5] = (1 * color0 + 4 * color1) / 5; out[6] = 0; out[7] = 1; } } /** * Decodes DXT1 data to a Uint8Array typed array with 8-8-8-8 RGBA bits. * * DXT1 is also known as BC1. */ export function decodeDxt1(src: Uint8Array, width: number, height: number): Uint8Array { const dst = new Uint8Array(width * height * 4); for (let blockY = 0, blockHeight = height / 4; blockY < blockHeight; blockY++) { for (let blockX = 0, blockWidth = width / 4; blockX < blockWidth; blockX++) { const i = 8 * (blockY * blockWidth + blockX); // Get the color values. dx1Colors(dx1colors, src[i] + 256 * src[i + 1], src[i + 2] + 256 * src[i + 3]); // The offset to the first pixel in the destination. const dstI = (blockY * 16) * width + blockX * 16; // All 32 color bits. const bits = src[i + 4] | (src[i + 5] << 8) | (src[i + 6] << 16) | (src[i + 7] << 24); for (let row = 0; row < 4; row++) { const rowOffset = row * 8; const dstOffset = dstI + row * width * 4; for (let column = 0; column < 4; column++) { const dstIndex = dstOffset + column * 4; const colorOffset = ((bits >> (rowOffset + column * 2)) & 3) * 4; dst[dstIndex + 0] = dx1colors[colorOffset + 0]; dst[dstIndex + 1] = dx1colors[colorOffset + 1]; dst[dstIndex + 2] = dx1colors[colorOffset + 2]; dst[dstIndex + 3] = dx1colors[colorOffset + 3]; } } } } return dst; } /** * Decodes DXT3 data to a Uint8Array typed array with 8-8-8-8 RGBA bits. * * DXT3 is also known as BC2. */ export function decodeDxt3(src: Uint8Array, width: number, height: number): Uint8Array { const dst = new Uint8Array(width * height * 4); const rowBytes = width * 4; for (let blockY = 0, blockHeight = height / 4; blockY < blockHeight; blockY++) { for (let blockX = 0, blockWidth = width / 4; blockX < blockWidth; blockX++) { const i = 16 * (blockY * blockWidth + blockX); // Get the color values. dx3Colors(dx3colors, src[i + 8] + 256 * src[i + 9], src[i + 10] + 256 * src[i + 11]); let dstI = (blockY * 16) * width + blockX * 16; for (let row = 0; row < 4; row++) { // Get 16 bits of alpha indices. const alphaBits = src[i + row * 2] + 256 * src[i + 1 + row * 2]; // Get 8 bits of color indices. const colorBits = src[i + 12 + row]; for (let column = 0; column < 4; column++) { const dstIndex = dstI + column * 4; const colorIndex = ((colorBits >> (column * 2)) & 3) * 3; dst[dstIndex + 0] = dx3colors[colorIndex + 0]; dst[dstIndex + 1] = dx3colors[colorIndex + 1]; dst[dstIndex + 2] = dx3colors[colorIndex + 2]; dst[dstIndex + 3] = ((alphaBits >> (column * 4)) & 0xf) * dxt4to8; } dstI += rowBytes; } } } return dst; } /** * Decodes DXT5 data to a Uint8Array typed array with 8-8-8-8 RGBA bits. * * DXT5 is also known as BC3. */ export function decodeDxt5(src: Uint8Array, width: number, height: number): Uint8Array { const dst = new Uint8Array(width * height * 4); const rowBytes = width * 4; for (let blockY = 0, blockHeight = height / 4; blockY < blockHeight; blockY++) { for (let blockX = 0, blockWidth = width / 4; blockX < blockWidth; blockX++) { const i = 16 * (blockY * blockWidth + blockX); // Get the alpha values. dx5Alphas(dx5alphas, src[i], src[i + 1]); // Get the color values. dx3Colors(dx3colors, src[i + 8] + 256 * src[i + 9], src[i + 10] + 256 * src[i + 11]); // The offset to the first pixel in the destination. let dstI = (blockY * 16) * width + blockX * 16; // The outer loop is only needed because JS bitwise operators only work on 32bit integers, while the alpha flags contain 48 bits. // Processing is instead done in two blocks, where each one handles 24 bits, or two rows of 4 pixels. for (let block = 0; block < 2; block++) { const alphaOffset = i + 2 + block * 3; const colorOffset = i + 12 + block * 2; // 24 alpha bits. const alphaBits = src[alphaOffset] + 256 * (src[alphaOffset + 1] + 256 * src[alphaOffset + 2]); // Go over two rows. for (let row = 0; row < 2; row++) { const colorBits = src[colorOffset + row]; // Go over four columns. for (let column = 0; column < 4; column++) { const dstIndex = dstI + column * 4; const colorIndex = ((colorBits >> (column * 2)) & 3) * 3; const alphaIndex = (alphaBits >> (row * 12 + column * 3)) & 7; // Set the pixel. dst[dstIndex + 0] = dx3colors[colorIndex + 0]; dst[dstIndex + 1] = dx3colors[colorIndex + 1]; dst[dstIndex + 2] = dx3colors[colorIndex + 2]; dst[dstIndex + 3] = dx5alphas[alphaIndex]; } // Next row. dstI += rowBytes; } } } } return dst; } /** * Decodes RGTC data to a Uint8Array typed array with 8-8 RG bits. * * RGTC is also known as BC5, ATI2, and 3Dc. */ export function decodeRgtc(src: Uint8Array, width: number, height: number): Uint8Array { const dst = new Uint8Array(width * height * 2); const rowBytes = width * 2; for (let blockY = 0, blockHeight = height / 4; blockY < blockHeight; blockY++) { for (let blockX = 0, blockWidth = width / 4; blockX < blockWidth; blockX++) { const i = 16 * (blockY * blockWidth + blockX); // Get the red colors. rgColors(red, src[i], src[i + 1]); // Get the green colors. rgColors(green, src[i + 8], src[i + 9]); // The offset to the first pixel in the destination. let dstI = (blockY * 8) * width + blockX * 8; // Split to two blocks of two rows, because there are 48 color bits. for (let block = 0; block < 2; block++) { const blockOffset = i + block * 3; // Get 24 bits of the color indices. const redbits = src[blockOffset + 2] + 256 * (src[blockOffset + 3] + 256 * src[blockOffset + 4]); const greenbits = src[blockOffset + 10] + 256 * (src[blockOffset + 11] + 256 * src[blockOffset + 12]); for (let row = 0; row < 2; row++) { const rowOffset = row * 4; for (let column = 0; column < 4; column++) { const dstOffset = dstI + column * 2; const shifts = 3 * (rowOffset + column); dst[dstOffset + 1] = red[(redbits >> shifts) & 7]; dst[dstOffset + 2] = green[(greenbits >> shifts) & 7]; } // Next row. dstI += rowBytes; } } } } return dst; } ================================================ FILE: src/common/fetchdatatype.ts ================================================ /** * The valid data type names for resource fetches. */ export type FetchDataTypeName = 'image' | 'text' | 'arrayBuffer' | 'bytes' | 'blob'; /** * The valid data types for resource fetches. */ export type FetchDataType = HTMLImageElement | string | ArrayBuffer | Uint8Array | Blob; /** * The structure that the promise returned by fetchDataType is resolved to. */ export interface FetchResult { ok: boolean; data: FetchDataType | Response | Event; error?: string; } /** * Returns a promise that will resolve with the data from the given path. * * The data type determines the returned object: * * "image" => Image * "text" => string * "arrayBuffer" => ArrayBuffer * "bytes" => Uint8Array * "blob" => Blob */ export async function fetchDataType(path: string, dataType: FetchDataTypeName): Promise { if (dataType === 'image') { // Promise wrapper for an image load. return new Promise((resolve) => { const image = new Image(); image.onload = (): void => { resolve({ ok: true, data: image }); }; image.onerror = (e): void => { resolve({ ok: false, error: 'Image Error', data: e }); }; image.src = path; }); } else { let response: Response; // Fetch. try { response = await fetch(path); } catch (e) { return { ok: false, error: 'Network Error', data: e }; } // Fetch went ok? if (!response.ok) { return { ok: false, error: 'Http Error', data: response }; } // Try to get the requested data type. try { let data: string | ArrayBuffer | Blob | null = null; if (dataType === 'text') { data = await response.text(); } else if (dataType === 'arrayBuffer' || dataType === 'bytes') { data = await response.arrayBuffer(); } else if (dataType === 'blob') { data = await response.blob(); } if (dataType === 'bytes') { data = new Uint8Array(data); } return { ok: true, data }; } catch (e) { return { ok: false, error: 'Data Error', data: e }; } } } ================================================ FILE: src/common/gl-matrix-addon.ts ================================================ import { vec3, vec4, quat, mat4 } from 'gl-matrix'; export const VEC3_UNIT_X = vec3.fromValues(1, 0, 0); export const VEC3_UNIT_Y = vec3.fromValues(0, 1, 0); export const VEC3_UNIT_Z = vec3.fromValues(0, 0, 1); export const VEC3_ZERO = vec3.create(); export const VEC3_ONE = vec3.fromValues(1, 1, 1); export const QUAT_ZERO = quat.fromValues(0, 0, 0, 0); export const QUAT_DEFAULT = quat.create(); const vec4Heap = vec4.create(); export function unproject(out: vec3, v: vec3, inverseMatrix: mat4, viewport: vec4): vec3 { const x = 2 * (v[0] - viewport[0]) / viewport[2] - 1; const y = 1 - 2 * (v[1] - viewport[1]) / viewport[3]; const z = 2 * v[2] - 1; vec4.set(vec4Heap, x, y, z, 1); vec4.transformMat4(vec4Heap, vec4Heap, inverseMatrix); vec3.set(out, vec4Heap[0] / vec4Heap[3], vec4Heap[1] / vec4Heap[3], vec4Heap[2] / vec4Heap[3]); return out; } /** * Get the distance of a point from a plane. * * dot(plane, vec4(point, 1)) */ export function distanceToPlane(plane: vec4, point: vec3): number { return plane[0] * point[0] + plane[1] * point[1] + plane[2] * point[2] + plane[3]; } /** * Get the distance of a point from a plane. * * dot(plane, vec4(x, y, 0, 1)) */ export function distanceToPlane2(plane: vec4, x: number, y: number): number { return plane[0] * x + plane[1] * y + plane[3]; } /** * Get the distance of a point from a plane. * * dot(plane, vec4(x, y, z, 1)) */ export function distanceToPlane3(plane: vec4, x: number, y: number, z: number): number { return plane[0] * x + plane[1] * y + plane[2] * z + plane[3]; } /** * Test if a sphere with the given center and radius intersects the given planes. * If it doesn't, the index of the first plane that proved this is returned. * Otherwise returns -1. * * If first is given, the test will begin from the plane at that index. */ export function testSphere(planes: vec4[], x: number, y: number, z: number, r: number, first: number): number { if (first === -1) { first = 0; } for (let i = 0; i < 6; i++) { const index = (first + i) % 6; if (distanceToPlane3(planes[index], x, y, z) <= -r) { return index; } } return -1; } /** * Test if a cell with the given coordinates intersects the given planes. * If it doesn't, the index of the first plane that proved this is returned. * Otherwise returns -1. * * If first is given, the test will begin from the plane at that index. */ export function testCell(planes: vec4[], left: number, right: number, bottom: number, top: number, first: number): number { if (first === -1) { first = 0; } for (let i = 0; i < 6; i++) { const index = (first + i) % 6; const plane = planes[index]; if (distanceToPlane2(plane, left, bottom) < 0 && distanceToPlane2(plane, left, top) < 0 && distanceToPlane2(plane, right, top) < 0 && distanceToPlane2(plane, right, bottom) < 0) { return index; } } return -1; } export function planeLength(plane: vec4): number { return Math.hypot(plane[0], plane[1], plane[2]); } /** * Normalize a plane. * * Note that this is not the same as normalizing a vec4. */ export function normalizePlane(out: vec4, plane: vec4): void { const len = planeLength(plane); out[0] = plane[0] / len; out[1] = plane[1] / len; out[2] = plane[2] / len; out[3] = plane[3] / len; } /** * Unpacks a matrix's planes. */ export function unpackPlanes(planes: vec4[], m: mat4): void { // eslint-disable-next-line one-var const a00 = m[0], a01 = m[4], a02 = m[8], a03 = m[12], a10 = m[1], a11 = m[5], a12 = m[9], a13 = m[13], a20 = m[2], a21 = m[6], a22 = m[10], a23 = m[14], a30 = m[3], a31 = m[7], a32 = m[11], a33 = m[15]; let plane; // Left clipping plane plane = planes[0]; plane[0] = a30 + a00; plane[1] = a31 + a01; plane[2] = a32 + a02; plane[3] = a33 + a03; // Right clipping plane plane = planes[1]; plane[0] = a30 - a00; plane[1] = a31 - a01; plane[2] = a32 - a02; plane[3] = a33 - a03; // Top clipping plane plane = planes[2]; plane[0] = a30 - a10; plane[1] = a31 - a11; plane[2] = a32 - a12; plane[3] = a33 - a13; // Bottom clipping plane plane = planes[3]; plane[0] = a30 + a10; plane[1] = a31 + a11; plane[2] = a32 + a12; plane[3] = a33 + a13; // Near clipping plane plane = planes[4]; plane[0] = a30 + a20; plane[1] = a31 + a21; plane[2] = a32 + a22; plane[3] = a33 + a23; // Far clipping plane plane = planes[5]; plane[0] = a30 - a20; plane[1] = a31 - a21; plane[2] = a32 - a22; plane[3] = a33 - a23; normalizePlane(planes[0], planes[0]); normalizePlane(planes[1], planes[1]); normalizePlane(planes[2], planes[2]); normalizePlane(planes[3], planes[3]); normalizePlane(planes[4], planes[4]); normalizePlane(planes[5], planes[5]); } const F = vec3.create(); const R = vec3.create(); const U = vec3.create(); /** * A look-at matrix, but for quaternions. * * See https://stackoverflow.com/a/52551983/2503048 */ export function quatLookAt(out: quat, from: vec3, to: vec3, worldUp: vec3): quat { vec3.normalize(F, vec3.sub(F, to, from)); vec3.normalize(R, vec3.cross(R, worldUp, F)); vec3.cross(U, R, F); const trace = R[0] + U[2] + F[1]; if (trace > 0.0) { const s = 0.5 / Math.sqrt(trace + 1.0); out[3] = 0.25 / s; out[0] = (U[1] - F[2]) * s; out[2] = (F[0] - R[1]) * s; out[1] = (R[2] - U[0]) * s; } else { if (R[0] > U[2] && R[0] > F[1]) { const s = 2.0 * Math.sqrt(1.0 + R[0] - U[2] - F[1]); out[3] = (U[1] - F[2]) / s; out[0] = 0.25 * s; out[2] = (U[0] + R[2]) / s; out[1] = (F[0] + R[1]) / s; } else if (U[2] > F[1]) { const s = 2.0 * Math.sqrt(1.0 + U[2] - R[0] - F[1]); out[3] = (F[0] - R[1]) / s; out[0] = (U[0] + R[2]) / s; out[2] = 0.25 * s; out[1] = (F[2] + U[1]) / s; } else { const s = 2.0 * Math.sqrt(1.0 + F[1] - R[0] - U[2]); out[3] = (R[2] - U[0]) / s; out[0] = (F[0] + R[1]) / s; out[2] = (F[2] + U[1]) / s; out[1] = 0.25 * s; } } return out; } ================================================ FILE: src/common/index.ts ================================================ import * as glMatrix from 'gl-matrix'; import * as glMatrixAddon from './gl-matrix-addon'; import * as math from './math'; import * as canvas from './canvas'; import BinaryStream from './binarystream'; import BitStream from './bitstream'; import urlWithParams from './urlwithparams'; import * as path from './path'; import { isPng, isJpeg, isGif, isWebP } from './isformat'; export default { glMatrix, glMatrixAddon, math, canvas, BinaryStream, BitStream, urlWithParams, path, isPng, isJpeg, isGif, isWebP, }; ================================================ FILE: src/common/isformat.ts ================================================ /** * Detects if the given object is a PNG source. * * PNG starts with [89 50 4E 47 0D 0A 1A 0A] */ export function isPng(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47 && bytes[4] === 0x0d && bytes[5] === 0x0a && bytes[6] === 0x1a && bytes[7] === 0x0a) { return true; } } return false; } /** * Detects if the given object is a JPG source. * * JPG starts with [FF D8] and ends with [FF D9] */ export function isJpeg(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[bytes.length - 2] === 0xff && bytes[bytes.length - 1] === 0xd9) { return true; } } return false; } /** * Detects if the given object is a GIF source. * * GIF starts with [47 49 46 38 37 61] or [47 49 46 38 39 61] */ export function isGif(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x38 && (bytes[4] === 0x37 || bytes[4] === 0x39) && bytes[5] === 0x61) { return true; } } return false; } /** * Detects if the given object is a WebP source. * * WebP starts with [52 49 46 46] followed by the file size - 8 followed by [57 45 42 50] */ export function isWebP(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46 && bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50) { return true; } } return false; } ================================================ FILE: src/common/math.ts ================================================ /** * Convert from degrees to radians. */ export function degToRad(degrees: number): number { return degrees * (Math.PI / 180); } /** * Convert from radians to degrees. */ export function radToDeg(radians: number): number { return radians * (180 / Math.PI); } /** * Gets a random number between a range. */ export function randomInRange(a: number, b: number): number { return a + Math.random() * (b - a); } /** * Clamp a number in a range. */ export function clamp(x: number, minVal: number, maxVal: number): number { return Math.min(Math.max(x, minVal), maxVal); } /** * Linear interpolation. */ export function lerp(a: number, b: number, t: number): number { return a + t * (b - a); } /** * Hermite interpolation. */ export function hermite(a: number, b: number, c: number, d: number, t: number): number { const factorTimes2 = t * t; const factor1 = factorTimes2 * (2 * t - 3) + 1; const factor2 = factorTimes2 * (t - 2) + t; const factor3 = factorTimes2 * (t - 1); const factor4 = factorTimes2 * (3 - 2 * t); return (a * factor1) + (b * factor2) + (c * factor3) + (d * factor4); } /** * Bezier interpolation. */ export function bezier(a: number, b: number, c: number, d: number, t: number): number { const invt = 1 - t; const factorTimes2 = t * t; const inverseFactorTimesTwo = invt * invt; const factor1 = inverseFactorTimesTwo * invt; const factor2 = 3 * t * inverseFactorTimesTwo; const factor3 = 3 * factorTimes2 * invt; const factor4 = factorTimes2 * t; return (a * factor1) + (b * factor2) + (c * factor3) + (d * factor4); } /** * Copies the sign of one number onto another. */ export function copysign(x: number, y: number): number { const signy = Math.sign(y); if (signy === 0) { return 0; } const signx = Math.sign(x); if (signx !== signy) { return -x; } return x; } /** * Gets the closest power of two bigger or equal to the given number. */ export function powerOfTwo(x: number): number { x--; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x++; return x; } /** * Is this number a power of two? */ export function isPowerOfTwo(x: number): boolean { if (x === 0) { return false; } return ((x & (x - 1)) === 0); } ================================================ FILE: src/common/path.ts ================================================ /** * Returns the base name of a file path. * * Path/To/My/File.ext => File.ext */ export function basename(path: string): string { if (path && path.length) { let index = path.lastIndexOf('/'); if (index !== -1) { path = path.slice(index + 1); } index = path.lastIndexOf('\\'); if (index !== -1) { path = path.slice(index + 1); } return path; } return ''; } /** * Returns the extension name of a file path. * * Path/To/My/File.ext => .ext */ export function extname(path: string): string { if (path && path.length) { const index = path.lastIndexOf('.'); if (index !== -1) { path = path.slice(index).toLowerCase(); } return path; } return ''; } /** * Returns the base name of a file path without the extension. * * Path/To/My/File.ext => File */ export function filename(path: string): string { path = basename(path); const index = path.lastIndexOf('.'); if (index !== -1) { path = path.slice(0, index); } return path; } ================================================ FILE: src/common/searches.ts ================================================ export function isStringInBytes(buffer: Uint8Array, target: string, offset = 0, length = Infinity): boolean { const start = Math.max(offset, 0); const end = Math.min(start + length, buffer.length); let whichByte = 0; let targetByte = target.charCodeAt(0); for (let i = start; i < end; i++) { const byte = buffer[i]; if (byte === targetByte) { whichByte += 1; if (whichByte === target.length) { return true; } targetByte = target.charCodeAt(whichByte); } else if (whichByte > 0) { whichByte = 0; targetByte = target.charCodeAt(0); } } return false; } export function isStringInString(buffer: string, target: string, offset = 0, length = Infinity): boolean { const start = Math.max(offset, 0); const end = Math.min(start + length, buffer.length); let whichByte = 0; let targetByte = target[0]; for (let i = start; i < end; i++) { const byte = buffer[i]; if (byte === targetByte) { whichByte += 1; if (whichByte === target.length) { return true; } targetByte = target[whichByte]; } else if (whichByte > 0) { whichByte = 0; targetByte = target[0]; } } return false; } export function boundIndexOf(buffer: Uint8Array, target: number, offset = 0, length = Infinity): number { const start = Math.max(offset, 0); const end = Math.min(start + length, buffer.length); for (let i = start; i < end; i++) { if (buffer[i] === target) { return i; } } return -1; } ================================================ FILE: src/common/seededrandom.ts ================================================ /** * Return a function that works in the same exact way as Math.random(), but with the given seed. * See http://indiegamr.com/generate-repeatable-random-numbers-in-js/ */ export default function seededRandom(seed: number) { return (): number => { seed = (seed * 9301 + 49297) % 233280; return seed / 233280; }; } ================================================ FILE: src/common/sstrhash2.ts ================================================ function hash(buffer: Uint8Array): number { let o = 0; let len = buffer.length; let a = 0x9e3779b9; let b = 0x9e3779b9; let c = 0; while (len >= 12) { a += (buffer[o + 0] + (buffer[o + 1] << 8) + (buffer[o + 2] << 16) + (buffer[o + 3] << 24)); b += (buffer[o + 4] + (buffer[o + 5] << 8) + (buffer[o + 6] << 16) + (buffer[o + 7] << 24)); c += (buffer[o + 8] + (buffer[o + 9] << 8) + (buffer[o + 10] << 16) + (buffer[o + 11] << 24)); a -= b; a -= c; a ^= (c >> 13); b -= c; b -= a; b ^= (a << 8); c -= a; c -= b; c ^= (b >> 13); a -= b; a -= c; a ^= (c >> 12); b -= c; b -= a; b ^= (a << 16); c -= a; c -= b; c ^= (b >> 5); a -= b; a -= c; a ^= (c >> 3); b -= c; b -= a; b ^= (a << 10); c -= a; c -= b; c ^= (b >> 15); o += 12; len -= 12; } c += buffer.length; if (len === 11) { c += (buffer[o + 10] << 24); } else if (len === 10) { c += (buffer[o + 9] << 16); } else if (len === 9) { c += (buffer[o + 8] << 8); } else if (len === 8) { b += (buffer[o + 7] << 24); } else if (len === 7) { b += (buffer[o + 6] << 16); } else if (len === 6) { b += (buffer[o + 5] << 8); } else if (len === 5) { b += buffer[o + 4]; } else if (len === 4) { a += (buffer[o + 3] << 24); } else if (len === 3) { a += (buffer[o + 2] << 16); } else if (len === 2) { a += (buffer[o + 1] << 8); } else if (len === 1) { a += buffer[o + 0]; } a -= b; a -= c; a ^= (c >> 13); b -= c; b -= a; b ^= (a << 8); c -= a; c -= b; c ^= (b >> 13); a -= b; a -= c; a ^= (c >> 12); b -= c; b -= a; b ^= (a << 16); c -= a; c -= b; c ^= (b >> 5); a -= b; a -= c; a ^= (c >> 3); b -= c; b -= a; b ^= (a << 10); c -= a; c -= b; c ^= (b >> 15); return c; } const buffer = new Uint8Array(0x400); /** * A hash function used by Warcraft 3's Jass virtual machine. * * See http://burtleburtle.net/bob/hash/doobs.html */ export default function sstrhash2(key: string): number { let offset = 0; buffer.fill(0); for (const char of key) { const byte = char.charCodeAt(0); if (byte < 97 || byte > 122) { if (byte === 47) { // slash to backwards slash. buffer[offset] = 92; } else { buffer[offset] = byte; } } else { // lower case ascii to upper case. buffer[offset] = byte - 0x20; } offset += 1; } return hash(buffer); } ================================================ FILE: src/common/stringreverse.ts ================================================ /** * Reverses a string. */ export default function reverse(s: string): string { return [...s].reverse().join(''); } ================================================ FILE: src/common/typecast.ts ================================================ const buffer = new ArrayBuffer(8); const int8 = new Int8Array(buffer); const int16 = new Int16Array(buffer); const int32 = new Int32Array(buffer); const uint8 = new Uint8Array(buffer); const uint16 = new Uint16Array(buffer); const uint32 = new Uint32Array(buffer); const float32 = new Float32Array(buffer); const float64 = new Float64Array(buffer); /** * Typecast a 8 bit unsigned integer to a 8 bits signed integer. */ export function uint8ToInt8(a: number): number { uint8[0] = a; return int8[0]; } /** * Typecast two 8 bit unsigned integers to a 16 bits signed integer. */ export function uint8ToInt16(a: number, b: number): number { uint8[0] = a; uint8[1] = b; return int16[0]; } /** * Typecast three 8 bit unsigned integers to a 24 bits signed integer. */ export function uint8ToInt24(a: number, b: number, c: number): number { uint8[0] = a; uint8[1] = b; uint8[2] = c; uint8[3] = 0; return int32[0]; } /** * Typecast four 8 bit unsigned integers to a 32 bits signed integer. */ export function uint8ToInt32(a: number, b: number, c: number, d: number): number { uint8[0] = a; uint8[1] = b; uint8[2] = c; uint8[3] = d; return int32[0]; } /** * Typecast two 8 bit unsigned integers to a 16 bits unsigned integer. */ export function uint8ToUint16(a: number, b: number): number { uint8[0] = a; uint8[1] = b; return uint16[0]; } /** * Typecast three 8 bit unsigned integers to a 24 bits unsigned integer. */ export function uint8ToUint24(a: number, b: number, c: number): number { uint8[0] = a; uint8[1] = b; uint8[2] = c; uint8[3] = 0; return uint32[0]; } /** * Typecast four 8 bit unsigned integers to a 32 bits unsigned integer. */ export function uint8ToUint32(a: number, b: number, c: number, d: number): number { uint8[0] = a; uint8[1] = b; uint8[2] = c; uint8[3] = d; return uint32[0]; } /** * Typecast four 8 bit unsigned integers to a 32 bits IEEE float. */ export function uint8ToFloat32(a: number, b: number, c: number, d: number): number { uint8[0] = a; uint8[1] = b; uint8[2] = c; uint8[3] = d; return float32[0]; } /** * Typecast eight 8 bit unsigned integers to a 64 bits IEEE float. */ export function uint8ToFloat64(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number): number { uint8[0] = a; uint8[1] = b; uint8[2] = c; uint8[3] = d; uint8[4] = e; uint8[5] = f; uint8[6] = g; uint8[7] = h; return float64[0]; } /** * Typecast a 8 bit signed integer to a 8 bit unsigned integer. */ export function int8ToUint8(a: number): number { uint8[0] = a; return int8[0]; } /** * Typecast a 16 bit signed integer to two 8 bit unsigned integers. * * The result is stored in out. */ export function int16ToUint8(out: Uint8Array, a: number): Uint8Array { int16[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; return out; } /** * Typecast a 24 bit signed integer to three 8 bit unsigned integers. * * The result is stored in out. */ export function int24ToUint8(out: Uint8Array, a: number): Uint8Array { int32[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; out[2] = uint8[2]; return out; } /** * Typecast a 32 bit signed integer to four 8 bit unsigned integers. * * The result is stored in out. */ export function int32ToUint8(out: Uint8Array, a: number): Uint8Array { int32[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; out[2] = uint8[2]; out[3] = uint8[3]; return out; } /** * Typecast a 16 bit unsigned integer to two 8 bit unsigned integers. * * The result is stored in out. */ export function uint16ToUint8(out: Uint8Array, a: number): Uint8Array { uint16[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; return out; } /** * Typecast a 24 bit unsigned integer to three 8 bit unsigned integers. * * The result is stored in out. */ export function uint24ToUint8(out: Uint8Array, a: number): Uint8Array { uint32[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; out[2] = uint8[2]; return out; } /** * Typecast a 32 bit unsigned integer to four 8 bit unsigned integers. * * The result is stored in out. */ export function uint32ToUint8(out: Uint8Array, a: number): Uint8Array { uint32[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; out[2] = uint8[2]; out[3] = uint8[3]; return out; } /** * Typecast a 32 bit IEEE float to four 8 bit unsigned integers. * * The result is stored in out. */ export function float32ToUint8(out: Uint8Array, a: number): Uint8Array { float32[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; out[2] = uint8[2]; out[3] = uint8[3]; return out; } /** * Typecast a 64 bit IEEE float to eight 8 bit unsigned integers. * * The result is stored in out. */ export function float64ToUint8(out: Uint8Array, a: number): Uint8Array { float64[0] = a; out[0] = uint8[0]; out[1] = uint8[1]; out[2] = uint8[2]; out[3] = uint8[3]; out[4] = uint8[4]; out[5] = uint8[5]; out[6] = uint8[6]; out[7] = uint8[7]; return out; } /** * Typecast a normal JavaScript number to a 32 bits unsigned integer. */ export function numberToUint32(number: number): number { uint32[0] = number; return uint32[0]; } /** * Interperts a string as a base 256 number. */ export function stringToBase256(string: string): number { let number = 0; for (const c of string) { number = number * 256 + c.charCodeAt(0); } return number; } /** * Interperts a number as a base 256 string. */ export function base256ToString(number: number): string { const array = []; while (number > 0) { array.push(String.fromCharCode(number % 256)); number = Math.floor(number / 256); } return array.reverse().join(''); } ================================================ FILE: src/common/urlwithparams.ts ================================================ /** * Appends url parameters given in params to the url given in src. * * The source url can have url parameters already in it. */ export default function urlWithParams(src: string, params: {[key: string]: string }): string { if (params) { const entries = Object.entries(params); if (entries.length) { const encodedParams = entries.map(([key, value]) => `${key}=${value}`).join('&'); let separator = '&'; if (src.indexOf('?') === -1) { separator = '?'; } return `${src}${separator}${encodedParams}`; } } return src; } ================================================ FILE: src/common/utf8.ts ================================================ const decoder = new TextDecoder(); const encoder = new TextEncoder(); /** * Decode bytes as a UTF8 string. */ export function decodeUtf8(buffer: ArrayBuffer | Uint8Array): string { return decoder.decode(buffer); } /** * Encode a UTF8 string to bytes. */ export function encodeUtf8(utf8: string): Uint8Array { return encoder.encode(utf8); } /** * Get the byte length of a UTF8 string. * * @see https://stackoverflow.com/a/23329386 */ export function byteLengthUtf8(str: string): number { // returns the byte length of an utf8 string let s = str.length; for (let i = str.length - 1; i >= 0; i--) { const code = str.charCodeAt(i); if (code > 0x7f && code <= 0x7ff) s++; else if (code > 0x7ff && code <= 0xffff) s += 2; if (code >= 0xDC00 && code <= 0xDFFF) i--; //trail surrogate } return s; } /** * Splits the given string into an array of strings. * * Each string will have a byte length smaller or equal to chunkBytelength when encoded as UTF8. * * @see https://stackoverflow.com/a/18729931 */ export function splitUtf8ByteLength(str: string, chunkBytelength: number): string[] { const chunks = []; let pos = 0; let bytes = 0; for (let i = 0, l = str.length; i < l; i++) { const code = str.charCodeAt(i); if (code < 0x80) { bytes += 1; } else if (code < 0x800) { bytes += 2; } else if (code < 0xd800 || code >= 0xe000) { bytes += 3; } else { i++; bytes += 4; } if (bytes >= chunkBytelength - 3) { chunks.push(str.substr(pos, i)); pos += i; bytes = 0; } } if (bytes > 0) { chunks.push(str.substr(pos)); } return chunks; } ================================================ FILE: src/index.ts ================================================ import { version } from './version'; import common from './common'; import parsers from './parsers'; import viewer from './viewer'; import utils from './utils'; export { version, common, parsers, viewer, utils, }; ================================================ FILE: src/parsers/blp/image.ts ================================================ import BitStream from '../../common/bitstream'; import { bytesOf } from '../../common/bytesof'; import convertBitRange from '../../common/convertbitrange'; import { JpegImage } from './jpg.js'; export const BLP1_MAGIC = 0x31504c42; export const CONTENT_JPG = 0x0; // const CONTENT_PALLETE = 0x1; /** * A BLP1 image. */ export class BlpImage { content = 0; alphaBits = 0; width = 0; height = 0; type = 0; hasMipmaps = false; mipmapOffsets = new Uint32Array(16); mipmapSizes = new Uint32Array(16); uint8array: Uint8Array | null = null; /** * Used for JPG images. */ jpgHeader: Uint8Array | null = null; /** * Used for indexed images. */ pallete: Uint8Array | null = null; load(buffer: ArrayBuffer | Uint8Array): void { const bytes = bytesOf(buffer); // This includes the JPG header size, in case its a JPG image. // Otherwise, the last element is ignored. const header = new Int32Array(bytes.buffer, 0, 40); if (header[0] !== BLP1_MAGIC) { throw new Error('WrongMagicNumber'); } this.content = header[1]; this.alphaBits = header[2]; this.width = header[3]; this.height = header[4]; this.type = header[5]; this.hasMipmaps = header[6] !== 0; for (let i = 0; i < 16; i++) { this.mipmapOffsets[i] = header[7 + i]; this.mipmapSizes[i] = header[23 + i]; } this.uint8array = bytes; if (this.content === CONTENT_JPG) { this.jpgHeader = bytes.subarray(160, 160 + header[39]); } else { this.pallete = bytes.subarray(156, 156 + 1024); } } getMipmap(level: number): ImageData { const uint8array = this.uint8array; const offset = this.mipmapOffsets[level]; const size = this.mipmapSizes[level]; let imageData: ImageData; if (this.content === CONTENT_JPG) { const jpgHeader = this.jpgHeader; const data = new Uint8Array(jpgHeader.length + size); const jpegImage = new JpegImage(); data.set(jpgHeader); data.set(uint8array.subarray(offset, offset + size), jpgHeader.length); jpegImage.parse(data); // The JPG data might not actually match the correct mipmap size. imageData = new ImageData(jpegImage.width, jpegImage.height); jpegImage.getData(imageData); } else { const pallete = this.pallete; const width = Math.max(this.width / (1 << level), 1); // max of 1 because for non-square textures one dimension will eventually be <1. const height = Math.max(this.height / (1 << level), 1); const size = width * height; let alphaBits = this.alphaBits; let bitStream; let bitsToByte = 0; imageData = new ImageData(width, height); if (alphaBits > 0) { if (alphaBits > 8) { alphaBits = 8; } bitStream = new BitStream(uint8array.buffer, offset + size, Math.ceil((size * alphaBits) / 8)); bitsToByte = convertBitRange(alphaBits, 8); } const data = imageData.data; for (let i = 0; i < size; i++) { const dataIndex = i * 4; const paletteIndex = uint8array[offset + i] * 4; // BGRA->RGBA data[dataIndex] = pallete[paletteIndex + 2]; data[dataIndex + 1] = pallete[paletteIndex + 1]; data[dataIndex + 2] = pallete[paletteIndex]; if (alphaBits > 0) { data[dataIndex + 3] = (bitStream).readBits(alphaBits) * bitsToByte; } else { data[dataIndex + 3] = 255; } } } return imageData; } mipmaps(): number { let mipmaps = 0; for (const size of this.mipmapSizes) { if (size > 0) { mipmaps += 1; } } return mipmaps; } fakeMipmaps(): number { const offsets = this.mipmapOffsets; let mipmaps = 0; for (let i = 0; i < 16; i++) { const offset = offsets[i]; if (offset > 0) { for (let j = i + 1; j < 16; j++) { if (offset === offsets[j]) { mipmaps += 1; break; } } } } return mipmaps; } } ================================================ FILE: src/parsers/blp/index.ts ================================================ import { BlpImage as Image } from './image'; export default { Image, }; ================================================ FILE: src/parsers/blp/isformat.ts ================================================ /** * Detects if the given object is a BLP source. */ export default function isBlp(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x42 && bytes[1] === 0x4c && bytes[2] === 0x50 && bytes[3] === 0x31) { return true; } } return false; } ================================================ FILE: src/parsers/blp/jpg.js ================================================ /* eslint-disable */ /* Copyright 2017 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // NOTICE: This file was edited to support loading JPEG data stored in BLP files, which use a non-standard RGBA pixel format. // NOTICE2: It has been edited more to support modern building. const _typeof = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === 'function' && obj.constructor === Symbol && obj !== Symbol.prototype ? 'symbol' : typeof obj; }; const JpegError = function JpegErrorClosure() { function JpegError(msg) { this.message = 'JPEG error: ' + msg; } JpegError.prototype = new Error(); JpegError.prototype.name = 'JpegError'; JpegError.constructor = JpegError; return JpegError; }(); const dctZigZag = new Uint8Array([0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63]); const dctCos1 = 4017; const dctSin1 = 799; const dctCos3 = 3406; const dctSin3 = 2276; const dctCos6 = 1567; const dctSin6 = 3784; const dctSqrt2 = 5793; const dctSqrt1d2 = 2896; function buildHuffmanTable(codeLengths, values) { let k = 0, code = [], i, j, length = 16; while (length > 0 && !codeLengths[length - 1]) { length--; } code.push({ children: [], index: 0, }); let p = code[0], q; for (i = 0; i < length; i++) { for (j = 0; j < codeLengths[i]; j++) { p = code.pop(); p.children[p.index] = values[k]; while (p.index > 0) { p = code.pop(); } p.index++; code.push(p); while (code.length <= i) { code.push(q = { children: [], index: 0, }); p.children[p.index] = q.children; p = q; } k++; } if (i + 1 < length) { code.push(q = { children: [], index: 0, }); p.children[p.index] = q.children; p = q; } } return code[0].children; } function getBlockBufferOffset(component, row, col) { return 64 * ((component.blocksPerLine + 1) * row + col); } function decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successivePrev, successive) { const mcusPerLine = frame.mcusPerLine; const progressive = frame.progressive; let startOffset = offset, bitsData = 0, bitsCount = 0; function readBit() { if (bitsCount > 0) { bitsCount--; return bitsData >> bitsCount & 1; } bitsData = data[offset++]; if (bitsData === 0xFF) { const nextByte = data[offset++]; if (nextByte) { throw new JpegError('unexpected marker ' + (bitsData << 8 | nextByte).toString(16)); } } bitsCount = 7; return bitsData >>> 7; } function decodeHuffman(tree) { let node = tree; while (true) { node = node[readBit()]; if (typeof node === 'number') { return node; } if ((typeof node === 'undefined' ? 'undefined' : _typeof(node)) !== 'object') { throw new JpegError('invalid huffman sequence'); } } } function receive(length) { let n = 0; while (length > 0) { n = n << 1 | readBit(); length--; } return n; } function receiveAndExtend(length) { if (length === 1) { return readBit() === 1 ? 1 : -1; } const n = receive(length); if (n >= 1 << length - 1) { return n; } return n + (-1 << length) + 1; } function decodeBaseline(component, offset) { const t = decodeHuffman(component.huffmanTableDC); const diff = t === 0 ? 0 : receiveAndExtend(t); component.blockData[offset] = component.pred += diff; let k = 1; while (k < 64) { const rs = decodeHuffman(component.huffmanTableAC); const s = rs & 15, r = rs >> 4; if (s === 0) { if (r < 15) { break; } k += 16; continue; } k += r; const z = dctZigZag[k]; component.blockData[offset + z] = receiveAndExtend(s); k++; } } function decodeDCFirst(component, offset) { const t = decodeHuffman(component.huffmanTableDC); const diff = t === 0 ? 0 : receiveAndExtend(t) << successive; component.blockData[offset] = component.pred += diff; } function decodeDCSuccessive(component, offset) { component.blockData[offset] |= readBit() << successive; } let eobrun = 0; function decodeACFirst(component, offset) { if (eobrun > 0) { eobrun--; return; } let k = spectralStart, e = spectralEnd; while (k <= e) { const rs = decodeHuffman(component.huffmanTableAC); const s = rs & 15, r = rs >> 4; if (s === 0) { if (r < 15) { eobrun = receive(r) + (1 << r) - 1; break; } k += 16; continue; } k += r; const z = dctZigZag[k]; component.blockData[offset + z] = receiveAndExtend(s) * (1 << successive); k++; } } let successiveACState = 0, successiveACNextValue; function decodeACSuccessive(component, offset) { let k = spectralStart; const e = spectralEnd; let r = 0; let s; let rs; while (k <= e) { const z = dctZigZag[k]; switch (successiveACState) { case 0: rs = decodeHuffman(component.huffmanTableAC); s = rs & 15; r = rs >> 4; if (s === 0) { if (r < 15) { eobrun = receive(r) + (1 << r); successiveACState = 4; } else { r = 16; successiveACState = 1; } } else { if (s !== 1) { throw new JpegError('invalid ACn encoding'); } successiveACNextValue = receiveAndExtend(s); successiveACState = r ? 2 : 3; } continue; case 1: case 2: if (component.blockData[offset + z]) { component.blockData[offset + z] += readBit() << successive; } else { r--; if (r === 0) { successiveACState = successiveACState === 2 ? 3 : 0; } } break; case 3: if (component.blockData[offset + z]) { component.blockData[offset + z] += readBit() << successive; } else { component.blockData[offset + z] = successiveACNextValue << successive; successiveACState = 0; } break; case 4: if (component.blockData[offset + z]) { component.blockData[offset + z] += readBit() << successive; } break; } k++; } if (successiveACState === 4) { eobrun--; if (eobrun === 0) { successiveACState = 0; } } } function decodeMcu(component, decode, mcu, row, col) { const mcuRow = mcu / mcusPerLine | 0; const mcuCol = mcu % mcusPerLine; const blockRow = mcuRow * component.v + row; const blockCol = mcuCol * component.h + col; const offset = getBlockBufferOffset(component, blockRow, blockCol); decode(component, offset); } function decodeBlock(component, decode, mcu) { const blockRow = mcu / component.blocksPerLine | 0; const blockCol = mcu % component.blocksPerLine; const offset = getBlockBufferOffset(component, blockRow, blockCol); decode(component, offset); } const componentsLength = components.length; let component, i, j, k, n; let decodeFn; if (progressive) { if (spectralStart === 0) { decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive; } else { decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive; } } else { decodeFn = decodeBaseline; } let mcu = 0, fileMarker; let mcuExpected; if (componentsLength === 1) { mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn; } else { mcuExpected = mcusPerLine * frame.mcusPerColumn; } let h, v; while (mcu < mcuExpected) { const mcuToRead = resetInterval ? Math.min(mcuExpected - mcu, resetInterval) : mcuExpected; for (i = 0; i < componentsLength; i++) { components[i].pred = 0; } eobrun = 0; if (componentsLength === 1) { component = components[0]; for (n = 0; n < mcuToRead; n++) { decodeBlock(component, decodeFn, mcu); mcu++; } } else { for (n = 0; n < mcuToRead; n++) { for (i = 0; i < componentsLength; i++) { component = components[i]; h = component.h; v = component.v; for (j = 0; j < v; j++) { for (k = 0; k < h; k++) { decodeMcu(component, decodeFn, mcu, j, k); } } } mcu++; } } bitsCount = 0; fileMarker = findNextFileMarker(data, offset); if (fileMarker && fileMarker.invalid) { // (0, _util.warn)('decodeScan - unexpected MCU data, next marker is: ' + fileMarker.invalid); offset = fileMarker.offset; } const marker = fileMarker && fileMarker.marker; if (!marker || marker <= 0xFF00) { throw new JpegError('marker was not found'); } if (marker >= 0xFFD0 && marker <= 0xFFD7) { offset += 2; } else { break; } } fileMarker = findNextFileMarker(data, offset); if (fileMarker && fileMarker.invalid) { // (0, _util.warn)('decodeScan - unexpected Scan data, next marker is: ' + fileMarker.invalid); offset = fileMarker.offset; } return offset - startOffset; } function quantizeAndInverse(component, blockBufferOffset, p) { const qt = component.quantizationTable, blockData = component.blockData; let v0, v1, v2, v3, v4, v5, v6, v7; let p0, p1, p2, p3, p4, p5, p6, p7; let t; if (!qt) { throw new JpegError('missing required Quantization Table.'); } for (let row = 0; row < 64; row += 8) { p0 = blockData[blockBufferOffset + row]; p1 = blockData[blockBufferOffset + row + 1]; p2 = blockData[blockBufferOffset + row + 2]; p3 = blockData[blockBufferOffset + row + 3]; p4 = blockData[blockBufferOffset + row + 4]; p5 = blockData[blockBufferOffset + row + 5]; p6 = blockData[blockBufferOffset + row + 6]; p7 = blockData[blockBufferOffset + row + 7]; p0 *= qt[row]; if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) { t = dctSqrt2 * p0 + 512 >> 10; p[row] = t; p[row + 1] = t; p[row + 2] = t; p[row + 3] = t; p[row + 4] = t; p[row + 5] = t; p[row + 6] = t; p[row + 7] = t; continue; } p1 *= qt[row + 1]; p2 *= qt[row + 2]; p3 *= qt[row + 3]; p4 *= qt[row + 4]; p5 *= qt[row + 5]; p6 *= qt[row + 6]; p7 *= qt[row + 7]; v0 = dctSqrt2 * p0 + 128 >> 8; v1 = dctSqrt2 * p4 + 128 >> 8; v2 = p2; v3 = p6; v4 = dctSqrt1d2 * (p1 - p7) + 128 >> 8; v7 = dctSqrt1d2 * (p1 + p7) + 128 >> 8; v5 = p3 << 4; v6 = p5 << 4; v0 = v0 + v1 + 1 >> 1; v1 = v0 - v1; t = v2 * dctSin6 + v3 * dctCos6 + 128 >> 8; v2 = v2 * dctCos6 - v3 * dctSin6 + 128 >> 8; v3 = t; v4 = v4 + v6 + 1 >> 1; v6 = v4 - v6; v7 = v7 + v5 + 1 >> 1; v5 = v7 - v5; v0 = v0 + v3 + 1 >> 1; v3 = v0 - v3; v1 = v1 + v2 + 1 >> 1; v2 = v1 - v2; t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12; v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12; v7 = t; t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12; v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12; v6 = t; p[row] = v0 + v7; p[row + 7] = v0 - v7; p[row + 1] = v1 + v6; p[row + 6] = v1 - v6; p[row + 2] = v2 + v5; p[row + 5] = v2 - v5; p[row + 3] = v3 + v4; p[row + 4] = v3 - v4; } for (let col = 0; col < 8; ++col) { p0 = p[col]; p1 = p[col + 8]; p2 = p[col + 16]; p3 = p[col + 24]; p4 = p[col + 32]; p5 = p[col + 40]; p6 = p[col + 48]; p7 = p[col + 56]; if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) { t = dctSqrt2 * p0 + 8192 >> 14; t = t < -2040 ? 0 : t >= 2024 ? 255 : t + 2056 >> 4; blockData[blockBufferOffset + col] = t; blockData[blockBufferOffset + col + 8] = t; blockData[blockBufferOffset + col + 16] = t; blockData[blockBufferOffset + col + 24] = t; blockData[blockBufferOffset + col + 32] = t; blockData[blockBufferOffset + col + 40] = t; blockData[blockBufferOffset + col + 48] = t; blockData[blockBufferOffset + col + 56] = t; continue; } v0 = dctSqrt2 * p0 + 2048 >> 12; v1 = dctSqrt2 * p4 + 2048 >> 12; v2 = p2; v3 = p6; v4 = dctSqrt1d2 * (p1 - p7) + 2048 >> 12; v7 = dctSqrt1d2 * (p1 + p7) + 2048 >> 12; v5 = p3; v6 = p5; v0 = (v0 + v1 + 1 >> 1) + 4112; v1 = v0 - v1; t = v2 * dctSin6 + v3 * dctCos6 + 2048 >> 12; v2 = v2 * dctCos6 - v3 * dctSin6 + 2048 >> 12; v3 = t; v4 = v4 + v6 + 1 >> 1; v6 = v4 - v6; v7 = v7 + v5 + 1 >> 1; v5 = v7 - v5; v0 = v0 + v3 + 1 >> 1; v3 = v0 - v3; v1 = v1 + v2 + 1 >> 1; v2 = v1 - v2; t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12; v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12; v7 = t; t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12; v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12; v6 = t; p0 = v0 + v7; p7 = v0 - v7; p1 = v1 + v6; p6 = v1 - v6; p2 = v2 + v5; p5 = v2 - v5; p3 = v3 + v4; p4 = v3 - v4; p0 = p0 < 16 ? 0 : p0 >= 4080 ? 255 : p0 >> 4; p1 = p1 < 16 ? 0 : p1 >= 4080 ? 255 : p1 >> 4; p2 = p2 < 16 ? 0 : p2 >= 4080 ? 255 : p2 >> 4; p3 = p3 < 16 ? 0 : p3 >= 4080 ? 255 : p3 >> 4; p4 = p4 < 16 ? 0 : p4 >= 4080 ? 255 : p4 >> 4; p5 = p5 < 16 ? 0 : p5 >= 4080 ? 255 : p5 >> 4; p6 = p6 < 16 ? 0 : p6 >= 4080 ? 255 : p6 >> 4; p7 = p7 < 16 ? 0 : p7 >= 4080 ? 255 : p7 >> 4; blockData[blockBufferOffset + col] = p0; blockData[blockBufferOffset + col + 8] = p1; blockData[blockBufferOffset + col + 16] = p2; blockData[blockBufferOffset + col + 24] = p3; blockData[blockBufferOffset + col + 32] = p4; blockData[blockBufferOffset + col + 40] = p5; blockData[blockBufferOffset + col + 48] = p6; blockData[blockBufferOffset + col + 56] = p7; } } function buildComponentData(frame, component) { const blocksPerLine = component.blocksPerLine; const blocksPerColumn = component.blocksPerColumn; const computationBuffer = new Int16Array(64); for (let blockRow = 0; blockRow < blocksPerColumn; blockRow++) { for (let blockCol = 0; blockCol < blocksPerLine; blockCol++) { const offset = getBlockBufferOffset(component, blockRow, blockCol); quantizeAndInverse(component, offset, computationBuffer); } } return component.blockData; } function clamp0to255(a) { return a <= 0 ? 0 : a >= 255 ? 255 : a; } function findNextFileMarker(data, currentPos, startPos) { function peekUint16(pos) { return data[pos] << 8 | data[pos + 1]; } const maxPos = data.length - 1; let newPos = startPos < currentPos ? startPos : currentPos; if (currentPos >= maxPos) { return null; } const currentMarker = peekUint16(currentPos); if (currentMarker >= 0xFFC0 && currentMarker <= 0xFFFE) { return { invalid: null, marker: currentMarker, offset: currentPos, }; } let newMarker = peekUint16(newPos); while (!(newMarker >= 0xFFC0 && newMarker <= 0xFFFE)) { if (++newPos >= maxPos) { return null; } newMarker = peekUint16(newPos); } return { invalid: currentMarker.toString(16), marker: newMarker, offset: newPos, }; } export class JpegImage { constructor() { this.decodeTransform = null; this.colorTransform = -1; this.width = 0; this.height = 0; } parse(data) { function readUint16() { const value = data[offset] << 8 | data[offset + 1]; offset += 2; return value; } function readDataBlock() { const length = readUint16(); let endOffset = offset + length - 2; const fileMarker = findNextFileMarker(data, endOffset, offset); if (fileMarker && fileMarker.invalid) { // (0, _util.warn)('readDataBlock - incorrect length, next marker is: ' + fileMarker.invalid); endOffset = fileMarker.offset; } const array = data.subarray(offset, endOffset); offset += array.length; return array; } function prepareComponents(frame) { const mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH); const mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV); for (let i = 0; i < frame.components.length; i++) { component = frame.components[i]; const blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / frame.maxH); const blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / frame.maxV); const blocksPerLineForMcu = mcusPerLine * component.h; const blocksPerColumnForMcu = mcusPerColumn * component.v; const blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1); component.blockData = new Int16Array(blocksBufferSize); component.blocksPerLine = blocksPerLine; component.blocksPerColumn = blocksPerColumn; } frame.mcusPerLine = mcusPerLine; frame.mcusPerColumn = mcusPerColumn; } var offset = 0; let jfif = null; let adobe = null; let frame, resetInterval; const quantizationTables = []; const huffmanTablesAC = [], huffmanTablesDC = []; let fileMarker = readUint16(); if (fileMarker !== 0xFFD8) { throw new JpegError('SOI not found'); } fileMarker = readUint16(); while (fileMarker !== 0xFFD9) { var i, j, l; switch (fileMarker) { case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3: case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7: case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB: case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF: case 0xFFFE: var appData = readDataBlock(); if (fileMarker === 0xFFE0) { if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 && appData[3] === 0x46 && appData[4] === 0) { jfif = { version: { major: appData[5], minor: appData[6], }, densityUnits: appData[7], xDensity: appData[8] << 8 | appData[9], yDensity: appData[10] << 8 | appData[11], thumbWidth: appData[12], thumbHeight: appData[13], thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13]), }; } } if (fileMarker === 0xFFEE) { if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F && appData[3] === 0x62 && appData[4] === 0x65) { adobe = { version: appData[5] << 8 | appData[6], flags0: appData[7] << 8 | appData[8], flags1: appData[9] << 8 | appData[10], transformCode: appData[11], }; } } break; case 0xFFDB: var quantizationTablesLength = readUint16(); var quantizationTablesEnd = quantizationTablesLength + offset - 2; var z; while (offset < quantizationTablesEnd) { const quantizationTableSpec = data[offset++]; const tableData = new Uint16Array(64); if (quantizationTableSpec >> 4 === 0) { for (j = 0; j < 64; j++) { z = dctZigZag[j]; tableData[z] = data[offset++]; } } else if (quantizationTableSpec >> 4 === 1) { for (j = 0; j < 64; j++) { z = dctZigZag[j]; tableData[z] = readUint16(); } } else { throw new JpegError('DQT - invalid table spec'); } quantizationTables[quantizationTableSpec & 15] = tableData; } break; case 0xFFC0: case 0xFFC1: case 0xFFC2: if (frame) { throw new JpegError('Only single frame JPEGs supported'); } readUint16(); frame = {}; frame.extended = fileMarker === 0xFFC1; frame.progressive = fileMarker === 0xFFC2; frame.precision = data[offset++]; frame.scanLines = readUint16(); frame.samplesPerLine = readUint16(); frame.components = []; frame.componentIds = {}; var componentsCount = data[offset++], componentId; var maxH = 0, maxV = 0; for (i = 0; i < componentsCount; i++) { componentId = data[offset]; const h = data[offset + 1] >> 4; const v = data[offset + 1] & 15; if (maxH < h) { maxH = h; } if (maxV < v) { maxV = v; } const qId = data[offset + 2]; l = frame.components.push({ h: h, v: v, quantizationId: qId, quantizationTable: null, }); frame.componentIds[componentId] = l - 1; offset += 3; } frame.maxH = maxH; frame.maxV = maxV; prepareComponents(frame); break; case 0xFFC4: var huffmanLength = readUint16(); for (i = 2; i < huffmanLength;) { const huffmanTableSpec = data[offset++]; const codeLengths = new Uint8Array(16); let codeLengthSum = 0; for (j = 0; j < 16; j++, offset++) { codeLengthSum += codeLengths[j] = data[offset]; } const huffmanValues = new Uint8Array(codeLengthSum); for (j = 0; j < codeLengthSum; j++, offset++) { huffmanValues[j] = data[offset]; } i += 17 + codeLengthSum; (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = buildHuffmanTable(codeLengths, huffmanValues); } break; case 0xFFDD: readUint16(); resetInterval = readUint16(); break; case 0xFFDA: readUint16(); var selectorsCount = data[offset++]; var components = [], component; for (i = 0; i < selectorsCount; i++) { const componentIndex = frame.componentIds[data[offset++]]; component = frame.components[componentIndex]; const tableSpec = data[offset++]; component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4]; component.huffmanTableAC = huffmanTablesAC[tableSpec & 15]; components.push(component); } var spectralStart = data[offset++]; var spectralEnd = data[offset++]; var successiveApproximation = data[offset++]; var processed = decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15); offset += processed; break; case 0xFFFF: if (data[offset] !== 0xFF) { offset--; } break; default: if (data[offset - 3] === 0xFF && data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) { offset -= 3; break; } throw new JpegError('unknown marker ' + fileMarker.toString(16)); } fileMarker = readUint16(); } this.width = frame.samplesPerLine; this.height = frame.scanLines; this.jfif = jfif; this.adobe = adobe; this.components = []; for (i = 0; i < frame.components.length; i++) { component = frame.components[i]; const quantizationTable = quantizationTables[component.quantizationId]; if (quantizationTable) { component.quantizationTable = quantizationTable; } this.components.push({ output: buildComponentData(frame, component), scaleX: component.h / frame.maxH, scaleY: component.v / frame.maxV, blocksPerLine: component.blocksPerLine, blocksPerColumn: component.blocksPerColumn, }); } this.numComponents = this.components.length; } getData(imageData) { const data = imageData.data; const components = this.components; const lineData = new Uint8Array((components[0].blocksPerLine << 3) * components[0].blocksPerColumn * 8); // NOTICE: This forces BGR->RGB conversion without adding any costs, since really we know this is going to be a hacky BGRA BLP file. [components[0], components[2]] = [components[2], components[0]]; for (let i = 0, numComponents = components.length; i < numComponents; i++) { const component = components[i]; const blocksPerLine = component.blocksPerLine; const blocksPerColumn = component.blocksPerColumn; const samplesPerLine = blocksPerLine << 3; var j, k, ll = 0; var lineOffset = 0; for (let blockRow = 0; blockRow < blocksPerColumn; blockRow++) { const scanLine = blockRow << 3; for (let blockCol = 0; blockCol < blocksPerLine; blockCol++) { const bufferOffset = getBlockBufferOffset(component, blockRow, blockCol); let offset2 = 0, sample = blockCol << 3; for (j = 0; j < 8; j++) { var lineOffset = (scanLine + j) * samplesPerLine; for (k = 0; k < 8; k++) { lineData[lineOffset + sample + k] = component.output[bufferOffset + offset2++]; } } } } let offset = i; for (let y = 0; y < this.height; y++) { for (let x = 0; x < this.width; x++) { data[offset] = lineData[y * samplesPerLine + x]; offset += numComponents; } } } return data; } } ================================================ FILE: src/parsers/dds/image.ts ================================================ import { base256ToString } from '../../common/typecast'; import { decodeDxt1, decodeDxt3, decodeDxt5, decodeRgtc } from '../../common/dxt'; import { bytesOf } from '../../common/bytesof'; export const DDS_MAGIC = 0x20534444; const DDSD_MIPMAPCOUNT = 0x20000; const DDPF_FOURCC = 0x4; export const FOURCC_DXT1 = 0x31545844; export const FOURCC_DXT3 = 0x33545844; export const FOURCC_DXT5 = 0x35545844; export const FOURCC_ATI2 = 0x32495441; const FOURCC_DX10 = 0x30315844; const DXGI_FORMAT_BC1_UNORM = 0x00000047; const DXGI_FORMAT_BC2_UNORM = 0x0000004A; const DXGI_FORMAT_BC3_UNORM = 0x0000004D; const DXGI_FORMAT_BC5_UNORM = 0x00000053; /** * A DDS image. */ export class DdsImage { width = 0; height = 0; format = 0; mipmapWidths: number[] = []; mipmapHeights: number[] = []; mipmapDatas: Uint8Array[] = []; load(buffer: ArrayBuffer | Uint8Array): void { const bytes = bytesOf(buffer); const header = new Int32Array(bytes.buffer, 0, 31); let offset = 128; // sizeof(DDS_HEADER) + 4 for the magic. if (header[0] !== DDS_MAGIC) { throw new Error('Wrong magic number'); } if (!(header[20] & DDPF_FOURCC)) { throw new Error('Not FourCC'); } let fourCC = header[21]; if (fourCC !== FOURCC_DXT1 && fourCC !== FOURCC_DXT3 && fourCC !== FOURCC_DXT5 && fourCC !== FOURCC_ATI2) { if (fourCC === FOURCC_DX10) { offset += 20; // sizeof(DDS_HEADER_DXT10) const extendedHeader = new Int32Array(bytes.buffer, 128, 5); const dxgiFormat = extendedHeader[0]; if (dxgiFormat === DXGI_FORMAT_BC1_UNORM) { fourCC = FOURCC_DXT1; } else if (dxgiFormat === DXGI_FORMAT_BC2_UNORM) { fourCC = FOURCC_DXT3; } else if (dxgiFormat === DXGI_FORMAT_BC3_UNORM) { fourCC = FOURCC_DXT5; } else if (dxgiFormat === DXGI_FORMAT_BC5_UNORM) { fourCC = FOURCC_ATI2; } else { throw new Error(`Unsupported DXGI format: ${dxgiFormat}`); } console.log(extendedHeader); } else { throw new Error(`Unsupported FourCC: ${base256ToString(fourCC)}`); } } this.format = fourCC; let mipmaps = 1; if (header[2] & DDSD_MIPMAPCOUNT) { mipmaps = Math.max(1, header[7]); } let width = header[4]; let height = header[3]; let blockSize = 16; // DXT3, DXT5, and RGTC, all have 16 bytes per block. if (fourCC === FOURCC_DXT1) { blockSize = 8; } this.width = width; this.height = height; for (let i = 0; i < mipmaps; i++) { const size = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockSize; this.mipmapWidths[i] = width; this.mipmapHeights[i] = height; this.mipmapDatas[i] = bytes.subarray(offset, offset + size); offset += size; width = Math.max(width / 2, 1); height = Math.max(height / 2, 1); } } mipmaps(): number { return this.mipmapDatas.length; } getMipmap(level: number, raw = false): { width: number, height: number, data: Uint8Array } { const width = this.mipmapWidths[level]; const height = this.mipmapHeights[level]; const data = this.mipmapDatas[level]; let mipmap: Uint16Array | Uint8Array; if (raw) { mipmap = data; } else if (this.format === FOURCC_DXT1) { mipmap = decodeDxt1(data, width, height); } else if (this.format === FOURCC_DXT3) { mipmap = decodeDxt3(data, width, height); } else if (this.format === FOURCC_DXT5) { mipmap = decodeDxt5(data, width, height); } else { mipmap = decodeRgtc(data, width, height); } return { width, height, data: mipmap }; } } ================================================ FILE: src/parsers/dds/index.ts ================================================ import { DdsImage as Image, FOURCC_DXT1, FOURCC_DXT3, FOURCC_DXT5, FOURCC_ATI2 } from './image'; import isDds from './isformat'; export default { Image, FOURCC_DXT1, FOURCC_DXT3, FOURCC_DXT5, FOURCC_ATI2, isDds, }; ================================================ FILE: src/parsers/dds/isformat.ts ================================================ /** * Detects if the given object is a DDS source. */ export default function isDds(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x44 && bytes[1] === 0x44 && bytes[2] === 0x53 && bytes[3] === 0x20) { return true; } } return false; } ================================================ FILE: src/parsers/index.ts ================================================ import ini from './ini'; import slk from './slk'; import m3 from './m3'; import mdlx from './mdlx'; import mpq from './mpq'; import w3x from './w3x'; import blp from './blp'; import dds from './dds'; import tga from './tga'; export default { ini, slk, m3, mdlx, mpq, w3x, blp, dds, tga, }; ================================================ FILE: src/parsers/ini/file.ts ================================================ /** * An INI section. */ export type IniSection = Map; /** * An INI file. */ export class IniFile { properties: Map = new Map(); sections: Map = new Map(); load(buffer: string): void { // All properties added until a section is reached are added to the properties map. // Once a section is reached, any further properties will be added to it until matching another section, etc. let section: IniSection | null = this.properties; const sections = this.sections; for (const line of buffer.split('\r\n')) { // INI defines comments as starting with a semicolon ';'. // However, Warcraft 3 INI files use normal C comments '//'. // In addition, Warcraft 3 files have empty lines. // Therefore, ignore any line matching any of these conditions. if (line.length && !line.startsWith('//') && !line.startsWith(';')) { let match = line.match(/^\[(.+?)\]/); if (match) { const name = match[1].trim(); section = sections.get(name); if (!section) { section = new Map(); sections.set(name, section); } } else { match = line.match(/^(.+?)=(.*?)$/); if (match) { let value = match[2]; if (value[0] === '"') { value = value.slice(1, -1); } section.set(match[1], value); } } } } } save(): string { const lines = []; for (const [key, value] of this.properties) { lines.push(`${key}=${value}`); } for (const [name, section] of this.sections) { lines.push(`[${name}]`); for (const [key, value] of section) { lines.push(`${key}=${value}`); } } return lines.join('\r\n'); } getSection(name: string): IniSection | undefined { return this.sections.get(name); } } ================================================ FILE: src/parsers/ini/index.ts ================================================ import { IniFile as File } from './file'; export default { File, }; ================================================ FILE: src/parsers/m3/animationreference.ts ================================================ import BinaryStream from '../../common/binarystream'; /** * The base class to all animation references. */ export abstract class AnimationReference { interpolationType = 0; animFlags = 0; animId = -1; initValue: number | Uint8Array | Float32Array | null = null; nullValue: number | Uint8Array | Float32Array | null = null; abstract readInitNullValues(stream: BinaryStream): void; load(stream: BinaryStream): void { this.interpolationType = stream.readUint16(); this.animFlags = stream.readUint16(); this.animId = stream.readUint32(); this.readInitNullValues(stream); stream.skip(4); // ? } } /** * A pixel animation reference. */ export class PixelAnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readUint8Array(4); this.nullValue = stream.readUint8Array(4); } } /** * A uint16 animation reference. */ export class Uint16AnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readUint16(); this.nullValue = stream.readUint16(); } } /** * A uint32 animation reference. */ export class Uint32AnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readUint32(); this.nullValue = stream.readUint32(); } } /** * A float32 animation reference. */ export class Float32AnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readFloat32(); this.nullValue = stream.readFloat32(); } } /** * A vec2 animation reference. */ export class Vector2AnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readFloat32Array(2); this.nullValue = stream.readFloat32Array(2); } } /** * A vec3 animation reference. */ export class Vector3AnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readFloat32Array(3); this.nullValue = stream.readFloat32Array(3); } } /** * A quat animation reference. */ export class Vector4AnimationReference extends AnimationReference { readInitNullValues(stream: BinaryStream): void { this.initValue = stream.readFloat32Array(4); this.nullValue = stream.readFloat32Array(4); } } ================================================ FILE: src/parsers/m3/attachmentpoint.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * An attachment point. */ export default class AttachmentPoint { version = -1; unknown = 0; name = new Reference(); bone = -1; load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.unknown = stream.readInt32(); this.name.load(stream, index); this.bone = stream.readUint32(); } } ================================================ FILE: src/parsers/m3/batch.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; /** * A batch. */ export default class Batch { version = -1; unknown0 = 0; regionIndex = -1; unknown1 = 0; materialReferenceIndex = -1; unknown2 = 0; load(stream: BinaryStream, version: number, _index: IndexEntry[]): void { this.version = version; this.unknown0 = stream.readUint32(); this.regionIndex = stream.readUint16(); this.unknown1 = stream.readUint32(); this.materialReferenceIndex = stream.readUint16(); this.unknown2 = stream.readUint16(); } } ================================================ FILE: src/parsers/m3/bone.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; import { Uint32AnimationReference, Vector3AnimationReference, Vector4AnimationReference } from './animationreference'; /** * A bone. */ export default class Bone { version = -1; unknown0 = 0; name = new Reference(); flags = 0; parent = -1; unknown1 = 0; location = new Vector3AnimationReference(); rotation = new Vector4AnimationReference(); scale = new Vector3AnimationReference(); visibility = new Uint32AnimationReference(); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.unknown0 = stream.readInt32(); this.name.load(stream, index); this.flags = stream.readUint32(); this.parent = stream.readInt16(); this.unknown1 = stream.readUint16(); this.location.load(stream); this.rotation.load(stream); this.scale.load(stream); this.visibility.load(stream); } } ================================================ FILE: src/parsers/m3/boundingshape.ts ================================================ import BinaryStream from '../../common/binarystream'; /** * A bounding shape. */ export default class BoundingShape { shape = -1; bone = -1; unknown0 = 0; matrix = new Float32Array(16); unknown1 = 0; unknown2 = 0; unknown3 = 0; unknown4 = 0; unknown5 = 0; unknown6 = 0; size = new Float32Array(3); load(stream: BinaryStream): void { this.shape = stream.readUint32(); this.bone = stream.readInt16(); this.unknown0 = stream.readUint16(); stream.readFloat32Array(this.matrix); this.unknown1 = stream.readUint32(); this.unknown2 = stream.readUint32(); this.unknown3 = stream.readUint32(); this.unknown4 = stream.readUint32(); this.unknown5 = stream.readUint32(); this.unknown6 = stream.readUint32(); stream.readFloat32Array(this.size); } } ================================================ FILE: src/parsers/m3/boundingsphere.ts ================================================ import BinaryStream from '../../common/binarystream'; /** * A bounding sphere. */ export default class BoundingSphere { min = new Float32Array(3); max = new Float32Array(3); radius = 0; load(stream: BinaryStream): void { stream.readFloat32Array(this.min); stream.readFloat32Array(this.max); this.radius = stream.readFloat32(); } } ================================================ FILE: src/parsers/m3/camera.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; import { Float32AnimationReference } from './animationreference'; /** * A camera. */ export default class Camera { version = -1; bone = -1; name = new Reference(); fieldOfView = new Float32AnimationReference(); unknown0 = 0; farClip = new Float32AnimationReference(); nearClip = new Float32AnimationReference(); clip2 = new Float32AnimationReference(); focalDepth = new Float32AnimationReference(); falloffStart = new Float32AnimationReference(); falloffEnd = new Float32AnimationReference(); depthOfField = new Float32AnimationReference(); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.bone = stream.readUint32(); this.name.load(stream, index); this.fieldOfView.load(stream); this.unknown0 = stream.readUint32(); this.farClip.load(stream); this.nearClip.load(stream); this.clip2.load(stream); this.focalDepth.load(stream); this.falloffStart.load(stream); this.falloffEnd.load(stream); this.depthOfField.load(stream); } } ================================================ FILE: src/parsers/m3/division.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * A division. */ export default class Division { version = -1; triangles = new Reference(); regions = new Reference(); batches = new Reference(); MSEC = new Reference(); unknown0 = 0; load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.triangles.load(stream, index); this.regions.load(stream, index); this.batches.load(stream, index); this.MSEC.load(stream, index); this.unknown0 = stream.readUint32(); } } ================================================ FILE: src/parsers/m3/event.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * An event. */ export default class Event { version = -1; name = new Reference(); unknown0 = 0; unknown1 = 0; unknown2 = 0; matrix = new Float32Array(16); unknown3 = 0; unknown4 = 0; unknown5 = 0; unknown6 = 0; unknown7 = 0; unknown8 = 0; load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.name.load(stream, index); this.unknown0 = stream.readInt32(); this.unknown1 = stream.readInt16(); this.unknown2 = stream.readUint16(); stream.readFloat32Array(this.matrix); this.unknown3 = stream.readInt32(); this.unknown4 = stream.readInt32(); this.unknown5 = stream.readInt32(); if (version > 0) { this.unknown6 = stream.readInt32(); this.unknown7 = stream.readInt32(); } if (version > 1) { this.unknown8 = stream.readInt32(); } } } ================================================ FILE: src/parsers/m3/index.ts ================================================ import Model from './model'; import isM3 from './isformat'; export default { Model, isM3, }; ================================================ FILE: src/parsers/m3/indexentry.ts ================================================ import reverse from '../../common/stringreverse'; import BinaryStream from '../../common/binarystream'; import Md34 from './md34'; import ModelHeader from './modelheader'; import Sequence from './sequence'; import Stc from './stc'; import Stg from './stg'; import Sts from './sts'; import Bone from './bone'; import Division from './division'; import Region from './region'; import Batch from './batch'; import MaterialReference from './materialreference'; import StandardMaterial from './standardmaterial'; import Layer from './layer'; import Event from './event'; import BoundingSphere from './boundingsphere'; import AttachmentPoint from './attachmentpoint'; import Camera from './camera'; import Sd from './sd'; import UnsupportedEntry from './unsupportedentry'; // Mapping from entry tags, to their constructors and known version->size values. const tagMapping = { // Objects MD34: [Md34, { 11: 24 }], MODL: [ModelHeader, { 23: 784, 25: 808, 26: 820, 28: 844, 29: 856 }], SEQS: [Sequence, { 1: 96, 2: 92 }], STC_: [Stc, { 4: 204 }], STG_: [Stg, { 0: 24 }], STS_: [Sts, { 0: 28 }], BONE: [Bone, { 1: 160 }], DIV_: [Division, { 2: 52 }], REGN: [Region, { 3: 36, 4: 40, 5: 48 }], BAT_: [Batch, { 1: 14 }], MATM: [MaterialReference, { 0: 8 }], MAT_: [StandardMaterial, { 15: 268, 16: 280, 17: 280, 18: 280, 19: 340 }], LAYR: [Layer, { 22: 356, 24: 436, 25: 468, 26: 464 }], EVNT: [Event, { 0: 96, 1: 104, 2: 108 }], BNDS: [BoundingSphere, { 0: 28 }], ATT_: [AttachmentPoint, { 1: 20 }], CAM_: [Camera, { 3: 180, 5: 264 }], SDEV: [Sd, { 0: 32 }], SDU6: [Sd, { 0: 32 }], SDFG: [Sd, { 0: 32 }], SDS6: [Sd, { 0: 32 }], SDR3: [Sd, { 0: 32 }], SD2V: [Sd, { 0: 32 }], SD3V: [Sd, { 0: 32 }], SD4Q: [Sd, { 0: 32 }], SDCC: [Sd, { 0: 32 }], SDMB: [Sd, { 0: 32 }], FLAG: [Sd, { 0: 32 }], // Unsupported entries MSEC: [UnsupportedEntry, { 1: 72 }], LITE: [UnsupportedEntry, { 7: 212 }], ATVL: [UnsupportedEntry, { 0: 116 }], PATU: [UnsupportedEntry, { 4: 152 }], TRGD: [UnsupportedEntry, { 0: 24 }], DIS_: [UnsupportedEntry, { 4: 68 }], CMS_: [UnsupportedEntry, { 0: 24 }], CMP_: [UnsupportedEntry, { 2: 28 }], TER_: [UnsupportedEntry, { 0: 24, 1: 28 }], VOL_: [UnsupportedEntry, { 0: 84 }], VON_: [UnsupportedEntry, { 0: 268 }], CREP: [UnsupportedEntry, { 0: 24, 1: 28 }], STBM: [UnsupportedEntry, { 0: 48 }], LFSB: [UnsupportedEntry, { 2: 56 }], LFLR: [UnsupportedEntry, { 2: 80, 3: 152 }], PAR_: [UnsupportedEntry, { 12: 1316, 17: 1460, 18: 1464, 19: 1464, 21: 1464, 22: 1484, 23: 1492, 24: 1496 }], PARC: [UnsupportedEntry, { 0: 40 }], PROJ: [UnsupportedEntry, { 4: 388, 5: 382 }], PHYJ: [UnsupportedEntry, { 0: 180 }], PHCC: [UnsupportedEntry, { 0: 76 }], PHAC: [UnsupportedEntry, { 0: 32 }], PHCL: [UnsupportedEntry, { 2: 128 }], FOR_: [UnsupportedEntry, { 1: 104, 2: 104 }], DMSE: [UnsupportedEntry, { 0: 4 }], PHSH: [UnsupportedEntry, { 1: 132, 3: 300 }], PHRB: [UnsupportedEntry, { 2: 104, 4: 80 }], SSGS: [UnsupportedEntry, { 1: 108 }], BBSC: [UnsupportedEntry, { 0: 48 }], SRIB: [UnsupportedEntry, { 0: 272 }], RIB_: [UnsupportedEntry, { 6: 748, 8: 756, 9: 760 }], IKJT: [UnsupportedEntry, { 0: 32 }], SHBX: [UnsupportedEntry, { 0: 64 }], WRP_: [UnsupportedEntry, { 1: 132 }], }; export type EntryType = Md34[] | ModelHeader[] | Sequence[] | Stc[] | Stg[] | Sts[] | Bone[] | Division[] | Region[] | Batch[] | MaterialReference[] | StandardMaterial[] | Layer[] | Event[] | BoundingSphere[] | AttachmentPoint[] | Camera[] | Sd[] | UnsupportedEntry[] | string | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Float32Array | Float32Array[]; export type SingleEntryType = Md34 | ModelHeader | Sequence | Stc | Stg | Sts | Bone | Division | Region | Batch | MaterialReference | StandardMaterial | Layer | Event | BoundingSphere | AttachmentPoint | Camera | Sd | UnsupportedEntry | string | number | Float32Array; /** * An index entry. */ export default class IndexEntry { index: IndexEntry[]; tag: string; offset: number; version: number; entries: EntryType; constructor(stream: BinaryStream, index: IndexEntry[]) { const tag = reverse(stream.readBinary(4)); const offset = stream.readUint32(); const entriesCount = stream.readUint32(); const version = stream.readUint32(); this.index = index; this.tag = tag; this.offset = offset; this.version = version; const mapping = tagMapping[tag]; const readerOffset = stream.index; stream.seek(offset); // This is an object if (mapping) { const constructor = mapping[0]; const entrySize = mapping[1][version]; if (!entrySize) { // Yey found a new version! throw new Error(': Unsupported object version - tag ' + tag + ' and version ' + version); } this.entries = []; for (let i = 0, l = entriesCount; i < l; i++) { // A sub stream is given for each object constructor. // This allows for parsing to work consistently, even if we don't quite know exactly how the structures look. // If some bytes aren't read, the error will not carry to the next object. // Since new versions of objects usually add data to the end, this allows the parser to work, even if trying to load newer versions. // Of course, the new version size needs to be added to IndexEntry.tagMapping, when finding one. if (constructor === UnsupportedEntry) { this.entries[i] = new UnsupportedEntry(stream.substream(entrySize), version, index); } else { const entry = new constructor(); entry.load(stream.substream(entrySize), version, index); this.entries[i] = entry; } } // This is maybe a typed array? } else if (tag === 'CHAR' || tag === 'SCHR') { this.entries = stream.read(entriesCount); } else if (tag === 'U8__') { this.entries = stream.readUint8Array(entriesCount); } else if (tag === 'U16_') { this.entries = stream.readUint16Array(entriesCount); } else if (tag === 'U32_') { this.entries = stream.readUint32Array(entriesCount); } else if (tag === 'I16_') { this.entries = stream.readInt16Array(entriesCount); } else if (tag === 'I32_') { this.entries = stream.readInt32Array(entriesCount); } else if (tag === 'REAL') { this.entries = stream.readFloat32Array(entriesCount); } else if (tag === 'VEC2') { this.entries = []; for (let i = 0; i < entriesCount; i++) { this.entries[i] = stream.readFloat32Array(2); } } else if (tag === 'VEC3' || tag === 'SVC3') { this.entries = []; for (let i = 0; i < entriesCount; i++) { this.entries[i] = stream.readFloat32Array(3); } } else if (tag === 'VEC4' || tag === 'QUAT') { this.entries = []; for (let i = 0; i < entriesCount; i++) { this.entries[i] = stream.readFloat32Array(4); } } else if (tag === 'IREF') { this.entries = []; for (let i = 0; i < entriesCount; i++) { this.entries[i] = stream.readFloat32Array(16); } } else { this.entries = []; throw new Error(': Unsupported object tag - tag ' + tag + ' and version ' + version); } stream.seek(readerOffset); } } ================================================ FILE: src/parsers/m3/isformat.ts ================================================ /** * Detects if the given object is an M3 source. */ export default function isM3(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x34 && bytes[1] === 0x33 && bytes[2] === 0x44 && bytes[3] === 0x4d) { return true; } } return false; } ================================================ FILE: src/parsers/m3/layer.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; import { PixelAnimationReference, Uint16AnimationReference, Uint32AnimationReference, Float32AnimationReference, Vector2AnimationReference, Vector3AnimationReference } from './animationreference'; /** * A layer. */ export default class Layer { version = -1; unknown0 = 0; imagePath = new Reference(); color = new PixelAnimationReference(); flags = 0; uvSource = -1; colorChannelSetting = 0; brightMult = new Float32AnimationReference(); midtoneOffset = new Float32AnimationReference(); unknown1 = 0; noiseAmp = 0; noiseFreq = 0; rttChannel = 0; videoFrameRate = 0; videoStartFrame = 0; videoEndFrame = 0; videoMode = 0; videoSyncTiming = 0; videoPlay = new Uint32AnimationReference(); videoRestart = new Uint32AnimationReference(); flipBookRows = 0; flipBookColumns = 0; flipBookFrame = new Uint16AnimationReference(); uvOffset = new Vector2AnimationReference(); uvAngle = new Vector3AnimationReference(); uvTiling = new Vector2AnimationReference(); unknown2 = new Uint32AnimationReference(); unknown3 = new Float32AnimationReference(); brightness = new Float32AnimationReference(); triPlanarOffset = new Vector3AnimationReference(); triPlanarScale = new Vector3AnimationReference(); unknown4 = 0; fresnelType = 0; fresnelExponent = 0; fresnelMin = 0; fresnelMaxOffset = 0; unknown5 = 0; unknown6 = new Uint8Array(8); fresnelInvertedMaskX = 0; fresnelInvertedMaskY = 0; fresnelInvertedMaskZ = 0; fresnelRotationYaw = 0; fresnelRotationPitch = 0; unknown7 = 0; load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.unknown0 = stream.readUint32(); this.imagePath.load(stream, index); this.color.load(stream); this.flags = stream.readUint32(); this.uvSource = stream.readUint32(); this.colorChannelSetting = stream.readUint32(); this.brightMult.load(stream); this.midtoneOffset.load(stream); this.unknown1 = stream.readUint32(); if (version > 23) { this.noiseAmp = stream.readFloat32(); this.noiseFreq = stream.readFloat32(); } this.rttChannel = stream.readInt32(); this.videoFrameRate = stream.readUint32(); this.videoStartFrame = stream.readUint32(); this.videoEndFrame = stream.readInt32(); this.videoMode = stream.readUint32(); this.videoSyncTiming = stream.readUint32(); this.videoPlay.load(stream); this.videoRestart.load(stream); this.flipBookRows = stream.readUint32(); this.flipBookColumns = stream.readUint32(); this.flipBookFrame.load(stream); this.uvOffset.load(stream); this.uvAngle.load(stream); this.uvTiling.load(stream); this.unknown2.load(stream); this.unknown3.load(stream); this.brightness.load(stream); if (version > 23) { this.triPlanarOffset.load(stream); this.triPlanarScale.load(stream); } this.unknown4 = stream.readInt32(); this.fresnelType = stream.readUint32(); this.fresnelExponent = stream.readFloat32(); this.fresnelMin = stream.readFloat32(); this.fresnelMaxOffset = stream.readFloat32(); this.unknown5 = stream.readFloat32(); if (version > 24) { this.unknown6 = stream.readUint8Array(8); this.fresnelInvertedMaskX = stream.readFloat32(); this.fresnelInvertedMaskY = stream.readFloat32(); this.fresnelInvertedMaskZ = stream.readFloat32(); this.fresnelRotationYaw = stream.readFloat32(); this.fresnelRotationPitch = stream.readFloat32(); this.unknown7 = stream.readUint32(); } } } ================================================ FILE: src/parsers/m3/light.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import { Float32AnimationReference, Vector3AnimationReference } from './animationreference'; /** * A light. */ export default class Light { version = -1; type = 0; unknown0 = 0; bone = -1; flags = 0; unknown1 = 0; unknown2 = 0; lightColor = new Vector3AnimationReference(); lightIntensity = new Float32AnimationReference(); specularColor = new Vector3AnimationReference(); specularIntensity = new Float32AnimationReference(); attenuationFar = new Float32AnimationReference(); unknown3 = 0; attenuationNear = new Float32AnimationReference(); hotSpot = new Float32AnimationReference(); falloff = new Float32AnimationReference(); load(stream: BinaryStream, version: number, _index: IndexEntry[]): void { this.version = version; this.type = stream.readUint8(); this.unknown0 = stream.readUint8(); this.bone = stream.readInt16(); this.flags = stream.readUint32(); this.unknown1 = stream.readUint32(); this.unknown2 = stream.readInt32(); this.lightColor.load(stream); this.lightIntensity.load(stream); this.specularColor.load(stream); this.specularIntensity.load(stream); this.attenuationFar.load(stream); this.unknown3 = stream.readFloat32(); this.attenuationNear.load(stream); this.hotSpot.load(stream); this.falloff.load(stream); } } ================================================ FILE: src/parsers/m3/materialreference.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; /** * A material reference. */ export default class MaterialReference { version = -1; materialType = 0; materialIndex = -1; load(stream: BinaryStream, version: number, _index: IndexEntry[]): void { this.version = version; this.materialType = stream.readUint32(); this.materialIndex = stream.readUint32(); } } ================================================ FILE: src/parsers/m3/md34.ts ================================================ import reverse from '../../common/stringreverse'; import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * The M3 header. */ export default class Md34 { version = -1; tag = ''; offset = 0; entries = 0; model = new Reference(); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.tag = reverse(stream.readBinary(4)); this.offset = stream.readUint32(); this.entries = stream.readUint32(); this.model.load(stream, index); } } ================================================ FILE: src/parsers/m3/model.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Md34 from './md34'; import ModelHeader from './modelheader'; /** * A model. */ export default class Model { index: IndexEntry[] = []; model: ModelHeader | null = null; load(src: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(src); const header = new Md34(); header.load(stream, 11, this.index); if (header.tag !== 'MD34') { throw new Error('WrongMagicNumber'); } stream.seek(header.offset); // Read the index entries for (let i = 0, l = header.entries; i < l; i++) { this.index[i] = new IndexEntry(stream, this.index); } const modelEntries = this.index[header.model.id].entries; if (modelEntries) { this.model = modelEntries[0]; } } } ================================================ FILE: src/parsers/m3/modelheader.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; import BoundingSphere from './boundingsphere'; import BoundingShape from './boundingshape'; /** * The model information structure. */ export default class ModelHeader { version = -1; modelName = new Reference(); flags = 0; sequences = new Reference(); stc = new Reference(); stg = new Reference(); unknown0 = 0; unknown1 = 0; unknown2 = 0; unknown3 = 0; sts = new Reference(); bones = new Reference(); numberOfBonesToCheckForSkin = 0; vertexFlags = 0; vertices = new Reference(); divisions = new Reference(); boneLookup = new Reference(); boundings = new BoundingSphere(); unknown4To20 = new Uint32Array(16); attachmentPoints = new Reference(); attachmentPointAddons = new Reference(); ligts = new Reference(); shbxData = new Reference(); cameras = new Reference(); unknown21 = new Reference(); materialReferences = new Reference(); materials: Reference[] = []; particleEmitters = new Reference(); particleEmitterCopies = new Reference(); ribbonEmitters = new Reference(); projections = new Reference(); forces = new Reference(); warps = new Reference(); unknown22 = new Reference(); rigidBodies = new Reference(); unknown23 = new Reference(); physicsJoints = new Reference(); clothBehavior = new Reference(); unknown24 = new Reference(); ikjtData = new Reference(); unknown25 = new Reference(); unknown26 = new Reference(); partsOfTurrentBehaviors = new Reference(); turrentBehaviors = new Reference(); absoluteInverseBoneRestPositions = new Reference(); tightHitTest = new BoundingShape(); fuzzyHitTestObjects = new Reference(); attachmentVolumes = new Reference(); attachmentVolumesAddon0 = new Reference(); attachmentVolumesAddon1 = new Reference(); billboardBehaviors = new Reference(); tmdData = new Reference(); unknown27 = 0; unknown28 = new Reference(); constructor() { for (let i = 0; i < 11; i++) { this.materials[i] = new Reference(); } } load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.modelName.load(stream, index); this.flags = stream.readUint32(); this.sequences.load(stream, index); this.stc.load(stream, index); this.stg.load(stream, index); this.unknown0 = stream.readFloat32(); this.unknown1 = stream.readFloat32(); this.unknown2 = stream.readFloat32(); this.unknown3 = stream.readFloat32(); this.sts.load(stream, index); this.bones.load(stream, index); this.numberOfBonesToCheckForSkin = stream.readUint32(); this.vertexFlags = stream.readUint32(); this.vertices.load(stream, index); this.divisions.load(stream, index); this.boneLookup.load(stream, index); this.boundings.load(stream); stream.readUint32Array(this.unknown4To20); this.attachmentPoints.load(stream, index); this.attachmentPointAddons.load(stream, index); this.ligts.load(stream, index); this.shbxData.load(stream, index); this.cameras.load(stream, index); this.unknown21.load(stream, index); this.materialReferences.load(stream, index); for (let i = 0; i < 7; i++) { this.materials[i].load(stream, index); // Standard, Displacement, Composite, Terrain, Volume, ?, Creep } if (version > 24) { this.materials[7].load(stream, index); // Volume noise } if (version > 25) { this.materials[8].load(stream, index); // Splat terrain bake } if (version > 27) { this.materials[9].load(stream, index); // ? } if (version > 28) { this.materials[10].load(stream, index); // Lens flare } this.particleEmitters.load(stream, index); this.particleEmitterCopies.load(stream, index); this.ribbonEmitters.load(stream, index); this.projections.load(stream, index); this.forces.load(stream, index); this.warps.load(stream, index); this.unknown22.load(stream, index); // ? this.rigidBodies.load(stream, index); this.unknown23.load(stream, index); // ? this.physicsJoints.load(stream, index); if (version > 27) { this.clothBehavior.load(stream, index); } this.unknown24.load(stream, index); // ? this.ikjtData.load(stream, index); this.unknown25.load(stream, index); // ? if (version > 24) { this.unknown26.load(stream, index); // ? } this.partsOfTurrentBehaviors.load(stream, index); this.turrentBehaviors.load(stream, index); this.absoluteInverseBoneRestPositions.load(stream, index); this.tightHitTest.load(stream); this.fuzzyHitTestObjects.load(stream, index); this.attachmentVolumes.load(stream, index); this.attachmentVolumesAddon0.load(stream, index); this.attachmentVolumesAddon1.load(stream, index); this.billboardBehaviors.load(stream, index); this.tmdData.load(stream, index); this.unknown27 = stream.readUint32(); // ? this.unknown28.load(stream, index); // ? } } ================================================ FILE: src/parsers/m3/reference.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry, { EntryType, SingleEntryType } from './indexentry'; /** * A reference. */ export default class Reference { index: IndexEntry[] | null = null; entries = 0; id = 0; flags = 0; load(stream: BinaryStream, index: IndexEntry[]): void { this.index = index; this.entries = stream.readUint32(); this.id = stream.readUint32(); this.flags = stream.readUint32(); } /** * Get the entries this index entry references. */ get(): EntryType | undefined { if (this.index && this.id !== 0 && this.entries !== 0) { return this.index[this.id].entries; } return; } /** * Get the first entry this index entry references. */ first(): SingleEntryType | undefined { const entries = this.get(); if (entries) { return entries[0]; } return; } } ================================================ FILE: src/parsers/m3/region.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; /** * A region. */ export default class Region { version = -1; unknown0 = 0; unknown1 = 0; firstVertexIndex = -1; verticesCount = 0; firstTriangleIndex = -1; triangleIndicesCount = 0; bonesCount = 0; firstBoneLookupIndex = -1; boneLookupIndicesCount = 0; unknown2 = 0; boneWeightPairsCount = 0; unknown3 = 0; rootBoneIndex = -1; unknown4 = 0; unknown5 = new Uint8Array(8); load(stream: BinaryStream, version: number, _index: IndexEntry[]): void { this.version = version; this.unknown0 = stream.readUint32(); this.unknown1 = stream.readUint32(); this.firstVertexIndex = stream.readUint32(); this.verticesCount = stream.readUint32(); this.firstTriangleIndex = stream.readUint32(); this.triangleIndicesCount = stream.readUint32(); this.bonesCount = stream.readUint16(); this.firstBoneLookupIndex = stream.readUint16(); this.boneLookupIndicesCount = stream.readUint16(); this.unknown2 = stream.readUint16(); this.boneWeightPairsCount = stream.readUint8(); this.unknown3 = stream.readUint8(); this.rootBoneIndex = stream.readUint16(); if (version > 3) { this.unknown4 = stream.readUint32(); } if (version > 4) { stream.readUint8Array(this.unknown5); } } } ================================================ FILE: src/parsers/m3/sd.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * Sequence data. */ export default class Sd { version = -1; keys = new Reference(); flags = 0; biggestKey = -1; values = new Reference(); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.keys.load(stream, index); this.flags = stream.readUint32(); this.biggestKey = stream.readUint32(); this.values.load(stream, index); } } ================================================ FILE: src/parsers/m3/sequence.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; import BoundingSphere from './boundingsphere'; /** * A sequence. */ export default class Sequence { version = -1; name = new Reference(); interval = new Uint32Array(2); movementSpeed = 0; flags = 0; frequency = 0; boundingSphere = new BoundingSphere(); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; stream.skip(8); // ? this.name.load(stream, index); stream.readUint32Array(this.interval); this.movementSpeed = stream.readFloat32(); this.flags = stream.readUint32(); this.frequency = stream.readUint32(); stream.skip(12); // ? if (version < 2) { stream.skip(4); // ? } this.boundingSphere.load(stream); stream.skip(12); // ? } } ================================================ FILE: src/parsers/m3/standardmaterial.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; import { Float32AnimationReference, Uint32AnimationReference } from './animationreference'; /** * A standard material. */ export default class StandardMaterial { version = -1; name = new Reference(); additionalFlags = 0; flags = 0; blendMode = 0; priority = 0; usedRTTChannels = 0; specularity = 0; depthBlendFalloff = 0; cutoutThreshold = 0; unknown1 = 0; unknown2 = 0; unknown3 = 0; specMult = 0; emisMult = 0; diffuseLayer = new Reference(); decalLayer = new Reference(); specularLayer = new Reference(); glossLayer = new Reference(); emissiveLayer = new Reference(); emissive2Layer = new Reference(); evioLayer = new Reference(); evioMaskLayer = new Reference(); alphaMaskLayer = new Reference(); alphaMask2Layer = new Reference(); normalLayer = new Reference(); heightLayer = new Reference(); lightMapLayer = new Reference(); ambientOcclusionLayer = new Reference(); unknown4 = new Reference(); unknown5 = new Reference(); unknown6 = new Reference(); unknown7 = new Reference(); unknown8 = 0; layerBlendType = 0; emisBlendType = 0; emisMode = 0; specType = 0; unknown9 = new Float32AnimationReference(); unknown10 = new Uint32AnimationReference(); unknown11 = new Uint8Array(12); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.name.load(stream, index); this.additionalFlags = stream.readUint32(); this.flags = stream.readUint32(); this.blendMode = stream.readUint32(); this.priority = stream.readInt32(); this.usedRTTChannels = stream.readUint32(); this.specularity = stream.readFloat32(); this.depthBlendFalloff = stream.readFloat32(); this.cutoutThreshold = stream.readUint8(); this.unknown1 = stream.readUint8(); // ? this.unknown2 = stream.readUint8(); // ? this.unknown3 = stream.readUint8(); // ? this.specMult = stream.readFloat32(); this.emisMult = stream.readFloat32(); this.diffuseLayer.load(stream, index); this.decalLayer.load(stream, index); this.specularLayer.load(stream, index); if (version > 15) { this.glossLayer.load(stream, index); } this.emissiveLayer.load(stream, index); this.emissive2Layer.load(stream, index); this.evioLayer.load(stream, index); this.evioMaskLayer.load(stream, index); this.alphaMaskLayer.load(stream, index); this.alphaMask2Layer.load(stream, index); this.normalLayer.load(stream, index); this.heightLayer.load(stream, index); this.lightMapLayer.load(stream, index); this.ambientOcclusionLayer.load(stream, index); if (version > 18) { this.unknown4.load(stream, index); // Unknown layer this.unknown5.load(stream, index); // Unknown layer this.unknown6.load(stream, index); // Unknown layer this.unknown7.load(stream, index); // Unknown layer } this.unknown8 = stream.readUint32(); // ? this.layerBlendType = stream.readUint32(); this.emisBlendType = stream.readUint32(); this.emisMode = stream.readUint32(); this.specType = stream.readUint32(); this.unknown9.load(stream); // ? this.unknown10.load(stream); // ? if (version > 18) { this.unknown11 = stream.readUint8Array(this.unknown11); // ? } } } ================================================ FILE: src/parsers/m3/stc.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * An animation timeline. */ export default class Stc { version = -1; name = new Reference(); runsConcurrent = 0; priority = 0; stsIndex = -1; stsIndexCopy = -1; animIds = new Reference(); animRefs = new Reference(); sd: Reference[] = []; constructor() { for (let i = 0; i < 13; i++) { this.sd[i] = new Reference(); } } load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.name.load(stream, index); this.runsConcurrent = stream.readUint16(); this.priority = stream.readUint16(); this.stsIndex = stream.readUint16(); this.stsIndexCopy = stream.readUint16(); // ? this.animIds.load(stream, index); this.animRefs.load(stream, index); stream.skip(4); // ? for (let i = 0; i < 13; i++) { this.sd[i].load(stream, index); } } } ================================================ FILE: src/parsers/m3/stg.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * An animation getter. */ export default class Stg { version = -1; name = new Reference(); stcIndices = new Reference(); load(stream: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.name.load(stream, index); this.stcIndices.load(stream, index); } } ================================================ FILE: src/parsers/m3/sts.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; import Reference from './reference'; /** * An animation validator. */ export default class Sts { version = -1; animIds = new Reference(); load(reader: BinaryStream, version: number, index: IndexEntry[]): void { this.version = version; this.animIds.load(reader, index); reader.skip(16); // ? } } ================================================ FILE: src/parsers/m3/unsupportedentry.ts ================================================ import BinaryStream from '../../common/binarystream'; import IndexEntry from './indexentry'; /** * An unsupported entry. * * This is used for entries that have known structures (or at least sizes), but this parser isn't going to actually parse. * The entry will contain its own reader and version, in case the client code wants to do anything with it. */ export default class UnsupportedEntry { stream: BinaryStream; version: number; index: IndexEntry[]; constructor(stream: BinaryStream, version: number, index: IndexEntry[]) { this.stream = stream; this.version = version; this.index = index; } } ================================================ FILE: src/parsers/mdlx/animatedobject.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import { Animation } from './animations'; import animationMap from './animationmap'; /** * The parent class for all objects that have animated data in them. */ export default class AnimatedObject { animations: Animation[] = []; readAnimations(stream: BinaryStream, size: number): void { const end = stream.index + size; while (stream.index < end) { const name = stream.readBinary(4); const animation = new animationMap[name][1](); animation.readMdx(stream, name); this.animations.push(animation); } } writeAnimations(stream: BinaryStream): void { for (const animation of this.animations) { animation.writeMdx(stream); } } /** * A wrapper around readBlock() which merges static tokens. * E.g.: static Color * This makes the condition blocks in the parent objects linear and simple. */ * readAnimatedBlock(stream: TokenStream): Generator { for (const token of stream.readBlock()) { if (token === 'static') { yield `static ${stream.read()}`; } else { yield token; } } } readAnimation(stream: TokenStream, name: string): void { const animation = new animationMap[name][1](); animation.readMdl(stream, name); this.animations.push(animation); } writeAnimation(stream: TokenStream, name: string): boolean { for (const animation of this.animations) { if (animation.name === name) { animation.writeMdl(stream, animationMap[name][0]); return true; } } return false; } /** * AnimatedObject itself doesn't care about versions, however objects that inherit it do. */ getByteLength(_version = 0): number { let size = 0; for (const animation of this.animations) { size += animation.getByteLength(); } return size; } } ================================================ FILE: src/parsers/mdlx/animationmap.ts ================================================ import { UintAnimation, FloatAnimation, Vector3Animation, Vector4Animation } from './animations'; // A map from MDX animation tags to their equivalent MDL tokens, and the implementation objects. export default { // Layer KMTF: ['TextureID', UintAnimation], KMTA: ['Alpha', FloatAnimation], KMTE: ['EmissiveGain', FloatAnimation], KFC3: ['FresnelColor', Vector3Animation], KFCA: ['FresnelOpacity', FloatAnimation], KFTC: ['FresnelTeamColor', UintAnimation], // TextureAnimation KTAT: ['Translation', Vector3Animation], KTAR: ['Rotation', Vector4Animation], KTAS: ['Scaling', Vector3Animation], // GeosetAnimation KGAO: ['Alpha', FloatAnimation], KGAC: ['Color', Vector3Animation], // GenericObject KGTR: ['Translation', Vector3Animation], KGRT: ['Rotation', Vector4Animation], KGSC: ['Scaling', Vector3Animation], // Light KLAS: ['AttenuationStart', FloatAnimation], KLAE: ['AttenuationEnd', FloatAnimation], KLAC: ['Color', Vector3Animation], KLAI: ['Intensity', FloatAnimation], KLBI: ['AmbIntensity', FloatAnimation], KLBC: ['AmbColor', Vector3Animation], KLAV: ['Visibility', FloatAnimation], // Attachment KATV: ['Visibility', FloatAnimation], // ParticleEmitter KPEE: ['EmissionRate', FloatAnimation], KPEG: ['Gravity', FloatAnimation], KPLN: ['Longitude', FloatAnimation], KPLT: ['Latitude', FloatAnimation], KPEL: ['LifeSpan', FloatAnimation], KPES: ['InitVelocity', FloatAnimation], KPEV: ['Visibility', FloatAnimation], // ParticleEmitter2 KP2S: ['Speed', FloatAnimation], KP2R: ['Variation', FloatAnimation], KP2L: ['Latitude', FloatAnimation], KP2G: ['Gravity', FloatAnimation], KP2E: ['EmissionRate', FloatAnimation], KP2N: ['Width', FloatAnimation], KP2W: ['Length', FloatAnimation], KP2V: ['Visibility', FloatAnimation], // ParticleEmitterCorn KPPA: ['Alpha', FloatAnimation], KPPC: ['Color', Vector3Animation], KPPE: ['EmissionRate', FloatAnimation], KPPL: ['LifeSpan', FloatAnimation], KPPS: ['Speed', FloatAnimation], KPPV: ['Visibility', FloatAnimation], // RibbonEmitter KRHA: ['HeightAbove', FloatAnimation], KRHB: ['HeightBelow', FloatAnimation], KRAL: ['Alpha', FloatAnimation], KRCO: ['Color', Vector3Animation], KRTX: ['TextureSlot', UintAnimation], KRVS: ['Visibility', FloatAnimation], // Camera KCTR: ['Translation', Vector3Animation], KTTR: ['Translation', Vector3Animation], KCRL: ['Rotation', FloatAnimation], }; ================================================ FILE: src/parsers/mdlx/animations.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; export const enum InterpolationType { DontInterp = 0, Linear = 1, Hermite = 2, Bezier = 3, } /** * An animation. */ export abstract class Animation { name = ''; interpolationType = InterpolationType.DontInterp; globalSequenceId = -1; frames: number[] = []; values: (Uint32Array | Float32Array)[] = []; inTans: (Uint32Array | Float32Array)[] = []; outTans: (Uint32Array | Float32Array)[] = []; abstract readMdxValue(stream: BinaryStream): Uint32Array | Float32Array; abstract writeMdxValue(stream: BinaryStream, value: Uint32Array | Float32Array): void; abstract readMdlValue(stream: TokenStream): Uint32Array | Float32Array; abstract writeMdlValue(stream: TokenStream, name: string, value: Uint32Array | Float32Array): void; readMdx(stream: BinaryStream, name: string): void { const frames = this.frames; const values = this.values; const inTans = this.inTans; const outTans = this.outTans; const tracksCount = stream.readUint32(); const interpolationType = stream.readUint32(); this.name = name; this.interpolationType = interpolationType; this.globalSequenceId = stream.readInt32(); for (let i = 0; i < tracksCount; i++) { frames.push(stream.readInt32()); values.push(this.readMdxValue(stream)); if (interpolationType > 1) { inTans.push(this.readMdxValue(stream)); outTans.push(this.readMdxValue(stream)); } } } writeMdx(stream: BinaryStream): void { const interpolationType = this.interpolationType; const frames = this.frames; const values = this.values; const inTans = this.inTans; const outTans = this.outTans; const tracksCount = frames.length; stream.writeBinary(this.name); stream.writeUint32(tracksCount); stream.writeUint32(interpolationType); stream.writeInt32(this.globalSequenceId); for (let i = 0; i < tracksCount; i++) { stream.writeInt32(frames[i]); this.writeMdxValue(stream, values[i]); if (interpolationType > InterpolationType.Linear) { this.writeMdxValue(stream, inTans[i]); this.writeMdxValue(stream, outTans[i]); } } } readMdl(stream: TokenStream, name: string): void { const frames = this.frames; const values = this.values; const inTans = this.inTans; const outTans = this.outTans; this.name = name; const tracksCount = stream.readInt(); stream.read(); // { let interpolationType = 0; const token = stream.read(); if (token === 'DontInterp') { interpolationType = InterpolationType.DontInterp; } else if (token === 'Linear') { interpolationType = InterpolationType.Linear; } else if (token === 'Hermite') { interpolationType = InterpolationType.Hermite; } else if (token === 'Bezier') { interpolationType = InterpolationType.Bezier; } this.interpolationType = interpolationType; // GlobalSeqId only exists if it's not -1. if (stream.peek() === 'GlobalSeqId') { stream.read(); this.globalSequenceId = stream.readInt(); } for (let i = 0; i < tracksCount; i++) { frames[i] = stream.readInt(); values[i] = this.readMdlValue(stream); if (interpolationType > InterpolationType.Linear) { stream.read(); // InTan inTans[i] = this.readMdlValue(stream); stream.read(); // OutTan outTans[i] = this.readMdlValue(stream); } } stream.read(); // } } writeMdl(stream: TokenStream, name: string): void { const interpolationType = this.interpolationType; const frames = this.frames; const values = this.values; const inTans = this.inTans; const outTans = this.outTans; const tracksCount = frames.length; stream.startBlock(name, this.frames.length); let token = ''; if (this.interpolationType === InterpolationType.DontInterp) { token = 'DontInterp'; } else if (this.interpolationType === InterpolationType.Linear) { token = 'Linear'; } else if (this.interpolationType === InterpolationType.Hermite) { token = 'Hermite'; } else if (this.interpolationType === InterpolationType.Bezier) { token = 'Bezier'; } stream.writeFlag(token); if (this.globalSequenceId !== -1) { stream.writeNumberAttrib('GlobalSeqId', this.globalSequenceId); } for (let i = 0; i < tracksCount; i++) { this.writeMdlValue(stream, `${frames[i]}:`, values[i]); if (interpolationType > InterpolationType.Linear) { stream.indent(); this.writeMdlValue(stream, 'InTan', inTans[i]); this.writeMdlValue(stream, 'OutTan', outTans[i]); stream.unindent(); } } stream.endBlock(); } getByteLength(): number { const tracksCount = this.frames.length; let size = 16; if (tracksCount) { const bytesPerValue = this.values[0].byteLength; let valuesPerTrack = 1; if (this.interpolationType > InterpolationType.Linear) { valuesPerTrack = 3; } size += (4 + valuesPerTrack * bytesPerValue) * tracksCount; } return size; } } /** * A uint animation. */ export class UintAnimation extends Animation { readMdxValue(stream: BinaryStream): Uint32Array { return stream.readUint32Array(1); } writeMdxValue(stream: BinaryStream, value: Uint32Array): void { stream.writeUint32(value[0]); } readMdlValue(stream: TokenStream): Uint32Array { return new Uint32Array([stream.readInt()]); } writeMdlValue(stream: TokenStream, name: string, value: Uint32Array): void { stream.writeNumberAttrib(name, value[0]); } } /** * A float animation */ export class FloatAnimation extends Animation { readMdxValue(stream: BinaryStream): Float32Array { return stream.readFloat32Array(1); } writeMdxValue(stream: BinaryStream, value: Float32Array): void { stream.writeFloat32(value[0]); } readMdlValue(stream: TokenStream): Float32Array { return new Float32Array([stream.readFloat()]); } writeMdlValue(stream: TokenStream, name: string, value: Float32Array): void { stream.writeNumberAttrib(name, value[0]); } } /** * A vector 3 animation. */ export class Vector3Animation extends Animation { readMdxValue(stream: BinaryStream): Float32Array { return stream.readFloat32Array(3); } writeMdxValue(stream: BinaryStream, value: Float32Array): void { stream.writeFloat32Array(value); } readMdlValue(stream: TokenStream): Float32Array { return stream.readVector(new Float32Array(3)); } writeMdlValue(stream: TokenStream, name: string, value: Float32Array): void { stream.writeVectorAttrib(name, value); } } /** * A vector 4 animation. */ export class Vector4Animation extends Animation { readMdxValue(stream: BinaryStream): Float32Array { return stream.readFloat32Array(4); } writeMdxValue(stream: BinaryStream, value: Float32Array): void { stream.writeFloat32Array(value); } readMdlValue(stream: TokenStream): Float32Array { return stream.readVector(new Float32Array(4)); } writeMdlValue(stream: TokenStream, name: string, value: Float32Array): void { stream.writeVectorAttrib(name, value); } } ================================================ FILE: src/parsers/mdlx/attachment.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; /** * An attachment. */ export default class Attachment extends GenericObject { path = ''; attachmentId = 0; constructor() { super(0x800); } override readMdx(stream: BinaryStream): void { const start = stream.index; const size = stream.readUint32(); super.readMdx(stream); this.path = stream.read(260); this.attachmentId = stream.readInt32(); this.readAnimations(stream, size - (stream.index - start)); } override writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); super.writeMdx(stream); stream.skip(260 - stream.write(this.path)); stream.writeInt32(this.attachmentId); this.writeNonGenericAnimationChunks(stream); } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'AttachmentID') { this.attachmentId = stream.readInt(); } else if (token === 'Path') { this.path = stream.read(); } else if (token === 'Visibility') { this.readAnimation(stream, 'KATV'); } else { throw new Error(`Unknown token in Attachment ${this.name}: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('Attachment', this.name); this.writeGenericHeader(stream); stream.writeNumberAttrib('AttachmentID', this.attachmentId); // Is this needed? MDX supplies it, but MdlxConv does not use it. if (this.path.length) { stream.writeStringAttrib('Path', this.path); } this.writeAnimation(stream, 'KATV'); this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 268 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/bone.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; /** * A bone. */ export default class Bone extends GenericObject { geosetId = -1; geosetAnimationId = -1; constructor() { super(0x100); } override readMdx(stream: BinaryStream): void { super.readMdx(stream); this.geosetId = stream.readInt32(); this.geosetAnimationId = stream.readInt32(); } override writeMdx(stream: BinaryStream): void { super.writeMdx(stream); stream.writeInt32(this.geosetId); stream.writeInt32(this.geosetAnimationId); } readMdl(stream: TokenStream): void { for (let token of super.readGenericBlock(stream)) { if (token === 'GeosetId') { token = stream.read(); if (token === 'Multiple') { this.geosetId = -1; } else { this.geosetId = parseInt(token); } } else if (token === 'GeosetAnimId') { token = stream.read(); if (token === 'None') { this.geosetAnimationId = -1; } else { this.geosetAnimationId = parseInt(token); } } else { throw new Error(`Unknown token in Bone ${this.name}: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('Bone', this.name); this.writeGenericHeader(stream); if (this.geosetId === -1) { stream.writeFlagAttrib('GeosetId', 'Multiple'); } else { stream.writeNumberAttrib('GeosetId', this.geosetId); } if (this.geosetAnimationId === -1) { stream.writeFlagAttrib('GeosetAnimId', 'None'); } else { stream.writeNumberAttrib('GeosetAnimId', this.geosetAnimationId); } this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 8 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/camera.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import AnimatedObject from './animatedobject'; /** * A camera. */ export default class Camera extends AnimatedObject { name = ''; position = new Float32Array(3); fieldOfView = 0; farClippingPlane = 0; nearClippingPlane = 0; targetPosition = new Float32Array(3); readMdx(stream: BinaryStream): void { const size = stream.readUint32(); this.name = stream.read(80); stream.readFloat32Array(this.position); this.fieldOfView = stream.readFloat32(); this.farClippingPlane = stream.readFloat32(); this.nearClippingPlane = stream.readFloat32(); stream.readFloat32Array(this.targetPosition); this.readAnimations(stream, size - 120); } writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); stream.skip(80 - stream.write(this.name)); stream.writeFloat32Array(this.position); stream.writeFloat32(this.fieldOfView); stream.writeFloat32(this.farClippingPlane); stream.writeFloat32(this.nearClippingPlane); stream.writeFloat32Array(this.targetPosition); this.writeAnimations(stream); } readMdl(stream: TokenStream): void { this.name = stream.read(); for (let token of stream.readBlock()) { if (token === 'Position') { stream.readVector(this.position); } else if (token === 'Translation') { this.readAnimation(stream, 'KCTR'); } else if (token === 'Rotation') { this.readAnimation(stream, 'KCRL'); } else if (token === 'FieldOfView') { this.fieldOfView = stream.readFloat(); } else if (token === 'FarClip') { this.farClippingPlane = stream.readFloat(); } else if (token === 'NearClip') { this.nearClippingPlane = stream.readFloat(); } else if (token === 'Target') { for (token of stream.readBlock()) { if (token === 'Position') { stream.readVector(this.targetPosition); } else if (token === 'Translation') { this.readAnimation(stream, 'KTTR'); } else { throw new Error(`Unknown token in Camera ${this.name}'s Target: "${token}"`); } } } else { throw new Error(`Unknown token in Camera ${this.name}: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('Camera', this.name); stream.writeVectorAttrib('Position', this.position); this.writeAnimation(stream, 'KCTR'); this.writeAnimation(stream, 'KCRL'); stream.writeNumberAttrib('FieldOfView', this.fieldOfView); stream.writeNumberAttrib('FarClip', this.farClippingPlane); stream.writeNumberAttrib('NearClip', this.nearClippingPlane); stream.startBlock('Target'); stream.writeVectorAttrib('Position', this.targetPosition); this.writeAnimation(stream, 'KTTR'); stream.endBlock(); stream.endBlock(); } override getByteLength(): number { return 120 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/collisionshape.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; export const enum Shape { Box = 0, Plane = 1, Sphere = 2, Cylinder = 3, } /** * A collision shape. */ export default class CollisionShape extends GenericObject { type = Shape.Box; vertices: Float32Array[] = [new Float32Array(3), new Float32Array(3)]; boundsRadius = 0; constructor() { super(0x2000); } override readMdx(stream: BinaryStream): void { super.readMdx(stream); this.type = stream.readUint32(); stream.readFloat32Array(this.vertices[0]); if (this.type !== Shape.Sphere) { stream.readFloat32Array(this.vertices[1]); } if (this.type === Shape.Sphere || this.type === Shape.Cylinder) { this.boundsRadius = stream.readFloat32(); } } override writeMdx(stream: BinaryStream): void { super.writeMdx(stream); stream.writeUint32(this.type); stream.writeFloat32Array(this.vertices[0]); if (this.type !== Shape.Sphere) { stream.writeFloat32Array(this.vertices[1]); } if (this.type === Shape.Sphere || this.type === Shape.Cylinder) { stream.writeFloat32(this.boundsRadius); } } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'Box') { this.type = Shape.Box; } else if (token === 'Plane') { this.type = Shape.Plane; } else if (token === 'Sphere') { this.type = Shape.Sphere; } else if (token === 'Cylinder') { this.type = Shape.Cylinder; } else if (token === 'Vertices') { const count = stream.readInt(); stream.read(); // { stream.readVector(this.vertices[0]); if (count === 2) { stream.readVector(this.vertices[1]); } stream.read(); // } } else if (token === 'BoundsRadius') { this.boundsRadius = stream.readFloat(); } else { throw new Error(`Unknown token in CollisionShape: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('CollisionShape', this.name); this.writeGenericHeader(stream); let type = ''; let vertices = 2; let boundsRadius = false; if (this.type === Shape.Box) { type = 'Box'; } else if (this.type === Shape.Plane) { type = 'Plane'; } else if (this.type === Shape.Sphere) { type = 'Sphere'; vertices = 1; boundsRadius = true; } else if (this.type === Shape.Cylinder) { type = 'Cylinder'; boundsRadius = true; } stream.writeFlag(type); stream.startBlock('Vertices', vertices); stream.writeVector(this.vertices[0]); if (vertices === 2) { stream.writeVector(this.vertices[1]); } stream.endBlock(); if (boundsRadius) { stream.writeNumberAttrib('BoundsRadius', this.boundsRadius); } this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { let size = 16 + super.getByteLength(); if (this.type !== Shape.Sphere) { size += 12; } if (this.type === Shape.Sphere || this.type === Shape.Cylinder) { size += 4; } return size; } } ================================================ FILE: src/parsers/mdlx/eventobject.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; /** * An event object. */ export default class EventObject extends GenericObject { globalSequenceId = -1; tracks = new Uint32Array(0); constructor() { super(0x400); } override readMdx(stream: BinaryStream): void { super.readMdx(stream); stream.skip(4); // KEVT const count = stream.readUint32(); this.globalSequenceId = stream.readInt32(); this.tracks = stream.readUint32Array(count); } override writeMdx(stream: BinaryStream): void { super.writeMdx(stream); stream.writeBinary('KEVT'); stream.writeUint32(this.tracks.length); stream.writeInt32(this.globalSequenceId); stream.writeUint32Array(this.tracks); } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'EventTrack') { const count = stream.readInt(); this.tracks = new Uint32Array(count); stream.read(); // { if (stream.peek() === 'GlobalSeqId') { stream.read(); this.globalSequenceId = stream.readInt(); } for (let i = 0; i < count; i++) { this.tracks[i] = stream.readInt(); } stream.read(); // } } else { throw new Error(`Unknown token in EventObject: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('EventObject', this.name); this.writeGenericHeader(stream); stream.startBlock('EventTrack', this.tracks.length); if (this.globalSequenceId !== -1) { stream.writeNumberAttrib('GlobalSeqId', this.globalSequenceId); } for (const track of this.tracks) { stream.writeFlag(`${track}`); } stream.endBlock(); this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 12 + this.tracks.byteLength + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/extent.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; /** * An extent. */ export default class Extent { boundsRadius = 0; min = new Float32Array(3); max = new Float32Array(3); readMdx(stream: BinaryStream): void { this.boundsRadius = stream.readFloat32(); stream.readFloat32Array(this.min); stream.readFloat32Array(this.max); } writeMdx(stream: BinaryStream): void { stream.writeFloat32(this.boundsRadius); stream.writeFloat32Array(this.min); stream.writeFloat32Array(this.max); } writeMdl(stream: TokenStream): void { if (this.min[0] !== 0 || this.min[1] !== 0 || this.min[2] !== 0) { stream.writeVectorAttrib('MinimumExtent', this.min); } if (this.max[0] !== 0 || this.max[1] !== 0 || this.max[2] !== 0) { stream.writeVectorAttrib('MaximumExtent', this.max); } if (this.boundsRadius !== 0) { stream.writeNumberAttrib('BoundsRadius', this.boundsRadius); } } } ================================================ FILE: src/parsers/mdlx/faceeffect.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; /** * A face effect. */ export default class FaceEffect { type = ''; path = ''; readMdx(stream: BinaryStream): void { this.type = stream.read(80); this.path = stream.read(260); } writeMdx(stream: BinaryStream): void { stream.skip(80 - stream.write(this.type)); stream.skip(260 - stream.write(this.path)); } readMdl(stream: TokenStream): void { this.type = stream.read(); for (const token of stream.readBlock()) { if (token === 'Path') { this.path = stream.read(); } else { throw new Error(`Unknown token in FaceEffect: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('FaceFX', this.type); stream.writeStringAttrib('Path', this.path); stream.endBlock(); } } ================================================ FILE: src/parsers/mdlx/genericobject.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import AnimatedObject from './animatedobject'; import { Animation } from './animations'; export const enum Flags { None = 0x0, DontInheritTranslation = 0x1, DontInheritScaling = 0x2, DontInheritRotation = 0x4, Billboarded = 0x8, BillboardedLockX = 0x10, BillboardedLockY = 0x20, BillboardedLockZ = 0x40, CameraAnchored = 0x80, } /** * A generic object. * * The parent class for all objects that exist in the world, and may contain spatial animations. * This includes bones, particle emitters, and many other things. */ export default abstract class GenericObject extends AnimatedObject { name = ''; objectId = -1; parentId = -1; flags: Flags; constructor(flags = Flags.None) { super(); this.flags = flags; } readMdx(stream: BinaryStream): void { const size = stream.readUint32(); this.name = stream.read(80); this.objectId = stream.readInt32(); this.parentId = stream.readInt32(); this.flags = stream.readUint32(); this.readAnimations(stream, size - 96); } writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getGenericByteLength()); stream.skip(80 - stream.write(this.name)); stream.writeInt32(this.objectId); stream.writeInt32(this.parentId); stream.writeUint32(this.flags); for (const animation of this.eachAnimation(true)) { animation.writeMdx(stream); } } writeNonGenericAnimationChunks(stream: BinaryStream): void { for (const animation of this.eachAnimation(false)) { animation.writeMdx(stream); } } * readGenericBlock(stream: TokenStream): Generator { this.name = stream.read(); for (let token of this.readAnimatedBlock(stream)) { if (token === 'ObjectId') { this.objectId = stream.readInt(); } else if (token === 'Parent') { this.parentId = stream.readInt(); } else if (token === 'BillboardedLockZ') { this.flags |= Flags.BillboardedLockZ; } else if (token === 'BillboardedLockY') { this.flags |= Flags.BillboardedLockY; } else if (token === 'BillboardedLockX') { this.flags |= Flags.BillboardedLockX; } else if (token === 'Billboarded') { this.flags |= Flags.Billboarded; } else if (token === 'CameraAnchored') { this.flags |= Flags.CameraAnchored; } else if (token === 'DontInherit') { for (token of stream.readBlock()) { if (token === 'Rotation') { this.flags |= Flags.DontInheritRotation; } else if (token === 'Translation') { this.flags |= Flags.DontInheritTranslation; } else if (token === 'Scaling') { this.flags |= Flags.DontInheritScaling; } } } else if (token === 'Translation') { this.readAnimation(stream, 'KGTR'); } else if (token === 'Rotation') { this.readAnimation(stream, 'KGRT'); } else if (token === 'Scaling') { this.readAnimation(stream, 'KGSC'); } else { yield token; } } } writeGenericHeader(stream: TokenStream): void { stream.writeNumberAttrib('ObjectId', this.objectId); if (this.parentId !== -1) { stream.writeNumberAttrib('Parent', this.parentId); } if (this.flags & Flags.BillboardedLockZ) { stream.writeFlag('BillboardedLockZ'); } if (this.flags & Flags.BillboardedLockY) { stream.writeFlag('BillboardedLockY'); } if (this.flags & Flags.BillboardedLockX) { stream.writeFlag('BillboardedLockX'); } if (this.flags & Flags.Billboarded) { stream.writeFlag('Billboarded'); } if (this.flags & Flags.CameraAnchored) { stream.writeFlag('CameraAnchored'); } if (this.flags & Flags.DontInheritRotation) { stream.writeFlag(`DontInherit { Rotation }`); } if (this.flags & Flags.DontInheritTranslation) { stream.writeFlag(`DontInherit { Translation }`); } if (this.flags & Flags.DontInheritScaling) { stream.writeFlag(`DontInherit { Scaling }`); } } writeGenericAnimations(stream: TokenStream): void { this.writeAnimation(stream, 'KGTR'); this.writeAnimation(stream, 'KGRT'); this.writeAnimation(stream, 'KGSC'); } /** * Allows to easily iterate either the GenericObject animations or the parent object animations. */ * eachAnimation(wantGeneric: boolean): Generator { for (const animation of this.animations) { const name = animation.name; const isGeneric = (name === 'KGTR' || name === 'KGRT' || name === 'KGSC'); if ((wantGeneric && isGeneric) || (!wantGeneric && !isGeneric)) { yield animation; } } } /** * Gets the byte length of the GenericObject part of whatever this object this. * * This is needed because only the KGTR, KGRT, and KGSC animations actually belong to it. */ getGenericByteLength(): number { let size = 96; for (const animation of this.eachAnimation(true)) { size += animation.getByteLength(); } return size; } override getByteLength(): number { return 96 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/geoset.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import Extent from './extent'; /** * A geoset. */ export default class Geoset { vertices = new Float32Array(0); normals = new Float32Array(0); faceTypeGroups = new Uint32Array(0); faceGroups = new Uint32Array(0); faces = new Uint16Array(0); vertexGroups = new Uint8Array(0); matrixGroups = new Uint32Array(0); matrixIndices = new Uint32Array(0); materialId = 0; selectionGroup = 0; selectionFlags = 0; /** * @since 900 */ lod = -1; /** * @since 900 */ lodName = ''; extent = new Extent(); sequenceExtents: Extent[] = []; /** * @since 900 */ tangents = new Float32Array(0); /** * An array of bone indices and weights. * Every 8 consecutive elements describe the following: * [B0, B1, B2, B3, W0, W1, W2, W3] * Where: * Bn is a bone index. * Wn is a weight, which can be normalized with Wn/255. * * @since 900 */ skin = new Uint8Array(0); uvSets: Float32Array[] = []; readMdx(stream: BinaryStream, version: number): void { stream.readUint32(); // Don't care about the size. stream.skip(4); // VRTX this.vertices = stream.readFloat32Array(stream.readUint32() * 3); stream.skip(4); // NRMS this.normals = stream.readFloat32Array(stream.readUint32() * 3); stream.skip(4); // PTYP this.faceTypeGroups = stream.readUint32Array(stream.readUint32()); stream.skip(4); // PCNT this.faceGroups = stream.readUint32Array(stream.readUint32()); stream.skip(4); // PVTX this.faces = stream.readUint16Array(stream.readUint32()); stream.skip(4); // GNDX this.vertexGroups = stream.readUint8Array(stream.readUint32()); stream.skip(4); // MTGC this.matrixGroups = stream.readUint32Array(stream.readUint32()); stream.skip(4); // MATS this.matrixIndices = stream.readUint32Array(stream.readUint32()); this.materialId = stream.readUint32(); this.selectionGroup = stream.readUint32(); this.selectionFlags = stream.readUint32(); if (version > 800) { this.lod = stream.readInt32(); this.lodName = stream.read(80); } this.extent.readMdx(stream); for (let i = 0, l = stream.readUint32(); i < l; i++) { const extent = new Extent(); extent.readMdx(stream); this.sequenceExtents.push(extent); } // Non-reforged models that come with reforged are saved with version >800, however they don't have TANG and SKIN. if (version > 800) { if (stream.readBinary(4) === 'TANG') { this.tangents = stream.readFloat32Array(stream.readUint32() * 4); } else { stream.skip(-4); } if (stream.readBinary(4) === 'SKIN') { this.skin = stream.readUint8Array(stream.readUint32()); } else { stream.skip(-4); } } stream.skip(4); // UVAS for (let i = 0, l = stream.readUint32(); i < l; i++) { stream.skip(4); // UVBS this.uvSets.push(stream.readFloat32Array(stream.readUint32() * 2)); } } writeMdx(stream: BinaryStream, version: number): void { stream.writeUint32(this.getByteLength(version)); stream.writeBinary('VRTX'); stream.writeUint32(this.vertices.length / 3); stream.writeFloat32Array(this.vertices); stream.writeBinary('NRMS'); stream.writeUint32(this.normals.length / 3); stream.writeFloat32Array(this.normals); stream.writeBinary('PTYP'); stream.writeUint32(this.faceTypeGroups.length); stream.writeUint32Array(this.faceTypeGroups); stream.writeBinary('PCNT'); stream.writeUint32(this.faceGroups.length); stream.writeUint32Array(this.faceGroups); stream.writeBinary('PVTX'); stream.writeUint32(this.faces.length); stream.writeUint16Array(this.faces); stream.writeBinary('GNDX'); stream.writeUint32(this.vertexGroups.length); stream.writeUint8Array(this.vertexGroups); stream.writeBinary('MTGC'); stream.writeUint32(this.matrixGroups.length); stream.writeUint32Array(this.matrixGroups); stream.writeBinary('MATS'); stream.writeUint32(this.matrixIndices.length); stream.writeUint32Array(this.matrixIndices); stream.writeUint32(this.materialId); stream.writeUint32(this.selectionGroup); stream.writeUint32(this.selectionFlags); if (version > 800) { stream.writeInt32(this.lod); stream.skip(80 - stream.write(this.lodName)); } this.extent.writeMdx(stream); stream.writeUint32(this.sequenceExtents.length); for (const sequenceExtent of this.sequenceExtents) { sequenceExtent.writeMdx(stream); } if (version > 800) { if (this.tangents.length) { stream.writeBinary('TANG'); stream.writeUint32(this.tangents.length / 4); stream.writeFloat32Array(this.tangents); } if (this.skin.length) { stream.writeBinary('SKIN'); stream.writeUint32(this.skin.length); stream.writeUint8Array(this.skin); } } stream.writeBinary('UVAS'); stream.writeUint32(this.uvSets.length); for (const uvSet of this.uvSets) { stream.writeBinary('UVBS'); stream.writeUint32(uvSet.length / 2); stream.writeFloat32Array(uvSet); } } readMdl(stream: TokenStream): void { for (let token of stream.readBlock()) { if (token === 'Vertices') { this.vertices = stream.readVectorsBlock(new Float32Array(stream.readInt() * 3), 3); } else if (token === 'Normals') { this.normals = stream.readVectorsBlock(new Float32Array(stream.readInt() * 3), 3); } else if (token === 'TVertices') { this.uvSets.push(stream.readVectorsBlock(new Float32Array(stream.readInt() * 2), 2)); } else if (token === 'VertexGroup') { // Vertex groups are stored in a block with no count, can't allocate the buffer yet. const vertexGroups = []; for (const vertexGroup of stream.readBlock()) { vertexGroups.push(parseInt(vertexGroup)); } this.vertexGroups = new Uint8Array(vertexGroups); } else if (token === 'Tangents') { this.tangents = stream.readVectorsBlock(new Float32Array(stream.readInt() * 4), 4); } else if (token === 'SkinWeights') { this.skin = stream.readVector(new Uint8Array(stream.readInt() * 8)); } else if (token === 'Faces') { // For now hardcoded for triangles, until I see a model with something different. this.faceTypeGroups = new Uint32Array([4]); // Number of vectors the indices are spread over. const vectors = stream.readInt(); // Total number of indices. const count = stream.readInt(); stream.read(); // { stream.read(); // Triangles this.faces = stream.readVectorsBlock(new Uint16Array(count), count / vectors); // Declare that all of the faces are in one group to conform with MDX. this.faceGroups = new Uint32Array([count]); stream.read(); // } } else if (token === 'Groups') { const indices = []; const groups = []; stream.readInt(); // matrices count stream.readInt(); // total indices for (const _ of stream.readBlock()) { let size = 0; for (const index of stream.readBlock()) { indices.push(parseInt(index)); size += 1; } groups.push(size); } this.matrixIndices = new Uint32Array(indices); this.matrixGroups = new Uint32Array(groups); } else if (token === 'MinimumExtent') { stream.readVector(this.extent.min); } else if (token === 'MaximumExtent') { stream.readVector(this.extent.max); } else if (token === 'BoundsRadius') { this.extent.boundsRadius = stream.readFloat(); } else if (token === 'Anim') { const extent = new Extent(); for (token of stream.readBlock()) { if (token === 'MinimumExtent') { stream.readVector(extent.min); } else if (token === 'MaximumExtent') { stream.readVector(extent.max); } else if (token === 'BoundsRadius') { extent.boundsRadius = stream.readFloat(); } } this.sequenceExtents.push(extent); } else if (token === 'MaterialID') { this.materialId = stream.readInt(); } else if (token === 'SelectionGroup') { this.selectionGroup = stream.readInt(); } else if (token === 'Unselectable') { this.selectionFlags = 4; } else if (token === 'LevelOfDetail') { this.lod = stream.readInt(); } else if (token === 'Name') { this.lodName = stream.read(); } else { throw new Error(`Unknown token in Geoset: "${token}"`); } } } writeMdl(stream: TokenStream, version: number): void { stream.startBlock('Geoset'); stream.writeVectorArrayBlock('Vertices', this.vertices, 3); stream.writeVectorArrayBlock('Normals', this.normals, 3); for (const uvSet of this.uvSets) { stream.writeVectorArrayBlock('TVertices', uvSet, 2); } if (version > 800 && this.tangents.length) { stream.writeVectorArrayBlock('Tangents', this.tangents, 4); } // Always write vertex groups if they exist. if (this.vertexGroups.length) { stream.startBlock('VertexGroup'); for (let i = 0, l = this.vertexGroups.length; i < l; i++) { stream.writeLine(`${this.vertexGroups[i]},`); } stream.endBlock(); } // If this is a Reforged HD geoset, write the skin. if (version > 800 && this.skin.length) { stream.startBlock('SkinWeights', this.skin.length / 8); for (let i = 0, l = this.skin.length; i < l; i += 8) { stream.writeLine(`${this.skin.subarray(i, i + 8).join(', ')},`); } stream.endBlock(); } // For now hardcoded for triangles, until I see a model with something different. stream.startBlock('Faces', 1, this.faces.length); stream.startBlock('Triangles'); stream.writeVector(this.faces); stream.endBlock(); stream.endBlock(); stream.startBlock('Groups', this.matrixGroups.length, this.matrixIndices.length); let index = 0; for (const groupSize of this.matrixGroups) { stream.writeVectorAttrib('Matrices', this.matrixIndices.subarray(index, index + groupSize)); index += groupSize; } stream.endBlock(); this.extent.writeMdl(stream); for (const sequenceExtent of this.sequenceExtents) { stream.startBlock('Anim'); sequenceExtent.writeMdl(stream); stream.endBlock(); } stream.writeNumberAttrib('MaterialID', this.materialId); stream.writeNumberAttrib('SelectionGroup', this.selectionGroup); if (this.selectionFlags === 4) { stream.writeFlag('Unselectable'); } if (version > 800) { stream.writeNumberAttrib('LevelOfDetail', this.lod); if (this.lodName.length) { stream.writeStringAttrib('Name', this.lodName); } } stream.endBlock(); } getByteLength(version: number): number { let size = 120 + this.vertices.byteLength + this.normals.byteLength + this.faceTypeGroups.byteLength + this.faceGroups.byteLength + this.faces.byteLength + this.vertexGroups.byteLength + this.matrixGroups.byteLength + this.matrixIndices.byteLength + this.sequenceExtents.length * 28; if (version > 800) { size += 84; if (this.tangents.length) { size += 8 + this.tangents.byteLength; } if (this.skin.length) { size += 8 + this.skin.byteLength; } } for (const uvSet of this.uvSets) { size += 8 + uvSet.byteLength; } return size; } } ================================================ FILE: src/parsers/mdlx/geosetanimation.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import AnimatedObject from './animatedobject'; /** * A geoset animation. */ export default class GeosetAnimation extends AnimatedObject { alpha = 1; flags = 0; color = new Float32Array([1, 1, 1]); geosetId = -1; readMdx(stream: BinaryStream): void { const size = stream.readUint32(); this.alpha = stream.readFloat32(); this.flags = stream.readUint32(); stream.readFloat32Array(this.color); this.geosetId = stream.readInt32(); this.readAnimations(stream, size - 28); } writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); stream.writeFloat32(this.alpha); stream.writeUint32(this.flags); stream.writeFloat32Array(this.color); stream.writeInt32(this.geosetId); this.writeAnimations(stream); } readMdl(stream: TokenStream): void { for (const token of super.readAnimatedBlock(stream)) { if (token === 'DropShadow') { this.flags |= 0x1; } else if (token === 'static Alpha') { this.alpha = stream.readFloat(); } else if (token === 'Alpha') { this.readAnimation(stream, 'KGAO'); } else if (token === 'static Color') { this.flags |= 0x2; stream.readColor(this.color); } else if (token === 'Color') { this.flags |= 0x2; this.readAnimation(stream, 'KGAC'); } else if (token === 'GeosetId') { this.geosetId = stream.readInt(); } else { throw new Error(`Unknown token in GeosetAnimation: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startBlock('GeosetAnim'); if (this.flags & 0x1) { stream.writeFlag('DropShadow'); } if (!this.writeAnimation(stream, 'KGAO')) { stream.writeNumberAttrib('static Alpha', this.alpha); } if (this.flags & 0x2) { if (!this.writeAnimation(stream, 'KGAC') && (this.color[0] !== 1 || this.color[1] !== 1 || this.color[2] !== 1)) { stream.writeColor('static Color ', this.color); } } stream.writeNumberAttrib('GeosetId', this.geosetId); stream.endBlock(); } override getByteLength(): number { return 28 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/helper.ts ================================================ import TokenStream from './tokenstream'; import GenericObject from './genericobject'; /** * A helper. */ export default class Helper extends GenericObject { readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { throw new Error(`Unknown token in Helper: "${token}"`); } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('Helper', this.name); this.writeGenericHeader(stream); this.writeGenericAnimations(stream); stream.endBlock(); } } ================================================ FILE: src/parsers/mdlx/index.ts ================================================ import Model from './model'; import Sequence from './sequence'; import Material from './material'; import Layer from './layer'; import Texture from './texture'; import TextureAnimation from './textureanimation'; import Geoset from './geoset'; import GeosetAnimation from './geosetanimation'; import Bone from './bone'; import Light from './light'; import Helper from './helper'; import Attachment from './attachment'; import ParticleEmitter from './particleemitter'; import ParticleEmitter2 from './particleemitter2'; import ParticleEmitterPopcorn from './particleemitterpopcorn'; import RibbonEmitter from './ribbonemitter'; import Camera from './camera'; import EventObject from './eventobject'; import CollisionShape from './collisionshape'; import UnknownChunk from './unknownchunk'; import TokenStream from './tokenstream'; import { isMdx, isMdl } from './isformat'; export default { Model, Sequence, Material, Layer, Texture, TextureAnimation, Geoset, GeosetAnimation, Bone, Light, Helper, Attachment, ParticleEmitter, ParticleEmitter2, ParticleEmitterPopcorn, RibbonEmitter, Camera, EventObject, CollisionShape, UnknownChunk, TokenStream, isMdx, isMdl, }; ================================================ FILE: src/parsers/mdlx/isformat.ts ================================================ import { isStringInBytes, isStringInString } from '../../common/searches'; /** * Detects if the given object is an MDX source. */ export function isMdx(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array) { if (bytes[0] === 0x4d && bytes[1] === 0x44 && bytes[2] === 0x4c && bytes[3] === 0x58) { return true; } } if (typeof bytes === 'string' && bytes.startsWith('MDLX')) { return true; } return false; } /** * Detects if the given object is an MDL source. */ export function isMdl(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } // Look for FormatVersion in the first 4KB. if (bytes instanceof Uint8Array && isStringInBytes(bytes, 'FormatVersion', 0, 4096)) { return true; } // If the source is a string, look for FormatVersion same as above. if (typeof bytes === 'string' && isStringInString(bytes, 'FormatVersion', 0, 4096)) { return true; } return false; } ================================================ FILE: src/parsers/mdlx/layer.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import AnimatedObject from './animatedobject'; export const enum FilterMode { None = 0, Transparent = 1, Blend = 2, Additive = 3, AddAlpha = 4, Modulate = 5, Modulate2x = 6, } export const enum Flags { None = 0x0, Unshaded = 0x1, SphereEnvMap = 0x2, TwoSided = 0x10, Unfogged = 0x20, NoDepthTest = 0x40, NoDepthSet = 0x80, Unlit = 0x100, } // These two functions are needed because I am using const enums, which lets TS completely remove them from the output. // I think it's worth it for the price of these two functions that effectively were always here either way. function stringToMode(s: string): FilterMode { if (s === 'None') return FilterMode.None; if (s === 'Transparent') return FilterMode.Transparent; if (s === 'Blend') return FilterMode.Blend; if (s === 'Additive') return FilterMode.Additive; if (s === 'AddAlpha') return FilterMode.AddAlpha; if (s === 'Modulate') return FilterMode.Modulate; if (s === 'Modulate2x') return FilterMode.Modulate2x; return FilterMode.None; } function modeToString(m: FilterMode): string { if (m === FilterMode.None) return 'None'; if (m === FilterMode.Transparent) return 'Transparent'; if (m === FilterMode.Blend) return 'Blend'; if (m === FilterMode.Additive) return 'Additive'; if (m === FilterMode.AddAlpha) return 'AddAlpha'; if (m === FilterMode.Modulate) return 'Modulate'; if (m === FilterMode.Modulate2x) return 'Modulate2x'; return 'None'; } /** * A layer. */ export default class Layer extends AnimatedObject { filterMode = FilterMode.None; flags = Flags.None; textureId = -1; textureAnimationId = -1; coordId = 0; alpha = 1; /** * @since 900 */ emissiveGain = 1; /** * @since 1000 */ fresnelColor = new Float32Array([1, 1, 1]); /** * @since 1000 */ fresnelOpacity = 0; /** * @since 1000 */ fresnelTeamColor = 0; readMdx(stream: BinaryStream, version: number): void { const start = stream.index; const size = stream.readUint32(); this.filterMode = stream.readUint32(); this.flags = stream.readUint32(); this.textureId = stream.readInt32(); this.textureAnimationId = stream.readInt32(); this.coordId = stream.readUint32(); this.alpha = stream.readFloat32(); // Note that even though these fields were introduced in versions 900 and 1000 separately, the game does not offer backwards compatibility. if (version > 800) { this.emissiveGain = stream.readFloat32(); stream.readFloat32Array(this.fresnelColor); this.fresnelOpacity = stream.readFloat32(); this.fresnelTeamColor = stream.readFloat32(); } this.readAnimations(stream, size - (stream.index - start)); } writeMdx(stream: BinaryStream, version: number): void { stream.writeUint32(this.getByteLength(version)); stream.writeUint32(this.filterMode); stream.writeUint32(this.flags); stream.writeInt32(this.textureId); stream.writeInt32(this.textureAnimationId); stream.writeUint32(this.coordId); stream.writeFloat32(this.alpha); // See note above in readMdx. if (version > 800) { stream.writeFloat32(this.emissiveGain); stream.writeFloat32Array(this.fresnelColor); stream.writeFloat32(this.fresnelOpacity); stream.writeFloat32(this.fresnelTeamColor); } this.writeAnimations(stream); } readMdl(stream: TokenStream): void { for (const token of super.readAnimatedBlock(stream)) { if (token === 'FilterMode') { this.filterMode = stringToMode(stream.read()); } else if (token === 'Unshaded') { this.flags |= Flags.Unshaded; } else if (token === 'SphereEnvMap') { this.flags |= Flags.SphereEnvMap; } else if (token === 'TwoSided') { this.flags |= Flags.TwoSided; } else if (token === 'Unfogged') { this.flags |= Flags.Unfogged; } else if (token === 'NoDepthTest') { this.flags |= Flags.NoDepthTest; } else if (token === 'NoDepthSet') { this.flags |= Flags.NoDepthSet; } else if (token === 'Unlit') { this.flags |= Flags.Unlit; } else if (token === 'static TextureID') { this.textureId = stream.readInt(); } else if (token === 'TextureID') { this.readAnimation(stream, 'KMTF'); } else if (token === 'TVertexAnimId') { this.textureAnimationId = stream.readInt(); } else if (token === 'CoordId') { this.coordId = stream.readInt(); } else if (token === 'static Alpha') { this.alpha = stream.readFloat(); } else if (token === 'Alpha') { this.readAnimation(stream, 'KMTA'); } else if (token === 'static EmissiveGain') { this.emissiveGain = stream.readFloat(); } else if (token === 'EmissiveGain') { this.readAnimation(stream, 'KMTE'); } else if (token === 'static FresnelColor') { stream.readVector(this.fresnelColor); } else if (token === 'FresnelColor') { this.readAnimation(stream, 'KFC3'); } else if (token === 'static FresnelOpacity') { this.fresnelOpacity = stream.readFloat(); } else if (token === 'FresnelOpacity') { this.readAnimation(stream, 'KFCA'); } else if (token === 'static FresnelTeamColor') { this.fresnelTeamColor = stream.readFloat(); } else if (token === 'FresnelTeamColor') { this.readAnimation(stream, 'KFTC'); } else { throw new Error(`Unknown token in Layer: "${token}"`); } } } writeMdl(stream: TokenStream, version: number): void { stream.startBlock('Layer'); stream.writeFlagAttrib('FilterMode', modeToString(this.filterMode)); if (this.flags & Flags.Unshaded) { stream.writeFlag('Unshaded'); } if (this.flags & Flags.SphereEnvMap) { stream.writeFlag('SphereEnvMap'); } if (this.flags & Flags.TwoSided) { stream.writeFlag('TwoSided'); } if (this.flags & Flags.Unfogged) { stream.writeFlag('Unfogged'); } if (this.flags & Flags.NoDepthTest) { stream.writeFlag('NoDepthTest'); } if (this.flags & Flags.NoDepthSet) { stream.writeFlag('NoDepthSet'); } if (version > 800) { if (this.flags & Flags.Unlit) { stream.writeFlag('Unlit'); } } if (!this.writeAnimation(stream, 'KMTF')) { stream.writeNumberAttrib('static TextureID', this.textureId); } if (this.textureAnimationId !== -1) { stream.writeNumberAttrib('TVertexAnimId', this.textureAnimationId); } if (this.coordId !== 0) { stream.writeNumberAttrib('CoordId', this.coordId); } if (!this.writeAnimation(stream, 'KMTA') && this.alpha !== 1) { stream.writeNumberAttrib('static Alpha', this.alpha); } if (version > 800) { if (!this.writeAnimation(stream, 'KMTE') && this.emissiveGain !== 1) { stream.writeNumberAttrib('static EmissiveGain', this.emissiveGain); } if (!this.writeAnimation(stream, 'KFC3') && (this.fresnelColor[0] !== 1 || this.fresnelColor[1] !== 1 || this.fresnelColor[2] !== 1)) { stream.writeVectorAttrib('static FresnelColor', this.fresnelColor); } if (!this.writeAnimation(stream, 'KFCA') && this.fresnelOpacity !== 0) { stream.writeNumberAttrib('static FresnelOpacity', this.fresnelOpacity); } if (!this.writeAnimation(stream, 'KFTC') && this.fresnelTeamColor !== 0) { stream.writeNumberAttrib('static FresnelTeamColor', this.fresnelTeamColor); } } stream.endBlock(); } override getByteLength(version: number): number { let size = 28 + super.getByteLength(); // See note above in readMdx. if (version > 800) { size += 24; } return size; } } ================================================ FILE: src/parsers/mdlx/light.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; export const enum LightType { None = -1, Omnidirectional = 0, Directional = 1, Ambient = 2, } /** * A light. */ export default class Light extends GenericObject { type = LightType.None; attenuation = new Float32Array(2); color = new Float32Array(3); intensity = 0; ambientColor = new Float32Array(3); ambientIntensity = 0; constructor() { super(0x200); } override readMdx(stream: BinaryStream): void { const start = stream.index; const size = stream.readUint32(); super.readMdx(stream); this.type = stream.readUint32(); stream.readFloat32Array(this.attenuation); stream.readFloat32Array(this.color); this.intensity = stream.readFloat32(); stream.readFloat32Array(this.ambientColor); this.ambientIntensity = stream.readFloat32(); this.readAnimations(stream, size - (stream.index - start)); } override writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); super.writeMdx(stream); stream.writeUint32(this.type); stream.writeFloat32Array(this.attenuation); stream.writeFloat32Array(this.color); stream.writeFloat32(this.intensity); stream.writeFloat32Array(this.ambientColor); stream.writeFloat32(this.ambientIntensity); this.writeNonGenericAnimationChunks(stream); } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'Omnidirectional') { this.type = LightType.Omnidirectional; } else if (token === 'Directional') { this.type = LightType.Directional; } else if (token === 'Ambient') { this.type = LightType.Ambient; } else if (token === 'static AttenuationStart') { this.attenuation[0] = stream.readFloat(); } else if (token === 'AttenuationStart') { this.readAnimation(stream, 'KLAS'); } else if (token === 'static AttenuationEnd') { this.attenuation[1] = stream.readFloat(); } else if (token === 'AttenuationEnd') { this.readAnimation(stream, 'KLAE'); } else if (token === 'static Intensity') { this.intensity = stream.readFloat(); } else if (token === 'Intensity') { this.readAnimation(stream, 'KLAI'); } else if (token === 'static Color') { stream.readColor(this.color); } else if (token === 'Color') { this.readAnimation(stream, 'KLAC'); } else if (token === 'static AmbIntensity') { this.ambientIntensity = stream.readFloat(); } else if (token === 'AmbIntensity') { this.readAnimation(stream, 'KLBI'); } else if (token === 'static AmbColor') { stream.readColor(this.ambientColor); } else if (token === 'AmbColor') { this.readAnimation(stream, 'KLBC'); } else if (token === 'Visibility') { this.readAnimation(stream, 'KLAV'); } else { throw new Error(`Unknown token in Light: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('Light', this.name); this.writeGenericHeader(stream); if (this.type === LightType.Omnidirectional) { stream.writeFlag('Omnidirectional'); } else if (this.type === LightType.Directional) { stream.writeFlag('Directional'); } else if (this.type === LightType.Ambient) { stream.writeFlag('Ambient'); } if (!this.writeAnimation(stream, 'KLAS')) { stream.writeNumberAttrib('static AttenuationStart', this.attenuation[0]); } if (!this.writeAnimation(stream, 'KLAE')) { stream.writeNumberAttrib('static AttenuationEnd', this.attenuation[1]); } if (!this.writeAnimation(stream, 'KLAI')) { stream.writeNumberAttrib('static Intensity', this.intensity); } if (!this.writeAnimation(stream, 'KLAC')) { stream.writeColor('static Color', this.color); } if (!this.writeAnimation(stream, 'KLBI')) { stream.writeNumberAttrib('static AmbIntensity', this.ambientIntensity); } if (!this.writeAnimation(stream, 'KLBC')) { stream.writeColor('static AmbColor', this.ambientColor); } this.writeAnimation(stream, 'KLAV'); this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 48 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/material.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import Layer from './layer'; export const enum Flags { None = 0x0, ConstantColor = 0x1, TwoSided = 0x2, SortPrimsNearZ = 0x8, SortPrimsFarZ = 0x10, FullResolution = 0x20, } /** * A material. */ export default class Material { priorityPlane = 0; flags = Flags.None; /** * @since 900 */ shader = ''; layers: Layer[] = []; readMdx(stream: BinaryStream, version: number): void { stream.readUint32(); // Don't care about the size. this.priorityPlane = stream.readInt32(); this.flags = stream.readUint32(); if (version > 800) { this.shader = stream.read(80); } stream.skip(4); // LAYS for (let i = 0, l = stream.readUint32(); i < l; i++) { const layer = new Layer(); layer.readMdx(stream, version); this.layers.push(layer); } } writeMdx(stream: BinaryStream, version: number): void { stream.writeUint32(this.getByteLength(version)); stream.writeInt32(this.priorityPlane); stream.writeUint32(this.flags); if (version > 800) { stream.skip(80 - stream.write(this.shader)); } stream.writeBinary('LAYS'); stream.writeUint32(this.layers.length); for (const layer of this.layers) { layer.writeMdx(stream, version); } } readMdl(stream: TokenStream): void { for (const token of stream.readBlock()) { if (token === 'ConstantColor') { this.flags |= Flags.ConstantColor; } else if (token === 'TwoSided') { this.flags |= Flags.TwoSided; } else if (token === 'SortPrimsNearZ') { this.flags |= Flags.SortPrimsNearZ; } else if (token === 'SortPrimsFarZ') { this.flags |= Flags.SortPrimsFarZ; } else if (token === 'FullResolution') { this.flags |= Flags.FullResolution; } else if (token === 'PriorityPlane') { this.priorityPlane = stream.readInt(); } else if (token === 'Shader') { this.shader = stream.read(); } else if (token === 'Layer') { const layer = new Layer(); layer.readMdl(stream); this.layers.push(layer); } else { throw new Error(`Unknown token in Material: "${token}"`); } } } writeMdl(stream: TokenStream, version: number): void { stream.startBlock('Material'); if (this.flags & Flags.ConstantColor) { stream.writeFlag('ConstantColor'); } if (version > 800) { if (this.flags & Flags.TwoSided) { stream.writeFlag('TwoSided'); } } if (this.flags & Flags.SortPrimsNearZ) { stream.writeFlag('SortPrimsNearZ'); } if (this.flags & Flags.SortPrimsFarZ) { stream.writeFlag('SortPrimsFarZ'); } if (this.flags & Flags.FullResolution) { stream.writeFlag('FullResolution'); } if (this.priorityPlane !== 0) { stream.writeNumberAttrib('PriorityPlane', this.priorityPlane); } if (version > 800) { stream.writeStringAttrib('Shader', this.shader); } for (const layer of this.layers) { layer.writeMdl(stream, version); } stream.endBlock(); } getByteLength(version: number): number { let size = 20; if (version > 800) { size += 80; } for (const layer of this.layers) { size += layer.getByteLength(version); } return size; } } ================================================ FILE: src/parsers/mdlx/model.ts ================================================ import BinaryStream from '../../common/binarystream'; import { decodeUtf8, encodeUtf8 } from '../../common/utf8'; import TokenStream from './tokenstream'; import Extent from './extent'; import Sequence from './sequence'; import Material from './material'; import Texture from './texture'; import TextureAnimation from './textureanimation'; import Geoset from './geoset'; import GeosetAnimation from './geosetanimation'; import GenericObject from './genericobject'; import Bone from './bone'; import Light from './light'; import Helper from './helper'; import Attachment from './attachment'; import ParticleEmitter from './particleemitter'; import ParticleEmitter2 from './particleemitter2'; import ParticleEmitterPopcorn from './particleemitterpopcorn'; import RibbonEmitter from './ribbonemitter'; import Camera from './camera'; import EventObject from './eventobject'; import CollisionShape from './collisionshape'; import FaceEffect from './faceeffect'; import UnknownChunk from './unknownchunk'; import { isMdl, isMdx } from './isformat'; // Used below to get proper typings for the generic methods. type MdxStaticObject = Sequence | Texture | FaceEffect; type MdxDynamicObject = Material | TextureAnimation | Geoset | GeosetAnimation | Bone | Light | Helper | Attachment | ParticleEmitter | ParticleEmitter2 | RibbonEmitter | Camera | EventObject | CollisionShape | ParticleEmitterPopcorn; type MdlNumberedObject = Sequence | Texture | Material | TextureAnimation; type MdlObject = Geoset | GeosetAnimation | Bone | Light | Helper | Attachment | ParticleEmitter | ParticleEmitter2 | RibbonEmitter | Camera | EventObject | CollisionShape | FaceEffect; /** * A Warcraft 3 model. * Supports loading from and saving to both the binary MDX and text MDL file formats. */ export default class Model { /** * 800 for Warcraft 3: RoC and TFT. * >800 for Warcraft 3: Reforged. */ version = 800; name = ''; /** * To the best of my knowledge, this should always be left empty. */ animationFile = ''; extent = new Extent(); /** * This is only used by the now-defunct previewer that came with Art Tools. */ blendTime = 0; sequences: Sequence[] = []; globalSequences: number[] = []; materials: Material[] = []; textures: Texture[] = []; textureAnimations: TextureAnimation[] = []; geosets: Geoset[] = []; geosetAnimations: GeosetAnimation[] = []; bones: Bone[] = []; lights: Light[] = []; helpers: Helper[] = []; attachments: Attachment[] = []; pivotPoints: Float32Array[] = []; particleEmitters: ParticleEmitter[] = []; particleEmitters2: ParticleEmitter2[] = []; /** * @since 900 */ particleEmittersPopcorn: ParticleEmitterPopcorn[] = []; ribbonEmitters: RibbonEmitter[] = []; cameras: Camera[] = []; eventObjects: EventObject[] = []; collisionShapes: CollisionShape[] = []; /** * @since 900 */ faceEffects: FaceEffect[] = []; /** * @since 900 */ bindPose: Float32Array[] = []; /** * The MDX format is chunk based, and Warcraft 3 does not mind there being unknown chunks in there. * Some 3rd party tools use this to attach metadata to models. * When an unknown chunk is encountered, it will be added here. * These chunks will be saved when saving as MDX. */ unknownChunks: UnknownChunk[] = []; /** * Load the model from MDX or MDL. * The format is detected automatically. */ load(buffer: ArrayBuffer | Uint8Array | string): void { if (isMdx(buffer)) { if (typeof buffer === 'string') { buffer = encodeUtf8(buffer); } this.loadMdx(buffer); } else if (isMdl(buffer)) { if (typeof buffer !== 'string') { buffer = decodeUtf8(buffer); } this.loadMdl(buffer); } else { throw new Error('Not a valid MDX/MDL buffer'); } } /** * Load the model from MDX. */ loadMdx(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); let tag; let size; stream.skip(4); // MDLX while (stream.remaining > 0) { tag = stream.readBinary(4); size = stream.readUint32(); if (tag === 'VERS') { this.loadVersionChunk(stream); } else if (tag === 'MODL') { this.loadModelChunk(stream); } else if (tag === 'SEQS') { this.loadStaticObjects(this.sequences, Sequence, stream, size / 132); } else if (tag === 'GLBS') { this.loadGlobalSequenceChunk(stream, size); } else if (tag === 'MTLS') { this.loadDynamicObjects(this.materials, Material, stream, size); } else if (tag === 'TEXS') { this.loadStaticObjects(this.textures, Texture, stream, size / 268); } else if (tag === 'TXAN') { this.loadDynamicObjects(this.textureAnimations, TextureAnimation, stream, size); } else if (tag === 'GEOS') { this.loadDynamicObjects(this.geosets, Geoset, stream, size); } else if (tag === 'GEOA') { this.loadDynamicObjects(this.geosetAnimations, GeosetAnimation, stream, size); } else if (tag === 'BONE') { this.loadDynamicObjects(this.bones, Bone, stream, size); } else if (tag === 'LITE') { this.loadDynamicObjects(this.lights, Light, stream, size); } else if (tag === 'HELP') { this.loadDynamicObjects(this.helpers, Helper, stream, size); } else if (tag === 'ATCH') { this.loadDynamicObjects(this.attachments, Attachment, stream, size); } else if (tag === 'PIVT') { this.loadPivotPointChunk(stream, size); } else if (tag === 'PREM') { this.loadDynamicObjects(this.particleEmitters, ParticleEmitter, stream, size); } else if (tag === 'PRE2') { this.loadDynamicObjects(this.particleEmitters2, ParticleEmitter2, stream, size); } else if (tag === 'CORN') { this.loadDynamicObjects(this.particleEmittersPopcorn, ParticleEmitterPopcorn, stream, size); } else if (tag === 'RIBB') { this.loadDynamicObjects(this.ribbonEmitters, RibbonEmitter, stream, size); } else if (tag === 'CAMS') { this.loadDynamicObjects(this.cameras, Camera, stream, size); } else if (tag === 'EVTS') { this.loadDynamicObjects(this.eventObjects, EventObject, stream, size); } else if (tag === 'CLID') { this.loadDynamicObjects(this.collisionShapes, CollisionShape, stream, size); } else if (tag === 'FAFX') { this.loadStaticObjects(this.faceEffects, FaceEffect, stream, size / 340); } else if (tag === 'BPOS') { this.loadBindPoseChunk(stream, size); } else { this.unknownChunks.push(new UnknownChunk(stream, size, tag)); } } } loadVersionChunk(stream: BinaryStream): void { this.version = stream.readUint32(); } loadModelChunk(stream: BinaryStream): void { this.name = stream.read(80); this.animationFile = stream.read(260); this.extent.readMdx(stream); this.blendTime = stream.readUint32(); } loadStaticObjects(out: T[], constructor: new () => T, stream: BinaryStream, count: number): void { for (let i = 0; i < count; i++) { const object = new constructor(); object.readMdx(stream); out.push(object); } } loadGlobalSequenceChunk(stream: BinaryStream, size: number): void { for (let i = 0, l = size / 4; i < l; i++) { this.globalSequences.push(stream.readUint32()); } } loadDynamicObjects(out: T[], constructor: new () => T, stream: BinaryStream, size: number): void { const end = stream.index + size; while (stream.index < end) { const object = new constructor(); object.readMdx(stream, this.version); out.push(object); } } loadPivotPointChunk(stream: BinaryStream, size: number): void { for (let i = 0, l = size / 12; i < l; i++) { this.pivotPoints.push(stream.readFloat32Array(3)); } } loadBindPoseChunk(stream: BinaryStream, _size: number): void { for (let i = 0, l = stream.readUint32(); i < l; i++) { this.bindPose[i] = stream.readFloat32Array(12); } } /** * Save the model as MDX. */ saveMdx(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeBinary('MDLX'); this.saveVersionChunk(stream); this.saveModelChunk(stream); this.saveStaticObjectChunk(stream, 'SEQS', this.sequences, 132); this.saveGlobalSequenceChunk(stream); this.saveDynamicObjectChunk(stream, 'MTLS', this.materials); this.saveStaticObjectChunk(stream, 'TEXS', this.textures, 268); this.saveDynamicObjectChunk(stream, 'TXAN', this.textureAnimations); this.saveDynamicObjectChunk(stream, 'GEOS', this.geosets); this.saveDynamicObjectChunk(stream, 'GEOA', this.geosetAnimations); this.saveDynamicObjectChunk(stream, 'BONE', this.bones); this.saveDynamicObjectChunk(stream, 'LITE', this.lights); this.saveDynamicObjectChunk(stream, 'HELP', this.helpers); this.saveDynamicObjectChunk(stream, 'ATCH', this.attachments); this.savePivotPointChunk(stream); this.saveDynamicObjectChunk(stream, 'PREM', this.particleEmitters); this.saveDynamicObjectChunk(stream, 'PRE2', this.particleEmitters2); if (this.version > 800) { this.saveDynamicObjectChunk(stream, 'CORN', this.particleEmittersPopcorn); } this.saveDynamicObjectChunk(stream, 'RIBB', this.ribbonEmitters); this.saveDynamicObjectChunk(stream, 'CAMS', this.cameras); this.saveDynamicObjectChunk(stream, 'EVTS', this.eventObjects); this.saveDynamicObjectChunk(stream, 'CLID', this.collisionShapes); if (this.version > 800) { this.saveStaticObjectChunk(stream, 'FAFX', this.faceEffects, 340); this.saveBindPoseChunk(stream); } for (const chunk of this.unknownChunks) { chunk.writeMdx(stream); } return stream.uint8array; } saveVersionChunk(stream: BinaryStream): void { stream.writeBinary('VERS'); stream.writeUint32(4); stream.writeUint32(this.version); } saveModelChunk(stream: BinaryStream): void { stream.writeBinary('MODL'); stream.writeUint32(372); stream.skip(80 - stream.write(this.name)); stream.skip(260 - stream.write(this.animationFile)); this.extent.writeMdx(stream); stream.writeUint32(this.blendTime); } saveStaticObjectChunk(stream: BinaryStream, name: string, objects: (Sequence | Texture | FaceEffect)[], size: number): void { if (objects.length) { stream.writeBinary(name); stream.writeUint32(objects.length * size); for (const object of objects) { object.writeMdx(stream); } } } saveGlobalSequenceChunk(stream: BinaryStream): void { if (this.globalSequences.length) { stream.writeBinary('GLBS'); stream.writeUint32(this.globalSequences.length * 4); for (const globalSequence of this.globalSequences) { stream.writeUint32(globalSequence); } } } saveDynamicObjectChunk(stream: BinaryStream, name: string, objects: (Material | TextureAnimation | Geoset | GeosetAnimation | GenericObject | Camera)[]): void { if (objects.length) { stream.writeBinary(name); stream.writeUint32(this.getObjectsByteLength(objects)); for (const object of objects) { object.writeMdx(stream, this.version); } } } savePivotPointChunk(stream: BinaryStream): void { if (this.pivotPoints.length) { stream.writeBinary('PIVT'); stream.writeUint32(this.pivotPoints.length * 12); for (const pivotPoint of this.pivotPoints) { stream.writeFloat32Array(pivotPoint); } } } saveBindPoseChunk(stream: BinaryStream): void { if (this.bindPose.length) { stream.writeBinary('BPOS'); stream.writeUint32(4 + this.bindPose.length * 48); stream.writeUint32(this.bindPose.length); for (const matrix of this.bindPose) { stream.writeFloat32Array(matrix); } } } /** * Load the model from MDL. */ loadMdl(buffer: string): void { let token: string; const stream = new TokenStream(buffer); while ((token = stream.readToken())) { if (token === 'Version') { this.loadVersionBlock(stream); } else if (token === 'Model') { this.loadModelBlock(stream); } else if (token === 'Sequences') { this.loadNumberedObjectBlock(this.sequences, Sequence, 'Anim', stream); } else if (token === 'GlobalSequences') { this.loadGlobalSequenceBlock(stream); } else if (token === 'Textures') { this.loadNumberedObjectBlock(this.textures, Texture, 'Bitmap', stream); } else if (token === 'Materials') { this.loadNumberedObjectBlock(this.materials, Material, 'Material', stream); } else if (token === 'TextureAnims') { this.loadNumberedObjectBlock(this.textureAnimations, TextureAnimation, 'TVertexAnim', stream); } else if (token === 'Geoset') { this.loadObject(this.geosets, Geoset, stream); } else if (token === 'GeosetAnim') { this.loadObject(this.geosetAnimations, GeosetAnimation, stream); } else if (token === 'Bone') { this.loadObject(this.bones, Bone, stream); } else if (token === 'Light') { this.loadObject(this.lights, Light, stream); } else if (token === 'Helper') { this.loadObject(this.helpers, Helper, stream); } else if (token === 'Attachment') { this.loadObject(this.attachments, Attachment, stream); } else if (token === 'PivotPoints') { this.loadPivotPointBlock(stream); } else if (token === 'ParticleEmitter') { this.loadObject(this.particleEmitters, ParticleEmitter, stream); } else if (token === 'ParticleEmitter2') { this.loadObject(this.particleEmitters2, ParticleEmitter2, stream); } else if (token === 'ParticleEmitterPopcorn') { this.loadObject(this.particleEmittersPopcorn, ParticleEmitterPopcorn, stream); } else if (token === 'RibbonEmitter') { this.loadObject(this.ribbonEmitters, RibbonEmitter, stream); } else if (token === 'Camera') { this.loadObject(this.cameras, Camera, stream); } else if (token === 'EventObject') { this.loadObject(this.eventObjects, EventObject, stream); } else if (token === 'CollisionShape') { this.loadObject(this.collisionShapes, CollisionShape, stream); } else if (token === 'FaceFX') { this.loadObject(this.faceEffects, FaceEffect, stream); } else if (token === 'BindPose') { this.loadBindPoseBlock(stream); } else { throw new Error(`Unsupported block: ${token}`); } } } loadVersionBlock(stream: TokenStream): void { for (const token of stream.readBlock()) { if (token === 'FormatVersion') { this.version = stream.readInt(); } else { throw new Error(`Unknown token in Version: "${token}"`); } } } loadModelBlock(stream: TokenStream): void { this.name = stream.read(); for (const token of stream.readBlock()) { if (token.startsWith('Num')) { // Don't care about the number of things, the arrays will grow as they wish. // This includes: // NumGeosets // NumGeosetAnims // NumHelpers // NumLights // NumBones // NumSoundEmitters (deprecated) // NumAttachments // NumParticleEmitters // NumParticleEmitters2 // NumParticleEmittersPopcorn (>800) // NumRibbonEmitters // NumEvents // NumFaceFX (>800) stream.read(); } else if (token === 'BlendTime') { this.blendTime = stream.readInt(); } else if (token === 'MinimumExtent') { stream.readVector(this.extent.min); } else if (token === 'MaximumExtent') { stream.readVector(this.extent.max); } else if (token === 'BoundsRadius') { this.extent.boundsRadius = stream.readFloat(); } else if (token === 'AnimationFile') { this.animationFile = stream.read(); } else { throw new Error(`Unknown token in Model: "${token}"`); } } } loadNumberedObjectBlock(out: T[], constructor: new () => T, name: string, stream: TokenStream): void { stream.read(); // Don't care about the number, the array will grow. for (const token of stream.readBlock()) { if (token === name) { const object = new constructor(); object.readMdl(stream); out.push(object); } else { throw new Error(`Unknown token in ${name}: "${token}"`); } } } loadGlobalSequenceBlock(stream: TokenStream): void { stream.read(); // Don't care about the number, the array will grow. for (const token of stream.readBlock()) { if (token === 'Duration') { this.globalSequences.push(stream.readInt()); } else { throw new Error(`Unknown token in GlobalSequences: "${token}"`); } } } loadObject(out: T[], constructor: new () => T, stream: TokenStream): void { const object = new constructor(); object.readMdl(stream); out.push(object); } loadPivotPointBlock(stream: TokenStream): void { const count = stream.readInt(); stream.read(); // { for (let i = 0; i < count; i++) { this.pivotPoints.push(stream.readVector(new Float32Array(3))); } stream.read(); // } } loadBindPoseBlock(stream: TokenStream): void { for (const token of stream.readBlock()) { if (token === 'Matrices') { const matrices = stream.readInt(); stream.read(); // { for (let i = 0; i < matrices; i++) { this.bindPose[i] = stream.readVector(new Float32Array(12)); } stream.read(); // } } else { throw new Error(`Unknown token in BindPose: "${token}"`); } } } /** * Save the model as MDL. */ saveMdl(): string { const stream = new TokenStream(); this.saveVersionBlock(stream); this.saveModelBlock(stream); this.saveStaticObjectsBlock(stream, 'Sequences', this.sequences); this.saveGlobalSequenceBlock(stream); this.saveStaticObjectsBlock(stream, 'Textures', this.textures); this.saveStaticObjectsBlock(stream, 'Materials', this.materials); this.saveStaticObjectsBlock(stream, 'TextureAnims', this.textureAnimations); this.saveObjects(stream, this.geosets); this.saveObjects(stream, this.geosetAnimations); this.saveObjects(stream, this.bones); this.saveObjects(stream, this.lights); this.saveObjects(stream, this.helpers); this.saveObjects(stream, this.attachments); this.savePivotPointBlock(stream); this.saveObjects(stream, this.particleEmitters); this.saveObjects(stream, this.particleEmitters2); if (this.version > 800) { this.saveObjects(stream, this.particleEmittersPopcorn); } this.saveObjects(stream, this.ribbonEmitters); this.saveObjects(stream, this.cameras); this.saveObjects(stream, this.eventObjects); this.saveObjects(stream, this.collisionShapes); if (this.version > 800) { this.saveObjects(stream, this.faceEffects); this.saveBindPoseBlock(stream); } return stream.buffer; } saveVersionBlock(stream: TokenStream): void { stream.startBlock('Version'); stream.writeNumberAttrib('FormatVersion', this.version); stream.endBlock(); } saveModelBlock(stream: TokenStream): void { stream.startObjectBlock('Model', this.name); stream.writeNumberAttrib('BlendTime', this.blendTime); this.extent.writeMdl(stream); if (this.animationFile.length) { stream.writeStringAttrib('AnimationFile', this.animationFile); } stream.endBlock(); } saveStaticObjectsBlock(stream: TokenStream, name: string, objects: (Sequence | Texture | Material | TextureAnimation)[]): void { if (objects.length) { stream.startBlock(name, objects.length); for (const object of objects) { object.writeMdl(stream, this.version); } stream.endBlock(); } } saveGlobalSequenceBlock(stream: TokenStream): void { if (this.globalSequences.length) { stream.startBlock('GlobalSequences', this.globalSequences.length); for (const globalSequence of this.globalSequences) { stream.writeNumberAttrib('Duration', globalSequence); } stream.endBlock(); } } saveObjects(stream: TokenStream, objects: (Geoset | GeosetAnimation | Bone | Light | Helper | Attachment | ParticleEmitter | ParticleEmitter2 | RibbonEmitter | Camera | EventObject | CollisionShape | FaceEffect)[]): void { for (const object of objects) { object.writeMdl(stream, this.version); } } savePivotPointBlock(stream: TokenStream): void { if (this.pivotPoints.length) { stream.startBlock('PivotPoints', this.pivotPoints.length); for (const pivotPoint of this.pivotPoints) { stream.writeVector(pivotPoint); } stream.endBlock(); } } saveBindPoseBlock(stream: TokenStream): void { if (this.bindPose.length) { stream.startBlock('BindPose'); stream.startBlock('Matrices', this.bindPose.length); for (const matrix of this.bindPose) { stream.writeVector(matrix); } stream.endBlock(); stream.endBlock(); } } /** * Calculate the size of the model as MDX. */ getByteLength(): number { let size = 396; size += this.getStaticObjectsChunkByteLength(this.sequences, 132); size += this.getStaticObjectsChunkByteLength(this.globalSequences, 4); size += this.getDynamicObjectsChunkByteLength(this.materials); size += this.getStaticObjectsChunkByteLength(this.textures, 268); size += this.getDynamicObjectsChunkByteLength(this.textureAnimations); size += this.getDynamicObjectsChunkByteLength(this.geosets); size += this.getDynamicObjectsChunkByteLength(this.geosetAnimations); size += this.getDynamicObjectsChunkByteLength(this.bones); size += this.getDynamicObjectsChunkByteLength(this.lights); size += this.getDynamicObjectsChunkByteLength(this.helpers); size += this.getDynamicObjectsChunkByteLength(this.attachments); size += this.getStaticObjectsChunkByteLength(this.pivotPoints, 12); size += this.getDynamicObjectsChunkByteLength(this.particleEmitters); size += this.getDynamicObjectsChunkByteLength(this.particleEmitters2); if (this.version > 800) { size += this.getDynamicObjectsChunkByteLength(this.particleEmittersPopcorn); } size += this.getDynamicObjectsChunkByteLength(this.ribbonEmitters); size += this.getDynamicObjectsChunkByteLength(this.cameras); size += this.getDynamicObjectsChunkByteLength(this.eventObjects); size += this.getDynamicObjectsChunkByteLength(this.collisionShapes); if (this.version > 800) { size += this.getStaticObjectsChunkByteLength(this.faceEffects, 340); size += this.getBindPoseChunkByteLength(); } size += this.getObjectsByteLength(this.unknownChunks); return size; } getObjectsByteLength(objects: (Material | TextureAnimation | Geoset | GeosetAnimation | GenericObject | Camera | UnknownChunk)[]): number { let size = 0; for (const object of objects) { size += object.getByteLength(this.version); } return size; } getDynamicObjectsChunkByteLength(objects: (Material | TextureAnimation | Geoset | GeosetAnimation | GenericObject | Camera | UnknownChunk)[]): number { if (objects.length) { return 8 + this.getObjectsByteLength(objects); } return 0; } getStaticObjectsChunkByteLength(objects: (Sequence | number | Texture | Float32Array | FaceEffect)[], size: number): number { if (objects.length) { return 8 + objects.length * size; } return 0; } getBindPoseChunkByteLength(): number { if (this.bindPose.length) { return 12 + this.bindPose.length * 48; } return 0; } } ================================================ FILE: src/parsers/mdlx/particleemitter.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; export const enum Flags { EmitterUsesMDL = 0x8000, EmitterUsesTGA = 0x10000, } /** * A particle emitter. */ export default class ParticleEmitter extends GenericObject { emissionRate = 0; gravity = 0; longitude = 0; latitude = 0; path = ''; lifeSpan = 0; speed = 0; constructor() { super(0x1000); } override readMdx(stream: BinaryStream): void { const start = stream.index; const size = stream.readUint32(); super.readMdx(stream); this.emissionRate = stream.readFloat32(); this.gravity = stream.readFloat32(); this.longitude = stream.readFloat32(); this.latitude = stream.readFloat32(); this.path = stream.read(260); this.lifeSpan = stream.readFloat32(); this.speed = stream.readFloat32(); this.readAnimations(stream, size - (stream.index - start)); } override writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); super.writeMdx(stream); stream.writeFloat32(this.emissionRate); stream.writeFloat32(this.gravity); stream.writeFloat32(this.longitude); stream.writeFloat32(this.latitude); stream.skip(260 - stream.write(this.path)); stream.writeFloat32(this.lifeSpan); stream.writeFloat32(this.speed); this.writeNonGenericAnimationChunks(stream); } readMdl(stream: TokenStream): void { for (let token of super.readGenericBlock(stream)) { if (token === 'EmitterUsesMDL') { this.flags |= Flags.EmitterUsesMDL; } else if (token === 'EmitterUsesTGA') { this.flags |= Flags.EmitterUsesTGA; } else if (token === 'static EmissionRate') { this.emissionRate = stream.readFloat(); } else if (token === 'EmissionRate') { this.readAnimation(stream, 'KPEE'); } else if (token === 'static Gravity') { this.gravity = stream.readFloat(); } else if (token === 'Gravity') { this.readAnimation(stream, 'KPEG'); } else if (token === 'static Longitude') { this.longitude = stream.readFloat(); } else if (token === 'Longitude') { this.readAnimation(stream, 'KPLN'); } else if (token === 'static Latitude') { this.latitude = stream.readFloat(); } else if (token === 'Latitude') { this.readAnimation(stream, 'KPLT'); } else if (token === 'Visibility') { this.readAnimation(stream, 'KPEV'); } else if (token === 'Particle') { for (token of this.readAnimatedBlock(stream)) { if (token === 'static LifeSpan') { this.lifeSpan = stream.readFloat(); } else if (token === 'LifeSpan') { this.readAnimation(stream, 'KPEL'); } else if (token === 'static InitVelocity') { this.speed = stream.readFloat(); } else if (token === 'InitVelocity') { this.readAnimation(stream, 'KPES'); } else if (token === 'Path') { this.path = stream.read(); } } } else { throw new Error(`Unknown token in ParticleEmitter: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('ParticleEmitter', this.name); this.writeGenericHeader(stream); if (this.flags & Flags.EmitterUsesMDL) { stream.writeFlag('EmitterUsesMDL'); } if (this.flags & Flags.EmitterUsesTGA) { stream.writeFlag('EmitterUsesTGA'); } if (!this.writeAnimation(stream, 'KPEE')) { stream.writeNumberAttrib('static EmissionRate', this.emissionRate); } if (!this.writeAnimation(stream, 'KPEG')) { stream.writeNumberAttrib('static Gravity', this.gravity); } if (!this.writeAnimation(stream, 'KPLN')) { stream.writeNumberAttrib('static Longitude', this.longitude); } if (!this.writeAnimation(stream, 'KPLT')) { stream.writeNumberAttrib('static Latitude', this.latitude); } this.writeAnimation(stream, 'KPEV'); stream.startBlock('Particle'); if (!this.writeAnimation(stream, 'KPEL')) { stream.writeNumberAttrib('static LifeSpan', this.lifeSpan); } if (!this.writeAnimation(stream, 'KPES')) { stream.writeNumberAttrib('static InitVelocity', this.speed); } if ((this.flags & Flags.EmitterUsesMDL) || (this.flags & Flags.EmitterUsesTGA)) { stream.writeStringAttrib('Path', this.path); } stream.endBlock(); this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 288 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/particleemitter2.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; export const enum Flags { Unshaded = 0x8000, SortPrimsFarZ = 0x10000, LineEmitter = 0x20000, Unfogged = 0x40000, ModelSpace = 0x80000, XYQuad = 0x100000, } export const enum FilterMode { Blend = 0, Additive = 1, Modulate = 2, Modulate2x = 3, AlphaKey = 4, } export const enum HeadOrTail { Head = 0, Tail = 1, Both = 2, } /** * A particle emitter type 2. */ export default class ParticleEmitter2 extends GenericObject { speed = 0; variation = 0; latitude = 0; gravity = 0; lifeSpan = 0; emissionRate = 0; width = 0; length = 0; filterMode = FilterMode.Blend; rows = 0; columns = 0; headOrTail = HeadOrTail.Head; tailLength = 0; timeMiddle = 0; segmentColors: Float32Array[] = [new Float32Array(3), new Float32Array(3), new Float32Array(3)]; segmentAlphas = new Uint8Array(3); segmentScaling = new Float32Array(3); headIntervals: Uint32Array[] = [new Uint32Array(3), new Uint32Array(3)]; tailIntervals: Uint32Array[] = [new Uint32Array(3), new Uint32Array(3)]; textureId = -1; squirt = 0; priorityPlane = 0; replaceableId = 0; override readMdx(stream: BinaryStream): void { const start = stream.index; const size = stream.readUint32(); super.readMdx(stream); this.speed = stream.readFloat32(); this.variation = stream.readFloat32(); this.latitude = stream.readFloat32(); this.gravity = stream.readFloat32(); this.lifeSpan = stream.readFloat32(); this.emissionRate = stream.readFloat32(); this.width = stream.readFloat32(); this.length = stream.readFloat32(); this.filterMode = stream.readUint32(); this.rows = stream.readUint32(); this.columns = stream.readUint32(); this.headOrTail = stream.readUint32(); this.tailLength = stream.readFloat32(); this.timeMiddle = stream.readFloat32(); stream.readFloat32Array(this.segmentColors[0]); stream.readFloat32Array(this.segmentColors[1]); stream.readFloat32Array(this.segmentColors[2]); stream.readUint8Array(this.segmentAlphas); stream.readFloat32Array(this.segmentScaling); stream.readUint32Array(this.headIntervals[0]); stream.readUint32Array(this.headIntervals[1]); stream.readUint32Array(this.tailIntervals[0]); stream.readUint32Array(this.tailIntervals[1]); this.textureId = stream.readInt32(); this.squirt = stream.readUint32(); this.priorityPlane = stream.readInt32(); this.replaceableId = stream.readUint32(); this.readAnimations(stream, size - (stream.index - start)); } override writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); super.writeMdx(stream); stream.writeFloat32(this.speed); stream.writeFloat32(this.variation); stream.writeFloat32(this.latitude); stream.writeFloat32(this.gravity); stream.writeFloat32(this.lifeSpan); stream.writeFloat32(this.emissionRate); stream.writeFloat32(this.width); stream.writeFloat32(this.length); stream.writeUint32(this.filterMode); stream.writeUint32(this.rows); stream.writeUint32(this.columns); stream.writeUint32(this.headOrTail); stream.writeFloat32(this.tailLength); stream.writeFloat32(this.timeMiddle); stream.writeFloat32Array(this.segmentColors[0]); stream.writeFloat32Array(this.segmentColors[1]); stream.writeFloat32Array(this.segmentColors[2]); stream.writeUint8Array(this.segmentAlphas); stream.writeFloat32Array(this.segmentScaling); stream.writeUint32Array(this.headIntervals[0]); stream.writeUint32Array(this.headIntervals[1]); stream.writeUint32Array(this.tailIntervals[0]); stream.writeUint32Array(this.tailIntervals[1]); stream.writeInt32(this.textureId); stream.writeUint32(this.squirt); stream.writeInt32(this.priorityPlane); stream.writeUint32(this.replaceableId); this.writeNonGenericAnimationChunks(stream); } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'SortPrimsFarZ') { this.flags |= Flags.SortPrimsFarZ; } else if (token === 'Unshaded') { this.flags |= Flags.Unshaded; } else if (token === 'LineEmitter') { this.flags |= Flags.LineEmitter; } else if (token === 'Unfogged') { this.flags |= Flags.Unfogged; } else if (token === 'ModelSpace') { this.flags |= Flags.ModelSpace; } else if (token === 'XYQuad') { this.flags |= Flags.XYQuad; } else if (token === 'static Speed') { this.speed = stream.readFloat(); } else if (token === 'Speed') { this.readAnimation(stream, 'KP2S'); } else if (token === 'static Variation') { this.variation = stream.readFloat(); } else if (token === 'Variation') { this.readAnimation(stream, 'KP2R'); } else if (token === 'static Latitude') { this.latitude = stream.readFloat(); } else if (token === 'Latitude') { this.readAnimation(stream, 'KP2L'); } else if (token === 'static Gravity') { this.gravity = stream.readFloat(); } else if (token === 'Gravity') { this.readAnimation(stream, 'KP2G'); } else if (token === 'Visibility') { this.readAnimation(stream, 'KP2V'); } else if (token === 'Squirt') { this.squirt = 1; } else if (token === 'LifeSpan') { this.lifeSpan = stream.readFloat(); } else if (token === 'static EmissionRate') { this.emissionRate = stream.readFloat(); } else if (token === 'EmissionRate') { this.readAnimation(stream, 'KP2E'); } else if (token === 'static Width') { this.width = stream.readFloat(); } else if (token === 'Width') { this.readAnimation(stream, 'KP2N'); } else if (token === 'static Length') { this.length = stream.readFloat(); } else if (token === 'Length') { this.readAnimation(stream, 'KP2W'); } else if (token === 'Blend') { this.filterMode = FilterMode.Blend; } else if (token === 'Additive') { this.filterMode = FilterMode.Additive; } else if (token === 'Modulate') { this.filterMode = FilterMode.Modulate; } else if (token === 'Modulate2x') { this.filterMode = FilterMode.Modulate2x; } else if (token === 'AlphaKey') { this.filterMode = FilterMode.AlphaKey; } else if (token === 'Rows') { this.rows = stream.readInt(); } else if (token === 'Columns') { this.columns = stream.readInt(); } else if (token === 'Head') { this.headOrTail = HeadOrTail.Head; } else if (token === 'Tail') { this.headOrTail = HeadOrTail.Tail; } else if (token === 'Both') { this.headOrTail = HeadOrTail.Both; } else if (token === 'TailLength') { this.tailLength = stream.readFloat(); } else if (token === 'Time') { this.timeMiddle = stream.readFloat(); } else if (token === 'SegmentColor') { stream.read(); // { for (let i = 0; i < 3; i++) { stream.read(); // Color stream.readColor(this.segmentColors[i]); } stream.read(); // } } else if (token === 'Alpha') { stream.readVector(this.segmentAlphas); } else if (token === 'ParticleScaling') { stream.readVector(this.segmentScaling); } else if (token === 'LifeSpanUVAnim') { stream.readVector(this.headIntervals[0]); } else if (token === 'DecayUVAnim') { stream.readVector(this.headIntervals[1]); } else if (token === 'TailUVAnim') { stream.readVector(this.tailIntervals[0]); } else if (token === 'TailDecayUVAnim') { stream.readVector(this.tailIntervals[1]); } else if (token === 'TextureID') { this.textureId = stream.readInt(); } else if (token === 'ReplaceableId') { this.replaceableId = stream.readInt(); } else if (token === 'PriorityPlane') { this.priorityPlane = stream.readInt(); } else { throw new Error(`Unknown token in ParticleEmitter2: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('ParticleEmitter2', this.name); this.writeGenericHeader(stream); if (this.flags & Flags.SortPrimsFarZ) { stream.writeFlag('SortPrimsFarZ'); } if (this.flags & Flags.Unshaded) { stream.writeFlag('Unshaded'); } if (this.flags & Flags.LineEmitter) { stream.writeFlag('LineEmitter'); } if (this.flags & Flags.Unfogged) { stream.writeFlag('Unfogged'); } if (this.flags & Flags.ModelSpace) { stream.writeFlag('ModelSpace'); } if (this.flags & Flags.XYQuad) { stream.writeFlag('XYQuad'); } if (!this.writeAnimation(stream, 'KP2S')) { stream.writeNumberAttrib('static Speed', this.speed); } if (!this.writeAnimation(stream, 'KP2R')) { stream.writeNumberAttrib('static Variation', this.variation); } if (!this.writeAnimation(stream, 'KP2L')) { stream.writeNumberAttrib('static Latitude', this.latitude); } if (!this.writeAnimation(stream, 'KP2G')) { stream.writeNumberAttrib('static Gravity', this.gravity); } this.writeAnimation(stream, 'KP2V'); if (this.squirt) { stream.writeFlag('Squirt'); } stream.writeNumberAttrib('LifeSpan', this.lifeSpan); if (!this.writeAnimation(stream, 'KP2E')) { stream.writeNumberAttrib('static EmissionRate', this.emissionRate); } if (!this.writeAnimation(stream, 'KP2N')) { stream.writeNumberAttrib('static Width', this.width); } if (!this.writeAnimation(stream, 'KP2W')) { stream.writeNumberAttrib('static Length', this.length); } if (this.filterMode === FilterMode.Blend) { stream.writeFlag('Blend'); } else if (this.filterMode === FilterMode.Additive) { stream.writeFlag('Additive'); } else if (this.filterMode === FilterMode.Modulate) { stream.writeFlag('Modulate'); } else if (this.filterMode === FilterMode.Modulate2x) { stream.writeFlag('Modulate2x'); } else if (this.filterMode === FilterMode.AlphaKey) { stream.writeFlag('AlphaKey'); } stream.writeNumberAttrib('Rows', this.rows); stream.writeNumberAttrib('Columns', this.columns); if (this.headOrTail === HeadOrTail.Head) { stream.writeFlag('Head'); } else if (this.headOrTail === HeadOrTail.Tail) { stream.writeFlag('Tail'); } else if (this.headOrTail === HeadOrTail.Both) { stream.writeFlag('Both'); } stream.writeNumberAttrib('TailLength', this.tailLength); stream.writeNumberAttrib('Time', this.timeMiddle); stream.startBlock('SegmentColor'); stream.writeColor('Color', this.segmentColors[0]); stream.writeColor('Color', this.segmentColors[1]); stream.writeColor('Color', this.segmentColors[2]); stream.endBlockComma(); stream.writeVectorAttrib('Alpha', this.segmentAlphas); stream.writeVectorAttrib('ParticleScaling', this.segmentScaling); stream.writeVectorAttrib('LifeSpanUVAnim', this.headIntervals[0]); stream.writeVectorAttrib('DecayUVAnim', this.headIntervals[1]); stream.writeVectorAttrib('TailUVAnim', this.tailIntervals[0]); stream.writeVectorAttrib('TailDecayUVAnim', this.tailIntervals[1]); stream.writeNumberAttrib('TextureID', this.textureId); if (this.replaceableId !== 0) { stream.writeNumberAttrib('ReplaceableId', this.replaceableId); } if (this.priorityPlane !== 0) { stream.writeNumberAttrib('PriorityPlane', this.priorityPlane); } this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 175 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/particleemitterpopcorn.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; export const enum Flags { Unshaded = 0x8000, SortPrimsFarZ = 0x10000, Unfogged = 0x40000, } /** * A popcorn particle emitter. * References a pkfx file, which is used by the PopcornFX runtime. * * @since 900 */ export default class ParticleEmitterPopcorn extends GenericObject { lifeSpan = 0; emissionRate = 0; speed = 0; color = new Float32Array(3); alpha = 1; replaceableId = 0; path = ''; animationVisiblityGuide = ''; override readMdx(stream: BinaryStream): void { const start = stream.index; const size = stream.readUint32(); super.readMdx(stream); this.lifeSpan = stream.readFloat32(); this.emissionRate = stream.readFloat32(); this.speed = stream.readFloat32(); stream.readFloat32Array(this.color); this.alpha = stream.readFloat32(); this.replaceableId = stream.readUint32(); this.path = stream.read(260); this.animationVisiblityGuide = stream.read(260); this.readAnimations(stream, size - (stream.index - start)); } override writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); super.writeMdx(stream); stream.writeFloat32(this.lifeSpan); stream.writeFloat32(this.emissionRate); stream.writeFloat32(this.speed); stream.writeFloat32Array(this.color); stream.writeFloat32(this.alpha); stream.writeUint32(this.replaceableId); stream.skip(260 - stream.write(this.path)); stream.skip(260 - stream.write(this.animationVisiblityGuide)); this.writeNonGenericAnimationChunks(stream); } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'SortPrimsFarZ') { this.flags |= Flags.SortPrimsFarZ; } else if (token === 'Unshaded') { this.flags |= Flags.Unshaded; } else if (token === 'Unfogged') { this.flags |= Flags.Unfogged; } else if (token === 'static LifeSpan') { this.lifeSpan = stream.readFloat(); } else if (token === 'LifeSpan') { this.readAnimation(stream, 'KPPL'); } else if (token === 'static EmissionRate') { this.emissionRate = stream.readFloat(); } else if (token === 'EmissionRate') { this.readAnimation(stream, 'KPPE'); } else if (token === 'static Speed') { this.speed = stream.readFloat(); } else if (token === 'Speed') { this.readAnimation(stream, 'KPPS'); } else if (token === 'static Color') { stream.readVector(this.color); } else if (token === 'Color') { this.readAnimation(stream, 'KPPC'); } else if (token === 'static Alpha') { this.alpha = stream.readFloat(); } else if (token === 'Alpha') { this.readAnimation(stream, 'KPPA'); } else if (token === 'Visibility') { this.readAnimation(stream, 'KPPV'); } else if (token === 'ReplaceableId') { this.replaceableId = stream.readInt(); } else if (token === 'Path') { this.path = stream.read(); } else if (token === 'AnimVisibilityGuide') { this.animationVisiblityGuide = stream.read(); } else { throw new Error(`Unknown token in ParticleEmitterPopcorn: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('ParticleEmitterPopcorn', this.name); this.writeGenericHeader(stream); if (this.flags & Flags.SortPrimsFarZ) { stream.writeFlag('SortPrimsFarZ'); } if (this.flags & Flags.Unshaded) { stream.writeFlag('Unshaded'); } if (this.flags & Flags.Unfogged) { stream.writeFlag('Unfogged'); } if (!this.writeAnimation(stream, 'KPPL')) { stream.writeNumberAttrib('static LifeSpan', this.lifeSpan); } if (!this.writeAnimation(stream, 'KPPE')) { stream.writeNumberAttrib('static EmissionRate', this.emissionRate); } if (!this.writeAnimation(stream, 'KPPS')) { stream.writeNumberAttrib('static Speed', this.speed); } if (!this.writeAnimation(stream, 'KPPC')) { stream.writeVectorAttrib('static Color', this.color); } if (!this.writeAnimation(stream, 'KPPA')) { stream.writeNumberAttrib('static Alpha', this.alpha); } this.writeAnimation(stream, 'KPPV'); if (this.replaceableId !== 0) { stream.writeNumberAttrib('ReplaceableId', this.replaceableId); } if (this.path.length) { stream.writeStringAttrib('Path', this.path); } if (this.animationVisiblityGuide.length) { stream.writeStringAttrib('AnimVisibilityGuide', this.animationVisiblityGuide); } this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 556 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/ribbonemitter.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import GenericObject from './genericobject'; /** * A ribbon emitter. */ export default class RibbonEmitter extends GenericObject { heightAbove = 0; heightBelow = 0; alpha = 0; color = new Float32Array(3); lifeSpan = 0; textureSlot = 0; emissionRate = 0; rows = 0; columns = 0; materialId = 0; gravity = 0; constructor() { super(0x4000); } override readMdx(stream: BinaryStream): void { const start = stream.index; const size = stream.readUint32(); super.readMdx(stream); this.heightAbove = stream.readFloat32(); this.heightBelow = stream.readFloat32(); this.alpha = stream.readFloat32(); stream.readFloat32Array(this.color); this.lifeSpan = stream.readFloat32(); this.textureSlot = stream.readUint32(); this.emissionRate = stream.readUint32(); this.rows = stream.readUint32(); this.columns = stream.readUint32(); this.materialId = stream.readInt32(); this.gravity = stream.readFloat32(); this.readAnimations(stream, size - (stream.index - start)); } override writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); super.writeMdx(stream); stream.writeFloat32(this.heightAbove); stream.writeFloat32(this.heightBelow); stream.writeFloat32(this.alpha); stream.writeFloat32Array(this.color); stream.writeFloat32(this.lifeSpan); stream.writeUint32(this.textureSlot); stream.writeUint32(this.emissionRate); stream.writeUint32(this.rows); stream.writeUint32(this.columns); stream.writeInt32(this.materialId); stream.writeFloat32(this.gravity); this.writeNonGenericAnimationChunks(stream); } readMdl(stream: TokenStream): void { for (const token of super.readGenericBlock(stream)) { if (token === 'static HeightAbove') { this.heightAbove = stream.readFloat(); } else if (token === 'HeightAbove') { this.readAnimation(stream, 'KRHA'); } else if (token === 'static HeightBelow') { this.heightBelow = stream.readFloat(); } else if (token === 'HeightBelow') { this.readAnimation(stream, 'KRHB'); } else if (token === 'static Alpha') { this.alpha = stream.readFloat(); } else if (token === 'Alpha') { this.readAnimation(stream, 'KRAL'); } else if (token === 'static Color') { stream.readColor(this.color); } else if (token === 'Color') { this.readAnimation(stream, 'KRCO'); } else if (token === 'static TextureSlot') { this.textureSlot = stream.readInt(); } else if (token === 'TextureSlot') { this.readAnimation(stream, 'KRTX'); } else if (token === 'Visibility') { this.readAnimation(stream, 'KRVS'); } else if (token === 'EmissionRate') { this.emissionRate = stream.readInt(); } else if (token === 'LifeSpan') { this.lifeSpan = stream.readFloat(); } else if (token === 'Gravity') { this.gravity = stream.readFloat(); } else if (token === 'Rows') { this.rows = stream.readInt(); } else if (token === 'Columns') { this.columns = stream.readInt(); } else if (token === 'MaterialID') { this.materialId = stream.readInt(); } else { throw new Error(`Unknown token in RibbonEmitter: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('RibbonEmitter', this.name); this.writeGenericHeader(stream); if (!this.writeAnimation(stream, 'KRHA')) { stream.writeNumberAttrib('static HeightAbove', this.heightAbove); } if (!this.writeAnimation(stream, 'KRHB')) { stream.writeNumberAttrib('static HeightBelow', this.heightBelow); } if (!this.writeAnimation(stream, 'KRAL')) { stream.writeNumberAttrib('static Alpha', this.alpha); } if (!this.writeAnimation(stream, 'KRCO')) { stream.writeColor('static Color', this.color); } if (!this.writeAnimation(stream, 'KRTX')) { stream.writeNumberAttrib('static TextureSlot', this.textureSlot); } this.writeAnimation(stream, 'KRVS'); stream.writeNumberAttrib('EmissionRate', this.emissionRate); stream.writeNumberAttrib('LifeSpan', this.lifeSpan); if (this.gravity !== 0) { stream.writeNumberAttrib('Gravity', this.gravity); } stream.writeNumberAttrib('Rows', this.rows); stream.writeNumberAttrib('Columns', this.columns); stream.writeNumberAttrib('MaterialID', this.materialId); this.writeGenericAnimations(stream); stream.endBlock(); } override getByteLength(): number { return 56 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/sequence.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import Extent from './extent'; /** * A sequence. */ export default class Sequence { name = ''; interval = new Uint32Array(2); moveSpeed = 0; nonLooping = 0; rarity = 0; syncPoint = 0; extent = new Extent(); readMdx(stream: BinaryStream): void { this.name = stream.read(80); stream.readUint32Array(this.interval); this.moveSpeed = stream.readFloat32(); this.nonLooping = stream.readUint32(); this.rarity = stream.readFloat32(); this.syncPoint = stream.readUint32(); this.extent.readMdx(stream); } writeMdx(stream: BinaryStream): void { stream.skip(80 - stream.write(this.name)); stream.writeUint32Array(this.interval); stream.writeFloat32(this.moveSpeed); stream.writeUint32(this.nonLooping); stream.writeFloat32(this.rarity); stream.writeUint32(this.syncPoint); this.extent.writeMdx(stream); } readMdl(stream: TokenStream): void { this.name = stream.read(); for (const token of stream.readBlock()) { if (token === 'Interval') { stream.readVector(this.interval); } else if (token === 'NonLooping') { this.nonLooping = 1; } else if (token === 'MoveSpeed') { this.moveSpeed = stream.readFloat(); } else if (token === 'Rarity') { this.rarity = stream.readFloat(); } else if (token === 'MinimumExtent') { stream.readVector(this.extent.min); } else if (token === 'MaximumExtent') { stream.readVector(this.extent.max); } else if (token === 'BoundsRadius') { this.extent.boundsRadius = stream.readFloat(); } else { throw new Error(`Unknown token in Sequence: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startObjectBlock('Anim', this.name); stream.writeVectorAttrib('Interval', this.interval); if (this.nonLooping === 1) { stream.writeFlag('NonLooping'); } if (this.moveSpeed !== 0) { stream.writeNumberAttrib('MoveSpeed', this.moveSpeed); } if (this.rarity !== 0) { stream.writeNumberAttrib('Rarity', this.rarity); } this.extent.writeMdl(stream); stream.endBlock(); } } ================================================ FILE: src/parsers/mdlx/texture.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; export const enum WrapMode { RepeatBoth = 0, WrapWidth = 1, WrapHeight = 2, WrapBoth = 3, } /** * A texture. */ export default class Texture { replaceableId = 0; path = ''; wrapMode = WrapMode.RepeatBoth; readMdx(stream: BinaryStream): void { this.replaceableId = stream.readUint32(); this.path = stream.read(260); this.wrapMode = stream.readUint32(); } writeMdx(stream: BinaryStream): void { stream.writeUint32(this.replaceableId); stream.skip(260 - stream.write(this.path)); stream.writeUint32(this.wrapMode); } readMdl(stream: TokenStream): void { for (const token of stream.readBlock()) { if (token === 'Image') { this.path = stream.read(); } else if (token === 'ReplaceableId') { this.replaceableId = stream.readInt(); } else if (token === 'WrapWidth') { this.wrapMode |= WrapMode.WrapWidth; } else if (token === 'WrapHeight') { this.wrapMode |= WrapMode.WrapHeight; } else { throw new Error(`Unknown token in Texture: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startBlock('Bitmap'); if (this.path.length) { stream.writeStringAttrib('Image', this.path); } if (this.replaceableId !== 0) { stream.writeNumberAttrib('ReplaceableId', this.replaceableId); } if (this.wrapMode & WrapMode.WrapWidth) { stream.writeFlag(`WrapWidth`); } if (this.wrapMode & WrapMode.WrapHeight) { stream.writeFlag(`WrapHeight`); } stream.endBlock(); } } ================================================ FILE: src/parsers/mdlx/textureanimation.ts ================================================ import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import AnimatedObject from './animatedobject'; /** * A texture animation. */ export default class TextureAnimation extends AnimatedObject { readMdx(stream: BinaryStream): void { const size = stream.readUint32(); this.readAnimations(stream, size - 4); } writeMdx(stream: BinaryStream): void { stream.writeUint32(this.getByteLength()); this.writeAnimations(stream); } readMdl(stream: TokenStream): void { for (const token of stream.readBlock()) { if (token === 'Translation') { this.readAnimation(stream, 'KTAT'); } else if (token === 'Rotation') { this.readAnimation(stream, 'KTAR'); } else if (token === 'Scaling') { this.readAnimation(stream, 'KTAS'); } else { throw new Error(`Unknown token in TextureAnimation: "${token}"`); } } } writeMdl(stream: TokenStream): void { stream.startBlock('TVertexAnim '); this.writeAnimation(stream, 'KTAT'); this.writeAnimation(stream, 'KTAR'); this.writeAnimation(stream, 'KTAS'); stream.endBlock(); } override getByteLength(): number { return 4 + super.getByteLength(); } } ================================================ FILE: src/parsers/mdlx/tokenstream.ts ================================================ /** * Used to read and write MDL tokens. */ export default class TokenStream { buffer: string; index = 0; ident = 0; indentSpaces = 4; precision = 1000000; // 6 digits after the decimal point. constructor(buffer?: string) { this.buffer = buffer || ''; } /** * Clear the stream from whatever buffer it had. */ clear(): void { this.buffer = ''; this.index = 0; this.ident = 0; } /** * Reads the next token in the stream. * Whitespaces are ignored outside of strings in the form of "". * Comments in the form of // are ignored. * Commas and colons are ignored as well. * Curly braces are used as separators, generally to denote text blocks. * * For example, given the following string: * * Header "A String" { * Name Value, // A Comment * } * * Read will return the values in order: * * Header * "A String" * { * Name * Value * } * * There are wrappers around read, below, that help to read structured code, check them out! */ readToken(): string | undefined { const buffer = this.buffer; const length = buffer.length; let inComment = false; let inString = false; let token = ''; while (this.index < length) { const c = buffer[this.index++]; if (inComment) { if (c === '\n') { inComment = false; } } else if (inString) { if (c === '\\') { token += c + buffer[this.index++]; } else if (c === '\n') { token += '\\n'; } else if (c === '\r') { token += '\\r'; } else if (c === '"') { return token; } else { token += c; } } else if (c === ' ' || c === ',' || c === '\t' || c === '\n' || c === ':' || c === '\r') { if (token.length) { return token; } } else if (c === '{' || c === '}') { if (token.length) { this.index--; return token; } else { return c; } } else if (c === '/' && buffer[this.index] === '/') { if (token.length) { this.index--; return token; } else { inComment = true; } } else if (c === '"') { if (token.length) { this.index--; return token; } else { inString = true; } } else { token += c; } } return; } /** * Same as readToken, but if the end of the stream was encountered, an exception will be thrown. */ read(): string { const value = this.readToken(); if (value === undefined) { throw new Error('End of stream reached prematurely'); } return value; } /** * Reads the next token without advancing the stream. */ peek(): string { const index = this.index; const value = this.read(); this.index = index; return value; } /** * Reads the next token, and parses it as an integer. */ readInt(): number { return parseInt(this.read()); } /** * Reads the next token, and parses it as a float. */ readFloat(): number { return parseFloat(this.read()); } /** * { Number0, Number1, ..., NumberN } */ readVector(view: T): T { this.read(); // { for (let i = 0, l = view.length; i < l; i++) { view[i] = this.readFloat(); } this.read(); // } return view; } /** * { * { Value1, Value2, ..., ValueSize }, * { Value1, Value2, ..., ValueSize }, * ... * } */ readVectorsBlock(view: T, size: number): T { this.read(); // { for (let i = 0, l = view.length; i < l; i += size) { this.readVector(view.subarray(i, i + size)); } this.read(); // } return view; } /** * Reads a color in the form: * * { R, G, B } * * The color is sizzled to BGR. */ readColor(view: Float32Array): Float32Array { this.read(); // { view[2] = this.readFloat(); view[1] = this.readFloat(); view[0] = this.readFloat(); this.read(); // } return view; } /** * Helper generator for block reading. * Let's say we have a block like so: * * { * Key1 Value1 * Key2 Value2 * ... * KeyN ValueN * } * * The generator yields the keys one by one, and the caller needs to read the values based on the keys. * It is used for most MDL blocks. */ * readBlock(): Generator { this.read(); // { let token = this.read(); while (token !== '}') { yield token; token = this.read(); } } /** * Adds the given string to the buffer. * The current indentation level is prepended, and the stream goes to the next line after the write. */ writeLine(line: string): void { this.buffer += `${' '.repeat(this.ident * this.indentSpaces)}${line}\n`; } /** * Flag, */ writeFlag(flag: string): void { this.writeLine(`${flag},`); } /** * Name Flag, */ writeFlagAttrib(name: string, flag: string): void { this.writeLine(`${name} ${flag},`); } /** * Name Value, */ writeNumberAttrib(name: string, value: number): void { this.writeLine(`${name} ${this.floatDecimals(value)},`); } /** * Name "Value", */ writeStringAttrib(name: string, value: string): void { this.writeLine(`${name} "${value}",`); } /** * Name { Value0, Value1, ..., ValueN } */ writeVectorAttrib(name: string, value: Uint8Array | Uint32Array | Float32Array): void { this.writeLine(`${name} { ${this.floatArrayDecimals(value)} },`); } /** * Writes a color in the form: * * { B, G, R } * * The color is sizzled to RGB. * The name can be either "Color" or "static Color", depending on the context. */ writeColor(name: string, value: Float32Array): void { const b = this.floatDecimals(value[0]); const g = this.floatDecimals(value[1]); const r = this.floatDecimals(value[2]); this.writeLine(`${name} { ${r}, ${g}, ${b} },`); } /** * { Value0, Value1, ..., ValueN }, */ writeVector(value: Uint16Array | Float32Array): void { this.writeLine(`{ ${this.floatArrayDecimals(value)} },`); } /** * Name Vectors { * { Value1, Value2, ..., ValueSize }, * { Value1, Value2, ..., ValueSize }, * ... * } */ writeVectorArrayBlock(name: string, view: Float32Array, size: number): void { this.startBlock(name, view.length / size); for (let i = 0, l = view.length; i < l; i += size) { this.writeVector(view.subarray(i, i + size)); } this.endBlock(); } /** * Starts a new block in the form: * * Header1 Header2 ... HeaderN { * ... * } */ startBlock(name: string, ...headers: (string | number)[]): void { if (headers.length) { name = `${name} ${headers.join(' ')}`; } this.writeLine(`${name} {`); this.ident += 1; } /** * Starts a new block in the form: * * Header "Name" { * ... * } */ startObjectBlock(header: string, name: string): void { // Turns out you can have quotation marks in object names. this.writeLine(`${header} "${name.replace(/"/g, '\\"')}" {`); this.ident += 1; } /** * Ends a previously started block, and handles the indentation. */ endBlock(): void { this.ident -= 1; this.writeLine('}'); } /** * Ends a previously started block, and handles the indentation. * Adds a comma after the block end. */ endBlockComma(): void { this.ident -= 1; this.writeLine('},'); } /** * Increases the indentation level for following line writes. */ indent(): void { this.ident += 1; } /** * Decreases the indentation level for following line writes. */ unindent(): void { this.ident -= 1; } /** * Given a number, truncates digits after the decimal point. * The given precision should be in base 10. * E.g. for a precision of two digits after the decimal point, the precision should be 100. * The result is returned as a string. */ floatDecimals(value: number): string { return `${Math.trunc(value * this.precision) / this.precision}`; } /** * Uses floatDecimals on a typed array, and returns its string representation. */ floatArrayDecimals(value: Uint8Array | Uint16Array | Uint32Array | Float32Array): string { if (value instanceof Float32Array) { const array = []; for (let i = 0, l = value.length; i < l; i++) { array[i] = this.floatDecimals(value[i]); } return array.join(', '); } else { return value.join(', '); } } } ================================================ FILE: src/parsers/mdlx/unknownchunk.ts ================================================ import BinaryStream from '../../common/binarystream'; /** * An unknown chunk. */ export default class UnknownChunk { tag: string; chunk: Uint8Array; constructor(stream: BinaryStream, size: number, tag: string) { this.tag = tag; this.chunk = stream.readUint8Array(new Uint8Array(size)); } writeMdx(stream: BinaryStream): void { stream.writeBinary(this.tag); stream.writeUint32(this.chunk.byteLength); stream.writeUint8Array(this.chunk); } getByteLength(): number { return 8 + this.chunk.byteLength; } } ================================================ FILE: src/parsers/mpq/adpcm.ts ================================================ import BinaryStream from '../../common/binarystream'; const MAX_ADPCM_CHANNEL_COUNT = 2; const INITIAL_ADPCM_STEP_INDEX = 0x2C; const NextStepTable = new Int32Array([ -1, 0, -1, 4, -1, 2, -1, 6, -1, 1, -1, 5, -1, 3, -1, 7, -1, 1, -1, 5, -1, 3, -1, 7, -1, 2, -1, 4, -1, 6, -1, 8, ]); const StepSizeTable = new Int32Array([ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767, ]); function GetNextStepIndex(StepIndex: number, EncodedSample: number): number { StepIndex = StepIndex + NextStepTable[EncodedSample & 0x1F]; if (StepIndex < 0) { StepIndex = 0; } else if (StepIndex > 88) { StepIndex = 88; } return StepIndex; } function UpdatePredictedSample(PredictedSample: number, EncodedSample: number, Difference: number): number { if (EncodedSample & 0x40) { PredictedSample -= Difference; if (PredictedSample <= -32768) { PredictedSample = -32768; } } else { PredictedSample += Difference; if (PredictedSample >= 32767) { PredictedSample = 32767; } } return PredictedSample; } function DecodeSample(PredictedSample: number, EncodedSample: number, StepSize: number, Difference: number): number { if (EncodedSample & 0x01) { Difference += (StepSize >> 0); } if (EncodedSample & 0x02) { Difference += (StepSize >> 1); } if (EncodedSample & 0x04) { Difference += (StepSize >> 2); } if (EncodedSample & 0x08) { Difference += (StepSize >> 3); } if (EncodedSample & 0x10) { Difference += (StepSize >> 4); } if (EncodedSample & 0x20) { Difference += (StepSize >> 5); } return UpdatePredictedSample(PredictedSample, EncodedSample, Difference); } export default function DecompressADPCM(pvInBuffer: Uint8Array, ChannelCount: number): Uint8Array { const is = new BinaryStream(pvInBuffer); const os = []; let EncodedSample; const PredictedSamples = new Uint16Array(MAX_ADPCM_CHANNEL_COUNT); const StepIndexes = new Uint16Array([INITIAL_ADPCM_STEP_INDEX, INITIAL_ADPCM_STEP_INDEX]); let ChannelIndex; is.readUint8(); const BitShift = is.readUint8(); for (let i = 0; i < ChannelCount; i++) { const InitialSample = is.readUint16(); PredictedSamples[i] = InitialSample; os.push(InitialSample); } ChannelIndex = ChannelCount - 1; while (is.remaining) { EncodedSample = is.readUint8(); ChannelIndex = (ChannelIndex + 1) % ChannelCount; if (EncodedSample == 0x80) { if (StepIndexes[ChannelIndex] != 0) { StepIndexes[ChannelIndex]--; } os.push(PredictedSamples[ChannelIndex]); } else if (EncodedSample == 0x81) { StepIndexes[ChannelIndex] += 8; if (StepIndexes[ChannelIndex] > 0x58) { StepIndexes[ChannelIndex] = 0x58; } ChannelIndex = (ChannelIndex + 1) % ChannelCount; } else { const StepIndex = StepIndexes[ChannelIndex]; const StepSize = StepSizeTable[StepIndex]; PredictedSamples[ChannelIndex] = DecodeSample(PredictedSamples[ChannelIndex], EncodedSample, StepSize, StepSize >> BitShift); os.push(PredictedSamples[ChannelIndex]); StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndex, EncodedSample); } } return new Uint8Array(new Uint16Array(os).buffer); } ================================================ FILE: src/parsers/mpq/archive.ts ================================================ import { bytesOf } from '../../common/bytesof'; import { powerOfTwo } from '../../common/math'; import { numberToUint32 } from '../../common/typecast'; import MpqBlockTable from './blocktable'; import { HASH_ENTRY_DELETED, HASH_ENTRY_EMPTY, MAGIC } from './constants'; import MpqCrypto from './crypto'; import MpqFile from './file'; import MpqHashTable from './hashtable'; import { searchHeader } from './isarchive'; /** * MoPaQ archive (MPQ) version 0. */ export default class MpqArchive { headerOffset: number; sectorSize: number; c: MpqCrypto; hashTable: MpqHashTable; blockTable: MpqBlockTable; files: MpqFile[]; readonly = false; constructor() { this.headerOffset = 0; this.sectorSize = 4096; this.c = new MpqCrypto(); this.hashTable = new MpqHashTable(this.c); this.blockTable = new MpqBlockTable(this.c); this.files = []; } /** * Load an existing archive. * * Note that this clears the archive from whatever it had in it before. */ load(buffer: ArrayBuffer | Uint8Array, readonly = false): void { const bytes = bytesOf(buffer); this.readonly = readonly; // let fileSize = buffer.byteLength; const headerOffset = searchHeader(bytes); if (headerOffset === -1) { throw new Error('No MPQ header'); } // Read the header. const uint32array = new Uint32Array(bytes.buffer, headerOffset, 8); // let headerSize = uint32array[1]; // let archiveSize = uint32array[2]; const formatVersionSectorSize = uint32array[3]; // let formatVersion = formatVersionSectorSize & 0x0000FFFF; const hashPos = numberToUint32(uint32array[4] + headerOffset); // Whoever thought of MoonLight, clever! const blockPos = numberToUint32(uint32array[5] + headerOffset); const hashSize = uint32array[6]; let blockSize = uint32array[7]; // There can only be as many or less blocks as there are hashes. // Therefore, if the file is reporting too many blocks, cap the actual blocks read to the amount of hashes. if (blockSize > hashSize) { blockSize = hashSize; } this.headerOffset = headerOffset; this.sectorSize = 512 * (1 << (formatVersionSectorSize >>> 16)); // Generally 4096 // Read the hash table. // Also clears any existing entries. // Have to copy the data, because hashPos is not guaranteed to be a multiple of 4. this.hashTable.load(bytes.slice(hashPos, hashPos + hashSize * 16)); // Read the block table. // Also clears any existing entries. // Have to copy the data, because blockPos is not guaranteed to be a multiple of 4. this.blockTable.load(bytes.slice(blockPos, blockPos + blockSize * 16)); // Clear any existing files. this.files.length = 0; // Read the files. for (const hash of this.hashTable.entries) { const blockIndex = hash.blockIndex; // If the block index is valid, load a file. // This isn't the case when the block is marked as deleted with HASH_ENTRY_DELETED. // This also isn't the case for archives with fake block indices. if (blockIndex < this.blockTable.entries.length) { this.files[blockIndex] = new MpqFile(this, hash, this.blockTable.entries[blockIndex], bytes, null); } } // If there is a listfile, use all of the file names in it. const listfile = this.get('(listfile)'); if (listfile) { const list = listfile.text(); if (list) { for (const name of list.split('\r\n')) { // get() internally also sets the file's name to the given one. this.get(name); } } } } /** * Save this archive. * * Returns null when... * * 1) The archive is in readonly mode. * 2) The offset of a file encrypted with FILE_OFFSET_ADJUSTED_KEY changed, and the file name is unknown. */ save(): Uint8Array | null { if (this.readonly) { return null; } const headerSize = 32; // Delete the internal attributes file. // The attributes might (and do in the case of World Editor generated maps) contain CRC checksums for the internal files. // If any of these files is edited in any way, the map will be considered corrupted. // Therefore, delete the file, and nothing will be corrupted. // As far as I can tell, there is no real reason to keep (and update) any of the file attributes. // It's not like Warcraft 3 has some database of checksums that it checks against. // I assume it does have a database for the Battle.net ladder maps. // If at any point it becomes known to me that it is indeed needed, I will add support for (attributes). this.delete('(attributes)'); // Some archives have empty blocks in them. // That is, blocks that take up memory, but have no actual valid data in them (as far as the archive is concerned). // I am not sure why they exist - maybe someone deleted a file's entry and was too lazy to rebuild the archive. // This removes such blocks of memory from the archive. this.saveMemory(); // Set the listfile. this.set('(listfile)', this.getFileNames().join('\r\n')); // Reset the file offsets. let offset = headerSize; for (const file of this.files) { // There can be holes in the files array. if (file) { // If the file's offset changed, and it is encrypted with a key that depends on its offset, // it needs to be decryped with it's current key, and encryped with the new key. if (!file.offsetChanged(offset)) { return null; } // If the file needs to be encoded, do it. file.encode(); offset += file.block.compressedSize; } } const hashTable = this.hashTable; const blockTable = this.blockTable; const hashes = hashTable.entries.length; const blocks = blockTable.entries.length; const filesSize = offset - headerSize; const archiveSize = headerSize + filesSize + hashes * 16 + blocks * 16; const hashPos = headerSize + filesSize; const blockPos = hashPos + hashes * 16; const bytes = new Uint8Array(archiveSize); const uint32array = new Uint32Array(bytes.buffer, 0, 8); // Write the header. uint32array[0] = MAGIC; uint32array[1] = headerSize; uint32array[2] = archiveSize; uint32array[3] = Math.log2(this.sectorSize / 512) << 16; // The version is always 0, so ignore it. uint32array[4] = hashPos; uint32array[5] = blockPos; uint32array[6] = hashes; uint32array[7] = blocks; offset = headerSize; // Write the files. for (const file of this.files) { // There can be holes in the files array. if (file) { if (file.rawBuffer) { bytes.set(file.rawBuffer, offset); } offset += file.block.compressedSize; } } // Write the hash table. hashTable.save(bytes.subarray(offset, offset + hashTable.entries.length * 16)); offset += hashTable.entries.length * 16; // Write the block table. blockTable.save(bytes.subarray(offset, offset + blockTable.entries.length * 16)); return bytes; } /** * Some MPQs have empty memory chunks in them, left over from files that were deleted. * This function searches for such chunks, and removes them. * * Note that it is called automatically by save(). * * Does nothing if the archive is in readonly mode. */ saveMemory(): number { if (this.readonly) { return 0; } const blocks = this.blockTable.entries; const hashes = this.hashTable.entries; let i = blocks.length; let saved = 0; while (i--) { const block = blocks[i]; // Remove blocks with no data. if (block.normalSize === 0) { this.removeBlock(i); saved += block.compressedSize; } else { let used = false; for (const hash of hashes) { if (hash.blockIndex === i) { used = true; break; } } // Remove blocks that are not used. if (!used) { this.removeBlock(i); saved += block.compressedSize; } } } return saved; } removeBlock(blockIndex: number): void { for (const hash of this.hashTable.entries) { if (hash.blockIndex < HASH_ENTRY_DELETED && hash.blockIndex > blockIndex) { hash.blockIndex -= 1; } } this.blockTable.entries.splice(blockIndex, 1); } /** * Gets a list of the file names in the archive. * * Note that files loaded from an existing archive, without resolved names, will be named FileXXXXXXXX. */ getFileNames(): string[] { const names = []; for (const file of this.files) { if (file && file.name !== '') { names.push(file.name); } } return names; } /** * Count the files with unresolved names. */ countUnresolved(): number { let unresolved = 0; for (const file of this.files) { if (!file.nameResolved) { unresolved++; } } return unresolved; } /** * Given an iterable of file names, attempt to resolve the archive files with them. */ applyListfile(listfile: Iterable): void { for (const file of listfile) { this.get(file); } } /** * Adds a file to this archive. * If the file already exists, its buffer will be set. * * Does nothing if the archive is in readonly mode. */ set(name: string, buffer: ArrayBuffer | Uint8Array | string): boolean { if (this.readonly) { return false; } const bytes = bytesOf(buffer); let file = this.get(name); // If the file already exists, change the data. if (file) { file.set(bytes); } else { const blockIndex = this.blockTable.entries.length; const hash = this.hashTable.add(name, blockIndex); if (!hash) { return false; } const block = this.blockTable.add(bytes); file = new MpqFile(this, hash, block, null, bytes); file.name = name; file.nameResolved = true; this.files[blockIndex] = file; } return true; } /** * Gets a file from this archive. * If the file doesn't exist, null is returned. */ get(name: string): MpqFile | null { const hash = this.hashTable.get(name); if (hash) { const blockIndex = hash.blockIndex; // Check if the block exists. if (blockIndex < HASH_ENTRY_DELETED) { const file = this.files[blockIndex]; if (file) { // Save the name in case it wasn't already resolved. file.name = name; file.nameResolved = true; return file; } } } return null; } /** * Checks if a file exists. * * Prefer to use get() if you are going to use get() afterwards anyway. */ has(name: string): boolean { return !!this.get(name); } /** * Deletes a file from this archive. * * Does nothing if... * * 1) The archive is in readonly mode. * 2) The file does not exist. */ delete(name: string): boolean { if (this.readonly) { return false; } const file = this.get(name); if (!file) { return false; } file.delete(); return true; } /** * Renames a file. * * Does nothing if... * * 1) The archive is in readonly mode. * 2) The file does not exist. * * Note that this sets the current file's hash's status to being deleted, rather than removing it. * This is due to the way the search algorithm works. */ rename(name: string, newName: string): boolean { if (this.readonly) { return false; } const file = this.get(name); if (!file) { return false; } file.rename(newName); return true; } /** * Resizes the hashtable to the nearest power of two equal to or bigger than the given size. * * Generally speaking, the bigger the hashtable is, the quicker insertions/searches are, at the cost of added memory. * * Does nothing if... * * 1) The archive is in readonly mode. * 2) The calculated size is smaller than the amount of files in the archive. * 3) Not all of the file names in the archive are resolved. */ resizeHashtable(size: number): boolean { if (this.readonly) { return false; } size = Math.max(4, powerOfTwo(size)); const files = this.files; // Can't resize to a size smaller than the existing files. if (files.length > size) { return false; } // If not all file names are known, don't resize. // The insertion algorithm depends on the names. for (const file of files) { if (!file.nameResolved) { return false; } } const hashTable = this.hashTable; const entries = hashTable.entries; const oldEntries = entries.slice(); // Clear the entries. hashTable.clear(); // Add empty entries. hashTable.addEmpties(size); // Go over all of the old entries, and copy them into the new entries. for (const hash of oldEntries) { if (hash.blockIndex !== HASH_ENTRY_EMPTY) { const file = files[hash.blockIndex]; const insertionIndex = hashTable.getInsertionIndex(file.name); entries[insertionIndex].copy(hash); } } return true; } } ================================================ FILE: src/parsers/mpq/block.ts ================================================ /** * A block. */ export default class Block { offset = 0; compressedSize = 0; normalSize = 0; flags = 0; load(bytes: Uint32Array): void { this.offset = bytes[0]; this.compressedSize = bytes[1]; this.normalSize = bytes[2]; this.flags = bytes[3]; } save(bytes: Uint32Array): void { bytes[0] = this.offset; bytes[1] = this.compressedSize; bytes[2] = this.normalSize; bytes[3] = this.flags; } } ================================================ FILE: src/parsers/mpq/blocktable.ts ================================================ import MpqCrypto from './crypto'; import MpqBlock from './block'; import { BLOCK_TABLE_KEY } from './constants'; /** * A block table. */ export default class BlockTable { c: MpqCrypto; entries: MpqBlock[]; constructor(c: MpqCrypto) { this.c = c; this.entries = []; } add(buffer: ArrayBuffer): MpqBlock { const block = new MpqBlock(); block.normalSize = buffer.byteLength; this.entries.push(block); return block; } clear(): void { this.entries.length = 0; } addEmpties(howMany: number): void { for (let i = 0; i < howMany; i++) { this.entries.push(new MpqBlock()); } } load(bytes: Uint8Array): void { const entriesCount = bytes.byteLength / 16; const uint32array = new Uint32Array(this.c.decryptBlock(bytes, BLOCK_TABLE_KEY).buffer); let offset = 0; // Clear the table and add the needed empties. this.clear(); this.addEmpties(entriesCount); for (const block of this.entries) { block.load(uint32array.subarray(offset, offset + 4)); offset += 4; } } save(bytes: Uint8Array): void { const uint32array = new Uint32Array(this.entries.length * 4); let offset = 0; for (const block of this.entries) { block.save(uint32array.subarray(offset, offset + 4)); offset += 4; } const uint8array = new Uint8Array(uint32array.buffer); this.c.encryptBlock(uint8array, BLOCK_TABLE_KEY); bytes.set(uint8array); } } ================================================ FILE: src/parsers/mpq/constants.ts ================================================ export const MAGIC = 0x1A51504D; // MPQ\x1A reversed export const HASH_TABLE_KEY = 0xC3AF3770; // Hash of (hashtable) export const HASH_TABLE_INDEX = 0; export const HASH_NAME_A = 1; export const HASH_NAME_B = 2; export const HASH_FILE_KEY = 3; export const HASH_ENTRY_DELETED = 0xFFFFFFFE; export const HASH_ENTRY_EMPTY = 0xFFFFFFFF; export const BLOCK_TABLE_KEY = 0xEC83B3A3; // Hash of (blocktable) export const FILE_IMPLODE = 0x00000100; export const FILE_COMPRESSED = 0x00000200; export const FILE_ENCRYPTED = 0x00010000; export const FILE_OFFSET_ADJUSTED_KEY = 0x00020000; export const FILE_PATCH_FILE = 0x00100000; export const FILE_SINGLE_UNIT = 0x01000000; export const FILE_DELETE_MARKER = 0x02000000; export const FILE_SECTOR_CRC = 0x04000000; export const FILE_EXISTS = 0x80000000; export const COMPRESSION_HUFFMAN = 0x01; export const COMPRESSION_DEFLATE = 0x02; export const COMPRESSION_IMPLODE = 0x08; export const COMPRESSION_BZIP2 = 0x10; export const COMPRESSION_ADPCM_MONO = 0x40; export const COMPRESSION_ADPCM_STEREO = 0x80; ================================================ FILE: src/parsers/mpq/crypto.ts ================================================ import MpqBlock from './block'; import { HASH_FILE_KEY, FILE_OFFSET_ADJUSTED_KEY } from './constants'; // Global variables for this module. const bytesHeap = new Uint8Array(4); const longHeap = new Uint32Array(bytesHeap.buffer); /** * MPQ crypto. */ export default class MpqCrypto { cryptTable = new Uint32Array(0x500); constructor() { let seed = 0x00100001; let temp1 = 0; let temp2 = 0; for (let index1 = 0; index1 < 0x100; index1++) { for (let index2 = index1, i = 0; i < 5; i += 1, index2 += 0x100) { seed = (seed * 125 + 3) % 0x2AAAAB; temp1 = (seed & 0xFFFF) << 0x10; seed = (seed * 125 + 3) % 0x2AAAAB; temp2 = (seed & 0xFFFF); this.cryptTable[index2] = temp1 | temp2; } } } hash(name: string, key: number): number { const cryptTable = this.cryptTable; let seed1 = 0x7FED7FED; let seed2 = 0xEEEEEEEE; name = name.toUpperCase(); for (let i = 0; i < name.length; i++) { const ch = name.charCodeAt(i); seed1 = cryptTable[(key << 8) + ch] ^ (seed1 + seed2); seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3; } // Convert the seed to an unsigned integer return seed1 >>> 0; } decryptBlock(data: T, key: number): T { const cryptTable = this.cryptTable; let seed = 0xEEEEEEEE; const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); for (let i = 0, l = data.byteLength >>> 2; i < l; i++) { // Update the seed. seed += cryptTable[0x400 + (key & 0xFF)]; // Get 4 encrypted bytes. bytesHeap[0] = bytes[i * 4]; bytesHeap[1] = bytes[i * 4 + 1]; bytesHeap[2] = bytes[i * 4 + 2]; bytesHeap[3] = bytes[i * 4 + 3]; // Decrypted 32bit integer. longHeap[0] ^= (key + seed); // Update the seed. key = ((~key << 0x15) + 0x11111111) | (key >>> 0x0B); seed = longHeap[0] + seed + (seed << 5) + 3; // Set 4 decryped bytes. bytes[i * 4] = bytesHeap[0]; bytes[i * 4 + 1] = bytesHeap[1]; bytes[i * 4 + 2] = bytesHeap[2]; bytes[i * 4 + 3] = bytesHeap[3]; } return data; } encryptBlock(data: T, key: number): T { const cryptTable = this.cryptTable; let seed = 0xEEEEEEEE; const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); for (let i = 0, l = data.byteLength >>> 2; i < l; i++) { // Update the seed. seed += cryptTable[0x400 + (key & 0xFF)]; // Get 4 decrypted bytes. bytesHeap[0] = bytes[i * 4]; bytesHeap[1] = bytes[i * 4 + 1]; bytesHeap[2] = bytes[i * 4 + 2]; bytesHeap[3] = bytes[i * 4 + 3]; // Decrypted 32bit integer. const decrypted = longHeap[0]; // Encrypted 32bit integer. longHeap[0] ^= (key + seed); // Update the seed. key = ((~key << 0x15) + 0x11111111) | (key >>> 0x0B); seed = decrypted + seed + (seed << 5) + 3; // Set 4 encrypted bytes. bytes[i * 4] = bytesHeap[0]; bytes[i * 4 + 1] = bytesHeap[1]; bytes[i * 4 + 2] = bytesHeap[2]; bytes[i * 4 + 3] = bytesHeap[3]; } return data; } computeFileKey(name: string, block: MpqBlock): number { const sepIndex = name.lastIndexOf('\\'); const pathlessName = name.substring(sepIndex + 1); let encryptionKey = this.hash(pathlessName, HASH_FILE_KEY); if (block.flags & FILE_OFFSET_ADJUSTED_KEY) { encryptionKey = (encryptionKey + block.offset) ^ block.normalSize; } return encryptionKey; } } ================================================ FILE: src/parsers/mpq/explode.ts ================================================ // A near direct copy of Ladislav Zezula's C implementation. // I left the comments out - if you wish to understand the algorithm, please check the C implementation at https://github.com/ladislav-zezula/StormLib/tree/master/src/pklib // // There are three key differences: // 1) It takes in a Uint8Array, and returns a Uint8Array, rather than using abstract read/write functions. // 2) The tables are generated once the first time explode() is used. // I am not sure why the C implementation copies all of the data and regenerates the tables on every explode(). // Further more, I am not sure why they are generated at all, unlike the rest of data. // 3) There is no output circle buffer, the output is a normal JS number array that grows as it will, wrapped at the end with a Uint8Array. // It's simple, and I don't think anything else will perform better in JS either way. const CMP_BINARY = 0; const CMP_ASCII = 1; class TDcmpStruct { ctype = 0; outputPos = 0; dsize_bits = 0; dsize_mask = 0; bit_buff = 0; extra_bits = 0; in_pos = 0; in_buff: Uint8Array; out_buff: number[] = []; constructor(in_buff: Uint8Array) { this.in_buff = in_buff; } } const PKDCL_OK = 0; const PKDCL_STREAM_END = 1; const DistBits = new Uint8Array([ 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, ]); const DistCode = new Uint8Array([ 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00, ]); const ExLenBits = new Uint8Array([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ]); const LenBase = new Uint16Array([ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106, ]); const LenBits = new Uint8Array([ 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, ]); const LenCode = new Uint8Array([ 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00, ]); const ChBitsAsc = new Uint8Array([ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, ]); const ChCodeAsc = new Uint16Array([ 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000, ]); // Generated on the first time explode() is used. let generatedDecodeTabs = false; const DistPosCodes = new Uint8Array(0x100); const LengthCodes = new Uint8Array(0x100); // Same as above. let generatedAscTabs = false; const offs2C34 = new Uint8Array(0x100); const offs2D34 = new Uint8Array(0x100); const offs2E34 = new Uint8Array(0x80); const offs2EB4 = new Uint8Array(0x100); function GenDecodeTabs(positions: Uint8Array, start_indexes: Uint8Array, length_bits: Uint8Array): void { for (let i = 0, elements = start_indexes.length; i < elements; i++) { const length = 1 << length_bits[i]; for (let index = start_indexes[i]; index < 0x100; index += length) { positions[index] = i; } } } function GenAscTabs(): void { let pChCodeAsc = 0xFF; let acc, add; for (let count = 0x00FF; pChCodeAsc >= 0; pChCodeAsc--, count--) { const pChBitsAsc = count; let bits_asc = ChBitsAsc[pChBitsAsc]; if (bits_asc <= 8) { add = (1 << bits_asc); acc = ChCodeAsc[pChCodeAsc]; do { offs2C34[acc] = count; acc += add; } while (acc < 0x100); } else if ((acc = (ChCodeAsc[pChCodeAsc] & 0xFF)) != 0) { offs2C34[acc] = 0xFF; if (ChCodeAsc[pChCodeAsc] & 0x3F) { bits_asc -= 4; ChBitsAsc[pChBitsAsc] = bits_asc; add = (1 << bits_asc); acc = ChCodeAsc[pChCodeAsc] >> 4; do { offs2D34[acc] = count; acc += add; } while (acc < 0x100); } else { bits_asc -= 6; ChBitsAsc[pChBitsAsc] = bits_asc; add = (1 << bits_asc); acc = ChCodeAsc[pChCodeAsc] >> 6; do { offs2E34[acc] = count; acc += add; } while (acc < 0x80); } } else { bits_asc -= 8; ChBitsAsc[pChBitsAsc] = bits_asc; add = (1 << bits_asc); acc = ChCodeAsc[pChCodeAsc] >> 8; do { offs2EB4[acc] = count; acc += add; } while (acc < 0x100); } } } function WasteBits(pWork: TDcmpStruct, nBits: number): number { if (nBits <= pWork.extra_bits) { pWork.extra_bits -= nBits; pWork.bit_buff >>= nBits; return PKDCL_OK; } pWork.bit_buff >>= pWork.extra_bits; if (pWork.in_pos === pWork.in_buff.byteLength) { return PKDCL_STREAM_END; } pWork.bit_buff |= (pWork.in_buff[pWork.in_pos++] << 8); pWork.bit_buff >>= (nBits - pWork.extra_bits); pWork.extra_bits = (pWork.extra_bits - nBits) + 8; return PKDCL_OK; } function DecodeLit(pWork: TDcmpStruct): number { if (pWork.bit_buff & 1) { if (WasteBits(pWork, 1)) { return 0x306; } let length_code = LengthCodes[pWork.bit_buff & 0xFF]; if (WasteBits(pWork, LenBits[length_code])) { return 0x306; } let extra_length_bits; if ((extra_length_bits = ExLenBits[length_code]) != 0) { const extra_length = pWork.bit_buff & ((1 << extra_length_bits) - 1); if (WasteBits(pWork, extra_length_bits)) { if ((length_code + extra_length) != 0x10E) { return 0x306; } } length_code = LenBase[length_code] + extra_length; } return length_code + 0x100; } if (WasteBits(pWork, 1)) { return 0x306; } if (pWork.ctype == CMP_BINARY) { const uncompressed_byte = pWork.bit_buff & 0xFF; if (WasteBits(pWork, 8)) { return 0x306; } return uncompressed_byte; } let value; if (pWork.bit_buff & 0xFF) { value = offs2C34[pWork.bit_buff & 0xFF]; if (value == 0xFF) { if (pWork.bit_buff & 0x3F) { if (WasteBits(pWork, 4)) { return 0x306; } value = offs2D34[pWork.bit_buff & 0xFF]; } else { if (WasteBits(pWork, 6)) { return 0x306; } value = offs2E34[pWork.bit_buff & 0x7F]; } } } else { if (WasteBits(pWork, 8)) { return 0x306; } value = offs2EB4[pWork.bit_buff & 0xFF]; } return WasteBits(pWork, ChBitsAsc[value]) ? 0x306 : value; } function DecodeDist(pWork: TDcmpStruct, rep_length: number): number { const dist_pos_code = DistPosCodes[pWork.bit_buff & 0xFF]; const dist_pos_bits = DistBits[dist_pos_code]; if (WasteBits(pWork, dist_pos_bits)) { return 0; } let distance; if (rep_length == 2) { distance = (dist_pos_code << 2) | (pWork.bit_buff & 0x03); if (WasteBits(pWork, 2)) { return 0; } } else { distance = (dist_pos_code << pWork.dsize_bits) | (pWork.bit_buff & pWork.dsize_mask); if (WasteBits(pWork, pWork.dsize_bits)) { return 0; } } return distance + 1; } function Expand(pWork: TDcmpStruct): number { let next_literal; while ((next_literal = DecodeLit(pWork)) < 0x305) { if (next_literal >= 0x100) { let rep_length = next_literal - 0xFE; let minus_dist; if ((minus_dist = DecodeDist(pWork, rep_length)) == 0) { return 0x306; } let target = pWork.outputPos; let source = target - minus_dist; pWork.outputPos += rep_length; while (rep_length-- > 0) { pWork.out_buff[target++] = pWork.out_buff[source++]; } } else { pWork.out_buff[pWork.outputPos++] = next_literal; } } return next_literal; } export default function explode(bytes: Uint8Array): Uint8Array { const pWork = new TDcmpStruct(bytes); if (pWork.in_buff.byteLength <= 4) { throw new Error('Bad data'); } pWork.ctype = pWork.in_buff[0]; pWork.dsize_bits = pWork.in_buff[1]; pWork.bit_buff = pWork.in_buff[2]; pWork.extra_bits = 0; pWork.in_pos = 3; if (4 > pWork.dsize_bits || pWork.dsize_bits > 6) { throw new Error('Invalid dictionary size'); } pWork.dsize_mask = 0xFFFF >> (0x10 - pWork.dsize_bits); if (pWork.ctype !== CMP_BINARY) { if (pWork.ctype !== CMP_ASCII) { throw new Error('Invalid mode'); } if (!generatedAscTabs) { GenAscTabs(); generatedAscTabs = true; } } if (!generatedDecodeTabs) { GenDecodeTabs(LengthCodes, LenCode, LenBits); GenDecodeTabs(DistPosCodes, DistCode, DistBits); generatedDecodeTabs = true; } if (Expand(pWork) === 0x306) { throw new Error('Error while expanding'); } return new Uint8Array(pWork.out_buff); } ================================================ FILE: src/parsers/mpq/file.ts ================================================ import { deflate, inflate } from 'pako'; import { decodeUtf8 } from '../../common/utf8'; import MpqArchive from './archive'; import MpqBlock from './block'; import { COMPRESSION_ADPCM_MONO, COMPRESSION_ADPCM_STEREO, COMPRESSION_BZIP2, COMPRESSION_DEFLATE, COMPRESSION_HUFFMAN, COMPRESSION_IMPLODE, FILE_COMPRESSED, FILE_ENCRYPTED, FILE_EXISTS, FILE_IMPLODE, FILE_OFFSET_ADJUSTED_KEY, FILE_SINGLE_UNIT, HASH_ENTRY_DELETED } from './constants'; import MpqCrypto from './crypto'; import explode from './explode'; // import decodeHuffman from './huffman'; import MpqHash from './hash'; import { isArchive } from './isarchive'; /** * A MPQ file. */ export default class MpqFile { archive: MpqArchive; c: MpqCrypto; name: string; nameResolved: boolean; hash: MpqHash; block: MpqBlock; rawBuffer: Uint8Array | null = null; buffer: Uint8Array | null = null; constructor(archive: MpqArchive, hash: MpqHash, block: MpqBlock, rawBuffer: Uint8Array | null, buffer: Uint8Array | null) { const headerOffset = archive.headerOffset; this.archive = archive; this.c = archive.c; this.name = `File${`${hash.blockIndex}`.padStart(8, '0')}`; this.nameResolved = false; this.hash = hash; this.block = block; if (rawBuffer) { this.rawBuffer = rawBuffer.slice(headerOffset + block.offset, headerOffset + block.offset + block.compressedSize); } if (buffer) { this.buffer = buffer; } } /** * Gets this file's data as a Uint8Array. * * An exception will be thrown if the file needs to be decoded, and decoding fails. */ bytes(): Uint8Array { // Decode if needed if (this.buffer === null) { this.decode(); } // If decoding failed, an exception would have been thrown, so buffer is known to exist at this point. return this.buffer; } /** * Gets this file's data as an ArrayBuffer. * * An exception will be thrown if the file needs to be decoded, and decoding fails. */ arrayBuffer(): ArrayBuffer { return this.bytes().buffer; } /** * Gets this file's data as a UTF8 string. * * An exception will be thrown if the file needs to be decoded, and decoding fails. */ text(): string { return decodeUtf8(this.bytes()); } /** * Changes the buffer of this file. * * Does nothing if the archive is in readonly mode. */ set(buffer: Uint8Array): boolean { if (this.archive.readonly) { return false; } const hash = this.hash; const block = this.block; // Reset the hash. hash.locale = 0; hash.platform = 0; // Reset the block. block.compressedSize = 0; block.normalSize = buffer.byteLength; block.flags = 0; this.buffer = buffer; this.rawBuffer = null; return true; } /** * Deletes this file. * * Using the file after it was deleted will result in undefined behavior. * * Does nothing if the archive is in readonly mode. */ delete(): boolean { if (this.archive.readonly) { return false; } const archive = this.archive; const hash = this.hash; const blockIndex = hash.blockIndex; hash.delete(); for (const hash of archive.hashTable.entries) { if (hash.blockIndex < HASH_ENTRY_DELETED && hash.blockIndex > blockIndex) { hash.blockIndex -= 1; } } archive.blockTable.entries.splice(blockIndex, 1); archive.files.splice(blockIndex, 1); return true; } /** * Renames this file. * * Note that this sets the current file's hash's status to being deleted, rather than removing it. * This is due to the way the search algorithm works. * * Does nothing if the archive is in readonly mode. */ rename(newName: string): boolean { if (this.archive.readonly) { return false; } const hash = this.hash; const locale = hash.locale; const platform = hash.platform; const blockIndex = hash.blockIndex; // First delete the current hash. // This will allow its entry to be reused in case it's the only empty/deleted entry in the hashtable. hash.delete(); const newHash = this.archive.hashTable.add(newName, blockIndex); newHash.locale = locale; newHash.platform = platform; this.name = newName; this.nameResolved = true; this.hash = newHash; return true; } /** * Decode this file. */ decode(): void { if (!this.rawBuffer) { throw new Error(`File ${this.name}: Nothing to decode`); } const archive = this.archive; const block = this.block; const c = archive.c; const encryptionKey = c.computeFileKey(this.name, block); const data = this.rawBuffer; const flags = block.flags; // One buffer of raw data. // I don't know why having no flags means it's a chunk of memory rather than sectors. // After all, there is no flag to say there are indeed sectors. if (flags === FILE_EXISTS) { this.buffer = data.slice(0, block.normalSize); } else if (flags & FILE_SINGLE_UNIT) { // One buffer of possibly encrypted and/or compressed data. // Read the sector let sector; // If this block is encrypted, decrypt the sector. if (flags & FILE_ENCRYPTED) { sector = c.decryptBlock(data.slice(0, block.compressedSize), encryptionKey); } else { sector = data.subarray(0, block.compressedSize); } // If this block is compressed, decompress the sector. // Otherwise, copy the sector as-is. if (flags & FILE_COMPRESSED) { sector = this.decompressSector(sector, block.normalSize); } else { sector = sector.slice(); } this.buffer = sector; } else { // One or more sectors of possibly encrypted and/or compressed data. const sectorCount = Math.ceil(block.normalSize / archive.sectorSize); // Alocate a buffer for the uncompressed block size const buffer = new Uint8Array(block.normalSize); // Get the sector offsets let sectorOffsets = new Uint32Array(data.buffer, 0, sectorCount + 1); // If this file is encrypted, copy the sector offsets and decrypt them. if (flags & FILE_ENCRYPTED) { sectorOffsets = c.decryptBlock(sectorOffsets.slice(), encryptionKey - 1); } let start = sectorOffsets[0]; let end = sectorOffsets[1]; let offset = 0; for (let i = 0; i < sectorCount; i++) { let sector; // If this file is encrypted, copy the sector and decrypt it. // Otherwise a view can be used directly. if (flags & FILE_ENCRYPTED) { sector = c.decryptBlock(data.slice(start, end), encryptionKey + i); } else { sector = data.subarray(start, end); } // Decompress the sector if (flags & FILE_COMPRESSED) { let uncompressedSize = archive.sectorSize; // If this is the last sector, its uncompressed size might not be the size of a sector. if (block.normalSize - offset < uncompressedSize) { uncompressedSize = block.normalSize - offset; } sector = this.decompressSector(sector, uncompressedSize); } // Some sectors have this flags instead of the compression flag + algorithm byte. if (flags & FILE_IMPLODE) { sector = explode(sector); } // Add the sector bytes to the buffer buffer.set(sector, offset); offset += sector.byteLength; // Prepare for the next sector if (i < sectorCount) { start = end; end = sectorOffsets[i + 2]; } } this.buffer = buffer; } // If the archive is in read-only mode, the raw buffer isn't needed anymore, so free the memory. if (archive.readonly) { this.rawBuffer = null; } } decompressSector(bytes: Uint8Array, decompressedSize: number): Uint8Array { // If the size of the data is the same as its decompressed size, it's not compressed. if (bytes.byteLength === decompressedSize) { return bytes; } else { const compressionMask = bytes[0]; if (compressionMask & COMPRESSION_BZIP2) { throw new Error(`File ${this.name}: compression type 'bzip2' not supported`); } if (compressionMask & COMPRESSION_IMPLODE) { try { bytes = explode(bytes.subarray(1)); } catch (e) { throw new Error(`File ${this.name}: failed to decompress with 'explode': ${e}`); } } if (compressionMask & COMPRESSION_DEFLATE) { try { bytes = inflate(bytes.subarray(1)); } catch (e) { throw new Error(`File ${this.name}: failed to decompress with 'zlib': ${e}`); } } if (compressionMask & COMPRESSION_HUFFMAN) { // try { // bytes = decodeHuffman(bytes.subarray(1)); // } catch (e) { // throw new Error(`File ${this.name}: failed to decompress with 'huffman': ${e}`); // } throw new Error(`File ${this.name}: compression type 'huffman' not supported`); } if (compressionMask & COMPRESSION_ADPCM_STEREO) { throw new Error(`File ${this.name}: compression type 'adpcm stereo' not supported`); } if (compressionMask & COMPRESSION_ADPCM_MONO) { throw new Error(`File ${this.name}: compression type 'adpcm mono' not supported`); } return bytes; } } /** * Encode this file. * Archives (maps or generic MPQs) are stored uncompressed in one chunk. * Other files are always stored in sectors, except when a file is smaller than a sector. * Sectors themselves are always compressed, except when the result is smaller than the uncompressed data. */ encode(): void { if (this.buffer !== null && this.rawBuffer === null) { const data = this.buffer; if (isArchive(data)) { this.rawBuffer = this.buffer; this.block.compressedSize = this.buffer.byteLength; this.block.flags = FILE_EXISTS; } else { const sectorSize = this.archive.sectorSize; const sectorCount = Math.ceil(data.byteLength / sectorSize); const offsets = new Uint32Array(sectorCount + 1); let offset = offsets.byteLength; const sectors = []; const compression = []; // First offset is right after the offsets list. offsets[0] = offset; for (let i = 0; i < sectorCount; i++) { const sectorOffset = i * sectorSize; let sector = data.subarray(sectorOffset, sectorOffset + sectorSize); let size = sector.byteLength; const compressed = deflate(sector); let isCompressed = false; // If the compressed size of the sector is smaller than the uncompressed, use the compressed data. // +1 because of the compression mask byte. if (compressed.byteLength + 1 < size) { sector = compressed; size = compressed.byteLength + 1; isCompressed = true; } offset += size; offsets[i + 1] = offset; sectors[i] = sector; compression[i] = isCompressed; } // Only use the compressed data if it's actually smaller than the uncompressed data. if (offset < data.byteLength) { const rawBuffer = new Uint8Array(offset); // Write the offsets list. rawBuffer.set(new Uint8Array(offsets.buffer)); offset = offsets.byteLength; for (let i = 0; i < sectorCount; i++) { // If this sector is compressed, set it to zlib. if (compression[i]) { rawBuffer[offset] = 2; offset += 1; } // Write the sector. const sector = sectors[i]; rawBuffer.set(sector, offset); offset += sector.byteLength; } this.rawBuffer = rawBuffer; this.block.compressedSize = rawBuffer.byteLength; this.block.flags = (FILE_EXISTS | FILE_COMPRESSED) >>> 0; } else { this.rawBuffer = this.buffer; this.block.compressedSize = this.buffer.byteLength; this.block.flags = FILE_EXISTS; } } } } /** * Decrypt this file and encrypt it back, with a new offset in the archive. * This is used for files that use FILE_OFFSET_ADJUSTED_KEY, which are encrypted with a key that depends on their offset. */ reEncrypt(offset: number): boolean { if (!this.rawBuffer) { return false; } const archive = this.archive; const block = this.block; const c = archive.c; const bytes = this.rawBuffer; const flags = block.flags; const encryptionKey = c.computeFileKey(this.name, block); block.offset = offset; const newEncryptionKey = c.computeFileKey(this.name, block); if (flags & FILE_SINGLE_UNIT) { // Decrypt the chunk with the old key. c.decryptBlock(bytes, encryptionKey); // Encrypt the chunk with the new key. c.encryptBlock(bytes, newEncryptionKey); } else { const sectorCount = Math.ceil(block.normalSize / archive.sectorSize); // Get the sector offsets const sectorOffsets = new Uint32Array(bytes.buffer, 0, sectorCount + 1); // Decrypt the sector offsets with the old key. c.decryptBlock(sectorOffsets, encryptionKey - 1); let start = sectorOffsets[0]; let end = sectorOffsets[1]; for (let i = 0; i < sectorCount; i++) { const sector = bytes.subarray(start, end); // Decrypt the chunk with the old key. c.decryptBlock(sector, encryptionKey + i); // Encrypt the chunk with the new key. c.encryptBlock(sector, newEncryptionKey + i); // Prepare for the next sector if (i < sectorCount) { start = end; end = sectorOffsets[i + 2]; } } // Encrypt the sector offsets with the new key. c.encryptBlock(sectorOffsets, newEncryptionKey - 1); } return true; } /** * The offset of the file has been recalculated. * If the offset is different, and this file uses FILE_OFFSET_ADJUSTED_KEY encryption, it must be re-encrypted with the new offset. */ offsetChanged(offset: number): boolean { const block = this.block; if (block.offset !== offset && block.flags & FILE_OFFSET_ADJUSTED_KEY) { if (this.nameResolved) { return this.reEncrypt(offset); } return false; } block.offset = offset; return true; } } ================================================ FILE: src/parsers/mpq/hash.ts ================================================ import { HASH_ENTRY_DELETED, HASH_ENTRY_EMPTY } from './constants'; /** * A MPQ hash. */ export default class MpqHash { nameA = 0xFFFFFFFF; nameB = 0xFFFFFFFF; locale = 0xFFFF; platform = 0xFFFF; blockIndex = HASH_ENTRY_EMPTY; load(bytes: Uint32Array): void { const localePlatform = bytes[2]; this.nameA = bytes[0]; this.nameB = bytes[1]; this.locale = localePlatform & 0x0000FFFF; this.platform = localePlatform >>> 16; this.blockIndex = bytes[3]; } copy(hash: MpqHash): void { this.nameA = hash.nameA; this.nameB = hash.nameB; this.locale = hash.locale; this.platform = hash.platform; this.blockIndex = hash.blockIndex; } save(bytes: Uint32Array): void { bytes[0] = this.nameA; bytes[1] = this.nameB; bytes[2] = (this.locale << 16) | this.platform; bytes[3] = this.blockIndex; } delete(): void { this.nameA = 0xFFFFFFFF; this.nameB = 0xFFFFFFFF; this.locale = 0xFFFF; this.platform = 0xFFFF; this.blockIndex = HASH_ENTRY_DELETED; } } ================================================ FILE: src/parsers/mpq/hashtable.ts ================================================ import MpqCrypto from './crypto'; import MpqHash from './hash'; import { HASH_TABLE_KEY, HASH_TABLE_INDEX, HASH_NAME_A, HASH_NAME_B } from './constants'; /** * A MPQ hash table. */ export default class MpqHashTable { c: MpqCrypto; entries: MpqHash[]; constructor(c: MpqCrypto) { this.c = c; this.entries = []; // Minimum size this.addEmpties(4); } clear(): void { this.entries.length = 0; } addEmpties(howMany: number): void { for (let i = 0; i < howMany; i++) { this.entries.push(new MpqHash()); } } getInsertionIndex(name: string): number { const entries = this.entries; const offset = this.c.hash(name, HASH_TABLE_INDEX) & (entries.length - 1); for (let i = 0, l = entries.length; i < l; i++) { const index = (i + offset) % l; const hash = entries[index]; if (hash.platform === 0xFFFF) { return index; } } return -1; } add(name: string, blockIndex: number): MpqHash | undefined { const insertionIndex = this.getInsertionIndex(name); if (insertionIndex !== -1) { const hash = this.entries[insertionIndex]; hash.nameA = this.c.hash(name, HASH_NAME_A); hash.nameB = this.c.hash(name, HASH_NAME_B); hash.locale = 0; hash.platform = 0; hash.blockIndex = blockIndex; return hash; } return; } load(bytes: Uint8Array): void { const entriesCount = bytes.byteLength / 16; const uint32array = new Uint32Array(this.c.decryptBlock(bytes, HASH_TABLE_KEY).buffer); let offset = 0; // Clear the table and add the needed empties. this.clear(); this.addEmpties(entriesCount); for (const hash of this.entries) { hash.load(uint32array.subarray(offset, offset + 4)); offset += 4; } } save(bytes: Uint8Array): void { const uint32array = new Uint32Array(this.entries.length * 4); let offset = 0; for (const hash of this.entries) { hash.save(uint32array.subarray(offset, offset + 4)); offset += 4; } const uint8array = new Uint8Array(uint32array.buffer); this.c.encryptBlock(uint8array, HASH_TABLE_KEY); bytes.set(uint8array); } get(name: string): MpqHash | null { const c = this.c; const entries = this.entries; const offset = c.hash(name, HASH_TABLE_INDEX) & (entries.length - 1); const nameA = c.hash(name, HASH_NAME_A); const nameB = c.hash(name, HASH_NAME_B); for (let i = 0, l = entries.length; i < l; i++) { const hash = entries[(i + offset) % l]; if (nameA === hash.nameA && nameB === hash.nameB) { return hash; } else if (hash.blockIndex === 0xFFFFFFFF) { return null; } } return null; } } ================================================ FILE: src/parsers/mpq/index.ts ================================================ import Archive from './archive'; import Crypto from './crypto'; import HashTable from './hashtable'; import Hash from './hash'; import BlockTable from './blocktable'; import Block from './block'; import File from './file'; import { isArchive } from './isarchive'; export default { Archive, Crypto, HashTable, Hash, BlockTable, Block, File, isArchive, }; ================================================ FILE: src/parsers/mpq/isarchive.ts ================================================ /** * Search for the MPQ header - MPQ\x1A. * The header can be on any 512 bytes boundry offset. */ export function searchHeader(bytes: Uint8Array): number { let offset = -1; for (let i = 0, l = Math.ceil(bytes.byteLength / 512); i < l; i++) { const base = i * 512; // Test 'MPQ\x1A'. if (bytes[base] === 77 && bytes[base + 1] === 80 && bytes[base + 2] === 81 && bytes[base + 3] === 26) { offset = base; } } return offset; } /** * Checks whether the given buffer is either a Warcraft 3 map or otherwise a generic MPQ archive. */ export function isArchive(bytes: Uint8Array): boolean { // Check for the map identifier - HM3W if (bytes[0] === 72 && bytes[1] === 77 && bytes[2] === 51 && bytes[3] === 87) { return true; } // Look for an MPQ header. return searchHeader(bytes) !== -1; } ================================================ FILE: src/parsers/slk/file.ts ================================================ /** * A SLK table file. */ export default class SlkFile { rows: string[][] = []; load(buffer: string): void { if (!buffer.startsWith('ID')) { throw new Error('WrongMagicNumber'); } const rows = this.rows; let x = 0; let y = 0; for (const line of buffer.split('\n')) { // The B command is supposed to define the total number of columns and rows, however in UbetSplatData.slk it gives wrong information // Therefore, just ignore it, since JavaScript arrays grow as they want either way if (line[0] !== 'B') { for (const token of line.split(';')) { const op = token[0]; const valueString = token.substring(1).trim(); let value; if (op === 'X') { x = parseInt(valueString, 10) - 1; } else if (op === 'Y') { y = parseInt(valueString, 10) - 1; } else if (op === 'K') { if (!rows[y]) { rows[y] = []; } if (valueString[0] === '"') { value = valueString.slice(1, -1); } else { value = valueString; } rows[y][x] = value; } } } } } save(): string { const rows = this.rows; const rowCount = rows.length; const lines = []; let biggestColumn = 0; for (let y = 0; y < rowCount; y++) { const row = rows[y]; const columnCount = row.length; if (columnCount > biggestColumn) { biggestColumn = columnCount; } let firstOfRow = true; for (let x = 0; x < columnCount; x++) { const value = row[x]; if (value !== undefined) { let encoded; if (typeof value === 'string') { encoded = `"${value}"`; } else if (typeof value === 'boolean') { if (value) { encoded = 'TRUE'; } else { encoded = 'FALSE'; } } else { encoded = `${value}`; } if (firstOfRow) { firstOfRow = false; lines.push(`C;X${x + 1};Y${y + 1};K${encoded}`); } else { lines.push(`C;X${x + 1};K${encoded}`); } } } } return `ID;P\r\nB;X${biggestColumn};Y${rowCount}\r\n${lines.join('\r\n')}\r\nE`; } } ================================================ FILE: src/parsers/slk/index.ts ================================================ import File from './file'; export default { File, }; ================================================ FILE: src/parsers/tga/image.ts ================================================ import TgaLoader from 'tga-js'; import { bytesOf } from '../../common/bytesof'; /** * A TGA image. */ export default class TgaImage { width = 0; height = 0; data: ImageData | null = null; load(buffer: ArrayBuffer | Uint8Array): void { const bytes = bytesOf(buffer); const tga = new TgaLoader(); tga.load(bytes); const header = tga.header; this.width = header.width; this.height = header.height; this.data = new ImageData(header.width, header.height); tga.getImageData(this.data); } } ================================================ FILE: src/parsers/tga/index.ts ================================================ import Image from './image'; import isTga from './isformat'; export default { Image, isTga, }; ================================================ FILE: src/parsers/tga/isformat.ts ================================================ import { isStringInBytes } from '../../common/searches'; /** * Detects if the given object is a TGA source. */ export default function isTga(bytes: unknown): boolean { if (bytes instanceof ArrayBuffer) { bytes = new Uint8Array(bytes); } if (bytes instanceof Uint8Array && isStringInBytes(bytes, 'TRUEVISION-XFILE.\0', bytes.length - 18)) { return true; } return false; } ================================================ FILE: src/parsers/w3x/doo/doodad.ts ================================================ import BinaryStream from '../../../common/binarystream'; import RandomItemSet from './randomitemset'; /** * A doodad. */ export default class Doodad { id = '\0\0\0\0'; variation = 0; location = new Float32Array(3); angle = 0; scale = new Float32Array([1, 1, 1]); /** * @since Game version 1.32 */ skin = '\0\0\0\0'; flags = 0; life = 0; itemTable = -1; itemSets: RandomItemSet[] = []; editorId = 0; u1 = new Uint8Array(8); load(stream: BinaryStream, version: number, buildVersion: number): void { this.id = stream.readBinary(4); this.variation = stream.readInt32(); stream.readFloat32Array(this.location); this.angle = stream.readFloat32(); stream.readFloat32Array(this.scale); if (buildVersion > 131) { this.skin = stream.readBinary(4); } this.flags = stream.readUint8(); this.life = stream.readUint8(); if (version > 7) { this.itemTable = stream.readUint32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const itemSet = new RandomItemSet(); itemSet.load(stream); this.itemSets.push(itemSet); } } this.editorId = stream.readInt32(); } save(stream: BinaryStream, version: number, buildVersion: number): void { stream.writeBinary(this.id); stream.writeInt32(this.variation); stream.writeFloat32Array(this.location); stream.writeFloat32(this.angle); stream.writeFloat32Array(this.scale); if (buildVersion > 131) { stream.writeBinary(this.skin); } stream.writeUint8(this.flags); stream.writeUint8(this.life); if (version > 7) { stream.writeUint32(this.itemTable); stream.writeUint32(this.itemSets.length); for (const itemSet of this.itemSets) { itemSet.save(stream); } } stream.writeInt32(this.editorId); } getByteLength(version: number, buildVersion: number): number { let size = 42; if (buildVersion > 131) { size += 4; } if (version > 7) { size += 8; for (const itemSet of this.itemSets) { size += itemSet.getByteLength(); } } return size; } } ================================================ FILE: src/parsers/w3x/doo/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Doodad from './doodad'; import TerrainDoodad from './terraindoodad'; /** * war3map.doo - the doodad and destructible file. */ export default class War3MapDoo { version = 0; u1 = new Uint8Array(4); doodads: Doodad[] = []; u2 = new Uint8Array(4); terrainDoodads: TerrainDoodad[] = []; load(buffer: ArrayBuffer | Uint8Array, buildVersion: number): void { const stream = new BinaryStream(buffer); if (stream.readBinary(4) !== 'W3do') { throw new Error('Not a valid war3map.doo buffer'); } this.version = stream.readInt32(); stream.readUint8Array(this.u1); for (let i = 0, l = stream.readInt32(); i < l; i++) { const doodad = new Doodad(); doodad.load(stream, this.version, buildVersion); this.doodads.push(doodad); } stream.readUint8Array(this.u2); for (let i = 0, l = stream.readInt32(); i < l; i++) { const terrainDoodad = new TerrainDoodad(); terrainDoodad.load(stream, this.version); this.terrainDoodads.push(terrainDoodad); } } save(buildVersion: number): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength(buildVersion))); stream.writeBinary('W3do'); stream.writeInt32(this.version); stream.writeUint8Array(this.u1); stream.writeUint32(this.doodads.length); for (const doodad of this.doodads) { doodad.save(stream, this.version, buildVersion); } stream.writeUint8Array(this.u2); stream.writeUint32(this.terrainDoodads.length); for (const terrainDoodad of this.terrainDoodads) { terrainDoodad.save(stream, this.version); } return stream.uint8array; } getByteLength(buildVersion: number): number { let size = 24 + this.terrainDoodads.length * 16; for (const doodad of this.doodads) { size += doodad.getByteLength(this.version, buildVersion); } return size; } } ================================================ FILE: src/parsers/w3x/doo/index.ts ================================================ import File from './file'; import Doodad from './doodad'; import RandomItemSet from './randomitemset'; import RandomItem from './randomitem'; import TerrainDoodad from './terraindoodad'; export default { File, Doodad, RandomItemSet, RandomItem, TerrainDoodad, }; ================================================ FILE: src/parsers/w3x/doo/randomitem.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A random item. */ export default class RandomItem { id = '\0\0\0\0'; chance = 0; load(stream: BinaryStream): void { this.id = stream.readBinary(4); this.chance = stream.readInt32(); } save(stream: BinaryStream): void { stream.writeBinary(this.id); stream.writeInt32(this.chance); } } ================================================ FILE: src/parsers/w3x/doo/randomitemset.ts ================================================ import RandomItem from './randomitem'; import BinaryStream from '../../../common/binarystream'; /** * A random item set. */ export default class RandomItemSet { items: RandomItem[] = []; load(stream: BinaryStream): void { for (let i = 0, l = stream.readUint32(); i < l; i++) { const item = new RandomItem(); item.load(stream); this.items.push(item); } } save(stream: BinaryStream): void { stream.writeUint32(this.items.length); for (const item of this.items) { item.save(stream); } } getByteLength(): number { return 4 + this.items.length * 8; } } ================================================ FILE: src/parsers/w3x/doo/terraindoodad.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A terrain doodad. * * This type of doodad works much like cliffs. * It uses the height of the terrain, and gets affected by the ground heightmap. * It cannot be manipulated in any way in the World Editor once placed. * Indeed, the only way to change it is to remove it by changing cliffs around it. */ export default class TerrainDoodad { id = '\0\0\0\0'; u1 = 0; location = new Uint32Array(2); load(stream: BinaryStream, _version: number): void { this.id = stream.readBinary(4); this.u1 = stream.readUint32(); stream.readUint32Array(this.location); } save(stream: BinaryStream, _version: number): void { stream.writeBinary(this.id); stream.writeUint32(this.u1); stream.writeUint32Array(this.location); } } ================================================ FILE: src/parsers/w3x/imp/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Import from './import'; /** * war3map.imp - the import file. */ export default class War3MapImp { version = 1; entries: Map = new Map(); load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readUint32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const entry = new Import(); entry.load(stream); if (entry.isCustom) { this.entries.set(entry.path, entry); } else { this.entries.set(`war3mapimported\\${entry.path}`, entry); } } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeUint32(this.version); stream.writeUint32(this.entries.size); for (const entry of this.entries.values()) { entry.save(stream); } return stream.uint8array; } getByteLength(): number { let size = 8; for (const entry of this.entries.values()) { size += entry.getByteLength(); } return size; } set(path: string): boolean { if (!this.entries.has(path)) { const entry = new Import(); entry.isCustom = 10; entry.path = path; this.entries.set(path, entry); return true; } return false; } has(path: string): boolean { return this.entries.has(path); } delete(path: string): boolean { return this.entries.delete(path); } rename(path: string, newPath: string): boolean { const entry = this.entries.get(path); if (entry) { entry.isCustom = 10; entry.path = newPath; return true; } return false; } } ================================================ FILE: src/parsers/w3x/imp/import.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * An import. */ export default class Import { isCustom = 0; path = ''; load(stream: BinaryStream): void { this.isCustom = stream.readUint8(); this.path = stream.readNull(); } save(stream: BinaryStream): void { stream.writeUint8(this.isCustom); stream.writeNull(this.path); } getByteLength(): number { return 2 + byteLengthUtf8(this.path); } } ================================================ FILE: src/parsers/w3x/imp/index.ts ================================================ import File from './file'; import Import from './import'; export default { File, Import, }; ================================================ FILE: src/parsers/w3x/index.ts ================================================ import Map from './map'; import doo from './doo'; import imp from './imp'; import mmp from './mmp'; import shd from './shd'; import w3c from './w3c'; import w3d from './w3d'; import w3e from './w3e'; import w3i from './w3i'; import w3o from './w3o'; import w3r from './w3r'; import w3s from './w3s'; import w3u from './w3u'; import wct from './wct'; import wpm from './wpm'; import wtg from './wtg'; import wts from './wts'; import unitsdoo from './unitsdoo'; import w3f from './w3f'; export default { Map, doo, imp, mmp, shd, w3c, w3d, w3e, w3i, w3o, w3r, w3s, w3u, wct, wpm, wtg, wts, unitsdoo, w3f, }; ================================================ FILE: src/parsers/w3x/map.ts ================================================ import BinaryStream from '../../common/binarystream'; import MpqArchive from '../mpq/archive'; import War3MapImp from './imp/file'; import War3MapW3d from './w3d/file'; import War3MapW3u from './w3u/file'; import War3MapWct from './wct/file'; import War3MapWtg from './wtg/file'; import War3MapWts from './wts/file'; import { TriggerData } from './wtg/triggerdata'; import War3MapW3i from './w3i/file'; import MpqFile from '../mpq/file'; type War3MapModificationNames = 'w3a' | 'w3b' | 'w3d' | 'w3h' | 'w3q' | 'w3t' | 'w3u'; interface War3MapModifications { w3a?: War3MapW3d; w3b?: War3MapW3u; w3d?: War3MapW3d; w3h?: War3MapW3u; w3q?: War3MapW3d; w3t?: War3MapW3u; w3u?: War3MapW3u; } /** * Warcraft 3 map (W3X and W3M). */ export default class War3Map { u1 = 0; name = ''; flags = 0; maxPlayers = 0; archive = new MpqArchive(); imports = new War3MapImp(); readonly = false; /** * Load an existing map. * * Note that this clears the map from whatever it had in it before. */ load(buffer: ArrayBuffer | Uint8Array, readonly = false): void { const stream = new BinaryStream(buffer); // The header no longer exists since some 1.3X.X patch? if (stream.readBinary(4) === 'HM3W') { this.u1 = stream.readUint32(); this.name = stream.readNull(); this.flags = stream.readUint32(); this.maxPlayers = stream.readUint32(); } this.readonly = readonly; // Read the archive. this.archive.load(buffer, readonly); // Read in the imports file if there is one. this.readImports(); } /** * Save this map. * If the archive is in readonly mode, returns null. */ save(): Uint8Array { // Update the imports if needed. this.setImportsFile(); const archiveBuffer = this.archive.save(); if (!archiveBuffer) { throw Error('Failed to save the map MPQ archive'); } const information = this.getMapInformation(); // If this is a pre-1.31 map, or we don't know what the version is, save also the map header. if (!information || information.getBuildVersion() < 131) { const bytes = new Uint8Array(512 + archiveBuffer.byteLength); const stream = new BinaryStream(bytes); // Write the header. stream.writeBinary('HM3W'); stream.writeUint32(this.u1); stream.writeNull(this.name); stream.writeUint32(this.flags); stream.writeUint32(this.maxPlayers); bytes.set(archiveBuffer, 512); return bytes; } else { return archiveBuffer; } } /** * A shortcut to the internal archive function. */ getFileNames(): string[] { return this.archive.getFileNames(); } /** * Gets a list of the file names imported in this map. */ getImportNames(): string[] { const names = []; for (const entry of this.imports.entries.values()) { const isCustom = entry.isCustom; if (isCustom === 10 || isCustom === 13) { names.push(entry.path); } else { names.push(`war3mapImported\\${entry.path}`); } } return names; } /** * Sets the imports file with all of the imports. * * Does nothing if the archive is in readonly mode. */ setImportsFile(): boolean { if (this.readonly) { return false; } if (this.imports.entries.size > 0) { return this.set('war3map.imp', this.imports.save()); } return false; } /** * Imports a file to this archive. * * If the file already exists, its buffer will be set. * * Files added to the archive but not to the imports list will be deleted by the World Editor automatically. * This of course doesn't apply to internal map files. * * Does nothing if the archive is in readonly mode. */ import(name: string, buffer: ArrayBuffer | string): boolean { if (this.readonly) { return false; } if (this.archive.set(name, buffer)) { this.imports.set(name); return true; } return false; } /** * A shortcut to the internal archive function. */ set(name: string, buffer: ArrayBuffer | string): boolean { if (this.readonly) { return false; } return this.archive.set(name, buffer); } /** * A shortcut to the internal archive function. */ get(name: string): MpqFile | null { return this.archive.get(name); } /** * Get the map's script. */ getScriptFile(): MpqFile | null { return this.get('war3map.j') || this.get('scripts\\war3map.j') || this.get('war3map.lua') || this.get('scripts\\war3map.lua'); } /** * A shortcut to the internal archive function. */ has(name: string): boolean { return this.archive.has(name); } /** * Deletes a file from the internal archive. * * Note that if the file is in the imports list, it will be removed from it too. * * Use this rather than the internal archive's delete. */ delete(name: string): boolean { if (this.readonly) { return false; } // If this file is in the import list, remove it. this.imports.delete(name); return this.archive.delete(name); } /** * A shortcut to the internal archive function. */ rename(name: string, newName: string): boolean { if (this.readonly) { return false; } if (this.archive.rename(name, newName)) { // If the file was actually renamed, and it is an import, rename also the import entry. this.imports.rename(name, newName); return true; } return false; } getMapInformation(): War3MapW3i { const file = this.archive.get('war3map.w3i'); if (!file) { throw new Error('File does not exist'); } const parser = new War3MapW3i(); parser.load(file.bytes()); return parser; } readImports(): void { const file = this.archive.get('war3map.imp'); if (file) { const buffer = file.arrayBuffer(); if (buffer) { this.imports.load(buffer); } } } readTriggers(triggerData: TriggerData): War3MapWtg | undefined { const file = this.archive.get('war3map.wtg'); if (file) { const buffer = file.arrayBuffer(); if (buffer) { const object = new War3MapWtg(); object.load(buffer, triggerData); return object; } } return; } /** * Read and parse the custom text trigger file. */ readCustomTextTriggers(): War3MapWct | undefined { const file = this.archive.get('war3map.wct'); if (file) { const buffer = file.arrayBuffer(); if (buffer) { const object = new War3MapWct(); object.load(buffer); return object; } } return; } /** * Read and parse the string table file. */ readStringTable(): War3MapWts | undefined { const file = this.archive.get('war3map.wts'); if (file) { const buffer = file.text(); if (buffer) { const object = new War3MapWts(); object.load(buffer); return object; } } return; } /** * Read and parse all of the modification tables. */ readModifications(): War3MapModifications { const modifications: War3MapModifications = {}; // useOptionalInts: // w3u: no (units) // w3t: no (items) // w3b: no (destructables) // w3d: yes (doodads) // w3a: yes (abilities) // w3h: no (buffs) // w3q: yes (upgrades) const fileNames: War3MapModificationNames[] = ['w3u', 'w3t', 'w3b', 'w3d', 'w3a', 'w3h', 'w3q']; const useOptionalInts = [false, false, false, true, true, false, true]; for (let i = 0, l = fileNames.length; i < l; i++) { const file = this.archive.get(`war3map.${fileNames[i]}`); if (file) { const buffer = file.arrayBuffer(); if (buffer) { let modification; if (useOptionalInts[i]) { modification = new War3MapW3d(); } else { modification = new War3MapW3u(); } modification.load(buffer); modifications[fileNames[i]] = modification; } } } return modifications; } } ================================================ FILE: src/parsers/w3x/mmp/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import MinimapIcon from './minimapicon'; /** * war3map.mmp - the minimap icon file. */ export default class War3MapMmp { u1 = 0; icons: MinimapIcon[] = []; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.u1 = stream.readInt32(); for (let i = 0, l = stream.readInt32(); i < l; i++) { const icon = new MinimapIcon(); icon.load(stream); this.icons[i] = icon; } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.u1); stream.writeUint32(this.icons.length); for (const icon of this.icons) { icon.save(stream); } return stream.uint8array; } getByteLength(): number { return 8 + this.icons.length * 16; } } ================================================ FILE: src/parsers/w3x/mmp/index.ts ================================================ import File from './file'; import MinimapIcon from './minimapicon'; export default { File, MinimapIcon, }; ================================================ FILE: src/parsers/w3x/mmp/minimapicon.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A minimap icon. */ export default class MinimapIcon { type = 0; location = new Int32Array(2); /** * Stored as BGRA. */ color = new Uint8Array(4); load(stream: BinaryStream): void { this.type = stream.readInt32(); stream.readInt32Array(this.location); stream.readUint8Array(this.color); } save(stream: BinaryStream): void { stream.writeInt32(this.type); stream.writeInt32Array(this.location); stream.writeUint8Array(this.color); } } ================================================ FILE: src/parsers/w3x/shd/file.ts ================================================ /** * war3map.shd - the shadow file. */ export default class War3MapShd { shadows = new Uint8Array(0); load(buffer: ArrayBuffer | Uint8Array, width: number, height: number): void { this.shadows = new Uint8Array(buffer.slice(0, width * height * 16)); } save(): Uint8Array { return this.shadows.slice(); } getByteLength(): number { return this.shadows.length; } } ================================================ FILE: src/parsers/w3x/shd/index.ts ================================================ import File from './file'; export default { File, }; ================================================ FILE: src/parsers/w3x/unitsdoo/droppeditem.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A dropped item. */ export default class DroppedItem { id = '\0\0\0\0'; chance = 0; load(stream: BinaryStream): void { this.id = stream.readBinary(4); this.chance = stream.readInt32(); } save(stream: BinaryStream): void { stream.writeBinary(this.id); stream.writeInt32(this.chance); } } ================================================ FILE: src/parsers/w3x/unitsdoo/droppeditemset.ts ================================================ import BinaryStream from '../../../common/binarystream'; import DroppedItem from './droppeditem'; /** * A dropped item set. */ export default class DroppedItemSet { items: DroppedItem[] = []; load(stream: BinaryStream): void { for (let i = 0, l = stream.readInt32(); i < l; i++) { const item = new DroppedItem(); item.load(stream); this.items[i] = item; } } save(stream: BinaryStream): void { stream.writeInt32(this.items.length); for (const item of this.items) { item.save(stream); } } getByteLength(): number { return 4 + this.items.length * 8; } } ================================================ FILE: src/parsers/w3x/unitsdoo/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Unit from './unit'; /** * war3mapUnits.doo - the units and items file. */ export default class War3MapUnitsDoo { version = 8; subversion = 11; units: Unit[] = []; load(buffer: ArrayBuffer | Uint8Array, buildVersion: number): void { const stream = new BinaryStream(buffer); if (stream.readBinary(4) !== 'W3do') { throw new Error('Not a valid war3mapUnits.doo buffer'); } this.version = stream.readInt32(); this.subversion = stream.readUint32(); for (let i = 0, l = stream.readInt32(); i < l; i++) { const unit = new Unit(); unit.load(stream, this.version, this.subversion, buildVersion); this.units[i] = unit; } } save(buildVersion: number): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength(buildVersion))); stream.writeBinary('W3do'); stream.writeInt32(this.version); stream.writeUint32(this.subversion); stream.writeInt32(this.units.length); for (const unit of this.units) { unit.save(stream, this.version, this.subversion, buildVersion); } return stream.uint8array; } getByteLength(buildVersion: number): number { let size = 16; for (const unit of this.units) { size += unit.getByteLength(this.version, this.subversion, buildVersion); } return size; } } ================================================ FILE: src/parsers/w3x/unitsdoo/index.ts ================================================ import File from './file'; import Unit from './unit'; import DroppedItemSet from './droppeditemset'; import DroppedItem from './droppeditem'; import InventoryItem from './inventoryitem'; import ModifiedAbility from './modifiedability'; import RandomUnit from './randomunit'; export default { File, Unit, DroppedItemSet, DroppedItem, InventoryItem, ModifiedAbility, RandomUnit, }; ================================================ FILE: src/parsers/w3x/unitsdoo/inventoryitem.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * An inventory item. */ export default class InventoryItem { slot = 0; id = '\0\0\0\0'; load(stream: BinaryStream): void { this.slot = stream.readInt32(); this.id = stream.readBinary(4); } save(stream: BinaryStream): void { stream.writeInt32(this.slot); stream.writeBinary(this.id); } } ================================================ FILE: src/parsers/w3x/unitsdoo/modifiedability.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A modified ability. */ export default class ModifiedAbility { id = '\0\0\0\0'; activeForAutocast = 0; heroLevel = 1; load(stream: BinaryStream): void { this.id = stream.readBinary(4); this.activeForAutocast = stream.readInt32(); this.heroLevel = stream.readInt32(); } save(stream: BinaryStream): void { stream.writeBinary(this.id); stream.writeInt32(this.activeForAutocast); stream.writeInt32(this.heroLevel); } } ================================================ FILE: src/parsers/w3x/unitsdoo/randomunit.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A random unit. */ export default class RandomUnit { id = '\0\0\0\0'; chance = 0; load(stream: BinaryStream): void { this.id = stream.readBinary(4); this.chance = stream.readInt32(); } save(stream: BinaryStream): void { stream.writeBinary(this.id); stream.writeInt32(this.chance); } } ================================================ FILE: src/parsers/w3x/unitsdoo/unit.ts ================================================ import BinaryStream from '../../../common/binarystream'; import DroppedItemSet from './droppeditemset'; import InventoryItem from './inventoryitem'; import ModifiedAbility from './modifiedability'; import RandomUnit from './randomunit'; /** * A unit. */ export default class Unit { id = '\0\0\0\0'; variation = 0; location = new Float32Array(3); angle = 0; scale = new Float32Array([1, 1, 1]); /** * @since Game version 1.32 */ skin = '\0\0\0\0'; flags = 0; player = 0; unknown = 0; hitpoints = -1; mana = -1; /** * @since 8 */ droppedItemTable = 0; droppedItemSets: DroppedItemSet[] = []; goldAmount = 0; targetAcquisition = 0; heroLevel = 0; /** * @since 8 */ heroStrength = 0; /** * @since 8 */ heroAgility = 0; /** * @since 8 */ heroIntelligence = 0; itemsInInventory: InventoryItem[] = []; modifiedAbilities: ModifiedAbility[] = []; randomFlag = 0; level = new Uint8Array(3); itemClass = 0; unitGroup = 0; positionInGroup = 0; randomUnitTables: RandomUnit[] = []; customTeamColor = 0; waygate = 0; creationNumber = 0; load(stream: BinaryStream, version: number, subversion: number, buildVersion: number): void { this.id = stream.readBinary(4); this.variation = stream.readInt32(); stream.readFloat32Array(this.location); this.angle = stream.readFloat32(); stream.readFloat32Array(this.scale); if (buildVersion > 131) { this.skin = stream.readBinary(4); } this.flags = stream.readUint8(); this.player = stream.readInt32(); this.unknown = stream.readUint16(); this.hitpoints = stream.readInt32(); this.mana = stream.readInt32(); if (subversion > 10) { this.droppedItemTable = stream.readInt32(); } for (let i = 0, l = stream.readInt32(); i < l; i++) { const set = new DroppedItemSet(); set.load(stream); this.droppedItemSets[i] = set; } this.goldAmount = stream.readInt32(); this.targetAcquisition = stream.readFloat32(); this.heroLevel = stream.readInt32(); if (subversion > 10) { this.heroStrength = stream.readInt32(); this.heroAgility = stream.readInt32(); this.heroIntelligence = stream.readInt32(); } for (let i = 0, l = stream.readInt32(); i < l; i++) { const item = new InventoryItem(); item.load(stream); this.itemsInInventory[i] = item; } for (let i = 0, l = stream.readInt32(); i < l; i++) { const modifiedAbility = new ModifiedAbility(); modifiedAbility.load(stream); this.modifiedAbilities[i] = modifiedAbility; } this.randomFlag = stream.readInt32(); if (this.randomFlag === 0) { stream.readUint8Array(this.level); // 24bit number this.itemClass = stream.readUint8(); } else if (this.randomFlag === 1) { this.unitGroup = stream.readUint32(); this.positionInGroup = stream.readUint32(); } else if (this.randomFlag === 2) { for (let i = 0, l = stream.readInt32(); i < l; i++) { const randomUnit = new RandomUnit(); randomUnit.load(stream); this.randomUnitTables[i] = randomUnit; } } this.customTeamColor = stream.readInt32(); this.waygate = stream.readInt32(); this.creationNumber = stream.readInt32(); } save(stream: BinaryStream, version: number, subversion: number, buildVersion: number): void { stream.writeBinary(this.id); stream.writeInt32(this.variation); stream.writeFloat32Array(this.location); stream.writeFloat32(this.angle); stream.writeFloat32Array(this.scale); if (buildVersion > 131) { stream.writeBinary(this.skin); } stream.writeUint8(this.flags); stream.writeInt32(this.player); stream.writeUint16(this.unknown); stream.writeInt32(this.hitpoints); stream.writeInt32(this.mana); if (subversion > 10) { stream.writeInt32(this.droppedItemTable); } stream.writeInt32(this.droppedItemSets.length); for (const droppedItemSet of this.droppedItemSets) { droppedItemSet.save(stream); } stream.writeInt32(this.goldAmount); stream.writeFloat32(this.targetAcquisition); stream.writeInt32(this.heroLevel); if (subversion > 10) { stream.writeInt32(this.heroStrength); stream.writeInt32(this.heroAgility); stream.writeInt32(this.heroIntelligence); } stream.writeInt32(this.itemsInInventory.length); for (const itemInInventory of this.itemsInInventory) { itemInInventory.save(stream); } stream.writeInt32(this.modifiedAbilities.length); for (const modifiedAbility of this.modifiedAbilities) { modifiedAbility.save(stream); } stream.writeInt32(this.randomFlag); if (this.randomFlag === 0) { stream.writeUint8Array(this.level); stream.writeUint8(this.itemClass); } else if (this.randomFlag === 1) { stream.writeUint32(this.unitGroup); stream.writeUint32(this.positionInGroup); } else if (this.randomFlag === 2) { stream.writeInt32(this.randomUnitTables.length); for (const randomUnitTable of this.randomUnitTables) { randomUnitTable.save(stream); } } stream.writeInt32(this.customTeamColor); stream.writeInt32(this.waygate); stream.writeInt32(this.creationNumber); } getByteLength(version: number, subversion: number, buildVersion: number): number { let size = 91; if (buildVersion > 131) { size += 4; } if (subversion > 10) { size += 16; } for (const droppedItemSet of this.droppedItemSets) { size += droppedItemSet.getByteLength(); } size += this.itemsInInventory.length * 8; size += this.modifiedAbilities.length * 12; if (this.randomFlag === 0) { size += 4; } else if (this.randomFlag === 1) { size += 8; } else if (this.randomFlag === 2) { size += 4 + this.randomUnitTables.length * 8; } return size; } } ================================================ FILE: src/parsers/w3x/w3c/camera.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A camera. */ export default class Camera { targetLocation = new Float32Array(3); rotation = 0; angleOfAttack = 0; distance = 0; roll = 0; fieldOfView = 0; farClippingPlane = 0; nearClippingPlane = 0; cinematicName = ''; /** * @since Game version 1.32 */ localPitch = 0; /** * @since Game version 1.32 */ localYaw = 0; /** * @since Game version 1.32 */ localRoll = 0; load(stream: BinaryStream, buildVersion: number): void { stream.readFloat32Array(this.targetLocation); this.rotation = stream.readFloat32(); // in degrees this.angleOfAttack = stream.readFloat32(); // in degrees this.distance = stream.readFloat32(); this.roll = stream.readFloat32(); this.fieldOfView = stream.readFloat32(); // in degrees this.farClippingPlane = stream.readFloat32(); this.nearClippingPlane = stream.readFloat32(); this.cinematicName = stream.readNull(); if (buildVersion > 131) { this.localPitch = stream.readFloat32(); this.localYaw = stream.readFloat32(); this.localRoll = stream.readFloat32(); } } save(stream: BinaryStream, buildVersion: number): void { stream.writeFloat32Array(this.targetLocation); stream.writeFloat32(this.rotation); stream.writeFloat32(this.angleOfAttack); stream.writeFloat32(this.distance); stream.writeFloat32(this.roll); stream.writeFloat32(this.fieldOfView); stream.writeFloat32(this.farClippingPlane); stream.writeFloat32(this.nearClippingPlane); stream.writeNull(this.cinematicName); if (buildVersion > 131) { stream.writeFloat32(this.localPitch); stream.writeFloat32(this.localYaw); stream.writeFloat32(this.localRoll); } } getByteLength(buildVersion: number): number { let size = 41 + byteLengthUtf8(this.cinematicName); if (buildVersion > 131) { size += 12; } return size; } } ================================================ FILE: src/parsers/w3x/w3c/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Camera from './camera'; /** * war3map.w3c - the camera file. */ export default class War3MapW3c { version = 0; cameras: Camera[] = []; load(buffer: ArrayBuffer | Uint8Array, buildVersion: number): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const camera = new Camera(); camera.load(stream, buildVersion); this.cameras[i] = camera; } } save(buildVersion: number): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength(buildVersion))); stream.writeInt32(this.version); stream.writeUint32(this.cameras.length); for (const camera of this.cameras) { camera.save(stream, buildVersion); } return stream.uint8array; } getByteLength(buildVersion: number): number { let size = 8; for (const camera of this.cameras) { size += camera.getByteLength(buildVersion); } return size; } } ================================================ FILE: src/parsers/w3x/w3c/index.ts ================================================ import File from './file'; import Camera from './camera'; export default { File, Camera, }; ================================================ FILE: src/parsers/w3x/w3d/file.ts ================================================ import BinaryStream from "../../../common/binarystream"; import ModificationTable from "../w3u/modificationtable"; /** * war3map.w3d - the doodad modification file. * * Also used for war3map.w3a (abilities), and war3map.w3q (upgrades). */ export default class War3MapW3d { version = 0; originalTable = new ModificationTable(); customTable = new ModificationTable(); load(bufferOrStream: ArrayBuffer | Uint8Array | BinaryStream): void { let stream; if (bufferOrStream instanceof BinaryStream) { stream = bufferOrStream; } else { stream = new BinaryStream(bufferOrStream); } this.version = stream.readInt32(); this.originalTable.load(stream, true, this.version); this.customTable.load(stream, true, this.version); } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); this.originalTable.save(stream, true, this.version); this.customTable.save(stream, true, this.version); return stream.uint8array; } getByteLength(): number { return ( 4 + this.originalTable.getByteLength(true, this.version) + this.customTable.getByteLength(true, this.version) ); } } ================================================ FILE: src/parsers/w3x/w3d/index.ts ================================================ import File from './file'; export default { File, }; ================================================ FILE: src/parsers/w3x/w3e/corner.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A tile corner. */ export default class Corner { groundHeight = 0; waterHeight = 0; mapEdge = 0; ramp = 0; blight = 0; water = 0; boundary = 0; groundTexture = 0; cliffVariation = 0; groundVariation = 0; cliffTexture = 0; layerHeight = 0; load(stream: BinaryStream): void { this.groundHeight = (stream.readInt16() - 8192) / 512; const waterAndEdge = stream.readInt16(); this.waterHeight = ((waterAndEdge & 0x3FFF) - 8192) / 512; this.mapEdge = waterAndEdge & 0x4000; const textureAndFlags = stream.readUint8(); this.ramp = textureAndFlags & 0b00010000; this.blight = textureAndFlags & 0b00100000; this.water = textureAndFlags & 0b01000000; this.boundary = textureAndFlags & 0b10000000; this.groundTexture = textureAndFlags & 0b00001111; const variation = stream.readUint8(); this.cliffVariation = (variation & 0b11100000) >>> 5; this.groundVariation = variation & 0b00011111; const cliffTextureAndLayer = stream.readUint8(); this.cliffTexture = (cliffTextureAndLayer & 0b11110000) >>> 4; this.layerHeight = cliffTextureAndLayer & 0b00001111; } save(stream: BinaryStream): void { stream.writeInt16(this.groundHeight * 512 + 8192); stream.writeInt16(this.waterHeight * 512 + 8192 + this.mapEdge << 14); stream.writeUint8((this.ramp << 4) | (this.blight << 5) | (this.water << 6) | (this.boundary << 7) | this.groundTexture); stream.writeUint8((this.cliffVariation << 5) | this.groundVariation); stream.writeUint8((this.cliffTexture << 4) + this.layerHeight); } } ================================================ FILE: src/parsers/w3x/w3e/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Corner from './corner'; /** * war3map.w3e - the environment file. */ export default class War3MapW3e { version = 0; tileset = 'A'; haveCustomTileset = 0; groundTilesets: string[] = []; cliffTilesets: string[] = []; mapSize = new Int32Array(2); centerOffset = new Float32Array(2); corners: Corner[][] = []; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); if (stream.readBinary(4) !== 'W3E!') { return; } this.version = stream.readInt32(); this.tileset = stream.readBinary(1); this.haveCustomTileset = stream.readInt32(); for (let i = 0, l = stream.readInt32(); i < l; i++) { this.groundTilesets[i] = stream.readBinary(4); } for (let i = 0, l = stream.readInt32(); i < l; i++) { this.cliffTilesets[i] = stream.readBinary(4); } stream.readInt32Array(this.mapSize); stream.readFloat32Array(this.centerOffset); for (let row = 0, rows = this.mapSize[1]; row < rows; row++) { this.corners[row] = []; for (let column = 0, columns = this.mapSize[0]; column < columns; column++) { const corner = new Corner(); corner.load(stream); this.corners[row][column] = corner; } } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeBinary('W3E!'); stream.writeInt32(this.version); stream.writeBinary(this.tileset); stream.writeInt32(this.haveCustomTileset); stream.writeUint32(this.groundTilesets.length); for (const groundTileset of this.groundTilesets) { stream.writeBinary(groundTileset); } stream.writeUint32(this.cliffTilesets.length); for (const cliffTileset of this.cliffTilesets) { stream.writeBinary(cliffTileset); } stream.writeInt32Array(this.mapSize); stream.writeFloat32Array(this.centerOffset); for (const row of this.corners) { for (const corner of row) { corner.save(stream); } } return stream.uint8array; } getByteLength(): number { return 37 + (this.groundTilesets.length * 4) + (this.cliffTilesets.length * 4) + (this.mapSize[0] * this.mapSize[1] * 7); } } ================================================ FILE: src/parsers/w3x/w3e/index.ts ================================================ import File from './file'; import Corner from './corner'; export default { File, Corner, }; ================================================ FILE: src/parsers/w3x/w3f/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import MapTitle from './maptitle'; import MapOrder from './maporder'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * war3campaign.w3f - the campaign information file. */ export default class War3CampaignW3f { version = 0; campaignVersion = 0; editorVersion = 0; name = ''; difficulty = ''; author = ''; description = ''; mode = -1; // 0: fixed difficulty, only w3m maps, 1: variable difficulty, only w3m maps, 1: fixed..., contains w3x maps, 2: variable..., contains w3xm maps. backgroundScreen = -1; // -1 = none or custom path backgroundScreenPath = ''; minimapImagePath = ''; ambientSound = 0; // -1 = imported, 0 = none, >0 = preset index ambientSoundPath = ''; terrainFog = 0; // 0 = not used, >0 = index of terrain fog style fogStartZ = 0; fogEndZ = 0; fogDensity = 0; fogColor = new Uint8Array(4); userInterface = -1; // 0 = human mapTitles: MapTitle[] = []; mapOrders: MapOrder[] = []; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); this.campaignVersion = stream.readInt32(); this.editorVersion = stream.readInt32(); this.name = stream.readNull(); this.difficulty = stream.readNull(); this.author = stream.readNull(); this.description = stream.readNull(); this.mode = stream.readInt32(); this.backgroundScreen = stream.readInt32(); this.backgroundScreenPath = stream.readNull(); this.minimapImagePath = stream.readNull(); this.ambientSound = stream.readInt32(); this.ambientSoundPath = stream.readNull(); this.terrainFog = stream.readInt32(); this.fogStartZ = stream.readFloat32(); this.fogEndZ = stream.readFloat32(); this.fogDensity = stream.readFloat32(); stream.readUint8Array(this.fogColor); this.userInterface = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const mapTitle = new MapTitle(); mapTitle.load(stream); this.mapTitles[i] = mapTitle; } for (let i = 0, l = stream.readUint32(); i < l; i++) { const mapOrder = new MapOrder(); mapOrder.load(stream); this.mapOrders[i] = mapOrder; } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); stream.writeInt32(this.campaignVersion); stream.writeInt32(this.editorVersion); stream.writeNull(this.name); stream.writeNull(this.difficulty); stream.writeNull(this.author); stream.writeNull(this.description); stream.writeInt32(this.mode); stream.writeInt32(this.backgroundScreen); stream.writeNull(this.backgroundScreenPath); stream.writeNull(this.minimapImagePath); stream.writeInt32(this.ambientSound); stream.writeNull(this.ambientSoundPath); stream.writeInt32(this.terrainFog); stream.writeFloat32(this.fogStartZ); stream.writeFloat32(this.fogEndZ); stream.writeFloat32(this.fogDensity); stream.writeUint8Array(this.fogColor); stream.writeInt32(this.userInterface); stream.writeUint32(this.mapTitles.length); for (const title of this.mapTitles) { title.save(stream); } stream.writeUint32(this.mapOrders.length); for (const order of this.mapOrders) { order.save(stream); } return stream.uint8array; } getByteLength(): number { let size = 63 + byteLengthUtf8(this.name) + byteLengthUtf8(this.difficulty) + byteLengthUtf8(this.author) + byteLengthUtf8(this.description) + byteLengthUtf8(this.backgroundScreenPath) + byteLengthUtf8(this.minimapImagePath) + byteLengthUtf8(this.ambientSoundPath); for (const title of this.mapTitles) { size += title.getByteLength(); } for (const order of this.mapOrders) { size += order.getByteLength(); } return size; } } ================================================ FILE: src/parsers/w3x/w3f/index.ts ================================================ import File from './file'; import MapTitle from './maptitle'; import MapOrder from './maporder'; export default { File, MapTitle, MapOrder, }; ================================================ FILE: src/parsers/w3x/w3f/maporder.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A map order. */ export default class MapOrder { u1 = 0; path = ''; load(stream: BinaryStream): void { this.u1 = stream.readInt8(); this.path = stream.readNull(); } save(stream: BinaryStream): void { stream.writeInt8(this.u1); stream.writeNull(this.path); } getByteLength(): number { return 2 + byteLengthUtf8(this.path); } } ================================================ FILE: src/parsers/w3x/w3f/maptitle.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A map title. */ export default class MapTitle { visible = 0; chapterTitle = ''; mapTitle = ''; path = ''; load(stream: BinaryStream): void { this.visible = stream.readInt32(); this.chapterTitle = stream.readNull(); this.mapTitle = stream.readNull(); this.path = stream.readNull(); } save(stream: BinaryStream): void { stream.writeInt32(this.visible); stream.writeNull(this.chapterTitle); stream.writeNull(this.mapTitle); stream.writeNull(this.path); } getByteLength(): number { return 7 + byteLengthUtf8(this.chapterTitle) + byteLengthUtf8(this.mapTitle) + byteLengthUtf8(this.path); } } ================================================ FILE: src/parsers/w3x/w3i/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import Force from './force'; import Player from './player'; import RandomItemTable from './randomitemtable'; import RandomUnitTable from './randomunittable'; import TechAvailabilityChange from './techavailabilitychange'; import UpgradeAvailabilityChange from './upgradeavailabilitychange'; /** * war3map.w3i - the general information file. */ export default class War3MapW3i { version = 0; saves = 0; editorVersion = 0; buildVersion = new Uint32Array(4); name = ''; author = ''; description = ''; recommendedPlayers = ''; cameraBounds = new Float32Array(8); cameraBoundsComplements = new Int32Array(4); playableSize = new Int32Array(2); flags = 0; tileset = 'A'; campaignBackground = 0; loadingScreenModel = ''; loadingScreenText = ''; loadingScreenTitle = ''; loadingScreenSubtitle = ''; loadingScreen = 0; prologueScreenModel = ''; prologueScreenText = ''; prologueScreenTitle = ''; prologueScreenSubtitle = ''; useTerrainFog = 0; fogHeight = new Float32Array(2); fogDensity = 0; fogColor = new Uint8Array(4); globalWeather = 0; soundEnvironment = ''; lightEnvironmentTileset = '\0'; waterVertexColor = new Uint8Array(4); scriptMode = 0; graphicsMode = 0; defaultCameraZoom = 0; maxCameraZoom = 0; minCameraZoom = 0; players: Player[] = []; forces: Force[] = []; upgradeAvailabilityChanges: UpgradeAvailabilityChange[] = []; techAvailabilityChanges: TechAvailabilityChange[] = []; randomUnitTables: RandomUnitTable[] = []; randomItemTables: RandomItemTable[] = []; unknown1 = 0; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); this.saves = stream.readInt32(); this.editorVersion = stream.readInt32(); if (this.version > 27) { stream.readUint32Array(this.buildVersion); } this.name = stream.readNull(); this.author = stream.readNull(); this.description = stream.readNull(); this.recommendedPlayers = stream.readNull(); stream.readFloat32Array(this.cameraBounds); stream.readInt32Array(this.cameraBoundsComplements); stream.readInt32Array(this.playableSize); this.flags = stream.readUint32(); this.tileset = stream.readBinary(1); this.campaignBackground = stream.readInt32(); if (this.version > 24) { this.loadingScreenModel = stream.readNull(); } this.loadingScreenText = stream.readNull(); this.loadingScreenTitle = stream.readNull(); this.loadingScreenSubtitle = stream.readNull(); this.loadingScreen = stream.readInt32(); if (this.version > 24) { this.prologueScreenModel = stream.readNull(); } this.prologueScreenText = stream.readNull(); this.prologueScreenTitle = stream.readNull(); this.prologueScreenSubtitle = stream.readNull(); if (this.version > 24) { this.useTerrainFog = stream.readInt32(); stream.readFloat32Array(this.fogHeight); this.fogDensity = stream.readFloat32(); stream.readUint8Array(this.fogColor); this.globalWeather = stream.readInt32(); this.soundEnvironment = stream.readNull(); this.lightEnvironmentTileset = stream.readBinary(1); stream.readUint8Array(this.waterVertexColor); } if (this.version > 27) { this.scriptMode = stream.readUint32(); } if (this.version > 30) { this.graphicsMode = stream.readUint32(); this.unknown1 = stream.readUint32(); } if (this.version > 32) { this.defaultCameraZoom = stream.readUint32(); this.maxCameraZoom = stream.readUint32(); this.minCameraZoom = stream.readUint32(); } for (let i = 0, l = stream.readInt32(); i < l; i++) { const player = new Player(); player.load(stream, this.version); this.players[i] = player; } for (let i = 0, l = stream.readInt32(); i < l; i++) { const force = new Force(); force.load(stream); this.forces[i] = force; } for (let i = 0, l = stream.readInt32(); i < l; i++) { const upgradeAvailabilityChange = new UpgradeAvailabilityChange(); upgradeAvailabilityChange.load(stream); this.upgradeAvailabilityChanges[i] = upgradeAvailabilityChange; } for (let i = 0, l = stream.readInt32(); i < l; i++) { const techAvailabilityChange = new TechAvailabilityChange(); techAvailabilityChange.load(stream); this.techAvailabilityChanges[i] = techAvailabilityChange; } for (let i = 0, l = stream.readInt32(); i < l; i++) { const randomUnitTable = new RandomUnitTable(); randomUnitTable.load(stream); this.randomUnitTables[i] = randomUnitTable; } if (this.version > 24) { for (let i = 0, l = stream.readInt32(); i < l; i++) { const randomItemTable = new RandomItemTable(); randomItemTable.load(stream); this.randomItemTables[i] = randomItemTable; } } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); stream.writeInt32(this.saves); stream.writeInt32(this.editorVersion); if (this.version > 27) { stream.writeUint32Array(this.buildVersion); } stream.writeNull(this.name); stream.writeNull(this.author); stream.writeNull(this.description); stream.writeNull(this.recommendedPlayers); stream.writeFloat32Array(this.cameraBounds); stream.writeInt32Array(this.cameraBoundsComplements); stream.writeInt32Array(this.playableSize); stream.writeUint32(this.flags); stream.writeBinary(this.tileset); stream.writeInt32(this.campaignBackground); if (this.version > 24) { stream.writeNull(this.loadingScreenModel); } stream.writeNull(this.loadingScreenText); stream.writeNull(this.loadingScreenTitle); stream.writeNull(this.loadingScreenSubtitle); stream.writeInt32(this.loadingScreen); if (this.version > 24) { stream.writeNull(this.prologueScreenModel); } stream.writeNull(this.prologueScreenText); stream.writeNull(this.prologueScreenTitle); stream.writeNull(this.prologueScreenSubtitle); if (this.version > 24) { stream.writeInt32(this.useTerrainFog); stream.writeFloat32Array(this.fogHeight); stream.writeFloat32(this.fogDensity); stream.writeUint8Array(this.fogColor); stream.writeInt32(this.globalWeather); stream.writeNull(this.soundEnvironment); stream.writeBinary(this.lightEnvironmentTileset); stream.writeUint8Array(this.waterVertexColor); } if (this.version > 27) { stream.writeUint32(this.scriptMode); } if (this.version > 30) { stream.writeUint32(this.graphicsMode); stream.writeUint32(this.unknown1); } if (this.version > 32) { stream.writeUint32(this.defaultCameraZoom); stream.writeUint32(this.maxCameraZoom); stream.writeUint32(this.minCameraZoom); } stream.writeUint32(this.players.length); for (const player of this.players) { player.save(stream, this.version); } stream.writeUint32(this.forces.length); for (const force of this.forces) { force.save(stream); } stream.writeUint32(this.upgradeAvailabilityChanges.length); for (const change of this.upgradeAvailabilityChanges) { change.save(stream); } stream.writeUint32(this.techAvailabilityChanges.length); for (const change of this.techAvailabilityChanges) { change.save(stream); } stream.writeUint32(this.randomUnitTables.length); for (const table of this.randomUnitTables) { table.save(stream); } if (this.version > 24) { stream.writeUint32(this.randomItemTables.length); for (const table of this.randomItemTables) { table.save(stream); } } return stream.uint8array; } getByteLength(): number { let size = 111 + byteLengthUtf8(this.name) + byteLengthUtf8(this.author) + byteLengthUtf8(this.description) + byteLengthUtf8(this.recommendedPlayers) + byteLengthUtf8(this.loadingScreenText) + byteLengthUtf8(this.loadingScreenTitle) + byteLengthUtf8(this.loadingScreenSubtitle) + byteLengthUtf8(this.prologueScreenText) + byteLengthUtf8(this.prologueScreenTitle) + byteLengthUtf8(this.prologueScreenSubtitle); for (const player of this.players) { size += player.getByteLength(this.version); } for (const force of this.forces) { size += force.getByteLength(); } size += this.upgradeAvailabilityChanges.length * 16; size += this.techAvailabilityChanges.length * 8; for (const table of this.randomUnitTables) { size += table.getByteLength(); } if (this.version > 24) { size += 36 + byteLengthUtf8(this.loadingScreenModel) + byteLengthUtf8(this.prologueScreenModel) + byteLengthUtf8(this.soundEnvironment); for (const table of this.randomItemTables) { size += table.getByteLength(); } } if (this.version > 27) { size += 20; } if (this.version > 30) { size += 8; } return size; } /** * Returns the build version as major+minor. * * For example version 1.31.X will return 131. * * Note that this will always return 0 for any version below 1.31. */ getBuildVersion(): number { return this.buildVersion[0] * 100 + this.buildVersion[1]; } } ================================================ FILE: src/parsers/w3x/w3i/force.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A force. */ export default class Force { flags = 0; playerMasks = 0; name = ''; load(stream: BinaryStream): void { this.flags = stream.readUint32(); this.playerMasks = stream.readUint32(); this.name = stream.readNull(); } save(stream: BinaryStream): void { stream.writeUint32(this.flags); stream.writeUint32(this.playerMasks); stream.writeNull(this.name); } getByteLength(): number { return 9 + byteLengthUtf8(this.name); } } ================================================ FILE: src/parsers/w3x/w3i/index.ts ================================================ import File from './file'; import Player from './player'; import Force from './force'; import UpgradeAvailabilityChange from './upgradeavailabilitychange'; import TechAvailabilityChange from './techavailabilitychange'; import RandomUnitTable from './randomunittable'; import RandomUnit from './randomunit'; import RandomItemTable from './randomitemtable'; import RandomItemSet from './randomitemset'; import RandomItem from './randomitem'; export default { File, Player, Force, UpgradeAvailabilityChange, TechAvailabilityChange, RandomUnitTable, RandomUnit, RandomItemTable, RandomItemSet, RandomItem, }; ================================================ FILE: src/parsers/w3x/w3i/player.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A player. */ export default class Player { id = 0; type = 0; race = 0; isFixedStartPosition = 0; name = ''; startLocation = new Float32Array(2); allyLowPriorities = 0; allyHighPriorities = 0; unknown1 = new Uint8Array(8); load(stream: BinaryStream, version: number): void { this.id = stream.readInt32(); this.type = stream.readInt32(); this.race = stream.readInt32(); this.isFixedStartPosition = stream.readInt32(); this.name = stream.readNull(); stream.readFloat32Array(this.startLocation); this.allyLowPriorities = stream.readUint32(); this.allyHighPriorities = stream.readUint32(); if (version > 30) { stream.readUint8Array(this.unknown1); } } save(stream: BinaryStream, version: number): void { stream.writeInt32(this.id); stream.writeInt32(this.type); stream.writeInt32(this.race); stream.writeInt32(this.isFixedStartPosition); stream.writeNull(this.name); stream.writeFloat32Array(this.startLocation); stream.writeUint32(this.allyLowPriorities); stream.writeUint32(this.allyHighPriorities); if (version > 30) { stream.writeUint8Array(this.unknown1); } } getByteLength(version: number): number { let size = 33 + byteLengthUtf8(this.name); if (version > 30) { size += 8; } return size; } } ================================================ FILE: src/parsers/w3x/w3i/randomitem.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A random item. */ export default class RandomItem { chance = 0; id = '\0\0\0\0'; load(stream: BinaryStream): void { this.chance = stream.readInt32(); this.id = stream.readBinary(4); } save(stream: BinaryStream): void { stream.writeInt32(this.chance); stream.writeBinary(this.id); } } ================================================ FILE: src/parsers/w3x/w3i/randomitemset.ts ================================================ import BinaryStream from '../../../common/binarystream'; import RandomItem from './randomitem'; /** * A random item set. */ export default class RandomItemSet { items: RandomItem[] = []; load(stream: BinaryStream): void { for (let i = 0, l = stream.readUint32(); i < l; i++) { const item = new RandomItem(); item.load(stream); this.items[i] = item; } } save(stream: BinaryStream): void { stream.writeUint32(this.items.length); for (const item of this.items) { item.save(stream); } } getByteLength(): number { return 4 + this.items.length * 8; } } ================================================ FILE: src/parsers/w3x/w3i/randomitemtable.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import RandomItemSet from './randomitemset'; /** * A random item table. */ export default class RandomItemTable { id = 0; name = ''; sets: RandomItemSet[] = []; load(stream: BinaryStream): void { this.id = stream.readInt32(); this.name = stream.readNull(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const set = new RandomItemSet(); set.load(stream); this.sets[i] = set; } } save(stream: BinaryStream): void { stream.writeInt32(this.id); stream.writeNull(this.name); stream.writeUint32(this.sets.length); for (const set of this.sets) { set.save(stream); } } getByteLength(): number { let size = 9 + byteLengthUtf8(this.name); for (const set of this.sets) { size += set.getByteLength(); } return size; } } ================================================ FILE: src/parsers/w3x/w3i/randomunit.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A random unit. */ export default class RandomUnit { chance = 0; ids: string[] = []; load(stream: BinaryStream, positions: number): void { this.chance = stream.readInt32(); for (let i = 0; i < positions; i++) { this.ids[i] = stream.readBinary(4); } } save(stream: BinaryStream): void { stream.writeInt32(this.chance); for (const id of this.ids) { stream.writeBinary(id); } } } ================================================ FILE: src/parsers/w3x/w3i/randomunittable.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import RandomUnit from './randomunit'; /** * A random unit table. */ export default class RandomUnitTable { id = 0; name = ''; positions = 0; columnTypes = new Int32Array(0); units: RandomUnit[] = []; load(stream: BinaryStream): void { this.id = stream.readInt32(); this.name = stream.readNull(); this.positions = stream.readInt32(); this.columnTypes = stream.readInt32Array(this.positions); for (let i = 0, l = stream.readUint32(); i < l; i++) { const unit = new RandomUnit(); unit.load(stream, this.positions); this.units[i] = unit; } } save(stream: BinaryStream): void { stream.writeInt32(this.id); stream.writeNull(this.name); stream.writeInt32(this.positions); stream.writeInt32Array(this.columnTypes); stream.writeUint32(this.units.length); for (const unit of this.units) { unit.save(stream); } } getByteLength(): number { return 13 + byteLengthUtf8(this.name) + this.columnTypes.byteLength + (this.units.length * (4 + 4 * this.positions)); } } ================================================ FILE: src/parsers/w3x/w3i/techavailabilitychange.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * A tech availablity change. */ export default class TechAvailabilityChange { playerFlags = 0; id = '\0\0\0\0'; load(stream: BinaryStream): void { this.playerFlags = stream.readUint32(); this.id = stream.readBinary(4); } save(stream: BinaryStream): void { stream.writeUint32(this.playerFlags); stream.writeBinary(this.id); } } ================================================ FILE: src/parsers/w3x/w3i/upgradeavailabilitychange.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * An upgrade availability change. */ export default class UpgradeAvailabilityChange { playerFlags = 0; id = '\0\0\0\0'; levelAffected = 0; availability = 0; load(stream: BinaryStream): void { this.playerFlags = stream.readUint32(); this.id = stream.readBinary(4); this.levelAffected = stream.readInt32(); this.availability = stream.readInt32(); } save(stream: BinaryStream): void { stream.writeUint32(this.playerFlags); stream.writeBinary(this.id); stream.writeInt32(this.levelAffected); stream.writeInt32(this.availability); } } ================================================ FILE: src/parsers/w3x/w3o/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import War3MapW3u from '../w3u/file'; import War3MapW3d from '../w3d/file'; /** * war3map.w3o - the combined modification file. * * Contains all of the modifications of a map. * Can be exported and imported via the World Editor. */ export default class War3MapW3o { version = 0; units: War3MapW3u | null = null; items: War3MapW3u | null = null; destructables: War3MapW3u | null = null; doodads: War3MapW3d | null = null; abilities: War3MapW3d | null = null; buffs: War3MapW3u | null = null; upgrades: War3MapW3d | null = null; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); if (stream.readInt32()) { this.units = new War3MapW3u(); this.units.load(stream); } if (stream.readInt32()) { this.items = new War3MapW3u(); this.items.load(stream); } if (stream.readInt32()) { this.destructables = new War3MapW3u(); this.destructables.load(stream); } if (stream.readInt32()) { this.doodads = new War3MapW3d(); this.doodads.load(stream); } if (stream.readInt32()) { this.abilities = new War3MapW3d(); this.abilities.load(stream); } if (stream.readInt32()) { this.buffs = new War3MapW3u(); this.buffs.load(stream); } if (stream.readInt32()) { this.upgrades = new War3MapW3d(); this.upgrades.load(stream); } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); if (this.units) { stream.writeInt32(1); stream.writeUint8Array(this.units.save()); } else { stream.writeInt32(0); } if (this.items) { stream.writeInt32(1); stream.writeUint8Array(this.items.save()); } else { stream.writeInt32(0); } if (this.destructables) { stream.writeInt32(1); stream.writeUint8Array(this.destructables.save()); } else { stream.writeInt32(0); } if (this.doodads) { stream.writeInt32(1); stream.writeUint8Array(this.doodads.save()); } else { stream.writeInt32(0); } if (this.abilities) { stream.writeInt32(1); stream.writeUint8Array(this.abilities.save()); } else { stream.writeInt32(0); } if (this.buffs) { stream.writeInt32(1); stream.writeUint8Array(this.buffs.save()); } else { stream.writeInt32(0); } if (this.upgrades) { stream.writeInt32(1); stream.writeUint8Array(this.upgrades.save()); } else { stream.writeInt32(0); } return stream.uint8array; } getByteLength(): number { let size = 32; if (this.units) { size += this.units.getByteLength(); } if (this.items) { size += this.items.getByteLength(); } if (this.destructables) { size += this.destructables.getByteLength(); } if (this.doodads) { size += this.doodads.getByteLength(); } if (this.abilities) { size += this.abilities.getByteLength(); } if (this.buffs) { size += this.buffs.getByteLength(); } if (this.upgrades) { size += this.upgrades.getByteLength(); } return size; } } ================================================ FILE: src/parsers/w3x/w3o/index.ts ================================================ import File from './file'; export default { File, }; ================================================ FILE: src/parsers/w3x/w3r/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Region from './region'; /** * war3map.w3r - the region file. */ export default class War3MapW3r { version = 0; regions: Region[] = []; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const region = new Region(); region.load(stream); this.regions[i] = region; } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); stream.writeUint32(this.regions.length); for (const region of this.regions) { region.save(stream); } return stream.uint8array; } getByteLength(): number { let size = 8; for (const region of this.regions) { size += region.getByteLength(); } return size; } } ================================================ FILE: src/parsers/w3x/w3r/index.ts ================================================ import File from './file'; import Region from './region'; export default { File, Region, }; ================================================ FILE: src/parsers/w3x/w3r/region.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A region. */ export default class Region { left = 0; right = 0; bottom = 0; top = 0; name = ''; creationNumber = 0; weatherEffectId = '\0\0\0\0'; ambientSound = ''; color = new Uint8Array(4); load(stream: BinaryStream): void { this.left = stream.readFloat32(); this.right = stream.readFloat32(); this.bottom = stream.readFloat32(); this.top = stream.readFloat32(); this.name = stream.readNull(); this.creationNumber = stream.readUint32(); this.weatherEffectId = stream.readBinary(4); this.ambientSound = stream.readNull(); stream.readUint8Array(this.color); } save(stream: BinaryStream): void { stream.writeFloat32(this.left); stream.writeFloat32(this.right); stream.writeFloat32(this.bottom); stream.writeFloat32(this.top); stream.writeNull(this.name); stream.writeUint32(this.creationNumber); if (this.weatherEffectId) { stream.writeBinary(this.weatherEffectId); } else { stream.writeUint32(0); } stream.writeNull(this.ambientSound); stream.writeUint8Array(this.color); } getByteLength(): number { return 30 + byteLengthUtf8(this.name) + byteLengthUtf8(this.ambientSound); } } ================================================ FILE: src/parsers/w3x/w3s/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import Sound from './sound'; /** * war3map.w3s - the sound file. */ export default class War3MapW3s { version = 0; sounds: Sound[] = []; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const sound = new Sound(); sound.load(stream, this.version); this.sounds[i] = sound; } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); stream.writeUint32(this.sounds.length); for (const sound of this.sounds) { sound.save(stream, this.version); } return stream.uint8array; } getByteLength(): number { let size = 8; for (const sound of this.sounds) { size += sound.getByteLength(this.version); } return size; } } ================================================ FILE: src/parsers/w3x/w3s/index.ts ================================================ import File from './file'; import Sound from './sound'; export default { File, Sound, }; ================================================ FILE: src/parsers/w3x/w3s/sound.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A sound. */ export default class Sound { name = ''; file = ''; eaxEffect = ''; flags = 0; fadeInRate = 0; fadeOutRate = 0; volume = 0; pitch = 0; pitchVariance = 0; priority = 0; channel = 0; minDistance = 0; maxDistance = 0; distanceCutoff = 0; coneInside = 0; coneOutside = 0; coneOutsideVolume = 0; coneOrientationX = 0; coneOrientationY = 0; coneOrientationZ = 0; load(stream: BinaryStream, version: number): void { this.name = stream.readNull(); this.file = stream.readNull(); this.eaxEffect = stream.readNull(); this.flags = stream.readUint32(); this.fadeInRate = stream.readInt32(); this.fadeOutRate = stream.readInt32(); this.volume = stream.readInt32(); this.pitch = stream.readFloat32(); this.pitchVariance = stream.readFloat32(); this.priority = stream.readInt32(); this.channel = stream.readInt32(); this.minDistance = stream.readFloat32(); this.maxDistance = stream.readFloat32(); this.distanceCutoff = stream.readFloat32(); this.coneInside = stream.readFloat32(); this.coneOutside = stream.readFloat32(); this.coneOutsideVolume = stream.readInt32(); this.coneOrientationX = stream.readFloat32(); this.coneOrientationY = stream.readFloat32(); this.coneOrientationZ = stream.readFloat32(); if (version > 1) { if (version > 2) { } } } save(stream: BinaryStream, version: number): void { stream.writeNull(this.name); stream.writeNull(this.file); stream.writeNull(this.eaxEffect); stream.writeUint32(this.flags); stream.writeUint32(this.fadeInRate); stream.writeUint32(this.fadeOutRate); stream.writeUint32(this.volume); stream.writeFloat32(this.pitch); stream.writeFloat32(this.pitchVariance); stream.writeInt32(this.priority); stream.writeInt32(this.channel); stream.writeFloat32(this.minDistance); stream.writeFloat32(this.maxDistance); stream.writeFloat32(this.distanceCutoff); stream.writeFloat32(this.coneInside); stream.writeFloat32(this.coneOutside); stream.writeInt32(this.coneOutsideVolume); stream.writeFloat32(this.coneOrientationX); stream.writeFloat32(this.coneOrientationY); stream.writeFloat32(this.coneOrientationZ); if (version > 1) { if (version > 2) { } } } getByteLength(version: number): number { const size = 71 + byteLengthUtf8(this.name) + byteLengthUtf8(this.file) + byteLengthUtf8(this.eaxEffect); if (version > 1) { if (version > 2) { } } return size; } } ================================================ FILE: src/parsers/w3x/w3u/file.ts ================================================ import BinaryStream from "../../../common/binarystream"; import ModificationTable from "./modificationtable"; /** * war3map.w3u - the unit modification file. * * Also used for war3map.w3t (items), war3map.w3b (destructibles), and war3map.w3h (buffs). */ export default class War3MapW3u { version = 0; originalTable = new ModificationTable(); customTable = new ModificationTable(); load(bufferOrStream: ArrayBuffer | Uint8Array | BinaryStream): void { let stream; if (bufferOrStream instanceof BinaryStream) { stream = bufferOrStream; } else { stream = new BinaryStream(bufferOrStream); } this.version = stream.readInt32(); this.originalTable.load(stream, false, this.version); this.customTable.load(stream, false, this.version); } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); this.originalTable.save(stream, false, this.version); this.customTable.save(stream, false, this.version); return stream.uint8array; } getByteLength(): number { return ( 4 + this.originalTable.getByteLength(false, this.version) + this.customTable.getByteLength(false, this.version) ); } } ================================================ FILE: src/parsers/w3x/w3u/index.ts ================================================ import File from './file'; import ModificationTable from './modificationtable'; import ModificationObject from './modifiedobject'; import Modification from './modification'; export default { File, ModificationTable, ModificationObject, Modification, }; ================================================ FILE: src/parsers/w3x/w3u/modification.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A modification. */ export default class Modification { id = '\0\0\0\0'; variableType = 0; levelOrVariation = 0; dataPointer = 0; value: number | string = 0; u1 = 0; load(stream: BinaryStream, useOptionalInts: boolean): void { this.id = stream.readBinary(4); this.variableType = stream.readInt32(); if (useOptionalInts) { this.levelOrVariation = stream.readInt32(); this.dataPointer = stream.readInt32(); } if (this.variableType === 0) { this.value = stream.readInt32(); } else if (this.variableType === 1 || this.variableType === 2) { this.value = stream.readFloat32(); } else if (this.variableType === 3) { this.value = stream.readNull(); } else { throw new Error(`Modification: unknown variable type ${this.variableType}`); } this.u1 = stream.readInt32(); } save(stream: BinaryStream, useOptionalInts: boolean): void { stream.writeBinary(this.id); stream.writeInt32(this.variableType); if (useOptionalInts) { stream.writeInt32(this.levelOrVariation); stream.writeInt32(this.dataPointer); } if (this.variableType === 0) { stream.writeInt32(this.value); } else if (this.variableType === 1 || this.variableType === 2) { stream.writeFloat32(this.value); } else if (this.variableType === 3) { stream.writeNull(this.value); } else { throw new Error(`Modification: unknown variable type ${this.variableType}`); } stream.writeInt32(this.u1); } getByteLength(useOptionalInts: boolean): number { let size = 12; if (useOptionalInts) { size += 8; } if (this.variableType === 3) { size += byteLengthUtf8(this.value) + 1; } else { size += 4; } return size; } } ================================================ FILE: src/parsers/w3x/w3u/modificationtable.ts ================================================ import BinaryStream from "../../../common/binarystream"; import ModifiedObject from "./modifiedobject"; /** * A modification table. */ export default class ModificationTable { objects: ModifiedObject[] = []; load( stream: BinaryStream, useOptionalInts: boolean, formatVersion: number ): void { for (let i = 0, l = stream.readUint32(); i < l; i++) { const object = new ModifiedObject(); object.load(stream, useOptionalInts, formatVersion); this.objects[i] = object; } } save( stream: BinaryStream, useOptionalInts: boolean, formatVersion: number ): void { stream.writeUint32(this.objects.length); for (const object of this.objects) { object.save(stream, useOptionalInts, formatVersion); } } getByteLength(useOptionalInts: boolean, formatVersion: number): number { let size = 4; for (const object of this.objects) { size += object.getByteLength(useOptionalInts, formatVersion); } return size; } } ================================================ FILE: src/parsers/w3x/w3u/modifiedobject.ts ================================================ import BinaryStream from "../../../common/binarystream"; import Modification from "./modification"; /** * A modified object. */ export default class ModifiedObject { oldId = "\0\0\0\0"; newId = "\0\0\0\0"; sets = 1; setsFlag: number[] = []; modifications: Modification[] = []; load( stream: BinaryStream, useOptionalInts: boolean, formatVersion: number ): void { this.oldId = stream.readBinary(4); this.newId = stream.readBinary(4); if (formatVersion >= 3) { this.sets = stream.readUint32(); } for (let set = 0; set < this.sets; set++) { if (formatVersion >= 3) { this.setsFlag[set] = stream.readUint32(); } for (let i = 0, l = stream.readUint32(); i < l; i++) { const modification = new Modification(); modification.load(stream, useOptionalInts); this.modifications[i] = modification; } } } save( stream: BinaryStream, useOptionalInts: boolean, formatVersion: number ): void { if (this.oldId !== "\0\0\0\0") { stream.writeBinary(this.oldId); } else { stream.writeUint32(0); } if (this.newId !== "\0\0\0\0") { stream.writeBinary(this.newId); } else { stream.writeUint32(0); } if (formatVersion >= 3) { stream.writeUint32(this.sets); } stream.writeUint32(this.modifications.length); for (let set = 0; set < this.sets; set++) { if (formatVersion >= 3) { stream.writeUint32(this.setsFlag[set]); } for (const modification of this.modifications) { modification.save(stream, useOptionalInts); } } } getByteLength(useOptionalInts: boolean, formatVersion: number): number { let size = formatVersion >= 3 ? 16 : 12; for (let set = 0; set < this.sets; set++) { if (formatVersion >= 3) { size += 4; } for (const modification of this.modifications) { size += modification.getByteLength(useOptionalInts); } } return size; } } ================================================ FILE: src/parsers/w3x/wct/customtexttrigger.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A custom text trigger. */ export default class CustomTextTrigger { text = ''; load(stream: BinaryStream): void { const textLength = stream.readInt32(); if (textLength) { this.text = stream.read(textLength - 1); stream.skip(1); } } save(stream: BinaryStream): void { if (this.text.length) { stream.writeInt32(byteLengthUtf8(this.text) + 1); stream.write(this.text); stream.skip(1); } else { stream.writeInt32(0); } } getByteLength(): number { let size = 4; if (this.text.length) { size += byteLengthUtf8(this.text) + 1; } return size; } } ================================================ FILE: src/parsers/w3x/wct/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import CustomTextTrigger from './customtexttrigger'; /** * war3map.wct - the custom text (jass) trigger file. */ export default class War3MapWct { version = 0; comment = ''; trigger = new CustomTextTrigger(); triggers: CustomTextTrigger[] = []; load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); this.version = stream.readInt32(); if (this.version === 1) { this.comment = stream.readNull(); this.trigger.load(stream); } for (let i = 0, l = stream.readUint32(); i < l; i++) { const trigger = new CustomTextTrigger(); trigger.load(stream); this.triggers[i] = trigger; } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeInt32(this.version); if (this.version === 1) { stream.writeNull(this.comment); this.trigger.save(stream); } stream.writeUint32(this.triggers.length); for (const trigger of this.triggers) { trigger.save(stream); } return stream.uint8array; } getByteLength(): number { let size = 8; if (this.version === 1) { size += byteLengthUtf8(this.comment) + 1 + this.trigger.getByteLength(); } for (const trigger of this.triggers) { size += trigger.getByteLength(); } return size; } } ================================================ FILE: src/parsers/w3x/wct/index.ts ================================================ import File from './file'; import CustomTextTrigger from './customtexttrigger'; export default { File, CustomTextTrigger, }; ================================================ FILE: src/parsers/w3x/wpm/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; /** * war3map.wpm - the pathing file. */ export default class War3MapWpm { version = 0; size = new Int32Array(2); pathing = new Uint8Array(0); load(buffer: ArrayBuffer | Uint8Array): void { const stream = new BinaryStream(buffer); if (stream.readBinary(4) !== 'MP3W') { return; } this.version = stream.readInt32(); stream.readInt32Array(this.size); this.pathing = stream.readUint8Array(this.size[0] * this.size[1]); } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeBinary('MP3W'); stream.writeInt32(this.version); stream.writeInt32Array(this.size); stream.writeUint8Array(this.pathing); return stream.uint8array; } getByteLength(): number { return 16 + (this.size[0] * this.size[1]); } } ================================================ FILE: src/parsers/w3x/wpm/index.ts ================================================ import File from './file'; export default { File, }; ================================================ FILE: src/parsers/w3x/wtg/eca.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import Parameter from './parameter'; import { TriggerData } from './triggerdata'; /** * An Event/Condition/Action. */ export default class ECA { type = -1; group = -1; name = ''; isEnabled = 0; parameters: Parameter[] = []; ecas: ECA[] = []; load(stream: BinaryStream, version: number, isChildECA: boolean, triggerData: TriggerData): void { this.type = stream.readInt32(); if (this.type < 0 || this.type > 3) { throw new Error(`ECA: Bad type: ${this.type}`); } if (isChildECA) { this.group = stream.readUint32(); } this.name = stream.readNull(); if (this.name.length === 0) { throw new Error('ECA: Empty name'); } this.isEnabled = stream.readInt32(); const signature = triggerData.getFunction(this.type, this.name); if (!signature) { throw new Error(`ECA "${this.name}:${this.type}": Unknown signature`); } const args = signature.args; for (let i = 0, l = args.length; i < l; i++) { const parameter = new Parameter(); try { parameter.load(stream, version, triggerData); } catch (e) { throw new Error(`ECA "${this.name}": Parameter ${i}: ${e}`); } this.parameters[i] = parameter; } if (version === 7) { for (let i = 0, l = stream.readUint32(); i < l; i++) { const eca = new ECA(); try { eca.load(stream, version, true, triggerData); } catch (e) { throw new Error(`ECA "${this.name}": Child ECA ${i} ${e}`); } this.ecas[i] = eca; } } } save(stream: BinaryStream, version: number): void { stream.writeInt32(this.type); if (this.group !== -1) { stream.writeInt32(this.group); } stream.writeNull(this.name); stream.writeInt32(this.isEnabled); for (const parameter of this.parameters) { parameter.save(stream, version); } if (version === 7) { stream.writeUint32(this.ecas.length); for (const eca of this.ecas) { eca.save(stream, version); } } } getByteLength(version: number): number { let size = 9 + byteLengthUtf8(this.name); if (this.group !== -1) { size += 4; } for (const parameter of this.parameters) { size += parameter.getByteLength(version); } if (version === 7) { size += 4; for (const eca of this.ecas) { size += eca.getByteLength(version); } } return size; } } ================================================ FILE: src/parsers/w3x/wtg/file.ts ================================================ import BinaryStream from '../../../common/binarystream'; import TriggerCategory from './triggercategory'; import Variable from './variable'; import Trigger from './trigger'; import { TriggerData } from './triggerdata'; /** * war3map.wtg - the trigger file. */ export default class War3MapWtg { version = 0; categories: TriggerCategory[] = []; u1 = 0; variables: Variable[] = []; triggers: Trigger[] = []; load(buffer: ArrayBuffer | Uint8Array, triggerData: TriggerData): void { const stream = new BinaryStream(buffer); if (stream.readBinary(4) !== 'WTG!') { throw new Error('Not a WTG file'); } this.version = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const category = new TriggerCategory(); category.load(stream, this.version); this.categories[i] = category; } this.u1 = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const variable = new Variable(); variable.load(stream, this.version); this.variables[i] = variable; } for (let i = 0, l = stream.readUint32(); i < l; i++) { const trigger = new Trigger(); try { trigger.load(stream, this.version, triggerData); } catch (e) { throw new Error(`Trigger ${i}: ${e}`); } this.triggers[i] = trigger; } } save(): Uint8Array { const stream = new BinaryStream(new ArrayBuffer(this.getByteLength())); stream.writeBinary('WTG!'); stream.writeInt32(this.version); stream.writeUint32(this.categories.length); for (const category of this.categories) { category.save(stream, this.version); } stream.writeInt32(this.u1); stream.writeUint32(this.variables.length); for (const variable of this.variables) { variable.save(stream, this.version); } stream.writeUint32(this.triggers.length); for (const trigger of this.triggers) { trigger.save(stream, this.version); } return stream.uint8array; } getByteLength(): number { let size = 24; const version = this.version; for (const category of this.categories) { size += category.getByteLength(version); } for (const variable of this.variables) { size += variable.getByteLength(version); } for (const trigger of this.triggers) { size += trigger.getByteLength(version); } return size; } } ================================================ FILE: src/parsers/w3x/wtg/index.ts ================================================ import File from './file'; import TriggerCategory from './triggercategory'; import Variable from './variable'; import Trigger from './trigger'; import ECA from './eca'; import Parameter from './parameter'; import SubParameters from './subparameters'; import { TriggerData } from './triggerdata'; export default { File, TriggerCategory, Variable, Trigger, ECA, Parameter, SubParameters, TriggerData, }; ================================================ FILE: src/parsers/w3x/wtg/parameter.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import SubParameters from './subparameters'; import { TriggerData } from './triggerdata'; /** * A function parameter. Can be a function itself, in which case it will have a SubParameters structure. */ export default class Parameter { type = 0; value = ''; subParameters: SubParameters | null = null; u1 = 0; isArray = 0; arrayIndex: Parameter | null = null; load(stream: BinaryStream, version: number, triggerData: TriggerData): void { this.type = stream.readInt32(); if (this.type < -1 || this.type > 3) { throw new Error(`Parameter: Bad type: ${this.type}`); } this.value = stream.readNull(); if (stream.readInt32()) { const subParameters = new SubParameters(); try { subParameters.load(stream, version, triggerData); } catch (e) { throw new Error(`Parameter "${this.value}": SubParameters ${e}`); } this.subParameters = subParameters; } if ((version === 4 && this.type === 2) || (version === 7 && this.subParameters)) { this.u1 = stream.readInt32(); } if ((version === 4 && this.type !== 2) || version === 7) { this.isArray = stream.readInt32(); } if (this.isArray) { const arrayIndex = new Parameter(); try { arrayIndex.load(stream, version, triggerData); } catch (e) { throw new Error(`Parameter "${this.value}": ArrayIndex: ${e}`); } this.arrayIndex = arrayIndex; } } save(stream: BinaryStream, version: number): void { stream.writeInt32(this.type); stream.writeNull(this.value); if (this.subParameters) { stream.writeInt32(1); this.subParameters.save(stream, version); } else { stream.writeInt32(0); } if ((version === 4 && this.type === 2) || (version === 7 && this.subParameters)) { stream.writeInt32(this.u1); } if ((version === 4 && this.type !== 2) || version === 7) { stream.writeInt32(this.isArray); } if (this.isArray && this.arrayIndex) { this.arrayIndex.save(stream, version); } } getByteLength(version: number): number { let size = 9 + byteLengthUtf8(this.value); if (this.subParameters) { size += this.subParameters.getByteLength(version); } if ((version === 4 && this.type === 2) || (version === 7 && this.subParameters)) { size += 4; } if ((version === 4 && this.type !== 2) || version === 7) { size += 4; } if (this.isArray && this.arrayIndex) { size += this.arrayIndex.getByteLength(version); } return size; } } ================================================ FILE: src/parsers/w3x/wtg/subparameters.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import Parameter from './parameter'; import { TriggerData } from './triggerdata'; /** * A function call in an expression. */ export default class SubParameters { type = 0; name = ''; beginParameters = 0; parameters: Parameter[] = []; load(stream: BinaryStream, version: number, triggerData: TriggerData): void { this.type = stream.readInt32(); if (this.type < 0 || this.type > 3) { throw new Error(`SubParameters: Bad type: ${this.type}`); } this.name = stream.readNull(); if (this.name.length === 0) { throw new Error(`SubParameters: Empty name`); } this.beginParameters = stream.readInt32(); if (this.beginParameters) { const signature = triggerData.getFunction(this.type, this.name); if (!signature) { throw new Error(`SubParameters "${this.name}:${this.type}": Unknown signature`); } const args = signature.args; for (let i = 0, l = args.length; i < l; i++) { const parameter = new Parameter(); try { parameter.load(stream, version, triggerData); } catch (e) { throw new Error(`SubParameters "${this.name}": Parameter ${i}: ${e}`); } this.parameters[i] = parameter; } } } save(stream: BinaryStream, version: number): void { stream.writeInt32(this.type); stream.writeNull(this.name); stream.writeInt32(this.beginParameters); for (const parameter of this.parameters) { parameter.save(stream, version); } } getByteLength(version: number): number { let size = 9 + byteLengthUtf8(this.name); if (this.parameters.length) { for (const parameter of this.parameters) { size += parameter.getByteLength(version); } } return size; } } ================================================ FILE: src/parsers/w3x/wtg/trigger.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; import ECA from './eca'; import { TriggerData } from './triggerdata'; /** * A GUI Trigger. */ export default class Trigger { name = ''; description = ''; isComment = 0; isEnabled = 0; isCustom = 0; isInitiallyOff = 0; runOnInitialization = 0; category = 0; ecas: ECA[] = []; load(stream: BinaryStream, version: number, triggerData: TriggerData): void { this.name = stream.readNull(); this.description = stream.readNull(); if (version === 7) { this.isComment = stream.readInt32(); } this.isEnabled = stream.readInt32(); this.isCustom = stream.readInt32(); this.isInitiallyOff = stream.readInt32(); this.runOnInitialization = stream.readInt32(); this.category = stream.readInt32(); for (let i = 0, l = stream.readUint32(); i < l; i++) { const eca = new ECA(); try { eca.load(stream, version, false, triggerData); } catch (e) { throw new Error(`Trigger "${this.name}": ECA ${i}: ${e}`); } this.ecas[i] = eca; } } save(stream: BinaryStream, version: number): void { stream.writeNull(this.name); stream.writeNull(this.description); if (version === 7) { stream.writeInt32(this.isComment); } stream.writeInt32(this.isEnabled); stream.writeInt32(this.isCustom); stream.writeInt32(this.isInitiallyOff); stream.writeInt32(this.runOnInitialization); stream.writeInt32(this.category); stream.writeUint32(this.ecas.length); for (const eca of this.ecas) { eca.save(stream, version); } } getByteLength(version: number): number { let size = 26 + byteLengthUtf8(this.name) + byteLengthUtf8(this.description); if (version === 7) { size += 4; } for (const eca of this.ecas) { size += eca.getByteLength(version); } return size; } } ================================================ FILE: src/parsers/w3x/wtg/triggercategory.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A Trigger category. * * Used to scope triggers together in a Folder-like hierarchy. */ export default class TriggerCategory { id = 0; name = ''; isComment = 0; load(stream: BinaryStream, version: number): void { this.id = stream.readInt32(); this.name = stream.readNull(); if (version === 7) { this.isComment = stream.readInt32(); } } save(stream: BinaryStream, version: number): void { stream.writeInt32(this.id); stream.writeNull(this.name); if (version === 7) { stream.writeInt32(this.isComment); } } getByteLength(version: number): number { let size = 5 + byteLengthUtf8(this.name); if (version === 7) { size += 4; } return size; } } ================================================ FILE: src/parsers/w3x/wtg/triggerdata.ts ================================================ import TokenStream from '../../../utils/jass2/tokenstream'; import { IniSection, IniFile } from '../../ini/file'; /** * A standard object mapping strings to strings. */ export type StringObject = {[key: string]: string }; export type FunctionSignature = { args: string[], scriptName: string | null, returnType: string | null }; /** * A standard object mapping strings to function signatures and an optional Jass name. */ export type FunctionObject = {[key: string]: FunctionSignature }; /** * Trigger data needed to load a WTG file. */ export class TriggerData { types: StringObject = {}; functions: FunctionObject[] = [{}, {}, {}, {}]; presets: StringObject = {}; externalTypes: StringObject = {}; externalFunctions: FunctionObject[] = [{}, {}, {}, {}]; externalPresets: StringObject = {}; addTriggerData(buffer: string, isExternal: boolean): void { let types = this.types; let functions = this.functions; let presets = this.presets; if (isExternal) { types = this.externalTypes; functions = this.externalFunctions; presets = this.externalPresets; } const triggerData = new IniFile(); triggerData.load(buffer); let section = triggerData.getSection('TriggerTypes'); if (section) { this.addTriggerTypes(types, section); } section = triggerData.getSection('TriggerEvents'); if (section) { this.addTriggerDataFunctions(functions[0], section, 1); } section = triggerData.getSection('TriggerConditions'); if (section) { this.addTriggerDataFunctions(functions[1], section, 1); } section = triggerData.getSection('TriggerActions'); if (section) { this.addTriggerDataFunctions(functions[2], section, 1); } section = triggerData.getSection('TriggerCalls'); if (section) { this.addTriggerDataFunctions(functions[3], section, 3); } section = triggerData.getSection('TriggerParams'); if (section) { this.addTriggerDataPresets(presets, section); } } addTriggerTypes(types: StringObject, section: IniSection): void { for (const [key, value] of section) { // We know the values are going to be strings. const tokens = value.split(','); types[key.toLowerCase()] = tokens[4] || ''; } } addTriggerDataFunctions(functions: FunctionObject, section: IniSection, skipped: number): void { for (const [key, value] of section) { // We don't care about metadata lines. if (key[0] !== '_') { // We know the values are going to be strings. const tokens = value.split(','); const args = []; // Can be used by actions to make aliases. const scriptName = section.get(`_${key}_scriptname`) || null; let returnType = null; // TriggerCalls have a return type. if (skipped === 3) { returnType = tokens[2]; } for (let i = skipped, l = tokens.length; i < l; i++) { const token = tokens[i]; // We don't care about constants. if (Number.isNaN(parseFloat(token)) && token !== 'nothing' && token !== '') { args.push(token); } } functions[key.toLowerCase()] = { args, scriptName, returnType }; } } } addTriggerDataPresets(presets: StringObject, section: IniSection): void { for (const [key, value] of section) { // We know the values are going to be strings. const tokens = value.split(','); // Note that the operators are enclosed by "" for some reason. // Note that string literals are enclosed by backticks. presets[key.toLowerCase()] = tokens[2].replace(/"/g, '').replace(/`/g, '"'); } } addJassFunctions(jass: string): void { const stream = new TokenStream(jass); let token; while ((token = stream.read()) !== undefined) { if (token === 'native' || token === 'function') { const scriptName = stream.read(); if (scriptName) { token = stream.read(); if (token === 'takes') { const args = []; const token = stream.readSafe(); // nothing or type if (token !== 'nothing') { args.push(token); stream.readSafe(); while (stream.read() === ',') { args.push(stream.readSafe()); stream.readSafe(); } } else { stream.read(); // returns } let returnType: string | null = stream.readSafe(); if (returnType === 'nothing') { returnType = null; } const name = scriptName.toLowerCase(); const signature = { args, scriptName, returnType }; // There is no way to know if this signature could be used as a TriggerAction or TriggerCall. // So try to always add to TriggerAction... this.externalFunctions[2][name] = signature; // ...and if there is a return type, add also to TriggerCall. if (returnType !== 'nothing') { this.externalFunctions[3][name] = signature; } } } } } } /** * Given a type, return its base type. * * Returns the given type if its not a child type. */ getBaseType(type: string): string { type = type.toLowerCase(); let base = this.types[type]; if (base === undefined) { base = this.externalTypes[type]; } // Same as !base, but be explicit to be clearer. if (base === '' || base === undefined) { return type; } return base; } isBaseFunction(type: number, name: string): boolean { name = name.toLowerCase(); if (this.functions[type][name]) { return true; } return false; } /** * Gets the signature of the given function. */ getFunction(type: number, name: string): FunctionSignature { name = name.toLowerCase(); let args = this.functions[type][name]; if (!args) { args = this.externalFunctions[type][name]; } return args; } /** * Get the type of a function given its name. * Returns -1 if the function isn't recognized. */ getFunctionType(name: string): number { name = name.toLowerCase(); const functions = this.functions; for (let i = 0; i < 4; i++) { if (functions[i][name]) { return i; } } return -1; } /** * Gets a preset value. */ getPreset(name: string): string { name = name.toLowerCase(); let preset = this.presets[name]; if (preset === undefined) { preset = this.externalPresets[name]; } return preset; } /** * Is the given preset a custom or standard one? */ isCustomPreset(name: string): boolean { name = name.toLowerCase(); if (this.presets[name] !== undefined) { return false; } if (this.externalPresets[name] !== undefined) { return true; } throw new Error(`Failed to find a preset: ${name}`); } } ================================================ FILE: src/parsers/w3x/wtg/variable.ts ================================================ import BinaryStream from '../../../common/binarystream'; import { byteLengthUtf8 } from '../../../common/utf8'; /** * A global variable. */ export default class Variable { name = ''; type = ''; u1 = 0; isArray = 0; arraySize = 0; isInitialized = 0; initialValue = ''; load(stream: BinaryStream, version: number): void { this.name = stream.readNull(); this.type = stream.readNull(); this.u1 = stream.readInt32(); this.isArray = stream.readInt32(); if (version === 7) { this.arraySize = stream.readInt32(); } this.isInitialized = stream.readInt32(); this.initialValue = stream.readNull(); } save(stream: BinaryStream, version: number): void { stream.writeNull(this.name); stream.writeNull(this.type); stream.writeInt32(this.u1); stream.writeInt32(this.isArray); if (version === 7) { stream.writeInt32(this.arraySize); } stream.writeInt32(this.isInitialized); stream.writeNull(this.initialValue); } getByteLength(version: number): number { let size = 15 + byteLengthUtf8(this.name) + byteLengthUtf8(this.type) + byteLengthUtf8(this.initialValue); if (version === 7) { size += 4; } return size; } } ================================================ FILE: src/parsers/w3x/wts/file.ts ================================================ import TokenStream from '../../mdlx/tokenstream'; /** * war3map.wts - the string table file. * * Contains a map of number->string. * When other map data like triggers use the string TRIGSTR_XXX, where XXX is a number, the value will be fetched from the table. */ export default class War3MapWts { stringMap: Map = new Map(); load(buffer: string): void { const stream = new TokenStream(buffer); let token; // Find the first instance of "STRING". // There are some weird war3map.wts files that begin with the bytes "", and this causes the tokenizer to see the first token as "STRING". // Going to the first "STRING" means we can ignore any weird bytes that happened to be before. const start = buffer.indexOf('STRING'); // Can war3map.wts have no entries? I don't know, might as well add a condition. if (start === -1) { throw new Error('Not a valid war3map.wts buffer'); } stream.index = start; while ((token = stream.readToken())) { if (token === 'STRING') { const index = stream.readInt(); stream.read(); // { const end = buffer.indexOf('}', stream.index); // For broken files, keep whatever data can be kept, and throw an exception. if (end === -1) { this.stringMap.set(index, buffer.slice(stream.index, buffer.length).trim()); throw new Error(`WTS: missing data in string ${this.stringMap.size} (and maybe more)`); } this.stringMap.set(index, buffer.slice(stream.index, end).trim()); stream.index = end; } } } save(): string { let buffer = ''; for (const [key, value] of this.stringMap) { buffer += `STRING ${key}\r\n{\r\n${value}\r\n}\r\n\r\n`; } return buffer; } /** * Get the string at the given index. * * Strings in the form "TRIGSTR_nnn" are also supported. */ getString(index: number | string): string | undefined { if (typeof index === 'string') { if (index.startsWith('TRIGSTR_')) { return this.stringMap.get(parseInt(index.slice(8))); } } else { return this.stringMap.get(index); } return; } /** * Set the string at the given index. * * Strings in the form "TRIGSTR_nnn" are also supported. */ setString(index: number | string, value: string): void { if (typeof index === 'string') { if (index.startsWith('TRIGSTR_')) { this.stringMap.set(parseInt(index.slice(8)), value); } } else { this.stringMap.set(index, value); } } } ================================================ FILE: src/parsers/w3x/wts/index.ts ================================================ import File from './file'; export default { File, }; ================================================ FILE: src/utils/blp/index.ts ================================================ import sanityTest from './sanitytest'; export default { sanityTest, }; ================================================ FILE: src/utils/blp/sanitytest.ts ================================================ import { isPowerOfTwo } from '../../common/math'; import { BlpImage } from '../../parsers/blp/image'; /** * Some tools allow to setup fake mipmaps. * These are mipmaps that use the same JPG data as other mipmaps. * This is technically not valid, but can work properly in the game. * Not always though. * Sadly I don't quite know the rules. */ function isMipmapFake(whichMipmap: number, mipmapOffsets: Uint32Array): boolean { const offset = mipmapOffsets[whichMipmap]; for (let i = 0; i < whichMipmap; i++) { if (mipmapOffsets[i] === offset) { return true; } } return false; } export interface SanityTestNode { type: string; message: string; } export interface SanityTestResult { nodes: SanityTestNode[]; warnings: number; } /** * Tests for issues in BLP textures. */ export default function sanityTest(texture: BlpImage): SanityTestResult { const nodes = []; const content = texture.content; const alphaBits = texture.alphaBits; const mipmapOffsets = texture.mipmapOffsets; const mipmapSizes = texture.mipmapSizes; let width = texture.width; let height = texture.height; if (content !== 0 && content !== 1) { nodes.push({ type: 'warning', message: 'Unknown content type' }); } if (alphaBits !== 0 && alphaBits !== 1 && alphaBits !== 4 && alphaBits !== 8) { nodes.push({ type: 'warning', message: `Expected alpha bits to be 0, 1, 4, or 8, but got ${alphaBits}` }); } if (width > 512 || height > 512) { nodes.push({ type: 'warning', message: `Expected width and height up to 512, but got ${width}x${height}` }); } if (content === 0) { const jpgHeader = texture.jpgHeader; if (jpgHeader.length > 624) { nodes.push({ type: 'warning', message: `Expected the JPG header to be at most 624 bytes, but got ${jpgHeader.length}` }); } } if (!isPowerOfTwo(width) || !isPowerOfTwo(height)) { nodes.push({ type: 'warning', message: `Expected the width and height to be powers of two, but got ${width}x${height}` }); } for (let i = 0; i < 16; i++) { if (mipmapSizes[i] > 0) { // This happens if this mipmap level supposedly exists, but we already passed the level that should have been last. if (width < 1 && height < 1) { nodes.push({ type: 'warning', message: `Mipmap ${i}: this mipmap should not exist` }); } else if (isMipmapFake(i, mipmapOffsets)) { nodes.push({ type: 'warning', message: `Mipmap ${i}: this mipmap is fake` }); } else { // In the case this is not a square texture, one dimension will get to size 1 before the other. width = Math.max(width, 1); height = Math.max(height, 1); let mipmapData; try { mipmapData = texture.getMipmap(i); } catch (e) { nodes.push({ type: 'warning', message: `Mipmap ${i}: Decoding failed` }); } if (mipmapData) { if (content === 0) { if (mipmapData.width !== width || mipmapData.height !== height) { nodes.push({ type: 'warning', message: `Mipmap ${i}: the JPG width (${mipmapData.width}) and height (${mipmapData.height}) do not match the mipmap width (${width}) and height (${height})` }); } } else if (content === 1) { const pixels = width * height; const size = pixels + Math.ceil((pixels * alphaBits) / 8); if (size !== mipmapSizes[i]) { nodes.push({ type: 'warning', message: `Mipmap ${i}: the declared size is ${mipmapSizes[i]}, but the real size is ${size}` }); } } } } } width >>= 1; height >>= 1; } return { nodes, warnings: nodes.length }; } ================================================ FILE: src/utils/dds/index.ts ================================================ import sanityTest from './sanitytest'; export default { sanityTest, }; ================================================ FILE: src/utils/dds/sanitytest.ts ================================================ import { isPowerOfTwo } from '../../common/math'; import { DdsImage } from '../../parsers/dds/image'; export interface SanityTestNode { type: string; message: string; } export interface SanityTestResult { nodes: SanityTestNode[]; warnings: number; } /** * Tests for issues in DDS textures. */ export default function sanityTest(texture: DdsImage): SanityTestResult { const nodes = []; const width = texture.width; const height = texture.height; const mipmaps = texture.mipmaps(); const expectedMipmaps = Math.log2(Math.max(width, height)); if (mipmaps < expectedMipmaps) { nodes.push({ type: 'warning', message: `Expected ${expectedMipmaps} mipmaps, but got ${mipmaps}` }); } if ((width % 4 !== 0) || (height % 4 !== 0)) { nodes.push({ type: 'warning', message: `Expected the width and height to be multiples of four, but got ${width}x${height}` }); } if (!isPowerOfTwo(width) || !isPowerOfTwo(height)) { nodes.push({ type: 'warning', message: `Expected the width and height to be powers of two, but got ${width}x${height}` }); } for (let i = 0; i < mipmaps; i++) { try { texture.getMipmap(i); } catch (e) { nodes.push({ type: 'warning', message: `Mipmap ${i}: Decoding failed` }); } } return { nodes, warnings: nodes.length }; } ================================================ FILE: src/utils/index.ts ================================================ import blp from './blp'; import dds from './dds'; import { MappedData } from './mappeddata'; import jass2 from './jass2'; import mdlx from './mdlx'; import w3x from './w3x'; export default { blp, dds, MappedData, jass2, mdlx, w3x, }; ================================================ FILE: src/utils/jass2/compilenatives.ts ================================================ import TokenStream from './tokenstream'; function compileGetters(params: { type: string, name: string }[]): string { return params.map((p, i) => { const type = p.type; if (type === 'code') { return `let _${p.name} = luaL_ref(L, LUA_REGISTRYINDEX);`; } else { let func; if (type === 'integer') { func = 'luaL_checkinteger'; } else if (type === 'real') { func = 'luaL_checknumber'; } else if (type === 'boolean') { func = 'lua_toboolean'; } else if (type === 'string') { func = 'luaL_checkstring'; } else { func = 'lua_touserdata'; } return `let _${p.name} = ${func}(L, ${i + 1});`; } }).join('\n'); } function compileReturn(type: string): string { if (type === 'nothing') { return 'return 0'; } else { let func; let value; if (type === 'integer') { func = 'lua_pushinteger'; value = '0'; } else if (type === 'real') { func = 'lua_pushnumber'; value = '0'; } else if (type === 'boolean') { func = 'lua_pushboolean'; value = 'false'; } else if (type === 'string') { func = 'lua_pushstring'; value = `''`; } else if (type === 'code') { throw 'CODE??'; } else { func = 'lua_pushlightuserdata'; value = `{name: 'FAKE'}`; } return `${func}(L, ${value});\nreturn 1;`; } } function compileNative(stream: TokenStream, isConstant: boolean): { name: string, decl: string } { const name = stream.readSafe(); const params = []; stream.read(); // takes const token = stream.readSafe(); // nothing or type if (token !== 'nothing') { params.push({ type: token, name: stream.readSafe() }); while (stream.read() === ',') { params.push({ type: stream.readSafe(), name: stream.readSafe() }); } } else { stream.read(); // returns } const returnType = stream.readSafe(); let luaParams; if (params.length) { luaParams = 'C: Context, L: lua_State'; } else { luaParams = '_C: Context, _L: lua_State'; } const decl = ` /** * ${isConstant ? 'constant ' : ''}native ${name} takes ${params.length ? params.map((p) => `${p.type} ${p.name}`).join(', ') : 'nothing'} returns ${returnType} */ function ${name}(${luaParams}): number { ${compileGetters(params)} console.warn('${name} was called but is not implemented :('); ${compileReturn(returnType)} }`; return { name, decl }; } function compileBindings(names: string[]): string { return ` /** * Bind natives to the given context. */ export default function bind(C: Context): void {\nlet L = C.L;\n${names.map((name) => ` lua_register(L, '${name}', ${name}.bind(null, C));`).join('\n')}\n}`; } export default function compileNatives(jass: string): string { const stream = new TokenStream(jass); const names = []; const decls = []; let token; while ((token = stream.read()) !== undefined) { let isConstant = false; if (token === 'constant') { isConstant = true; token = stream.read(); } if (token === 'native') { const { name, decl } = compileNative(stream, isConstant); names.push(name); decls.push(decl); } } return `${decls.join('\n')}\n${compileBindings(names)}\n`; } ================================================ FILE: src/utils/jass2/constanthandles.ts ================================================ import JassPlayerColor from './types/playercolor'; import JassRace from './types/race'; import JassPlayerGameResult from './types/playergameresult'; import JassAllianceType from './types/alliancetype'; import JassVersion from './types/version'; import JassAttackType from './types/attacktype'; import JassDamageType from './types/damagetype'; import JassWeaponType from './types/weapontype'; import JassPathingType from './types/pathingtype'; import JassMouseButtonType from './types/mousebuttontype'; import JassAnimType from './types/animtype'; import JassSubAnimType from './types/subanimtype'; import JassRacePreference from './types/racepreference'; import JassMapControl from './types/mapcontrol'; import JassGameType from './types/gametype'; import JassMapFlag from './types/mapflag'; import JassPlacement from './types/placement'; import JassStartLocPrio from './types/startlocprio'; import JassMapDensity from './types/mapdensity'; import JassGameDifficulty from './types/gamedifficulty'; import JassGameSpeed from './types/gamespeed'; import JassPlayerSlotState from './types/playerslotstate'; import JassVolumeGroup from './types/volumegroup'; import JassIGameState from './types/igamestate'; import JassFGameState from './types/fgamestate'; import JassPlayerState from './types/playerstate'; import JassUnitState from './types/unitstate'; import JassAiDifficulty from './types/aidifficulty'; import JassPlayerScore from './types/playerscore'; import JassGameEvent from './types/gameevent'; import JassPlayerEvent from './types/playerevent'; import JassPlayerUnitEvent from './types/playerunitevent'; import JassUnitEvent from './types/unitevent'; import JassWidgetEvent from './types/widgetevent'; import JassDialogEvent from './types/dialogevent'; import JassLimitOp from './types/limitop'; import JassUnitType from './types/unittype'; import JassItemType from './types/itemtype'; import JassCameraField from './types/camerafield'; import JassBlendMode from './types/blendmode'; import JassRarityControl from './types/raritycontrol'; import JassTexMapFlags from './types/texmapflags'; import JassFogState from './types/fogstate'; import JassEffectType from './types/effecttype'; import JassSoundType from './types/soundtype'; import { JassEventId, JassGameState } from './types'; export interface ConstantHandles { playerColors: JassPlayerColor[]; races: JassRace[]; playerGameResults: JassPlayerGameResult[]; allianceTypes: JassAllianceType[]; versions: JassVersion[]; attackTypes: JassAttackType[]; damageTypes: JassDamageType[]; weaponTypes: JassWeaponType[]; pathingTypes: JassPathingType[]; mouseButtonTypes: JassMouseButtonType[]; animTypes: JassAnimType[]; subAnimTypes: JassSubAnimType[]; racePrefs: JassRacePreference[]; mapControls: JassMapControl[]; gameTypes: JassGameType[]; mapFlags: JassMapFlag[]; placements: JassPlacement[]; startLocPrios: JassStartLocPrio[]; mapDensities: JassMapDensity[]; gameDifficulties: JassGameDifficulty[]; gameSpeeds: JassGameSpeed[]; playerSlotStates: JassPlayerSlotState[]; volumeGroups: JassVolumeGroup[]; gameStates: JassGameState[]; playerStates: JassPlayerState[]; unitStates: JassUnitState[]; aiDifficulties: JassAiDifficulty[]; playerScores: JassPlayerScore[]; events: JassEventId[]; limitOps: JassLimitOp[]; unitTypes: JassUnitType[]; itemTypes: JassItemType[]; cameraFields: JassCameraField[]; blendModes: JassBlendMode[]; rarityControls: JassRarityControl[]; texMapFlags: JassTexMapFlags[]; fogStates: JassFogState[]; effectTypes: JassEffectType[]; soundTypes: JassSoundType[]; } export default function constantHandles(): ConstantHandles { const playerColors = []; const races = []; const playerGameResults = []; const allianceTypes = []; const versions = []; const attackTypes = []; const damageTypes = []; const weaponTypes = []; const pathingTypes = []; const mouseButtonTypes = []; const animTypes = []; const subAnimTypes = []; const racePrefs = []; const mapControls = []; const gameTypes = []; const mapFlags = []; const placements = []; const startLocPrios = []; const mapDensities = []; const gameDifficulties = []; const gameSpeeds = []; const playerSlotStates = []; const volumeGroups = []; const gameStates = []; const playerStates = []; const unitStates = []; const aiDifficulties = []; const playerScores = []; const events = []; const limitOps = []; const unitTypes = []; const itemTypes = []; const cameraFields = []; const blendModes = []; const rarityControls = []; const texMapFlags = []; const fogStates = []; const effectTypes = []; const soundTypes = []; for (let i = 0; i < 24; i++) { playerColors[i] = new JassPlayerColor(i); } for (let i = 0; i < 8; i++) { races[i] = new JassRace(i); } for (let i = 0; i < 4; i++) { playerGameResults[i] = new JassPlayerGameResult(i); } for (let i = 0; i < 10; i++) { allianceTypes[i] = new JassAllianceType(i); } for (let i = 0; i < 2; i++) { versions[i] = new JassVersion(i); } for (let i = 0; i < 7; i++) { attackTypes[i] = new JassAttackType(i); } for (let i = 0; i < 27; i++) { // Note: 1, 2, 3, 6, and 7 not exposed in common.j damageTypes[i] = new JassDamageType(i); } for (let i = 0; i < 24; i++) { weaponTypes[i] = new JassWeaponType(i); } for (let i = 0; i < 8; i++) { pathingTypes[i] = new JassPathingType(i); } for (let i = 0; i < 4; i++) { mouseButtonTypes[i] = new JassMouseButtonType(i); } for (let i = 0; i < 11; i++) { animTypes[i] = new JassAnimType(i); } for (let i = 11; i < 63; i++) { subAnimTypes[i] = new JassSubAnimType(i); } for (let i = 0; i < 8; i++) { const p = Math.pow(2, i); racePrefs[p] = new JassRacePreference(p); } for (let i = 0; i < 6; i++) { mapControls[i] = new JassMapControl(i); } for (let i = 0; i < 8; i++) { const p = Math.pow(2, i); gameTypes[p] = new JassGameType(p); } for (let i = 0; i < 20; i++) { const p = Math.pow(2, i); mapFlags[p] = new JassMapFlag(p); } for (let i = 0; i < 4; i++) { placements[i] = new JassPlacement(i); } for (let i = 0; i < 3; i++) { startLocPrios[i] = new JassStartLocPrio(i); } for (let i = 0; i < 4; i++) { mapDensities[i] = new JassMapDensity(i); } for (let i = 0; i < 4; i++) { gameDifficulties[i] = new JassGameDifficulty(i); } for (let i = 0; i < 5; i++) { gameSpeeds[i] = new JassGameSpeed(i); } for (let i = 0; i < 3; i++) { playerSlotStates[i] = new JassPlayerSlotState(i); } for (let i = 0; i < 8; i++) { volumeGroups[i] = new JassVolumeGroup(i); } for (let i = 0; i < 2; i++) { gameStates[i] = new JassIGameState(i); } for (let i = 2; i < 3; i++) { gameStates[i] = new JassFGameState(i); } for (let i = 0; i < 26; i++) { // Note: 17-24 not exposed in common.j playerStates[i] = new JassPlayerState(i); } for (let i = 0; i < 4; i++) { unitStates[i] = new JassUnitState(i); } for (let i = 0; i < 3; i++) { aiDifficulties[i] = new JassAiDifficulty(i); } for (let i = 0; i < 25; i++) { playerScores[i] = new JassPlayerScore(i); } for (let i = 0; i < 11; i++) { events[i] = new JassGameEvent(i); } for (let i = 11; i < 18; i++) { events[i] = new JassPlayerEvent(i); } for (let i = 18; i < 52; i++) { events[i] = new JassPlayerUnitEvent(i); } for (let i = 52; i < 89; i++) { events[i] = new JassUnitEvent(i); } for (let i = 89; i < 90; i++) { events[i] = new JassWidgetEvent(i); } for (let i = 90; i < 92; i++) { events[i] = new JassDialogEvent(i); } for (let i = 256; i < 260; i++) { events[i] = new JassGameEvent(i); } for (let i = 261; i < 269; i++) { events[i] = new JassPlayerEvent(i); } for (let i = 269; i < 278; i++) { events[i] = new JassPlayerUnitEvent(i); } for (let i = 286; i < 295; i++) { events[i] = new JassUnitEvent(i); } for (let i = 0; i < 6; i++) { limitOps[i] = new JassLimitOp(i); } for (let i = 0; i < 27; i++) { unitTypes[i] = new JassUnitType(i); } for (let i = 0; i < 9; i++) { itemTypes[i] = new JassItemType(i); } for (let i = 0; i < 7; i++) { cameraFields[i] = new JassCameraField(i); } for (let i = 0; i < 6; i++) { blendModes[i] = new JassBlendMode(i); } for (let i = 0; i < 1; i++) { rarityControls[i] = new JassRarityControl(i); } for (let i = 0; i < 4; i++) { texMapFlags[i] = new JassTexMapFlags(i); } for (let i = 0; i < 3; i++) { const p = Math.pow(2, i); fogStates[p] = new JassFogState(p); } for (let i = 0; i < 7; i++) { effectTypes[i] = new JassEffectType(i); } for (let i = 0; i < 2; i++) { soundTypes[i] = new JassSoundType(i); } return { playerColors, races, playerGameResults, allianceTypes, versions, attackTypes, damageTypes, weaponTypes, pathingTypes, mouseButtonTypes, animTypes, subAnimTypes, racePrefs, mapControls, gameTypes, mapFlags, placements, startLocPrios, mapDensities, gameDifficulties, gameSpeeds, playerSlotStates, volumeGroups, gameStates, playerStates, unitStates, aiDifficulties, playerScores, events, limitOps, unitTypes, itemTypes, cameraFields, blendModes, rarityControls, texMapFlags, fogStates, effectTypes, soundTypes, }; } ================================================ FILE: src/utils/jass2/context.ts ================================================ import { EventEmitter } from 'events'; import { lua_State } from 'fengari/src/lstate'; import { lua_atnativeerror, lua_getglobal, lua_pcall, lua_pop, lua_pushstring, lua_rawgeti, lua_touserdata } from 'fengari/src/lapi'; import { LUA_REGISTRYINDEX, thread_status, to_jsstring, to_luastring } from 'fengari/src/defs'; import { luaL_checknumber, luaL_loadstring, luaL_newstate, luaL_tolstring } from 'fengari/src/lauxlib'; import { lua_resume } from 'fengari/src/ldo'; import War3Map from '../../parsers/w3x/map'; import jass2lua from './jass2lua'; import bindNatives from './natives'; import JassPlayer from './types/player'; import constantHandles from './constanthandles'; import Thread from './thread'; import JassHandle from './types/handle'; import JassLocation from './types/location'; import JassTimer from './types/timer'; import { JassTrigger } from './types/index'; /** * A Jass2 context. */ export default class Context extends EventEmitter { L: lua_State; map: War3Map | null = null; handle = 0; freeHandles: number[] = []; handles: (JassHandle | null)[] = []; name = ''; description = ''; players: JassPlayer[] = []; actualPlayers = 0; startLocations: JassLocation[] = []; constantHandles = constantHandles(); timers: Set = new Set(); triggers: Set = new Set(); threads: Set = new Set(); currentThread: Thread | null = null; enumUnit: JassHandle | null = null; filterUnit: JassHandle | null = null; enumPlayer: JassHandle | null = null; t = 0; constructor() { super(); this.L = luaL_newstate(); //luaL_openlibs(this.L); bindNatives(this); lua_atnativeerror(this.L, (L: lua_State) => { const e = lua_touserdata(L, -1); lua_pushstring(L, e.stack || 'An unknown error occured'); return 1; }); for (let i = 0; i < 28; i++) { this.players[i] = this.addHandle(new JassPlayer(i, 28)); } // this.mappedData = new MappedData(); // this.mapName = ''; // this.mapDescription = ''; // this.gamePlacement = null; // this.gameSpeed = null; // this.gameDifficulty = null; // this.playerCount = 0; // this.teamCount = 0; // this.startLocations = []; // this.players = []; // this.teams = []; // this.stringTable = map.readStringTable(); } start(): void { this.t = performance.now(); } step(): void { const t = performance.now(); const dt = (t - this.t) * 0.001; const timers = this.timers; const threads = this.threads; for (const timer of timers) { timer.elapsed += dt; if (timer.elapsed >= timer.timeout) { const thread = new Thread(this.L, { expiredTimer: timer }); const L = thread.L; // Push the entry point onto the thread's stack, so when the thread is resumed it will immediately be called. lua_rawgeti(L, LUA_REGISTRYINDEX, timer.handlerFunc); this.threads.add(thread); if (timer.periodic) { timer.elapsed = 0; } else { timers.delete(timer); /// TODO: better way to clean references. // If the timer isn't periodic, the callback reference can be collected. ///luaL_unref(timer.handlerFunc); } } } for (const thread of threads) { thread.sleep -= dt; if (thread.sleep <= 0) { this.currentThread = thread; const L = thread.L; const status = lua_resume(L, this.L, 0); if (status === thread_status.LUA_OK) { threads.delete(thread); } else if (status === thread_status.LUA_YIELD) { thread.sleep = luaL_checknumber(L, 1); } else { console.log('[JS] Something went wrong during execution'); console.log(to_jsstring(luaL_tolstring(L, -1))); lua_pop(L, 2); } } } this.t = t; } addHandle(handle: JassHandle): JassHandle { if (handle.handleId === -1) { let handleId; if (this.freeHandles.length) { handleId = this.freeHandles.pop(); } else { handleId = this.handle++; } this.handles[handleId] = handle; handle.handleId = handleId; } return handle; } freeHandle(handle: JassHandle): void { if (handle.handleId !== -1) { this.freeHandles.push(handle.handleId); this.handles[handle.handleId] = null; handle.handleId = -1; } } call(name?: string | number): void { const L = this.L; if (typeof name === 'string') { lua_getglobal(L, name); } else if (typeof name === 'number') { lua_rawgeti(L, LUA_REGISTRYINDEX, name); } if (lua_pcall(L, 0, 0, 0)) { console.log('Something went wrong during execution'); console.log(to_jsstring(luaL_tolstring(L, -1))); lua_pop(L, 2); } } run(code: string, isJass: boolean): void { const L = this.L; if (isJass) { code = jass2lua(code); } if (luaL_loadstring(L, to_luastring(code))) { console.log('Something went wrong during execution'); console.log(to_jsstring(luaL_tolstring(L, -1))); lua_pop(L, 2); } if (lua_pcall(L, 0, 0, 0)) { console.log('Something went wrong during execution'); console.log(to_jsstring(luaL_tolstring(L, -1))); lua_pop(L, 2); } } open(map: War3Map): void { this.map = map; const file = map.getScriptFile(); if (file) { const buffer = file.text(); if (buffer) { const isJass = file.name.endsWith('.j'); this.run(buffer, isJass); } } } } ================================================ FILE: src/utils/jass2/index.ts ================================================ import Context from './context'; import jass2lua from './jass2lua'; import * as types from './types'; import compileNatives from './compilenatives'; export default { Context, jass2lua, types, compileNatives, }; ================================================ FILE: src/utils/jass2/jass2lua.ts ================================================ import TokenStream from './tokenstream'; export default function jass2lua(jass: string): string { const stream = new TokenStream(jass); const tokens = []; let token; while ((token = stream.read()) !== undefined) { if (token === 'function') { const name = stream.readSafe(); stream.read(); // takes token = stream.read(); // nothing or type let params = ''; if (token !== 'nothing') { params += stream.readSafe(); while (stream.read() === ',') { stream.read(); params += ',' + stream.readSafe(); } } else { stream.read(); // returns } stream.read(); // return type const header = `function ${name}(${params})`; const body = []; while ((token = stream.readSafe()) !== 'endfunction') { if (token === 'local') { stream.read(); // type const arrayOrName = stream.readSafe(); if (arrayOrName === 'array') { body.push(`local ${stream.readSafe()}={}`); } else { body.push(`local ${arrayOrName}${stream.readUntil('\n')}\n`); } } else if (token === 'if' || token === 'elseif' || token === 'not') { body.push(token + ' '); } else if (token === 'then') { body.push(' ' + token); } else if (token === 'loop') { body.push('while 1 do'); } else if (token === 'endloop' || token === 'endif') { body.push('end'); } else if (token === 'exitwhen') { body.push(`if ${stream.readUntil('\n')} then break end\n`); } else if (token === 'return') { const value = stream.readUntil('\n'); token = stream.peek(); // return statmentes can only be the last statements in their block. // If a statement isn't the last in its block, it is inserted into its own if block. if (token === 'endif' || token === 'endloop' || token === 'endfunction') { body.push(`return ${value}\n`); } else { body.push(`if 1 then return ${value} end\n`); } } else if (token === '\n') { const lastLine = body[body.length - 1]; if (lastLine && lastLine[lastLine.length - 1] !== '\n') { body.push('\n'); } } else if (token !== 'set' && token !== 'call' && token !== 'function') { body.push(token); } } tokens.push(`${header}\n${body.join('')}end`); } else if (token === 'globals') { while ((token = stream.read()) !== 'endglobals') { if (token !== '\n') { // token can either be type or constant. if (token === 'constant') { token = stream.read(); } const arrayOrName = stream.read(); if (arrayOrName === 'array') { tokens.push(`${stream.readSafe()}={}`); } else { // Unlike locals, having a global name with no value is a syntax error. // In addition, globals that are nil effectively don't exist in Lua. // Therefore, remove both cases. let value = 'nil'; if (stream.peek() === '=') { stream.read(); // = value = stream.readUntil('\n'); } if (value !== 'nil') { tokens.push(`${arrayOrName}=${value}`); } } } } } } return tokens.join('\n'); } ================================================ FILE: src/utils/jass2/natives.ts ================================================ import { LUA_REGISTRYINDEX } from 'fengari/src/defs'; import { lua_State } from 'fengari/src/lstate'; import { lua_register, lua_pushinteger, lua_pushnumber, lua_pushstring, lua_pushlightuserdata, lua_touserdata, lua_pushboolean, lua_pushnil, lua_toboolean } from 'fengari/src/lapi'; import { luaL_checkstring, luaL_checkinteger, luaL_checknumber, luaL_ref, luaL_unref } from 'fengari/src/lauxlib'; import { lua_yield } from 'fengari/src/ldo'; import { JassTimer, JassGroup, JassLocation, JassForce, JassUnit, JassTrigger, JassPlayer, JassPlayerColor, JassMapControl, JassHandle } from './types'; import Context from './context'; /** * constant native ConvertRace takes integer i returns race */ function ConvertRace(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.races[i]); return 1; } /** * constant native ConvertAllianceType takes integer i returns alliancetype */ function ConvertAllianceType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.allianceTypes[i]); return 1; } /** * constant native ConvertRacePref takes integer i returns racepreference */ function ConvertRacePref(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.racePrefs[i]); return 1; } /** * constant native ConvertIGameState takes integer i returns igamestate */ function ConvertIGameState(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.gameStates[i]); return 1; } /** * constant native ConvertFGameState takes integer i returns fgamestate */ function ConvertFGameState(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.gameStates[i]); return 1; } /** * constant native ConvertPlayerState takes integer i returns playerstate */ function ConvertPlayerState(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.playerStates[i]); return 1; } /** * constant native ConvertPlayerScore takes integer i returns playerscore */ function ConvertPlayerScore(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.playerScores[i]); return 1; } /** * constant native ConvertPlayerGameResult takes integer i returns playergameresult */ function ConvertPlayerGameResult(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.playerGameResults[i]); return 1; } /** * constant native ConvertUnitState takes integer i returns unitstate */ function ConvertUnitState(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.unitStates[i]); return 1; } /** * constant native ConvertAIDifficulty takes integer i returns aidifficulty */ function ConvertAIDifficulty(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.aiDifficulties[i]); return 1; } /** * constant native ConvertGameEvent takes integer i returns gameevent */ function ConvertGameEvent(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.events[i]); return 1; } /** * constant native ConvertPlayerEvent takes integer i returns playerevent */ function ConvertPlayerEvent(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.events[i]); return 1; } /** * constant native ConvertPlayerUnitEvent takes integer i returns playerunitevent */ function ConvertPlayerUnitEvent(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.events[i]); return 1; } /** * constant native ConvertWidgetEvent takes integer i returns widgetevent */ function ConvertWidgetEvent(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.events[i]); return 1; } /** * constant native ConvertDialogEvent takes integer i returns dialogevent */ function ConvertDialogEvent(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.events[i]); return 1; } /** * constant native ConvertUnitEvent takes integer i returns unitevent */ function ConvertUnitEvent(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.events[i]); return 1; } /** * constant native ConvertLimitOp takes integer i returns limitop */ function ConvertLimitOp(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.limitOps[i]); return 1; } /** * constant native ConvertUnitType takes integer i returns unittype */ function ConvertUnitType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.unitTypes[i]); return 1; } /** * constant native ConvertGameSpeed takes integer i returns gamespeed */ function ConvertGameSpeed(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.gameSpeeds[i]); return 1; } /** * constant native ConvertPlacement takes integer i returns placement */ function ConvertPlacement(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.placements[i]); return 1; } /** * constant native ConvertStartLocPrio takes integer i returns startlocprio */ function ConvertStartLocPrio(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.startLocPrios[i]); return 1; } /** * constant native ConvertGameDifficulty takes integer i returns gamedifficulty */ function ConvertGameDifficulty(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.gameDifficulties[i]); return 1; } /** * constant native ConvertGameType takes integer i returns gametype */ function ConvertGameType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.gameTypes[i]); return 1; } /** * constant native ConvertMapFlag takes integer i returns mapflag */ function ConvertMapFlag(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.mapFlags[i]); return 1; } /** * constant native ConvertMapVisibility takes integer i returns mapvisibility */ function ConvertMapVisibility(C: Context, L: lua_State): number { const _i = luaL_checkinteger(L, 1); console.warn('ConvertMapVisibility used, but the implementation is unknown'); lua_pushnil(L); return 1; } /** * constant native ConvertMapSetting takes integer i returns mapsetting */ function ConvertMapSetting(C: Context, L: lua_State): number { const _i = luaL_checkinteger(L, 1); console.warn('ConvertMapSetting used, but the implementation is unknown'); lua_pushnil(L); return 1; } /** * constant native ConvertMapDensity takes integer i returns mapdensity */ function ConvertMapDensity(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.mapDensities[i]); return 1; } /** * constant native ConvertMapControl takes integer i returns mapcontrol */ function ConvertMapControl(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.mapControls[i]); return 1; } /** * constant native ConvertPlayerColor takes integer i returns playercolor */ function ConvertPlayerColor(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.playerColors[i]); return 1; } /** * constant native ConvertPlayerSlotState takes integer i returns playerslotstate */ function ConvertPlayerSlotState(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.playerSlotStates[i]); return 1; } /** * constant native ConvertVolumeGroup takes integer i returns volumegroup */ function ConvertVolumeGroup(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.volumeGroups[i]); return 1; } /** * constant native ConvertCameraField takes integer i returns camerafield */ function ConvertCameraField(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.cameraFields[i]); return 1; } /** * constant native ConvertBlendMode takes integer i returns blendmode */ function ConvertBlendMode(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.blendModes[i]); return 1; } /** * constant native ConvertRarityControl takes integer i returns raritycontrol */ function ConvertRarityControl(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.rarityControls[i]); return 1; } /** * constant native ConvertTexMapFlags takes integer i returns texmapflags */ function ConvertTexMapFlags(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.texMapFlags[i]); return 1; } /** * constant native ConvertFogState takes integer i returns fogstate */ function ConvertFogState(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.fogStates[i]); return 1; } /** * constant native ConvertEffectType takes integer i returns effecttype */ function ConvertEffectType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.effectTypes[i]); return 1; } /** * constant native ConvertVersion takes integer i returns version */ function ConvertVersion(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.versions[i]); return 1; } /** * constant native ConvertItemType takes integer i returns itemtype */ function ConvertItemType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.itemTypes[i]); return 1; } /** * constant native ConvertAttackType takes integer i returns attacktype */ function ConvertAttackType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.attackTypes[i]); return 1; } /** * constant native ConvertDamageType takes integer i returns damagetype */ function ConvertDamageType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.damageTypes[i]); return 1; } /** * constant native ConvertWeaponType takes integer i returns weapontype */ function ConvertWeaponType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.weaponTypes[i]); return 1; } /** * constant native ConvertSoundType takes integer i returns soundtype */ function ConvertSoundType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.soundTypes[i]); return 1; } /** * constant native ConvertPathingType takes integer i returns pathingtype */ function ConvertPathingType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.pathingTypes[i]); return 1; } /** * constant native ConvertMouseButtonType takes integer i returns mousebuttontype */ function ConvertMouseButtonType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.mouseButtonTypes[i]); return 1; } /** * constant native ConvertAnimType takes integer i returns animtype */ function ConvertAnimType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.animTypes[i]); return 1; } /** * constant native ConvertSubAnimType takes integer i returns subanimtype */ function ConvertSubAnimType(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.constantHandles.subAnimTypes[i]); return 1; } /** * constant native OrderId takes string orderIdString returns integer */ function OrderId(C: Context, L: lua_State): number { const _orderIdString = luaL_checkstring(L, 1); console.warn('OrderId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native OrderId2String takes integer orderId returns string */ function OrderId2String(C: Context, L: lua_State): number { const _orderId = luaL_checkinteger(L, 1); console.warn('OrderId2String was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native UnitId takes string unitIdString returns integer */ function UnitId(C: Context, L: lua_State): number { const _unitIdString = luaL_checkstring(L, 1); console.warn('UnitId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native UnitId2String takes integer unitId returns string */ function UnitId2String(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); console.warn('UnitId2String was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native AbilityId takes string abilityIdString returns integer */ function AbilityId(C: Context, L: lua_State): number { const _abilityIdString = luaL_checkstring(L, 1); console.warn('AbilityId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native AbilityId2String takes integer abilityId returns string */ function AbilityId2String(C: Context, L: lua_State): number { const _abilityId = luaL_checkinteger(L, 1); console.warn('AbilityId2String was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native GetObjectName takes integer objectId returns string */ function GetObjectName(C: Context, L: lua_State): number { const _objectId = luaL_checkinteger(L, 1); console.warn('GetObjectName was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native GetBJMaxPlayers takes nothing returns integer */ function GetBJMaxPlayers(C: Context, L: lua_State): number { lua_pushinteger(L, 24); return 1; } /** * constant native GetBJPlayerNeutralVictim takes nothing returns integer */ function GetBJPlayerNeutralVictim(C: Context, L: lua_State): number { lua_pushinteger(L, 24); return 1; } /** * constant native GetBJPlayerNeutralExtra takes nothing returns integer */ function GetBJPlayerNeutralExtra(C: Context, L: lua_State): number { lua_pushinteger(L, 25); return 1; } /** * constant native GetBJMaxPlayerSlots takes nothing returns integer */ function GetBJMaxPlayerSlots(C: Context, L: lua_State): number { lua_pushinteger(L, 28); return 1; } /** * constant native GetPlayerNeutralPassive takes nothing returns integer */ function GetPlayerNeutralPassive(C: Context, L: lua_State): number { lua_pushinteger(L, 26); return 1; } /** * constant native GetPlayerNeutralAggressive takes nothing returns integer */ function GetPlayerNeutralAggressive(C: Context, L: lua_State): number { lua_pushinteger(L, 27); return 1; } /** * native Deg2Rad takes real degrees returns real */ function Deg2Rad(C: Context, L: lua_State): number { const degrees = luaL_checknumber(L, 1); lua_pushnumber(L, degrees * (Math.PI / 180)); return 1; } /** * native Rad2Deg takes real radians returns real */ function Rad2Deg(C: Context, L: lua_State): number { const radians = luaL_checknumber(L, 1); lua_pushnumber(L, radians * (180 / Math.PI)); return 1; } /** * native Sin takes real radians returns real */ function Sin(C: Context, L: lua_State): number { const radians = luaL_checknumber(L, 1); lua_pushnumber(L, Math.sin(radians)); return 1; } /** * native Cos takes real radians returns real */ function Cos(C: Context, L: lua_State): number { const radians = luaL_checknumber(L, 1); lua_pushnumber(L, Math.cos(radians)); return 1; } /** * native Tan takes real radians returns real */ function Tan(C: Context, L: lua_State): number { const radians = luaL_checknumber(L, 1); lua_pushnumber(L, Math.tan(radians)); return 1; } /** * native Asin takes real y returns real */ function Asin(C: Context, L: lua_State): number { const y = luaL_checknumber(L, 1); lua_pushnumber(L, Math.asin(y)); return 1; } /** * native Acos takes real x returns real */ function Acos(C: Context, L: lua_State): number { const x = luaL_checknumber(L, 1); lua_pushnumber(L, Math.acos(x)); return 1; } /** * native Atan takes real x returns real */ function Atan(C: Context, L: lua_State): number { const x = luaL_checknumber(L, 1); lua_pushnumber(L, Math.atan(x)); return 1; } /** * native Atan2 takes real y, real x returns real */ function Atan2(C: Context, L: lua_State): number { const y = luaL_checknumber(L, 1); const x = luaL_checknumber(L, 2); lua_pushnumber(L, Math.atan2(y, x)); return 1; } /** * native SquareRoot takes real x returns real */ function SquareRoot(C: Context, L: lua_State): number { const x = luaL_checknumber(L, 1); lua_pushnumber(L, Math.sqrt(x)); return 1; } /** * native Pow takes real x, real power returns real */ function Pow(C: Context, L: lua_State): number { const x = luaL_checknumber(L, 1); const power = luaL_checknumber(L, 2); lua_pushnumber(L, Math.pow(x, power)); return 1; } /** * native I2R takes integer i returns real */ function I2R(C: Context, L: lua_State): number { const i = luaL_checkinteger(L, 1); lua_pushnumber(L, i); return 1; } /** * native R2I takes real r returns integer */ function R2I(C: Context, L: lua_State): number { const r = luaL_checknumber(L, 1); lua_pushinteger(L, r | 0); return 1; } /** * native I2S takes integer i returns string */ function I2S(C: Context, L: lua_State): number { const _i = luaL_checkinteger(L, 1); console.warn('I2S was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native R2S takes real r returns string */ function R2S(C: Context, L: lua_State): number { const _r = luaL_checknumber(L, 1); console.warn('R2S was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native R2SW takes real r, integer width, integer precision returns string */ function R2SW(C: Context, L: lua_State): number { const _r = luaL_checknumber(L, 1); const _width = luaL_checkinteger(L, 2); const _precision = luaL_checkinteger(L, 3); console.warn('R2SW was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native S2I takes string s returns integer */ function S2I(C: Context, L: lua_State): number { const _s = luaL_checkstring(L, 1); console.warn('S2I was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native S2R takes string s returns real */ function S2R(C: Context, L: lua_State): number { const _s = luaL_checkstring(L, 1); console.warn('S2R was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetHandleId takes handle h returns integer */ function GetHandleId(C: Context, L: lua_State): number { const h = lua_touserdata(L, 1); lua_pushinteger(L, h.handleId); return 1; } /** * native SubString takes string source, integer start, integer end_ returns string */ function SubString(C: Context, L: lua_State): number { const _source = luaL_checkstring(L, 1); const _start = luaL_checkinteger(L, 2); const _end_ = luaL_checkinteger(L, 3); console.warn('SubString was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native StringLength takes string s returns integer */ function StringLength(C: Context, L: lua_State): number { const _s = luaL_checkstring(L, 1); console.warn('StringLength was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native StringCase takes string source, boolean upper returns string */ function StringCase(C: Context, L: lua_State): number { const _source = luaL_checkstring(L, 1); const _upper = lua_toboolean(L, 2); console.warn('StringCase was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native StringHash takes string s returns integer */ function StringHash(C: Context, L: lua_State): number { const _s = luaL_checkstring(L, 1); console.warn('StringHash was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetLocalizedString takes string source returns string */ function GetLocalizedString(C: Context, L: lua_State): number { const _source = luaL_checkstring(L, 1); console.warn('GetLocalizedString was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native GetLocalizedHotkey takes string source returns integer */ function GetLocalizedHotkey(C: Context, L: lua_State): number { const _source = luaL_checkstring(L, 1); console.warn('GetLocalizedHotkey was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetMapName takes string name returns nothing */ function SetMapName(C: Context, L: lua_State): number { const _name = luaL_checkstring(L, 1); console.warn('SetMapName was called but is not implemented :('); return 0; } /** * native SetMapDescription takes string description returns nothing */ function SetMapDescription(C: Context, L: lua_State): number { const _description = luaL_checkstring(L, 1); console.warn('SetMapDescription was called but is not implemented :('); return 0; } /** * native SetTeams takes integer teamcount returns nothing */ function SetTeams(C: Context, L: lua_State): number { const _teamcount = luaL_checkinteger(L, 1); console.warn('SetTeams was called but is not implemented :('); return 0; } /** * native SetPlayers takes integer playercount returns nothing */ function SetPlayers(C: Context, L: lua_State): number { const _playercount = luaL_checkinteger(L, 1); console.warn('SetPlayers was called but is not implemented :('); return 0; } /** * native DefineStartLocation takes integer whichStartLoc, real x, real y returns nothing */ function DefineStartLocation(C: Context, L: lua_State): number { const whichStartLoc = luaL_checkinteger(L, 1); const x = luaL_checknumber(L, 2); const y = luaL_checknumber(L, 3); C.startLocations[whichStartLoc] = C.addHandle(new JassLocation(x, y)); return 0; } /** * native DefineStartLocationLoc takes integer whichStartLoc, location whichLocation returns nothing */ function DefineStartLocationLoc(C: Context, L: lua_State): number { const _whichStartLoc = luaL_checkinteger(L, 1); const _whichLocation = lua_touserdata(L, 2); console.warn('DefineStartLocationLoc was called but is not implemented :('); return 0; } /** * native SetStartLocPrioCount takes integer whichStartLoc, integer prioSlotCount returns nothing */ function SetStartLocPrioCount(C: Context, L: lua_State): number { const _whichStartLoc = luaL_checkinteger(L, 1); const _prioSlotCount = luaL_checkinteger(L, 2); console.warn('SetStartLocPrioCount was called but is not implemented :('); return 0; } /** * native SetStartLocPrio takes integer whichStartLoc, integer prioSlotIndex, integer otherStartLocIndex, startlocprio priority returns nothing */ function SetStartLocPrio(C: Context, L: lua_State): number { const _whichStartLoc = luaL_checkinteger(L, 1); const _prioSlotIndex = luaL_checkinteger(L, 2); const _otherStartLocIndex = luaL_checkinteger(L, 3); const _priority = lua_touserdata(L, 4); console.warn('SetStartLocPrio was called but is not implemented :('); return 0; } /** * native GetStartLocPrioSlot takes integer whichStartLoc, integer prioSlotIndex returns integer */ function GetStartLocPrioSlot(C: Context, L: lua_State): number { const _whichStartLoc = luaL_checkinteger(L, 1); const _prioSlotIndex = luaL_checkinteger(L, 2); console.warn('GetStartLocPrioSlot was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetStartLocPrio takes integer whichStartLoc, integer prioSlotIndex returns startlocprio */ function GetStartLocPrio(C: Context, L: lua_State): number { const _whichStartLoc = luaL_checkinteger(L, 1); const _prioSlotIndex = luaL_checkinteger(L, 2); console.warn('GetStartLocPrio was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SetGameTypeSupported takes gametype whichGameType, boolean value returns nothing */ function SetGameTypeSupported(C: Context, L: lua_State): number { const _whichGameType = lua_touserdata(L, 1); const _value = lua_toboolean(L, 2); console.warn('SetGameTypeSupported was called but is not implemented :('); return 0; } /** * native SetMapFlag takes mapflag whichMapFlag, boolean value returns nothing */ function SetMapFlag(C: Context, L: lua_State): number { const _whichMapFlag = lua_touserdata(L, 1); const _value = lua_toboolean(L, 2); console.warn('SetMapFlag was called but is not implemented :('); return 0; } /** * native SetGamePlacement takes placement whichPlacementType returns nothing */ function SetGamePlacement(C: Context, L: lua_State): number { const _whichPlacementType = lua_touserdata(L, 1); console.warn('SetGamePlacement was called but is not implemented :('); return 0; } /** * native SetGameSpeed takes gamespeed whichspeed returns nothing */ function SetGameSpeed(C: Context, L: lua_State): number { const _whichspeed = lua_touserdata(L, 1); console.warn('SetGameSpeed was called but is not implemented :('); return 0; } /** * native SetGameDifficulty takes gamedifficulty whichdifficulty returns nothing */ function SetGameDifficulty(C: Context, L: lua_State): number { const _whichdifficulty = lua_touserdata(L, 1); console.warn('SetGameDifficulty was called but is not implemented :('); return 0; } /** * native SetResourceDensity takes mapdensity whichdensity returns nothing */ function SetResourceDensity(C: Context, L: lua_State): number { const _whichdensity = lua_touserdata(L, 1); console.warn('SetResourceDensity was called but is not implemented :('); return 0; } /** * native SetCreatureDensity takes mapdensity whichdensity returns nothing */ function SetCreatureDensity(C: Context, L: lua_State): number { const _whichdensity = lua_touserdata(L, 1); console.warn('SetCreatureDensity was called but is not implemented :('); return 0; } /** * native GetTeams takes nothing returns integer */ function GetTeams(C: Context, L: lua_State): number { console.warn('GetTeams was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetPlayers takes nothing returns integer */ function GetPlayers(C: Context, L: lua_State): number { console.warn('GetPlayers was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native IsGameTypeSupported takes gametype whichGameType returns boolean */ function IsGameTypeSupported(C: Context, L: lua_State): number { const _whichGameType = lua_touserdata(L, 1); console.warn('IsGameTypeSupported was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetGameTypeSelected takes nothing returns gametype */ function GetGameTypeSelected(C: Context, L: lua_State): number { console.warn('GetGameTypeSelected was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native IsMapFlagSet takes mapflag whichMapFlag returns boolean */ function IsMapFlagSet(C: Context, L: lua_State): number { const _whichMapFlag = lua_touserdata(L, 1); console.warn('IsMapFlagSet was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native GetGamePlacement takes nothing returns placement */ function GetGamePlacement(C: Context, L: lua_State): number { console.warn('GetGamePlacement was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetGameSpeed takes nothing returns gamespeed */ function GetGameSpeed(C: Context, L: lua_State): number { console.warn('GetGameSpeed was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetGameDifficulty takes nothing returns gamedifficulty */ function GetGameDifficulty(C: Context, L: lua_State): number { console.warn('GetGameDifficulty was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetResourceDensity takes nothing returns mapdensity */ function GetResourceDensity(C: Context, L: lua_State): number { console.warn('GetResourceDensity was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetCreatureDensity takes nothing returns mapdensity */ function GetCreatureDensity(C: Context, L: lua_State): number { console.warn('GetCreatureDensity was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetStartLocationX takes integer whichStartLocation returns real */ function GetStartLocationX(C: Context, L: lua_State): number { const _whichStartLocation = luaL_checkinteger(L, 1); console.warn('GetStartLocationX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetStartLocationY takes integer whichStartLocation returns real */ function GetStartLocationY(C: Context, L: lua_State): number { const _whichStartLocation = luaL_checkinteger(L, 1); console.warn('GetStartLocationY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetStartLocationLoc takes integer whichStartLocation returns location */ function GetStartLocationLoc(C: Context, L: lua_State): number { const _whichStartLocation = luaL_checkinteger(L, 1); console.warn('GetStartLocationLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SetPlayerTeam takes player whichPlayer, integer whichTeam returns nothing */ function SetPlayerTeam(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichTeam = luaL_checkinteger(L, 2); console.warn('SetPlayerTeam was called but is not implemented :('); return 0; } /** * native SetPlayerStartLocation takes player whichPlayer, integer startLocIndex returns nothing */ function SetPlayerStartLocation(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); const startLocIndex = luaL_checkinteger(L, 2); whichPlayer.startLocation = startLocIndex; return 0; } /** * native ForcePlayerStartLocation takes player whichPlayer, integer startLocIndex returns nothing */ function ForcePlayerStartLocation(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _startLocIndex = luaL_checkinteger(L, 2); console.warn('ForcePlayerStartLocation was called but is not implemented :('); return 0; } /** * native SetPlayerColor takes player whichPlayer, playercolor color returns nothing */ function SetPlayerColor(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); const color = lua_touserdata(L, 2); whichPlayer.color = color.id; return 0; } /** * native SetPlayerAlliance takes player sourcePlayer, player otherPlayer, alliancetype whichAllianceSetting, boolean value returns nothing */ function SetPlayerAlliance(C: Context, L: lua_State): number { const _sourcePlayer = lua_touserdata(L, 1); const _otherPlayer = lua_touserdata(L, 2); const _whichAllianceSetting = lua_touserdata(L, 3); const _value = lua_toboolean(L, 4); console.warn('SetPlayerAlliance was called but is not implemented :('); return 0; } /** * native SetPlayerTaxRate takes player sourcePlayer, player otherPlayer, playerstate whichResource, integer rate returns nothing */ function SetPlayerTaxRate(C: Context, L: lua_State): number { const _sourcePlayer = lua_touserdata(L, 1); const _otherPlayer = lua_touserdata(L, 2); const _whichResource = lua_touserdata(L, 3); const _rate = luaL_checkinteger(L, 4); console.warn('SetPlayerTaxRate was called but is not implemented :('); return 0; } /** * native SetPlayerRacePreference takes player whichPlayer, racepreference whichRacePreference returns nothing */ function SetPlayerRacePreference(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichRacePreference = lua_touserdata(L, 2); console.warn('SetPlayerRacePreference was called but is not implemented :('); return 0; } /** * native SetPlayerRaceSelectable takes player whichPlayer, boolean value returns nothing */ function SetPlayerRaceSelectable(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); const value = lua_toboolean(L, 2); whichPlayer.raceSelectable = value; return 0; } /** * native SetPlayerController takes player whichPlayer, mapcontrol controlType returns nothing */ function SetPlayerController(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); const controlType = lua_touserdata(L, 2); whichPlayer.controller = controlType.id; return 0; } /** * native SetPlayerName takes player whichPlayer, string name returns nothing */ function SetPlayerName(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); const name = luaL_checkstring(L, 2); whichPlayer.name = name; return 0; } /** * native SetPlayerOnScoreScreen takes player whichPlayer, boolean flag returns nothing */ function SetPlayerOnScoreScreen(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetPlayerOnScoreScreen was called but is not implemented :('); return 0; } /** * native GetPlayerTeam takes player whichPlayer returns integer */ function GetPlayerTeam(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('GetPlayerTeam was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetPlayerStartLocation takes player whichPlayer returns integer */ function GetPlayerStartLocation(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); lua_pushinteger(L, whichPlayer.startLocation); return 1; } /** * native GetPlayerColor takes player whichPlayer returns playercolor */ function GetPlayerColor(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); lua_pushlightuserdata(L, whichPlayer.color); return 1; } /** * native GetPlayerSelectable takes player whichPlayer returns boolean */ function GetPlayerSelectable(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('GetPlayerSelectable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetPlayerController takes player whichPlayer returns mapcontrol */ function GetPlayerController(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); lua_pushlightuserdata(L, whichPlayer.controller); return 1; } /** * native GetPlayerSlotState takes player whichPlayer returns playerslotstate */ function GetPlayerSlotState(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('GetPlayerSlotState was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native GetPlayerTaxRate takes player sourcePlayer, player otherPlayer, playerstate whichResource returns integer */ function GetPlayerTaxRate(C: Context, L: lua_State): number { const _sourcePlayer = lua_touserdata(L, 1); const _otherPlayer = lua_touserdata(L, 2); const _whichResource = lua_touserdata(L, 3); console.warn('GetPlayerTaxRate was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native IsPlayerRacePrefSet takes player whichPlayer, racepreference pref returns boolean */ function IsPlayerRacePrefSet(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _pref = lua_touserdata(L, 2); console.warn('IsPlayerRacePrefSet was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetPlayerName takes player whichPlayer returns string */ function GetPlayerName(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); lua_pushstring(L, whichPlayer.name); return 1; } /** * native CreateTimer takes nothing returns timer */ function CreateTimer(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.addHandle(new JassTimer())); return 1; } /** * native DestroyTimer takes timer whichTimer returns nothing */ function DestroyTimer(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); // In case it's in the middle of running, remove it. C.timers.delete(whichTimer); C.freeHandle(whichTimer); return 0; } /** * native TimerStart takes timer whichTimer, real timeout, boolean periodic, code handlerFunc returns nothing */ function TimerStart(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); const timeout = luaL_checknumber(L, 2); const periodic = lua_toboolean(L, 3); const handlerFunc = luaL_ref(L, LUA_REGISTRYINDEX); whichTimer.elapsed = 0; whichTimer.timeout = timeout; whichTimer.periodic = periodic; whichTimer.handlerFunc = handlerFunc; C.timers.add(whichTimer); return 0; } /** * native TimerGetElapsed takes timer whichTimer returns real */ function TimerGetElapsed(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); lua_pushnumber(L, whichTimer.elapsed); return 1; } /** * native TimerGetRemaining takes timer whichTimer returns real */ function TimerGetRemaining(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); lua_pushnumber(L, whichTimer.timeout - whichTimer.elapsed); return 1; } /** * native TimerGetTimeout takes timer whichTimer returns real */ function TimerGetTimeout(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); lua_pushnumber(L, whichTimer.timeout); return 1; } /** * native PauseTimer takes timer whichTimer returns nothing */ function PauseTimer(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); C.timers.delete(whichTimer); return 0; } /** * native ResumeTimer takes timer whichTimer returns nothing */ function ResumeTimer(C: Context, L: lua_State): number { const whichTimer = lua_touserdata(L, 1); C.timers.add(whichTimer); return 0; } /** * native GetExpiredTimer takes nothing returns timer */ function GetExpiredTimer(C: Context, L: lua_State): number { const thread = C.currentThread; if (thread && thread.expiredTimer) { lua_pushlightuserdata(L, thread.expiredTimer); } else { lua_pushnil(L); } return 1; } /** * native CreateGroup takes nothing returns group */ function CreateGroup(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.addHandle(new JassGroup())); return 1; } /** * native DestroyGroup takes group whichGroup returns nothing */ function DestroyGroup(C: Context, L: lua_State): number { const whichGroup = lua_touserdata(L, 1); C.freeHandle(whichGroup); return 0; } /** * native GroupAddUnit takes group whichGroup, unit whichUnit returns nothing */ function GroupAddUnit(C: Context, L: lua_State): number { const whichGroup = lua_touserdata(L, 1); const whichUnit = lua_touserdata(L, 2); whichGroup.units.add(whichUnit); return 0; } /** * native GroupRemoveUnit takes group whichGroup, unit whichUnit returns nothing */ function GroupRemoveUnit(C: Context, L: lua_State): number { const whichGroup = lua_touserdata(L, 1); const whichUnit = lua_touserdata(L, 2); whichGroup.units.delete(whichUnit); return 0; } /** * native GroupClear takes group whichGroup returns nothing */ function GroupClear(C: Context, L: lua_State): number { const whichGroup = lua_touserdata(L, 1); whichGroup.units.clear(); return 0; } /** * native GroupEnumUnitsOfType takes group whichGroup, string unitname, boolexpr filter returns nothing */ function GroupEnumUnitsOfType(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _unitname = luaL_checkstring(L, 2); const _filter = lua_touserdata(L, 3); console.warn('GroupEnumUnitsOfType was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsOfPlayer takes group whichGroup, player whichPlayer, boolexpr filter returns nothing */ function GroupEnumUnitsOfPlayer(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('GroupEnumUnitsOfPlayer was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsOfTypeCounted takes group whichGroup, string unitname, boolexpr filter, integer countLimit returns nothing */ function GroupEnumUnitsOfTypeCounted(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _unitname = luaL_checkstring(L, 2); const _filter = lua_touserdata(L, 3); const _countLimit = luaL_checkinteger(L, 4); console.warn('GroupEnumUnitsOfTypeCounted was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsInRect takes group whichGroup, rect r, boolexpr filter returns nothing */ function GroupEnumUnitsInRect(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _r = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('GroupEnumUnitsInRect was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsInRectCounted takes group whichGroup, rect r, boolexpr filter, integer countLimit returns nothing */ function GroupEnumUnitsInRectCounted(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _r = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); const _countLimit = luaL_checkinteger(L, 4); console.warn('GroupEnumUnitsInRectCounted was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsInRange takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing */ function GroupEnumUnitsInRange(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _radius = luaL_checknumber(L, 4); const _filter = lua_touserdata(L, 5); console.warn('GroupEnumUnitsInRange was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsInRangeOfLoc takes group whichGroup, location whichLocation, real radius, boolexpr filter returns nothing */ function GroupEnumUnitsInRangeOfLoc(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); const _radius = luaL_checknumber(L, 3); const _filter = lua_touserdata(L, 4); console.warn('GroupEnumUnitsInRangeOfLoc was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsInRangeCounted takes group whichGroup, real x, real y, real radius, boolexpr filter, integer countLimit returns nothing */ function GroupEnumUnitsInRangeCounted(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _radius = luaL_checknumber(L, 4); const _filter = lua_touserdata(L, 5); const _countLimit = luaL_checkinteger(L, 6); console.warn('GroupEnumUnitsInRangeCounted was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsInRangeOfLocCounted takes group whichGroup, location whichLocation, real radius, boolexpr filter, integer countLimit returns nothing */ function GroupEnumUnitsInRangeOfLocCounted(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); const _radius = luaL_checknumber(L, 3); const _filter = lua_touserdata(L, 4); const _countLimit = luaL_checkinteger(L, 5); console.warn('GroupEnumUnitsInRangeOfLocCounted was called but is not implemented :('); return 0; } /** * native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer, boolexpr filter returns nothing */ function GroupEnumUnitsSelected(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('GroupEnumUnitsSelected was called but is not implemented :('); return 0; } /** * native GroupImmediateOrder takes group whichGroup, string order returns boolean */ function GroupImmediateOrder(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); console.warn('GroupImmediateOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupImmediateOrderById takes group whichGroup, integer order returns boolean */ function GroupImmediateOrderById(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); console.warn('GroupImmediateOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupPointOrder takes group whichGroup, string order, real x, real y returns boolean */ function GroupPointOrder(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('GroupPointOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupPointOrderLoc takes group whichGroup, string order, location whichLocation returns boolean */ function GroupPointOrderLoc(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _whichLocation = lua_touserdata(L, 3); console.warn('GroupPointOrderLoc was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupPointOrderById takes group whichGroup, integer order, real x, real y returns boolean */ function GroupPointOrderById(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('GroupPointOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupPointOrderByIdLoc takes group whichGroup, integer order, location whichLocation returns boolean */ function GroupPointOrderByIdLoc(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _whichLocation = lua_touserdata(L, 3); console.warn('GroupPointOrderByIdLoc was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupTargetOrder takes group whichGroup, string order, widget targetWidget returns boolean */ function GroupTargetOrder(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _targetWidget = lua_touserdata(L, 3); console.warn('GroupTargetOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GroupTargetOrderById takes group whichGroup, integer order, widget targetWidget returns boolean */ function GroupTargetOrderById(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _targetWidget = lua_touserdata(L, 3); console.warn('GroupTargetOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native ForGroup takes group whichGroup, code callback returns nothing */ function ForGroup(C: Context, L: lua_State): number { const whichGroup = lua_touserdata(L, 1); const callback = luaL_ref(L, LUA_REGISTRYINDEX); for (const unit of whichGroup.units) { C.enumUnit = unit; C.call(callback); } C.enumUnit = null; luaL_unref(L, LUA_REGISTRYINDEX, callback); return 0; } /** * native FirstOfGroup takes group whichGroup returns unit */ function FirstOfGroup(C: Context, L: lua_State): number { const _whichGroup = lua_touserdata(L, 1); console.warn('FirstOfGroup was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateForce takes nothing returns force */ function CreateForce(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.addHandle(new JassForce())); return 1; } /** * native DestroyForce takes force whichForce returns nothing */ function DestroyForce(C: Context, L: lua_State): number { const whichForce = lua_touserdata(L, 1); C.freeHandle(whichForce); return 0; } /** * native ForceAddPlayer takes force whichForce, player whichPlayer returns nothing */ function ForceAddPlayer(C: Context, L: lua_State): number { const whichForce = lua_touserdata(L, 1); const whichPlayer = lua_touserdata(L, 2); whichForce.players.add(whichPlayer); return 0; } /** * native ForceRemovePlayer takes force whichForce, player whichPlayer returns nothing */ function ForceRemovePlayer(C: Context, L: lua_State): number { const whichForce = lua_touserdata(L, 1); const whichPlayer = lua_touserdata(L, 2); whichForce.players.delete(whichPlayer); return 0; } /** * native ForceClear takes force whichForce returns nothing */ function ForceClear(C: Context, L: lua_State): number { const whichForce = lua_touserdata(L, 1); whichForce.players.clear(); return 0; } /** * native ForceEnumPlayers takes force whichForce, boolexpr filter returns nothing */ function ForceEnumPlayers(C: Context, L: lua_State): number { const _whichForce = lua_touserdata(L, 1); const _filter = lua_touserdata(L, 2); console.warn('ForceEnumPlayers was called but is not implemented :('); return 0; } /** * native ForceEnumPlayersCounted takes force whichForce, boolexpr filter, integer countLimit returns nothing */ function ForceEnumPlayersCounted(C: Context, L: lua_State): number { const _whichForce = lua_touserdata(L, 1); const _filter = lua_touserdata(L, 2); const _countLimit = luaL_checkinteger(L, 3); console.warn('ForceEnumPlayersCounted was called but is not implemented :('); return 0; } /** * native ForceEnumAllies takes force whichForce, player whichPlayer, boolexpr filter returns nothing */ function ForceEnumAllies(C: Context, L: lua_State): number { const _whichForce = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('ForceEnumAllies was called but is not implemented :('); return 0; } /** * native ForceEnumEnemies takes force whichForce, player whichPlayer, boolexpr filter returns nothing */ function ForceEnumEnemies(C: Context, L: lua_State): number { const _whichForce = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('ForceEnumEnemies was called but is not implemented :('); return 0; } /** * native ForForce takes force whichForce, code callback returns nothing */ function ForForce(C: Context, L: lua_State): number { const whichForce = lua_touserdata(L, 1); const callback = luaL_ref(L, LUA_REGISTRYINDEX); for (const player of whichForce.players) { C.enumPlayer = player; C.call(callback); } C.enumPlayer = null; luaL_unref(L, LUA_REGISTRYINDEX, callback); return 0; } /** * native Rect takes real minx, real miny, real maxx, real maxy returns rect */ function Rect(C: Context, L: lua_State): number { const _minx = luaL_checknumber(L, 1); const _miny = luaL_checknumber(L, 2); const _maxx = luaL_checknumber(L, 3); const _maxy = luaL_checknumber(L, 4); console.warn('Rect was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RectFromLoc takes location min, location max returns rect */ function RectFromLoc(C: Context, L: lua_State): number { const _min = lua_touserdata(L, 1); const _max = lua_touserdata(L, 2); console.warn('RectFromLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveRect takes rect whichRect returns nothing */ function RemoveRect(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('RemoveRect was called but is not implemented :('); return 0; } /** * native SetRect takes rect whichRect, real minx, real miny, real maxx, real maxy returns nothing */ function SetRect(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); const _minx = luaL_checknumber(L, 2); const _miny = luaL_checknumber(L, 3); const _maxx = luaL_checknumber(L, 4); const _maxy = luaL_checknumber(L, 5); console.warn('SetRect was called but is not implemented :('); return 0; } /** * native SetRectFromLoc takes rect whichRect, location min, location max returns nothing */ function SetRectFromLoc(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); const _min = lua_touserdata(L, 2); const _max = lua_touserdata(L, 3); console.warn('SetRectFromLoc was called but is not implemented :('); return 0; } /** * native MoveRectTo takes rect whichRect, real newCenterX, real newCenterY returns nothing */ function MoveRectTo(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); const _newCenterX = luaL_checknumber(L, 2); const _newCenterY = luaL_checknumber(L, 3); console.warn('MoveRectTo was called but is not implemented :('); return 0; } /** * native MoveRectToLoc takes rect whichRect, location newCenterLoc returns nothing */ function MoveRectToLoc(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); const _newCenterLoc = lua_touserdata(L, 2); console.warn('MoveRectToLoc was called but is not implemented :('); return 0; } /** * native GetRectCenterX takes rect whichRect returns real */ function GetRectCenterX(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('GetRectCenterX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetRectCenterY takes rect whichRect returns real */ function GetRectCenterY(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('GetRectCenterY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetRectMinX takes rect whichRect returns real */ function GetRectMinX(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('GetRectMinX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetRectMinY takes rect whichRect returns real */ function GetRectMinY(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('GetRectMinY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetRectMaxX takes rect whichRect returns real */ function GetRectMaxX(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('GetRectMaxX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetRectMaxY takes rect whichRect returns real */ function GetRectMaxY(C: Context, L: lua_State): number { const _whichRect = lua_touserdata(L, 1); console.warn('GetRectMaxY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native CreateRegion takes nothing returns region */ function CreateRegion(C: Context, L: lua_State): number { console.warn('CreateRegion was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveRegion takes region whichRegion returns nothing */ function RemoveRegion(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); console.warn('RemoveRegion was called but is not implemented :('); return 0; } /** * native RegionAddRect takes region whichRegion, rect r returns nothing */ function RegionAddRect(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _r = lua_touserdata(L, 2); console.warn('RegionAddRect was called but is not implemented :('); return 0; } /** * native RegionClearRect takes region whichRegion, rect r returns nothing */ function RegionClearRect(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _r = lua_touserdata(L, 2); console.warn('RegionClearRect was called but is not implemented :('); return 0; } /** * native RegionAddCell takes region whichRegion, real x, real y returns nothing */ function RegionAddCell(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('RegionAddCell was called but is not implemented :('); return 0; } /** * native RegionAddCellAtLoc takes region whichRegion, location whichLocation returns nothing */ function RegionAddCellAtLoc(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); console.warn('RegionAddCellAtLoc was called but is not implemented :('); return 0; } /** * native RegionClearCell takes region whichRegion, real x, real y returns nothing */ function RegionClearCell(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('RegionClearCell was called but is not implemented :('); return 0; } /** * native RegionClearCellAtLoc takes region whichRegion, location whichLocation returns nothing */ function RegionClearCellAtLoc(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); console.warn('RegionClearCellAtLoc was called but is not implemented :('); return 0; } /** * native Location takes real x, real y returns location */ function Location(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('Location was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveLocation takes location whichLocation returns nothing */ function RemoveLocation(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); console.warn('RemoveLocation was called but is not implemented :('); return 0; } /** * native MoveLocation takes location whichLocation, real newX, real newY returns nothing */ function MoveLocation(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); const _newX = luaL_checknumber(L, 2); const _newY = luaL_checknumber(L, 3); console.warn('MoveLocation was called but is not implemented :('); return 0; } /** * native GetLocationX takes location whichLocation returns real */ function GetLocationX(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); console.warn('GetLocationX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetLocationY takes location whichLocation returns real */ function GetLocationY(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); console.warn('GetLocationY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetLocationZ takes location whichLocation returns real */ function GetLocationZ(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); console.warn('GetLocationZ was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native IsUnitInRegion takes region whichRegion, unit whichUnit returns boolean */ function IsUnitInRegion(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); console.warn('IsUnitInRegion was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsPointInRegion takes region whichRegion, real x, real y returns boolean */ function IsPointInRegion(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('IsPointInRegion was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsLocationInRegion takes region whichRegion, location whichLocation returns boolean */ function IsLocationInRegion(C: Context, L: lua_State): number { const _whichRegion = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); console.warn('IsLocationInRegion was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetWorldBounds takes nothing returns rect */ function GetWorldBounds(C: Context, L: lua_State): number { console.warn('GetWorldBounds was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateTrigger takes nothing returns trigger */ function CreateTrigger(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.addHandle(new JassTrigger())); return 1; } /** * native DestroyTrigger takes trigger whichTrigger returns nothing */ function DestroyTrigger(C: Context, L: lua_State): number { const whichTrigger = lua_touserdata(L, 1); // In case it's registered, remove it. C.triggers.delete(whichTrigger); C.freeHandle(whichTrigger); return 0; } /** * native ResetTrigger takes trigger whichTrigger returns nothing */ function ResetTrigger(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('ResetTrigger was called but is not implemented :('); return 0; } /** * native EnableTrigger takes trigger whichTrigger returns nothing */ function EnableTrigger(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('EnableTrigger was called but is not implemented :('); return 0; } /** * native DisableTrigger takes trigger whichTrigger returns nothing */ function DisableTrigger(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('DisableTrigger was called but is not implemented :('); return 0; } /** * native IsTriggerEnabled takes trigger whichTrigger returns boolean */ function IsTriggerEnabled(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('IsTriggerEnabled was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native TriggerWaitOnSleeps takes trigger whichTrigger, boolean flag returns nothing */ function TriggerWaitOnSleeps(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('TriggerWaitOnSleeps was called but is not implemented :('); return 0; } /** * native IsTriggerWaitOnSleeps takes trigger whichTrigger returns boolean */ function IsTriggerWaitOnSleeps(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('IsTriggerWaitOnSleeps was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native GetFilterUnit takes nothing returns unit */ function GetFilterUnit(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.filterUnit); return 1; } /** * constant native GetEnumUnit takes nothing returns unit */ function GetEnumUnit(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.enumUnit); return 1; } /** * constant native GetFilterDestructable takes nothing returns destructable */ function GetFilterDestructable(C: Context, L: lua_State): number { console.warn('GetFilterDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEnumDestructable takes nothing returns destructable */ function GetEnumDestructable(C: Context, L: lua_State): number { console.warn('GetEnumDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetFilterItem takes nothing returns item */ function GetFilterItem(C: Context, L: lua_State): number { console.warn('GetFilterItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEnumItem takes nothing returns item */ function GetEnumItem(C: Context, L: lua_State): number { console.warn('GetEnumItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetFilterPlayer takes nothing returns player */ function GetFilterPlayer(C: Context, L: lua_State): number { console.warn('GetFilterPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEnumPlayer takes nothing returns player */ function GetEnumPlayer(C: Context, L: lua_State): number { lua_pushlightuserdata(L, C.enumPlayer); return 1; } /** * constant native GetTriggeringTrigger takes nothing returns trigger */ function GetTriggeringTrigger(C: Context, L: lua_State): number { const thread = C.currentThread; if (thread && thread.triggeringTrigger) { lua_pushlightuserdata(L, thread.triggeringTrigger); } else { lua_pushnil(L); } return 1; } /** * constant native GetTriggerEventId takes nothing returns eventid */ function GetTriggerEventId(C: Context, L: lua_State): number { console.warn('GetTriggerEventId was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTriggerEvalCount takes trigger whichTrigger returns integer */ function GetTriggerEvalCount(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('GetTriggerEvalCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetTriggerExecCount takes trigger whichTrigger returns integer */ function GetTriggerExecCount(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('GetTriggerExecCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native ExecuteFunc takes string funcName returns nothing */ function ExecuteFunc(C: Context, L: lua_State): number { const _funcName = luaL_checkstring(L, 1); console.warn('ExecuteFunc was called but is not implemented :('); return 0; } /** * native And takes boolexpr operandA, boolexpr operandB returns boolexpr */ function And(C: Context, L: lua_State): number { const _operandA = lua_touserdata(L, 1); const _operandB = lua_touserdata(L, 2); console.warn('And was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native Or takes boolexpr operandA, boolexpr operandB returns boolexpr */ function Or(C: Context, L: lua_State): number { const _operandA = lua_touserdata(L, 1); const _operandB = lua_touserdata(L, 2); console.warn('Or was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native Not takes boolexpr operand returns boolexpr */ function Not(C: Context, L: lua_State): number { const _operand = lua_touserdata(L, 1); console.warn('Not was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native Condition takes code func returns conditionfunc */ function Condition(C: Context, L: lua_State): number { const _func = luaL_ref(L, LUA_REGISTRYINDEX); console.warn('Condition was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyCondition takes conditionfunc c returns nothing */ function DestroyCondition(C: Context, L: lua_State): number { const _c = lua_touserdata(L, 1); console.warn('DestroyCondition was called but is not implemented :('); return 0; } /** * native Filter takes code func returns filterfunc */ function Filter(C: Context, L: lua_State): number { const _func = luaL_ref(L, LUA_REGISTRYINDEX); console.warn('Filter was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyFilter takes filterfunc f returns nothing */ function DestroyFilter(C: Context, L: lua_State): number { const _f = lua_touserdata(L, 1); console.warn('DestroyFilter was called but is not implemented :('); return 0; } /** * native DestroyBoolExpr takes boolexpr e returns nothing */ function DestroyBoolExpr(C: Context, L: lua_State): number { const _e = lua_touserdata(L, 1); console.warn('DestroyBoolExpr was called but is not implemented :('); return 0; } /** * native TriggerRegisterVariableEvent takes trigger whichTrigger, string varName, limitop opcode, real limitval returns event */ function TriggerRegisterVariableEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _varName = luaL_checkstring(L, 2); const _opcode = lua_touserdata(L, 3); const _limitval = luaL_checknumber(L, 4); console.warn('TriggerRegisterVariableEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterTimerEvent takes trigger whichTrigger, real timeout, boolean periodic returns event */ function TriggerRegisterTimerEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _timeout = luaL_checknumber(L, 2); const _periodic = lua_toboolean(L, 3); console.warn('TriggerRegisterTimerEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterTimerExpireEvent takes trigger whichTrigger, timer t returns event */ function TriggerRegisterTimerExpireEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _t = lua_touserdata(L, 2); console.warn('TriggerRegisterTimerExpireEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterGameStateEvent takes trigger whichTrigger, gamestate whichState, limitop opcode, real limitval returns event */ function TriggerRegisterGameStateEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _opcode = lua_touserdata(L, 3); const _limitval = luaL_checknumber(L, 4); console.warn('TriggerRegisterGameStateEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterDialogEvent takes trigger whichTrigger, dialog whichDialog returns event */ function TriggerRegisterDialogEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichDialog = lua_touserdata(L, 2); console.warn('TriggerRegisterDialogEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterDialogButtonEvent takes trigger whichTrigger, button whichButton returns event */ function TriggerRegisterDialogButtonEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichButton = lua_touserdata(L, 2); console.warn('TriggerRegisterDialogButtonEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventGameState takes nothing returns gamestate */ function GetEventGameState(C: Context, L: lua_State): number { console.warn('GetEventGameState was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterGameEvent takes trigger whichTrigger, gameevent whichGameEvent returns event */ function TriggerRegisterGameEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichGameEvent = lua_touserdata(L, 2); console.warn('TriggerRegisterGameEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetWinningPlayer takes nothing returns player */ function GetWinningPlayer(C: Context, L: lua_State): number { console.warn('GetWinningPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterEnterRegion takes trigger whichTrigger, region whichRegion, boolexpr filter returns event */ function TriggerRegisterEnterRegion(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichRegion = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('TriggerRegisterEnterRegion was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTriggeringRegion takes nothing returns region */ function GetTriggeringRegion(C: Context, L: lua_State): number { console.warn('GetTriggeringRegion was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEnteringUnit takes nothing returns unit */ function GetEnteringUnit(C: Context, L: lua_State): number { console.warn('GetEnteringUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterLeaveRegion takes trigger whichTrigger, region whichRegion, boolexpr filter returns event */ function TriggerRegisterLeaveRegion(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichRegion = lua_touserdata(L, 2); const _filter = lua_touserdata(L, 3); console.warn('TriggerRegisterLeaveRegion was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetLeavingUnit takes nothing returns unit */ function GetLeavingUnit(C: Context, L: lua_State): number { console.warn('GetLeavingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterTrackableHitEvent takes trigger whichTrigger, trackable t returns event */ function TriggerRegisterTrackableHitEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _t = lua_touserdata(L, 2); console.warn('TriggerRegisterTrackableHitEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterTrackableTrackEvent takes trigger whichTrigger, trackable t returns event */ function TriggerRegisterTrackableTrackEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _t = lua_touserdata(L, 2); console.warn('TriggerRegisterTrackableTrackEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTriggeringTrackable takes nothing returns trackable */ function GetTriggeringTrackable(C: Context, L: lua_State): number { console.warn('GetTriggeringTrackable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetClickedButton takes nothing returns button */ function GetClickedButton(C: Context, L: lua_State): number { console.warn('GetClickedButton was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetClickedDialog takes nothing returns dialog */ function GetClickedDialog(C: Context, L: lua_State): number { console.warn('GetClickedDialog was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTournamentFinishSoonTimeRemaining takes nothing returns real */ function GetTournamentFinishSoonTimeRemaining(C: Context, L: lua_State): number { console.warn('GetTournamentFinishSoonTimeRemaining was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetTournamentFinishNowRule takes nothing returns integer */ function GetTournamentFinishNowRule(C: Context, L: lua_State): number { console.warn('GetTournamentFinishNowRule was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetTournamentFinishNowPlayer takes nothing returns player */ function GetTournamentFinishNowPlayer(C: Context, L: lua_State): number { console.warn('GetTournamentFinishNowPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTournamentScore takes player whichPlayer returns integer */ function GetTournamentScore(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('GetTournamentScore was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetSaveBasicFilename takes nothing returns string */ function GetSaveBasicFilename(C: Context, L: lua_State): number { console.warn('GetSaveBasicFilename was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native TriggerRegisterPlayerEvent takes trigger whichTrigger, player whichPlayer, playerevent whichPlayerEvent returns event */ function TriggerRegisterPlayerEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _whichPlayerEvent = lua_touserdata(L, 3); console.warn('TriggerRegisterPlayerEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTriggerPlayer takes nothing returns player */ function GetTriggerPlayer(C: Context, L: lua_State): number { console.warn('GetTriggerPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterPlayerUnitEvent takes trigger whichTrigger, player whichPlayer, playerunitevent whichPlayerUnitEvent, boolexpr filter returns event */ function TriggerRegisterPlayerUnitEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _whichPlayerUnitEvent = lua_touserdata(L, 3); const _filter = lua_touserdata(L, 4); console.warn('TriggerRegisterPlayerUnitEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetLevelingUnit takes nothing returns unit */ function GetLevelingUnit(C: Context, L: lua_State): number { console.warn('GetLevelingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetLearningUnit takes nothing returns unit */ function GetLearningUnit(C: Context, L: lua_State): number { console.warn('GetLearningUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetLearnedSkill takes nothing returns integer */ function GetLearnedSkill(C: Context, L: lua_State): number { console.warn('GetLearnedSkill was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetLearnedSkillLevel takes nothing returns integer */ function GetLearnedSkillLevel(C: Context, L: lua_State): number { console.warn('GetLearnedSkillLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetRevivableUnit takes nothing returns unit */ function GetRevivableUnit(C: Context, L: lua_State): number { console.warn('GetRevivableUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetRevivingUnit takes nothing returns unit */ function GetRevivingUnit(C: Context, L: lua_State): number { console.warn('GetRevivingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetAttacker takes nothing returns unit */ function GetAttacker(C: Context, L: lua_State): number { console.warn('GetAttacker was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetRescuer takes nothing returns unit */ function GetRescuer(C: Context, L: lua_State): number { console.warn('GetRescuer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetDyingUnit takes nothing returns unit */ function GetDyingUnit(C: Context, L: lua_State): number { console.warn('GetDyingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetKillingUnit takes nothing returns unit */ function GetKillingUnit(C: Context, L: lua_State): number { console.warn('GetKillingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetDecayingUnit takes nothing returns unit */ function GetDecayingUnit(C: Context, L: lua_State): number { console.warn('GetDecayingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetConstructingStructure takes nothing returns unit */ function GetConstructingStructure(C: Context, L: lua_State): number { console.warn('GetConstructingStructure was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetCancelledStructure takes nothing returns unit */ function GetCancelledStructure(C: Context, L: lua_State): number { console.warn('GetCancelledStructure was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetConstructedStructure takes nothing returns unit */ function GetConstructedStructure(C: Context, L: lua_State): number { console.warn('GetConstructedStructure was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetResearchingUnit takes nothing returns unit */ function GetResearchingUnit(C: Context, L: lua_State): number { console.warn('GetResearchingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetResearched takes nothing returns integer */ function GetResearched(C: Context, L: lua_State): number { console.warn('GetResearched was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetTrainedUnitType takes nothing returns integer */ function GetTrainedUnitType(C: Context, L: lua_State): number { console.warn('GetTrainedUnitType was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetTrainedUnit takes nothing returns unit */ function GetTrainedUnit(C: Context, L: lua_State): number { console.warn('GetTrainedUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetDetectedUnit takes nothing returns unit */ function GetDetectedUnit(C: Context, L: lua_State): number { console.warn('GetDetectedUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSummoningUnit takes nothing returns unit */ function GetSummoningUnit(C: Context, L: lua_State): number { console.warn('GetSummoningUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSummonedUnit takes nothing returns unit */ function GetSummonedUnit(C: Context, L: lua_State): number { console.warn('GetSummonedUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTransportUnit takes nothing returns unit */ function GetTransportUnit(C: Context, L: lua_State): number { console.warn('GetTransportUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetLoadedUnit takes nothing returns unit */ function GetLoadedUnit(C: Context, L: lua_State): number { console.warn('GetLoadedUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSellingUnit takes nothing returns unit */ function GetSellingUnit(C: Context, L: lua_State): number { console.warn('GetSellingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSoldUnit takes nothing returns unit */ function GetSoldUnit(C: Context, L: lua_State): number { console.warn('GetSoldUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetBuyingUnit takes nothing returns unit */ function GetBuyingUnit(C: Context, L: lua_State): number { console.warn('GetBuyingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSoldItem takes nothing returns item */ function GetSoldItem(C: Context, L: lua_State): number { console.warn('GetSoldItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetChangingUnit takes nothing returns unit */ function GetChangingUnit(C: Context, L: lua_State): number { console.warn('GetChangingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetChangingUnitPrevOwner takes nothing returns player */ function GetChangingUnitPrevOwner(C: Context, L: lua_State): number { console.warn('GetChangingUnitPrevOwner was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetManipulatingUnit takes nothing returns unit */ function GetManipulatingUnit(C: Context, L: lua_State): number { console.warn('GetManipulatingUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetManipulatedItem takes nothing returns item */ function GetManipulatedItem(C: Context, L: lua_State): number { console.warn('GetManipulatedItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetOrderedUnit takes nothing returns unit */ function GetOrderedUnit(C: Context, L: lua_State): number { console.warn('GetOrderedUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetIssuedOrderId takes nothing returns integer */ function GetIssuedOrderId(C: Context, L: lua_State): number { console.warn('GetIssuedOrderId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetOrderPointX takes nothing returns real */ function GetOrderPointX(C: Context, L: lua_State): number { console.warn('GetOrderPointX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetOrderPointY takes nothing returns real */ function GetOrderPointY(C: Context, L: lua_State): number { console.warn('GetOrderPointY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetOrderPointLoc takes nothing returns location */ function GetOrderPointLoc(C: Context, L: lua_State): number { console.warn('GetOrderPointLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetOrderTarget takes nothing returns widget */ function GetOrderTarget(C: Context, L: lua_State): number { console.warn('GetOrderTarget was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetOrderTargetDestructable takes nothing returns destructable */ function GetOrderTargetDestructable(C: Context, L: lua_State): number { console.warn('GetOrderTargetDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetOrderTargetItem takes nothing returns item */ function GetOrderTargetItem(C: Context, L: lua_State): number { console.warn('GetOrderTargetItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetOrderTargetUnit takes nothing returns unit */ function GetOrderTargetUnit(C: Context, L: lua_State): number { console.warn('GetOrderTargetUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSpellAbilityUnit takes nothing returns unit */ function GetSpellAbilityUnit(C: Context, L: lua_State): number { console.warn('GetSpellAbilityUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSpellAbilityId takes nothing returns integer */ function GetSpellAbilityId(C: Context, L: lua_State): number { console.warn('GetSpellAbilityId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetSpellAbility takes nothing returns ability */ function GetSpellAbility(C: Context, L: lua_State): number { console.warn('GetSpellAbility was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSpellTargetLoc takes nothing returns location */ function GetSpellTargetLoc(C: Context, L: lua_State): number { console.warn('GetSpellTargetLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSpellTargetX takes nothing returns real */ function GetSpellTargetX(C: Context, L: lua_State): number { console.warn('GetSpellTargetX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetSpellTargetY takes nothing returns real */ function GetSpellTargetY(C: Context, L: lua_State): number { console.warn('GetSpellTargetY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetSpellTargetDestructable takes nothing returns destructable */ function GetSpellTargetDestructable(C: Context, L: lua_State): number { console.warn('GetSpellTargetDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSpellTargetItem takes nothing returns item */ function GetSpellTargetItem(C: Context, L: lua_State): number { console.warn('GetSpellTargetItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetSpellTargetUnit takes nothing returns unit */ function GetSpellTargetUnit(C: Context, L: lua_State): number { console.warn('GetSpellTargetUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterPlayerAllianceChange takes trigger whichTrigger, player whichPlayer, alliancetype whichAlliance returns event */ function TriggerRegisterPlayerAllianceChange(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _whichAlliance = lua_touserdata(L, 3); console.warn('TriggerRegisterPlayerAllianceChange was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterPlayerStateEvent takes trigger whichTrigger, player whichPlayer, playerstate whichState, limitop opcode, real limitval returns event */ function TriggerRegisterPlayerStateEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _whichState = lua_touserdata(L, 3); const _opcode = lua_touserdata(L, 4); const _limitval = luaL_checknumber(L, 5); console.warn('TriggerRegisterPlayerStateEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventPlayerState takes nothing returns playerstate */ function GetEventPlayerState(C: Context, L: lua_State): number { console.warn('GetEventPlayerState was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterPlayerChatEvent takes trigger whichTrigger, player whichPlayer, string chatMessageToDetect, boolean exactMatchOnly returns event */ function TriggerRegisterPlayerChatEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _chatMessageToDetect = luaL_checkstring(L, 3); const _exactMatchOnly = lua_toboolean(L, 4); console.warn('TriggerRegisterPlayerChatEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventPlayerChatString takes nothing returns string */ function GetEventPlayerChatString(C: Context, L: lua_State): number { console.warn('GetEventPlayerChatString was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native GetEventPlayerChatStringMatched takes nothing returns string */ function GetEventPlayerChatStringMatched(C: Context, L: lua_State): number { console.warn('GetEventPlayerChatStringMatched was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native TriggerRegisterDeathEvent takes trigger whichTrigger, widget whichWidget returns event */ function TriggerRegisterDeathEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichWidget = lua_touserdata(L, 2); console.warn('TriggerRegisterDeathEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetTriggerUnit takes nothing returns unit */ function GetTriggerUnit(C: Context, L: lua_State): number { const thread = C.currentThread; if (thread && thread.triggerUnit) { lua_pushlightuserdata(L, thread.triggerUnit); } else { lua_pushnil(L); } return 1; } /** * native TriggerRegisterUnitStateEvent takes trigger whichTrigger, unit whichUnit, unitstate whichState, limitop opcode, real limitval returns event */ function TriggerRegisterUnitStateEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); const _whichState = lua_touserdata(L, 3); const _opcode = lua_touserdata(L, 4); const _limitval = luaL_checknumber(L, 5); console.warn('TriggerRegisterUnitStateEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventUnitState takes nothing returns unitstate */ function GetEventUnitState(C: Context, L: lua_State): number { console.warn('GetEventUnitState was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterUnitEvent takes trigger whichTrigger, unit whichUnit, unitevent whichEvent returns event */ function TriggerRegisterUnitEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); const _whichEvent = lua_touserdata(L, 3); console.warn('TriggerRegisterUnitEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventDamage takes nothing returns real */ function GetEventDamage(C: Context, L: lua_State): number { console.warn('GetEventDamage was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetEventDamageSource takes nothing returns unit */ function GetEventDamageSource(C: Context, L: lua_State): number { console.warn('GetEventDamageSource was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventDetectingPlayer takes nothing returns player */ function GetEventDetectingPlayer(C: Context, L: lua_State): number { console.warn('GetEventDetectingPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterFilterUnitEvent takes trigger whichTrigger, unit whichUnit, unitevent whichEvent, boolexpr filter returns event */ function TriggerRegisterFilterUnitEvent(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); const _whichEvent = lua_touserdata(L, 3); const _filter = lua_touserdata(L, 4); console.warn('TriggerRegisterFilterUnitEvent was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetEventTargetUnit takes nothing returns unit */ function GetEventTargetUnit(C: Context, L: lua_State): number { console.warn('GetEventTargetUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRegisterUnitInRange takes trigger whichTrigger, unit whichUnit, real range, boolexpr filter returns event */ function TriggerRegisterUnitInRange(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); const _range = luaL_checknumber(L, 3); const _filter = lua_touserdata(L, 4); console.warn('TriggerRegisterUnitInRange was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerAddCondition takes trigger whichTrigger, boolexpr condition returns triggercondition */ function TriggerAddCondition(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _condition = lua_touserdata(L, 2); console.warn('TriggerAddCondition was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRemoveCondition takes trigger whichTrigger, triggercondition whichCondition returns nothing */ function TriggerRemoveCondition(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichCondition = lua_touserdata(L, 2); console.warn('TriggerRemoveCondition was called but is not implemented :('); return 0; } /** * native TriggerClearConditions takes trigger whichTrigger returns nothing */ function TriggerClearConditions(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('TriggerClearConditions was called but is not implemented :('); return 0; } /** * native TriggerAddAction takes trigger whichTrigger, code actionFunc returns triggeraction */ function TriggerAddAction(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _actionFunc = luaL_ref(L, LUA_REGISTRYINDEX); console.warn('TriggerAddAction was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TriggerRemoveAction takes trigger whichTrigger, triggeraction whichAction returns nothing */ function TriggerRemoveAction(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); const _whichAction = lua_touserdata(L, 2); console.warn('TriggerRemoveAction was called but is not implemented :('); return 0; } /** * native TriggerClearActions takes trigger whichTrigger returns nothing */ function TriggerClearActions(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('TriggerClearActions was called but is not implemented :('); return 0; } /** * native TriggerSleepAction takes real timeout returns nothing */ function TriggerSleepAction(C: Context, L: lua_State): number { const timeout = luaL_checknumber(L, 1); lua_pushnumber(L, timeout); lua_yield(L, 1); return 0; } /** * native TriggerWaitForSound takes sound s, real offset returns nothing */ function TriggerWaitForSound(C: Context, L: lua_State): number { const _s = lua_touserdata(L, 1); const _offset = luaL_checknumber(L, 2); console.warn('TriggerWaitForSound was called but is not implemented :('); return 0; } /** * native TriggerEvaluate takes trigger whichTrigger returns boolean */ function TriggerEvaluate(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('TriggerEvaluate was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native TriggerExecute takes trigger whichTrigger returns nothing */ function TriggerExecute(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('TriggerExecute was called but is not implemented :('); return 0; } /** * native TriggerExecuteWait takes trigger whichTrigger returns nothing */ function TriggerExecuteWait(C: Context, L: lua_State): number { const _whichTrigger = lua_touserdata(L, 1); console.warn('TriggerExecuteWait was called but is not implemented :('); return 0; } /** * native TriggerSyncStart takes nothing returns nothing */ function TriggerSyncStart(_C: Context, _L: lua_State): number { console.warn('TriggerSyncStart was called but is not implemented :('); return 0; } /** * native TriggerSyncReady takes nothing returns nothing */ function TriggerSyncReady(_C: Context, _L: lua_State): number { console.warn('TriggerSyncReady was called but is not implemented :('); return 0; } /** * native GetWidgetLife takes widget whichWidget returns real */ function GetWidgetLife(C: Context, L: lua_State): number { const _whichWidget = lua_touserdata(L, 1); console.warn('GetWidgetLife was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetWidgetLife takes widget whichWidget, real newLife returns nothing */ function SetWidgetLife(C: Context, L: lua_State): number { const _whichWidget = lua_touserdata(L, 1); const _newLife = luaL_checknumber(L, 2); console.warn('SetWidgetLife was called but is not implemented :('); return 0; } /** * native GetWidgetX takes widget whichWidget returns real */ function GetWidgetX(C: Context, L: lua_State): number { const _whichWidget = lua_touserdata(L, 1); console.warn('GetWidgetX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetWidgetY takes widget whichWidget returns real */ function GetWidgetY(C: Context, L: lua_State): number { const _whichWidget = lua_touserdata(L, 1); console.warn('GetWidgetY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetTriggerWidget takes nothing returns widget */ function GetTriggerWidget(C: Context, L: lua_State): number { console.warn('GetTriggerWidget was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateDestructable takes integer objectid, real x, real y, real face, real scale, integer variation returns destructable */ function CreateDestructable(C: Context, L: lua_State): number { const _objectid = luaL_checkinteger(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _face = luaL_checknumber(L, 4); const _scale = luaL_checknumber(L, 5); const _variation = luaL_checkinteger(L, 6); console.warn('CreateDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateDestructableZ takes integer objectid, real x, real y, real z, real face, real scale, integer variation returns destructable */ function CreateDestructableZ(C: Context, L: lua_State): number { const _objectid = luaL_checkinteger(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); const _face = luaL_checknumber(L, 5); const _scale = luaL_checknumber(L, 6); const _variation = luaL_checkinteger(L, 7); console.warn('CreateDestructableZ was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateDeadDestructable takes integer objectid, real x, real y, real face, real scale, integer variation returns destructable */ function CreateDeadDestructable(C: Context, L: lua_State): number { const _objectid = luaL_checkinteger(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _face = luaL_checknumber(L, 4); const _scale = luaL_checknumber(L, 5); const _variation = luaL_checkinteger(L, 6); console.warn('CreateDeadDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateDeadDestructableZ takes integer objectid, real x, real y, real z, real face, real scale, integer variation returns destructable */ function CreateDeadDestructableZ(C: Context, L: lua_State): number { const _objectid = luaL_checkinteger(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); const _face = luaL_checknumber(L, 5); const _scale = luaL_checknumber(L, 6); const _variation = luaL_checkinteger(L, 7); console.warn('CreateDeadDestructableZ was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveDestructable takes destructable d returns nothing */ function RemoveDestructable(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('RemoveDestructable was called but is not implemented :('); return 0; } /** * native KillDestructable takes destructable d returns nothing */ function KillDestructable(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('KillDestructable was called but is not implemented :('); return 0; } /** * native SetDestructableInvulnerable takes destructable d, boolean flag returns nothing */ function SetDestructableInvulnerable(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetDestructableInvulnerable was called but is not implemented :('); return 0; } /** * native IsDestructableInvulnerable takes destructable d returns boolean */ function IsDestructableInvulnerable(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('IsDestructableInvulnerable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native EnumDestructablesInRect takes rect r, boolexpr filter, code actionFunc returns nothing */ function EnumDestructablesInRect(C: Context, L: lua_State): number { const _r = lua_touserdata(L, 1); const _filter = lua_touserdata(L, 2); const _actionFunc = luaL_ref(L, LUA_REGISTRYINDEX); console.warn('EnumDestructablesInRect was called but is not implemented :('); return 0; } /** * native GetDestructableTypeId takes destructable d returns integer */ function GetDestructableTypeId(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableTypeId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetDestructableX takes destructable d returns real */ function GetDestructableX(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetDestructableY takes destructable d returns real */ function GetDestructableY(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetDestructableLife takes destructable d, real life returns nothing */ function SetDestructableLife(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _life = luaL_checknumber(L, 2); console.warn('SetDestructableLife was called but is not implemented :('); return 0; } /** * native GetDestructableLife takes destructable d returns real */ function GetDestructableLife(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableLife was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetDestructableMaxLife takes destructable d, real max returns nothing */ function SetDestructableMaxLife(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _max = luaL_checknumber(L, 2); console.warn('SetDestructableMaxLife was called but is not implemented :('); return 0; } /** * native GetDestructableMaxLife takes destructable d returns real */ function GetDestructableMaxLife(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableMaxLife was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native DestructableRestoreLife takes destructable d, real life, boolean birth returns nothing */ function DestructableRestoreLife(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _life = luaL_checknumber(L, 2); const _birth = lua_toboolean(L, 3); console.warn('DestructableRestoreLife was called but is not implemented :('); return 0; } /** * native QueueDestructableAnimation takes destructable d, string whichAnimation returns nothing */ function QueueDestructableAnimation(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _whichAnimation = luaL_checkstring(L, 2); console.warn('QueueDestructableAnimation was called but is not implemented :('); return 0; } /** * native SetDestructableAnimation takes destructable d, string whichAnimation returns nothing */ function SetDestructableAnimation(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _whichAnimation = luaL_checkstring(L, 2); console.warn('SetDestructableAnimation was called but is not implemented :('); return 0; } /** * native SetDestructableAnimationSpeed takes destructable d, real speedFactor returns nothing */ function SetDestructableAnimationSpeed(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _speedFactor = luaL_checknumber(L, 2); console.warn('SetDestructableAnimationSpeed was called but is not implemented :('); return 0; } /** * native ShowDestructable takes destructable d, boolean flag returns nothing */ function ShowDestructable(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('ShowDestructable was called but is not implemented :('); return 0; } /** * native GetDestructableOccluderHeight takes destructable d returns real */ function GetDestructableOccluderHeight(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableOccluderHeight was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetDestructableOccluderHeight takes destructable d, real height returns nothing */ function SetDestructableOccluderHeight(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); const _height = luaL_checknumber(L, 2); console.warn('SetDestructableOccluderHeight was called but is not implemented :('); return 0; } /** * native GetDestructableName takes destructable d returns string */ function GetDestructableName(C: Context, L: lua_State): number { const _d = lua_touserdata(L, 1); console.warn('GetDestructableName was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native GetTriggerDestructable takes nothing returns destructable */ function GetTriggerDestructable(C: Context, L: lua_State): number { console.warn('GetTriggerDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateItem takes integer itemid, real x, real y returns item */ function CreateItem(C: Context, L: lua_State): number { const _itemid = luaL_checkinteger(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('CreateItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveItem takes item whichItem returns nothing */ function RemoveItem(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('RemoveItem was called but is not implemented :('); return 0; } /** * native GetItemPlayer takes item whichItem returns player */ function GetItemPlayer(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('GetItemPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native GetItemTypeId takes item i returns integer */ function GetItemTypeId(C: Context, L: lua_State): number { const _i = lua_touserdata(L, 1); console.warn('GetItemTypeId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetItemX takes item i returns real */ function GetItemX(C: Context, L: lua_State): number { const _i = lua_touserdata(L, 1); console.warn('GetItemX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetItemY takes item i returns real */ function GetItemY(C: Context, L: lua_State): number { const _i = lua_touserdata(L, 1); console.warn('GetItemY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetItemPosition takes item i, real x, real y returns nothing */ function SetItemPosition(C: Context, L: lua_State): number { const _i = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('SetItemPosition was called but is not implemented :('); return 0; } /** * native SetItemDropOnDeath takes item whichItem, boolean flag returns nothing */ function SetItemDropOnDeath(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetItemDropOnDeath was called but is not implemented :('); return 0; } /** * native SetItemDroppable takes item i, boolean flag returns nothing */ function SetItemDroppable(C: Context, L: lua_State): number { const _i = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetItemDroppable was called but is not implemented :('); return 0; } /** * native SetItemPawnable takes item i, boolean flag returns nothing */ function SetItemPawnable(C: Context, L: lua_State): number { const _i = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetItemPawnable was called but is not implemented :('); return 0; } /** * native SetItemPlayer takes item whichItem, player whichPlayer, boolean changeColor returns nothing */ function SetItemPlayer(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _changeColor = lua_toboolean(L, 3); console.warn('SetItemPlayer was called but is not implemented :('); return 0; } /** * native SetItemInvulnerable takes item whichItem, boolean flag returns nothing */ function SetItemInvulnerable(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetItemInvulnerable was called but is not implemented :('); return 0; } /** * native IsItemInvulnerable takes item whichItem returns boolean */ function IsItemInvulnerable(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('IsItemInvulnerable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetItemVisible takes item whichItem, boolean show returns nothing */ function SetItemVisible(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _show = lua_toboolean(L, 2); console.warn('SetItemVisible was called but is not implemented :('); return 0; } /** * native IsItemVisible takes item whichItem returns boolean */ function IsItemVisible(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('IsItemVisible was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemOwned takes item whichItem returns boolean */ function IsItemOwned(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('IsItemOwned was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemPowerup takes item whichItem returns boolean */ function IsItemPowerup(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('IsItemPowerup was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemSellable takes item whichItem returns boolean */ function IsItemSellable(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('IsItemSellable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemPawnable takes item whichItem returns boolean */ function IsItemPawnable(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('IsItemPawnable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemIdPowerup takes integer itemId returns boolean */ function IsItemIdPowerup(C: Context, L: lua_State): number { const _itemId = luaL_checkinteger(L, 1); console.warn('IsItemIdPowerup was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemIdSellable takes integer itemId returns boolean */ function IsItemIdSellable(C: Context, L: lua_State): number { const _itemId = luaL_checkinteger(L, 1); console.warn('IsItemIdSellable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsItemIdPawnable takes integer itemId returns boolean */ function IsItemIdPawnable(C: Context, L: lua_State): number { const _itemId = luaL_checkinteger(L, 1); console.warn('IsItemIdPawnable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native EnumItemsInRect takes rect r, boolexpr filter, code actionFunc returns nothing */ function EnumItemsInRect(C: Context, L: lua_State): number { const _r = lua_touserdata(L, 1); const _filter = lua_touserdata(L, 2); const _actionFunc = luaL_ref(L, LUA_REGISTRYINDEX); console.warn('EnumItemsInRect was called but is not implemented :('); return 0; } /** * native GetItemLevel takes item whichItem returns integer */ function GetItemLevel(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('GetItemLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetItemType takes item whichItem returns itemtype */ function GetItemType(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('GetItemType was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SetItemDropID takes item whichItem, integer unitId returns nothing */ function SetItemDropID(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _unitId = luaL_checkinteger(L, 2); console.warn('SetItemDropID was called but is not implemented :('); return 0; } /** * constant native GetItemName takes item whichItem returns string */ function GetItemName(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('GetItemName was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native GetItemCharges takes item whichItem returns integer */ function GetItemCharges(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('GetItemCharges was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetItemCharges takes item whichItem, integer charges returns nothing */ function SetItemCharges(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _charges = luaL_checkinteger(L, 2); console.warn('SetItemCharges was called but is not implemented :('); return 0; } /** * native GetItemUserData takes item whichItem returns integer */ function GetItemUserData(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('GetItemUserData was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetItemUserData takes item whichItem, integer data returns nothing */ function SetItemUserData(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _data = luaL_checkinteger(L, 2); console.warn('SetItemUserData was called but is not implemented :('); return 0; } /** * native CreateUnit takes player id, integer unitid, real x, real y, real face returns unit */ function CreateUnit(C: Context, L: lua_State): number { const id = lua_touserdata(L, 1); const unitid = luaL_checkinteger(L, 2); const x = luaL_checknumber(L, 3); const y = luaL_checknumber(L, 4); const face = luaL_checknumber(L, 5); lua_pushlightuserdata(L, C.addHandle(new JassUnit(id, unitid, x, y, face))); return 1; } /** * native CreateUnitByName takes player whichPlayer, string unitname, real x, real y, real face returns unit */ function CreateUnitByName(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _unitname = luaL_checkstring(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); const _face = luaL_checknumber(L, 5); console.warn('CreateUnitByName was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateUnitAtLoc takes player id, integer unitid, location whichLocation, real face returns unit */ function CreateUnitAtLoc(C: Context, L: lua_State): number { const _id = lua_touserdata(L, 1); const _unitid = luaL_checkinteger(L, 2); const _whichLocation = lua_touserdata(L, 3); const _face = luaL_checknumber(L, 4); console.warn('CreateUnitAtLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateUnitAtLocByName takes player id, string unitname, location whichLocation, real face returns unit */ function CreateUnitAtLocByName(C: Context, L: lua_State): number { const _id = lua_touserdata(L, 1); const _unitname = luaL_checkstring(L, 2); const _whichLocation = lua_touserdata(L, 3); const _face = luaL_checknumber(L, 4); console.warn('CreateUnitAtLocByName was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateCorpse takes player whichPlayer, integer unitid, real x, real y, real face returns unit */ function CreateCorpse(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _unitid = luaL_checkinteger(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); const _face = luaL_checknumber(L, 5); console.warn('CreateCorpse was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native KillUnit takes unit whichUnit returns nothing */ function KillUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('KillUnit was called but is not implemented :('); return 0; } /** * native RemoveUnit takes unit whichUnit returns nothing */ function RemoveUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('RemoveUnit was called but is not implemented :('); return 0; } /** * native ShowUnit takes unit whichUnit, boolean show returns nothing */ function ShowUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _show = lua_toboolean(L, 2); console.warn('ShowUnit was called but is not implemented :('); return 0; } /** * native SetUnitState takes unit whichUnit, unitstate whichUnitState, real newVal returns nothing */ function SetUnitState(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichUnitState = lua_touserdata(L, 2); const _newVal = luaL_checknumber(L, 3); console.warn('SetUnitState was called but is not implemented :('); return 0; } /** * native SetUnitX takes unit whichUnit, real newX returns nothing */ function SetUnitX(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newX = luaL_checknumber(L, 2); console.warn('SetUnitX was called but is not implemented :('); return 0; } /** * native SetUnitY takes unit whichUnit, real newY returns nothing */ function SetUnitY(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newY = luaL_checknumber(L, 2); console.warn('SetUnitY was called but is not implemented :('); return 0; } /** * native SetUnitPosition takes unit whichUnit, real newX, real newY returns nothing */ function SetUnitPosition(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newX = luaL_checknumber(L, 2); const _newY = luaL_checknumber(L, 3); console.warn('SetUnitPosition was called but is not implemented :('); return 0; } /** * native SetUnitPositionLoc takes unit whichUnit, location whichLocation returns nothing */ function SetUnitPositionLoc(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); console.warn('SetUnitPositionLoc was called but is not implemented :('); return 0; } /** * native SetUnitFacing takes unit whichUnit, real facingAngle returns nothing */ function SetUnitFacing(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _facingAngle = luaL_checknumber(L, 2); console.warn('SetUnitFacing was called but is not implemented :('); return 0; } /** * native SetUnitFacingTimed takes unit whichUnit, real facingAngle, real duration returns nothing */ function SetUnitFacingTimed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _facingAngle = luaL_checknumber(L, 2); const _duration = luaL_checknumber(L, 3); console.warn('SetUnitFacingTimed was called but is not implemented :('); return 0; } /** * native SetUnitMoveSpeed takes unit whichUnit, real newSpeed returns nothing */ function SetUnitMoveSpeed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newSpeed = luaL_checknumber(L, 2); console.warn('SetUnitMoveSpeed was called but is not implemented :('); return 0; } /** * native SetUnitFlyHeight takes unit whichUnit, real newHeight, real rate returns nothing */ function SetUnitFlyHeight(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newHeight = luaL_checknumber(L, 2); const _rate = luaL_checknumber(L, 3); console.warn('SetUnitFlyHeight was called but is not implemented :('); return 0; } /** * native SetUnitTurnSpeed takes unit whichUnit, real newTurnSpeed returns nothing */ function SetUnitTurnSpeed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newTurnSpeed = luaL_checknumber(L, 2); console.warn('SetUnitTurnSpeed was called but is not implemented :('); return 0; } /** * native SetUnitPropWindow takes unit whichUnit, real newPropWindowAngle returns nothing */ function SetUnitPropWindow(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newPropWindowAngle = luaL_checknumber(L, 2); console.warn('SetUnitPropWindow was called but is not implemented :('); return 0; } /** * native SetUnitAcquireRange takes unit whichUnit, real newAcquireRange returns nothing */ function SetUnitAcquireRange(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _newAcquireRange = luaL_checknumber(L, 2); console.warn('SetUnitAcquireRange was called but is not implemented :('); return 0; } /** * native SetUnitCreepGuard takes unit whichUnit, boolean creepGuard returns nothing */ function SetUnitCreepGuard(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _creepGuard = lua_toboolean(L, 2); console.warn('SetUnitCreepGuard was called but is not implemented :('); return 0; } /** * native GetUnitAcquireRange takes unit whichUnit returns real */ function GetUnitAcquireRange(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitAcquireRange was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitTurnSpeed takes unit whichUnit returns real */ function GetUnitTurnSpeed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitTurnSpeed was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitPropWindow takes unit whichUnit returns real */ function GetUnitPropWindow(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitPropWindow was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitFlyHeight takes unit whichUnit returns real */ function GetUnitFlyHeight(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitFlyHeight was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitDefaultAcquireRange takes unit whichUnit returns real */ function GetUnitDefaultAcquireRange(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitDefaultAcquireRange was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitDefaultTurnSpeed takes unit whichUnit returns real */ function GetUnitDefaultTurnSpeed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitDefaultTurnSpeed was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitDefaultPropWindow takes unit whichUnit returns real */ function GetUnitDefaultPropWindow(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitDefaultPropWindow was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetUnitDefaultFlyHeight takes unit whichUnit returns real */ function GetUnitDefaultFlyHeight(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitDefaultFlyHeight was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetUnitOwner takes unit whichUnit, player whichPlayer, boolean changeColor returns nothing */ function SetUnitOwner(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _changeColor = lua_toboolean(L, 3); console.warn('SetUnitOwner was called but is not implemented :('); return 0; } /** * native SetUnitColor takes unit whichUnit, playercolor whichColor returns nothing */ function SetUnitColor(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichColor = lua_touserdata(L, 2); console.warn('SetUnitColor was called but is not implemented :('); return 0; } /** * native SetUnitScale takes unit whichUnit, real scaleX, real scaleY, real scaleZ returns nothing */ function SetUnitScale(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _scaleX = luaL_checknumber(L, 2); const _scaleY = luaL_checknumber(L, 3); const _scaleZ = luaL_checknumber(L, 4); console.warn('SetUnitScale was called but is not implemented :('); return 0; } /** * native SetUnitTimeScale takes unit whichUnit, real timeScale returns nothing */ function SetUnitTimeScale(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _timeScale = luaL_checknumber(L, 2); console.warn('SetUnitTimeScale was called but is not implemented :('); return 0; } /** * native SetUnitBlendTime takes unit whichUnit, real blendTime returns nothing */ function SetUnitBlendTime(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _blendTime = luaL_checknumber(L, 2); console.warn('SetUnitBlendTime was called but is not implemented :('); return 0; } /** * native SetUnitVertexColor takes unit whichUnit, integer red, integer green, integer blue, integer alpha returns nothing */ function SetUnitVertexColor(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('SetUnitVertexColor was called but is not implemented :('); return 0; } /** * native QueueUnitAnimation takes unit whichUnit, string whichAnimation returns nothing */ function QueueUnitAnimation(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichAnimation = luaL_checkstring(L, 2); console.warn('QueueUnitAnimation was called but is not implemented :('); return 0; } /** * native SetUnitAnimation takes unit whichUnit, string whichAnimation returns nothing */ function SetUnitAnimation(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichAnimation = luaL_checkstring(L, 2); console.warn('SetUnitAnimation was called but is not implemented :('); return 0; } /** * native SetUnitAnimationByIndex takes unit whichUnit, integer whichAnimation returns nothing */ function SetUnitAnimationByIndex(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichAnimation = luaL_checkinteger(L, 2); console.warn('SetUnitAnimationByIndex was called but is not implemented :('); return 0; } /** * native SetUnitAnimationWithRarity takes unit whichUnit, string whichAnimation, raritycontrol rarity returns nothing */ function SetUnitAnimationWithRarity(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichAnimation = luaL_checkstring(L, 2); const _rarity = lua_touserdata(L, 3); console.warn('SetUnitAnimationWithRarity was called but is not implemented :('); return 0; } /** * native AddUnitAnimationProperties takes unit whichUnit, string animProperties, boolean add returns nothing */ function AddUnitAnimationProperties(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _animProperties = luaL_checkstring(L, 2); const _add = lua_toboolean(L, 3); console.warn('AddUnitAnimationProperties was called but is not implemented :('); return 0; } /** * native SetUnitLookAt takes unit whichUnit, string whichBone, unit lookAtTarget, real offsetX, real offsetY, real offsetZ returns nothing */ function SetUnitLookAt(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichBone = luaL_checkstring(L, 2); const _lookAtTarget = lua_touserdata(L, 3); const _offsetX = luaL_checknumber(L, 4); const _offsetY = luaL_checknumber(L, 5); const _offsetZ = luaL_checknumber(L, 6); console.warn('SetUnitLookAt was called but is not implemented :('); return 0; } /** * native ResetUnitLookAt takes unit whichUnit returns nothing */ function ResetUnitLookAt(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('ResetUnitLookAt was called but is not implemented :('); return 0; } /** * native SetUnitRescuable takes unit whichUnit, player byWhichPlayer, boolean flag returns nothing */ function SetUnitRescuable(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _byWhichPlayer = lua_touserdata(L, 2); const _flag = lua_toboolean(L, 3); console.warn('SetUnitRescuable was called but is not implemented :('); return 0; } /** * native SetUnitRescueRange takes unit whichUnit, real range returns nothing */ function SetUnitRescueRange(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _range = luaL_checknumber(L, 2); console.warn('SetUnitRescueRange was called but is not implemented :('); return 0; } /** * native SetHeroStr takes unit whichHero, integer newStr, boolean permanent returns nothing */ function SetHeroStr(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _newStr = luaL_checkinteger(L, 2); const _permanent = lua_toboolean(L, 3); console.warn('SetHeroStr was called but is not implemented :('); return 0; } /** * native SetHeroAgi takes unit whichHero, integer newAgi, boolean permanent returns nothing */ function SetHeroAgi(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _newAgi = luaL_checkinteger(L, 2); const _permanent = lua_toboolean(L, 3); console.warn('SetHeroAgi was called but is not implemented :('); return 0; } /** * native SetHeroInt takes unit whichHero, integer newInt, boolean permanent returns nothing */ function SetHeroInt(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _newInt = luaL_checkinteger(L, 2); const _permanent = lua_toboolean(L, 3); console.warn('SetHeroInt was called but is not implemented :('); return 0; } /** * native GetHeroStr takes unit whichHero, boolean includeBonuses returns integer */ function GetHeroStr(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _includeBonuses = lua_toboolean(L, 2); console.warn('GetHeroStr was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetHeroAgi takes unit whichHero, boolean includeBonuses returns integer */ function GetHeroAgi(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _includeBonuses = lua_toboolean(L, 2); console.warn('GetHeroAgi was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetHeroInt takes unit whichHero, boolean includeBonuses returns integer */ function GetHeroInt(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _includeBonuses = lua_toboolean(L, 2); console.warn('GetHeroInt was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native UnitStripHeroLevel takes unit whichHero, integer howManyLevels returns boolean */ function UnitStripHeroLevel(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _howManyLevels = luaL_checkinteger(L, 2); console.warn('UnitStripHeroLevel was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetHeroXP takes unit whichHero returns integer */ function GetHeroXP(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); console.warn('GetHeroXP was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetHeroXP takes unit whichHero, integer newXpVal, boolean showEyeCandy returns nothing */ function SetHeroXP(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _newXpVal = luaL_checkinteger(L, 2); const _showEyeCandy = lua_toboolean(L, 3); console.warn('SetHeroXP was called but is not implemented :('); return 0; } /** * native GetHeroSkillPoints takes unit whichHero returns integer */ function GetHeroSkillPoints(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); console.warn('GetHeroSkillPoints was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native UnitModifySkillPoints takes unit whichHero, integer skillPointDelta returns boolean */ function UnitModifySkillPoints(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _skillPointDelta = luaL_checkinteger(L, 2); console.warn('UnitModifySkillPoints was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native AddHeroXP takes unit whichHero, integer xpToAdd, boolean showEyeCandy returns nothing */ function AddHeroXP(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _xpToAdd = luaL_checkinteger(L, 2); const _showEyeCandy = lua_toboolean(L, 3); console.warn('AddHeroXP was called but is not implemented :('); return 0; } /** * native SetHeroLevel takes unit whichHero, integer level, boolean showEyeCandy returns nothing */ function SetHeroLevel(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _level = luaL_checkinteger(L, 2); const _showEyeCandy = lua_toboolean(L, 3); console.warn('SetHeroLevel was called but is not implemented :('); return 0; } /** * constant native GetHeroLevel takes unit whichHero returns integer */ function GetHeroLevel(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); console.warn('GetHeroLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetUnitLevel takes unit whichUnit returns integer */ function GetUnitLevel(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetHeroProperName takes unit whichHero returns string */ function GetHeroProperName(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); console.warn('GetHeroProperName was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native SuspendHeroXP takes unit whichHero, boolean flag returns nothing */ function SuspendHeroXP(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SuspendHeroXP was called but is not implemented :('); return 0; } /** * native IsSuspendedXP takes unit whichHero returns boolean */ function IsSuspendedXP(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); console.warn('IsSuspendedXP was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SelectHeroSkill takes unit whichHero, integer abilcode returns nothing */ function SelectHeroSkill(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _abilcode = luaL_checkinteger(L, 2); console.warn('SelectHeroSkill was called but is not implemented :('); return 0; } /** * native GetUnitAbilityLevel takes unit whichUnit, integer abilcode returns integer */ function GetUnitAbilityLevel(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilcode = luaL_checkinteger(L, 2); console.warn('GetUnitAbilityLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native DecUnitAbilityLevel takes unit whichUnit, integer abilcode returns integer */ function DecUnitAbilityLevel(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilcode = luaL_checkinteger(L, 2); console.warn('DecUnitAbilityLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native IncUnitAbilityLevel takes unit whichUnit, integer abilcode returns integer */ function IncUnitAbilityLevel(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilcode = luaL_checkinteger(L, 2); console.warn('IncUnitAbilityLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetUnitAbilityLevel takes unit whichUnit, integer abilcode, integer level returns integer */ function SetUnitAbilityLevel(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilcode = luaL_checkinteger(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('SetUnitAbilityLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native ReviveHero takes unit whichHero, real x, real y, boolean doEyecandy returns boolean */ function ReviveHero(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _doEyecandy = lua_toboolean(L, 4); console.warn('ReviveHero was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native ReviveHeroLoc takes unit whichHero, location loc, boolean doEyecandy returns boolean */ function ReviveHeroLoc(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); const _loc = lua_touserdata(L, 2); const _doEyecandy = lua_toboolean(L, 3); console.warn('ReviveHeroLoc was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetUnitExploded takes unit whichUnit, boolean exploded returns nothing */ function SetUnitExploded(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _exploded = lua_toboolean(L, 2); console.warn('SetUnitExploded was called but is not implemented :('); return 0; } /** * native SetUnitInvulnerable takes unit whichUnit, boolean flag returns nothing */ function SetUnitInvulnerable(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetUnitInvulnerable was called but is not implemented :('); return 0; } /** * native PauseUnit takes unit whichUnit, boolean flag returns nothing */ function PauseUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('PauseUnit was called but is not implemented :('); return 0; } /** * native IsUnitPaused takes unit whichHero returns boolean */ function IsUnitPaused(C: Context, L: lua_State): number { const _whichHero = lua_touserdata(L, 1); console.warn('IsUnitPaused was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetUnitPathing takes unit whichUnit, boolean flag returns nothing */ function SetUnitPathing(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetUnitPathing was called but is not implemented :('); return 0; } /** * native ClearSelection takes nothing returns nothing */ function ClearSelection(_C: Context, _L: lua_State): number { console.warn('ClearSelection was called but is not implemented :('); return 0; } /** * native SelectUnit takes unit whichUnit, boolean flag returns nothing */ function SelectUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SelectUnit was called but is not implemented :('); return 0; } /** * native GetUnitPointValue takes unit whichUnit returns integer */ function GetUnitPointValue(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitPointValue was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetUnitPointValueByType takes integer unitType returns integer */ function GetUnitPointValueByType(C: Context, L: lua_State): number { const _unitType = luaL_checkinteger(L, 1); console.warn('GetUnitPointValueByType was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native UnitAddItem takes unit whichUnit, item whichItem returns boolean */ function UnitAddItem(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); console.warn('UnitAddItem was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitAddItemById takes unit whichUnit, integer itemId returns item */ function UnitAddItemById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _itemId = luaL_checkinteger(L, 2); console.warn('UnitAddItemById was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native UnitAddItemToSlotById takes unit whichUnit, integer itemId, integer itemSlot returns boolean */ function UnitAddItemToSlotById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _itemId = luaL_checkinteger(L, 2); const _itemSlot = luaL_checkinteger(L, 3); console.warn('UnitAddItemToSlotById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitRemoveItem takes unit whichUnit, item whichItem returns nothing */ function UnitRemoveItem(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); console.warn('UnitRemoveItem was called but is not implemented :('); return 0; } /** * native UnitRemoveItemFromSlot takes unit whichUnit, integer itemSlot returns item */ function UnitRemoveItemFromSlot(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _itemSlot = luaL_checkinteger(L, 2); console.warn('UnitRemoveItemFromSlot was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native UnitHasItem takes unit whichUnit, item whichItem returns boolean */ function UnitHasItem(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); console.warn('UnitHasItem was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitItemInSlot takes unit whichUnit, integer itemSlot returns item */ function UnitItemInSlot(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _itemSlot = luaL_checkinteger(L, 2); console.warn('UnitItemInSlot was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native UnitInventorySize takes unit whichUnit returns integer */ function UnitInventorySize(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitInventorySize was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native UnitDropItemPoint takes unit whichUnit, item whichItem, real x, real y returns boolean */ function UnitDropItemPoint(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('UnitDropItemPoint was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitDropItemSlot takes unit whichUnit, item whichItem, integer slot returns boolean */ function UnitDropItemSlot(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); const _slot = luaL_checkinteger(L, 3); console.warn('UnitDropItemSlot was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitDropItemTarget takes unit whichUnit, item whichItem, widget target returns boolean */ function UnitDropItemTarget(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); const _target = lua_touserdata(L, 3); console.warn('UnitDropItemTarget was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitUseItem takes unit whichUnit, item whichItem returns boolean */ function UnitUseItem(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); console.warn('UnitUseItem was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitUseItemPoint takes unit whichUnit, item whichItem, real x, real y returns boolean */ function UnitUseItemPoint(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('UnitUseItemPoint was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitUseItemTarget takes unit whichUnit, item whichItem, widget target returns boolean */ function UnitUseItemTarget(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichItem = lua_touserdata(L, 2); const _target = lua_touserdata(L, 3); console.warn('UnitUseItemTarget was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native GetUnitX takes unit whichUnit returns real */ function GetUnitX(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetUnitY takes unit whichUnit returns real */ function GetUnitY(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetUnitLoc takes unit whichUnit returns location */ function GetUnitLoc(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetUnitFacing takes unit whichUnit returns real */ function GetUnitFacing(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitFacing was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetUnitMoveSpeed takes unit whichUnit returns real */ function GetUnitMoveSpeed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitMoveSpeed was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetUnitDefaultMoveSpeed takes unit whichUnit returns real */ function GetUnitDefaultMoveSpeed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitDefaultMoveSpeed was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetUnitState takes unit whichUnit, unitstate whichUnitState returns real */ function GetUnitState(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichUnitState = lua_touserdata(L, 2); console.warn('GetUnitState was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetOwningPlayer takes unit whichUnit returns player */ function GetOwningPlayer(C: Context, L: lua_State): number { const whichUnit = lua_touserdata(L, 1); lua_pushlightuserdata(L, whichUnit.player); return 1; } /** * constant native GetUnitTypeId takes unit whichUnit returns integer */ function GetUnitTypeId(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitTypeId was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetUnitRace takes unit whichUnit returns race */ function GetUnitRace(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitRace was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetUnitName takes unit whichUnit returns string */ function GetUnitName(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitName was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * constant native GetUnitFoodUsed takes unit whichUnit returns integer */ function GetUnitFoodUsed(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitFoodUsed was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetUnitFoodMade takes unit whichUnit returns integer */ function GetUnitFoodMade(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitFoodMade was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetFoodMade takes integer unitId returns integer */ function GetFoodMade(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); console.warn('GetFoodMade was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetFoodUsed takes integer unitId returns integer */ function GetFoodUsed(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); console.warn('GetFoodUsed was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetUnitUseFood takes unit whichUnit, boolean useFood returns nothing */ function SetUnitUseFood(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _useFood = lua_toboolean(L, 2); console.warn('SetUnitUseFood was called but is not implemented :('); return 0; } /** * constant native GetUnitRallyPoint takes unit whichUnit returns location */ function GetUnitRallyPoint(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitRallyPoint was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetUnitRallyUnit takes unit whichUnit returns unit */ function GetUnitRallyUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitRallyUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetUnitRallyDestructable takes unit whichUnit returns destructable */ function GetUnitRallyDestructable(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitRallyDestructable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native IsUnitInGroup takes unit whichUnit, group whichGroup returns boolean */ function IsUnitInGroup(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichGroup = lua_touserdata(L, 2); console.warn('IsUnitInGroup was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitInForce takes unit whichUnit, force whichForce returns boolean */ function IsUnitInForce(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichForce = lua_touserdata(L, 2); console.warn('IsUnitInForce was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitOwnedByPlayer takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitOwnedByPlayer(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitOwnedByPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitAlly takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitAlly(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitAlly was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitEnemy takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitEnemy(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitEnemy was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitVisible takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitVisible(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitVisible was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitDetected takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitDetected(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitDetected was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitInvisible takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitInvisible(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitInvisible was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitFogged takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitFogged(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitFogged was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitMasked takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitMasked(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitMasked was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitSelected takes unit whichUnit, player whichPlayer returns boolean */ function IsUnitSelected(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsUnitSelected was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitRace takes unit whichUnit, race whichRace returns boolean */ function IsUnitRace(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichRace = lua_touserdata(L, 2); console.warn('IsUnitRace was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitType takes unit whichUnit, unittype whichUnitType returns boolean */ function IsUnitType(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichUnitType = lua_touserdata(L, 2); console.warn('IsUnitType was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnit takes unit whichUnit, unit whichSpecifiedUnit returns boolean */ function IsUnit(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichSpecifiedUnit = lua_touserdata(L, 2); console.warn('IsUnit was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitInRange takes unit whichUnit, unit otherUnit, real distance returns boolean */ function IsUnitInRange(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _otherUnit = lua_touserdata(L, 2); const _distance = luaL_checknumber(L, 3); console.warn('IsUnitInRange was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitInRangeXY takes unit whichUnit, real x, real y, real distance returns boolean */ function IsUnitInRangeXY(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _distance = luaL_checknumber(L, 4); console.warn('IsUnitInRangeXY was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitInRangeLoc takes unit whichUnit, location whichLocation, real distance returns boolean */ function IsUnitInRangeLoc(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); const _distance = luaL_checknumber(L, 3); console.warn('IsUnitInRangeLoc was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitHidden takes unit whichUnit returns boolean */ function IsUnitHidden(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('IsUnitHidden was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitIllusion takes unit whichUnit returns boolean */ function IsUnitIllusion(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('IsUnitIllusion was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitInTransport takes unit whichUnit, unit whichTransport returns boolean */ function IsUnitInTransport(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichTransport = lua_touserdata(L, 2); console.warn('IsUnitInTransport was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitLoaded takes unit whichUnit returns boolean */ function IsUnitLoaded(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('IsUnitLoaded was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsHeroUnitId takes integer unitId returns boolean */ function IsHeroUnitId(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); console.warn('IsHeroUnitId was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsUnitIdType takes integer unitId, unittype whichUnitType returns boolean */ function IsUnitIdType(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); const _whichUnitType = lua_touserdata(L, 2); console.warn('IsUnitIdType was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitShareVision takes unit whichUnit, player whichPlayer, boolean share returns nothing */ function UnitShareVision(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); const _share = lua_toboolean(L, 3); console.warn('UnitShareVision was called but is not implemented :('); return 0; } /** * native UnitSuspendDecay takes unit whichUnit, boolean suspend returns nothing */ function UnitSuspendDecay(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _suspend = lua_toboolean(L, 2); console.warn('UnitSuspendDecay was called but is not implemented :('); return 0; } /** * native UnitAddType takes unit whichUnit, unittype whichUnitType returns boolean */ function UnitAddType(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichUnitType = lua_touserdata(L, 2); console.warn('UnitAddType was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitRemoveType takes unit whichUnit, unittype whichUnitType returns boolean */ function UnitRemoveType(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _whichUnitType = lua_touserdata(L, 2); console.warn('UnitRemoveType was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitAddAbility takes unit whichUnit, integer abilityId returns boolean */ function UnitAddAbility(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilityId = luaL_checkinteger(L, 2); console.warn('UnitAddAbility was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitRemoveAbility takes unit whichUnit, integer abilityId returns boolean */ function UnitRemoveAbility(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilityId = luaL_checkinteger(L, 2); console.warn('UnitRemoveAbility was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitMakeAbilityPermanent takes unit whichUnit, boolean permanent, integer abilityId returns boolean */ function UnitMakeAbilityPermanent(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _permanent = lua_toboolean(L, 2); const _abilityId = luaL_checkinteger(L, 3); console.warn('UnitMakeAbilityPermanent was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitRemoveBuffs takes unit whichUnit, boolean removePositive, boolean removeNegative returns nothing */ function UnitRemoveBuffs(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _removePositive = lua_toboolean(L, 2); const _removeNegative = lua_toboolean(L, 3); console.warn('UnitRemoveBuffs was called but is not implemented :('); return 0; } /** * native UnitRemoveBuffsEx takes unit whichUnit, boolean removePositive, boolean removeNegative, boolean magic, boolean physical, boolean timedLife, boolean aura, boolean autoDispel returns nothing */ function UnitRemoveBuffsEx(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _removePositive = lua_toboolean(L, 2); const _removeNegative = lua_toboolean(L, 3); const _magic = lua_toboolean(L, 4); const _physical = lua_toboolean(L, 5); const _timedLife = lua_toboolean(L, 6); const _aura = lua_toboolean(L, 7); const _autoDispel = lua_toboolean(L, 8); console.warn('UnitRemoveBuffsEx was called but is not implemented :('); return 0; } /** * native UnitHasBuffsEx takes unit whichUnit, boolean removePositive, boolean removeNegative, boolean magic, boolean physical, boolean timedLife, boolean aura, boolean autoDispel returns boolean */ function UnitHasBuffsEx(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _removePositive = lua_toboolean(L, 2); const _removeNegative = lua_toboolean(L, 3); const _magic = lua_toboolean(L, 4); const _physical = lua_toboolean(L, 5); const _timedLife = lua_toboolean(L, 6); const _aura = lua_toboolean(L, 7); const _autoDispel = lua_toboolean(L, 8); console.warn('UnitHasBuffsEx was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitCountBuffsEx takes unit whichUnit, boolean removePositive, boolean removeNegative, boolean magic, boolean physical, boolean timedLife, boolean aura, boolean autoDispel returns integer */ function UnitCountBuffsEx(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _removePositive = lua_toboolean(L, 2); const _removeNegative = lua_toboolean(L, 3); const _magic = lua_toboolean(L, 4); const _physical = lua_toboolean(L, 5); const _timedLife = lua_toboolean(L, 6); const _aura = lua_toboolean(L, 7); const _autoDispel = lua_toboolean(L, 8); console.warn('UnitCountBuffsEx was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native UnitAddSleep takes unit whichUnit, boolean add returns nothing */ function UnitAddSleep(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _add = lua_toboolean(L, 2); console.warn('UnitAddSleep was called but is not implemented :('); return 0; } /** * native UnitCanSleep takes unit whichUnit returns boolean */ function UnitCanSleep(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitCanSleep was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitAddSleepPerm takes unit whichUnit, boolean add returns nothing */ function UnitAddSleepPerm(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _add = lua_toboolean(L, 2); console.warn('UnitAddSleepPerm was called but is not implemented :('); return 0; } /** * native UnitCanSleepPerm takes unit whichUnit returns boolean */ function UnitCanSleepPerm(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitCanSleepPerm was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitIsSleeping takes unit whichUnit returns boolean */ function UnitIsSleeping(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitIsSleeping was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitWakeUp takes unit whichUnit returns nothing */ function UnitWakeUp(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitWakeUp was called but is not implemented :('); return 0; } /** * native UnitApplyTimedLife takes unit whichUnit, integer buffId, real duration returns nothing */ function UnitApplyTimedLife(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _buffId = luaL_checkinteger(L, 2); const _duration = luaL_checknumber(L, 3); console.warn('UnitApplyTimedLife was called but is not implemented :('); return 0; } /** * native UnitIgnoreAlarm takes unit whichUnit, boolean flag returns boolean */ function UnitIgnoreAlarm(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('UnitIgnoreAlarm was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitIgnoreAlarmToggled takes unit whichUnit returns boolean */ function UnitIgnoreAlarmToggled(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitIgnoreAlarmToggled was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitResetCooldown takes unit whichUnit returns nothing */ function UnitResetCooldown(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('UnitResetCooldown was called but is not implemented :('); return 0; } /** * native UnitSetConstructionProgress takes unit whichUnit, integer constructionPercentage returns nothing */ function UnitSetConstructionProgress(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _constructionPercentage = luaL_checkinteger(L, 2); console.warn('UnitSetConstructionProgress was called but is not implemented :('); return 0; } /** * native UnitSetUpgradeProgress takes unit whichUnit, integer upgradePercentage returns nothing */ function UnitSetUpgradeProgress(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _upgradePercentage = luaL_checkinteger(L, 2); console.warn('UnitSetUpgradeProgress was called but is not implemented :('); return 0; } /** * native UnitPauseTimedLife takes unit whichUnit, boolean flag returns nothing */ function UnitPauseTimedLife(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('UnitPauseTimedLife was called but is not implemented :('); return 0; } /** * native UnitSetUsesAltIcon takes unit whichUnit, boolean flag returns nothing */ function UnitSetUsesAltIcon(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('UnitSetUsesAltIcon was called but is not implemented :('); return 0; } /** * native UnitDamagePoint takes unit whichUnit, real delay, real radius, real x, real y, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean */ function UnitDamagePoint(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _delay = luaL_checknumber(L, 2); const _radius = luaL_checknumber(L, 3); const _x = luaL_checknumber(L, 4); const _y = luaL_checknumber(L, 5); const _amount = luaL_checknumber(L, 6); const _attack = lua_toboolean(L, 7); const _ranged = lua_toboolean(L, 8); const _attackType = lua_touserdata(L, 9); const _damageType = lua_touserdata(L, 10); const _weaponType = lua_touserdata(L, 11); console.warn('UnitDamagePoint was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native UnitDamageTarget takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean */ function UnitDamageTarget(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _target = lua_touserdata(L, 2); const _amount = luaL_checknumber(L, 3); const _attack = lua_toboolean(L, 4); const _ranged = lua_toboolean(L, 5); const _attackType = lua_touserdata(L, 6); const _damageType = lua_touserdata(L, 7); const _weaponType = lua_touserdata(L, 8); console.warn('UnitDamageTarget was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueImmediateOrder takes unit whichUnit, string order returns boolean */ function IssueImmediateOrder(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); console.warn('IssueImmediateOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueImmediateOrderById takes unit whichUnit, integer order returns boolean */ function IssueImmediateOrderById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); console.warn('IssueImmediateOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssuePointOrder takes unit whichUnit, string order, real x, real y returns boolean */ function IssuePointOrder(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('IssuePointOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssuePointOrderLoc takes unit whichUnit, string order, location whichLocation returns boolean */ function IssuePointOrderLoc(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _whichLocation = lua_touserdata(L, 3); console.warn('IssuePointOrderLoc was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssuePointOrderById takes unit whichUnit, integer order, real x, real y returns boolean */ function IssuePointOrderById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('IssuePointOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssuePointOrderByIdLoc takes unit whichUnit, integer order, location whichLocation returns boolean */ function IssuePointOrderByIdLoc(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _whichLocation = lua_touserdata(L, 3); console.warn('IssuePointOrderByIdLoc was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueTargetOrder takes unit whichUnit, string order, widget targetWidget returns boolean */ function IssueTargetOrder(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _targetWidget = lua_touserdata(L, 3); console.warn('IssueTargetOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueTargetOrderById takes unit whichUnit, integer order, widget targetWidget returns boolean */ function IssueTargetOrderById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _targetWidget = lua_touserdata(L, 3); console.warn('IssueTargetOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueInstantPointOrder takes unit whichUnit, string order, real x, real y, widget instantTargetWidget returns boolean */ function IssueInstantPointOrder(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); const _instantTargetWidget = lua_touserdata(L, 5); console.warn('IssueInstantPointOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueInstantPointOrderById takes unit whichUnit, integer order, real x, real y, widget instantTargetWidget returns boolean */ function IssueInstantPointOrderById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); const _instantTargetWidget = lua_touserdata(L, 5); console.warn('IssueInstantPointOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueInstantTargetOrder takes unit whichUnit, string order, widget targetWidget, widget instantTargetWidget returns boolean */ function IssueInstantTargetOrder(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkstring(L, 2); const _targetWidget = lua_touserdata(L, 3); const _instantTargetWidget = lua_touserdata(L, 4); console.warn('IssueInstantTargetOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueInstantTargetOrderById takes unit whichUnit, integer order, widget targetWidget, widget instantTargetWidget returns boolean */ function IssueInstantTargetOrderById(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _order = luaL_checkinteger(L, 2); const _targetWidget = lua_touserdata(L, 3); const _instantTargetWidget = lua_touserdata(L, 4); console.warn('IssueInstantTargetOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueBuildOrder takes unit whichPeon, string unitToBuild, real x, real y returns boolean */ function IssueBuildOrder(C: Context, L: lua_State): number { const _whichPeon = lua_touserdata(L, 1); const _unitToBuild = luaL_checkstring(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('IssueBuildOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueBuildOrderById takes unit whichPeon, integer unitId, real x, real y returns boolean */ function IssueBuildOrderById(C: Context, L: lua_State): number { const _whichPeon = lua_touserdata(L, 1); const _unitId = luaL_checkinteger(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('IssueBuildOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueNeutralImmediateOrder takes player forWhichPlayer, unit neutralStructure, string unitToBuild returns boolean */ function IssueNeutralImmediateOrder(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _neutralStructure = lua_touserdata(L, 2); const _unitToBuild = luaL_checkstring(L, 3); console.warn('IssueNeutralImmediateOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueNeutralImmediateOrderById takes player forWhichPlayer, unit neutralStructure, integer unitId returns boolean */ function IssueNeutralImmediateOrderById(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _neutralStructure = lua_touserdata(L, 2); const _unitId = luaL_checkinteger(L, 3); console.warn('IssueNeutralImmediateOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueNeutralPointOrder takes player forWhichPlayer, unit neutralStructure, string unitToBuild, real x, real y returns boolean */ function IssueNeutralPointOrder(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _neutralStructure = lua_touserdata(L, 2); const _unitToBuild = luaL_checkstring(L, 3); const _x = luaL_checknumber(L, 4); const _y = luaL_checknumber(L, 5); console.warn('IssueNeutralPointOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueNeutralPointOrderById takes player forWhichPlayer, unit neutralStructure, integer unitId, real x, real y returns boolean */ function IssueNeutralPointOrderById(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _neutralStructure = lua_touserdata(L, 2); const _unitId = luaL_checkinteger(L, 3); const _x = luaL_checknumber(L, 4); const _y = luaL_checknumber(L, 5); console.warn('IssueNeutralPointOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueNeutralTargetOrder takes player forWhichPlayer, unit neutralStructure, string unitToBuild, widget target returns boolean */ function IssueNeutralTargetOrder(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _neutralStructure = lua_touserdata(L, 2); const _unitToBuild = luaL_checkstring(L, 3); const _target = lua_touserdata(L, 4); console.warn('IssueNeutralTargetOrder was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IssueNeutralTargetOrderById takes player forWhichPlayer, unit neutralStructure, integer unitId, widget target returns boolean */ function IssueNeutralTargetOrderById(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _neutralStructure = lua_touserdata(L, 2); const _unitId = luaL_checkinteger(L, 3); const _target = lua_touserdata(L, 4); console.warn('IssueNeutralTargetOrderById was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetUnitCurrentOrder takes unit whichUnit returns integer */ function GetUnitCurrentOrder(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitCurrentOrder was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetResourceAmount takes unit whichUnit, integer amount returns nothing */ function SetResourceAmount(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _amount = luaL_checkinteger(L, 2); console.warn('SetResourceAmount was called but is not implemented :('); return 0; } /** * native AddResourceAmount takes unit whichUnit, integer amount returns nothing */ function AddResourceAmount(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _amount = luaL_checkinteger(L, 2); console.warn('AddResourceAmount was called but is not implemented :('); return 0; } /** * native GetResourceAmount takes unit whichUnit returns integer */ function GetResourceAmount(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetResourceAmount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native WaygateGetDestinationX takes unit waygate returns real */ function WaygateGetDestinationX(C: Context, L: lua_State): number { const _waygate = lua_touserdata(L, 1); console.warn('WaygateGetDestinationX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native WaygateGetDestinationY takes unit waygate returns real */ function WaygateGetDestinationY(C: Context, L: lua_State): number { const _waygate = lua_touserdata(L, 1); console.warn('WaygateGetDestinationY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native WaygateSetDestination takes unit waygate, real x, real y returns nothing */ function WaygateSetDestination(C: Context, L: lua_State): number { const _waygate = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('WaygateSetDestination was called but is not implemented :('); return 0; } /** * native WaygateActivate takes unit waygate, boolean activate returns nothing */ function WaygateActivate(C: Context, L: lua_State): number { const _waygate = lua_touserdata(L, 1); const _activate = lua_toboolean(L, 2); console.warn('WaygateActivate was called but is not implemented :('); return 0; } /** * native WaygateIsActive takes unit waygate returns boolean */ function WaygateIsActive(C: Context, L: lua_State): number { const _waygate = lua_touserdata(L, 1); console.warn('WaygateIsActive was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native AddItemToAllStock takes integer itemId, integer currentStock, integer stockMax returns nothing */ function AddItemToAllStock(C: Context, L: lua_State): number { const _itemId = luaL_checkinteger(L, 1); const _currentStock = luaL_checkinteger(L, 2); const _stockMax = luaL_checkinteger(L, 3); console.warn('AddItemToAllStock was called but is not implemented :('); return 0; } /** * native AddItemToStock takes unit whichUnit, integer itemId, integer currentStock, integer stockMax returns nothing */ function AddItemToStock(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _itemId = luaL_checkinteger(L, 2); const _currentStock = luaL_checkinteger(L, 3); const _stockMax = luaL_checkinteger(L, 4); console.warn('AddItemToStock was called but is not implemented :('); return 0; } /** * native AddUnitToAllStock takes integer unitId, integer currentStock, integer stockMax returns nothing */ function AddUnitToAllStock(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); const _currentStock = luaL_checkinteger(L, 2); const _stockMax = luaL_checkinteger(L, 3); console.warn('AddUnitToAllStock was called but is not implemented :('); return 0; } /** * native AddUnitToStock takes unit whichUnit, integer unitId, integer currentStock, integer stockMax returns nothing */ function AddUnitToStock(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _unitId = luaL_checkinteger(L, 2); const _currentStock = luaL_checkinteger(L, 3); const _stockMax = luaL_checkinteger(L, 4); console.warn('AddUnitToStock was called but is not implemented :('); return 0; } /** * native RemoveItemFromAllStock takes integer itemId returns nothing */ function RemoveItemFromAllStock(C: Context, L: lua_State): number { const _itemId = luaL_checkinteger(L, 1); console.warn('RemoveItemFromAllStock was called but is not implemented :('); return 0; } /** * native RemoveItemFromStock takes unit whichUnit, integer itemId returns nothing */ function RemoveItemFromStock(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _itemId = luaL_checkinteger(L, 2); console.warn('RemoveItemFromStock was called but is not implemented :('); return 0; } /** * native RemoveUnitFromAllStock takes integer unitId returns nothing */ function RemoveUnitFromAllStock(C: Context, L: lua_State): number { const _unitId = luaL_checkinteger(L, 1); console.warn('RemoveUnitFromAllStock was called but is not implemented :('); return 0; } /** * native RemoveUnitFromStock takes unit whichUnit, integer unitId returns nothing */ function RemoveUnitFromStock(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _unitId = luaL_checkinteger(L, 2); console.warn('RemoveUnitFromStock was called but is not implemented :('); return 0; } /** * native SetAllItemTypeSlots takes integer slots returns nothing */ function SetAllItemTypeSlots(C: Context, L: lua_State): number { const _slots = luaL_checkinteger(L, 1); console.warn('SetAllItemTypeSlots was called but is not implemented :('); return 0; } /** * native SetAllUnitTypeSlots takes integer slots returns nothing */ function SetAllUnitTypeSlots(C: Context, L: lua_State): number { const _slots = luaL_checkinteger(L, 1); console.warn('SetAllUnitTypeSlots was called but is not implemented :('); return 0; } /** * native SetItemTypeSlots takes unit whichUnit, integer slots returns nothing */ function SetItemTypeSlots(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _slots = luaL_checkinteger(L, 2); console.warn('SetItemTypeSlots was called but is not implemented :('); return 0; } /** * native SetUnitTypeSlots takes unit whichUnit, integer slots returns nothing */ function SetUnitTypeSlots(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _slots = luaL_checkinteger(L, 2); console.warn('SetUnitTypeSlots was called but is not implemented :('); return 0; } /** * native GetUnitUserData takes unit whichUnit returns integer */ function GetUnitUserData(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('GetUnitUserData was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetUnitUserData takes unit whichUnit, integer data returns nothing */ function SetUnitUserData(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _data = luaL_checkinteger(L, 2); console.warn('SetUnitUserData was called but is not implemented :('); return 0; } /** * constant native Player takes integer number returns player */ function Player(C: Context, L: lua_State): number { const number = luaL_checkinteger(L, 1); lua_pushlightuserdata(L, C.players[number]); return 1; } /** * constant native GetLocalPlayer takes nothing returns player */ function GetLocalPlayer(C: Context, L: lua_State): number { console.warn('GetLocalPlayer was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native IsPlayerAlly takes player whichPlayer, player otherPlayer returns boolean */ function IsPlayerAlly(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _otherPlayer = lua_touserdata(L, 2); console.warn('IsPlayerAlly was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsPlayerEnemy takes player whichPlayer, player otherPlayer returns boolean */ function IsPlayerEnemy(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _otherPlayer = lua_touserdata(L, 2); console.warn('IsPlayerEnemy was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsPlayerInForce takes player whichPlayer, force whichForce returns boolean */ function IsPlayerInForce(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichForce = lua_touserdata(L, 2); console.warn('IsPlayerInForce was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsPlayerObserver takes player whichPlayer returns boolean */ function IsPlayerObserver(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('IsPlayerObserver was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsVisibleToPlayer takes real x, real y, player whichPlayer returns boolean */ function IsVisibleToPlayer(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _whichPlayer = lua_touserdata(L, 3); console.warn('IsVisibleToPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsLocationVisibleToPlayer takes location whichLocation, player whichPlayer returns boolean */ function IsLocationVisibleToPlayer(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsLocationVisibleToPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsFoggedToPlayer takes real x, real y, player whichPlayer returns boolean */ function IsFoggedToPlayer(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _whichPlayer = lua_touserdata(L, 3); console.warn('IsFoggedToPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsLocationFoggedToPlayer takes location whichLocation, player whichPlayer returns boolean */ function IsLocationFoggedToPlayer(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsLocationFoggedToPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsMaskedToPlayer takes real x, real y, player whichPlayer returns boolean */ function IsMaskedToPlayer(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _whichPlayer = lua_touserdata(L, 3); console.warn('IsMaskedToPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native IsLocationMaskedToPlayer takes location whichLocation, player whichPlayer returns boolean */ function IsLocationMaskedToPlayer(C: Context, L: lua_State): number { const _whichLocation = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('IsLocationMaskedToPlayer was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native GetPlayerRace takes player whichPlayer returns race */ function GetPlayerRace(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); lua_pushlightuserdata(L, C.constantHandles.races[whichPlayer.racePreference]); return 1; } /** * constant native GetPlayerId takes player whichPlayer returns integer */ function GetPlayerId(C: Context, L: lua_State): number { const whichPlayer = lua_touserdata(L, 1); lua_pushinteger(L, whichPlayer.index); return 1; } /** * constant native GetPlayerUnitCount takes player whichPlayer, boolean includeIncomplete returns integer */ function GetPlayerUnitCount(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _includeIncomplete = lua_toboolean(L, 2); console.warn('GetPlayerUnitCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetPlayerTypedUnitCount takes player whichPlayer, string unitName, boolean includeIncomplete, boolean includeUpgrades returns integer */ function GetPlayerTypedUnitCount(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _unitName = luaL_checkstring(L, 2); const _includeIncomplete = lua_toboolean(L, 3); const _includeUpgrades = lua_toboolean(L, 4); console.warn('GetPlayerTypedUnitCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetPlayerStructureCount takes player whichPlayer, boolean includeIncomplete returns integer */ function GetPlayerStructureCount(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _includeIncomplete = lua_toboolean(L, 2); console.warn('GetPlayerStructureCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetPlayerState takes player whichPlayer, playerstate whichPlayerState returns integer */ function GetPlayerState(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichPlayerState = lua_touserdata(L, 2); console.warn('GetPlayerState was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetPlayerScore takes player whichPlayer, playerscore whichPlayerScore returns integer */ function GetPlayerScore(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichPlayerScore = lua_touserdata(L, 2); console.warn('GetPlayerScore was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native GetPlayerAlliance takes player sourcePlayer, player otherPlayer, alliancetype whichAllianceSetting returns boolean */ function GetPlayerAlliance(C: Context, L: lua_State): number { const _sourcePlayer = lua_touserdata(L, 1); const _otherPlayer = lua_touserdata(L, 2); const _whichAllianceSetting = lua_touserdata(L, 3); console.warn('GetPlayerAlliance was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native GetPlayerHandicap takes player whichPlayer returns real */ function GetPlayerHandicap(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('GetPlayerHandicap was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetPlayerHandicapXP takes player whichPlayer returns real */ function GetPlayerHandicapXP(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('GetPlayerHandicapXP was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native SetPlayerHandicap takes player whichPlayer, real handicap returns nothing */ function SetPlayerHandicap(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _handicap = luaL_checknumber(L, 2); console.warn('SetPlayerHandicap was called but is not implemented :('); return 0; } /** * constant native SetPlayerHandicapXP takes player whichPlayer, real handicap returns nothing */ function SetPlayerHandicapXP(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _handicap = luaL_checknumber(L, 2); console.warn('SetPlayerHandicapXP was called but is not implemented :('); return 0; } /** * constant native SetPlayerTechMaxAllowed takes player whichPlayer, integer techid, integer maximum returns nothing */ function SetPlayerTechMaxAllowed(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); const _maximum = luaL_checkinteger(L, 3); console.warn('SetPlayerTechMaxAllowed was called but is not implemented :('); return 0; } /** * constant native GetPlayerTechMaxAllowed takes player whichPlayer, integer techid returns integer */ function GetPlayerTechMaxAllowed(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); console.warn('GetPlayerTechMaxAllowed was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * constant native AddPlayerTechResearched takes player whichPlayer, integer techid, integer levels returns nothing */ function AddPlayerTechResearched(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); const _levels = luaL_checkinteger(L, 3); console.warn('AddPlayerTechResearched was called but is not implemented :('); return 0; } /** * constant native SetPlayerTechResearched takes player whichPlayer, integer techid, integer setToLevel returns nothing */ function SetPlayerTechResearched(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); const _setToLevel = luaL_checkinteger(L, 3); console.warn('SetPlayerTechResearched was called but is not implemented :('); return 0; } /** * constant native GetPlayerTechResearched takes player whichPlayer, integer techid, boolean specificonly returns boolean */ function GetPlayerTechResearched(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); const _specificonly = lua_toboolean(L, 3); console.warn('GetPlayerTechResearched was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * constant native GetPlayerTechCount takes player whichPlayer, integer techid, boolean specificonly returns integer */ function GetPlayerTechCount(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); const _specificonly = lua_toboolean(L, 3); console.warn('GetPlayerTechCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetPlayerUnitsOwner takes player whichPlayer, integer newOwner returns nothing */ function SetPlayerUnitsOwner(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _newOwner = luaL_checkinteger(L, 2); console.warn('SetPlayerUnitsOwner was called but is not implemented :('); return 0; } /** * native CripplePlayer takes player whichPlayer, force toWhichPlayers, boolean flag returns nothing */ function CripplePlayer(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _toWhichPlayers = lua_touserdata(L, 2); const _flag = lua_toboolean(L, 3); console.warn('CripplePlayer was called but is not implemented :('); return 0; } /** * native SetPlayerAbilityAvailable takes player whichPlayer, integer abilid, boolean avail returns nothing */ function SetPlayerAbilityAvailable(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _abilid = luaL_checkinteger(L, 2); const _avail = lua_toboolean(L, 3); console.warn('SetPlayerAbilityAvailable was called but is not implemented :('); return 0; } /** * native SetPlayerState takes player whichPlayer, playerstate whichPlayerState, integer value returns nothing */ function SetPlayerState(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichPlayerState = lua_touserdata(L, 2); const _value = luaL_checkinteger(L, 3); console.warn('SetPlayerState was called but is not implemented :('); return 0; } /** * native RemovePlayer takes player whichPlayer, playergameresult gameResult returns nothing */ function RemovePlayer(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _gameResult = lua_touserdata(L, 2); console.warn('RemovePlayer was called but is not implemented :('); return 0; } /** * native CachePlayerHeroData takes player whichPlayer returns nothing */ function CachePlayerHeroData(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); console.warn('CachePlayerHeroData was called but is not implemented :('); return 0; } /** * native SetFogStateRect takes player forWhichPlayer, fogstate whichState, rect where, boolean useSharedVision returns nothing */ function SetFogStateRect(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _where = lua_touserdata(L, 3); const _useSharedVision = lua_toboolean(L, 4); console.warn('SetFogStateRect was called but is not implemented :('); return 0; } /** * native SetFogStateRadius takes player forWhichPlayer, fogstate whichState, real centerx, real centerY, real radius, boolean useSharedVision returns nothing */ function SetFogStateRadius(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _centerx = luaL_checknumber(L, 3); const _centerY = luaL_checknumber(L, 4); const _radius = luaL_checknumber(L, 5); const _useSharedVision = lua_toboolean(L, 6); console.warn('SetFogStateRadius was called but is not implemented :('); return 0; } /** * native SetFogStateRadiusLoc takes player forWhichPlayer, fogstate whichState, location center, real radius, boolean useSharedVision returns nothing */ function SetFogStateRadiusLoc(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _center = lua_touserdata(L, 3); const _radius = luaL_checknumber(L, 4); const _useSharedVision = lua_toboolean(L, 5); console.warn('SetFogStateRadiusLoc was called but is not implemented :('); return 0; } /** * native FogMaskEnable takes boolean enable returns nothing */ function FogMaskEnable(C: Context, L: lua_State): number { const _enable = lua_toboolean(L, 1); console.warn('FogMaskEnable was called but is not implemented :('); return 0; } /** * native IsFogMaskEnabled takes nothing returns boolean */ function IsFogMaskEnabled(C: Context, L: lua_State): number { console.warn('IsFogMaskEnabled was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native FogEnable takes boolean enable returns nothing */ function FogEnable(C: Context, L: lua_State): number { const _enable = lua_toboolean(L, 1); console.warn('FogEnable was called but is not implemented :('); return 0; } /** * native IsFogEnabled takes nothing returns boolean */ function IsFogEnabled(C: Context, L: lua_State): number { console.warn('IsFogEnabled was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native CreateFogModifierRect takes player forWhichPlayer, fogstate whichState, rect where, boolean useSharedVision, boolean afterUnits returns fogmodifier */ function CreateFogModifierRect(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _where = lua_touserdata(L, 3); const _useSharedVision = lua_toboolean(L, 4); const _afterUnits = lua_toboolean(L, 5); console.warn('CreateFogModifierRect was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateFogModifierRadius takes player forWhichPlayer, fogstate whichState, real centerx, real centerY, real radius, boolean useSharedVision, boolean afterUnits returns fogmodifier */ function CreateFogModifierRadius(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _centerx = luaL_checknumber(L, 3); const _centerY = luaL_checknumber(L, 4); const _radius = luaL_checknumber(L, 5); const _useSharedVision = lua_toboolean(L, 6); const _afterUnits = lua_toboolean(L, 7); console.warn('CreateFogModifierRadius was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateFogModifierRadiusLoc takes player forWhichPlayer, fogstate whichState, location center, real radius, boolean useSharedVision, boolean afterUnits returns fogmodifier */ function CreateFogModifierRadiusLoc(C: Context, L: lua_State): number { const _forWhichPlayer = lua_touserdata(L, 1); const _whichState = lua_touserdata(L, 2); const _center = lua_touserdata(L, 3); const _radius = luaL_checknumber(L, 4); const _useSharedVision = lua_toboolean(L, 5); const _afterUnits = lua_toboolean(L, 6); console.warn('CreateFogModifierRadiusLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyFogModifier takes fogmodifier whichFogModifier returns nothing */ function DestroyFogModifier(C: Context, L: lua_State): number { const _whichFogModifier = lua_touserdata(L, 1); console.warn('DestroyFogModifier was called but is not implemented :('); return 0; } /** * native FogModifierStart takes fogmodifier whichFogModifier returns nothing */ function FogModifierStart(C: Context, L: lua_State): number { const _whichFogModifier = lua_touserdata(L, 1); console.warn('FogModifierStart was called but is not implemented :('); return 0; } /** * native FogModifierStop takes fogmodifier whichFogModifier returns nothing */ function FogModifierStop(C: Context, L: lua_State): number { const _whichFogModifier = lua_touserdata(L, 1); console.warn('FogModifierStop was called but is not implemented :('); return 0; } /** * native VersionGet takes nothing returns version */ function VersionGet(C: Context, L: lua_State): number { console.warn('VersionGet was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native VersionCompatible takes version whichVersion returns boolean */ function VersionCompatible(C: Context, L: lua_State): number { const _whichVersion = lua_touserdata(L, 1); console.warn('VersionCompatible was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native VersionSupported takes version whichVersion returns boolean */ function VersionSupported(C: Context, L: lua_State): number { const _whichVersion = lua_touserdata(L, 1); console.warn('VersionSupported was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native EndGame takes boolean doScoreScreen returns nothing */ function EndGame(C: Context, L: lua_State): number { const _doScoreScreen = lua_toboolean(L, 1); console.warn('EndGame was called but is not implemented :('); return 0; } /** * native ChangeLevel takes string newLevel, boolean doScoreScreen returns nothing */ function ChangeLevel(C: Context, L: lua_State): number { const _newLevel = luaL_checkstring(L, 1); const _doScoreScreen = lua_toboolean(L, 2); console.warn('ChangeLevel was called but is not implemented :('); return 0; } /** * native RestartGame takes boolean doScoreScreen returns nothing */ function RestartGame(C: Context, L: lua_State): number { const _doScoreScreen = lua_toboolean(L, 1); console.warn('RestartGame was called but is not implemented :('); return 0; } /** * native ReloadGame takes nothing returns nothing */ function ReloadGame(_C: Context, _L: lua_State): number { console.warn('ReloadGame was called but is not implemented :('); return 0; } /** * native SetCampaignMenuRace takes race r returns nothing */ function SetCampaignMenuRace(C: Context, L: lua_State): number { const _r = lua_touserdata(L, 1); console.warn('SetCampaignMenuRace was called but is not implemented :('); return 0; } /** * native SetCampaignMenuRaceEx takes integer campaignIndex returns nothing */ function SetCampaignMenuRaceEx(C: Context, L: lua_State): number { const _campaignIndex = luaL_checkinteger(L, 1); console.warn('SetCampaignMenuRaceEx was called but is not implemented :('); return 0; } /** * native ForceCampaignSelectScreen takes nothing returns nothing */ function ForceCampaignSelectScreen(_C: Context, _L: lua_State): number { console.warn('ForceCampaignSelectScreen was called but is not implemented :('); return 0; } /** * native LoadGame takes string saveFileName, boolean doScoreScreen returns nothing */ function LoadGame(C: Context, L: lua_State): number { const _saveFileName = luaL_checkstring(L, 1); const _doScoreScreen = lua_toboolean(L, 2); console.warn('LoadGame was called but is not implemented :('); return 0; } /** * native SaveGame takes string saveFileName returns nothing */ function SaveGame(C: Context, L: lua_State): number { const _saveFileName = luaL_checkstring(L, 1); console.warn('SaveGame was called but is not implemented :('); return 0; } /** * native RenameSaveDirectory takes string sourceDirName, string destDirName returns boolean */ function RenameSaveDirectory(C: Context, L: lua_State): number { const _sourceDirName = luaL_checkstring(L, 1); const _destDirName = luaL_checkstring(L, 2); console.warn('RenameSaveDirectory was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native RemoveSaveDirectory takes string sourceDirName returns boolean */ function RemoveSaveDirectory(C: Context, L: lua_State): number { const _sourceDirName = luaL_checkstring(L, 1); console.warn('RemoveSaveDirectory was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native CopySaveGame takes string sourceSaveName, string destSaveName returns boolean */ function CopySaveGame(C: Context, L: lua_State): number { const _sourceSaveName = luaL_checkstring(L, 1); const _destSaveName = luaL_checkstring(L, 2); console.warn('CopySaveGame was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveGameExists takes string saveName returns boolean */ function SaveGameExists(C: Context, L: lua_State): number { const _saveName = luaL_checkstring(L, 1); console.warn('SaveGameExists was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SyncSelections takes nothing returns nothing */ function SyncSelections(_C: Context, _L: lua_State): number { console.warn('SyncSelections was called but is not implemented :('); return 0; } /** * native SetFloatGameState takes fgamestate whichFloatGameState, real value returns nothing */ function SetFloatGameState(C: Context, L: lua_State): number { const _whichFloatGameState = lua_touserdata(L, 1); const _value = luaL_checknumber(L, 2); console.warn('SetFloatGameState was called but is not implemented :('); return 0; } /** * constant native GetFloatGameState takes fgamestate whichFloatGameState returns real */ function GetFloatGameState(C: Context, L: lua_State): number { const _whichFloatGameState = lua_touserdata(L, 1); console.warn('GetFloatGameState was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetIntegerGameState takes igamestate whichIntegerGameState, integer value returns nothing */ function SetIntegerGameState(C: Context, L: lua_State): number { const _whichIntegerGameState = lua_touserdata(L, 1); const _value = luaL_checkinteger(L, 2); console.warn('SetIntegerGameState was called but is not implemented :('); return 0; } /** * constant native GetIntegerGameState takes igamestate whichIntegerGameState returns integer */ function GetIntegerGameState(C: Context, L: lua_State): number { const _whichIntegerGameState = lua_touserdata(L, 1); console.warn('GetIntegerGameState was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetTutorialCleared takes boolean cleared returns nothing */ function SetTutorialCleared(C: Context, L: lua_State): number { const _cleared = lua_toboolean(L, 1); console.warn('SetTutorialCleared was called but is not implemented :('); return 0; } /** * native SetMissionAvailable takes integer campaignNumber, integer missionNumber, boolean available returns nothing */ function SetMissionAvailable(C: Context, L: lua_State): number { const _campaignNumber = luaL_checkinteger(L, 1); const _missionNumber = luaL_checkinteger(L, 2); const _available = lua_toboolean(L, 3); console.warn('SetMissionAvailable was called but is not implemented :('); return 0; } /** * native SetCampaignAvailable takes integer campaignNumber, boolean available returns nothing */ function SetCampaignAvailable(C: Context, L: lua_State): number { const _campaignNumber = luaL_checkinteger(L, 1); const _available = lua_toboolean(L, 2); console.warn('SetCampaignAvailable was called but is not implemented :('); return 0; } /** * native SetOpCinematicAvailable takes integer campaignNumber, boolean available returns nothing */ function SetOpCinematicAvailable(C: Context, L: lua_State): number { const _campaignNumber = luaL_checkinteger(L, 1); const _available = lua_toboolean(L, 2); console.warn('SetOpCinematicAvailable was called but is not implemented :('); return 0; } /** * native SetEdCinematicAvailable takes integer campaignNumber, boolean available returns nothing */ function SetEdCinematicAvailable(C: Context, L: lua_State): number { const _campaignNumber = luaL_checkinteger(L, 1); const _available = lua_toboolean(L, 2); console.warn('SetEdCinematicAvailable was called but is not implemented :('); return 0; } /** * native GetDefaultDifficulty takes nothing returns gamedifficulty */ function GetDefaultDifficulty(C: Context, L: lua_State): number { console.warn('GetDefaultDifficulty was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SetDefaultDifficulty takes gamedifficulty g returns nothing */ function SetDefaultDifficulty(C: Context, L: lua_State): number { const _g = lua_touserdata(L, 1); console.warn('SetDefaultDifficulty was called but is not implemented :('); return 0; } /** * native SetCustomCampaignButtonVisible takes integer whichButton, boolean visible returns nothing */ function SetCustomCampaignButtonVisible(C: Context, L: lua_State): number { const _whichButton = luaL_checkinteger(L, 1); const _visible = lua_toboolean(L, 2); console.warn('SetCustomCampaignButtonVisible was called but is not implemented :('); return 0; } /** * native GetCustomCampaignButtonVisible takes integer whichButton returns boolean */ function GetCustomCampaignButtonVisible(C: Context, L: lua_State): number { const _whichButton = luaL_checkinteger(L, 1); console.warn('GetCustomCampaignButtonVisible was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native DoNotSaveReplay takes nothing returns nothing */ function DoNotSaveReplay(_C: Context, _L: lua_State): number { console.warn('DoNotSaveReplay was called but is not implemented :('); return 0; } /** * native DialogCreate takes nothing returns dialog */ function DialogCreate(C: Context, L: lua_State): number { console.warn('DialogCreate was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DialogDestroy takes dialog whichDialog returns nothing */ function DialogDestroy(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); console.warn('DialogDestroy was called but is not implemented :('); return 0; } /** * native DialogClear takes dialog whichDialog returns nothing */ function DialogClear(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); console.warn('DialogClear was called but is not implemented :('); return 0; } /** * native DialogSetMessage takes dialog whichDialog, string messageText returns nothing */ function DialogSetMessage(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _messageText = luaL_checkstring(L, 2); console.warn('DialogSetMessage was called but is not implemented :('); return 0; } /** * native DialogAddButton takes dialog whichDialog, string buttonText, integer hotkey returns button */ function DialogAddButton(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _buttonText = luaL_checkstring(L, 2); const _hotkey = luaL_checkinteger(L, 3); console.warn('DialogAddButton was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DialogAddQuitButton takes dialog whichDialog, boolean doScoreScreen, string buttonText, integer hotkey returns button */ function DialogAddQuitButton(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _doScoreScreen = lua_toboolean(L, 2); const _buttonText = luaL_checkstring(L, 3); const _hotkey = luaL_checkinteger(L, 4); console.warn('DialogAddQuitButton was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DialogDisplay takes player whichPlayer, dialog whichDialog, boolean flag returns nothing */ function DialogDisplay(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichDialog = lua_touserdata(L, 2); const _flag = lua_toboolean(L, 3); console.warn('DialogDisplay was called but is not implemented :('); return 0; } /** * native ReloadGameCachesFromDisk takes nothing returns boolean */ function ReloadGameCachesFromDisk(C: Context, L: lua_State): number { console.warn('ReloadGameCachesFromDisk was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native InitGameCache takes string campaignFile returns gamecache */ function InitGameCache(C: Context, L: lua_State): number { const _campaignFile = luaL_checkstring(L, 1); console.warn('InitGameCache was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SaveGameCache takes gamecache whichCache returns boolean */ function SaveGameCache(C: Context, L: lua_State): number { const _whichCache = lua_touserdata(L, 1); console.warn('SaveGameCache was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native StoreInteger takes gamecache cache, string missionKey, string key, integer value returns nothing */ function StoreInteger(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); const _value = luaL_checkinteger(L, 4); console.warn('StoreInteger was called but is not implemented :('); return 0; } /** * native StoreReal takes gamecache cache, string missionKey, string key, real value returns nothing */ function StoreReal(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); const _value = luaL_checknumber(L, 4); console.warn('StoreReal was called but is not implemented :('); return 0; } /** * native StoreBoolean takes gamecache cache, string missionKey, string key, boolean value returns nothing */ function StoreBoolean(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); const _value = lua_toboolean(L, 4); console.warn('StoreBoolean was called but is not implemented :('); return 0; } /** * native StoreUnit takes gamecache cache, string missionKey, string key, unit whichUnit returns boolean */ function StoreUnit(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); const _whichUnit = lua_touserdata(L, 4); console.warn('StoreUnit was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native StoreString takes gamecache cache, string missionKey, string key, string value returns boolean */ function StoreString(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); const _value = luaL_checkstring(L, 4); console.warn('StoreString was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SyncStoredInteger takes gamecache cache, string missionKey, string key returns nothing */ function SyncStoredInteger(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('SyncStoredInteger was called but is not implemented :('); return 0; } /** * native SyncStoredReal takes gamecache cache, string missionKey, string key returns nothing */ function SyncStoredReal(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('SyncStoredReal was called but is not implemented :('); return 0; } /** * native SyncStoredBoolean takes gamecache cache, string missionKey, string key returns nothing */ function SyncStoredBoolean(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('SyncStoredBoolean was called but is not implemented :('); return 0; } /** * native SyncStoredUnit takes gamecache cache, string missionKey, string key returns nothing */ function SyncStoredUnit(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('SyncStoredUnit was called but is not implemented :('); return 0; } /** * native SyncStoredString takes gamecache cache, string missionKey, string key returns nothing */ function SyncStoredString(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('SyncStoredString was called but is not implemented :('); return 0; } /** * native HaveStoredInteger takes gamecache cache, string missionKey, string key returns boolean */ function HaveStoredInteger(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('HaveStoredInteger was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveStoredReal takes gamecache cache, string missionKey, string key returns boolean */ function HaveStoredReal(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('HaveStoredReal was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveStoredBoolean takes gamecache cache, string missionKey, string key returns boolean */ function HaveStoredBoolean(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('HaveStoredBoolean was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveStoredUnit takes gamecache cache, string missionKey, string key returns boolean */ function HaveStoredUnit(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('HaveStoredUnit was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveStoredString takes gamecache cache, string missionKey, string key returns boolean */ function HaveStoredString(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('HaveStoredString was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native FlushGameCache takes gamecache cache returns nothing */ function FlushGameCache(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); console.warn('FlushGameCache was called but is not implemented :('); return 0; } /** * native FlushStoredMission takes gamecache cache, string missionKey returns nothing */ function FlushStoredMission(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); console.warn('FlushStoredMission was called but is not implemented :('); return 0; } /** * native FlushStoredInteger takes gamecache cache, string missionKey, string key returns nothing */ function FlushStoredInteger(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('FlushStoredInteger was called but is not implemented :('); return 0; } /** * native FlushStoredReal takes gamecache cache, string missionKey, string key returns nothing */ function FlushStoredReal(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('FlushStoredReal was called but is not implemented :('); return 0; } /** * native FlushStoredBoolean takes gamecache cache, string missionKey, string key returns nothing */ function FlushStoredBoolean(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('FlushStoredBoolean was called but is not implemented :('); return 0; } /** * native FlushStoredUnit takes gamecache cache, string missionKey, string key returns nothing */ function FlushStoredUnit(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('FlushStoredUnit was called but is not implemented :('); return 0; } /** * native FlushStoredString takes gamecache cache, string missionKey, string key returns nothing */ function FlushStoredString(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('FlushStoredString was called but is not implemented :('); return 0; } /** * native GetStoredInteger takes gamecache cache, string missionKey, string key returns integer */ function GetStoredInteger(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('GetStoredInteger was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetStoredReal takes gamecache cache, string missionKey, string key returns real */ function GetStoredReal(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('GetStoredReal was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetStoredBoolean takes gamecache cache, string missionKey, string key returns boolean */ function GetStoredBoolean(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('GetStoredBoolean was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetStoredString takes gamecache cache, string missionKey, string key returns string */ function GetStoredString(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); console.warn('GetStoredString was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native RestoreUnit takes gamecache cache, string missionKey, string key, player forWhichPlayer, real x, real y, real facing returns unit */ function RestoreUnit(C: Context, L: lua_State): number { const _cache = lua_touserdata(L, 1); const _missionKey = luaL_checkstring(L, 2); const _key = luaL_checkstring(L, 3); const _forWhichPlayer = lua_touserdata(L, 4); const _x = luaL_checknumber(L, 5); const _y = luaL_checknumber(L, 6); const _facing = luaL_checknumber(L, 7); console.warn('RestoreUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native InitHashtable takes nothing returns hashtable */ function InitHashtable(C: Context, L: lua_State): number { console.warn('InitHashtable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SaveInteger takes hashtable table, integer parentKey, integer childKey, integer value returns nothing */ function SaveInteger(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _value = luaL_checkinteger(L, 4); console.warn('SaveInteger was called but is not implemented :('); return 0; } /** * native SaveReal takes hashtable table, integer parentKey, integer childKey, real value returns nothing */ function SaveReal(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _value = luaL_checknumber(L, 4); console.warn('SaveReal was called but is not implemented :('); return 0; } /** * native SaveBoolean takes hashtable table, integer parentKey, integer childKey, boolean value returns nothing */ function SaveBoolean(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _value = lua_toboolean(L, 4); console.warn('SaveBoolean was called but is not implemented :('); return 0; } /** * native SaveStr takes hashtable table, integer parentKey, integer childKey, string value returns boolean */ function SaveStr(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _value = luaL_checkstring(L, 4); console.warn('SaveStr was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SavePlayerHandle takes hashtable table, integer parentKey, integer childKey, player whichPlayer returns boolean */ function SavePlayerHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichPlayer = lua_touserdata(L, 4); console.warn('SavePlayerHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveWidgetHandle takes hashtable table, integer parentKey, integer childKey, widget whichWidget returns boolean */ function SaveWidgetHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichWidget = lua_touserdata(L, 4); console.warn('SaveWidgetHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveDestructableHandle takes hashtable table, integer parentKey, integer childKey, destructable whichDestructable returns boolean */ function SaveDestructableHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichDestructable = lua_touserdata(L, 4); console.warn('SaveDestructableHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveItemHandle takes hashtable table, integer parentKey, integer childKey, item whichItem returns boolean */ function SaveItemHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichItem = lua_touserdata(L, 4); console.warn('SaveItemHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveUnitHandle takes hashtable table, integer parentKey, integer childKey, unit whichUnit returns boolean */ function SaveUnitHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichUnit = lua_touserdata(L, 4); console.warn('SaveUnitHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveAbilityHandle takes hashtable table, integer parentKey, integer childKey, ability whichAbility returns boolean */ function SaveAbilityHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichAbility = lua_touserdata(L, 4); console.warn('SaveAbilityHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTimerHandle takes hashtable table, integer parentKey, integer childKey, timer whichTimer returns boolean */ function SaveTimerHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTimer = lua_touserdata(L, 4); console.warn('SaveTimerHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTriggerHandle takes hashtable table, integer parentKey, integer childKey, trigger whichTrigger returns boolean */ function SaveTriggerHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTrigger = lua_touserdata(L, 4); console.warn('SaveTriggerHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTriggerConditionHandle takes hashtable table, integer parentKey, integer childKey, triggercondition whichTriggercondition returns boolean */ function SaveTriggerConditionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTriggercondition = lua_touserdata(L, 4); console.warn('SaveTriggerConditionHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTriggerActionHandle takes hashtable table, integer parentKey, integer childKey, triggeraction whichTriggeraction returns boolean */ function SaveTriggerActionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTriggeraction = lua_touserdata(L, 4); console.warn('SaveTriggerActionHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTriggerEventHandle takes hashtable table, integer parentKey, integer childKey, event whichEvent returns boolean */ function SaveTriggerEventHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichEvent = lua_touserdata(L, 4); console.warn('SaveTriggerEventHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveForceHandle takes hashtable table, integer parentKey, integer childKey, force whichForce returns boolean */ function SaveForceHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichForce = lua_touserdata(L, 4); console.warn('SaveForceHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveGroupHandle takes hashtable table, integer parentKey, integer childKey, group whichGroup returns boolean */ function SaveGroupHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichGroup = lua_touserdata(L, 4); console.warn('SaveGroupHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveLocationHandle takes hashtable table, integer parentKey, integer childKey, location whichLocation returns boolean */ function SaveLocationHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichLocation = lua_touserdata(L, 4); console.warn('SaveLocationHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveRectHandle takes hashtable table, integer parentKey, integer childKey, rect whichRect returns boolean */ function SaveRectHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichRect = lua_touserdata(L, 4); console.warn('SaveRectHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveBooleanExprHandle takes hashtable table, integer parentKey, integer childKey, boolexpr whichBoolexpr returns boolean */ function SaveBooleanExprHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichBoolexpr = lua_touserdata(L, 4); console.warn('SaveBooleanExprHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveSoundHandle takes hashtable table, integer parentKey, integer childKey, sound whichSound returns boolean */ function SaveSoundHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichSound = lua_touserdata(L, 4); console.warn('SaveSoundHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveEffectHandle takes hashtable table, integer parentKey, integer childKey, effect whichEffect returns boolean */ function SaveEffectHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichEffect = lua_touserdata(L, 4); console.warn('SaveEffectHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveUnitPoolHandle takes hashtable table, integer parentKey, integer childKey, unitpool whichUnitpool returns boolean */ function SaveUnitPoolHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichUnitpool = lua_touserdata(L, 4); console.warn('SaveUnitPoolHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveItemPoolHandle takes hashtable table, integer parentKey, integer childKey, itempool whichItempool returns boolean */ function SaveItemPoolHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichItempool = lua_touserdata(L, 4); console.warn('SaveItemPoolHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveQuestHandle takes hashtable table, integer parentKey, integer childKey, quest whichQuest returns boolean */ function SaveQuestHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichQuest = lua_touserdata(L, 4); console.warn('SaveQuestHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveQuestItemHandle takes hashtable table, integer parentKey, integer childKey, questitem whichQuestitem returns boolean */ function SaveQuestItemHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichQuestitem = lua_touserdata(L, 4); console.warn('SaveQuestItemHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveDefeatConditionHandle takes hashtable table, integer parentKey, integer childKey, defeatcondition whichDefeatcondition returns boolean */ function SaveDefeatConditionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichDefeatcondition = lua_touserdata(L, 4); console.warn('SaveDefeatConditionHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTimerDialogHandle takes hashtable table, integer parentKey, integer childKey, timerdialog whichTimerdialog returns boolean */ function SaveTimerDialogHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTimerdialog = lua_touserdata(L, 4); console.warn('SaveTimerDialogHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveLeaderboardHandle takes hashtable table, integer parentKey, integer childKey, leaderboard whichLeaderboard returns boolean */ function SaveLeaderboardHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichLeaderboard = lua_touserdata(L, 4); console.warn('SaveLeaderboardHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveMultiboardHandle takes hashtable table, integer parentKey, integer childKey, multiboard whichMultiboard returns boolean */ function SaveMultiboardHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichMultiboard = lua_touserdata(L, 4); console.warn('SaveMultiboardHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveMultiboardItemHandle takes hashtable table, integer parentKey, integer childKey, multiboarditem whichMultiboarditem returns boolean */ function SaveMultiboardItemHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichMultiboarditem = lua_touserdata(L, 4); console.warn('SaveMultiboardItemHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTrackableHandle takes hashtable table, integer parentKey, integer childKey, trackable whichTrackable returns boolean */ function SaveTrackableHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTrackable = lua_touserdata(L, 4); console.warn('SaveTrackableHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveDialogHandle takes hashtable table, integer parentKey, integer childKey, dialog whichDialog returns boolean */ function SaveDialogHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichDialog = lua_touserdata(L, 4); console.warn('SaveDialogHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveButtonHandle takes hashtable table, integer parentKey, integer childKey, button whichButton returns boolean */ function SaveButtonHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichButton = lua_touserdata(L, 4); console.warn('SaveButtonHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveTextTagHandle takes hashtable table, integer parentKey, integer childKey, texttag whichTexttag returns boolean */ function SaveTextTagHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichTexttag = lua_touserdata(L, 4); console.warn('SaveTextTagHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveLightningHandle takes hashtable table, integer parentKey, integer childKey, lightning whichLightning returns boolean */ function SaveLightningHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichLightning = lua_touserdata(L, 4); console.warn('SaveLightningHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveImageHandle takes hashtable table, integer parentKey, integer childKey, image whichImage returns boolean */ function SaveImageHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichImage = lua_touserdata(L, 4); console.warn('SaveImageHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveUbersplatHandle takes hashtable table, integer parentKey, integer childKey, ubersplat whichUbersplat returns boolean */ function SaveUbersplatHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichUbersplat = lua_touserdata(L, 4); console.warn('SaveUbersplatHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveRegionHandle takes hashtable table, integer parentKey, integer childKey, region whichRegion returns boolean */ function SaveRegionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichRegion = lua_touserdata(L, 4); console.warn('SaveRegionHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveFogStateHandle takes hashtable table, integer parentKey, integer childKey, fogstate whichFogState returns boolean */ function SaveFogStateHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichFogState = lua_touserdata(L, 4); console.warn('SaveFogStateHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveFogModifierHandle takes hashtable table, integer parentKey, integer childKey, fogmodifier whichFogModifier returns boolean */ function SaveFogModifierHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichFogModifier = lua_touserdata(L, 4); console.warn('SaveFogModifierHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveAgentHandle takes hashtable table, integer parentKey, integer childKey, agent whichAgent returns boolean */ function SaveAgentHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichAgent = lua_touserdata(L, 4); console.warn('SaveAgentHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SaveHashtableHandle takes hashtable table, integer parentKey, integer childKey, hashtable whichHashtable returns boolean */ function SaveHashtableHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); const _whichHashtable = lua_touserdata(L, 4); console.warn('SaveHashtableHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native LoadInteger takes hashtable table, integer parentKey, integer childKey returns integer */ function LoadInteger(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadInteger was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native LoadReal takes hashtable table, integer parentKey, integer childKey returns real */ function LoadReal(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadReal was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native LoadBoolean takes hashtable table, integer parentKey, integer childKey returns boolean */ function LoadBoolean(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadBoolean was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native LoadStr takes hashtable table, integer parentKey, integer childKey returns string */ function LoadStr(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadStr was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native LoadPlayerHandle takes hashtable table, integer parentKey, integer childKey returns player */ function LoadPlayerHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadPlayerHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadWidgetHandle takes hashtable table, integer parentKey, integer childKey returns widget */ function LoadWidgetHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadWidgetHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadDestructableHandle takes hashtable table, integer parentKey, integer childKey returns destructable */ function LoadDestructableHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadDestructableHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadItemHandle takes hashtable table, integer parentKey, integer childKey returns item */ function LoadItemHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadItemHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadUnitHandle takes hashtable table, integer parentKey, integer childKey returns unit */ function LoadUnitHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadUnitHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadAbilityHandle takes hashtable table, integer parentKey, integer childKey returns ability */ function LoadAbilityHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadAbilityHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTimerHandle takes hashtable table, integer parentKey, integer childKey returns timer */ function LoadTimerHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTimerHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTriggerHandle takes hashtable table, integer parentKey, integer childKey returns trigger */ function LoadTriggerHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTriggerHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTriggerConditionHandle takes hashtable table, integer parentKey, integer childKey returns triggercondition */ function LoadTriggerConditionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTriggerConditionHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTriggerActionHandle takes hashtable table, integer parentKey, integer childKey returns triggeraction */ function LoadTriggerActionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTriggerActionHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTriggerEventHandle takes hashtable table, integer parentKey, integer childKey returns event */ function LoadTriggerEventHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTriggerEventHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadForceHandle takes hashtable table, integer parentKey, integer childKey returns force */ function LoadForceHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadForceHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadGroupHandle takes hashtable table, integer parentKey, integer childKey returns group */ function LoadGroupHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadGroupHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadLocationHandle takes hashtable table, integer parentKey, integer childKey returns location */ function LoadLocationHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadLocationHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadRectHandle takes hashtable table, integer parentKey, integer childKey returns rect */ function LoadRectHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadRectHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadBooleanExprHandle takes hashtable table, integer parentKey, integer childKey returns boolexpr */ function LoadBooleanExprHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadBooleanExprHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadSoundHandle takes hashtable table, integer parentKey, integer childKey returns sound */ function LoadSoundHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadSoundHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadEffectHandle takes hashtable table, integer parentKey, integer childKey returns effect */ function LoadEffectHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadEffectHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadUnitPoolHandle takes hashtable table, integer parentKey, integer childKey returns unitpool */ function LoadUnitPoolHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadUnitPoolHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadItemPoolHandle takes hashtable table, integer parentKey, integer childKey returns itempool */ function LoadItemPoolHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadItemPoolHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadQuestHandle takes hashtable table, integer parentKey, integer childKey returns quest */ function LoadQuestHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadQuestHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadQuestItemHandle takes hashtable table, integer parentKey, integer childKey returns questitem */ function LoadQuestItemHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadQuestItemHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadDefeatConditionHandle takes hashtable table, integer parentKey, integer childKey returns defeatcondition */ function LoadDefeatConditionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadDefeatConditionHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTimerDialogHandle takes hashtable table, integer parentKey, integer childKey returns timerdialog */ function LoadTimerDialogHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTimerDialogHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadLeaderboardHandle takes hashtable table, integer parentKey, integer childKey returns leaderboard */ function LoadLeaderboardHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadLeaderboardHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadMultiboardHandle takes hashtable table, integer parentKey, integer childKey returns multiboard */ function LoadMultiboardHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadMultiboardHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadMultiboardItemHandle takes hashtable table, integer parentKey, integer childKey returns multiboarditem */ function LoadMultiboardItemHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadMultiboardItemHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTrackableHandle takes hashtable table, integer parentKey, integer childKey returns trackable */ function LoadTrackableHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTrackableHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadDialogHandle takes hashtable table, integer parentKey, integer childKey returns dialog */ function LoadDialogHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadDialogHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadButtonHandle takes hashtable table, integer parentKey, integer childKey returns button */ function LoadButtonHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadButtonHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadTextTagHandle takes hashtable table, integer parentKey, integer childKey returns texttag */ function LoadTextTagHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadTextTagHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadLightningHandle takes hashtable table, integer parentKey, integer childKey returns lightning */ function LoadLightningHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadLightningHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadImageHandle takes hashtable table, integer parentKey, integer childKey returns image */ function LoadImageHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadImageHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadUbersplatHandle takes hashtable table, integer parentKey, integer childKey returns ubersplat */ function LoadUbersplatHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadUbersplatHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadRegionHandle takes hashtable table, integer parentKey, integer childKey returns region */ function LoadRegionHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadRegionHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadFogStateHandle takes hashtable table, integer parentKey, integer childKey returns fogstate */ function LoadFogStateHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadFogStateHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadFogModifierHandle takes hashtable table, integer parentKey, integer childKey returns fogmodifier */ function LoadFogModifierHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadFogModifierHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LoadHashtableHandle takes hashtable table, integer parentKey, integer childKey returns hashtable */ function LoadHashtableHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('LoadHashtableHandle was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native HaveSavedInteger takes hashtable table, integer parentKey, integer childKey returns boolean */ function HaveSavedInteger(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('HaveSavedInteger was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveSavedReal takes hashtable table, integer parentKey, integer childKey returns boolean */ function HaveSavedReal(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('HaveSavedReal was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveSavedBoolean takes hashtable table, integer parentKey, integer childKey returns boolean */ function HaveSavedBoolean(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('HaveSavedBoolean was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveSavedString takes hashtable table, integer parentKey, integer childKey returns boolean */ function HaveSavedString(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('HaveSavedString was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native HaveSavedHandle takes hashtable table, integer parentKey, integer childKey returns boolean */ function HaveSavedHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('HaveSavedHandle was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native RemoveSavedInteger takes hashtable table, integer parentKey, integer childKey returns nothing */ function RemoveSavedInteger(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('RemoveSavedInteger was called but is not implemented :('); return 0; } /** * native RemoveSavedReal takes hashtable table, integer parentKey, integer childKey returns nothing */ function RemoveSavedReal(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('RemoveSavedReal was called but is not implemented :('); return 0; } /** * native RemoveSavedBoolean takes hashtable table, integer parentKey, integer childKey returns nothing */ function RemoveSavedBoolean(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('RemoveSavedBoolean was called but is not implemented :('); return 0; } /** * native RemoveSavedString takes hashtable table, integer parentKey, integer childKey returns nothing */ function RemoveSavedString(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('RemoveSavedString was called but is not implemented :('); return 0; } /** * native RemoveSavedHandle takes hashtable table, integer parentKey, integer childKey returns nothing */ function RemoveSavedHandle(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); const _childKey = luaL_checkinteger(L, 3); console.warn('RemoveSavedHandle was called but is not implemented :('); return 0; } /** * native FlushParentHashtable takes hashtable table returns nothing */ function FlushParentHashtable(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); console.warn('FlushParentHashtable was called but is not implemented :('); return 0; } /** * native FlushChildHashtable takes hashtable table, integer parentKey returns nothing */ function FlushChildHashtable(C: Context, L: lua_State): number { const _table = lua_touserdata(L, 1); const _parentKey = luaL_checkinteger(L, 2); console.warn('FlushChildHashtable was called but is not implemented :('); return 0; } /** * native GetRandomInt takes integer lowBound, integer highBound returns integer */ function GetRandomInt(C: Context, L: lua_State): number { const _lowBound = luaL_checkinteger(L, 1); const _highBound = luaL_checkinteger(L, 2); console.warn('GetRandomInt was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetRandomReal takes real lowBound, real highBound returns real */ function GetRandomReal(C: Context, L: lua_State): number { const _lowBound = luaL_checknumber(L, 1); const _highBound = luaL_checknumber(L, 2); console.warn('GetRandomReal was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native CreateUnitPool takes nothing returns unitpool */ function CreateUnitPool(C: Context, L: lua_State): number { console.warn('CreateUnitPool was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyUnitPool takes unitpool whichPool returns nothing */ function DestroyUnitPool(C: Context, L: lua_State): number { const _whichPool = lua_touserdata(L, 1); console.warn('DestroyUnitPool was called but is not implemented :('); return 0; } /** * native UnitPoolAddUnitType takes unitpool whichPool, integer unitId, real weight returns nothing */ function UnitPoolAddUnitType(C: Context, L: lua_State): number { const _whichPool = lua_touserdata(L, 1); const _unitId = luaL_checkinteger(L, 2); const _weight = luaL_checknumber(L, 3); console.warn('UnitPoolAddUnitType was called but is not implemented :('); return 0; } /** * native UnitPoolRemoveUnitType takes unitpool whichPool, integer unitId returns nothing */ function UnitPoolRemoveUnitType(C: Context, L: lua_State): number { const _whichPool = lua_touserdata(L, 1); const _unitId = luaL_checkinteger(L, 2); console.warn('UnitPoolRemoveUnitType was called but is not implemented :('); return 0; } /** * native PlaceRandomUnit takes unitpool whichPool, player forWhichPlayer, real x, real y, real facing returns unit */ function PlaceRandomUnit(C: Context, L: lua_State): number { const _whichPool = lua_touserdata(L, 1); const _forWhichPlayer = lua_touserdata(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); const _facing = luaL_checknumber(L, 5); console.warn('PlaceRandomUnit was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateItemPool takes nothing returns itempool */ function CreateItemPool(C: Context, L: lua_State): number { console.warn('CreateItemPool was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyItemPool takes itempool whichItemPool returns nothing */ function DestroyItemPool(C: Context, L: lua_State): number { const _whichItemPool = lua_touserdata(L, 1); console.warn('DestroyItemPool was called but is not implemented :('); return 0; } /** * native ItemPoolAddItemType takes itempool whichItemPool, integer itemId, real weight returns nothing */ function ItemPoolAddItemType(C: Context, L: lua_State): number { const _whichItemPool = lua_touserdata(L, 1); const _itemId = luaL_checkinteger(L, 2); const _weight = luaL_checknumber(L, 3); console.warn('ItemPoolAddItemType was called but is not implemented :('); return 0; } /** * native ItemPoolRemoveItemType takes itempool whichItemPool, integer itemId returns nothing */ function ItemPoolRemoveItemType(C: Context, L: lua_State): number { const _whichItemPool = lua_touserdata(L, 1); const _itemId = luaL_checkinteger(L, 2); console.warn('ItemPoolRemoveItemType was called but is not implemented :('); return 0; } /** * native PlaceRandomItem takes itempool whichItemPool, real x, real y returns item */ function PlaceRandomItem(C: Context, L: lua_State): number { const _whichItemPool = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('PlaceRandomItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native ChooseRandomCreep takes integer level returns integer */ function ChooseRandomCreep(C: Context, L: lua_State): number { const _level = luaL_checkinteger(L, 1); console.warn('ChooseRandomCreep was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native ChooseRandomNPBuilding takes nothing returns integer */ function ChooseRandomNPBuilding(C: Context, L: lua_State): number { console.warn('ChooseRandomNPBuilding was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native ChooseRandomItem takes integer level returns integer */ function ChooseRandomItem(C: Context, L: lua_State): number { const _level = luaL_checkinteger(L, 1); console.warn('ChooseRandomItem was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native ChooseRandomItemEx takes itemtype whichType, integer level returns integer */ function ChooseRandomItemEx(C: Context, L: lua_State): number { const _whichType = lua_touserdata(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('ChooseRandomItemEx was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetRandomSeed takes integer seed returns nothing */ function SetRandomSeed(C: Context, L: lua_State): number { const _seed = luaL_checkinteger(L, 1); console.warn('SetRandomSeed was called but is not implemented :('); return 0; } /** * native SetTerrainFog takes real a, real b, real c, real d, real e returns nothing */ function SetTerrainFog(C: Context, L: lua_State): number { const _a = luaL_checknumber(L, 1); const _b = luaL_checknumber(L, 2); const _c = luaL_checknumber(L, 3); const _d = luaL_checknumber(L, 4); const _e = luaL_checknumber(L, 5); console.warn('SetTerrainFog was called but is not implemented :('); return 0; } /** * native ResetTerrainFog takes nothing returns nothing */ function ResetTerrainFog(_C: Context, _L: lua_State): number { console.warn('ResetTerrainFog was called but is not implemented :('); return 0; } /** * native SetUnitFog takes real a, real b, real c, real d, real e returns nothing */ function SetUnitFog(C: Context, L: lua_State): number { const _a = luaL_checknumber(L, 1); const _b = luaL_checknumber(L, 2); const _c = luaL_checknumber(L, 3); const _d = luaL_checknumber(L, 4); const _e = luaL_checknumber(L, 5); console.warn('SetUnitFog was called but is not implemented :('); return 0; } /** * native SetTerrainFogEx takes integer style, real zstart, real zend, real density, real red, real green, real blue returns nothing */ function SetTerrainFogEx(C: Context, L: lua_State): number { const _style = luaL_checkinteger(L, 1); const _zstart = luaL_checknumber(L, 2); const _zend = luaL_checknumber(L, 3); const _density = luaL_checknumber(L, 4); const _red = luaL_checknumber(L, 5); const _green = luaL_checknumber(L, 6); const _blue = luaL_checknumber(L, 7); console.warn('SetTerrainFogEx was called but is not implemented :('); return 0; } /** * native DisplayTextToPlayer takes player toPlayer, real x, real y, string message returns nothing */ function DisplayTextToPlayer(C: Context, L: lua_State): number { const _toPlayer = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _message = luaL_checkstring(L, 4); console.warn('DisplayTextToPlayer was called but is not implemented :('); return 0; } /** * native DisplayTimedTextToPlayer takes player toPlayer, real x, real y, real duration, string message returns nothing */ function DisplayTimedTextToPlayer(C: Context, L: lua_State): number { const _toPlayer = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _duration = luaL_checknumber(L, 4); const _message = luaL_checkstring(L, 5); console.warn('DisplayTimedTextToPlayer was called but is not implemented :('); return 0; } /** * native DisplayTimedTextFromPlayer takes player toPlayer, real x, real y, real duration, string message returns nothing */ function DisplayTimedTextFromPlayer(C: Context, L: lua_State): number { const _toPlayer = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _duration = luaL_checknumber(L, 4); const _message = luaL_checkstring(L, 5); console.warn('DisplayTimedTextFromPlayer was called but is not implemented :('); return 0; } /** * native ClearTextMessages takes nothing returns nothing */ function ClearTextMessages(_C: Context, _L: lua_State): number { console.warn('ClearTextMessages was called but is not implemented :('); return 0; } /** * native SetDayNightModels takes string terrainDNCFile, string unitDNCFile returns nothing */ function SetDayNightModels(C: Context, L: lua_State): number { const _terrainDNCFile = luaL_checkstring(L, 1); const _unitDNCFile = luaL_checkstring(L, 2); console.warn('SetDayNightModels was called but is not implemented :('); return 0; } /** * native SetSkyModel takes string skyModelFile returns nothing */ function SetSkyModel(C: Context, L: lua_State): number { const _skyModelFile = luaL_checkstring(L, 1); console.warn('SetSkyModel was called but is not implemented :('); return 0; } /** * native EnableUserControl takes boolean b returns nothing */ function EnableUserControl(C: Context, L: lua_State): number { const _b = lua_toboolean(L, 1); console.warn('EnableUserControl was called but is not implemented :('); return 0; } /** * native EnableUserUI takes boolean b returns nothing */ function EnableUserUI(C: Context, L: lua_State): number { const _b = lua_toboolean(L, 1); console.warn('EnableUserUI was called but is not implemented :('); return 0; } /** * native SuspendTimeOfDay takes boolean b returns nothing */ function SuspendTimeOfDay(C: Context, L: lua_State): number { const _b = lua_toboolean(L, 1); console.warn('SuspendTimeOfDay was called but is not implemented :('); return 0; } /** * native SetTimeOfDayScale takes real r returns nothing */ function SetTimeOfDayScale(C: Context, L: lua_State): number { const _r = luaL_checknumber(L, 1); console.warn('SetTimeOfDayScale was called but is not implemented :('); return 0; } /** * native GetTimeOfDayScale takes nothing returns real */ function GetTimeOfDayScale(C: Context, L: lua_State): number { console.warn('GetTimeOfDayScale was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native ShowInterface takes boolean flag, real fadeDuration returns nothing */ function ShowInterface(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); const _fadeDuration = luaL_checknumber(L, 2); console.warn('ShowInterface was called but is not implemented :('); return 0; } /** * native PauseGame takes boolean flag returns nothing */ function PauseGame(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); console.warn('PauseGame was called but is not implemented :('); return 0; } /** * native UnitAddIndicator takes unit whichUnit, integer red, integer green, integer blue, integer alpha returns nothing */ function UnitAddIndicator(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('UnitAddIndicator was called but is not implemented :('); return 0; } /** * native AddIndicator takes widget whichWidget, integer red, integer green, integer blue, integer alpha returns nothing */ function AddIndicator(C: Context, L: lua_State): number { const _whichWidget = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('AddIndicator was called but is not implemented :('); return 0; } /** * native PingMinimap takes real x, real y, real duration returns nothing */ function PingMinimap(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _duration = luaL_checknumber(L, 3); console.warn('PingMinimap was called but is not implemented :('); return 0; } /** * native PingMinimapEx takes real x, real y, real duration, integer red, integer green, integer blue, boolean extraEffects returns nothing */ function PingMinimapEx(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _duration = luaL_checknumber(L, 3); const _red = luaL_checkinteger(L, 4); const _green = luaL_checkinteger(L, 5); const _blue = luaL_checkinteger(L, 6); const _extraEffects = lua_toboolean(L, 7); console.warn('PingMinimapEx was called but is not implemented :('); return 0; } /** * native EnableOcclusion takes boolean flag returns nothing */ function EnableOcclusion(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); console.warn('EnableOcclusion was called but is not implemented :('); return 0; } /** * native SetIntroShotText takes string introText returns nothing */ function SetIntroShotText(C: Context, L: lua_State): number { const _introText = luaL_checkstring(L, 1); console.warn('SetIntroShotText was called but is not implemented :('); return 0; } /** * native SetIntroShotModel takes string introModelPath returns nothing */ function SetIntroShotModel(C: Context, L: lua_State): number { const _introModelPath = luaL_checkstring(L, 1); console.warn('SetIntroShotModel was called but is not implemented :('); return 0; } /** * native EnableWorldFogBoundary takes boolean b returns nothing */ function EnableWorldFogBoundary(C: Context, L: lua_State): number { const _b = lua_toboolean(L, 1); console.warn('EnableWorldFogBoundary was called but is not implemented :('); return 0; } /** * native PlayModelCinematic takes string modelName returns nothing */ function PlayModelCinematic(C: Context, L: lua_State): number { const _modelName = luaL_checkstring(L, 1); console.warn('PlayModelCinematic was called but is not implemented :('); return 0; } /** * native PlayCinematic takes string movieName returns nothing */ function PlayCinematic(C: Context, L: lua_State): number { const _movieName = luaL_checkstring(L, 1); console.warn('PlayCinematic was called but is not implemented :('); return 0; } /** * native ForceUIKey takes string key returns nothing */ function ForceUIKey(C: Context, L: lua_State): number { const _key = luaL_checkstring(L, 1); console.warn('ForceUIKey was called but is not implemented :('); return 0; } /** * native ForceUICancel takes nothing returns nothing */ function ForceUICancel(_C: Context, _L: lua_State): number { console.warn('ForceUICancel was called but is not implemented :('); return 0; } /** * native DisplayLoadDialog takes nothing returns nothing */ function DisplayLoadDialog(_C: Context, _L: lua_State): number { console.warn('DisplayLoadDialog was called but is not implemented :('); return 0; } /** * native SetAltMinimapIcon takes string iconPath returns nothing */ function SetAltMinimapIcon(C: Context, L: lua_State): number { const _iconPath = luaL_checkstring(L, 1); console.warn('SetAltMinimapIcon was called but is not implemented :('); return 0; } /** * native DisableRestartMission takes boolean flag returns nothing */ function DisableRestartMission(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); console.warn('DisableRestartMission was called but is not implemented :('); return 0; } /** * native CreateTextTag takes nothing returns texttag */ function CreateTextTag(C: Context, L: lua_State): number { console.warn('CreateTextTag was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyTextTag takes texttag t returns nothing */ function DestroyTextTag(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); console.warn('DestroyTextTag was called but is not implemented :('); return 0; } /** * native SetTextTagText takes texttag t, string s, real height returns nothing */ function SetTextTagText(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _s = luaL_checkstring(L, 2); const _height = luaL_checknumber(L, 3); console.warn('SetTextTagText was called but is not implemented :('); return 0; } /** * native SetTextTagPos takes texttag t, real x, real y, real heightOffset returns nothing */ function SetTextTagPos(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _heightOffset = luaL_checknumber(L, 4); console.warn('SetTextTagPos was called but is not implemented :('); return 0; } /** * native SetTextTagPosUnit takes texttag t, unit whichUnit, real heightOffset returns nothing */ function SetTextTagPosUnit(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); const _heightOffset = luaL_checknumber(L, 3); console.warn('SetTextTagPosUnit was called but is not implemented :('); return 0; } /** * native SetTextTagColor takes texttag t, integer red, integer green, integer blue, integer alpha returns nothing */ function SetTextTagColor(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('SetTextTagColor was called but is not implemented :('); return 0; } /** * native SetTextTagVelocity takes texttag t, real xvel, real yvel returns nothing */ function SetTextTagVelocity(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _xvel = luaL_checknumber(L, 2); const _yvel = luaL_checknumber(L, 3); console.warn('SetTextTagVelocity was called but is not implemented :('); return 0; } /** * native SetTextTagVisibility takes texttag t, boolean flag returns nothing */ function SetTextTagVisibility(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetTextTagVisibility was called but is not implemented :('); return 0; } /** * native SetTextTagSuspended takes texttag t, boolean flag returns nothing */ function SetTextTagSuspended(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetTextTagSuspended was called but is not implemented :('); return 0; } /** * native SetTextTagPermanent takes texttag t, boolean flag returns nothing */ function SetTextTagPermanent(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetTextTagPermanent was called but is not implemented :('); return 0; } /** * native SetTextTagAge takes texttag t, real age returns nothing */ function SetTextTagAge(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _age = luaL_checknumber(L, 2); console.warn('SetTextTagAge was called but is not implemented :('); return 0; } /** * native SetTextTagLifespan takes texttag t, real lifespan returns nothing */ function SetTextTagLifespan(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _lifespan = luaL_checknumber(L, 2); console.warn('SetTextTagLifespan was called but is not implemented :('); return 0; } /** * native SetTextTagFadepoint takes texttag t, real fadepoint returns nothing */ function SetTextTagFadepoint(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); const _fadepoint = luaL_checknumber(L, 2); console.warn('SetTextTagFadepoint was called but is not implemented :('); return 0; } /** * native SetReservedLocalHeroButtons takes integer reserved returns nothing */ function SetReservedLocalHeroButtons(C: Context, L: lua_State): number { const _reserved = luaL_checkinteger(L, 1); console.warn('SetReservedLocalHeroButtons was called but is not implemented :('); return 0; } /** * native GetAllyColorFilterState takes nothing returns integer */ function GetAllyColorFilterState(C: Context, L: lua_State): number { console.warn('GetAllyColorFilterState was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetAllyColorFilterState takes integer state returns nothing */ function SetAllyColorFilterState(C: Context, L: lua_State): number { const _state = luaL_checkinteger(L, 1); console.warn('SetAllyColorFilterState was called but is not implemented :('); return 0; } /** * native GetCreepCampFilterState takes nothing returns boolean */ function GetCreepCampFilterState(C: Context, L: lua_State): number { console.warn('GetCreepCampFilterState was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetCreepCampFilterState takes boolean state returns nothing */ function SetCreepCampFilterState(C: Context, L: lua_State): number { const _state = lua_toboolean(L, 1); console.warn('SetCreepCampFilterState was called but is not implemented :('); return 0; } /** * native EnableMinimapFilterButtons takes boolean enableAlly, boolean enableCreep returns nothing */ function EnableMinimapFilterButtons(C: Context, L: lua_State): number { const _enableAlly = lua_toboolean(L, 1); const _enableCreep = lua_toboolean(L, 2); console.warn('EnableMinimapFilterButtons was called but is not implemented :('); return 0; } /** * native EnableDragSelect takes boolean state, boolean ui returns nothing */ function EnableDragSelect(C: Context, L: lua_State): number { const _state = lua_toboolean(L, 1); const _ui = lua_toboolean(L, 2); console.warn('EnableDragSelect was called but is not implemented :('); return 0; } /** * native EnablePreSelect takes boolean state, boolean ui returns nothing */ function EnablePreSelect(C: Context, L: lua_State): number { const _state = lua_toboolean(L, 1); const _ui = lua_toboolean(L, 2); console.warn('EnablePreSelect was called but is not implemented :('); return 0; } /** * native EnableSelect takes boolean state, boolean ui returns nothing */ function EnableSelect(C: Context, L: lua_State): number { const _state = lua_toboolean(L, 1); const _ui = lua_toboolean(L, 2); console.warn('EnableSelect was called but is not implemented :('); return 0; } /** * native CreateTrackable takes string trackableModelPath, real x, real y, real facing returns trackable */ function CreateTrackable(C: Context, L: lua_State): number { const _trackableModelPath = luaL_checkstring(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _facing = luaL_checknumber(L, 4); console.warn('CreateTrackable was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateQuest takes nothing returns quest */ function CreateQuest(C: Context, L: lua_State): number { console.warn('CreateQuest was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyQuest takes quest whichQuest returns nothing */ function DestroyQuest(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('DestroyQuest was called but is not implemented :('); return 0; } /** * native QuestSetTitle takes quest whichQuest, string title returns nothing */ function QuestSetTitle(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _title = luaL_checkstring(L, 2); console.warn('QuestSetTitle was called but is not implemented :('); return 0; } /** * native QuestSetDescription takes quest whichQuest, string description returns nothing */ function QuestSetDescription(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _description = luaL_checkstring(L, 2); console.warn('QuestSetDescription was called but is not implemented :('); return 0; } /** * native QuestSetIconPath takes quest whichQuest, string iconPath returns nothing */ function QuestSetIconPath(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _iconPath = luaL_checkstring(L, 2); console.warn('QuestSetIconPath was called but is not implemented :('); return 0; } /** * native QuestSetRequired takes quest whichQuest, boolean required returns nothing */ function QuestSetRequired(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _required = lua_toboolean(L, 2); console.warn('QuestSetRequired was called but is not implemented :('); return 0; } /** * native QuestSetCompleted takes quest whichQuest, boolean completed returns nothing */ function QuestSetCompleted(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _completed = lua_toboolean(L, 2); console.warn('QuestSetCompleted was called but is not implemented :('); return 0; } /** * native QuestSetDiscovered takes quest whichQuest, boolean discovered returns nothing */ function QuestSetDiscovered(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _discovered = lua_toboolean(L, 2); console.warn('QuestSetDiscovered was called but is not implemented :('); return 0; } /** * native QuestSetFailed takes quest whichQuest, boolean failed returns nothing */ function QuestSetFailed(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _failed = lua_toboolean(L, 2); console.warn('QuestSetFailed was called but is not implemented :('); return 0; } /** * native QuestSetEnabled takes quest whichQuest, boolean enabled returns nothing */ function QuestSetEnabled(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); const _enabled = lua_toboolean(L, 2); console.warn('QuestSetEnabled was called but is not implemented :('); return 0; } /** * native IsQuestRequired takes quest whichQuest returns boolean */ function IsQuestRequired(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('IsQuestRequired was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsQuestCompleted takes quest whichQuest returns boolean */ function IsQuestCompleted(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('IsQuestCompleted was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsQuestDiscovered takes quest whichQuest returns boolean */ function IsQuestDiscovered(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('IsQuestDiscovered was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsQuestFailed takes quest whichQuest returns boolean */ function IsQuestFailed(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('IsQuestFailed was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsQuestEnabled takes quest whichQuest returns boolean */ function IsQuestEnabled(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('IsQuestEnabled was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native QuestCreateItem takes quest whichQuest returns questitem */ function QuestCreateItem(C: Context, L: lua_State): number { const _whichQuest = lua_touserdata(L, 1); console.warn('QuestCreateItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native QuestItemSetDescription takes questitem whichQuestItem, string description returns nothing */ function QuestItemSetDescription(C: Context, L: lua_State): number { const _whichQuestItem = lua_touserdata(L, 1); const _description = luaL_checkstring(L, 2); console.warn('QuestItemSetDescription was called but is not implemented :('); return 0; } /** * native QuestItemSetCompleted takes questitem whichQuestItem, boolean completed returns nothing */ function QuestItemSetCompleted(C: Context, L: lua_State): number { const _whichQuestItem = lua_touserdata(L, 1); const _completed = lua_toboolean(L, 2); console.warn('QuestItemSetCompleted was called but is not implemented :('); return 0; } /** * native IsQuestItemCompleted takes questitem whichQuestItem returns boolean */ function IsQuestItemCompleted(C: Context, L: lua_State): number { const _whichQuestItem = lua_touserdata(L, 1); console.warn('IsQuestItemCompleted was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native CreateDefeatCondition takes nothing returns defeatcondition */ function CreateDefeatCondition(C: Context, L: lua_State): number { console.warn('CreateDefeatCondition was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyDefeatCondition takes defeatcondition whichCondition returns nothing */ function DestroyDefeatCondition(C: Context, L: lua_State): number { const _whichCondition = lua_touserdata(L, 1); console.warn('DestroyDefeatCondition was called but is not implemented :('); return 0; } /** * native DefeatConditionSetDescription takes defeatcondition whichCondition, string description returns nothing */ function DefeatConditionSetDescription(C: Context, L: lua_State): number { const _whichCondition = lua_touserdata(L, 1); const _description = luaL_checkstring(L, 2); console.warn('DefeatConditionSetDescription was called but is not implemented :('); return 0; } /** * native FlashQuestDialogButton takes nothing returns nothing */ function FlashQuestDialogButton(_C: Context, _L: lua_State): number { console.warn('FlashQuestDialogButton was called but is not implemented :('); return 0; } /** * native ForceQuestDialogUpdate takes nothing returns nothing */ function ForceQuestDialogUpdate(_C: Context, _L: lua_State): number { console.warn('ForceQuestDialogUpdate was called but is not implemented :('); return 0; } /** * native CreateTimerDialog takes timer t returns timerdialog */ function CreateTimerDialog(C: Context, L: lua_State): number { const _t = lua_touserdata(L, 1); console.warn('CreateTimerDialog was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyTimerDialog takes timerdialog whichDialog returns nothing */ function DestroyTimerDialog(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); console.warn('DestroyTimerDialog was called but is not implemented :('); return 0; } /** * native TimerDialogSetTitle takes timerdialog whichDialog, string title returns nothing */ function TimerDialogSetTitle(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _title = luaL_checkstring(L, 2); console.warn('TimerDialogSetTitle was called but is not implemented :('); return 0; } /** * native TimerDialogSetTitleColor takes timerdialog whichDialog, integer red, integer green, integer blue, integer alpha returns nothing */ function TimerDialogSetTitleColor(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('TimerDialogSetTitleColor was called but is not implemented :('); return 0; } /** * native TimerDialogSetTimeColor takes timerdialog whichDialog, integer red, integer green, integer blue, integer alpha returns nothing */ function TimerDialogSetTimeColor(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('TimerDialogSetTimeColor was called but is not implemented :('); return 0; } /** * native TimerDialogSetSpeed takes timerdialog whichDialog, real speedMultFactor returns nothing */ function TimerDialogSetSpeed(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _speedMultFactor = luaL_checknumber(L, 2); console.warn('TimerDialogSetSpeed was called but is not implemented :('); return 0; } /** * native TimerDialogDisplay takes timerdialog whichDialog, boolean display returns nothing */ function TimerDialogDisplay(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _display = lua_toboolean(L, 2); console.warn('TimerDialogDisplay was called but is not implemented :('); return 0; } /** * native IsTimerDialogDisplayed takes timerdialog whichDialog returns boolean */ function IsTimerDialogDisplayed(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); console.warn('IsTimerDialogDisplayed was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native TimerDialogSetRealTimeRemaining takes timerdialog whichDialog, real timeRemaining returns nothing */ function TimerDialogSetRealTimeRemaining(C: Context, L: lua_State): number { const _whichDialog = lua_touserdata(L, 1); const _timeRemaining = luaL_checknumber(L, 2); console.warn('TimerDialogSetRealTimeRemaining was called but is not implemented :('); return 0; } /** * native CreateLeaderboard takes nothing returns leaderboard */ function CreateLeaderboard(C: Context, L: lua_State): number { console.warn('CreateLeaderboard was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyLeaderboard takes leaderboard lb returns nothing */ function DestroyLeaderboard(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('DestroyLeaderboard was called but is not implemented :('); return 0; } /** * native LeaderboardDisplay takes leaderboard lb, boolean show returns nothing */ function LeaderboardDisplay(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _show = lua_toboolean(L, 2); console.warn('LeaderboardDisplay was called but is not implemented :('); return 0; } /** * native IsLeaderboardDisplayed takes leaderboard lb returns boolean */ function IsLeaderboardDisplayed(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('IsLeaderboardDisplayed was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native LeaderboardGetItemCount takes leaderboard lb returns integer */ function LeaderboardGetItemCount(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('LeaderboardGetItemCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native LeaderboardSetSizeByItemCount takes leaderboard lb, integer count returns nothing */ function LeaderboardSetSizeByItemCount(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _count = luaL_checkinteger(L, 2); console.warn('LeaderboardSetSizeByItemCount was called but is not implemented :('); return 0; } /** * native LeaderboardAddItem takes leaderboard lb, string label, integer value, player p returns nothing */ function LeaderboardAddItem(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _label = luaL_checkstring(L, 2); const _value = luaL_checkinteger(L, 3); const _p = lua_touserdata(L, 4); console.warn('LeaderboardAddItem was called but is not implemented :('); return 0; } /** * native LeaderboardRemoveItem takes leaderboard lb, integer index returns nothing */ function LeaderboardRemoveItem(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _index = luaL_checkinteger(L, 2); console.warn('LeaderboardRemoveItem was called but is not implemented :('); return 0; } /** * native LeaderboardRemovePlayerItem takes leaderboard lb, player p returns nothing */ function LeaderboardRemovePlayerItem(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _p = lua_touserdata(L, 2); console.warn('LeaderboardRemovePlayerItem was called but is not implemented :('); return 0; } /** * native LeaderboardClear takes leaderboard lb returns nothing */ function LeaderboardClear(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('LeaderboardClear was called but is not implemented :('); return 0; } /** * native LeaderboardSortItemsByValue takes leaderboard lb, boolean ascending returns nothing */ function LeaderboardSortItemsByValue(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _ascending = lua_toboolean(L, 2); console.warn('LeaderboardSortItemsByValue was called but is not implemented :('); return 0; } /** * native LeaderboardSortItemsByPlayer takes leaderboard lb, boolean ascending returns nothing */ function LeaderboardSortItemsByPlayer(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _ascending = lua_toboolean(L, 2); console.warn('LeaderboardSortItemsByPlayer was called but is not implemented :('); return 0; } /** * native LeaderboardSortItemsByLabel takes leaderboard lb, boolean ascending returns nothing */ function LeaderboardSortItemsByLabel(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _ascending = lua_toboolean(L, 2); console.warn('LeaderboardSortItemsByLabel was called but is not implemented :('); return 0; } /** * native LeaderboardHasPlayerItem takes leaderboard lb, player p returns boolean */ function LeaderboardHasPlayerItem(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _p = lua_touserdata(L, 2); console.warn('LeaderboardHasPlayerItem was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native LeaderboardGetPlayerIndex takes leaderboard lb, player p returns integer */ function LeaderboardGetPlayerIndex(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _p = lua_touserdata(L, 2); console.warn('LeaderboardGetPlayerIndex was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native LeaderboardSetLabel takes leaderboard lb, string label returns nothing */ function LeaderboardSetLabel(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _label = luaL_checkstring(L, 2); console.warn('LeaderboardSetLabel was called but is not implemented :('); return 0; } /** * native LeaderboardGetLabelText takes leaderboard lb returns string */ function LeaderboardGetLabelText(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('LeaderboardGetLabelText was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native PlayerSetLeaderboard takes player toPlayer, leaderboard lb returns nothing */ function PlayerSetLeaderboard(C: Context, L: lua_State): number { const _toPlayer = lua_touserdata(L, 1); const _lb = lua_touserdata(L, 2); console.warn('PlayerSetLeaderboard was called but is not implemented :('); return 0; } /** * native PlayerGetLeaderboard takes player toPlayer returns leaderboard */ function PlayerGetLeaderboard(C: Context, L: lua_State): number { const _toPlayer = lua_touserdata(L, 1); console.warn('PlayerGetLeaderboard was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native LeaderboardSetLabelColor takes leaderboard lb, integer red, integer green, integer blue, integer alpha returns nothing */ function LeaderboardSetLabelColor(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('LeaderboardSetLabelColor was called but is not implemented :('); return 0; } /** * native LeaderboardSetValueColor takes leaderboard lb, integer red, integer green, integer blue, integer alpha returns nothing */ function LeaderboardSetValueColor(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('LeaderboardSetValueColor was called but is not implemented :('); return 0; } /** * native LeaderboardSetStyle takes leaderboard lb, boolean showLabel, boolean showNames, boolean showValues, boolean showIcons returns nothing */ function LeaderboardSetStyle(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _showLabel = lua_toboolean(L, 2); const _showNames = lua_toboolean(L, 3); const _showValues = lua_toboolean(L, 4); const _showIcons = lua_toboolean(L, 5); console.warn('LeaderboardSetStyle was called but is not implemented :('); return 0; } /** * native LeaderboardSetItemValue takes leaderboard lb, integer whichItem, integer val returns nothing */ function LeaderboardSetItemValue(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _whichItem = luaL_checkinteger(L, 2); const _val = luaL_checkinteger(L, 3); console.warn('LeaderboardSetItemValue was called but is not implemented :('); return 0; } /** * native LeaderboardSetItemLabel takes leaderboard lb, integer whichItem, string val returns nothing */ function LeaderboardSetItemLabel(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _whichItem = luaL_checkinteger(L, 2); const _val = luaL_checkstring(L, 3); console.warn('LeaderboardSetItemLabel was called but is not implemented :('); return 0; } /** * native LeaderboardSetItemStyle takes leaderboard lb, integer whichItem, boolean showLabel, boolean showValue, boolean showIcon returns nothing */ function LeaderboardSetItemStyle(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _whichItem = luaL_checkinteger(L, 2); const _showLabel = lua_toboolean(L, 3); const _showValue = lua_toboolean(L, 4); const _showIcon = lua_toboolean(L, 5); console.warn('LeaderboardSetItemStyle was called but is not implemented :('); return 0; } /** * native LeaderboardSetItemLabelColor takes leaderboard lb, integer whichItem, integer red, integer green, integer blue, integer alpha returns nothing */ function LeaderboardSetItemLabelColor(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _whichItem = luaL_checkinteger(L, 2); const _red = luaL_checkinteger(L, 3); const _green = luaL_checkinteger(L, 4); const _blue = luaL_checkinteger(L, 5); const _alpha = luaL_checkinteger(L, 6); console.warn('LeaderboardSetItemLabelColor was called but is not implemented :('); return 0; } /** * native LeaderboardSetItemValueColor takes leaderboard lb, integer whichItem, integer red, integer green, integer blue, integer alpha returns nothing */ function LeaderboardSetItemValueColor(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _whichItem = luaL_checkinteger(L, 2); const _red = luaL_checkinteger(L, 3); const _green = luaL_checkinteger(L, 4); const _blue = luaL_checkinteger(L, 5); const _alpha = luaL_checkinteger(L, 6); console.warn('LeaderboardSetItemValueColor was called but is not implemented :('); return 0; } /** * native CreateMultiboard takes nothing returns multiboard */ function CreateMultiboard(C: Context, L: lua_State): number { console.warn('CreateMultiboard was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyMultiboard takes multiboard lb returns nothing */ function DestroyMultiboard(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('DestroyMultiboard was called but is not implemented :('); return 0; } /** * native MultiboardDisplay takes multiboard lb, boolean show returns nothing */ function MultiboardDisplay(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _show = lua_toboolean(L, 2); console.warn('MultiboardDisplay was called but is not implemented :('); return 0; } /** * native IsMultiboardDisplayed takes multiboard lb returns boolean */ function IsMultiboardDisplayed(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('IsMultiboardDisplayed was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native MultiboardMinimize takes multiboard lb, boolean minimize returns nothing */ function MultiboardMinimize(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _minimize = lua_toboolean(L, 2); console.warn('MultiboardMinimize was called but is not implemented :('); return 0; } /** * native IsMultiboardMinimized takes multiboard lb returns boolean */ function IsMultiboardMinimized(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('IsMultiboardMinimized was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native MultiboardClear takes multiboard lb returns nothing */ function MultiboardClear(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('MultiboardClear was called but is not implemented :('); return 0; } /** * native MultiboardSetTitleText takes multiboard lb, string label returns nothing */ function MultiboardSetTitleText(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _label = luaL_checkstring(L, 2); console.warn('MultiboardSetTitleText was called but is not implemented :('); return 0; } /** * native MultiboardGetTitleText takes multiboard lb returns string */ function MultiboardGetTitleText(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('MultiboardGetTitleText was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native MultiboardSetTitleTextColor takes multiboard lb, integer red, integer green, integer blue, integer alpha returns nothing */ function MultiboardSetTitleTextColor(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('MultiboardSetTitleTextColor was called but is not implemented :('); return 0; } /** * native MultiboardGetRowCount takes multiboard lb returns integer */ function MultiboardGetRowCount(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('MultiboardGetRowCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native MultiboardGetColumnCount takes multiboard lb returns integer */ function MultiboardGetColumnCount(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); console.warn('MultiboardGetColumnCount was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native MultiboardSetColumnCount takes multiboard lb, integer count returns nothing */ function MultiboardSetColumnCount(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _count = luaL_checkinteger(L, 2); console.warn('MultiboardSetColumnCount was called but is not implemented :('); return 0; } /** * native MultiboardSetRowCount takes multiboard lb, integer count returns nothing */ function MultiboardSetRowCount(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _count = luaL_checkinteger(L, 2); console.warn('MultiboardSetRowCount was called but is not implemented :('); return 0; } /** * native MultiboardSetItemsStyle takes multiboard lb, boolean showValues, boolean showIcons returns nothing */ function MultiboardSetItemsStyle(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _showValues = lua_toboolean(L, 2); const _showIcons = lua_toboolean(L, 3); console.warn('MultiboardSetItemsStyle was called but is not implemented :('); return 0; } /** * native MultiboardSetItemsValue takes multiboard lb, string value returns nothing */ function MultiboardSetItemsValue(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _value = luaL_checkstring(L, 2); console.warn('MultiboardSetItemsValue was called but is not implemented :('); return 0; } /** * native MultiboardSetItemsValueColor takes multiboard lb, integer red, integer green, integer blue, integer alpha returns nothing */ function MultiboardSetItemsValueColor(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('MultiboardSetItemsValueColor was called but is not implemented :('); return 0; } /** * native MultiboardSetItemsWidth takes multiboard lb, real width returns nothing */ function MultiboardSetItemsWidth(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _width = luaL_checknumber(L, 2); console.warn('MultiboardSetItemsWidth was called but is not implemented :('); return 0; } /** * native MultiboardSetItemsIcon takes multiboard lb, string iconPath returns nothing */ function MultiboardSetItemsIcon(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _iconPath = luaL_checkstring(L, 2); console.warn('MultiboardSetItemsIcon was called but is not implemented :('); return 0; } /** * native MultiboardGetItem takes multiboard lb, integer row, integer column returns multiboarditem */ function MultiboardGetItem(C: Context, L: lua_State): number { const _lb = lua_touserdata(L, 1); const _row = luaL_checkinteger(L, 2); const _column = luaL_checkinteger(L, 3); console.warn('MultiboardGetItem was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native MultiboardReleaseItem takes multiboarditem mbi returns nothing */ function MultiboardReleaseItem(C: Context, L: lua_State): number { const _mbi = lua_touserdata(L, 1); console.warn('MultiboardReleaseItem was called but is not implemented :('); return 0; } /** * native MultiboardSetItemStyle takes multiboarditem mbi, boolean showValue, boolean showIcon returns nothing */ function MultiboardSetItemStyle(C: Context, L: lua_State): number { const _mbi = lua_touserdata(L, 1); const _showValue = lua_toboolean(L, 2); const _showIcon = lua_toboolean(L, 3); console.warn('MultiboardSetItemStyle was called but is not implemented :('); return 0; } /** * native MultiboardSetItemValue takes multiboarditem mbi, string val returns nothing */ function MultiboardSetItemValue(C: Context, L: lua_State): number { const _mbi = lua_touserdata(L, 1); const _val = luaL_checkstring(L, 2); console.warn('MultiboardSetItemValue was called but is not implemented :('); return 0; } /** * native MultiboardSetItemValueColor takes multiboarditem mbi, integer red, integer green, integer blue, integer alpha returns nothing */ function MultiboardSetItemValueColor(C: Context, L: lua_State): number { const _mbi = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('MultiboardSetItemValueColor was called but is not implemented :('); return 0; } /** * native MultiboardSetItemWidth takes multiboarditem mbi, real width returns nothing */ function MultiboardSetItemWidth(C: Context, L: lua_State): number { const _mbi = lua_touserdata(L, 1); const _width = luaL_checknumber(L, 2); console.warn('MultiboardSetItemWidth was called but is not implemented :('); return 0; } /** * native MultiboardSetItemIcon takes multiboarditem mbi, string iconFileName returns nothing */ function MultiboardSetItemIcon(C: Context, L: lua_State): number { const _mbi = lua_touserdata(L, 1); const _iconFileName = luaL_checkstring(L, 2); console.warn('MultiboardSetItemIcon was called but is not implemented :('); return 0; } /** * native MultiboardSuppressDisplay takes boolean flag returns nothing */ function MultiboardSuppressDisplay(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); console.warn('MultiboardSuppressDisplay was called but is not implemented :('); return 0; } /** * native SetCameraPosition takes real x, real y returns nothing */ function SetCameraPosition(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('SetCameraPosition was called but is not implemented :('); return 0; } /** * native SetCameraQuickPosition takes real x, real y returns nothing */ function SetCameraQuickPosition(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('SetCameraQuickPosition was called but is not implemented :('); return 0; } /** * native SetCameraBounds takes real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4 returns nothing */ function SetCameraBounds(C: Context, L: lua_State): number { const _x1 = luaL_checknumber(L, 1); const _y1 = luaL_checknumber(L, 2); const _x2 = luaL_checknumber(L, 3); const _y2 = luaL_checknumber(L, 4); const _x3 = luaL_checknumber(L, 5); const _y3 = luaL_checknumber(L, 6); const _x4 = luaL_checknumber(L, 7); const _y4 = luaL_checknumber(L, 8); console.warn('SetCameraBounds was called but is not implemented :('); return 0; } /** * native StopCamera takes nothing returns nothing */ function StopCamera(_C: Context, _L: lua_State): number { console.warn('StopCamera was called but is not implemented :('); return 0; } /** * native ResetToGameCamera takes real duration returns nothing */ function ResetToGameCamera(C: Context, L: lua_State): number { const _duration = luaL_checknumber(L, 1); console.warn('ResetToGameCamera was called but is not implemented :('); return 0; } /** * native PanCameraTo takes real x, real y returns nothing */ function PanCameraTo(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('PanCameraTo was called but is not implemented :('); return 0; } /** * native PanCameraToTimed takes real x, real y, real duration returns nothing */ function PanCameraToTimed(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _duration = luaL_checknumber(L, 3); console.warn('PanCameraToTimed was called but is not implemented :('); return 0; } /** * native PanCameraToWithZ takes real x, real y, real zOffsetDest returns nothing */ function PanCameraToWithZ(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _zOffsetDest = luaL_checknumber(L, 3); console.warn('PanCameraToWithZ was called but is not implemented :('); return 0; } /** * native PanCameraToTimedWithZ takes real x, real y, real zOffsetDest, real duration returns nothing */ function PanCameraToTimedWithZ(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _zOffsetDest = luaL_checknumber(L, 3); const _duration = luaL_checknumber(L, 4); console.warn('PanCameraToTimedWithZ was called but is not implemented :('); return 0; } /** * native SetCinematicCamera takes string cameraModelFile returns nothing */ function SetCinematicCamera(C: Context, L: lua_State): number { const _cameraModelFile = luaL_checkstring(L, 1); console.warn('SetCinematicCamera was called but is not implemented :('); return 0; } /** * native SetCameraRotateMode takes real x, real y, real radiansToSweep, real duration returns nothing */ function SetCameraRotateMode(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _radiansToSweep = luaL_checknumber(L, 3); const _duration = luaL_checknumber(L, 4); console.warn('SetCameraRotateMode was called but is not implemented :('); return 0; } /** * native SetCameraField takes camerafield whichField, real value, real duration returns nothing */ function SetCameraField(C: Context, L: lua_State): number { const _whichField = lua_touserdata(L, 1); const _value = luaL_checknumber(L, 2); const _duration = luaL_checknumber(L, 3); console.warn('SetCameraField was called but is not implemented :('); return 0; } /** * native AdjustCameraField takes camerafield whichField, real offset, real duration returns nothing */ function AdjustCameraField(C: Context, L: lua_State): number { const _whichField = lua_touserdata(L, 1); const _offset = luaL_checknumber(L, 2); const _duration = luaL_checknumber(L, 3); console.warn('AdjustCameraField was called but is not implemented :('); return 0; } /** * native SetCameraTargetController takes unit whichUnit, real xoffset, real yoffset, boolean inheritOrientation returns nothing */ function SetCameraTargetController(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _xoffset = luaL_checknumber(L, 2); const _yoffset = luaL_checknumber(L, 3); const _inheritOrientation = lua_toboolean(L, 4); console.warn('SetCameraTargetController was called but is not implemented :('); return 0; } /** * native SetCameraOrientController takes unit whichUnit, real xoffset, real yoffset returns nothing */ function SetCameraOrientController(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _xoffset = luaL_checknumber(L, 2); const _yoffset = luaL_checknumber(L, 3); console.warn('SetCameraOrientController was called but is not implemented :('); return 0; } /** * native CreateCameraSetup takes nothing returns camerasetup */ function CreateCameraSetup(C: Context, L: lua_State): number { console.warn('CreateCameraSetup was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CameraSetupSetField takes camerasetup whichSetup, camerafield whichField, real value, real duration returns nothing */ function CameraSetupSetField(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _whichField = lua_touserdata(L, 2); const _value = luaL_checknumber(L, 3); const _duration = luaL_checknumber(L, 4); console.warn('CameraSetupSetField was called but is not implemented :('); return 0; } /** * native CameraSetupGetField takes camerasetup whichSetup, camerafield whichField returns real */ function CameraSetupGetField(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _whichField = lua_touserdata(L, 2); console.warn('CameraSetupGetField was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native CameraSetupSetDestPosition takes camerasetup whichSetup, real x, real y, real duration returns nothing */ function CameraSetupSetDestPosition(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _duration = luaL_checknumber(L, 4); console.warn('CameraSetupSetDestPosition was called but is not implemented :('); return 0; } /** * native CameraSetupGetDestPositionLoc takes camerasetup whichSetup returns location */ function CameraSetupGetDestPositionLoc(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); console.warn('CameraSetupGetDestPositionLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CameraSetupGetDestPositionX takes camerasetup whichSetup returns real */ function CameraSetupGetDestPositionX(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); console.warn('CameraSetupGetDestPositionX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native CameraSetupGetDestPositionY takes camerasetup whichSetup returns real */ function CameraSetupGetDestPositionY(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); console.warn('CameraSetupGetDestPositionY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native CameraSetupApply takes camerasetup whichSetup, boolean doPan, boolean panTimed returns nothing */ function CameraSetupApply(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _doPan = lua_toboolean(L, 2); const _panTimed = lua_toboolean(L, 3); console.warn('CameraSetupApply was called but is not implemented :('); return 0; } /** * native CameraSetupApplyWithZ takes camerasetup whichSetup, real zDestOffset returns nothing */ function CameraSetupApplyWithZ(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _zDestOffset = luaL_checknumber(L, 2); console.warn('CameraSetupApplyWithZ was called but is not implemented :('); return 0; } /** * native CameraSetupApplyForceDuration takes camerasetup whichSetup, boolean doPan, real forceDuration returns nothing */ function CameraSetupApplyForceDuration(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _doPan = lua_toboolean(L, 2); const _forceDuration = luaL_checknumber(L, 3); console.warn('CameraSetupApplyForceDuration was called but is not implemented :('); return 0; } /** * native CameraSetupApplyForceDurationWithZ takes camerasetup whichSetup, real zDestOffset, real forceDuration returns nothing */ function CameraSetupApplyForceDurationWithZ(C: Context, L: lua_State): number { const _whichSetup = lua_touserdata(L, 1); const _zDestOffset = luaL_checknumber(L, 2); const _forceDuration = luaL_checknumber(L, 3); console.warn('CameraSetupApplyForceDurationWithZ was called but is not implemented :('); return 0; } /** * native CameraSetTargetNoise takes real mag, real velocity returns nothing */ function CameraSetTargetNoise(C: Context, L: lua_State): number { const _mag = luaL_checknumber(L, 1); const _velocity = luaL_checknumber(L, 2); console.warn('CameraSetTargetNoise was called but is not implemented :('); return 0; } /** * native CameraSetSourceNoise takes real mag, real velocity returns nothing */ function CameraSetSourceNoise(C: Context, L: lua_State): number { const _mag = luaL_checknumber(L, 1); const _velocity = luaL_checknumber(L, 2); console.warn('CameraSetSourceNoise was called but is not implemented :('); return 0; } /** * native CameraSetTargetNoiseEx takes real mag, real velocity, boolean vertOnly returns nothing */ function CameraSetTargetNoiseEx(C: Context, L: lua_State): number { const _mag = luaL_checknumber(L, 1); const _velocity = luaL_checknumber(L, 2); const _vertOnly = lua_toboolean(L, 3); console.warn('CameraSetTargetNoiseEx was called but is not implemented :('); return 0; } /** * native CameraSetSourceNoiseEx takes real mag, real velocity, boolean vertOnly returns nothing */ function CameraSetSourceNoiseEx(C: Context, L: lua_State): number { const _mag = luaL_checknumber(L, 1); const _velocity = luaL_checknumber(L, 2); const _vertOnly = lua_toboolean(L, 3); console.warn('CameraSetSourceNoiseEx was called but is not implemented :('); return 0; } /** * native CameraSetSmoothingFactor takes real factor returns nothing */ function CameraSetSmoothingFactor(C: Context, L: lua_State): number { const _factor = luaL_checknumber(L, 1); console.warn('CameraSetSmoothingFactor was called but is not implemented :('); return 0; } /** * native SetCineFilterTexture takes string filename returns nothing */ function SetCineFilterTexture(C: Context, L: lua_State): number { const _filename = luaL_checkstring(L, 1); console.warn('SetCineFilterTexture was called but is not implemented :('); return 0; } /** * native SetCineFilterBlendMode takes blendmode whichMode returns nothing */ function SetCineFilterBlendMode(C: Context, L: lua_State): number { const _whichMode = lua_touserdata(L, 1); console.warn('SetCineFilterBlendMode was called but is not implemented :('); return 0; } /** * native SetCineFilterTexMapFlags takes texmapflags whichFlags returns nothing */ function SetCineFilterTexMapFlags(C: Context, L: lua_State): number { const _whichFlags = lua_touserdata(L, 1); console.warn('SetCineFilterTexMapFlags was called but is not implemented :('); return 0; } /** * native SetCineFilterStartUV takes real minu, real minv, real maxu, real maxv returns nothing */ function SetCineFilterStartUV(C: Context, L: lua_State): number { const _minu = luaL_checknumber(L, 1); const _minv = luaL_checknumber(L, 2); const _maxu = luaL_checknumber(L, 3); const _maxv = luaL_checknumber(L, 4); console.warn('SetCineFilterStartUV was called but is not implemented :('); return 0; } /** * native SetCineFilterEndUV takes real minu, real minv, real maxu, real maxv returns nothing */ function SetCineFilterEndUV(C: Context, L: lua_State): number { const _minu = luaL_checknumber(L, 1); const _minv = luaL_checknumber(L, 2); const _maxu = luaL_checknumber(L, 3); const _maxv = luaL_checknumber(L, 4); console.warn('SetCineFilterEndUV was called but is not implemented :('); return 0; } /** * native SetCineFilterStartColor takes integer red, integer green, integer blue, integer alpha returns nothing */ function SetCineFilterStartColor(C: Context, L: lua_State): number { const _red = luaL_checkinteger(L, 1); const _green = luaL_checkinteger(L, 2); const _blue = luaL_checkinteger(L, 3); const _alpha = luaL_checkinteger(L, 4); console.warn('SetCineFilterStartColor was called but is not implemented :('); return 0; } /** * native SetCineFilterEndColor takes integer red, integer green, integer blue, integer alpha returns nothing */ function SetCineFilterEndColor(C: Context, L: lua_State): number { const _red = luaL_checkinteger(L, 1); const _green = luaL_checkinteger(L, 2); const _blue = luaL_checkinteger(L, 3); const _alpha = luaL_checkinteger(L, 4); console.warn('SetCineFilterEndColor was called but is not implemented :('); return 0; } /** * native SetCineFilterDuration takes real duration returns nothing */ function SetCineFilterDuration(C: Context, L: lua_State): number { const _duration = luaL_checknumber(L, 1); console.warn('SetCineFilterDuration was called but is not implemented :('); return 0; } /** * native DisplayCineFilter takes boolean flag returns nothing */ function DisplayCineFilter(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); console.warn('DisplayCineFilter was called but is not implemented :('); return 0; } /** * native IsCineFilterDisplayed takes nothing returns boolean */ function IsCineFilterDisplayed(C: Context, L: lua_State): number { console.warn('IsCineFilterDisplayed was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetCinematicScene takes integer portraitUnitId, playercolor color, string speakerTitle, string text, real sceneDuration, real voiceoverDuration returns nothing */ function SetCinematicScene(C: Context, L: lua_State): number { const _portraitUnitId = luaL_checkinteger(L, 1); const _color = lua_touserdata(L, 2); const _speakerTitle = luaL_checkstring(L, 3); const _text = luaL_checkstring(L, 4); const _sceneDuration = luaL_checknumber(L, 5); const _voiceoverDuration = luaL_checknumber(L, 6); console.warn('SetCinematicScene was called but is not implemented :('); return 0; } /** * native EndCinematicScene takes nothing returns nothing */ function EndCinematicScene(_C: Context, _L: lua_State): number { console.warn('EndCinematicScene was called but is not implemented :('); return 0; } /** * native ForceCinematicSubtitles takes boolean flag returns nothing */ function ForceCinematicSubtitles(C: Context, L: lua_State): number { const _flag = lua_toboolean(L, 1); console.warn('ForceCinematicSubtitles was called but is not implemented :('); return 0; } /** * native GetCameraMargin takes integer whichMargin returns real */ function GetCameraMargin(C: Context, L: lua_State): number { const _whichMargin = luaL_checkinteger(L, 1); console.warn('GetCameraMargin was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraBoundMinX takes nothing returns real */ function GetCameraBoundMinX(C: Context, L: lua_State): number { console.warn('GetCameraBoundMinX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraBoundMinY takes nothing returns real */ function GetCameraBoundMinY(C: Context, L: lua_State): number { console.warn('GetCameraBoundMinY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraBoundMaxX takes nothing returns real */ function GetCameraBoundMaxX(C: Context, L: lua_State): number { console.warn('GetCameraBoundMaxX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraBoundMaxY takes nothing returns real */ function GetCameraBoundMaxY(C: Context, L: lua_State): number { console.warn('GetCameraBoundMaxY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraField takes camerafield whichField returns real */ function GetCameraField(C: Context, L: lua_State): number { const _whichField = lua_touserdata(L, 1); console.warn('GetCameraField was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraTargetPositionX takes nothing returns real */ function GetCameraTargetPositionX(C: Context, L: lua_State): number { console.warn('GetCameraTargetPositionX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraTargetPositionY takes nothing returns real */ function GetCameraTargetPositionY(C: Context, L: lua_State): number { console.warn('GetCameraTargetPositionY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraTargetPositionZ takes nothing returns real */ function GetCameraTargetPositionZ(C: Context, L: lua_State): number { console.warn('GetCameraTargetPositionZ was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraTargetPositionLoc takes nothing returns location */ function GetCameraTargetPositionLoc(C: Context, L: lua_State): number { console.warn('GetCameraTargetPositionLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * constant native GetCameraEyePositionX takes nothing returns real */ function GetCameraEyePositionX(C: Context, L: lua_State): number { console.warn('GetCameraEyePositionX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraEyePositionY takes nothing returns real */ function GetCameraEyePositionY(C: Context, L: lua_State): number { console.warn('GetCameraEyePositionY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraEyePositionZ takes nothing returns real */ function GetCameraEyePositionZ(C: Context, L: lua_State): number { console.warn('GetCameraEyePositionZ was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * constant native GetCameraEyePositionLoc takes nothing returns location */ function GetCameraEyePositionLoc(C: Context, L: lua_State): number { console.warn('GetCameraEyePositionLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native NewSoundEnvironment takes string environmentName returns nothing */ function NewSoundEnvironment(C: Context, L: lua_State): number { const _environmentName = luaL_checkstring(L, 1); console.warn('NewSoundEnvironment was called but is not implemented :('); return 0; } /** * native CreateSound takes string fileName, boolean looping, boolean is3D, boolean stopwhenoutofrange, integer fadeInRate, integer fadeOutRate, string eaxSetting returns sound */ function CreateSound(C: Context, L: lua_State): number { const _fileName = luaL_checkstring(L, 1); const _looping = lua_toboolean(L, 2); const _is3D = lua_toboolean(L, 3); const _stopwhenoutofrange = lua_toboolean(L, 4); const _fadeInRate = luaL_checkinteger(L, 5); const _fadeOutRate = luaL_checkinteger(L, 6); const _eaxSetting = luaL_checkstring(L, 7); console.warn('CreateSound was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateSoundFilenameWithLabel takes string fileName, boolean looping, boolean is3D, boolean stopwhenoutofrange, integer fadeInRate, integer fadeOutRate, string SLKEntryName returns sound */ function CreateSoundFilenameWithLabel(C: Context, L: lua_State): number { const _fileName = luaL_checkstring(L, 1); const _looping = lua_toboolean(L, 2); const _is3D = lua_toboolean(L, 3); const _stopwhenoutofrange = lua_toboolean(L, 4); const _fadeInRate = luaL_checkinteger(L, 5); const _fadeOutRate = luaL_checkinteger(L, 6); const _SLKEntryName = luaL_checkstring(L, 7); console.warn('CreateSoundFilenameWithLabel was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateSoundFromLabel takes string soundLabel, boolean looping, boolean is3D, boolean stopwhenoutofrange, integer fadeInRate, integer fadeOutRate returns sound */ function CreateSoundFromLabel(C: Context, L: lua_State): number { const _soundLabel = luaL_checkstring(L, 1); const _looping = lua_toboolean(L, 2); const _is3D = lua_toboolean(L, 3); const _stopwhenoutofrange = lua_toboolean(L, 4); const _fadeInRate = luaL_checkinteger(L, 5); const _fadeOutRate = luaL_checkinteger(L, 6); console.warn('CreateSoundFromLabel was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native CreateMIDISound takes string soundLabel, integer fadeInRate, integer fadeOutRate returns sound */ function CreateMIDISound(C: Context, L: lua_State): number { const _soundLabel = luaL_checkstring(L, 1); const _fadeInRate = luaL_checkinteger(L, 2); const _fadeOutRate = luaL_checkinteger(L, 3); console.warn('CreateMIDISound was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native SetSoundParamsFromLabel takes sound soundHandle, string soundLabel returns nothing */ function SetSoundParamsFromLabel(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _soundLabel = luaL_checkstring(L, 2); console.warn('SetSoundParamsFromLabel was called but is not implemented :('); return 0; } /** * native SetSoundDistanceCutoff takes sound soundHandle, real cutoff returns nothing */ function SetSoundDistanceCutoff(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _cutoff = luaL_checknumber(L, 2); console.warn('SetSoundDistanceCutoff was called but is not implemented :('); return 0; } /** * native SetSoundChannel takes sound soundHandle, integer channel returns nothing */ function SetSoundChannel(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _channel = luaL_checkinteger(L, 2); console.warn('SetSoundChannel was called but is not implemented :('); return 0; } /** * native SetSoundVolume takes sound soundHandle, integer volume returns nothing */ function SetSoundVolume(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _volume = luaL_checkinteger(L, 2); console.warn('SetSoundVolume was called but is not implemented :('); return 0; } /** * native SetSoundPitch takes sound soundHandle, real pitch returns nothing */ function SetSoundPitch(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _pitch = luaL_checknumber(L, 2); console.warn('SetSoundPitch was called but is not implemented :('); return 0; } /** * native SetSoundPlayPosition takes sound soundHandle, integer millisecs returns nothing */ function SetSoundPlayPosition(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _millisecs = luaL_checkinteger(L, 2); console.warn('SetSoundPlayPosition was called but is not implemented :('); return 0; } /** * native SetSoundDistances takes sound soundHandle, real minDist, real maxDist returns nothing */ function SetSoundDistances(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _minDist = luaL_checknumber(L, 2); const _maxDist = luaL_checknumber(L, 3); console.warn('SetSoundDistances was called but is not implemented :('); return 0; } /** * native SetSoundConeAngles takes sound soundHandle, real inside, real outside, integer outsideVolume returns nothing */ function SetSoundConeAngles(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _inside = luaL_checknumber(L, 2); const _outside = luaL_checknumber(L, 3); const _outsideVolume = luaL_checkinteger(L, 4); console.warn('SetSoundConeAngles was called but is not implemented :('); return 0; } /** * native SetSoundConeOrientation takes sound soundHandle, real x, real y, real z returns nothing */ function SetSoundConeOrientation(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); console.warn('SetSoundConeOrientation was called but is not implemented :('); return 0; } /** * native SetSoundPosition takes sound soundHandle, real x, real y, real z returns nothing */ function SetSoundPosition(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); console.warn('SetSoundPosition was called but is not implemented :('); return 0; } /** * native SetSoundVelocity takes sound soundHandle, real x, real y, real z returns nothing */ function SetSoundVelocity(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); console.warn('SetSoundVelocity was called but is not implemented :('); return 0; } /** * native AttachSoundToUnit takes sound soundHandle, unit whichUnit returns nothing */ function AttachSoundToUnit(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _whichUnit = lua_touserdata(L, 2); console.warn('AttachSoundToUnit was called but is not implemented :('); return 0; } /** * native StartSound takes sound soundHandle returns nothing */ function StartSound(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); console.warn('StartSound was called but is not implemented :('); return 0; } /** * native StopSound takes sound soundHandle, boolean killWhenDone, boolean fadeOut returns nothing */ function StopSound(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _killWhenDone = lua_toboolean(L, 2); const _fadeOut = lua_toboolean(L, 3); console.warn('StopSound was called but is not implemented :('); return 0; } /** * native KillSoundWhenDone takes sound soundHandle returns nothing */ function KillSoundWhenDone(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); console.warn('KillSoundWhenDone was called but is not implemented :('); return 0; } /** * native SetMapMusic takes string musicName, boolean random, integer index returns nothing */ function SetMapMusic(C: Context, L: lua_State): number { const _musicName = luaL_checkstring(L, 1); const _random = lua_toboolean(L, 2); const _index = luaL_checkinteger(L, 3); console.warn('SetMapMusic was called but is not implemented :('); return 0; } /** * native ClearMapMusic takes nothing returns nothing */ function ClearMapMusic(_C: Context, _L: lua_State): number { console.warn('ClearMapMusic was called but is not implemented :('); return 0; } /** * native PlayMusic takes string musicName returns nothing */ function PlayMusic(C: Context, L: lua_State): number { const _musicName = luaL_checkstring(L, 1); console.warn('PlayMusic was called but is not implemented :('); return 0; } /** * native PlayMusicEx takes string musicName, integer frommsecs, integer fadeinmsecs returns nothing */ function PlayMusicEx(C: Context, L: lua_State): number { const _musicName = luaL_checkstring(L, 1); const _frommsecs = luaL_checkinteger(L, 2); const _fadeinmsecs = luaL_checkinteger(L, 3); console.warn('PlayMusicEx was called but is not implemented :('); return 0; } /** * native StopMusic takes boolean fadeOut returns nothing */ function StopMusic(C: Context, L: lua_State): number { const _fadeOut = lua_toboolean(L, 1); console.warn('StopMusic was called but is not implemented :('); return 0; } /** * native ResumeMusic takes nothing returns nothing */ function ResumeMusic(_C: Context, _L: lua_State): number { console.warn('ResumeMusic was called but is not implemented :('); return 0; } /** * native PlayThematicMusic takes string musicFileName returns nothing */ function PlayThematicMusic(C: Context, L: lua_State): number { const _musicFileName = luaL_checkstring(L, 1); console.warn('PlayThematicMusic was called but is not implemented :('); return 0; } /** * native PlayThematicMusicEx takes string musicFileName, integer frommsecs returns nothing */ function PlayThematicMusicEx(C: Context, L: lua_State): number { const _musicFileName = luaL_checkstring(L, 1); const _frommsecs = luaL_checkinteger(L, 2); console.warn('PlayThematicMusicEx was called but is not implemented :('); return 0; } /** * native EndThematicMusic takes nothing returns nothing */ function EndThematicMusic(_C: Context, _L: lua_State): number { console.warn('EndThematicMusic was called but is not implemented :('); return 0; } /** * native SetMusicVolume takes integer volume returns nothing */ function SetMusicVolume(C: Context, L: lua_State): number { const _volume = luaL_checkinteger(L, 1); console.warn('SetMusicVolume was called but is not implemented :('); return 0; } /** * native SetMusicPlayPosition takes integer millisecs returns nothing */ function SetMusicPlayPosition(C: Context, L: lua_State): number { const _millisecs = luaL_checkinteger(L, 1); console.warn('SetMusicPlayPosition was called but is not implemented :('); return 0; } /** * native SetThematicMusicPlayPosition takes integer millisecs returns nothing */ function SetThematicMusicPlayPosition(C: Context, L: lua_State): number { const _millisecs = luaL_checkinteger(L, 1); console.warn('SetThematicMusicPlayPosition was called but is not implemented :('); return 0; } /** * native SetSoundDuration takes sound soundHandle, integer duration returns nothing */ function SetSoundDuration(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _duration = luaL_checkinteger(L, 2); console.warn('SetSoundDuration was called but is not implemented :('); return 0; } /** * native GetSoundDuration takes sound soundHandle returns integer */ function GetSoundDuration(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); console.warn('GetSoundDuration was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetSoundFileDuration takes string musicFileName returns integer */ function GetSoundFileDuration(C: Context, L: lua_State): number { const _musicFileName = luaL_checkstring(L, 1); console.warn('GetSoundFileDuration was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native VolumeGroupSetVolume takes volumegroup vgroup, real scale returns nothing */ function VolumeGroupSetVolume(C: Context, L: lua_State): number { const _vgroup = lua_touserdata(L, 1); const _scale = luaL_checknumber(L, 2); console.warn('VolumeGroupSetVolume was called but is not implemented :('); return 0; } /** * native VolumeGroupReset takes nothing returns nothing */ function VolumeGroupReset(_C: Context, _L: lua_State): number { console.warn('VolumeGroupReset was called but is not implemented :('); return 0; } /** * native GetSoundIsPlaying takes sound soundHandle returns boolean */ function GetSoundIsPlaying(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); console.warn('GetSoundIsPlaying was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetSoundIsLoading takes sound soundHandle returns boolean */ function GetSoundIsLoading(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); console.warn('GetSoundIsLoading was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native RegisterStackedSound takes sound soundHandle, boolean byPosition, real rectwidth, real rectheight returns nothing */ function RegisterStackedSound(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _byPosition = lua_toboolean(L, 2); const _rectwidth = luaL_checknumber(L, 3); const _rectheight = luaL_checknumber(L, 4); console.warn('RegisterStackedSound was called but is not implemented :('); return 0; } /** * native UnregisterStackedSound takes sound soundHandle, boolean byPosition, real rectwidth, real rectheight returns nothing */ function UnregisterStackedSound(C: Context, L: lua_State): number { const _soundHandle = lua_touserdata(L, 1); const _byPosition = lua_toboolean(L, 2); const _rectwidth = luaL_checknumber(L, 3); const _rectheight = luaL_checknumber(L, 4); console.warn('UnregisterStackedSound was called but is not implemented :('); return 0; } /** * native AddWeatherEffect takes rect where, integer effectID returns weathereffect */ function AddWeatherEffect(C: Context, L: lua_State): number { const _where = lua_touserdata(L, 1); const _effectID = luaL_checkinteger(L, 2); console.warn('AddWeatherEffect was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveWeatherEffect takes weathereffect whichEffect returns nothing */ function RemoveWeatherEffect(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); console.warn('RemoveWeatherEffect was called but is not implemented :('); return 0; } /** * native EnableWeatherEffect takes weathereffect whichEffect, boolean enable returns nothing */ function EnableWeatherEffect(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _enable = lua_toboolean(L, 2); console.warn('EnableWeatherEffect was called but is not implemented :('); return 0; } /** * native TerrainDeformCrater takes real x, real y, real radius, real depth, integer duration, boolean permanent returns terraindeformation */ function TerrainDeformCrater(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _radius = luaL_checknumber(L, 3); const _depth = luaL_checknumber(L, 4); const _duration = luaL_checkinteger(L, 5); const _permanent = lua_toboolean(L, 6); console.warn('TerrainDeformCrater was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TerrainDeformRipple takes real x, real y, real radius, real depth, integer duration, integer count, real spaceWaves, real timeWaves, real radiusStartPct, boolean limitNeg returns terraindeformation */ function TerrainDeformRipple(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _radius = luaL_checknumber(L, 3); const _depth = luaL_checknumber(L, 4); const _duration = luaL_checkinteger(L, 5); const _count = luaL_checkinteger(L, 6); const _spaceWaves = luaL_checknumber(L, 7); const _timeWaves = luaL_checknumber(L, 8); const _radiusStartPct = luaL_checknumber(L, 9); const _limitNeg = lua_toboolean(L, 10); console.warn('TerrainDeformRipple was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TerrainDeformWave takes real x, real y, real dirX, real dirY, real distance, real speed, real radius, real depth, integer trailTime, integer count returns terraindeformation */ function TerrainDeformWave(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _dirX = luaL_checknumber(L, 3); const _dirY = luaL_checknumber(L, 4); const _distance = luaL_checknumber(L, 5); const _speed = luaL_checknumber(L, 6); const _radius = luaL_checknumber(L, 7); const _depth = luaL_checknumber(L, 8); const _trailTime = luaL_checkinteger(L, 9); const _count = luaL_checkinteger(L, 10); console.warn('TerrainDeformWave was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TerrainDeformRandom takes real x, real y, real radius, real minDelta, real maxDelta, integer duration, integer updateInterval returns terraindeformation */ function TerrainDeformRandom(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _radius = luaL_checknumber(L, 3); const _minDelta = luaL_checknumber(L, 4); const _maxDelta = luaL_checknumber(L, 5); const _duration = luaL_checkinteger(L, 6); const _updateInterval = luaL_checkinteger(L, 7); console.warn('TerrainDeformRandom was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native TerrainDeformStop takes terraindeformation deformation, integer duration returns nothing */ function TerrainDeformStop(C: Context, L: lua_State): number { const _deformation = lua_touserdata(L, 1); const _duration = luaL_checkinteger(L, 2); console.warn('TerrainDeformStop was called but is not implemented :('); return 0; } /** * native TerrainDeformStopAll takes nothing returns nothing */ function TerrainDeformStopAll(_C: Context, _L: lua_State): number { console.warn('TerrainDeformStopAll was called but is not implemented :('); return 0; } /** * native AddSpecialEffect takes string modelName, real x, real y returns effect */ function AddSpecialEffect(C: Context, L: lua_State): number { const _modelName = luaL_checkstring(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); console.warn('AddSpecialEffect was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpecialEffectLoc takes string modelName, location where returns effect */ function AddSpecialEffectLoc(C: Context, L: lua_State): number { const _modelName = luaL_checkstring(L, 1); const _where = lua_touserdata(L, 2); console.warn('AddSpecialEffectLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpecialEffectTarget takes string modelName, widget targetWidget, string attachPointName returns effect */ function AddSpecialEffectTarget(C: Context, L: lua_State): number { const _modelName = luaL_checkstring(L, 1); const _targetWidget = lua_touserdata(L, 2); const _attachPointName = luaL_checkstring(L, 3); console.warn('AddSpecialEffectTarget was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyEffect takes effect whichEffect returns nothing */ function DestroyEffect(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); console.warn('DestroyEffect was called but is not implemented :('); return 0; } /** * native AddSpellEffect takes string abilityString, effecttype t, real x, real y returns effect */ function AddSpellEffect(C: Context, L: lua_State): number { const _abilityString = luaL_checkstring(L, 1); const _t = lua_touserdata(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('AddSpellEffect was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpellEffectLoc takes string abilityString, effecttype t, location where returns effect */ function AddSpellEffectLoc(C: Context, L: lua_State): number { const _abilityString = luaL_checkstring(L, 1); const _t = lua_touserdata(L, 2); const _where = lua_touserdata(L, 3); console.warn('AddSpellEffectLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpellEffectById takes integer abilityId, effecttype t, real x, real y returns effect */ function AddSpellEffectById(C: Context, L: lua_State): number { const _abilityId = luaL_checkinteger(L, 1); const _t = lua_touserdata(L, 2); const _x = luaL_checknumber(L, 3); const _y = luaL_checknumber(L, 4); console.warn('AddSpellEffectById was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpellEffectByIdLoc takes integer abilityId, effecttype t, location where returns effect */ function AddSpellEffectByIdLoc(C: Context, L: lua_State): number { const _abilityId = luaL_checkinteger(L, 1); const _t = lua_touserdata(L, 2); const _where = lua_touserdata(L, 3); console.warn('AddSpellEffectByIdLoc was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpellEffectTarget takes string modelName, effecttype t, widget targetWidget, string attachPoint returns effect */ function AddSpellEffectTarget(C: Context, L: lua_State): number { const _modelName = luaL_checkstring(L, 1); const _t = lua_touserdata(L, 2); const _targetWidget = lua_touserdata(L, 3); const _attachPoint = luaL_checkstring(L, 4); console.warn('AddSpellEffectTarget was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddSpellEffectTargetById takes integer abilityId, effecttype t, widget targetWidget, string attachPoint returns effect */ function AddSpellEffectTargetById(C: Context, L: lua_State): number { const _abilityId = luaL_checkinteger(L, 1); const _t = lua_touserdata(L, 2); const _targetWidget = lua_touserdata(L, 3); const _attachPoint = luaL_checkstring(L, 4); console.warn('AddSpellEffectTargetById was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddLightning takes string codeName, boolean checkVisibility, real x1, real y1, real x2, real y2 returns lightning */ function AddLightning(C: Context, L: lua_State): number { const _codeName = luaL_checkstring(L, 1); const _checkVisibility = lua_toboolean(L, 2); const _x1 = luaL_checknumber(L, 3); const _y1 = luaL_checknumber(L, 4); const _x2 = luaL_checknumber(L, 5); const _y2 = luaL_checknumber(L, 6); console.warn('AddLightning was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native AddLightningEx takes string codeName, boolean checkVisibility, real x1, real y1, real z1, real x2, real y2, real z2 returns lightning */ function AddLightningEx(C: Context, L: lua_State): number { const _codeName = luaL_checkstring(L, 1); const _checkVisibility = lua_toboolean(L, 2); const _x1 = luaL_checknumber(L, 3); const _y1 = luaL_checknumber(L, 4); const _z1 = luaL_checknumber(L, 5); const _x2 = luaL_checknumber(L, 6); const _y2 = luaL_checknumber(L, 7); const _z2 = luaL_checknumber(L, 8); console.warn('AddLightningEx was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyLightning takes lightning whichBolt returns boolean */ function DestroyLightning(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); console.warn('DestroyLightning was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native MoveLightning takes lightning whichBolt, boolean checkVisibility, real x1, real y1, real x2, real y2 returns boolean */ function MoveLightning(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); const _checkVisibility = lua_toboolean(L, 2); const _x1 = luaL_checknumber(L, 3); const _y1 = luaL_checknumber(L, 4); const _x2 = luaL_checknumber(L, 5); const _y2 = luaL_checknumber(L, 6); console.warn('MoveLightning was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native MoveLightningEx takes lightning whichBolt, boolean checkVisibility, real x1, real y1, real z1, real x2, real y2, real z2 returns boolean */ function MoveLightningEx(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); const _checkVisibility = lua_toboolean(L, 2); const _x1 = luaL_checknumber(L, 3); const _y1 = luaL_checknumber(L, 4); const _z1 = luaL_checknumber(L, 5); const _x2 = luaL_checknumber(L, 6); const _y2 = luaL_checknumber(L, 7); const _z2 = luaL_checknumber(L, 8); console.warn('MoveLightningEx was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetLightningColorA takes lightning whichBolt returns real */ function GetLightningColorA(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); console.warn('GetLightningColorA was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetLightningColorR takes lightning whichBolt returns real */ function GetLightningColorR(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); console.warn('GetLightningColorR was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetLightningColorG takes lightning whichBolt returns real */ function GetLightningColorG(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); console.warn('GetLightningColorG was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native GetLightningColorB takes lightning whichBolt returns real */ function GetLightningColorB(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); console.warn('GetLightningColorB was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native SetLightningColor takes lightning whichBolt, real r, real g, real b, real a returns boolean */ function SetLightningColor(C: Context, L: lua_State): number { const _whichBolt = lua_touserdata(L, 1); const _r = luaL_checknumber(L, 2); const _g = luaL_checknumber(L, 3); const _b = luaL_checknumber(L, 4); const _a = luaL_checknumber(L, 5); console.warn('SetLightningColor was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native GetAbilityEffect takes string abilityString, effecttype t, integer index returns string */ function GetAbilityEffect(C: Context, L: lua_State): number { const _abilityString = luaL_checkstring(L, 1); const _t = lua_touserdata(L, 2); const _index = luaL_checkinteger(L, 3); console.warn('GetAbilityEffect was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native GetAbilityEffectById takes integer abilityId, effecttype t, integer index returns string */ function GetAbilityEffectById(C: Context, L: lua_State): number { const _abilityId = luaL_checkinteger(L, 1); const _t = lua_touserdata(L, 2); const _index = luaL_checkinteger(L, 3); console.warn('GetAbilityEffectById was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native GetAbilitySound takes string abilityString, soundtype t returns string */ function GetAbilitySound(C: Context, L: lua_State): number { const _abilityString = luaL_checkstring(L, 1); const _t = lua_touserdata(L, 2); console.warn('GetAbilitySound was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native GetAbilitySoundById takes integer abilityId, soundtype t returns string */ function GetAbilitySoundById(C: Context, L: lua_State): number { const _abilityId = luaL_checkinteger(L, 1); const _t = lua_touserdata(L, 2); console.warn('GetAbilitySoundById was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native GetTerrainCliffLevel takes real x, real y returns integer */ function GetTerrainCliffLevel(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('GetTerrainCliffLevel was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetWaterBaseColor takes integer red, integer green, integer blue, integer alpha returns nothing */ function SetWaterBaseColor(C: Context, L: lua_State): number { const _red = luaL_checkinteger(L, 1); const _green = luaL_checkinteger(L, 2); const _blue = luaL_checkinteger(L, 3); const _alpha = luaL_checkinteger(L, 4); console.warn('SetWaterBaseColor was called but is not implemented :('); return 0; } /** * native SetWaterDeforms takes boolean val returns nothing */ function SetWaterDeforms(C: Context, L: lua_State): number { const _val = lua_toboolean(L, 1); console.warn('SetWaterDeforms was called but is not implemented :('); return 0; } /** * native GetTerrainType takes real x, real y returns integer */ function GetTerrainType(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('GetTerrainType was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native GetTerrainVariance takes real x, real y returns integer */ function GetTerrainVariance(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('GetTerrainVariance was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native SetTerrainType takes real x, real y, integer terrainType, integer variation, integer area, integer shape returns nothing */ function SetTerrainType(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _terrainType = luaL_checkinteger(L, 3); const _variation = luaL_checkinteger(L, 4); const _area = luaL_checkinteger(L, 5); const _shape = luaL_checkinteger(L, 6); console.warn('SetTerrainType was called but is not implemented :('); return 0; } /** * native IsTerrainPathable takes real x, real y, pathingtype t returns boolean */ function IsTerrainPathable(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _t = lua_touserdata(L, 3); console.warn('IsTerrainPathable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetTerrainPathable takes real x, real y, pathingtype t, boolean flag returns nothing */ function SetTerrainPathable(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _t = lua_touserdata(L, 3); const _flag = lua_toboolean(L, 4); console.warn('SetTerrainPathable was called but is not implemented :('); return 0; } /** * native CreateImage takes string file, real sizeX, real sizeY, real sizeZ, real posX, real posY, real posZ, real originX, real originY, real originZ, integer imageType returns image */ function CreateImage(C: Context, L: lua_State): number { const _file = luaL_checkstring(L, 1); const _sizeX = luaL_checknumber(L, 2); const _sizeY = luaL_checknumber(L, 3); const _sizeZ = luaL_checknumber(L, 4); const _posX = luaL_checknumber(L, 5); const _posY = luaL_checknumber(L, 6); const _posZ = luaL_checknumber(L, 7); const _originX = luaL_checknumber(L, 8); const _originY = luaL_checknumber(L, 9); const _originZ = luaL_checknumber(L, 10); const _imageType = luaL_checkinteger(L, 11); console.warn('CreateImage was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyImage takes image whichImage returns nothing */ function DestroyImage(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); console.warn('DestroyImage was called but is not implemented :('); return 0; } /** * native ShowImage takes image whichImage, boolean flag returns nothing */ function ShowImage(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('ShowImage was called but is not implemented :('); return 0; } /** * native SetImageConstantHeight takes image whichImage, boolean flag, real height returns nothing */ function SetImageConstantHeight(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); const _height = luaL_checknumber(L, 3); console.warn('SetImageConstantHeight was called but is not implemented :('); return 0; } /** * native SetImagePosition takes image whichImage, real x, real y, real z returns nothing */ function SetImagePosition(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); console.warn('SetImagePosition was called but is not implemented :('); return 0; } /** * native SetImageColor takes image whichImage, integer red, integer green, integer blue, integer alpha returns nothing */ function SetImageColor(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _red = luaL_checkinteger(L, 2); const _green = luaL_checkinteger(L, 3); const _blue = luaL_checkinteger(L, 4); const _alpha = luaL_checkinteger(L, 5); console.warn('SetImageColor was called but is not implemented :('); return 0; } /** * native SetImageRender takes image whichImage, boolean flag returns nothing */ function SetImageRender(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetImageRender was called but is not implemented :('); return 0; } /** * native SetImageRenderAlways takes image whichImage, boolean flag returns nothing */ function SetImageRenderAlways(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetImageRenderAlways was called but is not implemented :('); return 0; } /** * native SetImageAboveWater takes image whichImage, boolean flag, boolean useWaterAlpha returns nothing */ function SetImageAboveWater(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); const _useWaterAlpha = lua_toboolean(L, 3); console.warn('SetImageAboveWater was called but is not implemented :('); return 0; } /** * native SetImageType takes image whichImage, integer imageType returns nothing */ function SetImageType(C: Context, L: lua_State): number { const _whichImage = lua_touserdata(L, 1); const _imageType = luaL_checkinteger(L, 2); console.warn('SetImageType was called but is not implemented :('); return 0; } /** * native CreateUbersplat takes real x, real y, string name, integer red, integer green, integer blue, integer alpha, boolean forcePaused, boolean noBirthTime returns ubersplat */ function CreateUbersplat(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _name = luaL_checkstring(L, 3); const _red = luaL_checkinteger(L, 4); const _green = luaL_checkinteger(L, 5); const _blue = luaL_checkinteger(L, 6); const _alpha = luaL_checkinteger(L, 7); const _forcePaused = lua_toboolean(L, 8); const _noBirthTime = lua_toboolean(L, 9); console.warn('CreateUbersplat was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native DestroyUbersplat takes ubersplat whichSplat returns nothing */ function DestroyUbersplat(C: Context, L: lua_State): number { const _whichSplat = lua_touserdata(L, 1); console.warn('DestroyUbersplat was called but is not implemented :('); return 0; } /** * native ResetUbersplat takes ubersplat whichSplat returns nothing */ function ResetUbersplat(C: Context, L: lua_State): number { const _whichSplat = lua_touserdata(L, 1); console.warn('ResetUbersplat was called but is not implemented :('); return 0; } /** * native FinishUbersplat takes ubersplat whichSplat returns nothing */ function FinishUbersplat(C: Context, L: lua_State): number { const _whichSplat = lua_touserdata(L, 1); console.warn('FinishUbersplat was called but is not implemented :('); return 0; } /** * native ShowUbersplat takes ubersplat whichSplat, boolean flag returns nothing */ function ShowUbersplat(C: Context, L: lua_State): number { const _whichSplat = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('ShowUbersplat was called but is not implemented :('); return 0; } /** * native SetUbersplatRender takes ubersplat whichSplat, boolean flag returns nothing */ function SetUbersplatRender(C: Context, L: lua_State): number { const _whichSplat = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetUbersplatRender was called but is not implemented :('); return 0; } /** * native SetUbersplatRenderAlways takes ubersplat whichSplat, boolean flag returns nothing */ function SetUbersplatRenderAlways(C: Context, L: lua_State): number { const _whichSplat = lua_touserdata(L, 1); const _flag = lua_toboolean(L, 2); console.warn('SetUbersplatRenderAlways was called but is not implemented :('); return 0; } /** * native SetBlight takes player whichPlayer, real x, real y, real radius, boolean addBlight returns nothing */ function SetBlight(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _radius = luaL_checknumber(L, 4); const _addBlight = lua_toboolean(L, 5); console.warn('SetBlight was called but is not implemented :('); return 0; } /** * native SetBlightRect takes player whichPlayer, rect r, boolean addBlight returns nothing */ function SetBlightRect(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _r = lua_touserdata(L, 2); const _addBlight = lua_toboolean(L, 3); console.warn('SetBlightRect was called but is not implemented :('); return 0; } /** * native SetBlightPoint takes player whichPlayer, real x, real y, boolean addBlight returns nothing */ function SetBlightPoint(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _addBlight = lua_toboolean(L, 4); console.warn('SetBlightPoint was called but is not implemented :('); return 0; } /** * native SetBlightLoc takes player whichPlayer, location whichLocation, real radius, boolean addBlight returns nothing */ function SetBlightLoc(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _whichLocation = lua_touserdata(L, 2); const _radius = luaL_checknumber(L, 3); const _addBlight = lua_toboolean(L, 4); console.warn('SetBlightLoc was called but is not implemented :('); return 0; } /** * native CreateBlightedGoldmine takes player id, real x, real y, real face returns unit */ function CreateBlightedGoldmine(C: Context, L: lua_State): number { const _id = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _face = luaL_checknumber(L, 4); console.warn('CreateBlightedGoldmine was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native IsPointBlighted takes real x, real y returns boolean */ function IsPointBlighted(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); console.warn('IsPointBlighted was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native SetDoodadAnimation takes real x, real y, real radius, integer doodadID, boolean nearestOnly, string animName, boolean animRandom returns nothing */ function SetDoodadAnimation(C: Context, L: lua_State): number { const _x = luaL_checknumber(L, 1); const _y = luaL_checknumber(L, 2); const _radius = luaL_checknumber(L, 3); const _doodadID = luaL_checkinteger(L, 4); const _nearestOnly = lua_toboolean(L, 5); const _animName = luaL_checkstring(L, 6); const _animRandom = lua_toboolean(L, 7); console.warn('SetDoodadAnimation was called but is not implemented :('); return 0; } /** * native SetDoodadAnimationRect takes rect r, integer doodadID, string animName, boolean animRandom returns nothing */ function SetDoodadAnimationRect(C: Context, L: lua_State): number { const _r = lua_touserdata(L, 1); const _doodadID = luaL_checkinteger(L, 2); const _animName = luaL_checkstring(L, 3); const _animRandom = lua_toboolean(L, 4); console.warn('SetDoodadAnimationRect was called but is not implemented :('); return 0; } /** * native StartMeleeAI takes player num, string script returns nothing */ function StartMeleeAI(C: Context, L: lua_State): number { const _num = lua_touserdata(L, 1); const _script = luaL_checkstring(L, 2); console.warn('StartMeleeAI was called but is not implemented :('); return 0; } /** * native StartCampaignAI takes player num, string script returns nothing */ function StartCampaignAI(C: Context, L: lua_State): number { const _num = lua_touserdata(L, 1); const _script = luaL_checkstring(L, 2); console.warn('StartCampaignAI was called but is not implemented :('); return 0; } /** * native CommandAI takes player num, integer command, integer data returns nothing */ function CommandAI(C: Context, L: lua_State): number { const _num = lua_touserdata(L, 1); const _command = luaL_checkinteger(L, 2); const _data = luaL_checkinteger(L, 3); console.warn('CommandAI was called but is not implemented :('); return 0; } /** * native PauseCompAI takes player p, boolean pause returns nothing */ function PauseCompAI(C: Context, L: lua_State): number { const _p = lua_touserdata(L, 1); const _pause = lua_toboolean(L, 2); console.warn('PauseCompAI was called but is not implemented :('); return 0; } /** * native GetAIDifficulty takes player num returns aidifficulty */ function GetAIDifficulty(C: Context, L: lua_State): number { const _num = lua_touserdata(L, 1); console.warn('GetAIDifficulty was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native RemoveGuardPosition takes unit hUnit returns nothing */ function RemoveGuardPosition(C: Context, L: lua_State): number { const _hUnit = lua_touserdata(L, 1); console.warn('RemoveGuardPosition was called but is not implemented :('); return 0; } /** * native RecycleGuardPosition takes unit hUnit returns nothing */ function RecycleGuardPosition(C: Context, L: lua_State): number { const _hUnit = lua_touserdata(L, 1); console.warn('RecycleGuardPosition was called but is not implemented :('); return 0; } /** * native RemoveAllGuardPositions takes player num returns nothing */ function RemoveAllGuardPositions(C: Context, L: lua_State): number { const _num = lua_touserdata(L, 1); console.warn('RemoveAllGuardPositions was called but is not implemented :('); return 0; } /** * native Cheat takes string cheatStr returns nothing */ function Cheat(C: Context, L: lua_State): number { const _cheatStr = luaL_checkstring(L, 1); console.warn('Cheat was called but is not implemented :('); return 0; } /** * native IsNoVictoryCheat takes nothing returns boolean */ function IsNoVictoryCheat(C: Context, L: lua_State): number { console.warn('IsNoVictoryCheat was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native IsNoDefeatCheat takes nothing returns boolean */ function IsNoDefeatCheat(C: Context, L: lua_State): number { console.warn('IsNoDefeatCheat was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native Preload takes string filename returns nothing */ function Preload(C: Context, L: lua_State): number { const _filename = luaL_checkstring(L, 1); console.warn('Preload was called but is not implemented :('); return 0; } /** * native PreloadEnd takes real timeout returns nothing */ function PreloadEnd(C: Context, L: lua_State): number { const _timeout = luaL_checknumber(L, 1); console.warn('PreloadEnd was called but is not implemented :('); return 0; } /** * native PreloadStart takes nothing returns nothing */ function PreloadStart(_C: Context, _L: lua_State): number { console.warn('PreloadStart was called but is not implemented :('); return 0; } /** * native PreloadRefresh takes nothing returns nothing */ function PreloadRefresh(_C: Context, _L: lua_State): number { console.warn('PreloadRefresh was called but is not implemented :('); return 0; } /** * native PreloadEndEx takes nothing returns nothing */ function PreloadEndEx(_C: Context, _L: lua_State): number { console.warn('PreloadEndEx was called but is not implemented :('); return 0; } /** * native PreloadGenClear takes nothing returns nothing */ function PreloadGenClear(_C: Context, _L: lua_State): number { console.warn('PreloadGenClear was called but is not implemented :('); return 0; } /** * native PreloadGenStart takes nothing returns nothing */ function PreloadGenStart(_C: Context, _L: lua_State): number { console.warn('PreloadGenStart was called but is not implemented :('); return 0; } /** * native PreloadGenEnd takes string filename returns nothing */ function PreloadGenEnd(C: Context, L: lua_State): number { const _filename = luaL_checkstring(L, 1); console.warn('PreloadGenEnd was called but is not implemented :('); return 0; } /** * native Preloader takes string filename returns nothing */ function Preloader(C: Context, L: lua_State): number { const _filename = luaL_checkstring(L, 1); console.warn('Preloader was called but is not implemented :('); return 0; } /** * native AutomationTestStart takes string testName returns nothing */ function AutomationTestStart(C: Context, L: lua_State): number { const _testName = luaL_checkstring(L, 1); console.warn('AutomationTestStart was called but is not implemented :('); return 0; } /** * native AutomationTestEnd takes string testName returns nothing */ function AutomationTestEnd(C: Context, L: lua_State): number { const _testName = luaL_checkstring(L, 1); console.warn('AutomationTestEnd was called but is not implemented :('); return 0; } /** * native BlzGetTriggerPlayerMouseX takes nothing returns real */ function BlzGetTriggerPlayerMouseX(C: Context, L: lua_State): number { console.warn('BlzGetTriggerPlayerMouseX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetTriggerPlayerMouseY takes nothing returns real */ function BlzGetTriggerPlayerMouseY(C: Context, L: lua_State): number { console.warn('BlzGetTriggerPlayerMouseY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetTriggerPlayerMousePosition takes nothing returns location */ function BlzGetTriggerPlayerMousePosition(C: Context, L: lua_State): number { console.warn('BlzGetTriggerPlayerMousePosition was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native BlzGetTriggerPlayerMouseButton takes nothing returns mousebuttontype */ function BlzGetTriggerPlayerMouseButton(C: Context, L: lua_State): number { console.warn('BlzGetTriggerPlayerMouseButton was called but is not implemented :('); lua_pushlightuserdata(L, { name: 'FAKE' }); return 1; } /** * native BlzSetAbilityTooltip takes integer abilCode, string tooltip, integer level returns nothing */ function BlzSetAbilityTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _tooltip = luaL_checkstring(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzSetAbilityTooltip was called but is not implemented :('); return 0; } /** * native BlzSetAbilityActivatedTooltip takes integer abilCode, string tooltip, integer level returns nothing */ function BlzSetAbilityActivatedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _tooltip = luaL_checkstring(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzSetAbilityActivatedTooltip was called but is not implemented :('); return 0; } /** * native BlzSetAbilityExtendedTooltip takes integer abilCode, string ExtendedTooltip, integer level returns nothing */ function BlzSetAbilityExtendedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _ExtendedTooltip = luaL_checkstring(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzSetAbilityExtendedTooltip was called but is not implemented :('); return 0; } /** * native BlzSetAbilityActivatedExtendedTooltip takes integer abilCode, string ExtendedTooltip, integer level returns nothing */ function BlzSetAbilityActivatedExtendedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _ExtendedTooltip = luaL_checkstring(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzSetAbilityActivatedExtendedTooltip was called but is not implemented :('); return 0; } /** * native BlzSetAbilityResearchTooltip takes integer abilCode, string researchTooltip, integer level returns nothing */ function BlzSetAbilityResearchTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _researchTooltip = luaL_checkstring(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzSetAbilityResearchTooltip was called but is not implemented :('); return 0; } /** * native BlzSetAbilityResearchExtendedTooltip takes integer abilCode, string researchExtendedTooltip, integer level returns nothing */ function BlzSetAbilityResearchExtendedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _researchExtendedTooltip = luaL_checkstring(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzSetAbilityResearchExtendedTooltip was called but is not implemented :('); return 0; } /** * native BlzGetAbilityTooltip takes integer abilCode, integer level returns string */ function BlzGetAbilityTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzGetAbilityActivatedTooltip takes integer abilCode, integer level returns string */ function BlzGetAbilityActivatedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityActivatedTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzGetAbilityExtendedTooltip takes integer abilCode, integer level returns string */ function BlzGetAbilityExtendedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityExtendedTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzGetAbilityActivatedExtendedTooltip takes integer abilCode, integer level returns string */ function BlzGetAbilityActivatedExtendedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityActivatedExtendedTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzGetAbilityResearchTooltip takes integer abilCode, integer level returns string */ function BlzGetAbilityResearchTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityResearchTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzGetAbilityResearchExtendedTooltip takes integer abilCode, integer level returns string */ function BlzGetAbilityResearchExtendedTooltip(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityResearchExtendedTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzSetAbilityIcon takes integer abilCode, string iconPath returns nothing */ function BlzSetAbilityIcon(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _iconPath = luaL_checkstring(L, 2); console.warn('BlzSetAbilityIcon was called but is not implemented :('); return 0; } /** * native BlzGetAbilityIcon takes integer abilCode returns string */ function BlzGetAbilityIcon(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); console.warn('BlzGetAbilityIcon was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzSetAbilityActivatedIcon takes integer abilCode, string iconPath returns nothing */ function BlzSetAbilityActivatedIcon(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _iconPath = luaL_checkstring(L, 2); console.warn('BlzSetAbilityActivatedIcon was called but is not implemented :('); return 0; } /** * native BlzGetAbilityActivatedIcon takes integer abilCode returns string */ function BlzGetAbilityActivatedIcon(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); console.warn('BlzGetAbilityActivatedIcon was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzGetAbilityPosX takes integer abilCode returns integer */ function BlzGetAbilityPosX(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); console.warn('BlzGetAbilityPosX was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzGetAbilityPosY takes integer abilCode returns integer */ function BlzGetAbilityPosY(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); console.warn('BlzGetAbilityPosY was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetAbilityPosX takes integer abilCode, integer x returns nothing */ function BlzSetAbilityPosX(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _x = luaL_checkinteger(L, 2); console.warn('BlzSetAbilityPosX was called but is not implemented :('); return 0; } /** * native BlzSetAbilityPosY takes integer abilCode, integer y returns nothing */ function BlzSetAbilityPosY(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _y = luaL_checkinteger(L, 2); console.warn('BlzSetAbilityPosY was called but is not implemented :('); return 0; } /** * native BlzGetAbilityActivatedPosX takes integer abilCode returns integer */ function BlzGetAbilityActivatedPosX(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); console.warn('BlzGetAbilityActivatedPosX was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzGetAbilityActivatedPosY takes integer abilCode returns integer */ function BlzGetAbilityActivatedPosY(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); console.warn('BlzGetAbilityActivatedPosY was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetAbilityActivatedPosX takes integer abilCode, integer x returns nothing */ function BlzSetAbilityActivatedPosX(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _x = luaL_checkinteger(L, 2); console.warn('BlzSetAbilityActivatedPosX was called but is not implemented :('); return 0; } /** * native BlzSetAbilityActivatedPosY takes integer abilCode, integer y returns nothing */ function BlzSetAbilityActivatedPosY(C: Context, L: lua_State): number { const _abilCode = luaL_checkinteger(L, 1); const _y = luaL_checkinteger(L, 2); console.warn('BlzSetAbilityActivatedPosY was called but is not implemented :('); return 0; } /** * native BlzGetUnitMaxHP takes unit whichUnit returns integer */ function BlzGetUnitMaxHP(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzGetUnitMaxHP was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetUnitMaxHP takes unit whichUnit, integer hp returns nothing */ function BlzSetUnitMaxHP(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _hp = luaL_checkinteger(L, 2); console.warn('BlzSetUnitMaxHP was called but is not implemented :('); return 0; } /** * native BlzGetUnitMaxMana takes unit whichUnit returns integer */ function BlzGetUnitMaxMana(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzGetUnitMaxMana was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetUnitMaxMana takes unit whichUnit, integer mana returns nothing */ function BlzSetUnitMaxMana(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _mana = luaL_checkinteger(L, 2); console.warn('BlzSetUnitMaxMana was called but is not implemented :('); return 0; } /** * native BlzDeleteHeroAbility takes unit whichUnit, integer abilCode returns nothing */ function BlzDeleteHeroAbility(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilCode = luaL_checkinteger(L, 2); console.warn('BlzDeleteHeroAbility was called but is not implemented :('); return 0; } /** * native BlzSetItemName takes item whichItem, string name returns nothing */ function BlzSetItemName(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetItemName was called but is not implemented :('); return 0; } /** * native BlzSetItemDescription takes item whichItem, string name returns nothing */ function BlzSetItemDescription(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetItemDescription was called but is not implemented :('); return 0; } /** * native BlzGetItemDescription takes item whichItem returns string */ function BlzGetItemDescription(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('BlzGetItemDescription was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzSetItemTooltip takes item whichItem, string name returns nothing */ function BlzSetItemTooltip(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetItemTooltip was called but is not implemented :('); return 0; } /** * native BlzGetItemTooltip takes item whichItem returns string */ function BlzGetItemTooltip(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('BlzGetItemTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzSetItemExtendedTooltip takes item whichItem, string name returns nothing */ function BlzSetItemExtendedTooltip(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetItemExtendedTooltip was called but is not implemented :('); return 0; } /** * native BlzGetItemExtendedTooltip takes item whichItem returns string */ function BlzGetItemExtendedTooltip(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('BlzGetItemExtendedTooltip was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzSetItemIconPath takes item whichItem, string name returns nothing */ function BlzSetItemIconPath(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetItemIconPath was called but is not implemented :('); return 0; } /** * native BlzGetItemIconPath takes item whichItem returns string */ function BlzGetItemIconPath(C: Context, L: lua_State): number { const _whichItem = lua_touserdata(L, 1); console.warn('BlzGetItemIconPath was called but is not implemented :('); lua_pushstring(L, ''); return 1; } /** * native BlzSetUnitName takes unit whichUnit, string name returns nothing */ function BlzSetUnitName(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetUnitName was called but is not implemented :('); return 0; } /** * native BlzSetHeroProperName takes unit whichUnit, string name returns nothing */ function BlzSetHeroProperName(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _name = luaL_checkstring(L, 2); console.warn('BlzSetHeroProperName was called but is not implemented :('); return 0; } /** * native BlzGetUnitBaseDamage takes unit whichUnit, integer weaponIndex returns integer */ function BlzGetUnitBaseDamage(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _weaponIndex = luaL_checkinteger(L, 2); console.warn('BlzGetUnitBaseDamage was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetUnitBaseDamage takes unit whichUnit, integer baseDamage, integer weaponIndex returns nothing */ function BlzSetUnitBaseDamage(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _baseDamage = luaL_checkinteger(L, 2); const _weaponIndex = luaL_checkinteger(L, 3); console.warn('BlzSetUnitBaseDamage was called but is not implemented :('); return 0; } /** * native BlzGetUnitDiceNumber takes unit whichUnit, integer weaponIndex returns integer */ function BlzGetUnitDiceNumber(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _weaponIndex = luaL_checkinteger(L, 2); console.warn('BlzGetUnitDiceNumber was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetUnitDiceNumber takes unit whichUnit, integer diceNumber, integer weaponIndex returns nothing */ function BlzSetUnitDiceNumber(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _diceNumber = luaL_checkinteger(L, 2); const _weaponIndex = luaL_checkinteger(L, 3); console.warn('BlzSetUnitDiceNumber was called but is not implemented :('); return 0; } /** * native BlzGetUnitDiceSides takes unit whichUnit, integer weaponIndex returns integer */ function BlzGetUnitDiceSides(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _weaponIndex = luaL_checkinteger(L, 2); console.warn('BlzGetUnitDiceSides was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetUnitDiceSides takes unit whichUnit, integer diceSides, integer weaponIndex returns nothing */ function BlzSetUnitDiceSides(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _diceSides = luaL_checkinteger(L, 2); const _weaponIndex = luaL_checkinteger(L, 3); console.warn('BlzSetUnitDiceSides was called but is not implemented :('); return 0; } /** * native BlzGetUnitAttackCooldown takes unit whichUnit, integer weaponIndex returns real */ function BlzGetUnitAttackCooldown(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _weaponIndex = luaL_checkinteger(L, 2); console.warn('BlzGetUnitAttackCooldown was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzSetUnitAttackCooldown takes unit whichUnit, real cooldown, integer weaponIndex returns nothing */ function BlzSetUnitAttackCooldown(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _cooldown = luaL_checknumber(L, 2); const _weaponIndex = luaL_checkinteger(L, 3); console.warn('BlzSetUnitAttackCooldown was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectColorByPlayer takes effect whichEffect, player whichPlayer returns nothing */ function BlzSetSpecialEffectColorByPlayer(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _whichPlayer = lua_touserdata(L, 2); console.warn('BlzSetSpecialEffectColorByPlayer was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectColor takes effect whichEffect, integer r, integer g, integer b returns nothing */ function BlzSetSpecialEffectColor(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _r = luaL_checkinteger(L, 2); const _g = luaL_checkinteger(L, 3); const _b = luaL_checkinteger(L, 4); console.warn('BlzSetSpecialEffectColor was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectAlpha takes effect whichEffect, integer alpha returns nothing */ function BlzSetSpecialEffectAlpha(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _alpha = luaL_checkinteger(L, 2); console.warn('BlzSetSpecialEffectAlpha was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectScale takes effect whichEffect, real scale returns nothing */ function BlzSetSpecialEffectScale(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _scale = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectScale was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectPosition takes effect whichEffect, real x, real y, real z returns nothing */ function BlzSetSpecialEffectPosition(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); const _y = luaL_checknumber(L, 3); const _z = luaL_checknumber(L, 4); console.warn('BlzSetSpecialEffectPosition was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectHeight takes effect whichEffect, real height returns nothing */ function BlzSetSpecialEffectHeight(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _height = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectHeight was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectTimeScale takes effect whichEffect, real timeScale returns nothing */ function BlzSetSpecialEffectTimeScale(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _timeScale = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectTimeScale was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectTime takes effect whichEffect, real time returns nothing */ function BlzSetSpecialEffectTime(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _time = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectTime was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectOrientation takes effect whichEffect, real yaw, real pitch, real roll returns nothing */ function BlzSetSpecialEffectOrientation(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _yaw = luaL_checknumber(L, 2); const _pitch = luaL_checknumber(L, 3); const _roll = luaL_checknumber(L, 4); console.warn('BlzSetSpecialEffectOrientation was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectYaw takes effect whichEffect, real yaw returns nothing */ function BlzSetSpecialEffectYaw(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _yaw = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectYaw was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectPitch takes effect whichEffect, real pitch returns nothing */ function BlzSetSpecialEffectPitch(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _pitch = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectPitch was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectRoll takes effect whichEffect, real roll returns nothing */ function BlzSetSpecialEffectRoll(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _roll = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectRoll was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectX takes effect whichEffect, real x returns nothing */ function BlzSetSpecialEffectX(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _x = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectX was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectY takes effect whichEffect, real y returns nothing */ function BlzSetSpecialEffectY(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _y = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectY was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectZ takes effect whichEffect, real z returns nothing */ function BlzSetSpecialEffectZ(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _z = luaL_checknumber(L, 2); console.warn('BlzSetSpecialEffectZ was called but is not implemented :('); return 0; } /** * native BlzSetSpecialEffectPositionLoc takes effect whichEffect, location loc returns nothing */ function BlzSetSpecialEffectPositionLoc(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); const _loc = lua_touserdata(L, 2); console.warn('BlzSetSpecialEffectPositionLoc was called but is not implemented :('); return 0; } /** * native BlzGetLocalSpecialEffectX takes effect whichEffect returns real */ function BlzGetLocalSpecialEffectX(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); console.warn('BlzGetLocalSpecialEffectX was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetLocalSpecialEffectY takes effect whichEffect returns real */ function BlzGetLocalSpecialEffectY(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); console.warn('BlzGetLocalSpecialEffectY was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetLocalSpecialEffectZ takes effect whichEffect returns real */ function BlzGetLocalSpecialEffectZ(C: Context, L: lua_State): number { const _whichEffect = lua_touserdata(L, 1); console.warn('BlzGetLocalSpecialEffectZ was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetUnitArmor takes unit whichUnit returns real */ function BlzGetUnitArmor(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzGetUnitArmor was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzSetUnitArmor takes unit whichUnit, real armorAmount returns nothing */ function BlzSetUnitArmor(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _armorAmount = luaL_checknumber(L, 2); console.warn('BlzSetUnitArmor was called but is not implemented :('); return 0; } /** * native BlzUnitHideAbility takes unit whichUnit, integer abilId, boolean flag returns nothing */ function BlzUnitHideAbility(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); const _flag = lua_toboolean(L, 3); console.warn('BlzUnitHideAbility was called but is not implemented :('); return 0; } /** * native BlzUnitDisableAbility takes unit whichUnit, integer abilId, boolean flag, boolean hideUI returns nothing */ function BlzUnitDisableAbility(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); const _flag = lua_toboolean(L, 3); const _hideUI = lua_toboolean(L, 4); console.warn('BlzUnitDisableAbility was called but is not implemented :('); return 0; } /** * native BlzUnitCancelTimedLife takes unit whichUnit returns nothing */ function BlzUnitCancelTimedLife(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzUnitCancelTimedLife was called but is not implemented :('); return 0; } /** * native BlzIsUnitSelectable takes unit whichUnit returns boolean */ function BlzIsUnitSelectable(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzIsUnitSelectable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native BlzIsUnitInvulnerable takes unit whichUnit returns boolean */ function BlzIsUnitInvulnerable(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzIsUnitInvulnerable was called but is not implemented :('); lua_pushboolean(L, false); return 1; } /** * native BlzUnitInterruptAttack takes unit whichUnit returns nothing */ function BlzUnitInterruptAttack(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzUnitInterruptAttack was called but is not implemented :('); return 0; } /** * native BlzGetUnitCollisionSize takes unit whichUnit returns real */ function BlzGetUnitCollisionSize(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzGetUnitCollisionSize was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetAbilityManaCost takes integer abilId, integer level returns integer */ function BlzGetAbilityManaCost(C: Context, L: lua_State): number { const _abilId = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityManaCost was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzGetAbilityCooldown takes integer abilId, integer level returns real */ function BlzGetAbilityCooldown(C: Context, L: lua_State): number { const _abilId = luaL_checkinteger(L, 1); const _level = luaL_checkinteger(L, 2); console.warn('BlzGetAbilityCooldown was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzSetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level, real cooldown returns nothing */ function BlzSetUnitAbilityCooldown(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); const _level = luaL_checkinteger(L, 3); const _cooldown = luaL_checknumber(L, 4); console.warn('BlzSetUnitAbilityCooldown was called but is not implemented :('); return 0; } /** * native BlzGetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level returns real */ function BlzGetUnitAbilityCooldown(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzGetUnitAbilityCooldown was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzGetUnitAbilityCooldownRemaining takes unit whichUnit, integer abilId returns real */ function BlzGetUnitAbilityCooldownRemaining(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); console.warn('BlzGetUnitAbilityCooldownRemaining was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzEndUnitAbilityCooldown takes unit whichUnit, integer abilCode returns nothing */ function BlzEndUnitAbilityCooldown(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilCode = luaL_checkinteger(L, 2); console.warn('BlzEndUnitAbilityCooldown was called but is not implemented :('); return 0; } /** * native BlzGetUnitAbilityManaCost takes unit whichUnit, integer abilId, integer level returns integer */ function BlzGetUnitAbilityManaCost(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); const _level = luaL_checkinteger(L, 3); console.warn('BlzGetUnitAbilityManaCost was called but is not implemented :('); lua_pushinteger(L, 0); return 1; } /** * native BlzSetUnitAbilityManaCost takes unit whichUnit, integer abilId, integer level, integer manaCost returns nothing */ function BlzSetUnitAbilityManaCost(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); const _abilId = luaL_checkinteger(L, 2); const _level = luaL_checkinteger(L, 3); const _manaCost = luaL_checkinteger(L, 4); console.warn('BlzSetUnitAbilityManaCost was called but is not implemented :('); return 0; } /** * native BlzGetLocalUnitZ takes unit whichUnit returns real */ function BlzGetLocalUnitZ(C: Context, L: lua_State): number { const _whichUnit = lua_touserdata(L, 1); console.warn('BlzGetLocalUnitZ was called but is not implemented :('); lua_pushnumber(L, 0); return 1; } /** * native BlzDecPlayerTechResearched takes player whichPlayer, integer techid, integer levels returns nothing */ function BlzDecPlayerTechResearched(C: Context, L: lua_State): number { const _whichPlayer = lua_touserdata(L, 1); const _techid = luaL_checkinteger(L, 2); const _levels = luaL_checkinteger(L, 3); console.warn('BlzDecPlayerTechResearched was called but is not implemented :('); return 0; } /** * native BlzSetEventDamage takes real damage returns nothing */ function BlzSetEventDamage(C: Context, L: lua_State): number { const _damage = luaL_checknumber(L, 1); console.warn('BlzSetEventDamage was called but is not implemented :('); return 0; } export default function bindNatives(C: Context): void { const L = C.L; lua_register(L, 'ConvertRace', ConvertRace.bind(null, C)); lua_register(L, 'ConvertAllianceType', ConvertAllianceType.bind(null, C)); lua_register(L, 'ConvertRacePref', ConvertRacePref.bind(null, C)); lua_register(L, 'ConvertIGameState', ConvertIGameState.bind(null, C)); lua_register(L, 'ConvertFGameState', ConvertFGameState.bind(null, C)); lua_register(L, 'ConvertPlayerState', ConvertPlayerState.bind(null, C)); lua_register(L, 'ConvertPlayerScore', ConvertPlayerScore.bind(null, C)); lua_register(L, 'ConvertPlayerGameResult', ConvertPlayerGameResult.bind(null, C)); lua_register(L, 'ConvertUnitState', ConvertUnitState.bind(null, C)); lua_register(L, 'ConvertAIDifficulty', ConvertAIDifficulty.bind(null, C)); lua_register(L, 'ConvertGameEvent', ConvertGameEvent.bind(null, C)); lua_register(L, 'ConvertPlayerEvent', ConvertPlayerEvent.bind(null, C)); lua_register(L, 'ConvertPlayerUnitEvent', ConvertPlayerUnitEvent.bind(null, C)); lua_register(L, 'ConvertWidgetEvent', ConvertWidgetEvent.bind(null, C)); lua_register(L, 'ConvertDialogEvent', ConvertDialogEvent.bind(null, C)); lua_register(L, 'ConvertUnitEvent', ConvertUnitEvent.bind(null, C)); lua_register(L, 'ConvertLimitOp', ConvertLimitOp.bind(null, C)); lua_register(L, 'ConvertUnitType', ConvertUnitType.bind(null, C)); lua_register(L, 'ConvertGameSpeed', ConvertGameSpeed.bind(null, C)); lua_register(L, 'ConvertPlacement', ConvertPlacement.bind(null, C)); lua_register(L, 'ConvertStartLocPrio', ConvertStartLocPrio.bind(null, C)); lua_register(L, 'ConvertGameDifficulty', ConvertGameDifficulty.bind(null, C)); lua_register(L, 'ConvertGameType', ConvertGameType.bind(null, C)); lua_register(L, 'ConvertMapFlag', ConvertMapFlag.bind(null, C)); lua_register(L, 'ConvertMapVisibility', ConvertMapVisibility.bind(null, C)); lua_register(L, 'ConvertMapSetting', ConvertMapSetting.bind(null, C)); lua_register(L, 'ConvertMapDensity', ConvertMapDensity.bind(null, C)); lua_register(L, 'ConvertMapControl', ConvertMapControl.bind(null, C)); lua_register(L, 'ConvertPlayerColor', ConvertPlayerColor.bind(null, C)); lua_register(L, 'ConvertPlayerSlotState', ConvertPlayerSlotState.bind(null, C)); lua_register(L, 'ConvertVolumeGroup', ConvertVolumeGroup.bind(null, C)); lua_register(L, 'ConvertCameraField', ConvertCameraField.bind(null, C)); lua_register(L, 'ConvertBlendMode', ConvertBlendMode.bind(null, C)); lua_register(L, 'ConvertRarityControl', ConvertRarityControl.bind(null, C)); lua_register(L, 'ConvertTexMapFlags', ConvertTexMapFlags.bind(null, C)); lua_register(L, 'ConvertFogState', ConvertFogState.bind(null, C)); lua_register(L, 'ConvertEffectType', ConvertEffectType.bind(null, C)); lua_register(L, 'ConvertVersion', ConvertVersion.bind(null, C)); lua_register(L, 'ConvertItemType', ConvertItemType.bind(null, C)); lua_register(L, 'ConvertAttackType', ConvertAttackType.bind(null, C)); lua_register(L, 'ConvertDamageType', ConvertDamageType.bind(null, C)); lua_register(L, 'ConvertWeaponType', ConvertWeaponType.bind(null, C)); lua_register(L, 'ConvertSoundType', ConvertSoundType.bind(null, C)); lua_register(L, 'ConvertPathingType', ConvertPathingType.bind(null, C)); lua_register(L, 'ConvertMouseButtonType', ConvertMouseButtonType.bind(null, C)); lua_register(L, 'ConvertAnimType', ConvertAnimType.bind(null, C)); lua_register(L, 'ConvertSubAnimType', ConvertSubAnimType.bind(null, C)); lua_register(L, 'OrderId', OrderId.bind(null, C)); lua_register(L, 'OrderId2String', OrderId2String.bind(null, C)); lua_register(L, 'UnitId', UnitId.bind(null, C)); lua_register(L, 'UnitId2String', UnitId2String.bind(null, C)); lua_register(L, 'AbilityId', AbilityId.bind(null, C)); lua_register(L, 'AbilityId2String', AbilityId2String.bind(null, C)); lua_register(L, 'GetObjectName', GetObjectName.bind(null, C)); lua_register(L, 'GetBJMaxPlayers', GetBJMaxPlayers.bind(null, C)); lua_register(L, 'GetBJPlayerNeutralVictim', GetBJPlayerNeutralVictim.bind(null, C)); lua_register(L, 'GetBJPlayerNeutralExtra', GetBJPlayerNeutralExtra.bind(null, C)); lua_register(L, 'GetBJMaxPlayerSlots', GetBJMaxPlayerSlots.bind(null, C)); lua_register(L, 'GetPlayerNeutralPassive', GetPlayerNeutralPassive.bind(null, C)); lua_register(L, 'GetPlayerNeutralAggressive', GetPlayerNeutralAggressive.bind(null, C)); lua_register(L, 'Deg2Rad', Deg2Rad.bind(null, C)); lua_register(L, 'Rad2Deg', Rad2Deg.bind(null, C)); lua_register(L, 'Sin', Sin.bind(null, C)); lua_register(L, 'Cos', Cos.bind(null, C)); lua_register(L, 'Tan', Tan.bind(null, C)); lua_register(L, 'Asin', Asin.bind(null, C)); lua_register(L, 'Acos', Acos.bind(null, C)); lua_register(L, 'Atan', Atan.bind(null, C)); lua_register(L, 'Atan2', Atan2.bind(null, C)); lua_register(L, 'SquareRoot', SquareRoot.bind(null, C)); lua_register(L, 'Pow', Pow.bind(null, C)); lua_register(L, 'I2R', I2R.bind(null, C)); lua_register(L, 'R2I', R2I.bind(null, C)); lua_register(L, 'I2S', I2S.bind(null, C)); lua_register(L, 'R2S', R2S.bind(null, C)); lua_register(L, 'R2SW', R2SW.bind(null, C)); lua_register(L, 'S2I', S2I.bind(null, C)); lua_register(L, 'S2R', S2R.bind(null, C)); lua_register(L, 'GetHandleId', GetHandleId.bind(null, C)); lua_register(L, 'SubString', SubString.bind(null, C)); lua_register(L, 'StringLength', StringLength.bind(null, C)); lua_register(L, 'StringCase', StringCase.bind(null, C)); lua_register(L, 'StringHash', StringHash.bind(null, C)); lua_register(L, 'GetLocalizedString', GetLocalizedString.bind(null, C)); lua_register(L, 'GetLocalizedHotkey', GetLocalizedHotkey.bind(null, C)); lua_register(L, 'SetMapName', SetMapName.bind(null, C)); lua_register(L, 'SetMapDescription', SetMapDescription.bind(null, C)); lua_register(L, 'SetTeams', SetTeams.bind(null, C)); lua_register(L, 'SetPlayers', SetPlayers.bind(null, C)); lua_register(L, 'DefineStartLocation', DefineStartLocation.bind(null, C)); lua_register(L, 'DefineStartLocationLoc', DefineStartLocationLoc.bind(null, C)); lua_register(L, 'SetStartLocPrioCount', SetStartLocPrioCount.bind(null, C)); lua_register(L, 'SetStartLocPrio', SetStartLocPrio.bind(null, C)); lua_register(L, 'GetStartLocPrioSlot', GetStartLocPrioSlot.bind(null, C)); lua_register(L, 'GetStartLocPrio', GetStartLocPrio.bind(null, C)); lua_register(L, 'SetGameTypeSupported', SetGameTypeSupported.bind(null, C)); lua_register(L, 'SetMapFlag', SetMapFlag.bind(null, C)); lua_register(L, 'SetGamePlacement', SetGamePlacement.bind(null, C)); lua_register(L, 'SetGameSpeed', SetGameSpeed.bind(null, C)); lua_register(L, 'SetGameDifficulty', SetGameDifficulty.bind(null, C)); lua_register(L, 'SetResourceDensity', SetResourceDensity.bind(null, C)); lua_register(L, 'SetCreatureDensity', SetCreatureDensity.bind(null, C)); lua_register(L, 'GetTeams', GetTeams.bind(null, C)); lua_register(L, 'GetPlayers', GetPlayers.bind(null, C)); lua_register(L, 'IsGameTypeSupported', IsGameTypeSupported.bind(null, C)); lua_register(L, 'GetGameTypeSelected', GetGameTypeSelected.bind(null, C)); lua_register(L, 'IsMapFlagSet', IsMapFlagSet.bind(null, C)); lua_register(L, 'GetGamePlacement', GetGamePlacement.bind(null, C)); lua_register(L, 'GetGameSpeed', GetGameSpeed.bind(null, C)); lua_register(L, 'GetGameDifficulty', GetGameDifficulty.bind(null, C)); lua_register(L, 'GetResourceDensity', GetResourceDensity.bind(null, C)); lua_register(L, 'GetCreatureDensity', GetCreatureDensity.bind(null, C)); lua_register(L, 'GetStartLocationX', GetStartLocationX.bind(null, C)); lua_register(L, 'GetStartLocationY', GetStartLocationY.bind(null, C)); lua_register(L, 'GetStartLocationLoc', GetStartLocationLoc.bind(null, C)); lua_register(L, 'SetPlayerTeam', SetPlayerTeam.bind(null, C)); lua_register(L, 'SetPlayerStartLocation', SetPlayerStartLocation.bind(null, C)); lua_register(L, 'ForcePlayerStartLocation', ForcePlayerStartLocation.bind(null, C)); lua_register(L, 'SetPlayerColor', SetPlayerColor.bind(null, C)); lua_register(L, 'SetPlayerAlliance', SetPlayerAlliance.bind(null, C)); lua_register(L, 'SetPlayerTaxRate', SetPlayerTaxRate.bind(null, C)); lua_register(L, 'SetPlayerRacePreference', SetPlayerRacePreference.bind(null, C)); lua_register(L, 'SetPlayerRaceSelectable', SetPlayerRaceSelectable.bind(null, C)); lua_register(L, 'SetPlayerController', SetPlayerController.bind(null, C)); lua_register(L, 'SetPlayerName', SetPlayerName.bind(null, C)); lua_register(L, 'SetPlayerOnScoreScreen', SetPlayerOnScoreScreen.bind(null, C)); lua_register(L, 'GetPlayerTeam', GetPlayerTeam.bind(null, C)); lua_register(L, 'GetPlayerStartLocation', GetPlayerStartLocation.bind(null, C)); lua_register(L, 'GetPlayerColor', GetPlayerColor.bind(null, C)); lua_register(L, 'GetPlayerSelectable', GetPlayerSelectable.bind(null, C)); lua_register(L, 'GetPlayerController', GetPlayerController.bind(null, C)); lua_register(L, 'GetPlayerSlotState', GetPlayerSlotState.bind(null, C)); lua_register(L, 'GetPlayerTaxRate', GetPlayerTaxRate.bind(null, C)); lua_register(L, 'IsPlayerRacePrefSet', IsPlayerRacePrefSet.bind(null, C)); lua_register(L, 'GetPlayerName', GetPlayerName.bind(null, C)); lua_register(L, 'CreateTimer', CreateTimer.bind(null, C)); lua_register(L, 'DestroyTimer', DestroyTimer.bind(null, C)); lua_register(L, 'TimerStart', TimerStart.bind(null, C)); lua_register(L, 'TimerGetElapsed', TimerGetElapsed.bind(null, C)); lua_register(L, 'TimerGetRemaining', TimerGetRemaining.bind(null, C)); lua_register(L, 'TimerGetTimeout', TimerGetTimeout.bind(null, C)); lua_register(L, 'PauseTimer', PauseTimer.bind(null, C)); lua_register(L, 'ResumeTimer', ResumeTimer.bind(null, C)); lua_register(L, 'GetExpiredTimer', GetExpiredTimer.bind(null, C)); lua_register(L, 'CreateGroup', CreateGroup.bind(null, C)); lua_register(L, 'DestroyGroup', DestroyGroup.bind(null, C)); lua_register(L, 'GroupAddUnit', GroupAddUnit.bind(null, C)); lua_register(L, 'GroupRemoveUnit', GroupRemoveUnit.bind(null, C)); lua_register(L, 'GroupClear', GroupClear.bind(null, C)); lua_register(L, 'GroupEnumUnitsOfType', GroupEnumUnitsOfType.bind(null, C)); lua_register(L, 'GroupEnumUnitsOfPlayer', GroupEnumUnitsOfPlayer.bind(null, C)); lua_register(L, 'GroupEnumUnitsOfTypeCounted', GroupEnumUnitsOfTypeCounted.bind(null, C)); lua_register(L, 'GroupEnumUnitsInRect', GroupEnumUnitsInRect.bind(null, C)); lua_register(L, 'GroupEnumUnitsInRectCounted', GroupEnumUnitsInRectCounted.bind(null, C)); lua_register(L, 'GroupEnumUnitsInRange', GroupEnumUnitsInRange.bind(null, C)); lua_register(L, 'GroupEnumUnitsInRangeOfLoc', GroupEnumUnitsInRangeOfLoc.bind(null, C)); lua_register(L, 'GroupEnumUnitsInRangeCounted', GroupEnumUnitsInRangeCounted.bind(null, C)); lua_register(L, 'GroupEnumUnitsInRangeOfLocCounted', GroupEnumUnitsInRangeOfLocCounted.bind(null, C)); lua_register(L, 'GroupEnumUnitsSelected', GroupEnumUnitsSelected.bind(null, C)); lua_register(L, 'GroupImmediateOrder', GroupImmediateOrder.bind(null, C)); lua_register(L, 'GroupImmediateOrderById', GroupImmediateOrderById.bind(null, C)); lua_register(L, 'GroupPointOrder', GroupPointOrder.bind(null, C)); lua_register(L, 'GroupPointOrderLoc', GroupPointOrderLoc.bind(null, C)); lua_register(L, 'GroupPointOrderById', GroupPointOrderById.bind(null, C)); lua_register(L, 'GroupPointOrderByIdLoc', GroupPointOrderByIdLoc.bind(null, C)); lua_register(L, 'GroupTargetOrder', GroupTargetOrder.bind(null, C)); lua_register(L, 'GroupTargetOrderById', GroupTargetOrderById.bind(null, C)); lua_register(L, 'ForGroup', ForGroup.bind(null, C)); lua_register(L, 'FirstOfGroup', FirstOfGroup.bind(null, C)); lua_register(L, 'CreateForce', CreateForce.bind(null, C)); lua_register(L, 'DestroyForce', DestroyForce.bind(null, C)); lua_register(L, 'ForceAddPlayer', ForceAddPlayer.bind(null, C)); lua_register(L, 'ForceRemovePlayer', ForceRemovePlayer.bind(null, C)); lua_register(L, 'ForceClear', ForceClear.bind(null, C)); lua_register(L, 'ForceEnumPlayers', ForceEnumPlayers.bind(null, C)); lua_register(L, 'ForceEnumPlayersCounted', ForceEnumPlayersCounted.bind(null, C)); lua_register(L, 'ForceEnumAllies', ForceEnumAllies.bind(null, C)); lua_register(L, 'ForceEnumEnemies', ForceEnumEnemies.bind(null, C)); lua_register(L, 'ForForce', ForForce.bind(null, C)); lua_register(L, 'Rect', Rect.bind(null, C)); lua_register(L, 'RectFromLoc', RectFromLoc.bind(null, C)); lua_register(L, 'RemoveRect', RemoveRect.bind(null, C)); lua_register(L, 'SetRect', SetRect.bind(null, C)); lua_register(L, 'SetRectFromLoc', SetRectFromLoc.bind(null, C)); lua_register(L, 'MoveRectTo', MoveRectTo.bind(null, C)); lua_register(L, 'MoveRectToLoc', MoveRectToLoc.bind(null, C)); lua_register(L, 'GetRectCenterX', GetRectCenterX.bind(null, C)); lua_register(L, 'GetRectCenterY', GetRectCenterY.bind(null, C)); lua_register(L, 'GetRectMinX', GetRectMinX.bind(null, C)); lua_register(L, 'GetRectMinY', GetRectMinY.bind(null, C)); lua_register(L, 'GetRectMaxX', GetRectMaxX.bind(null, C)); lua_register(L, 'GetRectMaxY', GetRectMaxY.bind(null, C)); lua_register(L, 'CreateRegion', CreateRegion.bind(null, C)); lua_register(L, 'RemoveRegion', RemoveRegion.bind(null, C)); lua_register(L, 'RegionAddRect', RegionAddRect.bind(null, C)); lua_register(L, 'RegionClearRect', RegionClearRect.bind(null, C)); lua_register(L, 'RegionAddCell', RegionAddCell.bind(null, C)); lua_register(L, 'RegionAddCellAtLoc', RegionAddCellAtLoc.bind(null, C)); lua_register(L, 'RegionClearCell', RegionClearCell.bind(null, C)); lua_register(L, 'RegionClearCellAtLoc', RegionClearCellAtLoc.bind(null, C)); lua_register(L, 'Location', Location.bind(null, C)); lua_register(L, 'RemoveLocation', RemoveLocation.bind(null, C)); lua_register(L, 'MoveLocation', MoveLocation.bind(null, C)); lua_register(L, 'GetLocationX', GetLocationX.bind(null, C)); lua_register(L, 'GetLocationY', GetLocationY.bind(null, C)); lua_register(L, 'GetLocationZ', GetLocationZ.bind(null, C)); lua_register(L, 'IsUnitInRegion', IsUnitInRegion.bind(null, C)); lua_register(L, 'IsPointInRegion', IsPointInRegion.bind(null, C)); lua_register(L, 'IsLocationInRegion', IsLocationInRegion.bind(null, C)); lua_register(L, 'GetWorldBounds', GetWorldBounds.bind(null, C)); lua_register(L, 'CreateTrigger', CreateTrigger.bind(null, C)); lua_register(L, 'DestroyTrigger', DestroyTrigger.bind(null, C)); lua_register(L, 'ResetTrigger', ResetTrigger.bind(null, C)); lua_register(L, 'EnableTrigger', EnableTrigger.bind(null, C)); lua_register(L, 'DisableTrigger', DisableTrigger.bind(null, C)); lua_register(L, 'IsTriggerEnabled', IsTriggerEnabled.bind(null, C)); lua_register(L, 'TriggerWaitOnSleeps', TriggerWaitOnSleeps.bind(null, C)); lua_register(L, 'IsTriggerWaitOnSleeps', IsTriggerWaitOnSleeps.bind(null, C)); lua_register(L, 'GetFilterUnit', GetFilterUnit.bind(null, C)); lua_register(L, 'GetEnumUnit', GetEnumUnit.bind(null, C)); lua_register(L, 'GetFilterDestructable', GetFilterDestructable.bind(null, C)); lua_register(L, 'GetEnumDestructable', GetEnumDestructable.bind(null, C)); lua_register(L, 'GetFilterItem', GetFilterItem.bind(null, C)); lua_register(L, 'GetEnumItem', GetEnumItem.bind(null, C)); lua_register(L, 'GetFilterPlayer', GetFilterPlayer.bind(null, C)); lua_register(L, 'GetEnumPlayer', GetEnumPlayer.bind(null, C)); lua_register(L, 'GetTriggeringTrigger', GetTriggeringTrigger.bind(null, C)); lua_register(L, 'GetTriggerEventId', GetTriggerEventId.bind(null, C)); lua_register(L, 'GetTriggerEvalCount', GetTriggerEvalCount.bind(null, C)); lua_register(L, 'GetTriggerExecCount', GetTriggerExecCount.bind(null, C)); lua_register(L, 'ExecuteFunc', ExecuteFunc.bind(null, C)); lua_register(L, 'And', And.bind(null, C)); lua_register(L, 'Or', Or.bind(null, C)); lua_register(L, 'Not', Not.bind(null, C)); lua_register(L, 'Condition', Condition.bind(null, C)); lua_register(L, 'DestroyCondition', DestroyCondition.bind(null, C)); lua_register(L, 'Filter', Filter.bind(null, C)); lua_register(L, 'DestroyFilter', DestroyFilter.bind(null, C)); lua_register(L, 'DestroyBoolExpr', DestroyBoolExpr.bind(null, C)); lua_register(L, 'TriggerRegisterVariableEvent', TriggerRegisterVariableEvent.bind(null, C)); lua_register(L, 'TriggerRegisterTimerEvent', TriggerRegisterTimerEvent.bind(null, C)); lua_register(L, 'TriggerRegisterTimerExpireEvent', TriggerRegisterTimerExpireEvent.bind(null, C)); lua_register(L, 'TriggerRegisterGameStateEvent', TriggerRegisterGameStateEvent.bind(null, C)); lua_register(L, 'TriggerRegisterDialogEvent', TriggerRegisterDialogEvent.bind(null, C)); lua_register(L, 'TriggerRegisterDialogButtonEvent', TriggerRegisterDialogButtonEvent.bind(null, C)); lua_register(L, 'GetEventGameState', GetEventGameState.bind(null, C)); lua_register(L, 'TriggerRegisterGameEvent', TriggerRegisterGameEvent.bind(null, C)); lua_register(L, 'GetWinningPlayer', GetWinningPlayer.bind(null, C)); lua_register(L, 'TriggerRegisterEnterRegion', TriggerRegisterEnterRegion.bind(null, C)); lua_register(L, 'GetTriggeringRegion', GetTriggeringRegion.bind(null, C)); lua_register(L, 'GetEnteringUnit', GetEnteringUnit.bind(null, C)); lua_register(L, 'TriggerRegisterLeaveRegion', TriggerRegisterLeaveRegion.bind(null, C)); lua_register(L, 'GetLeavingUnit', GetLeavingUnit.bind(null, C)); lua_register(L, 'TriggerRegisterTrackableHitEvent', TriggerRegisterTrackableHitEvent.bind(null, C)); lua_register(L, 'TriggerRegisterTrackableTrackEvent', TriggerRegisterTrackableTrackEvent.bind(null, C)); lua_register(L, 'GetTriggeringTrackable', GetTriggeringTrackable.bind(null, C)); lua_register(L, 'GetClickedButton', GetClickedButton.bind(null, C)); lua_register(L, 'GetClickedDialog', GetClickedDialog.bind(null, C)); lua_register(L, 'GetTournamentFinishSoonTimeRemaining', GetTournamentFinishSoonTimeRemaining.bind(null, C)); lua_register(L, 'GetTournamentFinishNowRule', GetTournamentFinishNowRule.bind(null, C)); lua_register(L, 'GetTournamentFinishNowPlayer', GetTournamentFinishNowPlayer.bind(null, C)); lua_register(L, 'GetTournamentScore', GetTournamentScore.bind(null, C)); lua_register(L, 'GetSaveBasicFilename', GetSaveBasicFilename.bind(null, C)); lua_register(L, 'TriggerRegisterPlayerEvent', TriggerRegisterPlayerEvent.bind(null, C)); lua_register(L, 'GetTriggerPlayer', GetTriggerPlayer.bind(null, C)); lua_register(L, 'TriggerRegisterPlayerUnitEvent', TriggerRegisterPlayerUnitEvent.bind(null, C)); lua_register(L, 'GetLevelingUnit', GetLevelingUnit.bind(null, C)); lua_register(L, 'GetLearningUnit', GetLearningUnit.bind(null, C)); lua_register(L, 'GetLearnedSkill', GetLearnedSkill.bind(null, C)); lua_register(L, 'GetLearnedSkillLevel', GetLearnedSkillLevel.bind(null, C)); lua_register(L, 'GetRevivableUnit', GetRevivableUnit.bind(null, C)); lua_register(L, 'GetRevivingUnit', GetRevivingUnit.bind(null, C)); lua_register(L, 'GetAttacker', GetAttacker.bind(null, C)); lua_register(L, 'GetRescuer', GetRescuer.bind(null, C)); lua_register(L, 'GetDyingUnit', GetDyingUnit.bind(null, C)); lua_register(L, 'GetKillingUnit', GetKillingUnit.bind(null, C)); lua_register(L, 'GetDecayingUnit', GetDecayingUnit.bind(null, C)); lua_register(L, 'GetConstructingStructure', GetConstructingStructure.bind(null, C)); lua_register(L, 'GetCancelledStructure', GetCancelledStructure.bind(null, C)); lua_register(L, 'GetConstructedStructure', GetConstructedStructure.bind(null, C)); lua_register(L, 'GetResearchingUnit', GetResearchingUnit.bind(null, C)); lua_register(L, 'GetResearched', GetResearched.bind(null, C)); lua_register(L, 'GetTrainedUnitType', GetTrainedUnitType.bind(null, C)); lua_register(L, 'GetTrainedUnit', GetTrainedUnit.bind(null, C)); lua_register(L, 'GetDetectedUnit', GetDetectedUnit.bind(null, C)); lua_register(L, 'GetSummoningUnit', GetSummoningUnit.bind(null, C)); lua_register(L, 'GetSummonedUnit', GetSummonedUnit.bind(null, C)); lua_register(L, 'GetTransportUnit', GetTransportUnit.bind(null, C)); lua_register(L, 'GetLoadedUnit', GetLoadedUnit.bind(null, C)); lua_register(L, 'GetSellingUnit', GetSellingUnit.bind(null, C)); lua_register(L, 'GetSoldUnit', GetSoldUnit.bind(null, C)); lua_register(L, 'GetBuyingUnit', GetBuyingUnit.bind(null, C)); lua_register(L, 'GetSoldItem', GetSoldItem.bind(null, C)); lua_register(L, 'GetChangingUnit', GetChangingUnit.bind(null, C)); lua_register(L, 'GetChangingUnitPrevOwner', GetChangingUnitPrevOwner.bind(null, C)); lua_register(L, 'GetManipulatingUnit', GetManipulatingUnit.bind(null, C)); lua_register(L, 'GetManipulatedItem', GetManipulatedItem.bind(null, C)); lua_register(L, 'GetOrderedUnit', GetOrderedUnit.bind(null, C)); lua_register(L, 'GetIssuedOrderId', GetIssuedOrderId.bind(null, C)); lua_register(L, 'GetOrderPointX', GetOrderPointX.bind(null, C)); lua_register(L, 'GetOrderPointY', GetOrderPointY.bind(null, C)); lua_register(L, 'GetOrderPointLoc', GetOrderPointLoc.bind(null, C)); lua_register(L, 'GetOrderTarget', GetOrderTarget.bind(null, C)); lua_register(L, 'GetOrderTargetDestructable', GetOrderTargetDestructable.bind(null, C)); lua_register(L, 'GetOrderTargetItem', GetOrderTargetItem.bind(null, C)); lua_register(L, 'GetOrderTargetUnit', GetOrderTargetUnit.bind(null, C)); lua_register(L, 'GetSpellAbilityUnit', GetSpellAbilityUnit.bind(null, C)); lua_register(L, 'GetSpellAbilityId', GetSpellAbilityId.bind(null, C)); lua_register(L, 'GetSpellAbility', GetSpellAbility.bind(null, C)); lua_register(L, 'GetSpellTargetLoc', GetSpellTargetLoc.bind(null, C)); lua_register(L, 'GetSpellTargetX', GetSpellTargetX.bind(null, C)); lua_register(L, 'GetSpellTargetY', GetSpellTargetY.bind(null, C)); lua_register(L, 'GetSpellTargetDestructable', GetSpellTargetDestructable.bind(null, C)); lua_register(L, 'GetSpellTargetItem', GetSpellTargetItem.bind(null, C)); lua_register(L, 'GetSpellTargetUnit', GetSpellTargetUnit.bind(null, C)); lua_register(L, 'TriggerRegisterPlayerAllianceChange', TriggerRegisterPlayerAllianceChange.bind(null, C)); lua_register(L, 'TriggerRegisterPlayerStateEvent', TriggerRegisterPlayerStateEvent.bind(null, C)); lua_register(L, 'GetEventPlayerState', GetEventPlayerState.bind(null, C)); lua_register(L, 'TriggerRegisterPlayerChatEvent', TriggerRegisterPlayerChatEvent.bind(null, C)); lua_register(L, 'GetEventPlayerChatString', GetEventPlayerChatString.bind(null, C)); lua_register(L, 'GetEventPlayerChatStringMatched', GetEventPlayerChatStringMatched.bind(null, C)); lua_register(L, 'TriggerRegisterDeathEvent', TriggerRegisterDeathEvent.bind(null, C)); lua_register(L, 'GetTriggerUnit', GetTriggerUnit.bind(null, C)); lua_register(L, 'TriggerRegisterUnitStateEvent', TriggerRegisterUnitStateEvent.bind(null, C)); lua_register(L, 'GetEventUnitState', GetEventUnitState.bind(null, C)); lua_register(L, 'TriggerRegisterUnitEvent', TriggerRegisterUnitEvent.bind(null, C)); lua_register(L, 'GetEventDamage', GetEventDamage.bind(null, C)); lua_register(L, 'GetEventDamageSource', GetEventDamageSource.bind(null, C)); lua_register(L, 'GetEventDetectingPlayer', GetEventDetectingPlayer.bind(null, C)); lua_register(L, 'TriggerRegisterFilterUnitEvent', TriggerRegisterFilterUnitEvent.bind(null, C)); lua_register(L, 'GetEventTargetUnit', GetEventTargetUnit.bind(null, C)); lua_register(L, 'TriggerRegisterUnitInRange', TriggerRegisterUnitInRange.bind(null, C)); lua_register(L, 'TriggerAddCondition', TriggerAddCondition.bind(null, C)); lua_register(L, 'TriggerRemoveCondition', TriggerRemoveCondition.bind(null, C)); lua_register(L, 'TriggerClearConditions', TriggerClearConditions.bind(null, C)); lua_register(L, 'TriggerAddAction', TriggerAddAction.bind(null, C)); lua_register(L, 'TriggerRemoveAction', TriggerRemoveAction.bind(null, C)); lua_register(L, 'TriggerClearActions', TriggerClearActions.bind(null, C)); lua_register(L, 'TriggerSleepAction', TriggerSleepAction.bind(null, C)); lua_register(L, 'TriggerWaitForSound', TriggerWaitForSound.bind(null, C)); lua_register(L, 'TriggerEvaluate', TriggerEvaluate.bind(null, C)); lua_register(L, 'TriggerExecute', TriggerExecute.bind(null, C)); lua_register(L, 'TriggerExecuteWait', TriggerExecuteWait.bind(null, C)); lua_register(L, 'TriggerSyncStart', TriggerSyncStart.bind(null, C)); lua_register(L, 'TriggerSyncReady', TriggerSyncReady.bind(null, C)); lua_register(L, 'GetWidgetLife', GetWidgetLife.bind(null, C)); lua_register(L, 'SetWidgetLife', SetWidgetLife.bind(null, C)); lua_register(L, 'GetWidgetX', GetWidgetX.bind(null, C)); lua_register(L, 'GetWidgetY', GetWidgetY.bind(null, C)); lua_register(L, 'GetTriggerWidget', GetTriggerWidget.bind(null, C)); lua_register(L, 'CreateDestructable', CreateDestructable.bind(null, C)); lua_register(L, 'CreateDestructableZ', CreateDestructableZ.bind(null, C)); lua_register(L, 'CreateDeadDestructable', CreateDeadDestructable.bind(null, C)); lua_register(L, 'CreateDeadDestructableZ', CreateDeadDestructableZ.bind(null, C)); lua_register(L, 'RemoveDestructable', RemoveDestructable.bind(null, C)); lua_register(L, 'KillDestructable', KillDestructable.bind(null, C)); lua_register(L, 'SetDestructableInvulnerable', SetDestructableInvulnerable.bind(null, C)); lua_register(L, 'IsDestructableInvulnerable', IsDestructableInvulnerable.bind(null, C)); lua_register(L, 'EnumDestructablesInRect', EnumDestructablesInRect.bind(null, C)); lua_register(L, 'GetDestructableTypeId', GetDestructableTypeId.bind(null, C)); lua_register(L, 'GetDestructableX', GetDestructableX.bind(null, C)); lua_register(L, 'GetDestructableY', GetDestructableY.bind(null, C)); lua_register(L, 'SetDestructableLife', SetDestructableLife.bind(null, C)); lua_register(L, 'GetDestructableLife', GetDestructableLife.bind(null, C)); lua_register(L, 'SetDestructableMaxLife', SetDestructableMaxLife.bind(null, C)); lua_register(L, 'GetDestructableMaxLife', GetDestructableMaxLife.bind(null, C)); lua_register(L, 'DestructableRestoreLife', DestructableRestoreLife.bind(null, C)); lua_register(L, 'QueueDestructableAnimation', QueueDestructableAnimation.bind(null, C)); lua_register(L, 'SetDestructableAnimation', SetDestructableAnimation.bind(null, C)); lua_register(L, 'SetDestructableAnimationSpeed', SetDestructableAnimationSpeed.bind(null, C)); lua_register(L, 'ShowDestructable', ShowDestructable.bind(null, C)); lua_register(L, 'GetDestructableOccluderHeight', GetDestructableOccluderHeight.bind(null, C)); lua_register(L, 'SetDestructableOccluderHeight', SetDestructableOccluderHeight.bind(null, C)); lua_register(L, 'GetDestructableName', GetDestructableName.bind(null, C)); lua_register(L, 'GetTriggerDestructable', GetTriggerDestructable.bind(null, C)); lua_register(L, 'CreateItem', CreateItem.bind(null, C)); lua_register(L, 'RemoveItem', RemoveItem.bind(null, C)); lua_register(L, 'GetItemPlayer', GetItemPlayer.bind(null, C)); lua_register(L, 'GetItemTypeId', GetItemTypeId.bind(null, C)); lua_register(L, 'GetItemX', GetItemX.bind(null, C)); lua_register(L, 'GetItemY', GetItemY.bind(null, C)); lua_register(L, 'SetItemPosition', SetItemPosition.bind(null, C)); lua_register(L, 'SetItemDropOnDeath', SetItemDropOnDeath.bind(null, C)); lua_register(L, 'SetItemDroppable', SetItemDroppable.bind(null, C)); lua_register(L, 'SetItemPawnable', SetItemPawnable.bind(null, C)); lua_register(L, 'SetItemPlayer', SetItemPlayer.bind(null, C)); lua_register(L, 'SetItemInvulnerable', SetItemInvulnerable.bind(null, C)); lua_register(L, 'IsItemInvulnerable', IsItemInvulnerable.bind(null, C)); lua_register(L, 'SetItemVisible', SetItemVisible.bind(null, C)); lua_register(L, 'IsItemVisible', IsItemVisible.bind(null, C)); lua_register(L, 'IsItemOwned', IsItemOwned.bind(null, C)); lua_register(L, 'IsItemPowerup', IsItemPowerup.bind(null, C)); lua_register(L, 'IsItemSellable', IsItemSellable.bind(null, C)); lua_register(L, 'IsItemPawnable', IsItemPawnable.bind(null, C)); lua_register(L, 'IsItemIdPowerup', IsItemIdPowerup.bind(null, C)); lua_register(L, 'IsItemIdSellable', IsItemIdSellable.bind(null, C)); lua_register(L, 'IsItemIdPawnable', IsItemIdPawnable.bind(null, C)); lua_register(L, 'EnumItemsInRect', EnumItemsInRect.bind(null, C)); lua_register(L, 'GetItemLevel', GetItemLevel.bind(null, C)); lua_register(L, 'GetItemType', GetItemType.bind(null, C)); lua_register(L, 'SetItemDropID', SetItemDropID.bind(null, C)); lua_register(L, 'GetItemName', GetItemName.bind(null, C)); lua_register(L, 'GetItemCharges', GetItemCharges.bind(null, C)); lua_register(L, 'SetItemCharges', SetItemCharges.bind(null, C)); lua_register(L, 'GetItemUserData', GetItemUserData.bind(null, C)); lua_register(L, 'SetItemUserData', SetItemUserData.bind(null, C)); lua_register(L, 'CreateUnit', CreateUnit.bind(null, C)); lua_register(L, 'CreateUnitByName', CreateUnitByName.bind(null, C)); lua_register(L, 'CreateUnitAtLoc', CreateUnitAtLoc.bind(null, C)); lua_register(L, 'CreateUnitAtLocByName', CreateUnitAtLocByName.bind(null, C)); lua_register(L, 'CreateCorpse', CreateCorpse.bind(null, C)); lua_register(L, 'KillUnit', KillUnit.bind(null, C)); lua_register(L, 'RemoveUnit', RemoveUnit.bind(null, C)); lua_register(L, 'ShowUnit', ShowUnit.bind(null, C)); lua_register(L, 'SetUnitState', SetUnitState.bind(null, C)); lua_register(L, 'SetUnitX', SetUnitX.bind(null, C)); lua_register(L, 'SetUnitY', SetUnitY.bind(null, C)); lua_register(L, 'SetUnitPosition', SetUnitPosition.bind(null, C)); lua_register(L, 'SetUnitPositionLoc', SetUnitPositionLoc.bind(null, C)); lua_register(L, 'SetUnitFacing', SetUnitFacing.bind(null, C)); lua_register(L, 'SetUnitFacingTimed', SetUnitFacingTimed.bind(null, C)); lua_register(L, 'SetUnitMoveSpeed', SetUnitMoveSpeed.bind(null, C)); lua_register(L, 'SetUnitFlyHeight', SetUnitFlyHeight.bind(null, C)); lua_register(L, 'SetUnitTurnSpeed', SetUnitTurnSpeed.bind(null, C)); lua_register(L, 'SetUnitPropWindow', SetUnitPropWindow.bind(null, C)); lua_register(L, 'SetUnitAcquireRange', SetUnitAcquireRange.bind(null, C)); lua_register(L, 'SetUnitCreepGuard', SetUnitCreepGuard.bind(null, C)); lua_register(L, 'GetUnitAcquireRange', GetUnitAcquireRange.bind(null, C)); lua_register(L, 'GetUnitTurnSpeed', GetUnitTurnSpeed.bind(null, C)); lua_register(L, 'GetUnitPropWindow', GetUnitPropWindow.bind(null, C)); lua_register(L, 'GetUnitFlyHeight', GetUnitFlyHeight.bind(null, C)); lua_register(L, 'GetUnitDefaultAcquireRange', GetUnitDefaultAcquireRange.bind(null, C)); lua_register(L, 'GetUnitDefaultTurnSpeed', GetUnitDefaultTurnSpeed.bind(null, C)); lua_register(L, 'GetUnitDefaultPropWindow', GetUnitDefaultPropWindow.bind(null, C)); lua_register(L, 'GetUnitDefaultFlyHeight', GetUnitDefaultFlyHeight.bind(null, C)); lua_register(L, 'SetUnitOwner', SetUnitOwner.bind(null, C)); lua_register(L, 'SetUnitColor', SetUnitColor.bind(null, C)); lua_register(L, 'SetUnitScale', SetUnitScale.bind(null, C)); lua_register(L, 'SetUnitTimeScale', SetUnitTimeScale.bind(null, C)); lua_register(L, 'SetUnitBlendTime', SetUnitBlendTime.bind(null, C)); lua_register(L, 'SetUnitVertexColor', SetUnitVertexColor.bind(null, C)); lua_register(L, 'QueueUnitAnimation', QueueUnitAnimation.bind(null, C)); lua_register(L, 'SetUnitAnimation', SetUnitAnimation.bind(null, C)); lua_register(L, 'SetUnitAnimationByIndex', SetUnitAnimationByIndex.bind(null, C)); lua_register(L, 'SetUnitAnimationWithRarity', SetUnitAnimationWithRarity.bind(null, C)); lua_register(L, 'AddUnitAnimationProperties', AddUnitAnimationProperties.bind(null, C)); lua_register(L, 'SetUnitLookAt', SetUnitLookAt.bind(null, C)); lua_register(L, 'ResetUnitLookAt', ResetUnitLookAt.bind(null, C)); lua_register(L, 'SetUnitRescuable', SetUnitRescuable.bind(null, C)); lua_register(L, 'SetUnitRescueRange', SetUnitRescueRange.bind(null, C)); lua_register(L, 'SetHeroStr', SetHeroStr.bind(null, C)); lua_register(L, 'SetHeroAgi', SetHeroAgi.bind(null, C)); lua_register(L, 'SetHeroInt', SetHeroInt.bind(null, C)); lua_register(L, 'GetHeroStr', GetHeroStr.bind(null, C)); lua_register(L, 'GetHeroAgi', GetHeroAgi.bind(null, C)); lua_register(L, 'GetHeroInt', GetHeroInt.bind(null, C)); lua_register(L, 'UnitStripHeroLevel', UnitStripHeroLevel.bind(null, C)); lua_register(L, 'GetHeroXP', GetHeroXP.bind(null, C)); lua_register(L, 'SetHeroXP', SetHeroXP.bind(null, C)); lua_register(L, 'GetHeroSkillPoints', GetHeroSkillPoints.bind(null, C)); lua_register(L, 'UnitModifySkillPoints', UnitModifySkillPoints.bind(null, C)); lua_register(L, 'AddHeroXP', AddHeroXP.bind(null, C)); lua_register(L, 'SetHeroLevel', SetHeroLevel.bind(null, C)); lua_register(L, 'GetHeroLevel', GetHeroLevel.bind(null, C)); lua_register(L, 'GetUnitLevel', GetUnitLevel.bind(null, C)); lua_register(L, 'GetHeroProperName', GetHeroProperName.bind(null, C)); lua_register(L, 'SuspendHeroXP', SuspendHeroXP.bind(null, C)); lua_register(L, 'IsSuspendedXP', IsSuspendedXP.bind(null, C)); lua_register(L, 'SelectHeroSkill', SelectHeroSkill.bind(null, C)); lua_register(L, 'GetUnitAbilityLevel', GetUnitAbilityLevel.bind(null, C)); lua_register(L, 'DecUnitAbilityLevel', DecUnitAbilityLevel.bind(null, C)); lua_register(L, 'IncUnitAbilityLevel', IncUnitAbilityLevel.bind(null, C)); lua_register(L, 'SetUnitAbilityLevel', SetUnitAbilityLevel.bind(null, C)); lua_register(L, 'ReviveHero', ReviveHero.bind(null, C)); lua_register(L, 'ReviveHeroLoc', ReviveHeroLoc.bind(null, C)); lua_register(L, 'SetUnitExploded', SetUnitExploded.bind(null, C)); lua_register(L, 'SetUnitInvulnerable', SetUnitInvulnerable.bind(null, C)); lua_register(L, 'PauseUnit', PauseUnit.bind(null, C)); lua_register(L, 'IsUnitPaused', IsUnitPaused.bind(null, C)); lua_register(L, 'SetUnitPathing', SetUnitPathing.bind(null, C)); lua_register(L, 'ClearSelection', ClearSelection.bind(null, C)); lua_register(L, 'SelectUnit', SelectUnit.bind(null, C)); lua_register(L, 'GetUnitPointValue', GetUnitPointValue.bind(null, C)); lua_register(L, 'GetUnitPointValueByType', GetUnitPointValueByType.bind(null, C)); lua_register(L, 'UnitAddItem', UnitAddItem.bind(null, C)); lua_register(L, 'UnitAddItemById', UnitAddItemById.bind(null, C)); lua_register(L, 'UnitAddItemToSlotById', UnitAddItemToSlotById.bind(null, C)); lua_register(L, 'UnitRemoveItem', UnitRemoveItem.bind(null, C)); lua_register(L, 'UnitRemoveItemFromSlot', UnitRemoveItemFromSlot.bind(null, C)); lua_register(L, 'UnitHasItem', UnitHasItem.bind(null, C)); lua_register(L, 'UnitItemInSlot', UnitItemInSlot.bind(null, C)); lua_register(L, 'UnitInventorySize', UnitInventorySize.bind(null, C)); lua_register(L, 'UnitDropItemPoint', UnitDropItemPoint.bind(null, C)); lua_register(L, 'UnitDropItemSlot', UnitDropItemSlot.bind(null, C)); lua_register(L, 'UnitDropItemTarget', UnitDropItemTarget.bind(null, C)); lua_register(L, 'UnitUseItem', UnitUseItem.bind(null, C)); lua_register(L, 'UnitUseItemPoint', UnitUseItemPoint.bind(null, C)); lua_register(L, 'UnitUseItemTarget', UnitUseItemTarget.bind(null, C)); lua_register(L, 'GetUnitX', GetUnitX.bind(null, C)); lua_register(L, 'GetUnitY', GetUnitY.bind(null, C)); lua_register(L, 'GetUnitLoc', GetUnitLoc.bind(null, C)); lua_register(L, 'GetUnitFacing', GetUnitFacing.bind(null, C)); lua_register(L, 'GetUnitMoveSpeed', GetUnitMoveSpeed.bind(null, C)); lua_register(L, 'GetUnitDefaultMoveSpeed', GetUnitDefaultMoveSpeed.bind(null, C)); lua_register(L, 'GetUnitState', GetUnitState.bind(null, C)); lua_register(L, 'GetOwningPlayer', GetOwningPlayer.bind(null, C)); lua_register(L, 'GetUnitTypeId', GetUnitTypeId.bind(null, C)); lua_register(L, 'GetUnitRace', GetUnitRace.bind(null, C)); lua_register(L, 'GetUnitName', GetUnitName.bind(null, C)); lua_register(L, 'GetUnitFoodUsed', GetUnitFoodUsed.bind(null, C)); lua_register(L, 'GetUnitFoodMade', GetUnitFoodMade.bind(null, C)); lua_register(L, 'GetFoodMade', GetFoodMade.bind(null, C)); lua_register(L, 'GetFoodUsed', GetFoodUsed.bind(null, C)); lua_register(L, 'SetUnitUseFood', SetUnitUseFood.bind(null, C)); lua_register(L, 'GetUnitRallyPoint', GetUnitRallyPoint.bind(null, C)); lua_register(L, 'GetUnitRallyUnit', GetUnitRallyUnit.bind(null, C)); lua_register(L, 'GetUnitRallyDestructable', GetUnitRallyDestructable.bind(null, C)); lua_register(L, 'IsUnitInGroup', IsUnitInGroup.bind(null, C)); lua_register(L, 'IsUnitInForce', IsUnitInForce.bind(null, C)); lua_register(L, 'IsUnitOwnedByPlayer', IsUnitOwnedByPlayer.bind(null, C)); lua_register(L, 'IsUnitAlly', IsUnitAlly.bind(null, C)); lua_register(L, 'IsUnitEnemy', IsUnitEnemy.bind(null, C)); lua_register(L, 'IsUnitVisible', IsUnitVisible.bind(null, C)); lua_register(L, 'IsUnitDetected', IsUnitDetected.bind(null, C)); lua_register(L, 'IsUnitInvisible', IsUnitInvisible.bind(null, C)); lua_register(L, 'IsUnitFogged', IsUnitFogged.bind(null, C)); lua_register(L, 'IsUnitMasked', IsUnitMasked.bind(null, C)); lua_register(L, 'IsUnitSelected', IsUnitSelected.bind(null, C)); lua_register(L, 'IsUnitRace', IsUnitRace.bind(null, C)); lua_register(L, 'IsUnitType', IsUnitType.bind(null, C)); lua_register(L, 'IsUnit', IsUnit.bind(null, C)); lua_register(L, 'IsUnitInRange', IsUnitInRange.bind(null, C)); lua_register(L, 'IsUnitInRangeXY', IsUnitInRangeXY.bind(null, C)); lua_register(L, 'IsUnitInRangeLoc', IsUnitInRangeLoc.bind(null, C)); lua_register(L, 'IsUnitHidden', IsUnitHidden.bind(null, C)); lua_register(L, 'IsUnitIllusion', IsUnitIllusion.bind(null, C)); lua_register(L, 'IsUnitInTransport', IsUnitInTransport.bind(null, C)); lua_register(L, 'IsUnitLoaded', IsUnitLoaded.bind(null, C)); lua_register(L, 'IsHeroUnitId', IsHeroUnitId.bind(null, C)); lua_register(L, 'IsUnitIdType', IsUnitIdType.bind(null, C)); lua_register(L, 'UnitShareVision', UnitShareVision.bind(null, C)); lua_register(L, 'UnitSuspendDecay', UnitSuspendDecay.bind(null, C)); lua_register(L, 'UnitAddType', UnitAddType.bind(null, C)); lua_register(L, 'UnitRemoveType', UnitRemoveType.bind(null, C)); lua_register(L, 'UnitAddAbility', UnitAddAbility.bind(null, C)); lua_register(L, 'UnitRemoveAbility', UnitRemoveAbility.bind(null, C)); lua_register(L, 'UnitMakeAbilityPermanent', UnitMakeAbilityPermanent.bind(null, C)); lua_register(L, 'UnitRemoveBuffs', UnitRemoveBuffs.bind(null, C)); lua_register(L, 'UnitRemoveBuffsEx', UnitRemoveBuffsEx.bind(null, C)); lua_register(L, 'UnitHasBuffsEx', UnitHasBuffsEx.bind(null, C)); lua_register(L, 'UnitCountBuffsEx', UnitCountBuffsEx.bind(null, C)); lua_register(L, 'UnitAddSleep', UnitAddSleep.bind(null, C)); lua_register(L, 'UnitCanSleep', UnitCanSleep.bind(null, C)); lua_register(L, 'UnitAddSleepPerm', UnitAddSleepPerm.bind(null, C)); lua_register(L, 'UnitCanSleepPerm', UnitCanSleepPerm.bind(null, C)); lua_register(L, 'UnitIsSleeping', UnitIsSleeping.bind(null, C)); lua_register(L, 'UnitWakeUp', UnitWakeUp.bind(null, C)); lua_register(L, 'UnitApplyTimedLife', UnitApplyTimedLife.bind(null, C)); lua_register(L, 'UnitIgnoreAlarm', UnitIgnoreAlarm.bind(null, C)); lua_register(L, 'UnitIgnoreAlarmToggled', UnitIgnoreAlarmToggled.bind(null, C)); lua_register(L, 'UnitResetCooldown', UnitResetCooldown.bind(null, C)); lua_register(L, 'UnitSetConstructionProgress', UnitSetConstructionProgress.bind(null, C)); lua_register(L, 'UnitSetUpgradeProgress', UnitSetUpgradeProgress.bind(null, C)); lua_register(L, 'UnitPauseTimedLife', UnitPauseTimedLife.bind(null, C)); lua_register(L, 'UnitSetUsesAltIcon', UnitSetUsesAltIcon.bind(null, C)); lua_register(L, 'UnitDamagePoint', UnitDamagePoint.bind(null, C)); lua_register(L, 'UnitDamageTarget', UnitDamageTarget.bind(null, C)); lua_register(L, 'IssueImmediateOrder', IssueImmediateOrder.bind(null, C)); lua_register(L, 'IssueImmediateOrderById', IssueImmediateOrderById.bind(null, C)); lua_register(L, 'IssuePointOrder', IssuePointOrder.bind(null, C)); lua_register(L, 'IssuePointOrderLoc', IssuePointOrderLoc.bind(null, C)); lua_register(L, 'IssuePointOrderById', IssuePointOrderById.bind(null, C)); lua_register(L, 'IssuePointOrderByIdLoc', IssuePointOrderByIdLoc.bind(null, C)); lua_register(L, 'IssueTargetOrder', IssueTargetOrder.bind(null, C)); lua_register(L, 'IssueTargetOrderById', IssueTargetOrderById.bind(null, C)); lua_register(L, 'IssueInstantPointOrder', IssueInstantPointOrder.bind(null, C)); lua_register(L, 'IssueInstantPointOrderById', IssueInstantPointOrderById.bind(null, C)); lua_register(L, 'IssueInstantTargetOrder', IssueInstantTargetOrder.bind(null, C)); lua_register(L, 'IssueInstantTargetOrderById', IssueInstantTargetOrderById.bind(null, C)); lua_register(L, 'IssueBuildOrder', IssueBuildOrder.bind(null, C)); lua_register(L, 'IssueBuildOrderById', IssueBuildOrderById.bind(null, C)); lua_register(L, 'IssueNeutralImmediateOrder', IssueNeutralImmediateOrder.bind(null, C)); lua_register(L, 'IssueNeutralImmediateOrderById', IssueNeutralImmediateOrderById.bind(null, C)); lua_register(L, 'IssueNeutralPointOrder', IssueNeutralPointOrder.bind(null, C)); lua_register(L, 'IssueNeutralPointOrderById', IssueNeutralPointOrderById.bind(null, C)); lua_register(L, 'IssueNeutralTargetOrder', IssueNeutralTargetOrder.bind(null, C)); lua_register(L, 'IssueNeutralTargetOrderById', IssueNeutralTargetOrderById.bind(null, C)); lua_register(L, 'GetUnitCurrentOrder', GetUnitCurrentOrder.bind(null, C)); lua_register(L, 'SetResourceAmount', SetResourceAmount.bind(null, C)); lua_register(L, 'AddResourceAmount', AddResourceAmount.bind(null, C)); lua_register(L, 'GetResourceAmount', GetResourceAmount.bind(null, C)); lua_register(L, 'WaygateGetDestinationX', WaygateGetDestinationX.bind(null, C)); lua_register(L, 'WaygateGetDestinationY', WaygateGetDestinationY.bind(null, C)); lua_register(L, 'WaygateSetDestination', WaygateSetDestination.bind(null, C)); lua_register(L, 'WaygateActivate', WaygateActivate.bind(null, C)); lua_register(L, 'WaygateIsActive', WaygateIsActive.bind(null, C)); lua_register(L, 'AddItemToAllStock', AddItemToAllStock.bind(null, C)); lua_register(L, 'AddItemToStock', AddItemToStock.bind(null, C)); lua_register(L, 'AddUnitToAllStock', AddUnitToAllStock.bind(null, C)); lua_register(L, 'AddUnitToStock', AddUnitToStock.bind(null, C)); lua_register(L, 'RemoveItemFromAllStock', RemoveItemFromAllStock.bind(null, C)); lua_register(L, 'RemoveItemFromStock', RemoveItemFromStock.bind(null, C)); lua_register(L, 'RemoveUnitFromAllStock', RemoveUnitFromAllStock.bind(null, C)); lua_register(L, 'RemoveUnitFromStock', RemoveUnitFromStock.bind(null, C)); lua_register(L, 'SetAllItemTypeSlots', SetAllItemTypeSlots.bind(null, C)); lua_register(L, 'SetAllUnitTypeSlots', SetAllUnitTypeSlots.bind(null, C)); lua_register(L, 'SetItemTypeSlots', SetItemTypeSlots.bind(null, C)); lua_register(L, 'SetUnitTypeSlots', SetUnitTypeSlots.bind(null, C)); lua_register(L, 'GetUnitUserData', GetUnitUserData.bind(null, C)); lua_register(L, 'SetUnitUserData', SetUnitUserData.bind(null, C)); lua_register(L, 'Player', Player.bind(null, C)); lua_register(L, 'GetLocalPlayer', GetLocalPlayer.bind(null, C)); lua_register(L, 'IsPlayerAlly', IsPlayerAlly.bind(null, C)); lua_register(L, 'IsPlayerEnemy', IsPlayerEnemy.bind(null, C)); lua_register(L, 'IsPlayerInForce', IsPlayerInForce.bind(null, C)); lua_register(L, 'IsPlayerObserver', IsPlayerObserver.bind(null, C)); lua_register(L, 'IsVisibleToPlayer', IsVisibleToPlayer.bind(null, C)); lua_register(L, 'IsLocationVisibleToPlayer', IsLocationVisibleToPlayer.bind(null, C)); lua_register(L, 'IsFoggedToPlayer', IsFoggedToPlayer.bind(null, C)); lua_register(L, 'IsLocationFoggedToPlayer', IsLocationFoggedToPlayer.bind(null, C)); lua_register(L, 'IsMaskedToPlayer', IsMaskedToPlayer.bind(null, C)); lua_register(L, 'IsLocationMaskedToPlayer', IsLocationMaskedToPlayer.bind(null, C)); lua_register(L, 'GetPlayerRace', GetPlayerRace.bind(null, C)); lua_register(L, 'GetPlayerId', GetPlayerId.bind(null, C)); lua_register(L, 'GetPlayerUnitCount', GetPlayerUnitCount.bind(null, C)); lua_register(L, 'GetPlayerTypedUnitCount', GetPlayerTypedUnitCount.bind(null, C)); lua_register(L, 'GetPlayerStructureCount', GetPlayerStructureCount.bind(null, C)); lua_register(L, 'GetPlayerState', GetPlayerState.bind(null, C)); lua_register(L, 'GetPlayerScore', GetPlayerScore.bind(null, C)); lua_register(L, 'GetPlayerAlliance', GetPlayerAlliance.bind(null, C)); lua_register(L, 'GetPlayerHandicap', GetPlayerHandicap.bind(null, C)); lua_register(L, 'GetPlayerHandicapXP', GetPlayerHandicapXP.bind(null, C)); lua_register(L, 'SetPlayerHandicap', SetPlayerHandicap.bind(null, C)); lua_register(L, 'SetPlayerHandicapXP', SetPlayerHandicapXP.bind(null, C)); lua_register(L, 'SetPlayerTechMaxAllowed', SetPlayerTechMaxAllowed.bind(null, C)); lua_register(L, 'GetPlayerTechMaxAllowed', GetPlayerTechMaxAllowed.bind(null, C)); lua_register(L, 'AddPlayerTechResearched', AddPlayerTechResearched.bind(null, C)); lua_register(L, 'SetPlayerTechResearched', SetPlayerTechResearched.bind(null, C)); lua_register(L, 'GetPlayerTechResearched', GetPlayerTechResearched.bind(null, C)); lua_register(L, 'GetPlayerTechCount', GetPlayerTechCount.bind(null, C)); lua_register(L, 'SetPlayerUnitsOwner', SetPlayerUnitsOwner.bind(null, C)); lua_register(L, 'CripplePlayer', CripplePlayer.bind(null, C)); lua_register(L, 'SetPlayerAbilityAvailable', SetPlayerAbilityAvailable.bind(null, C)); lua_register(L, 'SetPlayerState', SetPlayerState.bind(null, C)); lua_register(L, 'RemovePlayer', RemovePlayer.bind(null, C)); lua_register(L, 'CachePlayerHeroData', CachePlayerHeroData.bind(null, C)); lua_register(L, 'SetFogStateRect', SetFogStateRect.bind(null, C)); lua_register(L, 'SetFogStateRadius', SetFogStateRadius.bind(null, C)); lua_register(L, 'SetFogStateRadiusLoc', SetFogStateRadiusLoc.bind(null, C)); lua_register(L, 'FogMaskEnable', FogMaskEnable.bind(null, C)); lua_register(L, 'IsFogMaskEnabled', IsFogMaskEnabled.bind(null, C)); lua_register(L, 'FogEnable', FogEnable.bind(null, C)); lua_register(L, 'IsFogEnabled', IsFogEnabled.bind(null, C)); lua_register(L, 'CreateFogModifierRect', CreateFogModifierRect.bind(null, C)); lua_register(L, 'CreateFogModifierRadius', CreateFogModifierRadius.bind(null, C)); lua_register(L, 'CreateFogModifierRadiusLoc', CreateFogModifierRadiusLoc.bind(null, C)); lua_register(L, 'DestroyFogModifier', DestroyFogModifier.bind(null, C)); lua_register(L, 'FogModifierStart', FogModifierStart.bind(null, C)); lua_register(L, 'FogModifierStop', FogModifierStop.bind(null, C)); lua_register(L, 'VersionGet', VersionGet.bind(null, C)); lua_register(L, 'VersionCompatible', VersionCompatible.bind(null, C)); lua_register(L, 'VersionSupported', VersionSupported.bind(null, C)); lua_register(L, 'EndGame', EndGame.bind(null, C)); lua_register(L, 'ChangeLevel', ChangeLevel.bind(null, C)); lua_register(L, 'RestartGame', RestartGame.bind(null, C)); lua_register(L, 'ReloadGame', ReloadGame.bind(null, C)); lua_register(L, 'SetCampaignMenuRace', SetCampaignMenuRace.bind(null, C)); lua_register(L, 'SetCampaignMenuRaceEx', SetCampaignMenuRaceEx.bind(null, C)); lua_register(L, 'ForceCampaignSelectScreen', ForceCampaignSelectScreen.bind(null, C)); lua_register(L, 'LoadGame', LoadGame.bind(null, C)); lua_register(L, 'SaveGame', SaveGame.bind(null, C)); lua_register(L, 'RenameSaveDirectory', RenameSaveDirectory.bind(null, C)); lua_register(L, 'RemoveSaveDirectory', RemoveSaveDirectory.bind(null, C)); lua_register(L, 'CopySaveGame', CopySaveGame.bind(null, C)); lua_register(L, 'SaveGameExists', SaveGameExists.bind(null, C)); lua_register(L, 'SyncSelections', SyncSelections.bind(null, C)); lua_register(L, 'SetFloatGameState', SetFloatGameState.bind(null, C)); lua_register(L, 'GetFloatGameState', GetFloatGameState.bind(null, C)); lua_register(L, 'SetIntegerGameState', SetIntegerGameState.bind(null, C)); lua_register(L, 'GetIntegerGameState', GetIntegerGameState.bind(null, C)); lua_register(L, 'SetTutorialCleared', SetTutorialCleared.bind(null, C)); lua_register(L, 'SetMissionAvailable', SetMissionAvailable.bind(null, C)); lua_register(L, 'SetCampaignAvailable', SetCampaignAvailable.bind(null, C)); lua_register(L, 'SetOpCinematicAvailable', SetOpCinematicAvailable.bind(null, C)); lua_register(L, 'SetEdCinematicAvailable', SetEdCinematicAvailable.bind(null, C)); lua_register(L, 'GetDefaultDifficulty', GetDefaultDifficulty.bind(null, C)); lua_register(L, 'SetDefaultDifficulty', SetDefaultDifficulty.bind(null, C)); lua_register(L, 'SetCustomCampaignButtonVisible', SetCustomCampaignButtonVisible.bind(null, C)); lua_register(L, 'GetCustomCampaignButtonVisible', GetCustomCampaignButtonVisible.bind(null, C)); lua_register(L, 'DoNotSaveReplay', DoNotSaveReplay.bind(null, C)); lua_register(L, 'DialogCreate', DialogCreate.bind(null, C)); lua_register(L, 'DialogDestroy', DialogDestroy.bind(null, C)); lua_register(L, 'DialogClear', DialogClear.bind(null, C)); lua_register(L, 'DialogSetMessage', DialogSetMessage.bind(null, C)); lua_register(L, 'DialogAddButton', DialogAddButton.bind(null, C)); lua_register(L, 'DialogAddQuitButton', DialogAddQuitButton.bind(null, C)); lua_register(L, 'DialogDisplay', DialogDisplay.bind(null, C)); lua_register(L, 'ReloadGameCachesFromDisk', ReloadGameCachesFromDisk.bind(null, C)); lua_register(L, 'InitGameCache', InitGameCache.bind(null, C)); lua_register(L, 'SaveGameCache', SaveGameCache.bind(null, C)); lua_register(L, 'StoreInteger', StoreInteger.bind(null, C)); lua_register(L, 'StoreReal', StoreReal.bind(null, C)); lua_register(L, 'StoreBoolean', StoreBoolean.bind(null, C)); lua_register(L, 'StoreUnit', StoreUnit.bind(null, C)); lua_register(L, 'StoreString', StoreString.bind(null, C)); lua_register(L, 'SyncStoredInteger', SyncStoredInteger.bind(null, C)); lua_register(L, 'SyncStoredReal', SyncStoredReal.bind(null, C)); lua_register(L, 'SyncStoredBoolean', SyncStoredBoolean.bind(null, C)); lua_register(L, 'SyncStoredUnit', SyncStoredUnit.bind(null, C)); lua_register(L, 'SyncStoredString', SyncStoredString.bind(null, C)); lua_register(L, 'HaveStoredInteger', HaveStoredInteger.bind(null, C)); lua_register(L, 'HaveStoredReal', HaveStoredReal.bind(null, C)); lua_register(L, 'HaveStoredBoolean', HaveStoredBoolean.bind(null, C)); lua_register(L, 'HaveStoredUnit', HaveStoredUnit.bind(null, C)); lua_register(L, 'HaveStoredString', HaveStoredString.bind(null, C)); lua_register(L, 'FlushGameCache', FlushGameCache.bind(null, C)); lua_register(L, 'FlushStoredMission', FlushStoredMission.bind(null, C)); lua_register(L, 'FlushStoredInteger', FlushStoredInteger.bind(null, C)); lua_register(L, 'FlushStoredReal', FlushStoredReal.bind(null, C)); lua_register(L, 'FlushStoredBoolean', FlushStoredBoolean.bind(null, C)); lua_register(L, 'FlushStoredUnit', FlushStoredUnit.bind(null, C)); lua_register(L, 'FlushStoredString', FlushStoredString.bind(null, C)); lua_register(L, 'GetStoredInteger', GetStoredInteger.bind(null, C)); lua_register(L, 'GetStoredReal', GetStoredReal.bind(null, C)); lua_register(L, 'GetStoredBoolean', GetStoredBoolean.bind(null, C)); lua_register(L, 'GetStoredString', GetStoredString.bind(null, C)); lua_register(L, 'RestoreUnit', RestoreUnit.bind(null, C)); lua_register(L, 'InitHashtable', InitHashtable.bind(null, C)); lua_register(L, 'SaveInteger', SaveInteger.bind(null, C)); lua_register(L, 'SaveReal', SaveReal.bind(null, C)); lua_register(L, 'SaveBoolean', SaveBoolean.bind(null, C)); lua_register(L, 'SaveStr', SaveStr.bind(null, C)); lua_register(L, 'SavePlayerHandle', SavePlayerHandle.bind(null, C)); lua_register(L, 'SaveWidgetHandle', SaveWidgetHandle.bind(null, C)); lua_register(L, 'SaveDestructableHandle', SaveDestructableHandle.bind(null, C)); lua_register(L, 'SaveItemHandle', SaveItemHandle.bind(null, C)); lua_register(L, 'SaveUnitHandle', SaveUnitHandle.bind(null, C)); lua_register(L, 'SaveAbilityHandle', SaveAbilityHandle.bind(null, C)); lua_register(L, 'SaveTimerHandle', SaveTimerHandle.bind(null, C)); lua_register(L, 'SaveTriggerHandle', SaveTriggerHandle.bind(null, C)); lua_register(L, 'SaveTriggerConditionHandle', SaveTriggerConditionHandle.bind(null, C)); lua_register(L, 'SaveTriggerActionHandle', SaveTriggerActionHandle.bind(null, C)); lua_register(L, 'SaveTriggerEventHandle', SaveTriggerEventHandle.bind(null, C)); lua_register(L, 'SaveForceHandle', SaveForceHandle.bind(null, C)); lua_register(L, 'SaveGroupHandle', SaveGroupHandle.bind(null, C)); lua_register(L, 'SaveLocationHandle', SaveLocationHandle.bind(null, C)); lua_register(L, 'SaveRectHandle', SaveRectHandle.bind(null, C)); lua_register(L, 'SaveBooleanExprHandle', SaveBooleanExprHandle.bind(null, C)); lua_register(L, 'SaveSoundHandle', SaveSoundHandle.bind(null, C)); lua_register(L, 'SaveEffectHandle', SaveEffectHandle.bind(null, C)); lua_register(L, 'SaveUnitPoolHandle', SaveUnitPoolHandle.bind(null, C)); lua_register(L, 'SaveItemPoolHandle', SaveItemPoolHandle.bind(null, C)); lua_register(L, 'SaveQuestHandle', SaveQuestHandle.bind(null, C)); lua_register(L, 'SaveQuestItemHandle', SaveQuestItemHandle.bind(null, C)); lua_register(L, 'SaveDefeatConditionHandle', SaveDefeatConditionHandle.bind(null, C)); lua_register(L, 'SaveTimerDialogHandle', SaveTimerDialogHandle.bind(null, C)); lua_register(L, 'SaveLeaderboardHandle', SaveLeaderboardHandle.bind(null, C)); lua_register(L, 'SaveMultiboardHandle', SaveMultiboardHandle.bind(null, C)); lua_register(L, 'SaveMultiboardItemHandle', SaveMultiboardItemHandle.bind(null, C)); lua_register(L, 'SaveTrackableHandle', SaveTrackableHandle.bind(null, C)); lua_register(L, 'SaveDialogHandle', SaveDialogHandle.bind(null, C)); lua_register(L, 'SaveButtonHandle', SaveButtonHandle.bind(null, C)); lua_register(L, 'SaveTextTagHandle', SaveTextTagHandle.bind(null, C)); lua_register(L, 'SaveLightningHandle', SaveLightningHandle.bind(null, C)); lua_register(L, 'SaveImageHandle', SaveImageHandle.bind(null, C)); lua_register(L, 'SaveUbersplatHandle', SaveUbersplatHandle.bind(null, C)); lua_register(L, 'SaveRegionHandle', SaveRegionHandle.bind(null, C)); lua_register(L, 'SaveFogStateHandle', SaveFogStateHandle.bind(null, C)); lua_register(L, 'SaveFogModifierHandle', SaveFogModifierHandle.bind(null, C)); lua_register(L, 'SaveAgentHandle', SaveAgentHandle.bind(null, C)); lua_register(L, 'SaveHashtableHandle', SaveHashtableHandle.bind(null, C)); lua_register(L, 'LoadInteger', LoadInteger.bind(null, C)); lua_register(L, 'LoadReal', LoadReal.bind(null, C)); lua_register(L, 'LoadBoolean', LoadBoolean.bind(null, C)); lua_register(L, 'LoadStr', LoadStr.bind(null, C)); lua_register(L, 'LoadPlayerHandle', LoadPlayerHandle.bind(null, C)); lua_register(L, 'LoadWidgetHandle', LoadWidgetHandle.bind(null, C)); lua_register(L, 'LoadDestructableHandle', LoadDestructableHandle.bind(null, C)); lua_register(L, 'LoadItemHandle', LoadItemHandle.bind(null, C)); lua_register(L, 'LoadUnitHandle', LoadUnitHandle.bind(null, C)); lua_register(L, 'LoadAbilityHandle', LoadAbilityHandle.bind(null, C)); lua_register(L, 'LoadTimerHandle', LoadTimerHandle.bind(null, C)); lua_register(L, 'LoadTriggerHandle', LoadTriggerHandle.bind(null, C)); lua_register(L, 'LoadTriggerConditionHandle', LoadTriggerConditionHandle.bind(null, C)); lua_register(L, 'LoadTriggerActionHandle', LoadTriggerActionHandle.bind(null, C)); lua_register(L, 'LoadTriggerEventHandle', LoadTriggerEventHandle.bind(null, C)); lua_register(L, 'LoadForceHandle', LoadForceHandle.bind(null, C)); lua_register(L, 'LoadGroupHandle', LoadGroupHandle.bind(null, C)); lua_register(L, 'LoadLocationHandle', LoadLocationHandle.bind(null, C)); lua_register(L, 'LoadRectHandle', LoadRectHandle.bind(null, C)); lua_register(L, 'LoadBooleanExprHandle', LoadBooleanExprHandle.bind(null, C)); lua_register(L, 'LoadSoundHandle', LoadSoundHandle.bind(null, C)); lua_register(L, 'LoadEffectHandle', LoadEffectHandle.bind(null, C)); lua_register(L, 'LoadUnitPoolHandle', LoadUnitPoolHandle.bind(null, C)); lua_register(L, 'LoadItemPoolHandle', LoadItemPoolHandle.bind(null, C)); lua_register(L, 'LoadQuestHandle', LoadQuestHandle.bind(null, C)); lua_register(L, 'LoadQuestItemHandle', LoadQuestItemHandle.bind(null, C)); lua_register(L, 'LoadDefeatConditionHandle', LoadDefeatConditionHandle.bind(null, C)); lua_register(L, 'LoadTimerDialogHandle', LoadTimerDialogHandle.bind(null, C)); lua_register(L, 'LoadLeaderboardHandle', LoadLeaderboardHandle.bind(null, C)); lua_register(L, 'LoadMultiboardHandle', LoadMultiboardHandle.bind(null, C)); lua_register(L, 'LoadMultiboardItemHandle', LoadMultiboardItemHandle.bind(null, C)); lua_register(L, 'LoadTrackableHandle', LoadTrackableHandle.bind(null, C)); lua_register(L, 'LoadDialogHandle', LoadDialogHandle.bind(null, C)); lua_register(L, 'LoadButtonHandle', LoadButtonHandle.bind(null, C)); lua_register(L, 'LoadTextTagHandle', LoadTextTagHandle.bind(null, C)); lua_register(L, 'LoadLightningHandle', LoadLightningHandle.bind(null, C)); lua_register(L, 'LoadImageHandle', LoadImageHandle.bind(null, C)); lua_register(L, 'LoadUbersplatHandle', LoadUbersplatHandle.bind(null, C)); lua_register(L, 'LoadRegionHandle', LoadRegionHandle.bind(null, C)); lua_register(L, 'LoadFogStateHandle', LoadFogStateHandle.bind(null, C)); lua_register(L, 'LoadFogModifierHandle', LoadFogModifierHandle.bind(null, C)); lua_register(L, 'LoadHashtableHandle', LoadHashtableHandle.bind(null, C)); lua_register(L, 'HaveSavedInteger', HaveSavedInteger.bind(null, C)); lua_register(L, 'HaveSavedReal', HaveSavedReal.bind(null, C)); lua_register(L, 'HaveSavedBoolean', HaveSavedBoolean.bind(null, C)); lua_register(L, 'HaveSavedString', HaveSavedString.bind(null, C)); lua_register(L, 'HaveSavedHandle', HaveSavedHandle.bind(null, C)); lua_register(L, 'RemoveSavedInteger', RemoveSavedInteger.bind(null, C)); lua_register(L, 'RemoveSavedReal', RemoveSavedReal.bind(null, C)); lua_register(L, 'RemoveSavedBoolean', RemoveSavedBoolean.bind(null, C)); lua_register(L, 'RemoveSavedString', RemoveSavedString.bind(null, C)); lua_register(L, 'RemoveSavedHandle', RemoveSavedHandle.bind(null, C)); lua_register(L, 'FlushParentHashtable', FlushParentHashtable.bind(null, C)); lua_register(L, 'FlushChildHashtable', FlushChildHashtable.bind(null, C)); lua_register(L, 'GetRandomInt', GetRandomInt.bind(null, C)); lua_register(L, 'GetRandomReal', GetRandomReal.bind(null, C)); lua_register(L, 'CreateUnitPool', CreateUnitPool.bind(null, C)); lua_register(L, 'DestroyUnitPool', DestroyUnitPool.bind(null, C)); lua_register(L, 'UnitPoolAddUnitType', UnitPoolAddUnitType.bind(null, C)); lua_register(L, 'UnitPoolRemoveUnitType', UnitPoolRemoveUnitType.bind(null, C)); lua_register(L, 'PlaceRandomUnit', PlaceRandomUnit.bind(null, C)); lua_register(L, 'CreateItemPool', CreateItemPool.bind(null, C)); lua_register(L, 'DestroyItemPool', DestroyItemPool.bind(null, C)); lua_register(L, 'ItemPoolAddItemType', ItemPoolAddItemType.bind(null, C)); lua_register(L, 'ItemPoolRemoveItemType', ItemPoolRemoveItemType.bind(null, C)); lua_register(L, 'PlaceRandomItem', PlaceRandomItem.bind(null, C)); lua_register(L, 'ChooseRandomCreep', ChooseRandomCreep.bind(null, C)); lua_register(L, 'ChooseRandomNPBuilding', ChooseRandomNPBuilding.bind(null, C)); lua_register(L, 'ChooseRandomItem', ChooseRandomItem.bind(null, C)); lua_register(L, 'ChooseRandomItemEx', ChooseRandomItemEx.bind(null, C)); lua_register(L, 'SetRandomSeed', SetRandomSeed.bind(null, C)); lua_register(L, 'SetTerrainFog', SetTerrainFog.bind(null, C)); lua_register(L, 'ResetTerrainFog', ResetTerrainFog.bind(null, C)); lua_register(L, 'SetUnitFog', SetUnitFog.bind(null, C)); lua_register(L, 'SetTerrainFogEx', SetTerrainFogEx.bind(null, C)); lua_register(L, 'DisplayTextToPlayer', DisplayTextToPlayer.bind(null, C)); lua_register(L, 'DisplayTimedTextToPlayer', DisplayTimedTextToPlayer.bind(null, C)); lua_register(L, 'DisplayTimedTextFromPlayer', DisplayTimedTextFromPlayer.bind(null, C)); lua_register(L, 'ClearTextMessages', ClearTextMessages.bind(null, C)); lua_register(L, 'SetDayNightModels', SetDayNightModels.bind(null, C)); lua_register(L, 'SetSkyModel', SetSkyModel.bind(null, C)); lua_register(L, 'EnableUserControl', EnableUserControl.bind(null, C)); lua_register(L, 'EnableUserUI', EnableUserUI.bind(null, C)); lua_register(L, 'SuspendTimeOfDay', SuspendTimeOfDay.bind(null, C)); lua_register(L, 'SetTimeOfDayScale', SetTimeOfDayScale.bind(null, C)); lua_register(L, 'GetTimeOfDayScale', GetTimeOfDayScale.bind(null, C)); lua_register(L, 'ShowInterface', ShowInterface.bind(null, C)); lua_register(L, 'PauseGame', PauseGame.bind(null, C)); lua_register(L, 'UnitAddIndicator', UnitAddIndicator.bind(null, C)); lua_register(L, 'AddIndicator', AddIndicator.bind(null, C)); lua_register(L, 'PingMinimap', PingMinimap.bind(null, C)); lua_register(L, 'PingMinimapEx', PingMinimapEx.bind(null, C)); lua_register(L, 'EnableOcclusion', EnableOcclusion.bind(null, C)); lua_register(L, 'SetIntroShotText', SetIntroShotText.bind(null, C)); lua_register(L, 'SetIntroShotModel', SetIntroShotModel.bind(null, C)); lua_register(L, 'EnableWorldFogBoundary', EnableWorldFogBoundary.bind(null, C)); lua_register(L, 'PlayModelCinematic', PlayModelCinematic.bind(null, C)); lua_register(L, 'PlayCinematic', PlayCinematic.bind(null, C)); lua_register(L, 'ForceUIKey', ForceUIKey.bind(null, C)); lua_register(L, 'ForceUICancel', ForceUICancel.bind(null, C)); lua_register(L, 'DisplayLoadDialog', DisplayLoadDialog.bind(null, C)); lua_register(L, 'SetAltMinimapIcon', SetAltMinimapIcon.bind(null, C)); lua_register(L, 'DisableRestartMission', DisableRestartMission.bind(null, C)); lua_register(L, 'CreateTextTag', CreateTextTag.bind(null, C)); lua_register(L, 'DestroyTextTag', DestroyTextTag.bind(null, C)); lua_register(L, 'SetTextTagText', SetTextTagText.bind(null, C)); lua_register(L, 'SetTextTagPos', SetTextTagPos.bind(null, C)); lua_register(L, 'SetTextTagPosUnit', SetTextTagPosUnit.bind(null, C)); lua_register(L, 'SetTextTagColor', SetTextTagColor.bind(null, C)); lua_register(L, 'SetTextTagVelocity', SetTextTagVelocity.bind(null, C)); lua_register(L, 'SetTextTagVisibility', SetTextTagVisibility.bind(null, C)); lua_register(L, 'SetTextTagSuspended', SetTextTagSuspended.bind(null, C)); lua_register(L, 'SetTextTagPermanent', SetTextTagPermanent.bind(null, C)); lua_register(L, 'SetTextTagAge', SetTextTagAge.bind(null, C)); lua_register(L, 'SetTextTagLifespan', SetTextTagLifespan.bind(null, C)); lua_register(L, 'SetTextTagFadepoint', SetTextTagFadepoint.bind(null, C)); lua_register(L, 'SetReservedLocalHeroButtons', SetReservedLocalHeroButtons.bind(null, C)); lua_register(L, 'GetAllyColorFilterState', GetAllyColorFilterState.bind(null, C)); lua_register(L, 'SetAllyColorFilterState', SetAllyColorFilterState.bind(null, C)); lua_register(L, 'GetCreepCampFilterState', GetCreepCampFilterState.bind(null, C)); lua_register(L, 'SetCreepCampFilterState', SetCreepCampFilterState.bind(null, C)); lua_register(L, 'EnableMinimapFilterButtons', EnableMinimapFilterButtons.bind(null, C)); lua_register(L, 'EnableDragSelect', EnableDragSelect.bind(null, C)); lua_register(L, 'EnablePreSelect', EnablePreSelect.bind(null, C)); lua_register(L, 'EnableSelect', EnableSelect.bind(null, C)); lua_register(L, 'CreateTrackable', CreateTrackable.bind(null, C)); lua_register(L, 'CreateQuest', CreateQuest.bind(null, C)); lua_register(L, 'DestroyQuest', DestroyQuest.bind(null, C)); lua_register(L, 'QuestSetTitle', QuestSetTitle.bind(null, C)); lua_register(L, 'QuestSetDescription', QuestSetDescription.bind(null, C)); lua_register(L, 'QuestSetIconPath', QuestSetIconPath.bind(null, C)); lua_register(L, 'QuestSetRequired', QuestSetRequired.bind(null, C)); lua_register(L, 'QuestSetCompleted', QuestSetCompleted.bind(null, C)); lua_register(L, 'QuestSetDiscovered', QuestSetDiscovered.bind(null, C)); lua_register(L, 'QuestSetFailed', QuestSetFailed.bind(null, C)); lua_register(L, 'QuestSetEnabled', QuestSetEnabled.bind(null, C)); lua_register(L, 'IsQuestRequired', IsQuestRequired.bind(null, C)); lua_register(L, 'IsQuestCompleted', IsQuestCompleted.bind(null, C)); lua_register(L, 'IsQuestDiscovered', IsQuestDiscovered.bind(null, C)); lua_register(L, 'IsQuestFailed', IsQuestFailed.bind(null, C)); lua_register(L, 'IsQuestEnabled', IsQuestEnabled.bind(null, C)); lua_register(L, 'QuestCreateItem', QuestCreateItem.bind(null, C)); lua_register(L, 'QuestItemSetDescription', QuestItemSetDescription.bind(null, C)); lua_register(L, 'QuestItemSetCompleted', QuestItemSetCompleted.bind(null, C)); lua_register(L, 'IsQuestItemCompleted', IsQuestItemCompleted.bind(null, C)); lua_register(L, 'CreateDefeatCondition', CreateDefeatCondition.bind(null, C)); lua_register(L, 'DestroyDefeatCondition', DestroyDefeatCondition.bind(null, C)); lua_register(L, 'DefeatConditionSetDescription', DefeatConditionSetDescription.bind(null, C)); lua_register(L, 'FlashQuestDialogButton', FlashQuestDialogButton.bind(null, C)); lua_register(L, 'ForceQuestDialogUpdate', ForceQuestDialogUpdate.bind(null, C)); lua_register(L, 'CreateTimerDialog', CreateTimerDialog.bind(null, C)); lua_register(L, 'DestroyTimerDialog', DestroyTimerDialog.bind(null, C)); lua_register(L, 'TimerDialogSetTitle', TimerDialogSetTitle.bind(null, C)); lua_register(L, 'TimerDialogSetTitleColor', TimerDialogSetTitleColor.bind(null, C)); lua_register(L, 'TimerDialogSetTimeColor', TimerDialogSetTimeColor.bind(null, C)); lua_register(L, 'TimerDialogSetSpeed', TimerDialogSetSpeed.bind(null, C)); lua_register(L, 'TimerDialogDisplay', TimerDialogDisplay.bind(null, C)); lua_register(L, 'IsTimerDialogDisplayed', IsTimerDialogDisplayed.bind(null, C)); lua_register(L, 'TimerDialogSetRealTimeRemaining', TimerDialogSetRealTimeRemaining.bind(null, C)); lua_register(L, 'CreateLeaderboard', CreateLeaderboard.bind(null, C)); lua_register(L, 'DestroyLeaderboard', DestroyLeaderboard.bind(null, C)); lua_register(L, 'LeaderboardDisplay', LeaderboardDisplay.bind(null, C)); lua_register(L, 'IsLeaderboardDisplayed', IsLeaderboardDisplayed.bind(null, C)); lua_register(L, 'LeaderboardGetItemCount', LeaderboardGetItemCount.bind(null, C)); lua_register(L, 'LeaderboardSetSizeByItemCount', LeaderboardSetSizeByItemCount.bind(null, C)); lua_register(L, 'LeaderboardAddItem', LeaderboardAddItem.bind(null, C)); lua_register(L, 'LeaderboardRemoveItem', LeaderboardRemoveItem.bind(null, C)); lua_register(L, 'LeaderboardRemovePlayerItem', LeaderboardRemovePlayerItem.bind(null, C)); lua_register(L, 'LeaderboardClear', LeaderboardClear.bind(null, C)); lua_register(L, 'LeaderboardSortItemsByValue', LeaderboardSortItemsByValue.bind(null, C)); lua_register(L, 'LeaderboardSortItemsByPlayer', LeaderboardSortItemsByPlayer.bind(null, C)); lua_register(L, 'LeaderboardSortItemsByLabel', LeaderboardSortItemsByLabel.bind(null, C)); lua_register(L, 'LeaderboardHasPlayerItem', LeaderboardHasPlayerItem.bind(null, C)); lua_register(L, 'LeaderboardGetPlayerIndex', LeaderboardGetPlayerIndex.bind(null, C)); lua_register(L, 'LeaderboardSetLabel', LeaderboardSetLabel.bind(null, C)); lua_register(L, 'LeaderboardGetLabelText', LeaderboardGetLabelText.bind(null, C)); lua_register(L, 'PlayerSetLeaderboard', PlayerSetLeaderboard.bind(null, C)); lua_register(L, 'PlayerGetLeaderboard', PlayerGetLeaderboard.bind(null, C)); lua_register(L, 'LeaderboardSetLabelColor', LeaderboardSetLabelColor.bind(null, C)); lua_register(L, 'LeaderboardSetValueColor', LeaderboardSetValueColor.bind(null, C)); lua_register(L, 'LeaderboardSetStyle', LeaderboardSetStyle.bind(null, C)); lua_register(L, 'LeaderboardSetItemValue', LeaderboardSetItemValue.bind(null, C)); lua_register(L, 'LeaderboardSetItemLabel', LeaderboardSetItemLabel.bind(null, C)); lua_register(L, 'LeaderboardSetItemStyle', LeaderboardSetItemStyle.bind(null, C)); lua_register(L, 'LeaderboardSetItemLabelColor', LeaderboardSetItemLabelColor.bind(null, C)); lua_register(L, 'LeaderboardSetItemValueColor', LeaderboardSetItemValueColor.bind(null, C)); lua_register(L, 'CreateMultiboard', CreateMultiboard.bind(null, C)); lua_register(L, 'DestroyMultiboard', DestroyMultiboard.bind(null, C)); lua_register(L, 'MultiboardDisplay', MultiboardDisplay.bind(null, C)); lua_register(L, 'IsMultiboardDisplayed', IsMultiboardDisplayed.bind(null, C)); lua_register(L, 'MultiboardMinimize', MultiboardMinimize.bind(null, C)); lua_register(L, 'IsMultiboardMinimized', IsMultiboardMinimized.bind(null, C)); lua_register(L, 'MultiboardClear', MultiboardClear.bind(null, C)); lua_register(L, 'MultiboardSetTitleText', MultiboardSetTitleText.bind(null, C)); lua_register(L, 'MultiboardGetTitleText', MultiboardGetTitleText.bind(null, C)); lua_register(L, 'MultiboardSetTitleTextColor', MultiboardSetTitleTextColor.bind(null, C)); lua_register(L, 'MultiboardGetRowCount', MultiboardGetRowCount.bind(null, C)); lua_register(L, 'MultiboardGetColumnCount', MultiboardGetColumnCount.bind(null, C)); lua_register(L, 'MultiboardSetColumnCount', MultiboardSetColumnCount.bind(null, C)); lua_register(L, 'MultiboardSetRowCount', MultiboardSetRowCount.bind(null, C)); lua_register(L, 'MultiboardSetItemsStyle', MultiboardSetItemsStyle.bind(null, C)); lua_register(L, 'MultiboardSetItemsValue', MultiboardSetItemsValue.bind(null, C)); lua_register(L, 'MultiboardSetItemsValueColor', MultiboardSetItemsValueColor.bind(null, C)); lua_register(L, 'MultiboardSetItemsWidth', MultiboardSetItemsWidth.bind(null, C)); lua_register(L, 'MultiboardSetItemsIcon', MultiboardSetItemsIcon.bind(null, C)); lua_register(L, 'MultiboardGetItem', MultiboardGetItem.bind(null, C)); lua_register(L, 'MultiboardReleaseItem', MultiboardReleaseItem.bind(null, C)); lua_register(L, 'MultiboardSetItemStyle', MultiboardSetItemStyle.bind(null, C)); lua_register(L, 'MultiboardSetItemValue', MultiboardSetItemValue.bind(null, C)); lua_register(L, 'MultiboardSetItemValueColor', MultiboardSetItemValueColor.bind(null, C)); lua_register(L, 'MultiboardSetItemWidth', MultiboardSetItemWidth.bind(null, C)); lua_register(L, 'MultiboardSetItemIcon', MultiboardSetItemIcon.bind(null, C)); lua_register(L, 'MultiboardSuppressDisplay', MultiboardSuppressDisplay.bind(null, C)); lua_register(L, 'SetCameraPosition', SetCameraPosition.bind(null, C)); lua_register(L, 'SetCameraQuickPosition', SetCameraQuickPosition.bind(null, C)); lua_register(L, 'SetCameraBounds', SetCameraBounds.bind(null, C)); lua_register(L, 'StopCamera', StopCamera.bind(null, C)); lua_register(L, 'ResetToGameCamera', ResetToGameCamera.bind(null, C)); lua_register(L, 'PanCameraTo', PanCameraTo.bind(null, C)); lua_register(L, 'PanCameraToTimed', PanCameraToTimed.bind(null, C)); lua_register(L, 'PanCameraToWithZ', PanCameraToWithZ.bind(null, C)); lua_register(L, 'PanCameraToTimedWithZ', PanCameraToTimedWithZ.bind(null, C)); lua_register(L, 'SetCinematicCamera', SetCinematicCamera.bind(null, C)); lua_register(L, 'SetCameraRotateMode', SetCameraRotateMode.bind(null, C)); lua_register(L, 'SetCameraField', SetCameraField.bind(null, C)); lua_register(L, 'AdjustCameraField', AdjustCameraField.bind(null, C)); lua_register(L, 'SetCameraTargetController', SetCameraTargetController.bind(null, C)); lua_register(L, 'SetCameraOrientController', SetCameraOrientController.bind(null, C)); lua_register(L, 'CreateCameraSetup', CreateCameraSetup.bind(null, C)); lua_register(L, 'CameraSetupSetField', CameraSetupSetField.bind(null, C)); lua_register(L, 'CameraSetupGetField', CameraSetupGetField.bind(null, C)); lua_register(L, 'CameraSetupSetDestPosition', CameraSetupSetDestPosition.bind(null, C)); lua_register(L, 'CameraSetupGetDestPositionLoc', CameraSetupGetDestPositionLoc.bind(null, C)); lua_register(L, 'CameraSetupGetDestPositionX', CameraSetupGetDestPositionX.bind(null, C)); lua_register(L, 'CameraSetupGetDestPositionY', CameraSetupGetDestPositionY.bind(null, C)); lua_register(L, 'CameraSetupApply', CameraSetupApply.bind(null, C)); lua_register(L, 'CameraSetupApplyWithZ', CameraSetupApplyWithZ.bind(null, C)); lua_register(L, 'CameraSetupApplyForceDuration', CameraSetupApplyForceDuration.bind(null, C)); lua_register(L, 'CameraSetupApplyForceDurationWithZ', CameraSetupApplyForceDurationWithZ.bind(null, C)); lua_register(L, 'CameraSetTargetNoise', CameraSetTargetNoise.bind(null, C)); lua_register(L, 'CameraSetSourceNoise', CameraSetSourceNoise.bind(null, C)); lua_register(L, 'CameraSetTargetNoiseEx', CameraSetTargetNoiseEx.bind(null, C)); lua_register(L, 'CameraSetSourceNoiseEx', CameraSetSourceNoiseEx.bind(null, C)); lua_register(L, 'CameraSetSmoothingFactor', CameraSetSmoothingFactor.bind(null, C)); lua_register(L, 'SetCineFilterTexture', SetCineFilterTexture.bind(null, C)); lua_register(L, 'SetCineFilterBlendMode', SetCineFilterBlendMode.bind(null, C)); lua_register(L, 'SetCineFilterTexMapFlags', SetCineFilterTexMapFlags.bind(null, C)); lua_register(L, 'SetCineFilterStartUV', SetCineFilterStartUV.bind(null, C)); lua_register(L, 'SetCineFilterEndUV', SetCineFilterEndUV.bind(null, C)); lua_register(L, 'SetCineFilterStartColor', SetCineFilterStartColor.bind(null, C)); lua_register(L, 'SetCineFilterEndColor', SetCineFilterEndColor.bind(null, C)); lua_register(L, 'SetCineFilterDuration', SetCineFilterDuration.bind(null, C)); lua_register(L, 'DisplayCineFilter', DisplayCineFilter.bind(null, C)); lua_register(L, 'IsCineFilterDisplayed', IsCineFilterDisplayed.bind(null, C)); lua_register(L, 'SetCinematicScene', SetCinematicScene.bind(null, C)); lua_register(L, 'EndCinematicScene', EndCinematicScene.bind(null, C)); lua_register(L, 'ForceCinematicSubtitles', ForceCinematicSubtitles.bind(null, C)); lua_register(L, 'GetCameraMargin', GetCameraMargin.bind(null, C)); lua_register(L, 'GetCameraBoundMinX', GetCameraBoundMinX.bind(null, C)); lua_register(L, 'GetCameraBoundMinY', GetCameraBoundMinY.bind(null, C)); lua_register(L, 'GetCameraBoundMaxX', GetCameraBoundMaxX.bind(null, C)); lua_register(L, 'GetCameraBoundMaxY', GetCameraBoundMaxY.bind(null, C)); lua_register(L, 'GetCameraField', GetCameraField.bind(null, C)); lua_register(L, 'GetCameraTargetPositionX', GetCameraTargetPositionX.bind(null, C)); lua_register(L, 'GetCameraTargetPositionY', GetCameraTargetPositionY.bind(null, C)); lua_register(L, 'GetCameraTargetPositionZ', GetCameraTargetPositionZ.bind(null, C)); lua_register(L, 'GetCameraTargetPositionLoc', GetCameraTargetPositionLoc.bind(null, C)); lua_register(L, 'GetCameraEyePositionX', GetCameraEyePositionX.bind(null, C)); lua_register(L, 'GetCameraEyePositionY', GetCameraEyePositionY.bind(null, C)); lua_register(L, 'GetCameraEyePositionZ', GetCameraEyePositionZ.bind(null, C)); lua_register(L, 'GetCameraEyePositionLoc', GetCameraEyePositionLoc.bind(null, C)); lua_register(L, 'NewSoundEnvironment', NewSoundEnvironment.bind(null, C)); lua_register(L, 'CreateSound', CreateSound.bind(null, C)); lua_register(L, 'CreateSoundFilenameWithLabel', CreateSoundFilenameWithLabel.bind(null, C)); lua_register(L, 'CreateSoundFromLabel', CreateSoundFromLabel.bind(null, C)); lua_register(L, 'CreateMIDISound', CreateMIDISound.bind(null, C)); lua_register(L, 'SetSoundParamsFromLabel', SetSoundParamsFromLabel.bind(null, C)); lua_register(L, 'SetSoundDistanceCutoff', SetSoundDistanceCutoff.bind(null, C)); lua_register(L, 'SetSoundChannel', SetSoundChannel.bind(null, C)); lua_register(L, 'SetSoundVolume', SetSoundVolume.bind(null, C)); lua_register(L, 'SetSoundPitch', SetSoundPitch.bind(null, C)); lua_register(L, 'SetSoundPlayPosition', SetSoundPlayPosition.bind(null, C)); lua_register(L, 'SetSoundDistances', SetSoundDistances.bind(null, C)); lua_register(L, 'SetSoundConeAngles', SetSoundConeAngles.bind(null, C)); lua_register(L, 'SetSoundConeOrientation', SetSoundConeOrientation.bind(null, C)); lua_register(L, 'SetSoundPosition', SetSoundPosition.bind(null, C)); lua_register(L, 'SetSoundVelocity', SetSoundVelocity.bind(null, C)); lua_register(L, 'AttachSoundToUnit', AttachSoundToUnit.bind(null, C)); lua_register(L, 'StartSound', StartSound.bind(null, C)); lua_register(L, 'StopSound', StopSound.bind(null, C)); lua_register(L, 'KillSoundWhenDone', KillSoundWhenDone.bind(null, C)); lua_register(L, 'SetMapMusic', SetMapMusic.bind(null, C)); lua_register(L, 'ClearMapMusic', ClearMapMusic.bind(null, C)); lua_register(L, 'PlayMusic', PlayMusic.bind(null, C)); lua_register(L, 'PlayMusicEx', PlayMusicEx.bind(null, C)); lua_register(L, 'StopMusic', StopMusic.bind(null, C)); lua_register(L, 'ResumeMusic', ResumeMusic.bind(null, C)); lua_register(L, 'PlayThematicMusic', PlayThematicMusic.bind(null, C)); lua_register(L, 'PlayThematicMusicEx', PlayThematicMusicEx.bind(null, C)); lua_register(L, 'EndThematicMusic', EndThematicMusic.bind(null, C)); lua_register(L, 'SetMusicVolume', SetMusicVolume.bind(null, C)); lua_register(L, 'SetMusicPlayPosition', SetMusicPlayPosition.bind(null, C)); lua_register(L, 'SetThematicMusicPlayPosition', SetThematicMusicPlayPosition.bind(null, C)); lua_register(L, 'SetSoundDuration', SetSoundDuration.bind(null, C)); lua_register(L, 'GetSoundDuration', GetSoundDuration.bind(null, C)); lua_register(L, 'GetSoundFileDuration', GetSoundFileDuration.bind(null, C)); lua_register(L, 'VolumeGroupSetVolume', VolumeGroupSetVolume.bind(null, C)); lua_register(L, 'VolumeGroupReset', VolumeGroupReset.bind(null, C)); lua_register(L, 'GetSoundIsPlaying', GetSoundIsPlaying.bind(null, C)); lua_register(L, 'GetSoundIsLoading', GetSoundIsLoading.bind(null, C)); lua_register(L, 'RegisterStackedSound', RegisterStackedSound.bind(null, C)); lua_register(L, 'UnregisterStackedSound', UnregisterStackedSound.bind(null, C)); lua_register(L, 'AddWeatherEffect', AddWeatherEffect.bind(null, C)); lua_register(L, 'RemoveWeatherEffect', RemoveWeatherEffect.bind(null, C)); lua_register(L, 'EnableWeatherEffect', EnableWeatherEffect.bind(null, C)); lua_register(L, 'TerrainDeformCrater', TerrainDeformCrater.bind(null, C)); lua_register(L, 'TerrainDeformRipple', TerrainDeformRipple.bind(null, C)); lua_register(L, 'TerrainDeformWave', TerrainDeformWave.bind(null, C)); lua_register(L, 'TerrainDeformRandom', TerrainDeformRandom.bind(null, C)); lua_register(L, 'TerrainDeformStop', TerrainDeformStop.bind(null, C)); lua_register(L, 'TerrainDeformStopAll', TerrainDeformStopAll.bind(null, C)); lua_register(L, 'AddSpecialEffect', AddSpecialEffect.bind(null, C)); lua_register(L, 'AddSpecialEffectLoc', AddSpecialEffectLoc.bind(null, C)); lua_register(L, 'AddSpecialEffectTarget', AddSpecialEffectTarget.bind(null, C)); lua_register(L, 'DestroyEffect', DestroyEffect.bind(null, C)); lua_register(L, 'AddSpellEffect', AddSpellEffect.bind(null, C)); lua_register(L, 'AddSpellEffectLoc', AddSpellEffectLoc.bind(null, C)); lua_register(L, 'AddSpellEffectById', AddSpellEffectById.bind(null, C)); lua_register(L, 'AddSpellEffectByIdLoc', AddSpellEffectByIdLoc.bind(null, C)); lua_register(L, 'AddSpellEffectTarget', AddSpellEffectTarget.bind(null, C)); lua_register(L, 'AddSpellEffectTargetById', AddSpellEffectTargetById.bind(null, C)); lua_register(L, 'AddLightning', AddLightning.bind(null, C)); lua_register(L, 'AddLightningEx', AddLightningEx.bind(null, C)); lua_register(L, 'DestroyLightning', DestroyLightning.bind(null, C)); lua_register(L, 'MoveLightning', MoveLightning.bind(null, C)); lua_register(L, 'MoveLightningEx', MoveLightningEx.bind(null, C)); lua_register(L, 'GetLightningColorA', GetLightningColorA.bind(null, C)); lua_register(L, 'GetLightningColorR', GetLightningColorR.bind(null, C)); lua_register(L, 'GetLightningColorG', GetLightningColorG.bind(null, C)); lua_register(L, 'GetLightningColorB', GetLightningColorB.bind(null, C)); lua_register(L, 'SetLightningColor', SetLightningColor.bind(null, C)); lua_register(L, 'GetAbilityEffect', GetAbilityEffect.bind(null, C)); lua_register(L, 'GetAbilityEffectById', GetAbilityEffectById.bind(null, C)); lua_register(L, 'GetAbilitySound', GetAbilitySound.bind(null, C)); lua_register(L, 'GetAbilitySoundById', GetAbilitySoundById.bind(null, C)); lua_register(L, 'GetTerrainCliffLevel', GetTerrainCliffLevel.bind(null, C)); lua_register(L, 'SetWaterBaseColor', SetWaterBaseColor.bind(null, C)); lua_register(L, 'SetWaterDeforms', SetWaterDeforms.bind(null, C)); lua_register(L, 'GetTerrainType', GetTerrainType.bind(null, C)); lua_register(L, 'GetTerrainVariance', GetTerrainVariance.bind(null, C)); lua_register(L, 'SetTerrainType', SetTerrainType.bind(null, C)); lua_register(L, 'IsTerrainPathable', IsTerrainPathable.bind(null, C)); lua_register(L, 'SetTerrainPathable', SetTerrainPathable.bind(null, C)); lua_register(L, 'CreateImage', CreateImage.bind(null, C)); lua_register(L, 'DestroyImage', DestroyImage.bind(null, C)); lua_register(L, 'ShowImage', ShowImage.bind(null, C)); lua_register(L, 'SetImageConstantHeight', SetImageConstantHeight.bind(null, C)); lua_register(L, 'SetImagePosition', SetImagePosition.bind(null, C)); lua_register(L, 'SetImageColor', SetImageColor.bind(null, C)); lua_register(L, 'SetImageRender', SetImageRender.bind(null, C)); lua_register(L, 'SetImageRenderAlways', SetImageRenderAlways.bind(null, C)); lua_register(L, 'SetImageAboveWater', SetImageAboveWater.bind(null, C)); lua_register(L, 'SetImageType', SetImageType.bind(null, C)); lua_register(L, 'CreateUbersplat', CreateUbersplat.bind(null, C)); lua_register(L, 'DestroyUbersplat', DestroyUbersplat.bind(null, C)); lua_register(L, 'ResetUbersplat', ResetUbersplat.bind(null, C)); lua_register(L, 'FinishUbersplat', FinishUbersplat.bind(null, C)); lua_register(L, 'ShowUbersplat', ShowUbersplat.bind(null, C)); lua_register(L, 'SetUbersplatRender', SetUbersplatRender.bind(null, C)); lua_register(L, 'SetUbersplatRenderAlways', SetUbersplatRenderAlways.bind(null, C)); lua_register(L, 'SetBlight', SetBlight.bind(null, C)); lua_register(L, 'SetBlightRect', SetBlightRect.bind(null, C)); lua_register(L, 'SetBlightPoint', SetBlightPoint.bind(null, C)); lua_register(L, 'SetBlightLoc', SetBlightLoc.bind(null, C)); lua_register(L, 'CreateBlightedGoldmine', CreateBlightedGoldmine.bind(null, C)); lua_register(L, 'IsPointBlighted', IsPointBlighted.bind(null, C)); lua_register(L, 'SetDoodadAnimation', SetDoodadAnimation.bind(null, C)); lua_register(L, 'SetDoodadAnimationRect', SetDoodadAnimationRect.bind(null, C)); lua_register(L, 'StartMeleeAI', StartMeleeAI.bind(null, C)); lua_register(L, 'StartCampaignAI', StartCampaignAI.bind(null, C)); lua_register(L, 'CommandAI', CommandAI.bind(null, C)); lua_register(L, 'PauseCompAI', PauseCompAI.bind(null, C)); lua_register(L, 'GetAIDifficulty', GetAIDifficulty.bind(null, C)); lua_register(L, 'RemoveGuardPosition', RemoveGuardPosition.bind(null, C)); lua_register(L, 'RecycleGuardPosition', RecycleGuardPosition.bind(null, C)); lua_register(L, 'RemoveAllGuardPositions', RemoveAllGuardPositions.bind(null, C)); lua_register(L, 'Cheat', Cheat.bind(null, C)); lua_register(L, 'IsNoVictoryCheat', IsNoVictoryCheat.bind(null, C)); lua_register(L, 'IsNoDefeatCheat', IsNoDefeatCheat.bind(null, C)); lua_register(L, 'Preload', Preload.bind(null, C)); lua_register(L, 'PreloadEnd', PreloadEnd.bind(null, C)); lua_register(L, 'PreloadStart', PreloadStart.bind(null, C)); lua_register(L, 'PreloadRefresh', PreloadRefresh.bind(null, C)); lua_register(L, 'PreloadEndEx', PreloadEndEx.bind(null, C)); lua_register(L, 'PreloadGenClear', PreloadGenClear.bind(null, C)); lua_register(L, 'PreloadGenStart', PreloadGenStart.bind(null, C)); lua_register(L, 'PreloadGenEnd', PreloadGenEnd.bind(null, C)); lua_register(L, 'Preloader', Preloader.bind(null, C)); lua_register(L, 'AutomationTestStart', AutomationTestStart.bind(null, C)); lua_register(L, 'AutomationTestEnd', AutomationTestEnd.bind(null, C)); lua_register(L, 'BlzGetTriggerPlayerMouseX', BlzGetTriggerPlayerMouseX.bind(null, C)); lua_register(L, 'BlzGetTriggerPlayerMouseY', BlzGetTriggerPlayerMouseY.bind(null, C)); lua_register(L, 'BlzGetTriggerPlayerMousePosition', BlzGetTriggerPlayerMousePosition.bind(null, C)); lua_register(L, 'BlzGetTriggerPlayerMouseButton', BlzGetTriggerPlayerMouseButton.bind(null, C)); lua_register(L, 'BlzSetAbilityTooltip', BlzSetAbilityTooltip.bind(null, C)); lua_register(L, 'BlzSetAbilityActivatedTooltip', BlzSetAbilityActivatedTooltip.bind(null, C)); lua_register(L, 'BlzSetAbilityExtendedTooltip', BlzSetAbilityExtendedTooltip.bind(null, C)); lua_register(L, 'BlzSetAbilityActivatedExtendedTooltip', BlzSetAbilityActivatedExtendedTooltip.bind(null, C)); lua_register(L, 'BlzSetAbilityResearchTooltip', BlzSetAbilityResearchTooltip.bind(null, C)); lua_register(L, 'BlzSetAbilityResearchExtendedTooltip', BlzSetAbilityResearchExtendedTooltip.bind(null, C)); lua_register(L, 'BlzGetAbilityTooltip', BlzGetAbilityTooltip.bind(null, C)); lua_register(L, 'BlzGetAbilityActivatedTooltip', BlzGetAbilityActivatedTooltip.bind(null, C)); lua_register(L, 'BlzGetAbilityExtendedTooltip', BlzGetAbilityExtendedTooltip.bind(null, C)); lua_register(L, 'BlzGetAbilityActivatedExtendedTooltip', BlzGetAbilityActivatedExtendedTooltip.bind(null, C)); lua_register(L, 'BlzGetAbilityResearchTooltip', BlzGetAbilityResearchTooltip.bind(null, C)); lua_register(L, 'BlzGetAbilityResearchExtendedTooltip', BlzGetAbilityResearchExtendedTooltip.bind(null, C)); lua_register(L, 'BlzSetAbilityIcon', BlzSetAbilityIcon.bind(null, C)); lua_register(L, 'BlzGetAbilityIcon', BlzGetAbilityIcon.bind(null, C)); lua_register(L, 'BlzSetAbilityActivatedIcon', BlzSetAbilityActivatedIcon.bind(null, C)); lua_register(L, 'BlzGetAbilityActivatedIcon', BlzGetAbilityActivatedIcon.bind(null, C)); lua_register(L, 'BlzGetAbilityPosX', BlzGetAbilityPosX.bind(null, C)); lua_register(L, 'BlzGetAbilityPosY', BlzGetAbilityPosY.bind(null, C)); lua_register(L, 'BlzSetAbilityPosX', BlzSetAbilityPosX.bind(null, C)); lua_register(L, 'BlzSetAbilityPosY', BlzSetAbilityPosY.bind(null, C)); lua_register(L, 'BlzGetAbilityActivatedPosX', BlzGetAbilityActivatedPosX.bind(null, C)); lua_register(L, 'BlzGetAbilityActivatedPosY', BlzGetAbilityActivatedPosY.bind(null, C)); lua_register(L, 'BlzSetAbilityActivatedPosX', BlzSetAbilityActivatedPosX.bind(null, C)); lua_register(L, 'BlzSetAbilityActivatedPosY', BlzSetAbilityActivatedPosY.bind(null, C)); lua_register(L, 'BlzGetUnitMaxHP', BlzGetUnitMaxHP.bind(null, C)); lua_register(L, 'BlzSetUnitMaxHP', BlzSetUnitMaxHP.bind(null, C)); lua_register(L, 'BlzGetUnitMaxMana', BlzGetUnitMaxMana.bind(null, C)); lua_register(L, 'BlzSetUnitMaxMana', BlzSetUnitMaxMana.bind(null, C)); lua_register(L, 'BlzDeleteHeroAbility', BlzDeleteHeroAbility.bind(null, C)); lua_register(L, 'BlzSetItemName', BlzSetItemName.bind(null, C)); lua_register(L, 'BlzSetItemDescription', BlzSetItemDescription.bind(null, C)); lua_register(L, 'BlzGetItemDescription', BlzGetItemDescription.bind(null, C)); lua_register(L, 'BlzSetItemTooltip', BlzSetItemTooltip.bind(null, C)); lua_register(L, 'BlzGetItemTooltip', BlzGetItemTooltip.bind(null, C)); lua_register(L, 'BlzSetItemExtendedTooltip', BlzSetItemExtendedTooltip.bind(null, C)); lua_register(L, 'BlzGetItemExtendedTooltip', BlzGetItemExtendedTooltip.bind(null, C)); lua_register(L, 'BlzSetItemIconPath', BlzSetItemIconPath.bind(null, C)); lua_register(L, 'BlzGetItemIconPath', BlzGetItemIconPath.bind(null, C)); lua_register(L, 'BlzSetUnitName', BlzSetUnitName.bind(null, C)); lua_register(L, 'BlzSetHeroProperName', BlzSetHeroProperName.bind(null, C)); lua_register(L, 'BlzGetUnitBaseDamage', BlzGetUnitBaseDamage.bind(null, C)); lua_register(L, 'BlzSetUnitBaseDamage', BlzSetUnitBaseDamage.bind(null, C)); lua_register(L, 'BlzGetUnitDiceNumber', BlzGetUnitDiceNumber.bind(null, C)); lua_register(L, 'BlzSetUnitDiceNumber', BlzSetUnitDiceNumber.bind(null, C)); lua_register(L, 'BlzGetUnitDiceSides', BlzGetUnitDiceSides.bind(null, C)); lua_register(L, 'BlzSetUnitDiceSides', BlzSetUnitDiceSides.bind(null, C)); lua_register(L, 'BlzGetUnitAttackCooldown', BlzGetUnitAttackCooldown.bind(null, C)); lua_register(L, 'BlzSetUnitAttackCooldown', BlzSetUnitAttackCooldown.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectColorByPlayer', BlzSetSpecialEffectColorByPlayer.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectColor', BlzSetSpecialEffectColor.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectAlpha', BlzSetSpecialEffectAlpha.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectScale', BlzSetSpecialEffectScale.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectPosition', BlzSetSpecialEffectPosition.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectHeight', BlzSetSpecialEffectHeight.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectTimeScale', BlzSetSpecialEffectTimeScale.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectTime', BlzSetSpecialEffectTime.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectOrientation', BlzSetSpecialEffectOrientation.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectYaw', BlzSetSpecialEffectYaw.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectPitch', BlzSetSpecialEffectPitch.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectRoll', BlzSetSpecialEffectRoll.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectX', BlzSetSpecialEffectX.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectY', BlzSetSpecialEffectY.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectZ', BlzSetSpecialEffectZ.bind(null, C)); lua_register(L, 'BlzSetSpecialEffectPositionLoc', BlzSetSpecialEffectPositionLoc.bind(null, C)); lua_register(L, 'BlzGetLocalSpecialEffectX', BlzGetLocalSpecialEffectX.bind(null, C)); lua_register(L, 'BlzGetLocalSpecialEffectY', BlzGetLocalSpecialEffectY.bind(null, C)); lua_register(L, 'BlzGetLocalSpecialEffectZ', BlzGetLocalSpecialEffectZ.bind(null, C)); lua_register(L, 'BlzGetUnitArmor', BlzGetUnitArmor.bind(null, C)); lua_register(L, 'BlzSetUnitArmor', BlzSetUnitArmor.bind(null, C)); lua_register(L, 'BlzUnitHideAbility', BlzUnitHideAbility.bind(null, C)); lua_register(L, 'BlzUnitDisableAbility', BlzUnitDisableAbility.bind(null, C)); lua_register(L, 'BlzUnitCancelTimedLife', BlzUnitCancelTimedLife.bind(null, C)); lua_register(L, 'BlzIsUnitSelectable', BlzIsUnitSelectable.bind(null, C)); lua_register(L, 'BlzIsUnitInvulnerable', BlzIsUnitInvulnerable.bind(null, C)); lua_register(L, 'BlzUnitInterruptAttack', BlzUnitInterruptAttack.bind(null, C)); lua_register(L, 'BlzGetUnitCollisionSize', BlzGetUnitCollisionSize.bind(null, C)); lua_register(L, 'BlzGetAbilityManaCost', BlzGetAbilityManaCost.bind(null, C)); lua_register(L, 'BlzGetAbilityCooldown', BlzGetAbilityCooldown.bind(null, C)); lua_register(L, 'BlzSetUnitAbilityCooldown', BlzSetUnitAbilityCooldown.bind(null, C)); lua_register(L, 'BlzGetUnitAbilityCooldown', BlzGetUnitAbilityCooldown.bind(null, C)); lua_register(L, 'BlzGetUnitAbilityCooldownRemaining', BlzGetUnitAbilityCooldownRemaining.bind(null, C)); lua_register(L, 'BlzEndUnitAbilityCooldown', BlzEndUnitAbilityCooldown.bind(null, C)); lua_register(L, 'BlzGetUnitAbilityManaCost', BlzGetUnitAbilityManaCost.bind(null, C)); lua_register(L, 'BlzSetUnitAbilityManaCost', BlzSetUnitAbilityManaCost.bind(null, C)); lua_register(L, 'BlzGetLocalUnitZ', BlzGetLocalUnitZ.bind(null, C)); lua_register(L, 'BlzDecPlayerTechResearched', BlzDecPlayerTechResearched.bind(null, C)); lua_register(L, 'BlzSetEventDamage', BlzSetEventDamage.bind(null, C)); } ================================================ FILE: src/utils/jass2/thread.ts ================================================ import { lua_newthread, lua_State } from 'fengari/src/lstate'; import JassTrigger from './types/trigger'; import JassTimer from './types/timer'; import JassUnit from './types/unit'; /** * A thread. */ export default class Thread { L: lua_State; sleep = 0; expiredTimer: JassTimer | null; triggerUnit: JassUnit | null; triggeringTrigger: JassTrigger | null; constructor(L: lua_State, data: { expiredTimer?: JassTimer, triggerUnit?: JassUnit, triggeringTrigger?: JassTrigger }) { this.L = lua_newthread(L); this.expiredTimer = data.expiredTimer || null; this.triggerUnit = data.triggerUnit || null; this.triggeringTrigger = data.triggeringTrigger || null; } } ================================================ FILE: src/utils/jass2/tokenstream.ts ================================================ import { stringToBase256 } from '../../common/typecast'; export default class TokenStream { buffer: string; index: number; constructor(buffer: string) { this.buffer = buffer; this.index = 0; } read(): string | undefined { const buffer = this.buffer; const length = buffer.length; let inComment = false; let inString = false; let inIdString = false; let token = ''; while (this.index < length) { const c = buffer[this.index++]; if (inComment) { if (c === '\n') { inComment = false; this.index--; } } else if (inString) { if (c === '\\') { token += c + buffer[this.index++]; } else if (c === '\n') { token += '\\n'; } else if (c === '\r') { token += '\\r'; } else { token += c; } if (c === '"') { return token; } } else if (inIdString) { token += c; if (c === "'") { return token; } } else if (c === ' ' || c === '\t') { if (token.length) { return token; } } else if (c === '(' || c === ')' || c === '[' || c === ']' || c === '=' || c === '\r' || c === '\n' || c === ',' || c === '!' || c === '-' || c === '<' || c === '>' || c === '+' || c === '*' || c === '/') { if (token.length) { this.index--; return token; } else { const c2 = buffer[this.index]; if (c === '=' && c2 === '=') { this.index++; return '=='; } else if (c === '\r') { if (c2 === '\n') { this.index++; } return '\n'; } else if (c === '!' && c2 === '=') { this.index++; return '!='; } else if (c === '/' && c2 === '/') { if (token.length) { this.index--; return token; } else { inComment = true; } } else { return c; } } } else if (c === '"') { if (token.length) { this.index--; return token; } else { token += c; inString = true; } } else if (c === "'") { if (token.length) { this.index--; return token; } else { token += c; inIdString = true; } } else { token += c; } if (this.index === length) { return token; } } return; } /** * Reads the next token without advancing the stream. */ peek(): string | undefined { const index = this.index; const value = this.read(); this.index = index; return value; } readSafe(): string { const token = this.read(); if (token === undefined) { throw new Error('Premature end of stream reached'); } if (token === 'null') { return 'nil'; } else if (token === '!=') { return '~='; } else if (token[0] === "'") { return `${stringToBase256(token.slice(1, token.indexOf("'", 1)))}`; } else if (token === 'break' || token === 'do' || token === 'end' || token === 'for' || token === 'goto' || token === 'in' || token === 'nil' || token === 'repeat' || token === 'until' || token === 'while') { // Lua reserved keywords return token + '_'; } else if (token === 'and' || token === 'or') { return ' ' + token + ' '; } else if (token[0] === '$') { return '0x' + token.slice(1); } return token; } readUntil(delimiter: string): string { let tokens = ''; let token; while ((token = this.readSafe()) !== delimiter) { tokens += token; } return tokens; } } ================================================ FILE: src/utils/jass2/types/agent.ts ================================================ import JassHandle from './handle'; /** * type agent */ export default class JassAgent extends JassHandle {} ================================================ FILE: src/utils/jass2/types/aidifficulty.ts ================================================ import JassEnum from './enum'; /** * type aidifficulty */ export default class JassAiDifficulty extends JassEnum {} ================================================ FILE: src/utils/jass2/types/alliancetype.ts ================================================ import JassEnum from './enum'; /** * type alliancetype */ export default class JassAllianceType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/animtype.ts ================================================ import JassEnum from './enum'; /** * type animtype */ export default class JassAnimType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/attacktype.ts ================================================ import JassEnum from './enum'; /** * type attacktype */ export default class JassAttackType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/blendmode.ts ================================================ import JassEnum from './enum'; /** * type blendmode */ export default class JassBlendMode extends JassEnum {} ================================================ FILE: src/utils/jass2/types/camerafield.ts ================================================ import JassEnum from './enum'; /** * type camerafield */ export default class JassCameraField extends JassEnum {} ================================================ FILE: src/utils/jass2/types/camerasetup.ts ================================================ import JassHandle from './handle'; import JassLocation from './location'; /** * type camerasetup */ export default class JassCameraSetup extends JassHandle { targetDistance = 0; farZ = 0; angleOfAttack = 0; fieldOfView = 0; roll = 0; rotation = 0; zOffset = 0; destPosition = new JassLocation(0, 0); } ================================================ FILE: src/utils/jass2/types/damagetype.ts ================================================ import JassEnum from './enum'; /** * type damagetype */ export default class JassDamageType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/dialogevent.ts ================================================ import JassEventId from './eventid'; /** * type dialogevent */ export default class JassDialogEvent extends JassEventId {} ================================================ FILE: src/utils/jass2/types/effecttype.ts ================================================ import JassEnum from './enum'; /** * type effecttype */ export default class JassEffectType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/enum.ts ================================================ import JassHandle from './handle'; /** * Parent class for all enum types. */ export default class JassEnum extends JassHandle { id: number; constructor(value: number) { super(); this.id = value; } } ================================================ FILE: src/utils/jass2/types/eventid.ts ================================================ import JassEnum from './enum'; /** * type eventid */ export default class JassEventId extends JassEnum {} ================================================ FILE: src/utils/jass2/types/fgamestate.ts ================================================ import JassGameState from './gamestate'; /** * type fgamestate */ export default class JassFGameState extends JassGameState {} ================================================ FILE: src/utils/jass2/types/fogstate.ts ================================================ import JassEnum from './enum'; /** * type fogstate */ export default class JassFogState extends JassEnum {} ================================================ FILE: src/utils/jass2/types/force.ts ================================================ import JassAgent from './agent'; import JassPlayer from './player'; /** * type force */ export default class JassForce extends JassAgent { players: Set = new Set(); } ================================================ FILE: src/utils/jass2/types/gamedifficulty.ts ================================================ import JassEnum from './enum'; /** * type gamedifficulty */ export default class JassGameDifficulty extends JassEnum {} ================================================ FILE: src/utils/jass2/types/gameevent.ts ================================================ import JassEventId from './eventid'; /** * type gameevent */ export default class JassGameEvent extends JassEventId {} ================================================ FILE: src/utils/jass2/types/gamespeed.ts ================================================ import JassEnum from './enum'; /** * type gamespeed */ export default class JassGameSpeed extends JassEnum {} ================================================ FILE: src/utils/jass2/types/gamestate.ts ================================================ import JassEnum from './enum'; /** * type gamestate */ export default class JassGameState extends JassEnum {} ================================================ FILE: src/utils/jass2/types/gametype.ts ================================================ import JassEnum from './enum'; /** * type gametype */ export default class JassGameType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/group.ts ================================================ import JassAgent from './agent'; import JassUnit from './unit'; /** * type group */ export default class JassGroup extends JassAgent { units: Set = new Set(); } ================================================ FILE: src/utils/jass2/types/handle.ts ================================================ /** * type handle */ export default class JassHandle { handleId = -1; } ================================================ FILE: src/utils/jass2/types/hashtable.ts ================================================ import JassAgent from './agent'; /** * type unit */ export default class JassHashTable extends JassAgent { table: Map> = new Map(); save(parentKey: number, childKey: number, value: unknown): void { const table = this.table; let childTable = table.get(parentKey); if (!childTable) { childTable = new Map(); table.set(parentKey, childTable); } childTable.set(childKey, value); } load(parentKey: number, childKey: number, defaultValue?: unknown): unknown { const table = this.table; const childTable = table.get(parentKey); if (childTable) { const value = childTable.get(childKey); if (value !== undefined) { return value; } } return defaultValue; } have(parentKey: number, childKey: number): boolean { const table = this.table; const childTable = table.get(parentKey); if (!childTable) { return false; } return childTable.has(childKey); } remove(parentKey: number, childKey: number): void { const table = this.table; const childTable = table.get(parentKey); if (childTable) { childTable.delete(childKey); if (!childTable.size) { table.delete(parentKey); } } } flush(): void { this.table.clear(); } flushChild(parentKey: number): void { const child = this.table.get(parentKey); if (child) { child.clear(); } } } ================================================ FILE: src/utils/jass2/types/igamestate.ts ================================================ import JassGameState from './gamestate'; /** * type igamestate */ export default class JassIGameState extends JassGameState {} ================================================ FILE: src/utils/jass2/types/index.ts ================================================ import JassHandle from './handle'; import JassAgent from './agent'; // import JassEvent from './event'; import JassPlayer from './player'; import JassWidget from './widget'; import JassUnit from './unit'; // import JassDestructable from './destructable'; // import JassItem from './item'; // import JassAbility from './ability'; // import JassBuff from './buff'; import JassForce from './force'; import JassGroup from './group'; import JassTrigger from './trigger'; // import JassTriggerCondition from './triggercondition'; // import JassTriggerAction from './triggeraction'; import JassTimer from './timer'; import JassLocation from './location'; import JassRegion from './region'; import JassRect from './rect'; // import JassBoolexpr from './boolexpr'; // import JassSound from './sound'; // import JassConditionFunc from './conditionfunc'; // import JassFilterFunc from './filterfunc'; // import JassUnitPool from './unitpool'; // import JassItemPool from './itempool'; import JassRace from './race'; import JassAllianceType from './alliancetype'; import JassRacePreference from './racepreference'; import JassGameState from './gamestate'; import JassIGameState from './igamestate'; import JassFGameState from './fgamestate'; import JassPlayerState from './playerstate'; import JassPlayerScore from './playerscore'; import JassPlayerGameResult from './playergameresult'; import JassUnitState from './unitstate'; import JassAiDifficulty from './aidifficulty'; import JassEventId from './eventid'; import JassGameEvent from './gameevent'; import JassPlayerEvent from './playerevent'; import JassPlayerUnitEvent from './playerunitevent'; import JassUnitEvent from './unitevent'; import JassLimitOp from './limitop'; import JassWidgetEvent from './widgetevent'; import JassDialogEvent from './dialogevent'; import JassUnitType from './unittype'; import JassGameSpeed from './gamespeed'; import JassGameDifficulty from './gamedifficulty'; import JassGameType from './gametype'; import JassMapFlag from './mapflag'; import JassMapVisibility from './mapvisibility'; import JassMapSetting from './mapsetting'; import JassMapDensity from './mapdensity'; import JassMapControl from './mapcontrol'; import JassPlayerSlotState from './playerslotstate'; import JassVolumeGroup from './volumegroup'; import JassCameraField from './camerafield'; import JassCameraSetup from './camerasetup'; import JassPlayerColor from './playercolor'; import JassPlacement from './placement'; import JassStartLocPrio from './startlocprio'; import JassRarityControl from './raritycontrol'; import JassBlendMode from './blendmode'; import JassTexMapFlags from './texmapflags'; // import JassEffect from './effect'; import JassEffectType from './effecttype'; import JassWeatherEffect from './weathereffect'; // import JassTerrainDeformation from './terraindeformation'; import JassFogState from './fogstate'; // import JassFogModifier from './fogmodifier'; // import JassDialog from './dialog'; // import JassButton from './button'; // import JassQuest from './quest'; // import JassQuestItem from './questitem'; // import JassDefeatCondition from './defeatcondition'; // import JassTimerDialog from './timerdialog'; // import JassLeaderboard from './leaderboard'; // import JassMultiboard from './multiboard'; // import JassMultiboardItem from './multiboarditem'; // import JassTrackable from './trackable'; // import JassGameCache from './gamecache'; import JassVersion from './version'; import JassItemType from './itemtype'; // import JassTextTag from './texttag'; import JassAttackType from './attacktype'; import JassDamageType from './damagetype'; import JassWeaponType from './weapontype'; import JassSoundType from './soundtype'; // import JassLightning from './lightning'; import JassPathingType from './pathingtype'; // import JassImage from './image'; // import JassUbersplat from './ubersplat'; import JassHashtable from './hashtable'; export { JassHandle, JassAgent, // JassEvent, JassPlayer, JassWidget, JassUnit, // JassDestructable, // JassItem, // JassAbility, // JassBuff, JassForce, JassGroup, JassTrigger, // JassTriggerCondition, // JassTriggerAction, JassTimer, JassLocation, JassRegion, JassRect, // JassBoolexpr, // JassSound, // JassConditionFunc, // JassFilterFunc, // JassUnitPool, // JassItemPool, JassRace, JassAllianceType, JassRacePreference, JassGameState, JassIGameState, JassFGameState, JassPlayerState, JassPlayerScore, JassPlayerGameResult, JassUnitState, JassAiDifficulty, JassEventId, JassGameEvent, JassPlayerEvent, JassPlayerUnitEvent, JassUnitEvent, JassLimitOp, JassWidgetEvent, JassDialogEvent, JassUnitType, JassGameSpeed, JassGameDifficulty, JassGameType, JassMapFlag, JassMapVisibility, JassMapSetting, JassMapDensity, JassMapControl, JassPlayerSlotState, JassVolumeGroup, JassCameraField, JassCameraSetup, JassPlayerColor, JassPlacement, JassStartLocPrio, JassRarityControl, JassBlendMode, JassTexMapFlags, // JassEffect, JassEffectType, JassWeatherEffect, // JassTerrainDeformation, JassFogState, // JassFogModifier, // JassDialog, // JassButton, // JassQuest, // JassQuestItem, // JassDefeatCondition, // JassTimerDialog, // JassLeaderboard, // JassMultiboard, // JassMultiboardItem, // JassTrackable, // JassGameCache, JassVersion, JassItemType, // JassTextTag, JassAttackType, JassDamageType, JassWeaponType, JassSoundType, // JassLightning, JassPathingType, // JassImage, // JassUbersplat, JassHashtable }; ================================================ FILE: src/utils/jass2/types/itemtype.ts ================================================ import JassEnum from './enum'; /** * type itemtype */ export default class JassItemType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/limitop.ts ================================================ import JassEventId from './eventid'; /** * type limitop */ export default class JassLimitOp extends JassEventId {} ================================================ FILE: src/utils/jass2/types/location.ts ================================================ import JassAgent from './agent'; /** * type location */ export default class JassLocation extends JassAgent { x: number; y: number; z = 0; constructor(x: number, y: number) { super(); this.x = x; this.y = y; } } ================================================ FILE: src/utils/jass2/types/mapcontrol.ts ================================================ import JassEnum from './enum'; /** * type mapcontrol */ export default class JassMapControl extends JassEnum {} ================================================ FILE: src/utils/jass2/types/mapdensity.ts ================================================ import JassEnum from './enum'; /** * type mapdensity */ export default class JassMapDensity extends JassEnum {} ================================================ FILE: src/utils/jass2/types/mapflag.ts ================================================ import JassEnum from './enum'; /** * type mapflag */ export default class JassMapFlag extends JassEnum {} ================================================ FILE: src/utils/jass2/types/mapsetting.ts ================================================ import JassEnum from './enum'; /** * type mapflag */ export default class JassMapFlag extends JassEnum {} ================================================ FILE: src/utils/jass2/types/mapvisibility.ts ================================================ import JassEnum from './enum'; /** * type mapvisibility */ export default class JassMapVisibility extends JassEnum {} ================================================ FILE: src/utils/jass2/types/mousebuttontype.ts ================================================ import JassEnum from './enum'; /** * type buttontype */ export default class JassMouseButtonType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/pathingtype.ts ================================================ import JassEnum from './enum'; /** * type pathingtype */ export default class JassPathingType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/placement.ts ================================================ import JassEnum from './enum'; /** * type placement */ export default class JassPlacement extends JassEnum {} ================================================ FILE: src/utils/jass2/types/player.ts ================================================ import JassAgent from './agent'; export interface Alliance { passive: boolean, helpRequest: boolean, helpResponse: boolean, sharedXp: boolean, sharedSpells: boolean, sharedVision: boolean, sharedControl: boolean, sharedAdvancedControl: boolean, rescuable: boolean, sharedVisionForced: boolean, } /** * type player */ export default class JassPlayer extends JassAgent { index: number; name: string; team = -1; startLocation = -1; forcedStartLocation = -1; color = -1; race = 0; racePreference = -1; raceSelectable = false; controller = -1; alliances: Map = new Map(); constructor(index: number, maxPlayers: number) { super(); this.index = index; this.name = `Player ${index}`; for (let i = 0; i < maxPlayers; i++) { if (i !== index) { this.alliances.set(i, { passive: false, helpRequest: false, helpResponse: false, sharedXp: false, sharedSpells: false, sharedVision: false, sharedControl: false, sharedAdvancedControl: false, rescuable: false, sharedVisionForced: false, }); } } } } ================================================ FILE: src/utils/jass2/types/playercolor.ts ================================================ import JassEnum from './enum'; /** * type playercolor */ export default class JassPlayerColor extends JassEnum {} ================================================ FILE: src/utils/jass2/types/playerevent.ts ================================================ import JassEventId from './eventid'; /** * type playerevent */ export default class JassPlayerEvent extends JassEventId {} ================================================ FILE: src/utils/jass2/types/playergameresult.ts ================================================ import JassEnum from './enum'; /** * type playergameresult */ export default class JassPlayerGameResult extends JassEnum {} ================================================ FILE: src/utils/jass2/types/playerscore.ts ================================================ import JassEnum from './enum'; /** * type playerscore */ export default class JassPlayerScore extends JassEnum {} ================================================ FILE: src/utils/jass2/types/playerslotstate.ts ================================================ import JassEnum from './enum'; /** * type playerslotstate */ export default class JassPlayerSlotState extends JassEnum {} ================================================ FILE: src/utils/jass2/types/playerstate.ts ================================================ import JassEnum from './enum'; /** * type playerstate */ export default class JassPlayerState extends JassEnum {} ================================================ FILE: src/utils/jass2/types/playerunitevent.ts ================================================ import JassEventId from './eventid'; /** * type playerunitevent */ export default class JassPlayerUnitEvent extends JassEventId {} ================================================ FILE: src/utils/jass2/types/race.ts ================================================ import JassEnum from './enum'; /** * type race */ export default class JassRace extends JassEnum {} ================================================ FILE: src/utils/jass2/types/racepreference.ts ================================================ import JassEnum from './enum'; /** * type racepreference */ export default class JassRacePreference extends JassEnum {} ================================================ FILE: src/utils/jass2/types/raritycontrol.ts ================================================ import JassEnum from './enum'; /** * type raritycontrol */ export default class JassRarityControl extends JassEnum {} ================================================ FILE: src/utils/jass2/types/rect.ts ================================================ import JassAgent from './agent'; /** * type rect */ export default class JassRect extends JassAgent { center: Float32Array; min: Float32Array; max: Float32Array; constructor(minx: number, miny: number, maxx: number, maxy: number) { super(); this.center = new Float32Array([maxx - minx, maxy - miny]); this.min = new Float32Array([minx, miny]); this.max = new Float32Array([maxx, maxy]); } } ================================================ FILE: src/utils/jass2/types/region.ts ================================================ import JassAgent from './agent'; import JassRect from './rect'; /** * type region */ export default class JassRegion extends JassAgent { rects: Set = new Set(); } ================================================ FILE: src/utils/jass2/types/soundtype.ts ================================================ import JassEnum from './enum'; /** * type soundtype */ export default class JassSoundType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/startlocprio.ts ================================================ import JassEnum from './enum'; /** * type startlocprio */ export default class JassStartLocPrio extends JassEnum {} ================================================ FILE: src/utils/jass2/types/subanimtype.ts ================================================ import JassEnum from './enum'; /** * type subanimtype */ export default class JassSubAnimType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/texmapflags.ts ================================================ import JassEnum from './enum'; /** * type texmapflags */ export default class JassTexMapFlags extends JassEnum {} ================================================ FILE: src/utils/jass2/types/timer.ts ================================================ import JassAgent from './agent'; /** * type timer */ export default class JassTimer extends JassAgent { elapsed = 0; timeout = 0; periodic = false; handlerFunc = -1; } ================================================ FILE: src/utils/jass2/types/trigger.ts ================================================ import JassAgent from './agent'; /** * type trigger */ export default class JassTrigger extends JassAgent { events: number[] = []; conditions: number[] = []; actions: number[] = []; enabled = true; } ================================================ FILE: src/utils/jass2/types/unit.ts ================================================ import { base256ToString } from '../../../common/typecast'; import JassWidget from './widget'; import JassPlayer from './player'; /** * type unit */ export default class JassUnit extends JassWidget { player: JassPlayer; unitId: string; x: number; y: number; face: number; acquireRange = 500; constructor(player: JassPlayer, unitId: number, x: number, y: number, face: number) { super(); this.player = player; this.unitId = base256ToString(unitId); this.x = x; this.y = y; this.face = face; // if (balanceRow) { // this.balanceRow = balanceRow; // this.health = balanceRow.realHP; // this.maxHealth = this.health; // this.mana = parseFloat(balanceRow.realM) || 0; // this.maxMana = this.mana; // } else if (jass.debugMode) { // console.log('Unknown unitid', unitId); // } } } ================================================ FILE: src/utils/jass2/types/unitevent.ts ================================================ import JassEventId from './eventid'; /** * type unitevent */ export default class JassUnitEvent extends JassEventId {} ================================================ FILE: src/utils/jass2/types/unitstate.ts ================================================ import JassEnum from './enum'; /** * type unitstate */ export default class JassUnitState extends JassEnum {} ================================================ FILE: src/utils/jass2/types/unittype.ts ================================================ import JassEnum from './enum'; /** * type unittype */ export default class JassUnitType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/version.ts ================================================ import JassEnum from './enum'; /** * type version */ export default class JassVersion extends JassEnum {} ================================================ FILE: src/utils/jass2/types/volumegroup.ts ================================================ import JassEnum from './enum'; /** * type volumegroup */ export default class JassVolumeGroup extends JassEnum {} ================================================ FILE: src/utils/jass2/types/weapontype.ts ================================================ import JassEnum from './enum'; /** * type weapontype */ export default class JassWeaponType extends JassEnum {} ================================================ FILE: src/utils/jass2/types/weathereffect.ts ================================================ import JassHandle from './handle'; import JassRect from './rect'; /** * type weathereffect */ export default class JassWeatherEffect extends JassHandle { whichRect: JassRect; effectId: string; enabled = false; constructor(whichRect: JassRect, effectId: string) { super(); this.whichRect = whichRect; this.effectId = effectId; } } ================================================ FILE: src/utils/jass2/types/widget.ts ================================================ import JassAgent from './agent'; /** * type widget */ export default class JassWidget extends JassAgent { health = 0; maxHealth = 0; } ================================================ FILE: src/utils/jass2/types/widgetevent.ts ================================================ import JassEventId from './eventid'; /** * type widgetevent */ export default class JassWidgetEvent extends JassEventId {} ================================================ FILE: src/utils/mappeddata.ts ================================================ import SlkFile from '../parsers/slk/file'; import { IniFile } from '../parsers/ini/file'; /** * A MappedData row. */ export class MappedDataRow { map: {[key: string]: string } = {}; set(key: string, value: string | number): void { if (typeof value !== 'string') { value = value.toString(); } this.map[key.toLowerCase()] = value; } string(key: string): string | undefined { return this.map[key.toLowerCase()]; } number(key: string): number { const string = this.string(key); if (!string) { return 0; } return parseFloat(string); } } /** * A structure that holds mapped data from INI and SLK files. * * In the case of SLK files, the first row is expected to hold the names of the columns. */ export class MappedData { map: {[key: string]: MappedDataRow } = {}; constructor(buffer?: string) { if (buffer) { this.load(buffer); } } /** * Load data from an SLK file or an INI file. * * Note that this may override previous properties! */ load(buffer: string): void { if (buffer.startsWith('ID;')) { const file = new SlkFile(); file.load(buffer); const rows = file.rows; const header = rows[0]; const map = this.map; for (let i = 1, l = rows.length; i < l; i++) { const row = rows[i]; // DialogueDemonBase.slk has an empty row. if (row) { const name = row[0]; // DialogueDemonBase.slk also has rows containing only a single underline. if (name && name !== '_') { if (!map[name]) { map[name] = new MappedDataRow(); } const mapped = map[name]; for (let j = 0, k = header.length; j < k; j++) { let key = header[j]; // UnitBalance.slk doesn't define the name of one column. if (key === undefined) { key = `column${j}`; } mapped.map[key.toLowerCase()] = row[j]; } } } } } else { const file = new IniFile(); file.load(buffer); const sections = file.sections; const map = this.map; for (const [row, properties] of sections.entries()) { if (!map[row]) { map[row] = new MappedDataRow(); } const mapped = map[row]; for (const [name, property] of properties) { mapped.map[name.toLowerCase()] = property; } } } } getRow(key: string): MappedDataRow | undefined { return this.map[key]; } getProperty(key: string, name: string): string { return this.map[key].map[name]; } setRow(key: string, values: MappedDataRow): void { this.map[key] = values; } findRow(key: string, expectedValue: string): MappedDataRow | undefined { for (const row of Object.values(this.map)) { if (row.string(key) === expectedValue) { return row; } } return; } } ================================================ FILE: src/utils/mdlx/index.ts ================================================ import sanityTest from './sanitytest/sanitytest'; import createPrimitive from './primitives/createprimitive'; import * as primitives from './primitives/primitives'; import mdlStructure from './mdlstructure'; export default { sanityTest, createPrimitive, primitives, mdlStructure, }; ================================================ FILE: src/utils/mdlx/mdlstructure.ts ================================================ import Attachment from '../../parsers/mdlx/attachment'; import Bone from '../../parsers/mdlx/bone'; import Camera from '../../parsers/mdlx/camera'; import CollisionShape from '../../parsers/mdlx/collisionshape'; import FaceEffect from '../../parsers/mdlx/faceeffect'; import Geoset from '../../parsers/mdlx/geoset'; import GeosetAnimation from '../../parsers/mdlx/geosetanimation'; import Helper from '../../parsers/mdlx/helper'; import Layer from '../../parsers/mdlx/layer'; import Light from '../../parsers/mdlx/light'; import Model from '../../parsers/mdlx/model'; import ParticleEmitter from '../../parsers/mdlx/particleemitter'; import ParticleEmitter2 from '../../parsers/mdlx/particleemitter2'; import ParticleEmitterPopcorn from '../../parsers/mdlx/particleemitterpopcorn'; import RibbonEmitter from '../../parsers/mdlx/ribbonemitter'; import Sequence from '../../parsers/mdlx/sequence'; import Texture from '../../parsers/mdlx/texture'; import TextureAnimation from '../../parsers/mdlx/textureanimation'; import TokenStream from '../../parsers/mdlx/tokenstream'; import { getObjectName, getObjectTypeName } from './sanitytest/utils'; interface MdlStructureNode { name: string; source: string; nodes?: MdlStructureNode[]; } function mdlObjects(stream: TokenStream, model: Model, objects: (Sequence | Layer | Texture | TextureAnimation | Geoset | GeosetAnimation | Bone | Light | Helper | Attachment | ParticleEmitter | ParticleEmitter2 | ParticleEmitterPopcorn | RibbonEmitter | Camera | CollisionShape | FaceEffect)[], out: MdlStructureNode[]): void { if (objects.length) { for (const [index, object] of objects.entries()) { object.writeMdl(stream, model.version); out.push({ name: getObjectName(object, index), source: stream.buffer }); stream.clear(); } } } function mdlObjectsBlock(stream: TokenStream, model: Model, objects: (Sequence | Texture | TextureAnimation)[], out: MdlStructureNode[]): void { if (objects.length) { const name = getObjectTypeName(objects[0]) + 's'; const nodes = []; mdlObjects(stream, model, objects, nodes); model.saveStaticObjectsBlock(stream, name, objects); out.push({ name, source: stream.buffer, nodes }); stream.clear(); } } export default function mdlStructure(model: Model): MdlStructureNode[] { const stream = new TokenStream(); const out = []; model.saveVersionBlock(stream); out.push({ name: 'Version', source: stream.buffer }); stream.clear(); model.saveModelBlock(stream); out.push({ name: 'Model', source: stream.buffer }); stream.clear(); mdlObjectsBlock(stream, model, model.sequences, out); if (model.globalSequences.length) { model.saveGlobalSequenceBlock(stream); out.push({ name: 'GlobalSequences', source: stream.buffer }); stream.clear(); } mdlObjectsBlock(stream, model, model.textures, out); if (model.materials.length) { const nodes = []; for (const [index, material] of model.materials.entries()) { const layerNodes = []; mdlObjects(stream, model, material.layers, layerNodes); material.writeMdl(stream, model.version); nodes.push({ name: `Material ${index}`, source: stream.buffer, nodes: layerNodes }); stream.clear(); } model.saveStaticObjectsBlock(stream, 'Materials', model.materials); out.push({ name: 'Materials', source: stream.buffer, nodes }); stream.clear(); } mdlObjectsBlock(stream, model, model.textureAnimations, out); mdlObjects(stream, model, model.geosets, out); mdlObjects(stream, model, model.geosetAnimations, out); mdlObjects(stream, model, model.bones, out); mdlObjects(stream, model, model.lights, out); mdlObjects(stream, model, model.helpers, out); mdlObjects(stream, model, model.attachments, out); if (model.pivotPoints.length) { model.savePivotPointBlock(stream); out.push({ name: 'PivotPoints', source: stream.buffer }); stream.clear(); } mdlObjects(stream, model, model.particleEmitters, out); mdlObjects(stream, model, model.particleEmitters2, out); mdlObjects(stream, model, model.particleEmittersPopcorn, out); mdlObjects(stream, model, model.ribbonEmitters, out); mdlObjects(stream, model, model.cameras, out); mdlObjects(stream, model, model.eventObjects, out); mdlObjects(stream, model, model.collisionShapes, out); mdlObjects(stream, model, model.faceEffects, out); if (model.bindPose.length) { model.saveBindPoseBlock(stream); out.push({ name: 'BindPose', source: stream.buffer }); stream.clear(); } return out; } ================================================ FILE: src/utils/mdlx/primitives/createprimitive.ts ================================================ import MdlxModel from '../../../parsers/mdlx/model'; import MdlxTexture from '../../../parsers/mdlx/texture'; import MdlxMaterial from '../../../parsers/mdlx/material'; import MdlxLayer, { Flags } from '../../../parsers/mdlx/layer'; import MdlxGeoset from '../../../parsers/mdlx/geoset'; import MdlxGeosetAnimation from '../../../parsers/mdlx/geosetanimation'; import MdlxBone from '../../../parsers/mdlx/bone'; import ModelViewer from '../../../viewer/viewer'; import Texture from '../../../viewer/texture'; import { PathSolver } from '../../../viewer/handlerresource'; import MdxModel from '../../../viewer/handlers/mdx/model'; interface Primitive { vertices: Float32Array; uvs: Float32Array; faces: Uint16Array; edges: Uint16Array; boundingRadius: number; } interface Material { lines?: boolean; color?: Float32Array; texture?: Texture | Promise; twoSided?: boolean; } export default function createPrimitive(viewer: ModelViewer, primitive: Primitive, material: Material): Promise { let lines: boolean | undefined; let color: Float32Array | undefined; let texture: Texture | Promise | undefined; let layerFlags = Flags.Unshaded; if (material) { lines = material.lines; color = material.color; texture = material.texture; if (material.twoSided) { layerFlags |= Flags.TwoSided; } } const model = new MdlxModel(); // Extent const extent = model.extent; const r = primitive.boundingRadius; extent.min.fill(-r); extent.max.fill(r); extent.boundsRadius = r; // Texture const tex = new MdlxTexture(); tex.path = 'PLACEHOLDER'; model.textures[0] = tex; const pathSolver: PathSolver = (src: unknown): unknown => { if (src === model) { return model; } return texture; }; // Material const mat = new MdlxMaterial(); const layer = new MdlxLayer(); layer.textureId = 0; layer.flags = layerFlags; mat.layers[0] = layer; model.materials[0] = mat; // Geoset const geoset = new MdlxGeoset(); geoset.vertices = primitive.vertices; geoset.uvSets[0] = primitive.uvs; geoset.matrixGroups = new Uint32Array([1]); geoset.matrixIndices = new Uint32Array([0]); geoset.vertexGroups = new Uint8Array(primitive.vertices.length / 3); let faceTypeGroup = 4; let indices = primitive.faces; if (lines) { faceTypeGroup = 1; indices = primitive.edges; } geoset.faceTypeGroups = new Uint32Array([faceTypeGroup]); geoset.faceGroups = new Uint32Array([indices.length]); geoset.faces = indices; model.geosets[0] = geoset; // Color via a geoset animation. if (color) { const geosetAnimation = new MdlxGeosetAnimation(); geosetAnimation.geosetId = 0; geosetAnimation.color = color; model.geosetAnimations[0] = geosetAnimation; } // Bone - otherwise can't transform the instance. const bone = new MdlxBone(); bone.objectId = 0; model.bones[0] = bone; // Load and return the promise. return >viewer.load(model, pathSolver); } ================================================ FILE: src/utils/mdlx/primitives/primitives.ts ================================================ interface PrimitiveShape { vertices: Float32Array; uvs: Float32Array; faces: Uint16Array; edges: Uint16Array; boundingRadius: number; } /** * Creates a rectangle geometry object. */ export function createRectangle(w: number, d: number): PrimitiveShape { return { vertices: new Float32Array([-w, d, 0, -w, -d, 0, w, -d, 0, w, d, 0]), uvs: new Float32Array([0, 0, 0, 1, 1, 1, 1, 0]), faces: new Uint16Array([0, 1, 2, 0, 2, 3]), edges: new Uint16Array([0, 1, 1, 2, 2, 3, 3, 0]), boundingRadius: Math.hypot(w, d), }; } /** * Creates a unit rectangle geometry object. */ export function createUnitRectangle(): PrimitiveShape { return createRectangle(1, 1); } /** * Creates a cube geometry object. */ export function createCube(w: number, d: number, h: number): PrimitiveShape { return { vertices: new Float32Array([-w, -d, -h, -w, -d, h, -w, d, -h, -w, d, h, w, d, -h, w, d, h, w, -d, -h, w, -d, h]), uvs: new Float32Array([0, 0, 0, 1, 0.25, 0, 0.25, 1, 0.5, 0, 0.5, 1, 0.75, 0, 0.75, 1]), faces: new Uint16Array([0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6, 5, 7, 6, 6, 7, 0, 7, 1, 0, 0, 2, 4, 0, 4, 6, 1, 5, 3, 1, 7, 5]), edges: new Uint16Array([0, 1, 2, 3, 4, 5, 6, 7, 0, 2, 2, 4, 4, 6, 6, 0, 1, 3, 3, 5, 5, 7, 7, 1]), boundingRadius: Math.hypot(w, d, h), }; } /** * Creates a unit cube geometry object. */ export function createUnitCube(): PrimitiveShape { return createCube(1, 1, 1); } /** * Creates a sphere geometry object. */ export function createSphere(radius: number, stacks: number, slices: number): PrimitiveShape { const points = (stacks + 1) * (slices + 1); const vertices = new Float32Array(points * 3); const uvs = new Float32Array(points * 2); const faces = new Uint16Array(stacks * slices * 6); const edges = new Uint16Array(stacks * slices * 6); for (let stack = 0, vOffset = 0, uOffset = 0; stack <= stacks; stack++) { const theta = stack * Math.PI / stacks; const sinTheta = Math.sin(theta); const cosTheta = Math.cos(theta); for (let slice = 0; slice <= slices; slice += 1, vOffset += 3, uOffset += 2) { const phi = slice * 2 * Math.PI / slices; const sinPhi = Math.sin(phi); const cosPhi = Math.cos(phi); vertices[vOffset + 0] = cosPhi * sinTheta * radius; vertices[vOffset + 1] = sinPhi * sinTheta * radius; vertices[vOffset + 2] = cosTheta * radius; uvs[uOffset + 0] = slice / slices; uvs[uOffset + 1] = 1 - (stack / stacks); } } for (let stack = 0, fOffset = 0; stack < stacks; stack++) { for (let slice = 0; slice < slices; slice += 1, fOffset += 6) { const first = (stack * (slices + 1)) + slice; const second = first + slices + 1; // Faces faces[fOffset + 0] = first; faces[fOffset + 1] = second; faces[fOffset + 2] = first + 1; faces[fOffset + 3] = second; faces[fOffset + 4] = second + 1; faces[fOffset + 5] = first + 1; // Edges edges[fOffset + 0] = first; edges[fOffset + 1] = second; edges[fOffset + 2] = first; edges[fOffset + 3] = first + 1; edges[fOffset + 4] = second; edges[fOffset + 5] = second + 1; } } return { vertices: vertices, uvs: uvs, faces: faces, edges: edges, boundingRadius: radius, }; } /** * Creates a unit sphere geometry object. */ export function createUnitSphere(stacks: number, slices: number): PrimitiveShape { return createSphere(1, stacks, slices); } /** * Creates a cylinder geometry object. */ export function createCylinder(radius: number, height: number, slices: number): PrimitiveShape { slices = Math.max(slices, 3); const points = (slices + 1) * 2 + 2; const vertices = new Float32Array(points * 3); const uvs = new Float32Array(points * 2); const faces = new Uint16Array(slices * 12); const edges = new Uint16Array(slices * 10); const step = (Math.PI * 2) / slices; let vOffset = 0; let uOffset = 0; for (let slice = 0; slice < slices + 1; slice += 1, vOffset += 6, uOffset += 4) { const x = Math.cos(step * slice) * radius; const y = Math.sin(step * slice) * radius; const u = slice / slices; vertices[vOffset + 0] = x; vertices[vOffset + 1] = y; vertices[vOffset + 2] = height; vertices[vOffset + 3] = x; vertices[vOffset + 4] = y; vertices[vOffset + 5] = -height; uvs[uOffset + 0] = u; uvs[uOffset + 1] = 1; uvs[uOffset + 2] = u; uvs[uOffset + 3] = 0; } // Poles vertices[vOffset + 0] = 0; vertices[vOffset + 1] = 0; vertices[vOffset + 2] = height; vertices[vOffset + 3] = 0; vertices[vOffset + 4] = 0; vertices[vOffset + 5] = -height; uvs[uOffset + 0] = 0; uvs[uOffset + 1] = 1; uvs[uOffset + 2] = 0; uvs[uOffset + 3] = 0; for (let slice = 0, fOffset = 0, eOffset = 0; slice < slices; slice += 1, fOffset += 12, eOffset += 10) { const first = slice * 2; // Faces faces[fOffset + 0] = first + 0; faces[fOffset + 1] = first + 1; faces[fOffset + 2] = (first + 3) % (points - 2); faces[fOffset + 3] = first + 0; faces[fOffset + 4] = (first + 3) % (points - 2); faces[fOffset + 5] = (first + 2) % (points - 2); faces[fOffset + 6] = first + 0; faces[fOffset + 7] = (first + 2) % (points - 2); faces[fOffset + 8] = points - 2; faces[fOffset + 9] = first + 1; faces[fOffset + 10] = (first + 3) % (points - 2); faces[fOffset + 11] = points - 1; // Edges edges[eOffset + 0] = first + 0; edges[eOffset + 1] = first + 1; edges[eOffset + 2] = first + 0; edges[eOffset + 3] = (first + 2) % (points - 2); edges[eOffset + 4] = first + 1; edges[eOffset + 5] = (first + 3) % (points - 2); edges[eOffset + 6] = first + 0; edges[eOffset + 7] = points - 2; edges[eOffset + 8] = first + 1; edges[eOffset + 9] = points - 1; } return { vertices: vertices, uvs: uvs, faces: faces, edges: edges, boundingRadius: Math.hypot(radius, height), }; } /** * Creates a unit cylinder geometry object. */ export function createUnitCylinder(slices: number): PrimitiveShape { return createCylinder(1, 1, slices); } /** * Create a furstum geometry. */ export function createFrustum(fieldOfView: number, aspectRatio: number, nearClipPlane: number, farClipPlane: number): PrimitiveShape { const tanFov = 2 * Math.tan(fieldOfView / 2); const nearHeight = (tanFov * nearClipPlane) / 2; const nearWidth = (nearClipPlane * aspectRatio) / 2; const farHeight = (tanFov * farClipPlane) / 2; const farWidth = (farClipPlane * aspectRatio) / 2; return { vertices: new Float32Array([ -nearWidth, -nearHeight, nearClipPlane, -nearWidth, nearHeight, nearClipPlane, -farWidth, -farHeight, farClipPlane, -farWidth, farHeight, farClipPlane, farWidth, -farHeight, farClipPlane, farWidth, farHeight, farClipPlane, nearWidth, -nearHeight, nearClipPlane, nearWidth, nearHeight, nearClipPlane]), uvs: new Float32Array([0, 0, 0, 1, 0.25, 0, 0.25, 1, 0.5, 0, 0.5, 1, 0.75, 0, 0.75, 1]), faces: new Uint16Array([0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6, 5, 7, 6, 6, 7, 0, 7, 1, 0, 0, 2, 4, 0, 4, 6, 1, 5, 3, 1, 7, 5]), edges: new Uint16Array([0, 1, 2, 3, 4, 5, 6, 7, 0, 2, 2, 4, 4, 6, 6, 0, 1, 3, 3, 5, 5, 7, 7, 1]), boundingRadius: Math.hypot(farWidth, farHeight), }; } ================================================ FILE: src/utils/mdlx/sanitytest/data.ts ================================================ import Model from '../../../parsers/mdlx/model'; import GenericObject from '../../../parsers/mdlx/genericobject'; import { getObjectName, MdlxType } from './utils'; export interface SanityTestMessage { type: 'error' | 'severe' | 'warning' | 'unused'; message: string; } export interface SanityTestNode { type: 'node'; name: string; errors: number; severe: number; warnings: number; unused: number; nodes: (SanityTestNode | SanityTestMessage)[]; uses?: number; } export default class SanityTestData { model: Model; objects: GenericObject[] = []; current: SanityTestNode; stack: SanityTestNode[]; map: Map = new Map(); foundStand = false; foundDeath = false; boneUsageMap = new Map(); constructor(model: Model) { this.model = model; this.current = { type: 'node', name: '', errors: 0, severe: 0, warnings: 0, unused: 0, nodes: []}; this.stack = [this.current]; this.addObjects(model.sequences); this.addObjects(model.globalSequences); this.addObjects(model.textures); this.addObjects(model.materials); this.addObjects(model.textureAnimations); this.addObjects(model.geosets); this.addObjects(model.geosetAnimations); this.addObjects(model.bones); this.addObjects(model.lights); this.addObjects(model.helpers); this.addObjects(model.attachments); this.addObjects(model.particleEmitters); this.addObjects(model.particleEmitters2); this.addObjects(model.particleEmittersPopcorn); this.addObjects(model.ribbonEmitters); this.addObjects(model.cameras); this.addObjects(model.eventObjects); this.addObjects(model.collisionShapes); this.addObjects(model.faceEffects); } /** * Adds nodes for all of the given objects. * Also handles the flat array of generic objects. */ addObjects(objects: MdlxType[]): void { if (objects.length) { const areGeneric = objects[0] instanceof GenericObject; for (let i = 0, l = objects.length; i < l; i++) { const object = objects[i]; const name = getObjectName(object, i); const node = { type: 'node', name, errors: 0, severe: 0, warnings: 0, unused: 0, nodes: []}; if (!areGeneric) { node.uses = 0; } this.map.set(object, node); } if (areGeneric) { this.objects.push(...objects); } } } /** * Pushes to the stack the node the given object maps to. * If this node does not exist, a new one will be created, which is used by internal nodes like material layers. */ push(object: MdlxType, index: number): void { let node = this.map.get(object); if (!node) { const name = getObjectName(object, index); node = { type: 'node', name, errors: 0, severe: 0, warnings: 0, unused: 0, nodes: []}; } this.current.nodes.push(node); this.current = node; this.stack.unshift(node); } /** * Pops the current node from the stack. */ pop(): void { this.stack.shift(); this.current = this.stack[0]; } /** * Adds a reference to the node the given object maps to. */ addReference(object: MdlxType): void { const node = this.map.get(object); if (node.uses !== undefined) { node.uses += 1; } } /** * Add a reference to the current node. */ addImplicitReference(): void { const node = this.current; if (node.uses !== undefined) { node.uses += 1; } } addError(message: string): void { this.current.nodes.push({ type: 'error', message }); for (const node of this.stack) { node.errors += 1; } } addSevere(message: string): void { this.current.nodes.push({ type: 'severe', message }); for (const node of this.stack) { node.severe += 1; } } addWarning(message: string): void { this.current.nodes.push({ type: 'warning', message }); for (const node of this.stack) { node.warnings += 1; } } addUnused(message: string): void { this.current.nodes.push({ type: 'unused', message }); for (const node of this.stack) { node.unused += 1; } } assertError(condition: boolean, message: string): void { if (!condition) { this.addError(message); } } assertSevere(condition: boolean, message: string): void { if (!condition) { this.addSevere(message); } } assertWarning(condition: boolean, message: string): void { if (!condition) { this.addWarning(message); } } assertUnused(condition: boolean, message: string): void { if (!condition) { this.addUnused(message); } } } ================================================ FILE: src/utils/mdlx/sanitytest/sanitytest.ts ================================================ import Model from '../../../parsers/mdlx/model'; import SanityTestData, { SanityTestMessage, SanityTestNode } from './data'; import { testObjects, cleanNode } from './utils'; import { testHeader, testSequences, testGlobalSequence, testTextures, testMaterial, testGeoset, testGeosetAnimation, testBone, testLight, testAttachments, testPivotPoints, testParticleEmitter, testParticleEmitter2, testParticleEmitterPopcorn, testRibbonEmitter, testEventObject, testCamera, testFaceEffect, testBindPose } from './testers'; export interface SanityTestResult { type: string; nodes: (SanityTestNode | SanityTestMessage)[]; errors: number; severe: number; warnings: number; unused: number; } /** * Run a sanity test on the model and return the results. */ export default function sanityTest(model: Model): SanityTestResult { const data = new SanityTestData(model); // Run the tests. testHeader(data); testSequences(data); testObjects(data, model.globalSequences, testGlobalSequence); testTextures(data); testObjects(data, model.materials, testMaterial); testObjects(data, model.textureAnimations); testObjects(data, model.geosets, testGeoset); testObjects(data, model.geosetAnimations, testGeosetAnimation); testObjects(data, model.bones, testBone); testObjects(data, model.lights, testLight); testObjects(data, model.helpers); testAttachments(data); testPivotPoints(data); testObjects(data, model.particleEmitters, testParticleEmitter); testObjects(data, model.particleEmitters2, testParticleEmitter2); if (model.version > 800) { testObjects(data, model.particleEmittersPopcorn, testParticleEmitterPopcorn); } testObjects(data, model.ribbonEmitters, testRibbonEmitter); testObjects(data, model.eventObjects, testEventObject); testObjects(data, model.cameras, testCamera); testObjects(data, model.collisionShapes); if (model.version > 800) { testObjects(data, model.faceEffects, testFaceEffect); testBindPose(data); } const root = data.stack[0]; // Remove nodes that passed the test. cleanNode(root); const { nodes, errors, severe, warnings } = root; let { unused } = root; // Add top-level objects that are not used. for (const node of nodes) { if (node.type === 'node') { if (node.uses === 0) { unused += 1; } } } return { type: 'node', nodes, errors, severe, warnings, unused }; } ================================================ FILE: src/utils/mdlx/sanitytest/testers.ts ================================================ import { extname } from '../../../common/path'; import Sequence from '../../../parsers/mdlx/sequence'; import Texture from '../../../parsers/mdlx/texture'; import Material from '../../../parsers/mdlx/material'; import Layer, { FilterMode as LayerFilterMode } from '../../../parsers/mdlx/layer'; import Geoset from '../../../parsers/mdlx/geoset'; import GeosetAnimation from '../../../parsers/mdlx/geosetanimation'; import Bone from '../../../parsers/mdlx/bone'; import Light from '../../../parsers/mdlx/light'; import ParticleEmitter from '../../../parsers/mdlx/particleemitter'; import ParticleEmitter2, { FilterMode as Particle2FilterMode, Flags as Particle2Flags } from '../../../parsers/mdlx/particleemitter2'; import ParticleEmitterPopcorn from '../../../parsers/mdlx/particleemitterpopcorn'; import RibbonEmitter from '../../../parsers/mdlx/ribbonemitter'; import EventObject from '../../../parsers/mdlx/eventobject'; import Camera from '../../../parsers/mdlx/camera'; import FaceEffect from '../../../parsers/mdlx/faceeffect'; import SanityTestData from './data'; import { sequenceNames, replaceableIds, testObjects, testReference, getTextureIds, testGeosetSkinning, hasAnimation, getAnimation, testExtent, testAndGetReference } from './utils'; import testTracks from './tracks'; export function testHeader(data: SanityTestData): void { const version = data.model.version; if (version !== 800 && version !== 900 && version !== 1000) { data.addWarning(`Unknown version: ${version}`); } if (version === 900) { data.addError('Version 900 is not supported by Warcrft 3'); } if (data.model.animationFile !== '') { data.addWarning(`The animation file should probably be empty, currently set to: "${data.model.animationFile}"`); } testExtent(data, data.model.extent); } export function testSequences(data: SanityTestData): void { const sequences = data.model.sequences; if (sequences.length) { testObjects(data, sequences, testSequence); data.assertSevere(data.foundStand, 'Missing "Stand" sequence'); data.assertSevere(data.foundDeath, 'Missing "Death" sequence'); } else { data.addWarning('No sequences'); } } function testSequence(data: SanityTestData, sequence: Sequence, index: number): void { const name = sequence.name; const tokens = name.toLowerCase().trim().split('-')[0].split(/\s+/); let token = tokens[0]; const interval = sequence.interval; const length = interval[1] - interval[0]; const sequences = data.model.sequences; for (let i = 0; i < index; i++) { const otherSequence = sequences[i]; const otherInterval = otherSequence.interval; // Reforged fixed these weird issues with sequence ordering. if (data.model.version === 800) { if (interval[0] === otherInterval[0]) { data.addSevere(`This sequence starts at the same frame as sequence ${i} "${otherSequence.name}"`); } else if (interval[0] < otherInterval[1]) { data.addSevere(`This sequence starts before sequence ${i} "${otherSequence.name}" ends`); } } } if (token === 'alternate') { token = tokens[1]; } if (token === 'stand') { data.foundStand = true; } if (token === 'death') { data.foundDeath = true; } data.addImplicitReference(); data.assertWarning(sequenceNames.has(token), `"${token}" is not a standard name`); data.assertWarning(length !== 0, 'Zero length'); data.assertWarning(length > -1, `Negative length: ${length}`); testExtent(data, sequence.extent); } export function testGlobalSequence(data: SanityTestData, sequence: number): void { data.assertWarning(sequence !== 0, 'Zero length'); data.assertWarning(sequence >= 0, `Negative length: ${sequence}`); } export function testTextures(data: SanityTestData): void { const textures = data.model.textures; if (textures.length) { testObjects(data, textures, testTexture); } else { data.addWarning('No textures'); } } function testTexture(data: SanityTestData, texture: Texture): void { const replaceableId = texture.replaceableId; const path = texture.path.toLowerCase(); const ext = extname(path); data.assertError(path === '' || ext === '.blp' || ext === '.tga' || ext === '.tif' || ext === '.dds', `Corrupted path: "${path}"`); data.assertError(replaceableId === 0 || replaceableIds.has(replaceableId), `Unknown replaceable ID: ${replaceableId}`); data.assertWarning(path === '' || replaceableId === 0, `Path "${path}" and replaceable ID ${replaceableId} used together`); } export function testMaterial(data: SanityTestData, material: Material): void { const layers = material.layers; const shader = material.shader; if (data.model.version > 800) { data.assertWarning(shader === '' || shader === 'Shader_SD_FixedFunction' || shader === 'Shader_HD_DefaultUnit', `Unknown shader: "${shader}"`); } if (layers.length) { testObjects(data, layers, testLayer); } else { data.addWarning('No layers'); } } function testLayer(data: SanityTestData, layer: Layer): void { const textures = data.model.textures; const textureAnimations = data.model.textureAnimations; for (const textureId of getTextureIds(layer)) { testReference(data, textures, textureId, 'texture'); } const textureAnimationId = layer.textureAnimationId; if (textureAnimationId !== -1) { testReference(data, textureAnimations, textureAnimationId, 'texture animation'); } const filterMode = layer.filterMode; data.assertWarning(filterMode >= LayerFilterMode.None && filterMode <= LayerFilterMode.Modulate2x, `Invalid filter mode: ${layer.filterMode}`); } export function testGeoset(data: SanityTestData, geoset: Geoset, index: number): void { const geosetAnimations = data.model.geosetAnimations; const material = testAndGetReference(data, data.model.materials, geoset.materialId, 'material'); let isHd = false; if (material && material.shader === 'Shader_HD_DefaultUnit') { isHd = true; } if (!isHd) { // When a geoset has too many vertices (or faces? or both?) it will render completely bugged in WC3. // I don't know the exact number, but here are numbers that I tested: // // Verts Faces Result // ---------------------- // 7433 16386 Bugged // 7394 16290 Good // const GUESSED_MAX_VERTICES = 7433 * 3; data.assertSevere(geoset.vertices.length < GUESSED_MAX_VERTICES, `Too many vertices in one geoset: ${geoset.vertices.length / 3}`); } testGeosetSkinning(data, geoset); if (geosetAnimations.length) { const references = []; for (let j = 0, k = geosetAnimations.length; j < k; j++) { if (geosetAnimations[j].geosetId === index) { references.push(j); } } data.assertWarning(references.length <= 1, `Referenced by ${references.length} geoset animations: ${references.join(', ')}`); } if (geoset.faces.length) { data.addImplicitReference(); } else { // The game and my code have no issue with geosets containing no faces, but Magos crashes, so add a warning in addition to it being useless. data.addWarning('Zero faces'); } // The game and my code have no issue with geosets having any number of sequence extents, but Magos fails to parse, so add a warning. // Either way this is only relevant to version 800, because there seem to always be 0 extents in >800 models. if (geoset.sequenceExtents.length !== data.model.sequences.length && data.model.version === 800) { data.addWarning(`Number of sequence extents (${geoset.sequenceExtents.length}) does not match the number of sequences (${data.model.sequences.length})`); } testExtent(data, geoset.extent); for (const extent of geoset.sequenceExtents) { testExtent(data, extent); } } export function testGeosetAnimation(data: SanityTestData, geosetAnimation: GeosetAnimation): void { const geosets = data.model.geosets; const geosetId = geosetAnimation.geosetId; data.addImplicitReference(); testReference(data, geosets, geosetId, 'geoset'); } const SUPPOSED_ALPHA_THRESHOLD = 0.1; export function testBone(data: SanityTestData, bone: Bone, index: number): void { const geosets = data.model.geosets; const geosetAnimations = data.model.geosetAnimations; const geosetId = bone.geosetId; const geosetAnimationId = bone.geosetAnimationId; if (geosetId !== -1) { testReference(data, geosets, geosetId, 'geoset'); } if (geosetAnimationId !== -1 && testReference(data, geosetAnimations, geosetAnimationId, 'geoset animation')) { const geosetAnimation = geosetAnimations[geosetAnimationId]; if (geosetId !== -1 && geosetAnimation.alpha < SUPPOSED_ALPHA_THRESHOLD && !hasAnimation(geosetAnimation, 'KGAO')) { data.addSevere(`Referencing geoset ${geosetId} and geoset animation ${geosetAnimationId} with a 0 alpha, the geoset may be invisible`); } } data.assertWarning(data.boneUsageMap.get(index) > 0, `There are no vertices attached to this bone`); } export function testLight(data: SanityTestData, light: Light): void { const attenuation = light.attenuation; data.assertWarning(attenuation[0] >= 80, `Minimum attenuation should probably be bigger than or equal to 80, but is ${attenuation[0]}`); data.assertWarning(attenuation[1] <= 200, `Maximum attenuation should probably be smaller than or equal to 200, but is ${attenuation[1]}`); data.assertWarning(attenuation[1] - attenuation[0] > 0, `The maximum attenuation should be bigger than the minimum, but isn't`); } export function testAttachments(data: SanityTestData): void { const attachments = data.model.attachments; let foundOrigin = false; for (const attachment of attachments) { const path = attachment.path; if (path.length) { const lowerCase = path.toLowerCase(); data.assertError(lowerCase.endsWith('.mdl') || lowerCase.endsWith('.mdx'), `Invalid path "${path}"`); } if (attachment.name.startsWith('Origin Ref')) { foundOrigin = true; } } if (!foundOrigin) { data.addWarning('Missing the Origin attachment point'); } } export function testPivotPoints(data: SanityTestData): void { const pivotPoints = data.model.pivotPoints; const objects = data.objects; data.assertWarning(pivotPoints.length === objects.length, `Expected ${objects.length} pivot points, got ${pivotPoints.length}`); } export function testParticleEmitter(data: SanityTestData, emitter: ParticleEmitter): void { const path = emitter.path.toLowerCase(); data.assertError(path.endsWith('.mdl') || path.endsWith('.mdx'), 'Invalid path'); } export function testParticleEmitter2(data: SanityTestData, emitter: ParticleEmitter2): void { const replaceableId = emitter.replaceableId; testReference(data, data.model.textures, emitter.textureId, 'texture'); const filterMode = emitter.filterMode; data.assertWarning(filterMode >= Particle2FilterMode.Blend && filterMode <= Particle2FilterMode.AlphaKey, `Invalid filter mode: ${emitter.filterMode}`); data.assertError(replaceableId === 0 || replaceableIds.has(replaceableId), `Invalid replaceable ID: ${replaceableId}`); if (emitter.flags & Particle2Flags.XYQuad) { data.assertSevere(emitter.speed !== 0 && emitter.latitude !== 0, 'XY Quad emitters must have a non-zero speed and latitude'); } data.assertSevere(emitter.timeMiddle >= 0 && emitter.timeMiddle <= 1, `Expected time middle to be between 0 and 1, got ${emitter.timeMiddle}`); if (emitter.squirt && !getAnimation(emitter, 'KP2E')) { data.addSevere('Using squirt without animating the emission rate'); } } export function testParticleEmitterPopcorn(data: SanityTestData, emitter: ParticleEmitterPopcorn): void { data.assertSevere(emitter.animationVisiblityGuide.length > 0, 'No animation visibility guide'); } export function testRibbonEmitter(data: SanityTestData, emitter: RibbonEmitter): void { testReference(data, data.model.materials, emitter.materialId, 'material'); } export function testEventObject(data: SanityTestData, eventObject: EventObject): void { testTracks(data, eventObject); } export function testCamera(data: SanityTestData, _camera: Camera): void { // I don't know what the rules are as to when cameras are used for portraits. // Therefore, for now never report them as not used. data.addImplicitReference(); } export function testFaceEffect(data: SanityTestData, faceEffect: FaceEffect): void { const path = faceEffect.path; if (path.length) { data.assertError(path.endsWith('.facefx') || path.endsWith('.facefx_ingame'), `Corrupted face effect path: "${path}"`); } data.addImplicitReference(); } export function testBindPose(data: SanityTestData): void { const matrices = data.model.bindPose; const objects = data.objects; if (matrices.length && objects.length) { // There's always an extra matrix for some reason. // Face effects? but also models with no face effects have it. data.assertWarning(matrices.length === objects.length + 1, `Expected ${objects.length + 1} matrices, got ${matrices.length}`); } } ================================================ FILE: src/utils/mdlx/sanitytest/tracks.ts ================================================ import { Animation, InterpolationType } from '../../../parsers/mdlx/animations'; import EventObject from '../../../parsers/mdlx/eventobject'; import SanityTestData from './data'; import { testReference } from './utils'; function getSequenceFromFrame(data: SanityTestData, frame: number, globalSequenceId: number): number { if (globalSequenceId === -1) { const sequences = data.model.sequences; for (let i = 0, l = sequences.length; i < l; i++) { const interval = sequences[i].interval; if (frame >= interval[0] && frame <= interval[1]) { return i; } } } else { const end = data.model.globalSequences[globalSequenceId]; if (frame >= 0 && frame <= end) { return globalSequenceId; } } return -1; } function seprateTracks(data: SanityTestData, frames: number[] | Uint32Array, globalSequenceId: number, separated: number[][]): void { let lastFrame = -Infinity; for (let i = 0, l = frames.length; i < l; i++) { const frame = frames[i]; data.assertWarning(frame >= 0, `Track ${i} has a negative frame ${frame}`); if (frame === lastFrame) { data.addWarning(`Track ${i} has the same frame ${frame} as track ${i - 1}`); } else if (frame < lastFrame) { data.addSevere(`Track ${i} at frame ${frame} is lower than the track before it at ${lastFrame}`); } const sequence = getSequenceFromFrame(data, frame, globalSequenceId); if (sequence !== -1) { separated[sequence].push(i); } else { // Frame 0 seems to be special. // Or maybe it's the first keyframe regardless of the frame. // Who knows. if (frame !== 0 && frames.length > 1) { if (globalSequenceId === -1) { data.addUnused(`Track ${i} at frame ${frame} is not in any sequence`); } else { data.addUnused(`Track ${i} at frame ${frame} is not in global sequence ${globalSequenceId}`); } } } lastFrame = frame; } } function getSequenceName(data: SanityTestData, sequence: number, globalSequenceId: number): string { if (globalSequenceId === -1) { return `sequence "${data.model.sequences[sequence].name}"`; } else { return `global sequence ${globalSequenceId}`; } } const EPSILON = 0.001; export function getValuesDiff(a: Uint32Array | Float32Array, b: Uint32Array | Float32Array, c: Uint32Array | Float32Array): number { let d = 0; for (let i = 0, l = a.length; i < l; i++) { const ai = a[i]; const d1 = Math.abs(ai - b[i]); const d2 = Math.abs(ai - c[i]); if (d1 > d) { d = d1; } if (d2 > d) { d = d2; } } return d; } export function areValuesEqual(a: Uint32Array | Float32Array, b: Uint32Array | Float32Array): boolean { for (let i = 0, l = a.length; i < l; i++) { if (a[i] !== b[i]) { return false; } } return true; } function testSequenceTracks(data: SanityTestData, indices: number[], sequence: number, object: Animation, frames: number[] | Uint32Array): void { const { globalSequenceId, interpolationType, values } = object; let start; if (globalSequenceId === -1) { start = data.model.sequences[sequence].interval[0]; } else { start = 0; } const firstIndex = indices[0]; const lastIndex = indices[indices.length - 1]; const firstFrame = frames[firstIndex]; // Missing the opening track for a specific sequence can cause bugged warping with negative interpolations. if (interpolationType !== InterpolationType.DontInterp && firstFrame !== start) { const firstValue = values[firstIndex]; const lastValue = values[lastIndex]; // If the first and last values are equal, even though there's warping, it won't do anything. if (!areValuesEqual(firstValue, lastValue)) { data.addSevere(`Missing opening track for ${getSequenceName(data, sequence, globalSequenceId)} at frame ${start} where it is needed`); } } // Check for consecutive tracks with the same values. if (indices.length > 2) { let a = values[indices[0]]; let b = values[indices[1]]; for (let i = 2, l = indices.length; i < l; i++) { const c = values[indices[i]]; const index = indices[i - 1]; const d = getValuesDiff(a, b, c); if (d === 0) { data.addUnused(`Track ${index} at frame ${frames[index]} has exactly the same value as tracks ${index - 1} and ${index + 1}`); } else if (d < EPSILON) { data.addUnused(`Track ${index} at frame ${frames[index]} has roughly the same value as tracks ${index - 1} and ${index + 1}`); } a = b; b = c; } } } export default function testTracks(data: SanityTestData, object: Animation | EventObject): void { let framesOrTracks; if (object instanceof Animation) { data.assertWarning(object.frames.length > 0, 'Zero tracks'); framesOrTracks = object.frames; } else { data.assertError(object.tracks.length > 0, 'Zero tracks'); framesOrTracks = object.tracks; } const globalSequenceId = object.globalSequenceId; const separated: number[][] = []; if (globalSequenceId === -1) { data.assertWarning(data.model.sequences.length > 0, 'This animation exists, but the model has no sequences'); for (let i = 0, l = data.model.sequences.length; i < l; i++) { separated.push([]); } } else if (testReference(data, data.model.globalSequences, globalSequenceId, 'global sequence')) { separated[globalSequenceId] = []; } else { return; } seprateTracks(data, framesOrTracks, globalSequenceId, separated); // Since event objects work on the concept of notes, where a keyframe denotes emission, check just animation keyframe values. if (object instanceof Animation) { for (let i = 0, l = separated.length; i < l; i++) { const indices = separated[i]; if (indices && indices.length > 1) { testSequenceTracks(data, indices, i, object, framesOrTracks); } } } } ================================================ FILE: src/utils/mdlx/sanitytest/utils.ts ================================================ import unique from '../../../common/arrayunique'; import { basename } from '../../../common/path'; import { Animation, InterpolationType } from '../../../parsers/mdlx/animations'; import AnimatedObject from '../../../parsers/mdlx/animatedobject'; import GenericObject from '../../../parsers/mdlx/genericobject'; import Extent from '../../../parsers/mdlx/extent'; import Sequence from '../../../parsers/mdlx/sequence'; import Texture from '../../../parsers/mdlx/texture'; import Material from '../../../parsers/mdlx/material'; import Layer from '../../../parsers/mdlx/layer'; import TextureAnimation from '../../../parsers/mdlx/textureanimation'; import Geoset from '../../../parsers/mdlx/geoset'; import GeosetAnimation from '../../../parsers/mdlx/geosetanimation'; import Bone from '../../../parsers/mdlx/bone'; import Light from '../../../parsers/mdlx/light'; import Helper from '../../../parsers/mdlx/helper'; import Attachment from '../../../parsers/mdlx/attachment'; import ParticleEmitter from '../../../parsers/mdlx/particleemitter'; import ParticleEmitter2 from '../../../parsers/mdlx/particleemitter2'; import ParticleEmitterPopcorn from '../../../parsers/mdlx/particleemitterpopcorn'; import RibbonEmitter from '../../../parsers/mdlx/ribbonemitter'; import EventObject from '../../../parsers/mdlx/eventobject'; import Camera from '../../../parsers/mdlx/camera'; import CollisionShape from '../../../parsers/mdlx/collisionshape'; import FaceEffect from '../../../parsers/mdlx/faceeffect'; import SanityTestData from './data'; import testTracks from './tracks'; import { SanityTestNode } from './data'; export function isBetween(x: number, minVal: number, maxVal: number): boolean { return x >= minVal && x <= maxVal; } export const sequenceNames = new Set([ 'attack', 'birth', 'cinematic', 'death', 'decay', 'dissipate', 'morph', 'portrait', 'sleep', 'spell', 'stand', 'walk', 'ready', // HeroMountainKing.mdx has "Alternate Ready" which I assume is the same as or a replacement to "Alternate Stand Ready"? ]); export const replaceableIds = new Set([ 1, 2, 11, 21, 31, 32, 33, 34, 35, 36, 37, ]); export const animatedTypeNames = new Map([ // Layer ['KMTF', 'Texture ID'], ['KMTA', 'Alpha'], ['KMTE', 'Emissive Gain'], ['KFC3', 'Fresnel Color'], ['KFCA', 'Fresnel Opacity'], ['KFTC', 'Fresnel Team Color'], // TextureAnimation ['KTAT', 'Translation'], ['KTAR', 'Rotation'], ['KTAS', 'Scaling'], // GeosetAnimation ['KGAO', 'Alpha'], ['KGAC', 'Color'], // GenericObject ['KGTR', 'Translation'], ['KGRT', 'Rotation'], ['KGSC', 'Scaling'], // Light ['KLAS', 'Attenuation Start'], ['KLAE', 'Attenuation End'], ['KLAC', 'Color'], ['KLAI', 'Intensity'], ['KLBI', 'Ambient Intensity'], ['KLBC', 'Ambient Color'], ['KLAV', 'Visibility'], // Attachment ['KATV', 'Visibility'], // ParticleEmitter ['KPEE', 'Emission Rate'], ['KPEG', 'Gravity'], ['KPLN', 'Longitude'], ['KPLT', 'Latitude'], ['KPEL', 'Lifespan'], ['KPES', 'Speed'], ['KPEV', 'Visibility'], // ParticleEmitter2 ['KP2E', 'Emission Rate'], ['KP2G', 'Gravity'], ['KP2L', 'Latitude'], ['KP2R', 'Variation'], ['KP2N', 'Length'], ['KP2W', 'Width'], ['KP2S', 'Speed'], ['KP2V', 'Visibility'], // ParticleEmitterCorn ['KPPA', 'Alpha'], ['KPPC', 'Color'], ['KPPE', 'EmissionRate'], ['KPPL', 'LifeSpan'], ['KPPS', 'Speed'], ['KPPV', 'Visibility'], // RibbonEmitter ['KRHA', 'Height Above'], ['KRHB', 'Height Below'], ['KRAL', 'Alpha'], ['KRCO', 'Color'], ['KRTX', 'Texture Slot'], ['KRVS', 'Visibility'], // Camera ['KCTR', 'Translation'], ['KTTR', 'Rotation'], ['KCRL', 'Target Translation'], ]); export function hasAnimation(object: AnimatedObject, name: string): boolean { for (const animation of object.animations) { if (animation.name === name) { return true; } } return false; } export type MdlxType = Extent | Sequence | number | Texture | Material | Layer | TextureAnimation | Geoset | GeosetAnimation | Bone | Light | Helper | Attachment | ParticleEmitter | ParticleEmitter2 | ParticleEmitterPopcorn | RibbonEmitter | EventObject | Camera | CollisionShape | FaceEffect | Animation; export function getObjectTypeName(object: MdlxType): string { if (object instanceof Extent) { return 'Extent'; } else if (object instanceof Sequence) { return 'Sequence'; } else if (typeof object === 'number') { return 'GlobalSequence'; } else if (object instanceof Texture) { return 'Texture'; } else if (object instanceof Material) { return 'Material'; } else if (object instanceof Layer) { return 'Layer'; } else if (object instanceof TextureAnimation) { return 'TextureAnimation'; } else if (object instanceof Geoset) { return 'Geoset'; } else if (object instanceof GeosetAnimation) { return 'GeosetAnimation'; } else if (object instanceof Bone) { return 'Bone'; } else if (object instanceof Light) { return 'Light'; } else if (object instanceof Helper) { return 'Helper'; } else if (object instanceof Attachment) { return 'Attachment'; } else if (object instanceof ParticleEmitter) { return 'ParticleEmitter'; } else if (object instanceof ParticleEmitter2) { return 'ParticleEmitter2'; } else if (object instanceof ParticleEmitterPopcorn) { return 'ParticleEmitterPopcorn'; } else if (object instanceof RibbonEmitter) { return 'RibbonEmitter'; } else if (object instanceof EventObject) { return 'EventObject'; } else if (object instanceof Camera) { return 'Camera'; } else if (object instanceof CollisionShape) { return 'CollisionShape'; } else if (object instanceof FaceEffect) { return 'FaceEffect'; } else if (object instanceof Animation) { return animatedTypeNames.get(object.name); } else { console.warn('Unknown object type', object); return 'Unknown'; } } export function getObjectName(object: MdlxType, index: number): string { let name = getObjectTypeName(object); if (!(object instanceof Animation) && !(object instanceof Extent)) { name += ` ${index}`; } if (object instanceof Sequence || object instanceof GenericObject || object instanceof Camera) { name += ` - "${object.name}"`; } if (object instanceof Texture || object instanceof FaceEffect) { if (object.path.length) { name += ` - "${basename(object.path)}"`; } if (object instanceof Texture) { if (object.replaceableId === 1) { name += ' - Team color'; } else if (object.replaceableId === 2) { name += ' - Team glow'; } else if (object.replaceableId > 0) { name += ` - Replaceable ID ${object.replaceableId}`; } } } return name; } export function testObjects(data: SanityTestData, objects: T[], handler?: (data: SanityTestData, object: T, index: number) => void): void { const l = objects.length; if (l) { const isAnimated = objects[0] instanceof AnimatedObject; const isGeneric = objects[0] instanceof GenericObject; for (let i = 0; i < l; i++) { const object = objects[i]; data.push(object, i); if (handler) { handler(data, object, i); } if (isAnimated) { const asAnimated = object; testObjects(data, asAnimated.animations, testAnimation); } if (isGeneric) { const asGeneric = object; const objectId = asGeneric.objectId; const parentId = asGeneric.parentId; data.assertError(parentId === -1 || hasGenericObject(data, parentId), `Invalid parent ${parentId}`); data.assertError(objectId !== parentId, 'Same object and parent'); } data.pop(); } } } export function testAndGetReference(data: SanityTestData, objects: T[], index: number, typeNameIfError: string): T | undefined { if (index >= 0 && index < objects.length) { data.addReference(objects[index]); return objects[index]; } else { data.addError(`Invalid ${typeNameIfError} ${index}`); return; } } export function testReference(data: SanityTestData, objects: T[], index: number, typeNameIfError: string): boolean { // This explicit test against undefined is needed because global sequences are numbers and could be equal to 0. return testAndGetReference(data, objects, index, typeNameIfError) !== undefined; } /** * Get all of the texture indices referenced by a layer. */ export function getTextureIds(layer: Layer): number[] { for (const animation of layer.animations) { if (animation.name === 'KMTF') { return unique(animation.values.map((value) => value[0])); } } return [layer.textureId]; } function testVertexSkinning(data: SanityTestData, vertex: number, bone: number, isHd: boolean): void { const object = data.objects[bone]; if (isHd) { data.assertError(isBetween(bone, 0, 255), `Vertex ${vertex}: References bone ${bone} but there can only be 256 bones in an HD model`); } if (object) { if (!(object instanceof Bone)) { data.addSevere(`Vertex ${vertex}: Attached to "${object.name}" which is not a bone`); } else { // Add a use for this bone, to check later if bones have vertices attached to them. const uses = data.boneUsageMap.get(bone) || 0; data.boneUsageMap.set(bone, uses + 1); } } else { data.addError(`Vertex ${vertex}: Attached to object ${bone} which does not exist`); } } /** * Test geoset skinning. */ export function testGeosetSkinning(data: SanityTestData, geoset: Geoset): void { if (data.model.version > 800 && geoset.skin.length) { data.assertWarning(geoset.vertexGroups.length === 0, 'This geoset has both skin/weights and vertex groups'); const skin = geoset.skin; for (let i = 0, l = skin.length / 8; i < l; i++) { const offset = i * 8; const bone0 = skin[offset]; const bone1 = skin[offset + 1]; const bone2 = skin[offset + 2]; const bone3 = skin[offset + 3]; const weight0 = skin[offset + 4]; const weight1 = skin[offset + 5]; const weight2 = skin[offset + 6]; const weight3 = skin[offset + 7]; if (weight0 > 0) { testVertexSkinning(data, i, bone0, true); } if (weight1 > 0) { testVertexSkinning(data, i, bone1, true); } if (weight2 > 0) { testVertexSkinning(data, i, bone2, true); } if (weight3 > 0) { testVertexSkinning(data, i, bone3, true); } const weight = weight0 + weight1 + weight2 + weight3; if (weight === 0) { data.addSevere(`Vertex ${i}: Not attached to anything`); } else if (weight !== 255) { data.addSevere(`Vertex ${i}: The weights are not normalized to 1`); } } } else { // A model having no bones at all is also valid. // I don't know if the skinning information in that case can be anything whatsoever, or if there are rules. if (data.model.bones.length) { const vertexGroups = geoset.vertexGroups; const matrixGroups = geoset.matrixGroups; const matrixIndices = geoset.matrixIndices; const slices = []; for (let i = 0, l = matrixGroups.length, k = 0; i < l; i++) { slices.push(matrixIndices.subarray(k, k + matrixGroups[i])); k += matrixGroups[i]; } for (let i = 0, l = vertexGroups.length; i < l; i++) { const slice = slices[vertexGroups[i]]; if (slice) { for (const bone of slice) { testVertexSkinning(data, i, bone, false); } } else { const vertexGroup = vertexGroups[i]; if (vertexGroup === 255) { data.addSevere(`Vertex ${i}: Not attached to anything`); } else { data.addSevere(`Vertex ${i}: Attached to vertex group ${vertexGroup} which does not exist`); } } } } } } /** * Is the given ID a valid generic object? */ function hasGenericObject(data: SanityTestData, id: number): boolean { for (const object of data.objects) { if (object.objectId === id) { return true; } } return false; } export function testAnimation(data: SanityTestData, animation: Animation): void { const name = animation.name; const interpolationType = animation.interpolationType; // Particle emitter 2 variation animations are not implemented in Magos for the MDX format. data.assertWarning(name !== 'KP2R', 'Using a variation animation.'); // Particle emitter 2 gravity animations are not implemented in Magos for the MDX format. data.assertWarning(name !== 'KP2G', 'Using a gravity animation.'); // The game seems to force visiblity (and others?) interpolation types to none. data.assertWarning(animatedTypeNames.get(name) !== 'Visibility' || interpolationType === InterpolationType.DontInterp, 'Interpolation type not set to None'); testTracks(data, animation); } export function cleanNode(node: SanityTestNode): void { const nodes = node.nodes; for (let i = nodes.length - 1; i >= 0; i--) { const child = nodes[i]; if (child.type === 'node') { if (child.errors || child.severe || child.warnings || child.unused || (child.uses !== undefined && !child.uses)) { cleanNode(child); } else { nodes.splice(i, 1); } } } } export function getAnimation(object: AnimatedObject, name: string): Animation | undefined { for (const animation of object.animations) { if (animation.name === name) { return animation; } } return; } export function testExtent(data: SanityTestData, extent: Extent): void { data.push(extent, 0); const { max, min } = extent; if ((max[0] - min[0] < 0) || (max[1] - min[1] < 0) || (max[2] - min[2] < 0)) { data.addWarning('Negative extents'); } data.pop(); } /* let attachmentNames = new Set([ 'chest', 'feet', 'foot', 'hand', 'head', 'origin', 'overhead', 'sprite', 'weapon', ]); let attachmentQualifiers = new Set([ 'alternate', 'left', 'mount', 'right', 'rear', 'smart', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'small', 'medium', 'large', 'gold', 'rallypoint', 'eattree', ]); function testAttachmentName(attachment) { let tokens = attachment.node.name.toLowerCase().trim().split(/\s+/), valid = true; if (tokens.length > 1) { let names = attachmentNames, firstToken = tokens[0], lastToken = tokens[tokens.length - 1]; if (!names.has(tokens[0]) || lastToken !== 'ref') { valid = false; } if (tokens.length > 2) { let qualifiers = attachmentQualifiers; for (let i = 1, l = tokens.length - 1; i < l; i++) { if (!qualifiers.has(tokens[i])) { valid = false; } } } } else { valid = false; } return valid; } */ ================================================ FILE: src/utils/w3x/generatelistfile.ts ================================================ import { basename } from '../../common/path'; import { IniFile } from '../../parsers/ini/file'; import MdlxModel from '../../parsers/mdlx/model'; import War3MapImp from '../../parsers/w3x/imp/file'; import War3Map from '../../parsers/w3x/map'; import War3MapW3d from '../../parsers/w3x/w3d/file'; import War3MapW3i from '../../parsers/w3x/w3i/file'; import War3MapW3s from '../../parsers/w3x/w3s/file'; import War3MapW3u from '../../parsers/w3x/w3u/file'; import TokenStream from '../jass2/tokenstream'; function isModel(file: string): boolean { return file.endsWith('.mdx') || file.endsWith('.mdl'); } function isTexture(file: string): boolean { return file.endsWith('.blp') || file.endsWith('.dds') || file.endsWith('.tga'); } function isOther(file: string): boolean { return file.endsWith('.wav') || file.endsWith('.mp3') || file.endsWith('.slk') || file.endsWith('.txt'); } function filterFile(files: string[], file: string): void { if (file.length > 6 && (isModel(file) || isTexture(file) || isOther(file))) { if (file.endsWith('.mdl')) { file = `${file.slice(0, -4)}.mdx`; } files.push(file.replace(/\\\\/g, '\\')); } } /** * Given a map, attempt to find all file names referenced in it. * * Can be used with MpqArchive.applyListfile() to actually attempt to resolve the files in the archive. * * Based on code generously shared by Ralle. */ export default function generateListfile(map: War3Map): Set { const files = [ '(listfile)', '(signature)', '(attributes)', 'war3map.w3e', 'war3map.w3i', 'war3map.wtg', 'war3map.wct', 'war3map.wts', 'war3map.j', 'scripts\\war3map.j', 'war3map.lua', 'scripts\\war3map.lua', 'war3map.shd', 'war3mapMap.blp', 'war3mapMap.b00', 'war3mapMap.tga', 'war3mapPreview.tga', 'war3map.mmp', 'war3mapPath.tga', 'war3map.wpm', 'war3map.doo', 'war3mapUnits.doo', 'war3map.w3r', 'war3map.w3c', 'war3map.w3s', 'war3map.w3u', 'war3map.w3t', 'war3map.w3a', 'war3map.w3b', 'war3map.w3d', 'war3map.w3q', 'war3mapMisc.txt', 'war3mapSkin.txt', 'war3mapExtra.txt', 'war3map.imp', ]; // Listfile. let file = map.get('(listfile)'); if (file) { try { const text = file.text(); const lines = text.split(/\r\n/g); for (const line of lines) { files.push(line.trim()); } } catch (e) { console.warn('(listfile)', e); } } // Object files. for (const objectFile of ['.w3u', '.w3t', '.w3b', '.w3d', '.w3a', '.w3h', '.w3q']) { file = map.get('war3map' + objectFile); if (file) { try { const bytes = file.bytes(); let parser; if (objectFile === '.w3d' || objectFile === '.w3q' || objectFile === '.w3a') { parser = new War3MapW3d(); } else { parser = new War3MapW3u(); } parser.load(bytes); const tables = [ parser.originalTable, parser.customTable, ]; for (const table of tables) { for (const object of table.objects) { for (const modification of object.modifications) { // String if (modification.variableType === 3) { filterFile(files, modification.value); } } } } } catch (e) { console.warn(file.name, e); } } } // Sounds. file = map.get('war3map.w3s'); if (file) { try { const bytes = file.bytes(); const parser = new War3MapW3s(); parser.load(bytes); for (const sound of parser.sounds) { files.push(sound.file); } } catch (e) { console.warn('war3map.w3s', e); } } // Scripts. file = map.get('war3map.j') || map.get('Scripts\\war3map.j') || map.get('war3map.lua') || map.get('Scripts\\war3map.lua'); if (file) { try { const text = file.text(); const stream = new TokenStream(text); let token; while ((token = stream.read()) !== undefined) { if (token[0] === '"') { filterFile(files, token.slice(1, -1)); } } } catch (e) { console.warn(file.name, e); } } // User interface replacements. file = map.get('war3mapSkin.txt'); if (file) { try { const text = file.text(); const config = new IniFile(); config.load(text); for (const section of config.sections.values()) { for (const value of section.values()) { // We know the values are going to be strings. for (const token of value.split(',')) { filterFile(files, token); } } } } catch (e) { console.warn('war3mapSkin.txt', e); } } // Imports file = map.get('war3map.imp'); if (file) { try { const bytes = file.bytes(); const parser = new War3MapImp(); parser.load(bytes); for (const file of parser.entries.keys()) { files.push(file); } } catch (e) { console.warn('war3map.imp', e); } } // Map information. file = map.get('war3map.w3i'); if (file) { try { const bytes = file.bytes(); const parser = new War3MapW3i(); parser.load(bytes); filterFile(files, parser.loadingScreenModel); filterFile(files, parser.prologueScreenModel); } catch (e) { console.warn('war3map.w3i', e); } } // Model portraits for (let i = 0, l = files.length; i < l; i++) { const file = files[i]; if (isModel(file)) { files.push(`${file.slice(0, -4)}_portrait.mdx`); // MDL portraits? } } // Model textures. for (let i = 0, l = files.length; i < l; i++) { const file = files[i]; if (isModel(file)) { const actualFile = map.get(file); if (actualFile) { try { const bytes = actualFile.bytes(); const parser = new MdlxModel(); parser.load(bytes); for (const texture of parser.textures) { if (texture.path.length) { files.push(texture.path); } } for (const attachment of parser.attachments) { filterFile(files, attachment.path); } for (const emitter of parser.particleEmitters) { filterFile(files, emitter.path); } } catch (e) { console.warn(file, e); } } } } // Disabled icon versions. for (let i = 0, l = files.length; i < l; i++) { const file = files[i]; if (isTexture(file)) { files.push(`ReplaceableTextures\\CommandButtonsDisabled\\DIS${basename(file)}`); } } return new Set(files); } ================================================ FILE: src/utils/w3x/index.ts ================================================ import convertWeu from './weu/weu'; import generateListfile from './generatelistfile'; export default { convertWeu, generateListfile, }; ================================================ FILE: src/utils/w3x/weu/conversions.ts ================================================ import Trigger from '../../../parsers/w3x/wtg/trigger'; import ECA from '../../../parsers/w3x/wtg/eca'; import Parameter from '../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../parsers/w3x/wtg/subparameters'; import WeuData from './data'; import { createCustomScriptECA, ensureNameSafety } from './utils'; /** * A list of vanilla operators that take 3 parameters. * The only one not here, which takes 2 parameters, is OperatorString. */ const OPERATOR_NAMES = new Set([ 'OperatorCompareBoolean', 'OperatorCompareAbilityId', 'OperatorCompareBuffId', 'OperatorCompareDestructible', 'OperatorCompareDestructableCode', 'OperatorCompareButton', 'OperatorCompareGameDifficulty', 'OperatorCompareGameSpeed', 'OperatorCompareHeroSkill', 'OperatorCompareInteger', 'OperatorCompareItem', 'OperatorCompareItemType', 'OperatorCompareItemCode', 'OperatorCompareMouseButton', 'OperatorCompareMeleeDifficulty', 'OperatorCompareOrderCode', 'OperatorComparePlayer', 'OperatorComparePlayerColor', 'OperatorComparePlayerControl', 'OperatorComparePlayerSlotStatus', 'OperatorCompareRace', 'OperatorCompareReal', 'OperatorCompareString', 'OperatorCompareTechCode', 'OperatorCompareTerrainType', 'OperatorCompareTrigger', 'OperatorCompareUnit', 'OperatorCompareUnitCode', 'OperatorInt', 'OperatorReal', ]); /** * A list of vanilla functions which have an implicit code parameter. * The control flow "functions" such as IfThenElseMultiple and ForLoopAMultiple are handled specifically. */ const HAS_IMPLICIT_CODE = new Set([ 'EnumDestructablesInRectAllMultiple', 'EnumDestructablesInCircleBJMultiple', 'EnumItemsInRectBJMultiple', 'ForForceMultiple', 'ForGroupMultiple', ]); /** * Converts a Trigger to a custom script string. * Callbacks that are generated due to the conversion are added to the input callbacks array. */ export function convertTrigger(data: WeuData, trigger: Trigger, callbacks: string[]): string { const name = ensureNameSafety(trigger.name); const events = []; const conditions = []; const actions = []; // Separate the events/conditions/actions. for (const eca of trigger.ecas) { if (eca.type === 0) { events.push(eca); } else if (eca.type === 1) { conditions.push(eca); } else { actions.push(eca); } } const functions = []; if (events.length || conditions.length || actions.length) { const initBody = []; const conditionsBody = []; const actionsBody = []; // Reference the global trigger that WE generates. const triggerName = `gg_trg_${name}`; // Events don't explicitly define the trigger parameter. // Therefore it is created here, and prepended below to the parameters of each event. const triggerParameter = new Parameter(); triggerParameter.type = 3; triggerParameter.value = triggerName; initBody.push(`set ${triggerName} = CreateTrigger()`); // Convert the events. for (const event of events) { event.parameters.unshift(triggerParameter); for (const eca of convertFunctionCall(data, event, callbacks)) { initBody.push(eca.parameters[0].value); } } // Convert the conditions. if (conditions.length) { initBody.push(`call TriggerAddCondition(${triggerName}, Condition(function Trig_${name}_Conditions)`); for (const condition of conditions) { for (const eca of convertFunctionCall(data, condition, callbacks)) { conditionsBody.push(`if ${eca.parameters[0].value} then\r\n return true\r\nendif`); } } } // Convert the actions. if (actions.length) { initBody.push(`call TriggerAddAction(${triggerName}, function Trig_${name}_Actions)`); for (const action of actions) { for (const eca of convertFunctionCall(data, action, callbacks)) { actionsBody.push(eca.parameters[0].value); } } } // Add the actions function. if (actionsBody.length) { functions.push(`function Trig_${name}_Actions takes nothing returns nothing\r\n${actionsBody.join('\r\n')}\r\nendfunction`); } // Add the conditions function. if (conditionsBody.length) { functions.push(`function Trig_${name}_Conditions takes nothing returns boolean\r\n${conditionsBody.join('\r\n')}\r\nreturn false\r\nendfunction`); } // Add the initalization function. functions.push(`function InitTrig_${name} takes nothing returns nothing\r\n${initBody.join('\r\n')}\r\nendfunction`); } // Finally, return the whole trigger as Jass. return functions.join('\r\n'); } /** * Converts an ECA or SubParameters to an array of custom script ECAs. * Callbacks that are generated due to the conversion are added to the input callbacks array. */ export function convertFunctionCall(data: WeuData, object: ECA | SubParameters, callbacks: string[]): ECA[] { const name = object.name; const ecas: string[] = []; const parameters = object.parameters; const signature = data.triggerData.getFunction(object.type, object.name); if (!signature) { throw new Error(`Could not find a function signature: ${name}. Stack: ${data.stackToString()}`); } let { args, scriptName } = signature; const argCount = args.length; let isCode = false; let isBoolexpr = false; let isScriptCode = false; const ecaObject = object; // Get correct typing for the cases where the object is known to be an ECA. scriptName = scriptName || object.name; if (argCount) { const lastArg = args[argCount - 1]; if (lastArg === 'code' || HAS_IMPLICIT_CODE.has(name)) { isCode = true; } else if (lastArg === 'boolexpr') { isBoolexpr = true; } else if (lastArg === 'scriptcode') { isScriptCode = true; } } // IfThenElse and other control flow "functions" must come before the generic code/boolexpr callback handling, since they don't follow the same rules. if (name === 'IfThenElse') { ecas.push(`if ${convertParameter(data, parameters[0], args[0], callbacks)} then`); ecas.push(`call ${convertParameter(data, parameters[1], args[1], callbacks)}`); ecas.push('else'); ecas.push(`call ${convertParameter(data, parameters[2], args[2], callbacks)}`); ecas.push('endif'); } else if (name === 'OrMultiple') { ecas.push(ecaObject.ecas.slice().map((eca) => convertFunctionCall(data, eca, callbacks).map((eca) => eca.parameters[0].value)).join(' or ')); } else if (name === 'AndMultiple') { ecas.push(ecaObject.ecas.slice().map((eca) => convertFunctionCall(data, eca, callbacks).map((eca) => eca.parameters[0].value)).join(' and ')); } else if (name === 'ForLoopAMultiple' || name === 'ForLoopBMultiple' || name === 'ForLoopVarMultiple') { let loopName = 'A'; if (name === 'ForLoopBMultiple') { loopName = 'B'; } else if (name === 'ForLoopVarMultiple') { loopName = 'Var'; } let index; if (loopName === 'A' || loopName === 'B') { index = `bj_forLoop${loopName}Index`; const indexEnd = `${index}End`; ecas.push(`set ${index} = ${convertParameter(data, parameters[0], args[0], callbacks)}`); ecas.push(`set ${indexEnd} = ${convertParameter(data, parameters[1], args[1], callbacks)}`); ecas.push('loop'); ecas.push(`exitwhen ${index} > ${indexEnd}`); } else { index = convertParameter(data, parameters[0], args[0], callbacks); ecas.push(`set ${index} = ${convertParameter(data, parameters[1], args[1], callbacks)}`); ecas.push('loop'); ecas.push(`exitwhen ${index} > ${convertParameter(data, parameters[2], args[2], callbacks)}`); } for (const action of ecaObject.ecas) { const replacements = convertFunctionCall(data, action, callbacks); for (const replacement of replacements) { ecas.push(`${replacement.parameters[0].value}`); } } ecas.push(`set ${index} = ${index} + 1`); ecas.push('endloop'); } else if (name === 'IfThenElseMultiple') { let condition; const thenActions = []; const elseActions = []; for (const eca of ecaObject.ecas) { if (eca.group === 0) { condition = eca; } else if (eca.group === 1) { thenActions.push(eca); } else if (eca.group === 2) { elseActions.push(eca); } } if (condition) { ecas.push(`if ${convertFunctionCall(data, condition, callbacks)[0].parameters[0].value} then`); } for (const action of thenActions) { const replacements = convertFunctionCall(data, action, callbacks); for (const replacement of replacements) { ecas.push(`${replacement.parameters[0].value}`); } } if (elseActions.length) { ecas.push('else'); for (const action of elseActions) { const replacements = convertFunctionCall(data, action, callbacks); for (const replacement of replacements) { ecas.push(`${replacement.parameters[0].value}`); } } } ecas.push('endif'); } else if (isCode || isBoolexpr) { const triggerName = data.getTriggerName(); const callbackName = `Trig_${ensureNameSafety(triggerName)}_Func${callbacks.length}`; let call = `function ${callbackName}`; let returnType = 'nothing'; let callOrReturn = 'call'; let lastParam = parameters.length - 1; const isMultiple = object.name.endsWith('Multiple'); if (isBoolexpr) { call = `Filter(${call})`; returnType = 'boolean'; callOrReturn = 'return'; } if (isMultiple) { lastParam = parameters.length; } // The callback names are based on where they are in the callback array. // This breaks when one of the convert functions below need to create more callbacks before actually adding this one to the callbacks array. // To solve this, add a placeholder and save the index, and then use the index after converting everything. const callbackIndex = callbacks.length; callbacks[callbackIndex] = 'NOTHING'; const callParams = [...parameters.slice(0, lastParam).map((value, index) => convertParameter(data, value, args[index], callbacks)), call]; if (object instanceof ECA) { ecas.push(`call ${scriptName}(${callParams.join(', ')})`); } else { ecas.push(`${scriptName}(${callParams.join(', ')})`); } let body; if (isMultiple) { body = ecaObject.ecas.map((eca) => convertFunctionCall(data, eca, callbacks).map((customScript) => customScript.parameters[0].value).join('\r\n')).join('\r\n'); } else { body = `${callOrReturn} ${convertParameter(data, parameters[lastParam], args[lastParam], callbacks)}`; } // Now use the callback index and replace the placeholder. callbacks[callbackIndex] = `function ${callbackName} takes nothing returns ${returnType}\r\n${body}\r\nendfunction`; } else if (isScriptCode) { ecas.push(convertParameter(data, ecaObject.parameters[0], 'scriptcode', callbacks)); } else if (name === 'SetVariable') { ecas.push(`set ${convertParameter(data, parameters[0], args[0], callbacks)} = ${convertParameter(data, parameters[1], args[1], callbacks)}`); } else if (name === 'OperatorString') { // String concat ecas.push(`${convertParameter(data, parameters[0], args[0], callbacks)} + ${convertParameter(data, parameters[1], args[1], callbacks)}`); } else if (OPERATOR_NAMES.has(name)) { // All other operators ecas.push(`${convertParameter(data, parameters[0], args[0], callbacks)} ${convertParameter(data, parameters[1], args[1], callbacks)} ${convertParameter(data, parameters[2], args[2], callbacks)}`); } else if (name === 'CommentString') { // Comment ecas.push(`// ${parameters[0].value}`); } else if (name === 'GetBooleanAnd') { ecas.push(`(${convertParameter(data, parameters[0], args[0], callbacks)} and ${convertParameter(data, parameters[1], args[1], callbacks)})`); } else if (name === 'GetBooleanOr') { ecas.push(`(${convertParameter(data, parameters[0], args[0], callbacks)} or ${convertParameter(data, parameters[1], args[1], callbacks)})`); } else if (object instanceof ECA) { // If this is a trigger event, there is the implicit trigger parameter at the beginning. if (object.type === 0) { args = ['trigger', ...args]; } ecas.push(`call ${scriptName}(${parameters.map((value, index) => convertParameter(data, value, args[index], callbacks)).join(', ')})`); } else if (object instanceof SubParameters) { ecas.push(`${scriptName}(${parameters.map((value, index) => convertParameter(data, value, args[index], callbacks)).join(', ')})`); } return ecas.map((eca) => createCustomScriptECA(eca)); } /** * Converts a parameter to custom script. * Callbacks that are generated due to the conversion are added to the input callbacks array. */ export function convertParameter(data: WeuData, parameter: Parameter, dataType: string, callbacks: string[]): string { const { type, value } = parameter; if (type === 0) { const preset = data.triggerData.getPreset(value); if (preset === undefined) { throw new Error(`Failed to find a preset: "${value}"`); } return preset; } else if (type === 1) { if (value.startsWith('gg_')) { // Used to track global generated variables and their status. data.updateGUIReference(value, false); return value; } else { let global = `udg_${value}`; if (parameter.isArray && parameter.arrayIndex) { global += `[${convertParameter(data, parameter.arrayIndex, 'integer', callbacks)}]`; } return global; } } else if (parameter.type === 2) { return convertFunctionCall(data, parameter.subParameters, callbacks)[0].parameters[0].value; } else if (parameter.type === 3) { const baseType = data.triggerData.getBaseType(dataType); // "value" // scriptcode needs to be converted as-is, and doesn't need quotes. if (baseType === 'string' && dataType !== 'scriptcode') { // Inline string table entries. if (value.startsWith('TRIGSTR') && data.stringTable) { const string = data.stringTable.getString(value); if (string !== undefined) { return `"${string.replace(/\r\n/g, '\\r\n')}"`; } else { data.change('missingstring', 'Entry not found in the string table', value); } } return `"${value.replace(/\\/g, '\\\\')}"`; } // 'value' if (baseType === 'integer' && isNaN(parseInt(value))) { return `'${value}'`; } // value return value; } else { return ''; } } /** * Convert a parameter to a custom script string, discarding any generated callbacks. */ export function convertParameterInline(data: WeuData, parameter: Parameter, dataType: string): string { return convertParameter(data, parameter, dataType, []); } ================================================ FILE: src/utils/w3x/weu/data.ts ================================================ import Trigger from '../../../parsers/w3x/wtg/trigger'; import ECA from '../../../parsers/w3x/wtg/eca'; import Parameter from '../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../parsers/w3x/wtg/subparameters'; import CustomTextTrigger from '../../../parsers/w3x/wct/customtexttrigger'; import { TriggerData } from '../../../parsers/w3x/wtg/triggerdata'; import War3MapWts from '../../../parsers/w3x/wts/file'; export interface WEUChange { type: string; reason: string; data: string; stack: string; } export default class WeuData { triggerData: TriggerData; stringTable: War3MapWts; preplacedObjects: Map = new Map(); changes: WEUChange[] = []; stack: (Trigger | ECA | Parameter | SubParameters)[] = []; constructor(triggerData: TriggerData, stringTable: War3MapWts) { this.triggerData = triggerData; this.stringTable = stringTable; } push(object: Trigger | ECA | Parameter | SubParameters): void { this.stack.unshift(object); } pop(): void { this.stack.shift(); } change(type: string, reason: string, data: string): void { this.changes.push({ type, reason, data, stack: this.stackToString() }); } stackToString(): string { return this.stack.map((object) => { if (object instanceof Parameter) { return object.value; } else { return object.name; } }).reverse().join(' > '); } getTriggerName(): string { for (const node of this.stack) { if (node instanceof Trigger) { return node.name; } } return ''; } /** * Every time a reference to a preplaced object is encountered while testing the GUI, this will be called with isGUI being true. * Every time a reference to a preplaced object is converted to custom script, this will be called with isGUI being false. * This is used to track references that existed in GUI before the conversion, but that will be only in custom scripts afterwards. * References that are lost due to the conversion are then added in a new trigger called PreplacedObjectReferences. */ updateGUIReference(name: string, isGUI: boolean): void { // For now track only units and destructibles. // Not sure what else needs tracking. if (name.startsWith('gg_unit') || name.startsWith('gg_dest')) { const preplacedObjects = this.preplacedObjects; // If the reference is already known to be used by GUI, no need to do anything. if (!preplacedObjects.get(name)) { preplacedObjects.set(name, isGUI); } } } saveGUIReferences(triggers: Trigger[], customTextTriggers: CustomTextTrigger[]): void { const references = []; // Get all of the references that are no longer references. for (const [name, isGUI] of this.preplacedObjects) { if (!isGUI) { references.push(name); } } // If there are indeed missing references, add them to a new trigger. if (references.length) { const trigger = new Trigger(); trigger.name = 'PreplacedObjectReferences'; trigger.isEnabled = 1; trigger.isInitiallyOff = 1; for (const reference of references) { const eca = new ECA(); eca.type = 2; eca.isEnabled = 1; if (reference.startsWith('gg_unit')) { eca.name = 'RemoveUnit'; } else if (reference.startsWith('gg_dest')) { eca.name = 'RemoveDestructable'; } const parameter = new Parameter(); parameter.type = 1; parameter.value = reference; eca.parameters[0] = parameter; trigger.ecas.push(eca); } triggers.push(trigger); customTextTriggers.push(new CustomTextTrigger()); this.change('references', 'Saved references to preplaced objects lost due to conversions', references.join('\n')); } } } ================================================ FILE: src/utils/w3x/weu/parsewtg.ts ================================================ import War3Map from '../../../parsers/w3x/map'; import War3MapWtg from '../../../parsers/w3x/wtg/file'; import ECA from '../../../parsers/w3x/wtg/eca'; import SubParameters from '../../../parsers/w3x/wtg/subparameters'; import { FunctionSignature, TriggerData } from '../../../parsers/w3x/wtg/triggerdata'; import WeuData from './data'; function typeFunctionCall(wtg: War3MapWtg, object: ECA | SubParameters, signatures: Map, customTriggerData: TriggerData): void { // If this object's signature was unknown, attempt to fill in the argument types. // Note that this is done every time the signature is encountered. // If a parameter's type isn't known in one call, maybe it will be known in another call. if (signatures.has(object.name)) { const signature = signatures.get(object.name); const args = signature.args; for (const [index, parameter] of object.parameters.entries()) { const { type, value } = parameter; if (type === 1) { for (const variable of wtg.variables) { if (variable.name === value) { args[index] = variable.type; break; } } } else if (type === 2) { if (parameter.subParameters) { const subParameters = parameter.subParameters; const childSignature = customTriggerData.getFunction(subParameters.type, subParameters.name); if (childSignature) { const returnType = childSignature.returnType; if (returnType && returnType !== 'AnyType') { args[index] = returnType; } } } } else if (type === 3) { if (value.startsWith('TRIGSTER_') || value.includes('\\')) { args[index] = 'string'; } else if (value === 'true' || value === 'false') { args[index] = 'boolean'; } else if (!isNaN(parseFloat(value))) { const valueAsFloat = parseFloat(value); if (!isNaN(valueAsFloat)) { if (Number.isInteger(valueAsFloat) && !value.includes('.')) { args[index] = 'integer'; } else { args[index] = 'real'; } } } } } } // Continue the hierarchy down any function call parameter. for (const parameter of object.parameters) { if (parameter.type === 2 && parameter.subParameters) { typeFunctionCall(wtg, parameter.subParameters, signatures, customTriggerData); } } // Continue the hierarchy down any ECA. if (object instanceof ECA) { for (const child of object.ecas) { typeFunctionCall(wtg, child, signatures, customTriggerData); } } } const BIGGEST_SIGNATURE = 20; /** * Parses a WTG file, but with a twist - it also tries to fill in unknown function signatures. * * This lets the WEU converter to handle maps with small TriggerData modifications that are unknown. * * Unfortunately it only handles simple cases - if there is an unknown signature in an unknown signature, there is no way to parse it as far as I can tell. * * With that being said, it already managed to parse and mostly fill the signatures of relevant test maps. */ export default function parseWtg(map: War3Map, customTriggerData: TriggerData, data: WeuData): War3MapWtg | undefined { let wtg; const signatures: Map = new Map(); let currentName: string | undefined; let currentSignature: FunctionSignature | undefined; let searching = true; // If there's an unknown signature exception while parsing the triggers, a new signature will be injected. // Initially the signature starts with 0 arguments. // The triggers are then read again. // If there's an exception, another argument is added to the signature, and this goes on up to BIGGEST_SIGNATURE arguments. // If there's another unknown signature exception, the current signature is considered complete. // If the triggers are fully parsed, the current signature is considered complete. // Note that this will not work if there is an unknown signature with a child unknown signature. // For example, a function call given as an argument to a function call. // This is also the case if it's not a direct child, but anywhere down the hierarchy. // If both have unknown signatures, there is no deterministic way (that I can tell) to parse the data. while (searching) { try { wtg = map.readTriggers(customTriggerData); searching = false; } catch (e) { if (e instanceof Error) { const message = e.message; if (message.endsWith('Unknown signature')) { const end = message.lastIndexOf('"'); const start = message.lastIndexOf('"', end - 1) + 1; const nameAndType = message.slice(start, end); const [name, type] = nameAndType.split(':'); const typeAsNumber = parseInt(type); const signature: FunctionSignature = { args: [], scriptName: null, returnType: typeAsNumber === 3 ? 'AnyType' : null }; currentName = name.toLowerCase(); currentSignature = signature; signatures.set(name, signature); customTriggerData.externalFunctions[typeAsNumber][currentName] = currentSignature; } else if (currentName && currentSignature) { currentSignature.args.push('AnyType'); if (currentSignature.args.length > BIGGEST_SIGNATURE) { searching = false; } } } } } if (signatures.size) { if (wtg) { for (const trigger of wtg.triggers) { for (const eca of trigger.ecas) { typeFunctionCall(wtg, eca, signatures, customTriggerData); } } } for (const [name, signature] of signatures) { data.change('unknownsignature', `Unknown signature`, `${name}(${signature.args.join(', ')}) => ${signature.returnType ? signature.returnType : 'void'}`); } } return wtg; } ================================================ FILE: src/utils/w3x/weu/processing.ts ================================================ import Trigger from '../../../parsers/w3x/wtg/trigger'; import ECA from '../../../parsers/w3x/wtg/eca'; import Parameter from '../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../parsers/w3x/wtg/subparameters'; import WeuData from './data'; import { createCustomScriptECA, convertSingleToMultiple, isConditionECA, ensureCustomScriptCodeSafety } from './utils'; import { convertFunctionCall } from './conversions'; import transformFunction from './transformations/functions'; import transformPreset from './transformations/presets'; interface ConvertionResult { convert: boolean; reason: string; } export function processTrigger(data: WeuData, trigger: Trigger, callbacks: string[]): ConvertionResult { data.push(trigger); const eventsAndConditions = []; const actions = []; for (const eca of trigger.ecas) { const type = eca.type; if (type === 0 || type === 1) { eventsAndConditions.push(eca); } else if (type === 2) { actions.push(eca); } } const outputEcas = []; for (const eventOrCondition of eventsAndConditions) { const result = processECA(data, eventOrCondition, callbacks); if (result.convert) { data.pop(); return result; } outputEcas.push(eventOrCondition); } for (const action of actions) { const result = processECA(data, action, callbacks); if (result.convert) { const customScripts = convertFunctionCall(data, action, callbacks); data.change('inlinecustomscript', result.reason, customScripts.map((eca) => eca.parameters[0].value).join('\n')); outputEcas.push(...customScripts); } else { outputEcas.push(action); } } trigger.ecas = ensureCustomScriptCodeSafety(outputEcas); data.pop(); return { convert: false, reason: '' }; } export function processECA(data: WeuData, eca: ECA, callbacks: string[]): ConvertionResult { data.push(eca); // Test if this function call, or anything down its hierarchy, needs to be converted to custom script. const result = processFunctionCall(data, eca, callbacks); if (result.convert) { const reason = result.reason; // If conversion is needed, try first to see if this is a RoC control flow ECA, and convert it to its TFT equivalent. // This includes things like IfThenElse (RoC) and IfThenElseMultiple (TFT). // This allows to potentially only convert to custom script one part of the control flow block, rather than all of it. if (convertSingleToMultiple(eca)) { // If the test passes here (that is, false is returned), the TFT conversion allowed to handle the conversion down the hierarchy. // In this case, this ECA no longer needs to be converted to custom script. const result = processFunctionCall(data, eca, callbacks); if (result.convert) { data.pop(); return result; } else { data.change('singletomultiple', reason, eca.name); } } else { data.pop(); return result; } } const outputEcas = []; // Test the child ECAs if there are any. for (const child of eca.ecas) { const result = processECA(data, child, callbacks); if (result.convert) { let customScripts; // If this is a condition ECA, make a custom script condition. if (isConditionECA(eca.name, child.group)) { let condition = convertFunctionCall(data, child, callbacks)[0].parameters[0].value; // Normally type 2 (function) ECAs have the call keyword prepended to them. // If one was added, remove it now, since this is a condition. if (condition.startsWith('call ')) { condition = condition.slice(5); } let finalCondition; let returnValue; // IfThenElseMultiple and AndMultiple return false if any condition is false. // OrMultiple needs to return true if any condition is true. if (eca.name === 'OrMultiple') { finalCondition = condition; returnValue = 'true'; } else { finalCondition = `not (${condition})`; returnValue = 'false'; } customScripts = [ createCustomScriptECA(`if ${finalCondition} then`), createCustomScriptECA(`return ${returnValue}`), createCustomScriptECA('endif'), ]; } else { customScripts = convertFunctionCall(data, child, callbacks); } // All of the custom scripts should be in the same group as the original child. for (const script of customScripts) { script.group = child.group; } data.change('inlinecustomscript', result.reason, customScripts.map((eca) => eca.parameters[0].value).join('\n')); outputEcas.push(...customScripts); } else { outputEcas.push(child); } } eca.ecas = ensureCustomScriptCodeSafety(outputEcas); data.pop(); return { convert: false, reason: '' }; } function processFunctionCall(data: WeuData, object: ECA | SubParameters, callbacks: string[]): ConvertionResult { const name = object.name; // Check if this object can be converted back to normal GUI. // If it's already normal GUI, nothing will happen. if (transformFunction(data, object)) { data.change('inlinegui', name, object.name); } // If this function is not from normal GUI, it has to be converted. if (!data.triggerData.isBaseFunction(object.type, object.name)) { return { convert: true, reason: object.name }; } // Check the parameters. // Note that they will also be checked if GUI was inlined. // This is needed, because the inline functions don't check the parameters, only move them around. for (const parameter of object.parameters) { // Check for custom presets. if (parameter.type === 0 && data.triggerData.isCustomPreset(parameter.value)) { const value = parameter.value; if (transformPreset(data, parameter)) { data.change('inlinepreset', value, parameter.value); } else { return { convert: true, reason: value }; } } const result = processParameter(data, parameter, callbacks); if (result.convert) { return result; } } return { convert: false, reason: '' }; } function processParameter(data: WeuData, parameter: Parameter, callbacks: string[]): { convert: boolean, reason: string } { data.push(parameter); const type = parameter.type; const value = parameter.value; if (type === 1) { if (value.startsWith('gg_')) { // Used to track global generated variables and their status. data.updateGUIReference(value, true); } } else if (type === 2) { const result = processSubParameters(data, parameter.subParameters, callbacks); if (result.convert) { data.pop(); return result; } } // If this is an array element, test the array index. const index = parameter.arrayIndex; if (index) { const result = processParameter(data, index, callbacks); if (result.convert) { data.pop(); return result; } } data.pop(); return { convert: false, reason: '' }; } function processSubParameters(data: WeuData, subParameters: SubParameters, callbacks: string[]): ConvertionResult { data.push(subParameters); const result = processFunctionCall(data, subParameters, callbacks); if (result.convert) { data.pop(); return result; } data.pop(); return { convert: false, reason: '' }; } ================================================ FILE: src/utils/w3x/weu/transformations/blz.ts ================================================ import ECA from '../../../../parsers/w3x/wtg/eca'; import Parameter from '../../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../../parsers/w3x/wtg/subparameters'; import WeuData from '../data'; /** * The Warcraft 3 1.29 PTR introduced many new functions. * A lot were later prepended with Blz to avoid name clashes with user functions. * This returns whether the given name matches one of these functions. */ function isBlzNeeded(name: string): boolean { return name === 'GetTriggerPlayerMouseX' || name === 'GetTriggerPlayerMouseY' || name === 'GetTriggerPlayerMousePosition' || name === 'GetTriggerPlayerMouseButton' || name === 'SetAbilityTooltip' || name === 'SetAbilityExtendedTooltip' || name === 'SetAbilityResearchTooltip' || name === 'SetAbilityResearchExtendedTooltip' || name === 'GetAbilityTooltip' || name === 'GetAbilityExtendedTooltip' || name === 'GetAbilityResearchTooltip' || name === 'GetAbilityResearchExtendedTooltip' || name === 'SetAbilityIcon' || name === 'GetAbilityIcon' || name === 'GetAbilityPosX' || name === 'GetAbilityPosY' || name === 'SetAbilityPosX' || name === 'SetAbilityPosY' || name === 'GetUnitMaxHP' || name === 'SetUnitMaxHP' || name === 'GetUnitMaxMana' || name === 'SetUnitMaxMana' || name === 'SetItemName' || name === 'SetItemDescription' || name === 'GetItemDescription' || name === 'SetItemTooltip' || name === 'GetItemTooltip' || name === 'SetItemExtendedTooltip' || name === 'GetItemExtendedTooltip' || name === 'SetItemIconPath' || name === 'GetItemIconPath' || name === 'SetUnitName' || name === 'SetHeroProperName' || name === 'GetUnitBaseDamage' || name === 'SetUnitBaseDamage' || name === 'GetUnitDiceNumber' || name === 'SetUnitDiceNumber' || name === 'GetUnitDiceSides' || name === 'SetUnitDiceSides' || name === 'GetUnitAttackCooldown' || name === 'SetUnitAttackCooldown' || name === 'SetSpcialEffectColorByPlayer' || name === 'SetSpecialEffectColor' || name === 'SetSpecialEffectAlpha' || name === 'SetSpecialEffectScale' || name === 'SetSpecialEffectPosition' || name === 'SetSpecialEffectHeight' || name === 'SetSpecialEffectTimeScale' || name === 'SetSpecialEffectTime' || name === 'SetSpecialEffectOrientation' || name === 'SetSpecialEffectYaw' || name === 'SetSpecialEffectPitch' || name === 'SetSpecialEffectRoll' || name === 'SetSpecialEffectX' || name === 'SetSpecialEffectY' || name === 'SetSpecialEffectZ' || name === 'SetSpecialEffectPositionLoc' || name === 'GetLocalSpecialEffectX' || name === 'GetLocalSpecialEffectY' || name === 'GetLocalSpecialEffectZ' || name === 'GetUnitArmor' || name === 'SetUnitArmor' || name === 'UnitHideAbility' || name === 'UnitDisableAbility' || name === 'UnitCancelTimedLife' || name === 'IsUnitSelectable' || name === 'IsUnitInvulnerable' || name === 'UnitInterruptAttack' || name === 'GetUnitCollisionSize' || name === 'GetAbilityManaCost' || name === 'GetAbilityCooldown' || name === 'SetUnitAbilityCooldown' || name === 'GetUnitAbilityCooldown' || name === 'GetUnitAbilityCooldownRemaining' || name === 'EndUnitAbilityCooldown' || name === 'GetUnitAbilityManaCost' || name === 'SetEventDamage' || // Note, the following two functions are available in the 1.29 PTR, but not in the public version! // They require version 1.30, which at the time of writing is in PTR. name === 'PlaySpecialEffect' || name === 'PlaySpecialEffectWithTimeScale'; } export default function transformBlz(data: WeuData, object: ECA | SubParameters): boolean { const name = object.name; if (!isBlzNeeded(name)) { return false; } object.name = `Blz${name}`; // If this is a subparameters object, need to change the name also for the parent parameter. if (object instanceof SubParameters) { (data.stack[1]).value = `Blz${name}`; } const parameters = object.parameters; // In the PTR these functions had 3 parameters, but later it became 2. if ((name === 'GetAbilityIcon' || name === 'SetAbilityIcon') && parameters.length === 3) { parameters.pop(); } return true; } ================================================ FILE: src/utils/w3x/weu/transformations/functions.ts ================================================ import ECA from '../../../../parsers/w3x/wtg/eca'; import SubParameters from '../../../../parsers/w3x/wtg/subparameters'; import WeuData from '../data'; import transformer, { Transformer } from './transformer'; import { transformerIsUnitOwnedByPlayer, transformerIsUnitRace, transformerIsUnitType } from './specific'; import transformBlz from './blz'; let initialized = false; let transformers: {[keyof: string]: (data: WeuData, object: ECA | SubParameters) => boolean }; function rename(name: string): Transformer { return transformer({ [name]: {} }); } function swap(parameters: number[]): (name: string) => Transformer { return function (name: string): Transformer { return transformer({ [name]: { parameters } }); }; } function initialize(): void { if (!initialized) { initialized = true; const swap10 = swap([1, 0]); const swap102 = swap([1, 0, 2]); const swap120 = swap([1, 2, 0]); const swap201 = swap([2, 0, 1]); const swap210 = swap([2, 1, 0]); const swap0231 = swap([0, 2, 3, 1]); const swap1023 = swap([1, 0, 2, 3]); const swap3012 = swap([3, 0, 1, 2]); const swap3201 = swap([3, 2, 0, 1]); const swap3210 = swap([3, 2, 1, 0]); transformers = { UnitId: rename('String2UnitIdBJ'), UnitId2String: rename('UnitId2StringBJ'), GetObjectName: rename('GetAbilityName'), // Math API Sin: transformer({ SinBJ: { parameters: [[0, '/', Math.PI / 180]] } }), Cos: transformer({ CosBJ: { parameters: [[0, '/', Math.PI / 180]] } }), Tan: transformer({ TanBJ: { parameters: [[0, '/', Math.PI / 180]] } }), // String Utility API GetHandleId: rename('GetHandleIdBJ'), SubString: transformer({ SubStringBJ: { parameters: [0, [1, '+', 1], 2] } }), StringHash: rename('StringHashBJ'), GetLocalizedString: rename('StringIdentity'), // Map Setup API SetMapFlag: transformer({ LockGameSpeedBJ: { tests: [[0, 'MAP_LOCK_SPEED'], [1, 'true']], parameters: [] }, UnlockGameSpeedBJ: { tests: [[0, 'MAP_LOCK_SPEED'], [1, 'false']], parameters: [] } }), SetPlayerColor: transformer({ SetPlayerColorBJ: { parameters: [0, 1, 'PlayerChangeColorRetain'] } }), SetPlayerAlliance: swap0231('SetPlayerAllianceBJ'), SetPlayerTaxRate: swap3201('SetPlayerTaxRateBJ'), SetPlayerOnScoreScreen: swap10('SetPlayerOnScoreScreenBJ'), GetPlayerTaxRate: swap201('GetPlayerTaxRateBJ'), // Timer API TimerStart: transformer({ StartTimerBJ: { test: [3, 'null'], parameters: [0, 2, 1] } }), PauseTimer: transformer({ PauseTimerBJ: { parameters: ['PauseResumePause', 0] } }), ResumeTimer: transformer({ PauseTimerBJ: { parameters: ['PauseResumeResume', 0] } }), // Group API GroupAddUnit: swap10('GroupAddUnitSimple'), GroupRemoveUnit: swap10('GroupRemoveUnitSimple'), GroupImmediateOrderById: rename('GroupTrainOrderByIdBJ'), // Force API ForceAddPlayer: swap10('ForceAddPlayerSimple'), ForceRemovePlayer: swap10('ForceRemovePlayerSimple'), // Region and Location API GetWorldBounds: rename('GetEntireMapRect'), // Trigger Game Event API TriggerRegisterTimerEvent: transformer({ TriggerRegisterTimerEventPeriodic: { test: [2, 'true'], parameters: [0, 1] }, TriggerRegisterTimerEventSingle: { test: [2, 'false'], parameters: [0, 1] } }), TriggerRegisterTimerExpireEvent: rename('TriggerRegisterTimerExpireEventBJ'), TriggerRegisterGameStateEvent: transformer({ TriggerRegisterGameStateEventTimeOfDay: { test: [1, 'GAME_STATE_TIME_OF_DAY'], parameters: [0, 2, 3] } }), TriggerRegisterDialogEvent: rename('TriggerRegisterDialogEventBJ'), TriggerRegisterGameEvent: transformer({ TriggerRegisterShowSkillEventBJ: { test: [1, 'EVENT_GAME_SHOW_SKILL'], parameters: [0] }, TriggerRegisterBuildSubmenuEventBJ: { test: [1, 'EVENT_GAME_BUILD_SUBMENU'], parameters: [0] }, TriggerRegisterGameLoadedEventBJ: { test: [1, 'EVENT_GAME_LOADED'], parameters: [0] }, TriggerRegisterGameSavedEventBJ: { test: [1, 'EVENT_GAME_SAVE'], parameters: [0] } }), GetClickedButton: rename('GetClickedButtonBJ'), GetClickedDialog: rename('GetClickedDialogBJ'), // Trigger Player Based Event API TriggerRegisterPlayerEvent: transformer({ TriggerRegisterPlayerKeyEventBJ: [ { test: [2, 'EVENT_PLAYER_ARROW_LEFT_DOWN'], parameters: [0, 1, 'KeyEventTypeDepress', 'KeyEventKeyLeft'] }, { test: [2, 'EVENT_PLAYER_ARROW_RIGHT_DOWN'], parameters: [0, 1, 'KeyEventTypeDepress', 'KeyEventKeyRight'] }, { test: [2, 'EVENT_PLAYER_ARROW_DOWN_DOWN'], parameters: [0, 1, 'KeyEventTypeDepress', 'KeyEventKeyDown'] }, { test: [2, 'EVENT_PLAYER_ARROW_UP_DOWN'], parameters: [0, 1, 'KeyEventTypeDepress', 'KeyEventKeyUp'] }, { test: [2, 'EVENT_PLAYER_ARROW_LEFT_UP'], parameters: [0, 1, 'KeyEventTypeRelease', 'KeyEventKeyLeft'] }, { test: [2, 'EVENT_PLAYER_ARROW_RIGHT_UP'], parameters: [0, 1, 'KeyEventTypeRelease', 'KeyEventKeyRight'] }, { test: [2, 'EVENT_PLAYER_ARROW_DOWN_UP'], parameters: [0, 1, 'KeyEventTypeRelease', 'KeyEventKeyDown'] }, { test: [2, 'EVENT_PLAYER_ARROW_UP_UP'], parameters: [0, 1, 'KeyEventTypeRelease', 'KeyEventKeyUp'] } ], TriggerRegisterPlayerMouseEventBJ: [ { test: [2, 'EVENT_PLAYER_MOUSE_DOWN'], parameters: [0, 1, 'MouseEventTypeDown'] }, { test: [2, 'EVENT_PLAYER_MOUSE_UP'], parameters: [0, 1, 'MouseEventTypeUp'] }, { test: [2, 'EVENT_PLAYER_MOUSE_MOVE'], parameters: [0, 1, 'MouseEventTypeMove'] }, ], TriggerRegisterPlayerEventVictory: { test: [2, 'EVENT_PLAYER_VICTORY'], parameters: [0, 1] }, TriggerRegisterPlayerEventDefeat: { test: [2, 'EVENT_PLAYER_DEFEAT'], parameters: [0, 1] }, TriggerRegisterPlayerEventLeave: { test: [2, 'EVENT_PLAYER_LEAVE'], parameters: [0, 1] }, TriggerRegisterPlayerEventAllianceChanged: { test: [2, 'EVENT_PLAYER_ALLIANCE_CHANGED'], parameters: [0, 1] }, TriggerRegisterPlayerEventEndCinematic: { test: [2, 'EVENT_PLAYER_END_CINEMATIC'], parameters: [0, 1] } }), TriggerRegisterPlayerUnitEvent: transformer({ TriggerRegisterPlayerUnitEventSimple: { test: [3, 'null'], parameters: [0, 1, 2] } }), GetLearnedSkill: rename('GetLearnedSkillBJ'), GetKillingUnit: rename('GetKillingUnitBJ'), GetTransportUnit: rename('GetTransportUnitBJ'), GetLoadedUnit: rename('GetLoadedUnitBJ'), GetIssuedOrderId: rename('GetIssuedOrderIdBJ'), // Trigger Unit Based Event API TriggerRegisterUnitStateEvent: transformer({ TriggerRegisterUnitLifeEvent: { test: [1, 'UNIT_STATE_LIFE'], parameters: [0, 2, 3] }, TriggerRegisterUnitManaEvent: { test: [1, 'UNIT_STATE_MANA'], parameters: [0, 2, 3] } }), TriggerWaitForSound: rename('WaitForSoundBJ'), // Widget API GetWidgetLife: rename('GetItemLifeBJ'), SetWidgetLife: rename('SetItemLifeBJ'), // Destructable Object API SetDestructableInvulnerable: rename('SetDestructableInvulnerableBJ'), IsDestructableInvulnerable: rename('IsDestructableInvulnerableBJ'), EnumDestructablesInRect: transformer({ EnumDestructablesInRectAll: { test: [1, 'null'], parameters: [0, 2] } }), SetDestructableMaxLife: rename('SetDestructableMaxLifeBJ'), QueueDestructableAnimation: rename('QueueDestructableAnimationBJ'), SetDestructableAnimation: rename('SetDestructableAnimationBJ'), SetDestructableAnimationSpeed: transformer({ SetDestAnimationSpeedPercent: { parameters: [0, [1, '*', 100]] } }), ShowDestructable: swap10('ShowDestructableBJ'), GetTriggerDestructable: rename('GetDyingDestructable'), // Item API SetItemDropOnDeath: rename('SetItemDropOnDeathBJ'), SetItemDroppable: rename('SetItemDroppableBJ'), SetItemPlayer: rename('SetItemPlayerBJ'), SetItemInvulnerable: rename('SetItemInvulnerableBJ'), SetItemVisible: swap10('SetItemVisibleBJ'), IsItemOwned: transformer({ CheckItemStatus: { parameters: [0, 'ItemStatusOwned'] } }), IsItemPowerup: transformer({ CheckItemStatus: { parameters: [0, 'ItemStatusPowerup'] } }), IsItemSellable: transformer({ CheckItemStatus: { parameters: [0, 'ItemStatusSellable'] } }), IsItemPawnable: transformer({ CheckItemStatus: { parameters: [0, 'ItemStatusPawnable'] } }), IsItemIdPowerup: transformer({ CheckItemcodeStatus: { parameters: [0, 'ItemcodeStatusPowerup'] } }), IsItemIdSellable: transformer({ CheckItemcodeStatus: { parameters: [0, 'ItemcodeStatusSellable'] } }), IsItemIdPawnable: transformer({ CheckItemcodeStatus: { parameters: [0, 'ItemcodeStatusPawnable'] } }), EnumItemsInRect: transformer({ EnumItemsInRectBJ: { test: [1, 'null'], parameters: [0, 2] } }), // Unit API ShowUnit: transformer({ ShowUnitShow: { test: [1, 'true'], parameters: [0] }, ShowUnitHide: { test: [1, 'false'], parameters: [0] } }), SetUnitState: transformer({ SetUnitLifeBJ: { test: [1, 'UNIT_STATE_LIFE'], parameters: [0, 2] }, SetUnitManaBJ: { test: [1, 'UNIT_STATE_MANA'], parameters: [0, 2] } }), SetUnitFlyHeight: rename('SetUnitFlyHeightBJ'), SetUnitTurnSpeed: rename('SetUnitTurnSpeedBJ'), SetUnitAcquireRange: rename('SetUnitAcquireRangeBJ'), SetUnitCreepGuard: transformer({ LockGuardPosition: { test: [1, 'true'], parameters: [0] } }), GetUnitDefaultPropWindow: rename('GetUnitDefaultPropWindowBJ'), SetUnitScale: transformer({ SetUnitScalePercent: { parameters: [0, [1, '*', 100], [2, '*', 100], [3, '*', 100]] } }), SetUnitTimeScale: transformer({ SetUnitTimeScalePercent: { parameters: [0, [1, '*', 100]] } }), SetUnitBlendTime: rename('SetUnitBlendTimeBJ'), QueueUnitAnimation: rename('QueueUnitAnimationBJ'), SetUnitAnimation: transformer({ ResetUnitAnimation: { test: [1, '"stand"'], parameters: [0] } }), AddUnitAnimationProperties: swap210('AddUnitAnimationPropertiesBJ'), SetHeroStr: transformer({ ModifyHeroStat: { test: [2, 'true'], parameters: ['HeroStatStr', 0, 'ModifyMethodSet', 1] } }), SetHeroAgi: transformer({ ModifyHeroStat: { test: [2, 'true'], parameters: ['HeroStatAgi', 0, 'ModifyMethodSet', 1] } }), SetHeroInt: transformer({ ModifyHeroStat: { test: [2, 'true'], parameters: ['HeroStatInt', 0, 'ModifyMethodSet', 1] } }), GetHeroStr: transformer({ GetHeroStatBJ: { parameters: ['HeroStatStr', 0, 1] } }), GetHeroAgi: transformer({ GetHeroStatBJ: { parameters: ['HeroStatAgi', 0, 1] } }), GetHeroInt: transformer({ GetHeroStatBJ: { parameters: ['HeroStatInt', 0, 1] } }), UnitModifySkillPoints: transformer({ ModifyHeroSkillPoints: { parameters: [0, '0', 1] } }), AddHeroXP: swap102('AddHeroXPSwapped'), GetUnitAbilityLevel: swap10('GetUnitAbilityLevelSwapped'), DecUnitAbilityLevel: swap10('DecUnitAbilityLevelSwapped'), IncUnitAbilityLevel: swap10('IncUnitAbilityLevelSwapped'), SetUnitAbilityLevel: swap102('SetUnitAbilityLevelSwapped'), SetUnitExploded: rename('SetUnitExplodedBJ'), PauseUnit: swap10('PauseUnitBJ'), IsUnitPaused: rename('IsUnitPausedBJ'), SelectUnit: transformer({ SelectUnitAdd: { test: [1, 'true'], parameters: [0] }, SelectUnitRemove: { test: [1, 'false'], parameters: [0] } }), UnitAddItem: swap10('UnitAddItemSwapped'), UnitRemoveItem: swap10('UnitRemoveItemSwapped'), UnitRemoveItemFromSlot: transformer({ UnitRemoveItemFromSlotSwapped: { parameters: [0, [1, '+', 1]] } }), UnitItemInSlot: transformer({ UnitItemInSlotBJ: { parameters: [0, [1, '+', 1]] } }), UnitInventorySize: rename('UnitInventorySizeBJ'), UnitDropItemSlot: transformer({ UnitDropItemSlotBJ: { parameters: [0, 1, [2, '+', 1]] } }), UnitDropItemTarget: rename('UnitDropItemTargetBJ'), GetUnitState: swap10('GetUnitStateSwap'), SetUnitUseFood: swap10('SetUnitUseFoodBJ'), IsUnitOwnedByPlayer: transformerIsUnitOwnedByPlayer, IsUnitRace: transformerIsUnitRace, IsUnitType: transformerIsUnitType, IsUnitHidden: rename('IsUnitHiddenBJ'), IsUnitIllusion: rename('IsUnitIllusionBJ'), IsUnitInTransport: rename('IsUnitInTransportBJ'), IsUnitLoaded: rename('IsUnitLoadedBJ'), UnitShareVision: swap201('UnitShareVisionBJ'), UnitSuspendDecay: swap10('UnitSuspendDecayBJ'), UnitAddType: swap10('UnitAddTypeBJ'), UnitRemoveType: swap10('UnitRemoveTypeBJ'), UnitAddAbility: swap10('UnitAddAbilityBJ'), UnitRemoveAbility: swap10('UnitRemoveAbilityBJ'), UnitRemoveBuffs: transformer({ UnitRemoveBuffsBJ: [ { tests: [[1, 'true'], [2, 'false']], parameters: ['BuffTypePositive', 0] }, { tests: [[1, 'false'], [2, 'true']], parameters: ['BuffTypeNegative', 0] }, { tests: [[1, 'true'], [2, 'true']], parameters: ['BuffTypeAll', 0] } ] }), UnitRemoveBuffsEx: transformer({ UnitRemoveBuffsBJ: { tests: [[1, 'true'], [2, 'true'], [3, 'false'], [4, 'false'], [5, 'false'], [6, 'true'], [7, 'false']], parameters: ['BuffTypeNonTLife', 0] } }), UnitAddSleep: rename('UnitSetCanSleepBJ'), UnitCanSleep: rename('UnitCanSleepBJ'), UnitIsSleeping: rename('UnitIsSleepingBJ'), UnitWakeUp: rename('UnitWakeUpBJ'), UnitApplyTimedLife: swap210('UnitApplyTimedLifeBJ'), UnitPauseTimedLife: swap10('UnitPauseTimedLifeBJ'), UnitSetUsesAltIcon: swap10('UnitSetUsesAltIconBJ'), UnitDamageTarget: transformer({ UnitDamageTargetBJ: { tests: [[3, 'true'], [4, 'false'], [7, 'WEAPON_TYPE_WHOKNOWS']], parameters: [0, 1, 2, 5, 6] } }), IssueImmediateOrderById: rename('IssueTrainOrderByIdBJ'), AddResourceAmount: swap10('AddResourceAmountBJ'), WaygateActivate: swap10('WaygateActivateBJ'), WaygateIsActive: rename('WaygateIsActiveBJ'), AddItemToStock: swap1023('AddItemToStockBJ'), AddUnitToStock: swap1023('AddUnitToStockBJ'), RemoveItemFromStock: swap10('RemoveItemFromStockBJ'), RemoveUnitFromStock: swap10('RemoveUnitFromStockBJ'), // Player API Player: transformer({ ConvertedPlayer: { parameters: [[0, '+', 1]] } }), SetPlayerHandicap: transformer({ SetPlayerHandicapBJ: { parameters: [0, [1, '*', 100]] } }), SetPlayerHandicapXP: transformer({ SetPlayerHandicapXPBJ: { parameters: [0, [1, '*', 100]] } }), SetPlayerTechMaxAllowed: swap120('SetPlayerTechMaxAllowedSwap'), GetPlayerTechMaxAllowed: swap10('GetPlayerTechMaxAllowedSwap'), SetPlayerTechResearched: swap120('SetPlayerTechResearchedSwap'), GetPlayerTechCount: transformer({ GetPlayerTechCountSimple: { test: [2, 'true'], parameters: [1, 0] } }), SetPlayerAbilityAvailable: swap210('SetPlayerAbilityAvailableBJ'), // Fog of War API FogMaskEnable: transformer({ FogMaskEnableOn: { test: [0, 'true'], parameters: [] }, FogMaskEnableOff: { test: [0, 'false'], parameters: [] } }), FogEnable: transformer({ FogEnableOn: { test: [0, 'true'], parameters: [] }, FogEnableOff: { test: [0, 'false'], parameters: [] } }), // Game API SetCampaignMenuRace: transformer({ SetCampaignMenuRaceBJ: [ { test: [0, 'RACE_OTHER'], parameters: ['CampaignIndexT'] }, { test: [0, 'RACE_HUMAN'], parameters: ['CampaignIndexH'] }, { test: [0, 'RACE_UNDEAD'], parameters: ['CampaignIndexU'] }, { test: [0, 'RACE_ORC'], parameters: ['CampaignIndexO'] }, { test: [0, 'RACE_NIGHTELF'], parameters: ['CampaignIndexN'] } ] }), SetCampaignMenuRaceEx: transformer({ SetCampaignMenuRaceBJ: [ { test: [0, 'bj_CAMPAIGN_OFFSET_XN'], parameters: ['CampaignIndexXN'] }, { test: [0, 'bj_CAMPAIGN_OFFSET_XH'], parameters: ['CampaignIndexXH'] }, { test: [0, 'bj_CAMPAIGN_OFFSET_XU'], parameters: ['CampaignIndexXU'] }, { test: [0, 'bj_CAMPAIGN_OFFSET_XO'], parameters: ['CampaignIndexXO'] } ] }), LoadGame: rename('LoadGameBJ'), RenameSaveDirectory: rename('RenameSaveDirectoryBJ'), RemoveSaveDirectory: rename('RemoveSaveDirectoryBJ'), CopySaveGame: rename('CopySaveGameBJ'), GetFloatGameState: transformer({ GetTimeOfDay: { test: [0, 'GAME_STATE_TIME_OF_DAY'], parameters: [] } }), SetFloatGameState: transformer({ SetTimeOfDay: { test: [0, 'GAME_STATE_TIME_OF_DAY'], parameters: [1] } }), // Campaign API SetCustomCampaignButtonVisible: transformer({ ShowCustomCampaignButton: { parameters: [[0, '+', 1], 1] } }), GetCustomCampaignButtonVisible: transformer({ IsCustomCampaignButtonVisibile: { parameters: [[0, '+', 1]] } }), // Dialog API DialogClear: rename('DialogClearBJ'), DialogSetMessage: rename('DialogSetMessageBJ'), DialogDisplay: swap210('DialogDisplayBJ'), InitGameCache: rename('InitGameCacheBJ'), SaveGameCache: rename('SaveGameCacheBJ'), StoreInteger: swap3210('StoreIntegerBJ'), StoreReal: swap3210('StoreRealBJ'), StoreBoolean: swap3210('StoreBooleanBJ'), StoreUnit: swap3210('StoreUnitBJ'), StoreString: swap3210('StoreStringBJ'), HaveStoredBoolean: transformer({ HaveStoredValue: { parameters: [2, 'CacheValueTypeBoolean', 1, 0] } }), HaveStoredInteger: transformer({ HaveStoredValue: { parameters: [2, 'CacheValueTypeInteger', 1, 0] } }), HaveStoredReal: transformer({ HaveStoredValue: { parameters: [2, 'CacheValueTypeReal', 1, 0] } }), HaveStoredUnit: transformer({ HaveStoredValue: { parameters: [2, 'CacheValueTypeUnit', 1, 0] } }), HaveStoredString: transformer({ HaveStoredValue: { parameters: [2, 'CacheValueTypeString', 1, 0] } }), FlushGameCache: rename('FlushGameCacheBJ'), FlushStoredMission: swap10('FlushStoredMissionBJ'), GetStoredInteger: swap210('GetStoredIntegerBJ'), GetStoredReal: swap210('GetStoredRealBJ'), GetStoredBoolean: swap210('GetStoredBooleanBJ'), GetStoredString: swap210('GetStoredStringBJ'), InitHashtable: rename('InitHashtableBJ'), SaveInteger: swap3210('SaveIntegerBJ'), SaveReal: swap3210('SaveRealBJ'), SaveBoolean: swap3210('SaveBooleanBJ'), SaveStr: swap3210('SaveStringBJ'), SavePlayerHandle: swap3210('SavePlayerHandleBJ'), SaveWidgetHandle: swap3210('SaveWidgetHandleBJ'), SaveDestructableHandle: swap3210('SaveDestructableHandleBJ'), SaveItemHandle: swap3210('SaveItemHandleBJ'), SaveUnitHandle: swap3210('SaveUnitHandleBJ'), SaveAbilityHandle: swap3210('SaveAbilityHandleBJ'), SaveTimerHandle: swap3210('SaveTimerHandleBJ'), SaveTriggerHandle: swap3210('SaveTriggerHandleBJ'), SaveTriggerConditionHandle: swap3210('SaveTriggerConditionHandleBJ'), SaveTriggerActionHandle: swap3210('SaveTriggerActionHandleBJ'), SaveTriggerEventHandle: swap3210('SaveTriggerEventHandleBJ'), SaveForceHandle: swap3210('SaveForceHandleBJ'), SaveGroupHandle: swap3210('SaveGroupHandleBJ'), SaveLocationHandle: swap3210('SaveLocationHandleBJ'), SaveRectHandle: swap3210('SaveRectHandleBJ'), SaveBooleanExprHandle: swap3210('SaveBooleanExprHandleBJ'), SaveSoundHandle: swap3210('SaveSoundHandleBJ'), SaveEffectHandle: swap3210('SaveEffectHandleBJ'), SaveUnitPoolHandle: swap3210('SaveUnitPoolHandleBJ'), SaveItemPoolHandle: swap3210('SaveItemPoolHandleBJ'), SaveQuestHandle: swap3210('SaveQuestHandleBJ'), SaveQuestItemHandle: swap3210('SaveQuestItemHandleBJ'), SaveDefeatConditionHandle: swap3210('SaveDefeatConditionHandleBJ'), SaveTimerDialogHandle: swap3210('SaveTimerDialogHandleBJ'), SaveLeaderboardHandle: swap3210('SaveLeaderboardHandleBJ'), SaveMultiboardHandle: swap3210('SaveMultiboardHandleBJ'), SaveMultiboardItemHandle: swap3210('SaveMultiboardItemHandleBJ'), SaveTrackableHandle: swap3210('SaveTrackableHandleBJ'), SaveDialogHandle: swap3210('SaveDialogHandleBJ'), SaveButtonHandle: swap3210('SaveButtonHandleBJ'), SaveTextTagHandle: swap3210('SaveTextTagHandleBJ'), SaveLightningHandle: swap3210('SaveLightningHandleBJ'), SaveImageHandle: swap3210('SaveImageHandleBJ'), SaveUbersplatHandle: swap3210('SaveUbersplatHandleBJ'), SaveRegionHandle: swap3210('SaveRegionHandleBJ'), SaveFogStateHandle: swap3210('SaveFogStateHandleBJ'), SaveFogModifierHandle: swap3210('SaveFogModifierHandleBJ'), LoadInteger: swap210('LoadIntegerBJ'), LoadReal: swap210('LoadRealBJ'), LoadBoolean: swap210('LoadBooleanBJ'), LoadStr: swap210('LoadStringBJ'), LoadPlayerHandle: swap210('LoadPlayerHandleBJ'), LoadWidgetHandle: swap210('LoadWidgetHandleBJ'), LoadDestructableHandle: swap210('LoadDestructableHandleBJ'), LoadItemHandle: swap210('LoadItemHandleBJ'), LoadUnitHandle: swap210('LoadUnitHandleBJ'), LoadAbilityHandle: swap210('LoadAbilityHandleBJ'), LoadTimerHandle: swap210('LoadTimerHandleBJ'), LoadTriggerHandle: swap210('LoadTriggerHandleBJ'), LoadTriggerConditionHandle: swap210('LoadTriggerConditionHandleBJ'), LoadTriggerActionHandle: swap210('LoadTriggerActionHandleBJ'), LoadTriggerEventHandle: swap210('LoadTriggerEventHandleBJ'), LoadForceHandle: swap210('LoadForceHandleBJ'), LoadGroupHandle: swap210('LoadGroupHandleBJ'), LoadLocationHandle: swap210('LoadLocationHandleBJ'), LoadRectHandle: swap210('LoadRectHandleBJ'), LoadBooleanExprHandle: swap210('LoadBooleanExprHandleBJ'), LoadSoundHandle: swap210('LoadSoundHandleBJ'), LoadEffectHandle: swap210('LoadEffectHandleBJ'), LoadUnitPoolHandle: swap210('LoadUnitPoolHandleBJ'), LoadItemPoolHandle: swap210('LoadItemPoolHandleBJ'), LoadQuestHandle: swap210('LoadQuestHandleBJ'), LoadQuestItemHandle: swap210('LoadQuestItemHandleBJ'), LoadDefeatConditionHandle: swap210('LoadDefeatConditionHandleBJ'), LoadTimerDialogHandle: swap210('LoadTimerDialogHandleBJ'), LoadLeaderboardHandle: swap210('LoadLeaderboardHandleBJ'), LoadMultiboardHandle: swap210('LoadMultiboardHandleBJ'), LoadMultiboardItemHandle: swap210('LoadMultiboardItemHandleBJ'), LoadTrackableHandle: swap210('LoadTrackableHandleBJ'), LoadDialogHandle: swap210('LoadDialogHandleBJ'), LoadButtonHandle: swap210('LoadButtonHandleBJ'), LoadTextTagHandle: swap210('LoadTextTagHandleBJ'), LoadLightningHandle: swap210('LoadLightningHandleBJ'), LoadImageHandle: swap210('LoadImageHandleBJ'), LoadUbersplatHandle: swap210('LoadUbersplatHandleBJ'), LoadRegionHandle: swap210('LoadRegionHandleBJ'), LoadFogStateHandle: swap210('LoadFogStateHandleBJ'), LoadFogModifierHandle: swap210('LoadFogModifierHandleBJ'), HaveSavedBoolean: transformer({ HaveSavedValue: { parameters: [2, 'HashtableValueTypeBoolean', 1, 0] } }), HaveSavedInteger: transformer({ HaveSavedValue: { parameters: [2, 'HashtableValueTypeInteger', 1, 0] } }), HaveSavedReal: transformer({ HaveSavedValue: { parameters: [2, 'HashtableValueTypeReal', 1, 0] } }), HaveSavedString: transformer({ HaveSavedValue: { parameters: [2, 'HashtableValueTypeString', 1, 0] } }), HaveSavedHandle: transformer({ HaveSavedValue: { parameters: [2, 'HashtableValueTypeHandle', 1, 0] } }), FlushParentHashtable: rename('FlushParentHashtableBJ'), FlushChildHashtable: swap10('FlushChildHashtableBJ'), // Randomization API ChooseRandomCreep: rename('ChooseRandomCreepBJ'), ChooseRandomNPBuilding: rename('ChooseRandomNPBuildingBJ'), ChooseRandomItem: rename('ChooseRandomItemBJ'), ChooseRandomItemEx: swap10('ChooseRandomItemExBJ'), // Visual API ResetTerrainFog: rename('ResetTerrainFogBJ'), SetTerrainFogEx: transformer({ SetTerrainFogExBJ: { parameters: [0, 1, 2, 3, [4, '*', 100], [5, '*', 100], [6, '*', 100]] } }), SetTimeOfDayScale: transformer({ SetTimeOfDayScalePercentBJ: { parameters: [[0, '*', 100]] } }), PauseGame: transformer({ PauseGameOn: { test: [0, 'true'], parameters: [] }, PauseGameOff: { test: [0, 'false'], parameters: [] } }), DestroyTextTag: rename('DestroyTextTagBJ'), SetTextTagPosUnit: rename('SetTextTagPosUnitBJ'), SetTextTagSuspended: rename('SetTextTagSuspendedBJ'), SetTextTagPermanent: rename('SetTextTagPermanentBJ'), SetTextTagAge: rename('SetTextTagAgeBJ'), SetTextTagLifespan: rename('SetTextTagLifespanBJ'), SetTextTagFadepoint: rename('SetTextTagFadepointBJ'), // Quest API DestroyQuest: rename('DestroyQuestBJ'), QuestSetTitle: rename('QuestSetTitleBJ'), QuestSetDescription: rename('QuestSetDescriptionBJ'), QuestSetCompleted: rename('QuestSetCompletedBJ'), QuestSetDiscovered: rename('QuestSetDiscoveredBJ'), QuestSetFailed: rename('QuestSetFailedBJ'), QuestSetEnabled: swap10('QuestSetEnabledBJ'), QuestItemSetDescription: rename('QuestItemSetDescriptionBJ'), QuestItemSetCompleted: rename('QuestItemSetCompletedBJ'), DestroyDefeatCondition: rename('DestroyDefeatConditionBJ'), DefeatConditionSetDescription: rename('DefeatConditionSetDescriptionBJ'), FlashQuestDialogButton: rename('FlashQuestDialogButtonBJ'), // Timer Dialog API DestroyTimerDialog: rename('DestroyTimerDialogBJ'), TimerDialogSetTitle: rename('TimerDialogSetTitleBJ'), TimerDialogDisplay: swap10('TimerDialogDisplayBJ'), // Leaderboard API DestroyLeaderboard: rename('DestroyLeaderboardBJ'), LeaderboardDisplay: swap10('LeaderboardDisplayBJ'), LeaderboardRemovePlayerItem: swap10('LeaderboardRemovePlayerItemBJ'), LeaderboardSortItemsByValue: transformer({ LeaderboardSortItemsBJ: { parameters: [0, 'LeaderboardSortByValue', 1] } }), LeaderboardSortItemsByPlayer: transformer({ LeaderboardSortItemsBJ: { parameters: [0, 'LeaderboardSortByPlayer', 1] } }), LeaderboardSortItemsByLabel: transformer({ LeaderboardSortItemsBJ: { parameters: [0, 'LeaderboardSortByLabel', 1] } }), LeaderboardHasPlayerItem: rename('LeaderboardHasPlayerItemBJ'), LeaderboardSetLabel: rename('LeaderboardSetLabelBJ'), PlayerGetLeaderboard: rename('PlayerGetLeaderboardBJ'), LeaderboardSetStyle: rename('LeaderboardSetStyleBJ'), // Multiboard API DestroyMultiboard: rename('DestroyMultiboardBJ'), MultiboardDisplay: swap10('MultiboardDisplayBJ'), MultiboardMinimize: swap10('MultiboardMinimizeBJ'), // Camera API CameraSetupGetField: swap10('CameraSetupGetFieldSwap'), CameraSetSmoothingFactor: rename('CameraSetSmoothingFactorBJ'), DisplayCineFilter: rename('DisplayCineFilterBJ'), ForceCinematicSubtitles: rename('ForceCinematicSubtitlesBJ'), // Sound API SetSoundDistanceCutoff: rename('SetSoundDistanceCutoffBJ'), SetSoundPitch: rename('SetSoundPitchBJ'), AttachSoundToUnit: rename('AttachSoundToUnitBJ'), StopSound: transformer({ StopSoundBJ: { test: [1, 'false'], parameters: [0, 2] } }), KillSoundWhenDone: rename('KillSoundWhenDoneBJ'), SetMapMusic: transformer({ SetMapMusicIndexedBJ: { test: [1, 'false'], parameters: [0, 2] }, SetMapMusicRandomBJ: { tests: [[1, 'true'], [2, '0']], parameters: [0] } }), ClearMapMusic: rename('ClearMapMusicBJ'), PlayMusic: rename('PlayMusicBJ'), StopMusic: rename('StopMusicBJ'), ResumeMusic: rename('ResumeMusicBJ'), PlayThematicMusic: rename('PlayThematicMusicBJ'), EndThematicMusic: rename('EndThematicMusicBJ'), VolumeGroupSetVolume: transformer({ VolumeGroupSetVolumeBJ: { parameters: [0, [1, '*', 100]] } }), // Effects API AddWeatherEffect: rename('AddWeatherEffectSaveLast'), RemoveWeatherEffect: rename('RemoveWeatherEffectBJ'), AddSpecialEffectLoc: swap10('AddSpecialEffectLocBJ'), AddSpecialEffectTarget: swap210('AddSpecialEffectTargetUnitBJ'), DestroyEffect: rename('DestroyEffectBJ'), DestroyLightning: rename('DestroyLightningBJ'), GetLightningColorA: rename('GetLightningColorABJ'), GetLightningColorR: rename('GetLightningColorRBJ'), GetLightningColorG: rename('GetLightningColorGBJ'), GetLightningColorB: rename('GetLightningColorBBJ'), SetLightningColor: rename('SetLightningColorBJ'), GetAbilityEffectById: rename('GetAbilityEffectBJ'), GetAbilitySoundById: rename('GetAbilitySoundBJ'), // Image API ShowImage: swap10('ShowImageBJ'), // Ubersplat API ShowUbersplat: swap10('ShowUbersplatBJ'), // Blight API SetBlightRect: swap201('SetBlightRectBJ'), SetBlightLoc: swap3012('SetBlightRadiusLocBJ'), // Doodad API SetDoodadAnimationRect: transformer({ SetDoodadAnimationRectBJ: { test: [3, 'false'], parameters: [2, 1, 0] }, }), }; } } export default function transformFunction(data: WeuData, object: ECA | SubParameters): boolean { if (!initialized) { initialize(); } const transform = transformers[object.name]; if (transform) { return transform(data, object); } return transformBlz(data, object); } ================================================ FILE: src/utils/w3x/weu/transformations/presets.ts ================================================ import Parameter from '../../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../../parsers/w3x/wtg/subparameters'; import WeuData from '../data'; let initialized = false; let transformers: {[keyof: string]: (data: WeuData, object: Parameter) => boolean }; function preset(name: string) { return function (data: WeuData, object: Parameter): boolean { const subParameters = new SubParameters(); subParameters.name = name; subParameters.type = data.triggerData.getFunctionType(name); object.value = name; object.type = 2; object.subParameters = subParameters; return true; }; } function initialize(): void { if (!initialized) { initialized = true; transformers = { bj_forLoopAIndex: preset('GetForLoopIndexA'), bj_forLoopBIndex: preset('GetForLoopIndexB'), bj_queuedExecTotal: preset('QueuedTriggerCountBJ'), bj_mapInitialCameraBounds: preset('GetCameraBoundsMapRect'), bj_mapInitialPlayableArea: preset('GetPlayableMapRect'), bj_lastCreatedWeatherEffect: preset('GetLastCreatedWeatherEffect'), bj_lastCreatedTerrainDeformation: preset('GetLastCreatedTerrainDeformation'), bj_lastCreatedLightning: preset('GetLastCreatedLightningBJ'), bj_lastCreatedFogModifier: preset('GetLastCreatedFogModifier'), bj_lastCreatedImage: preset('GetLastCreatedImage'), bj_lastCreatedUbersplat: preset('GetLastCreatedUbersplat'), bj_lastPlayedSound: preset('GetLastPlayedSound'), bj_lastPlayedMusic: preset('GetLastPlayedMusic'), bj_useDawnDuskSounds: preset('IsDawnDuskEnabled'), bj_lastCreatedEffect: preset('GetLastCreatedEffectBJ'), bj_lastCreatedItem: preset('GetLastCreatedItem'), bj_lastRemovedItem: preset('GetLastRemovedItem'), bj_lastCreatedUnit: preset('GetLastCreatedUnit'), bj_lastReplacedUnit: preset('GetLastReplacedUnitBJ'), bj_lastCreatedDestructable: preset('GetLastCreatedDestructable'), bj_FORCE_ALL_PLAYERS: preset('GetPlayersAll'), bj_lastCreatedButton: preset('GetLastCreatedButtonBJ'), bj_lastCreatedQuest: preset('GetLastCreatedQuestBJ'), bj_lastCreatedQuestItem: preset('GetLastCreatedQuestItemBJ'), bj_lastCreatedDefeatCondition: preset('GetLastCreatedDefeatConditionBJ'), bj_lastStartedTimer: preset('GetLastCreatedTimerBJ'), bj_lastCreatedTimerDialog: preset('GetLastCreatedTimerDialogBJ'), bj_lastCreatedLeaderboard: preset('GetLastCreatedLeaderboard'), bj_lastCreatedMultiboard: preset('GetLastCreatedMultiboard'), bj_lastCreatedTextTag: preset('GetLastCreatedTextTag'), bj_lastTransmissionDuration: preset('GetLastTransmissionDurationBJ'), bj_lastCreatedGameCache: preset('GetLastCreatedGameCacheBJ'), bj_lastCreatedHashtable: preset('GetLastCreatedHashtableBJ'), bj_lastLoadedUnit: preset('GetLastRestoredUnitBJ'), bj_lastHauntedGoldMine: preset('GetLastHauntedGoldMine'), }; } } export default function transformPreset(data: WeuData, parameter: Parameter): boolean { if (!initialized) { initialize(); } const transform = transformers[parameter.value]; if (transform) { return transform(data, parameter); } return false; } ================================================ FILE: src/utils/w3x/weu/transformations/specific.ts ================================================ import ECA from '../../../../parsers/w3x/wtg/eca'; import Parameter from '../../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../../parsers/w3x/wtg/subparameters'; import WeuData from '../data'; import { convertParameterInline } from '../conversions'; /** * IsUnitOwnedByPlayer(whichUnit, whichPlayer) == boolean * => * GetOwningPlayer(whichUnit) == whichPlayer */ export function transformerIsUnitOwnedByPlayer(data: WeuData, object: ECA | SubParameters): boolean { const parameter = data.stack[1]; const comparator = data.stack[2]; const comparatorParameters = comparator.parameters; if (comparator.name !== 'OperatorCompareBoolean') { return false; } let otherParameter; if (comparator.parameters[0] === parameter) { otherParameter = comparatorParameters[2]; } else { otherParameter = comparatorParameters[0]; } const trueOrFalse = convertParameterInline(data, otherParameter, 'boolean'); if (trueOrFalse !== 'true' && trueOrFalse !== 'false') { return false; } // Change to a player comparison. comparator.name = 'OperatorComparePlayer'; const parameters = object.parameters; const whichPlayer = parameters[1]; // Change IsUnitOwnedByPlayer(whichUnit, whichPlayer) to GetOwningPlayer(whichUnit) parameter.value = 'GetOwningPlayer'; object.name = 'GetOwningPlayer'; object.parameters.length = 1; comparatorParameters[0] = parameter; // Equal or not equal. if (trueOrFalse === 'true') { comparatorParameters[1].value = 'OperatorEqualENE'; } else { comparatorParameters[1].value = 'OperatorNotEqualENE'; } // Change the boolean to whichPlayer. comparatorParameters[2] = whichPlayer; return true; } /** * IsUnitRace(whichUnit, whichRace) == boolean * => * GetUnitRace(whichUnit) == whichRace */ export function transformerIsUnitRace(data: WeuData, object: ECA | SubParameters): boolean { const parameter = data.stack[1]; const comparator = data.stack[2]; const comparatorParameters = comparator.parameters; if (comparator.name !== 'OperatorCompareBoolean') { return false; } let otherParameter; if (comparator.parameters[0] === parameter) { otherParameter = comparatorParameters[2]; } else { otherParameter = comparatorParameters[0]; } const trueOrFalse = convertParameterInline(data, otherParameter, 'boolean'); if (trueOrFalse !== 'true' && trueOrFalse !== 'false') { return false; } // Change to a race comparison. comparator.name = 'OperatorCompareRace'; const parameters = object.parameters; const whichRace = parameters[1]; // Change IsUnitRace(whichUnit, whichRace) to GetUnitRace(whichUnit) parameter.value = 'GetUnitRace'; object.name = 'GetUnitRace'; object.parameters.length = 1; comparatorParameters[0] = parameter; const isEqual = comparatorParameters[1].value === 'OperatorEqualENE'; const isTrue = trueOrFalse === 'true'; // Essentially a XOR between the booleans. if (isEqual === isTrue) { comparatorParameters[1].value = 'OperatorEqualENE'; } else { comparatorParameters[1].value = 'OperatorNotEqualENE'; } comparatorParameters[1] = whichRace; return true; } /** * IsUnitType(whichUnit, UNIT_TYPE_DEAD) == boolean * => * IsUnitDeadBJ(whichUnit) == boolean */ export function transformerIsUnitType(data: WeuData, object: ECA | SubParameters): boolean { const comparator = data.stack[2]; if (comparator.name !== 'OperatorCompareBoolean') { return false; } const whichUnitType = convertParameterInline(data, object.parameters[1], 'unittype'); if (whichUnitType !== 'UNIT_TYPE_DEAD') { return false; } const parameter = data.stack[1]; // Change IsUnitType(whichUnit, UNIT_TYPE_DEAD) to IsUnitDeadBJ(whichUnit) parameter.value = 'IsUnitDeadBJ'; object.name = 'IsUnitDeadBJ'; object.parameters.length = 1; return true; } ================================================ FILE: src/utils/w3x/weu/transformations/transformer.ts ================================================ import ECA from '../../../../parsers/w3x/wtg/eca'; import Parameter from '../../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../../parsers/w3x/wtg/subparameters'; import WeuData from '../data'; import { convertParameterInline } from '../conversions'; type WEUTransformerTest = [number, string]; type WEUTransformerOp = [number, '+' | '-' | '*' | '/', number]; type WEUTransformerParameter = number | string | WEUTransformerOp; interface WEUTransformerTransformation { test?: WEUTransformerTest; tests?: WEUTransformerTest[]; parameters?: WEUTransformerParameter[]; } interface WEUTransformerTransformations { [keyof: string]: WEUTransformerTransformation | WEUTransformerTransformation[]; } function runTests(data: WeuData, object: ECA | SubParameters, args: string[], mapping: WEUTransformerTransformation, convertedParameters: string[]): boolean { const parameters = object.parameters; const tests = []; if (mapping.test) { tests.push(mapping.test); } if (mapping.tests) { tests.push(...mapping.tests); } for (const [index, value] of tests) { // Convert and cache the parameter. if (convertedParameters[index] === undefined) { convertedParameters[index] = convertParameterInline(data, parameters[index], args[index]); } if (value !== convertedParameters[index]) { return false; } } return true; } function setNameAndType(data: WeuData, object: ECA | SubParameters, name: string): void { object.name = name; object.type = data.triggerData.getFunctionType(name); if (object instanceof SubParameters) { const parameter = data.stack[1]; parameter.value = name; } } function setParameters(data: WeuData, object: ECA | SubParameters, args: string[], mapping: WEUTransformerTransformation): void { if (mapping.parameters) { const parameters = object.parameters; object.parameters = mapping.parameters.map((value) => { if (typeof value === 'number') { return parameters[value]; } else if (typeof value === 'string') { const parameter = new Parameter(); if (data.triggerData.getPreset(value)) { parameter.type = 0; } else { parameter.type = 3; } parameter.value = value; return parameter; } else { const whichParameter = value[0]; const whichOperator = value[1]; const operandValue = value[2]; const argType = args[whichParameter]; let typedFunction; let mathOp; if (argType === 'integer') { typedFunction = 'OperatorInt'; } else if (argType === 'real') { typedFunction = 'OperatorReal'; } else { throw new Error(`Attempted to use an operator on a non-number parameter of type "${argType}`); } if (whichOperator === '+') { mathOp = 'OperatorAdd'; } else if (whichOperator === '-') { mathOp = 'OperatorSubtract'; } else if (whichOperator === '*') { mathOp = 'OperatorMultiply'; } else { mathOp = 'OperatorDivide'; } const parameter = new Parameter(); parameter.value = typedFunction; parameter.type = 2; const subParameters = new SubParameters(); subParameters.name = typedFunction; subParameters.type = 3; const operandA = parameters[whichParameter]; const operator = new Parameter(); operator.type = 0; operator.value = mathOp; const operandB = new Parameter(); operandB.type = 3; operandB.value = `${operandValue}`; subParameters.beginParameters = 1; subParameters.parameters = [operandA, operator, operandB]; parameter.subParameters = subParameters; return parameter; } }); } } export default function transformer(transformations: WEUTransformerTransformations) { return function (data: WeuData, object: ECA | SubParameters): boolean { // The signature for the input (to be replaced) function. const signature = data.triggerData.getFunction(object.type, object.name); // This can happen if there is a transformer that is implemented, however it's not found in the custom TriggerData.txt // Perhaps it will be worthwhile in the future to also query the signature from common.j, however that's an extra download etc. // For now I am going to assume the used YDWE TriggerData.txt exposes more or less everything. if (!signature) { console.warn(`transformer failed to get the signature for the input function: ${object.name}`); return false; } const args = signature.args; // A cache for converted parameters. // If there are multiple transformations, or transformations with multiple mappings, usually they branch on the same parameter(s). // The first time a parameter is tested, it will be converted, and stored here. // The next time it is tested, it will be fetched directly. const convertedParameters: string[] = []; for (const [name, mappings] of Object.entries(transformations)) { let mappingAsArray; if (Array.isArray(mappings)) { mappingAsArray = mappings; } else { mappingAsArray = [mappings]; } for (const mapping of mappingAsArray) { if (runTests(data, object, args, mapping, convertedParameters)) { setNameAndType(data, object, name); setParameters(data, object, args, mapping); return true; } } } return false; }; } export type Transformer = ReturnType; ================================================ FILE: src/utils/w3x/weu/utils.ts ================================================ import { byteLengthUtf8, splitUtf8ByteLength } from '../../../common/utf8'; import ECA from '../../../parsers/w3x/wtg/eca'; import Parameter from '../../../parsers/w3x/wtg/parameter'; import SubParameters from '../../../parsers/w3x/wtg/subparameters'; /** * Creates a new Custom Script or comment ECA with the given data. */ export function createCustomScriptOrCommentECA(data: string, isComment: boolean): ECA { const eca = new ECA(); eca.type = 2; // Action if (isComment) { eca.name = 'CommentString'; } else { eca.name = 'CustomScriptCode'; } eca.isEnabled = 1; const parameter = new Parameter(); parameter.type = 3; // String parameter.value = data; eca.parameters[0] = parameter; return eca; } /** * Creates a new Custom Script ECA with the given script. */ export function createCustomScriptECA(script: string): ECA { return createCustomScriptOrCommentECA(script, false); } // /** // * Creates a new comment ECA with the given comment. // */ // function createCommentECA(comment: string) { // return createCustomScriptOrCommentECA(comment, true); // } function subParametersToEca(subParameters: SubParameters, group: number): ECA { const eca = new ECA(); eca.name = subParameters.name; eca.type = subParameters.type; eca.group = group; eca.isEnabled = 1; eca.parameters.push(...subParameters.parameters); return eca; } export function convertSingleToMultiple(eca: ECA): boolean { if (eca.name === 'IfThenElse') { const parameters = eca.parameters; const ifParam = subParametersToEca(parameters[0].subParameters, 0); const thenParam = subParametersToEca(parameters[1].subParameters, 1); const elseParam = subParametersToEca(parameters[2].subParameters, 2); eca.name = 'IfThenElseMultiple'; eca.parameters.length = 0; eca.ecas.push(ifParam, thenParam, elseParam); return true; } else if (eca.name === 'ForGroup' || eca.name === 'ForForce') { const action = subParametersToEca(eca.parameters[1].subParameters, 0); eca.name = `${eca.name}Multiple`; eca.parameters.length = 1; eca.ecas.push(action); return true; } return false; } /** * Given the name of the parent of some child ECA, and the child's group, determine if it's a condition. */ export function isConditionECA(name: string, group: number): boolean { if (group !== 0) { return false; } return name === 'AndMultiple' || name === 'OrMultiple' || name === 'IfThenElseMultiple'; } // The number of bytes that each custom script action can contain. const SCRIPT_LINE_LENGTH = 239; /** * CustomScriptCode ECAs have a maximum length for their (typically) string parameter. * If the script length exceeds the maximum length, WE will fail to load the map properly. * Either it crashes, or it loads the map and GUI up until the invalid ECA, after which everything is an error. * This function is used to split such ECAs. * Splitting is possible, because the Jass parser seems to not consider multiline comments as token delimiters. * For example, the following lines: * * call BJDebug/* * /*Msg("hi") * * When compiled result in the correct call: * * call BJDebugMsg("hi") */ export function ensureCustomScriptCodeSafety(ecas: ECA[]): ECA[] { const outputEcas = []; for (const eca of ecas) { if (eca.name === 'CustomScriptCode') { const script = eca.parameters[0].value; const scriptByteLength = byteLengthUtf8(script); if (scriptByteLength > SCRIPT_LINE_LENGTH) { const chunks = splitUtf8ByteLength(script, SCRIPT_LINE_LENGTH); const lines = chunks.length; const lastLine = lines - 1; for (let i = 0; i < lines; i++) { let text = ''; // If this is not the first line, end the previous line's comment. if (i > 0) { text += '*/'; } text += chunks[i]; // If this is not the last line, start a new comment. if (i < lastLine) { text += '/*'; } const customScript = createCustomScriptECA(text); customScript.group = eca.group; outputEcas.push(customScript); } } else { outputEcas.push(eca); } } else { outputEcas.push(eca); } } return outputEcas; } /** * Given a name, converts all of the non-ASCII characters and space characters to underlines. */ export function ensureNameSafety(name: string): string { // Convert non-ASCII characters to underlines, for locales other than en. return name.split('').map((c) => c.charCodeAt(0) > 127 ? '_' : c).join('').replace(/\s/g, '_'); } ================================================ FILE: src/utils/w3x/weu/weu.ts ================================================ import War3Map from '../../../parsers/w3x/map'; import { TriggerData } from '../../../parsers/w3x/wtg/triggerdata'; import CustomTextTrigger from '../../../parsers/w3x/wct/customtexttrigger'; import parseWtg from './parsewtg'; import WeuData, { WEUChange } from './data'; import { processTrigger } from './processing'; import { convertTrigger } from './conversions'; export interface WeuConversionResult { ok: boolean; error?: string; changes?: WEUChange[]; } export default function convertWeu(map: War3Map, customTriggerData: TriggerData, weTriggerData: TriggerData): WeuConversionResult { let wts; let wtg; let wct; // Try to read the string table. try { wts = map.readStringTable(); } catch (e) { return { ok: false, error: `Failed to read the string table file: ${e}` }; } if (!wts) { return { ok: false, error: `The string table file doesn't exist` }; } // Try to add function signatures from the map script. // This handles the case of injected libraries, mostly seen in YDWE maps. const scriptFile = map.getScriptFile(); if (scriptFile && scriptFile.name.endsWith('.j')) { try { customTriggerData.addJassFunctions(scriptFile.text()); } catch (e) { } } const data = new WeuData(customTriggerData, wts); // Try to read the triggers file using the custom trigger data. // This will also try to analyze unknown signatures if such exist. try { wtg = parseWtg(map, customTriggerData, data); } catch (e) { return { ok: false, error: `Failed to read the triggers file: ${e}` }; } if (!wtg) { return { ok: false, error: `The triggers file doesn't exist` }; } // Try to read the custom text triggers file. try { wct = map.readCustomTextTriggers(); } catch (e) { return { ok: false, error: `Failed to read the custom text triggers file: ${e}` }; } if (!wct) { return { ok: false, error: `The custom text triggers file doesn't exist` }; } const triggers = wtg.triggers; const customTextTriggers = wct.triggers; const mapHeader = wct.trigger; // If there are less custom text triggers than triggers, WE does not crash, however it doesn't load the map. if (customTextTriggers.length < triggers.length) { for (let i = 0, l = triggers.length - customTextTriggers.length; i < l; i++) { customTextTriggers.push(new CustomTextTrigger()); } } // Process and convert the triggers as needed. for (let i = 0, l = triggers.length; i < l; i++) { const trigger = triggers[i]; // Any callbacks that are generated due to conversions for this trigger will end up here. const callbacks: string[] = []; try { // Process the trigger. // If things inside it need to be converted, this will convert them. const result = processTrigger(data, trigger, callbacks); // If the trigger itself needs to be converted, convert it. if (result.convert) { data.push(trigger); // The trigger body. let body = convertTrigger(data, trigger, callbacks); // If any callbacks were generated when converting the trigger, add them to the trigger. if (callbacks.length) { body = `${callbacks.join('\r\n')}\r\n${body}`; } customTextTriggers[i].text = body; trigger.ecas.length = 0; trigger.isCustom = 1; data.change('convertedtrigger', result.reason, customTextTriggers[i].text); data.pop(); } else if (callbacks.length) { const callbacksText = callbacks.join('\r\n'); // If the trigger didn't need to be converted, but callbacks were generated due to things inside it being converted, add them to the map header. mapHeader.text += `// Callbacks generated for trigger "${trigger.name}" due to conversions\r\n${callbacksText}\r\n`; data.change('generatedcallbacks', trigger.name, callbacksText); } } catch (e) { return { ok: false, error: `Error at ${data.stackToString()}: ${e}` }; } } // WE will only generate global variables for preplaced objects that are referenced directly by GUI. // Referencing them in custom text ECAs or custom text triggers doesn't cut it. // This function saves such references if they are deemed to be lost due to the conversion. // It does this by adding a new trigger called PreplacedObjectReferences, which is not initially on. // In it an ECA is added for each reference. // Note that this is not the case for all preplaced objects. // For example, triggers and regions seem to always be available. // For now only units and destructibles are checked. data.saveGUIReferences(triggers, customTextTriggers); // Save the triggers file back. map.set('war3map.wtg', wtg.save()); // Save the custom text triggers file back. map.set('war3map.wct', wct.save()); // Now try to re-read the triggers file, but using the normal WE trigger data. // If this fails, WE will fail too. try { wtg = map.readTriggers(weTriggerData); } catch (e) { return { ok: false, error: `Failed to validate the triggers file: ${e}` }; } if (!wtg) { return { ok: false, error: `Failed to re-read the triggers file` }; } return { ok: true, changes: data.changes }; } ================================================ FILE: src/version.ts ================================================ export const version = '5.13.0'; ================================================ FILE: src/viewer/bounds.ts ================================================ /** * An object representing both a sphere and an AABB, which is used for culling of all instances. * * By default, the size of the bounds is 0, and thus point-culling is done. */ export default class Bounds { x = 0; y = 0; z = 0; r = 0; fromExtents(min: Float32Array, max: Float32Array): void { const x = min[0]; const y = min[1]; const z = min[2]; const w = max[0] - x; const d = max[1] - y; const h = max[2] - z; this.x = x + w / 2; this.y = y + d / 2; this.z = z + h / 2; // Ensure the radius is actually 0 or bigger. // Some models apparently have reversed extents, go figure. this.r = Math.max(0, Math.max(w, d, h) / 2); } } ================================================ FILE: src/viewer/camera.ts ================================================ import { vec3, vec4, quat, mat4 } from 'gl-matrix'; import { VEC3_UNIT_Y, VEC3_UNIT_X, VEC3_UNIT_Z, unproject, unpackPlanes, quatLookAt } from '../common/gl-matrix-addon'; const vectorHeap = vec3.create(); const vectorHeap2 = vec3.create(); const vectorHeap3 = vec3.create(); const quatHeap = quat.create(); const facingCorrection = quat.setAxisAngle(quat.create(), VEC3_UNIT_X, Math.PI / 2); /** * A camera. */ export default class Camera { isPerspective = true; fov = 0; aspect = 0; isOrtho = false; leftClipPlane = 0; rightClipPlane = 0; bottomClipPlane = 0; topClipPlane = 0; nearClipPlane = 0; farClipPlane = 0; location = vec3.create(); rotation = quat.create(); inverseRotation = quat.create(); /** * World -> View. */ viewMatrix = mat4.create(); /** * View -> Clip. */ projectionMatrix = mat4.create(); /** * World -> Clip. */ viewProjectionMatrix = mat4.create(); /** * View -> World. */ inverseViewMatrix = mat4.create(); /** * Clip -> World. */ inverseViewProjectionMatrix = mat4.create(); /** * The X axis in camera space. */ directionX = vec3.create(); /** * The Y axis in camera space. */ directionY = vec3.create(); /** * The Z axis in camera space. */ directionZ = vec3.create(); /** * The four corners of a 2x2 rectangle. */ vectors = [vec3.fromValues(-1, -1, 0), vec3.fromValues(-1, 1, 0), vec3.fromValues(1, 1, 0), vec3.fromValues(1, -1, 0), vec3.fromValues(1, 0, 0), vec3.fromValues(0, 1, 0), vec3.fromValues(0, 0, 1)]; /** * Same as vectors, however these are all billboarded to the camera. */ billboardedVectors = [vec3.create(), vec3.create(), vec3.create(), vec3.create(), vec3.create(), vec3.create(), vec3.create()]; /** * The camera frustum planes in this order: left, right, top, bottom, near, far. */ planes = [vec4.create(), vec4.create(), vec4.create(), vec4.create(), vec4.create(), vec4.create()]; /** * Set the camera to perspective projection mode. */ perspective(fov: number, aspect: number, near: number, far: number): void { this.isPerspective = true; this.isOrtho = false; this.fov = fov; this.aspect = aspect; this.nearClipPlane = near; this.farClipPlane = far; this.update(); } /** * Set the camera to orthogonal projection mode. */ ortho(left: number, right: number, bottom: number, top: number, near: number, far: number): void { this.isPerspective = false; this.isOrtho = true; this.leftClipPlane = left; this.rightClipPlane = right; this.bottomClipPlane = bottom; this.topClipPlane = top; this.nearClipPlane = near; this.farClipPlane = far; this.update(); } /** * Set the camera location in world coordinates. */ setLocation(location: vec3): void { vec3.copy(this.location, location); this.update(); } /** * Move the camera by the given offset in world coordinates. */ move(offset: vec3): void { vec3.add(this.location, this.location, offset); this.update(); } /** * Set the camera rotation. */ setRotation(rotation: quat): void { quat.copy(this.rotation, rotation); this.update(); } /** * Rotate the camera by the given rotation. */ rotate(rotation: quat): void { quat.mul(this.rotation, this.rotation, rotation); this.update(); } /** * Look at `to`. */ face(to: vec3, worldUp: vec3): void { quat.mul(this.rotation, facingCorrection, quatLookAt(quatHeap, to, this.location, worldUp)); this.update(); } /** * Move to `from` and look at `to`. */ moveToAndFace(from: vec3, to: vec3, worldUp: vec3): void { vec3.copy(this.location, from); this.face(to, worldUp); } /** * Reset the location and angles. */ reset(): void { vec3.set(this.location, 0, 0, 0); quat.identity(this.rotation); this.update(); } /** * Recalculate the camera's transformation. */ update(): void { const location = this.location; const rotation = this.rotation; const inverseRotation = this.inverseRotation; const viewMatrix = this.viewMatrix; const projectionMatrix = this.projectionMatrix; const viewProjectionMatrix = this.viewProjectionMatrix; const vectors = this.vectors; const billboardedVectors = this.billboardedVectors; // View -> Clip. if (this.isPerspective) { mat4.perspective(projectionMatrix, this.fov, this.aspect, this.nearClipPlane, this.farClipPlane); } else { mat4.ortho(projectionMatrix, this.leftClipPlane, this.rightClipPlane, this.bottomClipPlane, this.topClipPlane, this.nearClipPlane, this.farClipPlane); } // World -> View. mat4.fromQuat(viewMatrix, rotation); mat4.translate(viewMatrix, viewMatrix, vec3.negate(vectorHeap, location)); // World -> Clip. mat4.mul(viewProjectionMatrix, projectionMatrix, viewMatrix); // View -> World. mat4.invert(this.inverseViewMatrix, viewMatrix); // Clip -> World. mat4.invert(this.inverseViewProjectionMatrix, viewProjectionMatrix); // Recaculate the camera's frusum planes unpackPlanes(this.planes, viewProjectionMatrix); quat.conjugate(inverseRotation, rotation); // View-space axes. vec3.transformQuat(this.directionX, VEC3_UNIT_X, inverseRotation); vec3.transformQuat(this.directionY, VEC3_UNIT_Y, inverseRotation); vec3.transformQuat(this.directionZ, VEC3_UNIT_Z, inverseRotation); // View-space rectangle, aka billboarded. for (let i = 0; i < 7; i++) { vec3.transformQuat(billboardedVectors[i], vectors[i], inverseRotation); } } /** * Given a vector in camera space, return the vector transformed to world space. */ cameraToWorld(out: vec3, v: vec3): vec3 { return vec3.transformMat4(out, v, this.inverseViewMatrix); } /** * Given a vector in world space, return the vector transformed to camera space. */ worldToCamera(out: vec3, v: vec3): vec3 { return vec3.transformMat4(out, v, this.viewMatrix); } /** * Given a vector in world space, return the vector transformed to screen space. */ worldToScreen(out: Float32Array, v: Float32Array, viewport: vec4): Float32Array { vec3.transformMat4(vectorHeap, v, this.viewProjectionMatrix); out[0] = Math.round(((vectorHeap[0] + 1) / 2) * viewport[2]); out[1] = Math.round(((vectorHeap[1] + 1) / 2) * viewport[3]); return out; } /** * Given a vector in screen space, return a ray from the near plane to the far plane. */ screenToWorldRay(out: Float32Array, v: Float32Array, viewport: vec4): Float32Array { const a = vectorHeap; const b = vectorHeap2; const c = vectorHeap3; const x = v[0]; const y = v[1]; const inverseViewProjectionMatrix = this.inverseViewProjectionMatrix; // Intersection on the near-plane unproject(a, vec3.set(c, x, y, 0), inverseViewProjectionMatrix, viewport); // Intersection on the far-plane unproject(b, vec3.set(c, x, y, 1), inverseViewProjectionMatrix, viewport); out.set(a, 0); out.set(b, 3); return out; } } ================================================ FILE: src/viewer/cell.ts ================================================ import { testCell } from '../common/gl-matrix-addon'; import Camera from './camera'; import ModelInstance from './modelinstance'; /** * A grid cell. */ export default class Cell { left: number; right: number; bottom: number; top: number; plane = -1; instances: ModelInstance[] = []; visible = false; constructor(left: number, right: number, bottom: number, top: number) { this.left = left; this.right = right; this.bottom = bottom; this.top = top; } add(instance: ModelInstance): void { this.instances.push(instance); } remove(instance: ModelInstance): void { const index = this.instances.indexOf(instance); this.instances.splice(index, 1); } /** * Remove all of the instances from this cell. */ clear(): void { this.instances.length = 0; } isVisible(camera: Camera): boolean { this.plane = testCell(camera.planes, this.left, this.right, this.bottom, this.top, this.plane); return this.plane === -1; } } ================================================ FILE: src/viewer/emittedobject.ts ================================================ import Emitter from './emitter'; /** * An emitted object. */ export default abstract class EmittedObject { emitter: Emitter; index = -1; health = 0; abstract bind(emitData?: unknown): void; abstract update(dt: number): void; constructor(emitter: Emitter) { this.emitter = emitter; } } ================================================ FILE: src/viewer/emittedobjectupdater.ts ================================================ import EmittedObject from './emittedobject'; /** * An emitted object updater. */ export default class EmittedObjectUpdater { objects: EmittedObject[] = []; alive = 0; add(object: EmittedObject): void { this.objects[this.alive++] = object; } update(dt: number): void { const objects = this.objects; for (let i = 0; i < this.alive; i++) { const object = objects[i]; object.update(dt * object.emitter.instance.timeScale); if (object.health <= 0) { this.alive -= 1; object.emitter.kill(object); // Swap between this object and the last living object. // Decrement the iterator so the swapped object is updated this frame. if (i !== this.alive) { objects[i] = objects[this.alive]; i -= 1; } } } } } ================================================ FILE: src/viewer/emitter.ts ================================================ import Scene from './scene'; import ModelInstance from './modelinstance'; import EmittedObject from './emittedobject'; /** * An emitter. */ export default abstract class Emitter { instance: ModelInstance; objects: EmittedObject[] = []; alive = 0; currentEmission = 0; abstract createObject(): EmittedObject; abstract updateEmission(dt: number): void; abstract emit(): void; constructor(instance: ModelInstance) { this.instance = instance; } /** * Update this emitter. */ update(dt: number): void { // Emit new objects if needed. this.updateEmission(dt); const currentEmission = this.currentEmission; if (currentEmission >= 1) { for (let i = 0; i < currentEmission; i += 1) { this.emit(); } } } /** * Clear any emitted objects. */ clear(): void { const objects = this.objects; for (let i = 0, l = this.alive; i < l; i++) { const object = objects[i]; object.health = 0; } this.currentEmission = 0; } emitObject(emitData?: unknown): EmittedObject { const objects = this.objects; // If there are no unused objects, create a new one. if (this.alive === objects.length) { objects.push(this.createObject()); } // Get the first unused object. const object = objects[this.alive]; object.index = this.alive; object.bind(emitData); this.alive += 1; this.currentEmission -= 1; const scene = this.instance.scene; scene.emittedObjectUpdater.add(object); return object; } kill(object: EmittedObject): void { const objects = this.objects; this.alive -= 1; const otherObject = objects[this.alive]; objects[object.index] = otherObject; objects[this.alive] = object; otherObject.index = object.index; object.index = -1; } } ================================================ FILE: src/viewer/genericresource.ts ================================================ import { Resource, ResourceData } from './resource'; /** * A generic resource. */ export default class GenericResource extends Resource { data: unknown = null; constructor(data: unknown, resourceData: ResourceData) { super(resourceData); this.data = data; } } ================================================ FILE: src/viewer/gl/clientbuffer.ts ================================================ /** * A buffer. */ export default class ClientBuffer { gl: WebGLRenderingContext; buffer: WebGLBuffer; size = 0; arrayBuffer: ArrayBuffer | null = null; byteView: Uint8Array | null = null; floatView: Float32Array | null = null; constructor(gl: WebGLRenderingContext, size = 4) { this.gl = gl; this.buffer = gl.createBuffer(); this.reserve(size); } reserve(size: number): void { if (this.size < size) { const gl = this.gl; // Ensure the size is on a 4 byte boundary. this.size = Math.ceil(size / 4) * 4; gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); gl.bufferData(gl.ARRAY_BUFFER, this.size, gl.DYNAMIC_DRAW); this.arrayBuffer = new ArrayBuffer(this.size); this.byteView = new Uint8Array(this.arrayBuffer); this.floatView = new Float32Array(this.arrayBuffer); } } bindAndUpdate(size = this.size): void { const gl = this.gl; const byteView = this.byteView; gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); gl.bufferSubData(gl.ARRAY_BUFFER, 0, byteView.subarray(0, size)); } } ================================================ FILE: src/viewer/gl/clientdatatexture.ts ================================================ /** * A data texture. */ export default class ClientDataTexture { gl: WebGLRenderingContext; texture: WebGLTexture; width = 0; height = 0; arrayBuffer = new ArrayBuffer(0); byteView: Uint8Array | null = null; floatView: Float32Array | null = null; constructor(gl: WebGLRenderingContext, width = 1, height = 1) { this.gl = gl; this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); this.reserve(width, height); } reserve(width: number, height: number): void { if (this.width < width || this.height < height) { const gl = this.gl; this.width = Math.max(this.width, width); this.height = Math.max(this.height, height); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.FLOAT, null); this.arrayBuffer = new ArrayBuffer(this.width * this.height * 16); this.byteView = new Uint8Array(this.arrayBuffer); this.floatView = new Float32Array(this.arrayBuffer); } } bindAndUpdate(width = this.width, height = this.height): void { const gl = this.gl; gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.FLOAT, this.byteView); } } ================================================ FILE: src/viewer/gl/datatexture.ts ================================================ /** * A data texture. */ export default class DataTexture { gl: WebGLRenderingContext; texture: WebGLTexture; format: number; width = 0; height = 0; constructor(gl: WebGLRenderingContext, channels = 4, width = 1, height = 1) { this.gl = gl; this.texture = gl.createTexture(); this.format = (channels === 3 ? gl.RGB : gl.RGBA); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); this.reserve(width, height); } reserve(width: number, height: number): void { if (this.width < width || this.height < height) { const gl = this.gl; this.width = Math.max(this.width, width); this.height = Math.max(this.height, height); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, gl.FLOAT, null); } } bindAndUpdate(buffer: Float32Array, width = this.width, height = this.height): void { const gl = this.gl; gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, this.format, gl.FLOAT, buffer); } bind(unit: number): void { const gl = this.gl; gl.activeTexture(gl.TEXTURE0 + unit); gl.bindTexture(gl.TEXTURE_2D, this.texture); } } ================================================ FILE: src/viewer/gl/gl.ts ================================================ import Texture from '../texture'; import ClientBuffer from './clientbuffer'; import ClientDataTexture from './clientdatatexture'; import DataTexture from './datatexture'; import Shader from './shader'; /** * A small WebGL utility class. * Makes it easier to generate shaders, textures, etc. */ export default class WebGL { gl: WebGLRenderingContext; currentShader: Shader | null = null; emptyTexture: WebGLTexture; extensions: {[key: string]: unknown } = {}; constructor(canvas: HTMLCanvasElement, options: WebGLContextAttributes = { alpha: false }) { let gl = canvas.getContext('webgl', options); if (!gl) { gl = canvas.getContext('experimental-webgl', options); } if (!gl) { throw new Error('WebGL: Failed to create a WebGL context!'); } const twoByTwo = new Uint8ClampedArray(16).fill(255); const emptyTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, emptyTexture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, twoByTwo); this.gl = gl; this.emptyTexture = emptyTexture; } /** * Ensures that an extension is available. * * If it is, it will be added to `extensions`. */ ensureExtension(name: string): boolean { const ext = this.gl.getExtension(name); if (ext) { this.extensions[name] = ext; return true; } return false; } createShader(vertexSource: string, fragmentSource: string): Shader { const gl = this.gl; const vertex = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertex, vertexSource); gl.compileShader(vertex); const fragment = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragment, fragmentSource); gl.compileShader(fragment); const program = gl.createProgram(); gl.attachShader(program, vertex); gl.attachShader(program, fragment); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { let log = 'Shader failed to link:'; const vertexLog = gl.getShaderInfoLog(vertex); if (vertexLog && vertexLog.length) { log += ` Vertex shader: ${vertexLog}`; } const fragmentLog = gl.getShaderInfoLog(fragment); if (fragmentLog && fragmentLog.length) { log += ` Fragment shader: ${fragmentLog}`; } throw new Error(log); } return new Shader(this, program); } /** * Enables all vertex attribs between [start, end], including start and discluding end. */ enableVertexAttribs(start: number, end: number): void { const gl = this.gl; for (let i = start; i < end; i++) { gl.enableVertexAttribArray(i); } } /** * Disables all vertex attribs between [start, end], including start and discluding end. */ disableVertexAttribs(start: number, end: number): void { const gl = this.gl; for (let i = start; i < end; i++) { gl.disableVertexAttribArray(i); } } /** * Use a shader program. */ useShader(shader: Shader): void { if (shader && shader !== this.currentShader) { let oldAttribs = 0; const newAttribs = shader.attribsCount; if (this.currentShader) { oldAttribs = this.currentShader.attribsCount; } this.gl.useProgram(shader.program); if (newAttribs > oldAttribs) { this.enableVertexAttribs(oldAttribs, newAttribs); } else if (newAttribs < oldAttribs) { this.disableVertexAttribs(newAttribs, oldAttribs); } this.currentShader = shader; } } /** * Bind a texture. * * If the given texture is invalid, a 2x2 black texture will be bound instead. */ bindTexture(texture: Texture | undefined | null, unit: number): void { const gl = this.gl; gl.activeTexture(gl.TEXTURE0 + unit); if (texture) { gl.bindTexture(gl.TEXTURE_2D, texture.webglResource); } else { // Bind an empty texture in case an invalid one was given, to avoid WebGL errors. gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture); } } bindTextureAndWrap(texture: Texture | undefined | null, unit: number, wrapS: number, wrapT: number): void { const gl = this.gl; gl.activeTexture(gl.TEXTURE0 + unit); if (texture) { gl.bindTexture(gl.TEXTURE_2D, texture.webglResource); } else { // Bind an empty texture in case an invalid one was given, to avoid WebGL errors. gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture); } gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); } /** * Set the texture wrap and filter values. */ setTextureMode(wrapS: number, wrapT: number, magFilter: number, minFilter: number): void { const gl = this.gl; gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); } /** * A shortcut for `new ClientBuffer(gl, size)`. */ createClientBuffer(size = 4): ClientBuffer { return new ClientBuffer(this.gl, size); } /** * A shortcut for `new DataTexture(gl, channels, width, height)`. */ createDataTexture(channels = 4, width = 1, height = 1): DataTexture { return new DataTexture(this.gl, channels, width, height); } /** * A shortcut for `new ClientDataTexture(gl, width, height)`. */ createClientDataTexture(width = 1, height = 1): ClientDataTexture { return new ClientDataTexture(this.gl, width, height); } } ================================================ FILE: src/viewer/gl/index.ts ================================================ import WebGL from './gl'; import Shader from './shader'; import ClientBuffer from './clientbuffer'; import DataTexture from './datatexture'; import ClientDataTexture from './clientdatatexture'; export default { WebGL, Shader, ClientBuffer, DataTexture, ClientDataTexture, }; ================================================ FILE: src/viewer/gl/shader.ts ================================================ import WebGL from './gl'; /** * A wrapper around a WebGL shader program. */ export default class Shader { webgl: WebGL; program: WebGLProgram; uniforms: {[key: string]: WebGLUniformLocation } = {}; attribs: {[key: string]: number } = {}; attribsCount = 0; constructor(webgl: WebGL, program: WebGLProgram) { this.webgl = webgl; this.program = program; const gl = webgl.gl; for (let i = 0, l = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); i < l; i++) { const object = gl.getActiveUniform(program, i); if (object) { if (object.size === 1) { this.uniforms[object.name] = gl.getUniformLocation(program, object.name); } else { const base = object.name.substr(0, object.name.length - 3); for (let index = 0; index < object.size; index++) { const name = base + '[' + index + ']'; this.uniforms[name] = gl.getUniformLocation(program, name); } } } } for (let i = 0, l = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); i < l; i++) { const object = gl.getActiveAttrib(program, i); if (object) { this.attribsCount += object.size; if (object.size === 1) { this.attribs[object.name] = gl.getAttribLocation(program, object.name); } else { const base = object.name.substr(0, object.name.length - 3); for (let index = 0; index < object.size; index++) { const name = base + '[' + index + ']'; this.attribs[name] = gl.getAttribLocation(program, name); } } } } } use(): void { this.webgl.useShader(this); } } ================================================ FILE: src/viewer/grid.ts ================================================ import Cell from './cell'; import ModelInstance from './modelinstance'; /** * A grid. */ export default class Grid { x: number; y: number; width: number; depth: number; cellWidth: number; cellDepth: number; columns: number; rows: number; cells: Cell[] = []; constructor(x: number, y: number, width: number, depth: number, cellWidth: number, cellDepth: number) { const columns = width / cellWidth; const rows = depth / cellDepth; this.x = x; this.y = y; this.width = width; this.depth = depth; this.cellWidth = cellWidth; this.cellDepth = cellDepth; this.columns = columns; this.rows = rows; for (let row = 0; row < rows; row++) { for (let column = 0; column < columns; column++) { const left = x + column * cellWidth; const right = left + cellWidth; const bottom = y + row * cellDepth; const top = bottom + cellDepth; this.cells[row * columns + column] = new Cell(left, right, bottom, top); } } } add(instance: ModelInstance): void { const cells = this.cells; const columns = this.columns; const left = instance.left; const right = instance.right + 1; const bottom = instance.bottom; const top = instance.top + 1; if (left !== -1) { for (let y = bottom; y < top; y++) { for (let x = left; x < right; x++) { cells[y * columns + x].add(instance); } } } } remove(instance: ModelInstance): void { const cells = this.cells; const columns = this.columns; const left = instance.left; const right = instance.right + 1; const bottom = instance.bottom; const top = instance.top + 1; if (left !== -1) { instance.left = -1; for (let y = bottom; y < top; y++) { for (let x = left; x < right; x++) { cells[y * columns + x].remove(instance); } } } } moved(instance: ModelInstance): void { const cellWidth = this.cellWidth; const cellDepth = this.cellDepth; const bounds = instance.model.bounds; const x = instance.worldLocation[0] + bounds.x - this.x; const y = instance.worldLocation[1] + bounds.y - this.y; const r = bounds.r; const s = instance.worldScale; let left = Math.floor((x - r * s[0]) / cellWidth); let right = Math.floor((x + r * s[0]) / cellWidth); let bottom = Math.floor((y - r * s[1]) / cellDepth); let top = Math.floor((y + r * s[1]) / cellDepth); if (right < 0 || left > this.columns - 1 || top < 0 || bottom > this.rows - 1) { // The instance is outside of the grid, so remove it. this.remove(instance); } else { // Clamp the values so they are in the grid. left = Math.max(left, 0); right = Math.min(right, this.columns - 1); bottom = Math.max(bottom, 0); top = Math.min(top, this.rows - 1); // If the values actually changed, update the cells. if (left !== instance.left || right !== instance.right || bottom !== instance.bottom || top !== instance.top) { /// TODO: This can be optimized by checking if there are shared cells. /// That can be done in precisely the same way as done a few lines above, i.e. simple rectangle intersection. this.remove(instance); instance.left = left; instance.right = right; instance.bottom = bottom; instance.top = top; this.add(instance); } } } /** * Removes all of the instances from this grid. */ clear(): void { for (const cell of this.cells) { cell.clear(); } } } ================================================ FILE: src/viewer/handlerresource.ts ================================================ import { ResourceData, Resource } from './resource'; export type SolverParams ={[key: string]: unknown }; /** * A path solver used for resolving fetch paths. */ export type PathSolver = (src: unknown, params?: SolverParams) => unknown; /** * The data sent to every handler resource as part of the loading process. */ export type HandlerResourceData = ResourceData & { pathSolver?: PathSolver }; /** * A viewer handler resource. * * Generally speaking handler resources are created via viewer.load(). */ export abstract class HandlerResource extends Resource { pathSolver?: PathSolver; constructor(resourceData: HandlerResourceData) { super(resourceData); this.pathSolver = resourceData.pathSolver; } } ================================================ FILE: src/viewer/handlers/blp/handler.ts ================================================ import { BlpImage } from '../../../parsers/blp/image'; import isBlp from '../../../parsers/blp/isformat'; import Texture from './texture'; export default { isValidSource(object: unknown): boolean { if (object instanceof BlpImage) { return true; } return isBlp(object); }, resource: Texture, }; ================================================ FILE: src/viewer/handlers/blp/texture.ts ================================================ import { isPowerOfTwo } from '../../../common/math'; import { BlpImage } from '../../../parsers/blp/image'; import { HandlerResourceData } from '../../handlerresource'; import Texture from '../../texture'; /** * A BLP texure handler. */ export default class BlpTexture extends Texture { constructor(bufferOrImage: ArrayBuffer | BlpImage, resourceData: HandlerResourceData) { super(resourceData); let image; if (bufferOrImage instanceof BlpImage) { image = bufferOrImage; } else { image = new BlpImage(); image.load(bufferOrImage); } const viewer = this.viewer; const gl = viewer.gl; const id = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, id); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); const isPOT = isPowerOfTwo(image.width) && isPowerOfTwo(image.height); if (!isPOT) { // Required for NPOT textures. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } const mipmaps = image.mipmaps(); // If there is one mipmap, or fake mipmaps, or it's an NPOT image, use just the first mipmap. Otherwise load all of them. if (mipmaps === 1 || image.fakeMipmaps() || !isPOT) { const imageData = image.getMipmap(0); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData); } else { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); let width = image.width; let height = image.height; for (let i = 0; i < mipmaps; i++) { const imageData = image.getMipmap(i); // Don't use the image data dimensions directly. // Some JPG mipmaps out there have wrong sizes. // For example the last two mipmaps being 2x1, which messes with GL. gl.texImage2D(gl.TEXTURE_2D, i, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData.data); width = Math.ceil(width / 2); height = Math.ceil(height / 2); } } this.width = image.width; this.height = image.height; this.webglResource = id; } } ================================================ FILE: src/viewer/handlers/dds/handler.ts ================================================ import { DdsImage } from '../../../parsers/dds/image'; import isDds from '../../../parsers/dds/isformat'; import ModelViewer from '../../viewer'; import Texture from './texture'; export default { load(viewer: ModelViewer): void { const webgl = viewer.webgl; // Optionally used when decoding mipmaps. if (!webgl.ensureExtension('WEBGL_compressed_texture_s3tc')) { console.warn('DDS: No compressed textures support! This might reduce performance.'); } }, isValidSource(object: unknown): boolean { if (object instanceof DdsImage) { return true; } return isDds(object); }, resource: Texture, }; ================================================ FILE: src/viewer/handlers/dds/texture.ts ================================================ import { DdsImage, FOURCC_DXT1, FOURCC_DXT3, FOURCC_DXT5, FOURCC_ATI2 } from '../../../parsers/dds/image'; import { HandlerResourceData } from '../../handlerresource'; import Texture from '../../texture'; /** * A DDS texture handler. */ export default class DdsTexture extends Texture { constructor(bufferOrImage: ArrayBuffer | DdsImage, resourceData: HandlerResourceData) { super(resourceData); let image; if (bufferOrImage instanceof DdsImage) { image = bufferOrImage; } else { image = new DdsImage(); image.load(bufferOrImage); } const viewer = this.viewer; const gl = viewer.gl; const webgl = viewer.webgl; const compressedTextures = webgl.extensions['WEBGL_compressed_texture_s3tc']; const format = image.format; let internalFormat = 0; if (compressedTextures) { if (format === FOURCC_DXT1) { internalFormat = compressedTextures.COMPRESSED_RGB_S3TC_DXT1_EXT; } else if (format === FOURCC_DXT3) { internalFormat = compressedTextures.COMPRESSED_RGBA_S3TC_DXT3_EXT; } else if (format === FOURCC_DXT5) { internalFormat = compressedTextures.COMPRESSED_RGBA_S3TC_DXT5_EXT; } } const id = gl.createTexture(); this.width = image.width; this.height = image.height; this.webglResource = id; gl.bindTexture(gl.TEXTURE_2D, id); const mipmaps = image.mipmaps(); // DXT1 and ATI2 pixels are two bytes. // This generally doesn't matter, however, when having 1x2 or 2x1 mipmaps, it does. // Therefore set the proper alignment if needed. if (format === FOURCC_DXT1 || format === FOURCC_ATI2) { gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2); } for (let i = 0; i < mipmaps; i++) { // Let the GPU handle the compressed data if it supports it. // Otherwise, decode the data on the client. const { width, height, data } = image.getMipmap(i, internalFormat !== 0); if (internalFormat) { gl.compressedTexImage2D(gl.TEXTURE_2D, i, internalFormat, width, height, 0, data); } else if (format === FOURCC_DXT1) { gl.texImage2D(gl.TEXTURE_2D, i, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); } else if (format === FOURCC_DXT3) { gl.texImage2D(gl.TEXTURE_2D, i, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); } else if (format === FOURCC_DXT5) { gl.texImage2D(gl.TEXTURE_2D, i, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); } else { gl.texImage2D(gl.TEXTURE_2D, i, gl.LUMINANCE_ALPHA, width, height, 0, gl.LUMINANCE_ALPHA, gl.UNSIGNED_BYTE, data); } } // Restore the alignment to the default, in case it changed. gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); if (mipmaps > 1) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); } else { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); } } } ================================================ FILE: src/viewer/handlers/index.ts ================================================ import blp from './blp/handler'; import dds from './dds/handler'; import m3 from './m3/handler'; import mdx from './mdx/handler'; import tga from './tga/handler'; import War3MapViewer from './w3x/viewer'; export default { blp, dds, m3, mdx, tga, War3MapViewer, }; ================================================ FILE: src/viewer/handlers/m3/attachment.ts ================================================ import AttachmentPoint from '../../../parsers/m3/attachmentpoint'; /** * An M3 attachment. */ export default class M3Attachment { name: string; bone: number; constructor(attachment: AttachmentPoint) { this.name = attachment.name.get(); this.bone = attachment.bone; } } ================================================ FILE: src/viewer/handlers/m3/batch.ts ================================================ import M3Region from './region'; import { M3StandardMaterial } from './standardmaterial'; /** * An M3 batch. */ export default class M3Batch { region: M3Region; material: M3StandardMaterial; constructor(region: M3Region, material: M3StandardMaterial) { this.region = region; this.material = material; } } ================================================ FILE: src/viewer/handlers/m3/bone.ts ================================================ import Bone from '../../../parsers/m3/bone'; import { Uint32AnimationReference, Vector3AnimationReference, Vector4AnimationReference } from '../../../parsers/m3/animationreference'; /** * An M3 bone. */ export default class M3Bone { name: string; parent: number; location: Vector3AnimationReference; rotation: Vector4AnimationReference; scale: Vector3AnimationReference; visibility: Uint32AnimationReference; inhertTranslation: number; inheritScale: number; inheritRotation: number; billboard1: number; billboard2: number; twoDProjection: number; animated: number; inverseKinematics: number; skinned: number; real: number; constructor(bone: Bone) { const flags = bone.flags; this.name = bone.name.get(); this.parent = bone.parent; this.location = bone.location; this.rotation = bone.rotation; this.scale = bone.scale; this.visibility = bone.visibility; this.inhertTranslation = flags & 0x1; this.inheritScale = flags & 0x2; this.inheritRotation = flags & 0x4; this.billboard1 = flags & 0x10; this.billboard2 = flags & 0x40; this.twoDProjection = flags & 0x100; this.animated = flags & 0x200; this.inverseKinematics = flags & 0x400; this.skinned = flags & 0x800; this.real = flags & 0x2000; } } ================================================ FILE: src/viewer/handlers/m3/boundingshape.ts ================================================ import M3BoundingShape from '../../../parsers/m3/boundingshape'; /** * An M3 bounding shape. */ export default class BoundingShape { bone: number; matrix: Float32Array; constructor(boundingshape: M3BoundingShape) { this.bone = boundingshape.bone; this.matrix = boundingshape.matrix; //this.name = bones[boundingshape.bone].name; /* var size = boundingshape.size; var shape; if (boundingshape.shape === 0) { shape = gl.createCube(-size[0], -size[1], -size[2], size[0], size[1], size[2]); } else if (boundingshape.shape === 1) { shape = gl.createSphere(0, 0, 0, 9, 9, size[0]); } else { shape = gl.createCylinder(0, 0, 0, size[0], size[1], 9); } this.shape = shape; */ } } ================================================ FILE: src/viewer/handlers/m3/camera.ts ================================================ import Camera from '../../../parsers/m3/camera'; /** * An M3 camera. */ export default class M3Camera { bone: number; name: string; constructor(camera: Camera) { this.bone = camera.bone; this.name = camera.name.get(); // / TODO: Add animated getters, much like the Mdx structures. /* this.fieldOfView = new AnimationReference(reader, readFloat32); this.farClip = new AnimationReference(reader, readFloat32); this.nearClip = new AnimationReference(reader, readFloat32); this.clip2 = new AnimationReference(reader, readFloat32); this.focalDepth = new AnimationReference(reader, readFloat32); this.falloffStart = new AnimationReference(reader, readFloat32); this.falloffEnd = new AnimationReference(reader, readFloat32); this.depthOfField = new AnimationReference(reader, readFloat32); */ } } ================================================ FILE: src/viewer/handlers/m3/handler.ts ================================================ import Parser from '../../../parsers/m3/model'; import isM3 from '../../../parsers/m3/isformat'; import ModelViewer from '../../viewer'; import Shader from '../../gl/shader'; import Model from './model'; import standardVert from './shaders/standard.vert'; import standardFrag from './shaders/standard.frag'; export interface M3HandlerObject { standardShaders: Shader[]; } export default { load(viewer: ModelViewer): void { const gl = viewer.gl; const webgl = viewer.webgl; const teamColors = [[255, 3, 3], [0, 66, 255], [28, 230, 185], [84, 0, 129], [255, 252, 1], [254, 138, 14], [32, 192, 0], [229, 91, 176], [149, 150, 151], [126, 191, 241], [16, 98, 70], [78, 42, 4], [40, 40, 40], [0, 0, 0]]; // Bone textures. if (!webgl.ensureExtension('OES_texture_float')) { throw new Error('M3: No float texture support!'); } const standardShaders = []; // Load shaders for 1-4 texture coordinate models. for (let i = 0; i < 4; i++) { const shader = webgl.createShader(`#define EXPLICITUV${i}\n${standardVert}`, standardFrag); // Bind the shader and set the team color uniforms. shader.use(); for (let i = 0; i < 14; i++) { const color = teamColors[i]; gl.uniform3f(shader.uniforms['u_teamColors[' + i + ']'], color[0] / 255, color[1] / 255, color[2] / 255); } standardShaders[i] = shader; } const handlerData: M3HandlerObject = { standardShaders }; viewer.sharedCache.set('m3', handlerData); }, isValidSource(object: unknown): boolean { if (object instanceof Parser) { return true; } return isM3(object); }, resource: Model, }; ================================================ FILE: src/viewer/handlers/m3/layer.ts ================================================ import Reference from '../../../parsers/m3/reference'; import Layer from '../../../parsers/m3/layer'; import Texture from '../../texture'; import Shader from '../../gl/shader'; import { M3StandardMaterial, STANDARD_MATERIAL_OFFSET } from './standardmaterial'; import M3Model from './model'; import M3Texture from './texture'; const layerTypeToTextureUnit = { diffuse: 1, decal: 2, specular: 3, gloss: 4, emissive: 5, emissive2: 6, evio: 7, evioMask: 8, alphaMask: 9, alphaMask2: 10, normal: 11, heightMap: 12, lightMap: 13, ao: 14, }; /** * An M3 layer. */ export default class M3Layer { model: M3Model; material: M3StandardMaterial; index: number; active = 0; layer: Layer | null = null; gl: WebGLRenderingContext; uniformMap: { map: string; enabled: string; op: string; channels: string; teamColorMode: string; invert: string; clampResult: string; uvCoordinate: string; }; source = ''; texture: M3Texture | null = null; flags = 0; colorChannels = 0; type = ''; op = 0; uvCoordinate = 0; textureUnit = 0; invert = 0; clampResult = 0; teamColorMode = 0; constructor(material: M3StandardMaterial, index: number, layerReference: Reference, type: string, op: number) { const model = material.model; this.model = model; this.material = material; this.gl = material.gl; this.index = index; const uniform = 'u_' + type; const settings = uniform + 'LayerSettings.'; this.uniformMap = { map: uniform + 'Map', enabled: settings + 'enabled', op: settings + 'op', channels: settings + 'channels', teamColorMode: settings + 'teamColorMode', invert: settings + 'invert', clampResult: settings + 'clampResult', uvCoordinate: settings + 'uvCoordinate', }; // Since Gloss doesn't exist in all versions if (layerReference.entries) { const layer = layerReference.first(); this.layer = layer; const pathSolver = model.pathSolver; const path = layer.imagePath.get(); if (path) { const source = (path).toLowerCase(); if (source.length) { this.source = source; this.active = 1; const uvSource = layer.uvSource; const flags = layer.flags; this.flags = flags; this.colorChannels = layer.colorChannelSetting; this.model = model; this.type = type; this.op = op; let uvCoordinate = 0; if (uvSource === 1) { uvCoordinate = 1; } else if (uvSource === 9) { uvCoordinate = 2; } else if (uvSource === 10) { uvCoordinate = 3; } this.uvCoordinate = uvCoordinate; this.textureUnit = layerTypeToTextureUnit[type]; this.invert = flags & 0x10; this.clampResult = flags & 0x20; // I am not sure if the emissive team color mode is even used, since so far combineColors takes care of it. if (type === 'diffuse') { this.teamColorMode = 1; } const m3Texture = new M3Texture(!!(flags & 0x4), !!(flags & 0x8)); model.viewer.load(source, pathSolver) .then((texture) => { if (texture) { m3Texture.texture = texture; } }); this.texture = m3Texture; } } } } bind(shader: Shader, textureOverrides: Map): void { const gl = this.gl; const uniformMap = this.uniformMap; const uniforms = shader.uniforms; const active = this.active; gl.uniform1f(uniforms[uniformMap.enabled], active); if (active) { const m3Texture = this.texture; const texture = textureOverrides.get(this.material.index * STANDARD_MATERIAL_OFFSET + this.index) || m3Texture.texture; const textureUnit = this.textureUnit; gl.uniform1i(uniforms[uniformMap.map], textureUnit); this.model.viewer.webgl.bindTextureAndWrap(texture, textureUnit, m3Texture.wrapS, m3Texture.wrapT); gl.uniform1f(uniforms[uniformMap.op], this.op); gl.uniform1f(uniforms[uniformMap.channels], this.colorChannels); gl.uniform1f(uniforms[uniformMap.teamColorMode], this.teamColorMode); // Alpha is probably unknown12. Can this be confirmed? // Many of these flags seem to be incorrect // gl.setParameter(uniform + 'multAddAlpha', [this.model.getValue(this.rgbMultiply, sequence, frame), this.model.getValue(this.rgbAdd, sequence, frame), 0]); // gl.setParameter(uniform + 'useAlphaFactor', 0); gl.uniform1f(uniforms[uniformMap.invert], this.invert); // gl.setParameter(uniform + 'multColor', 0); // gl.setParameter(uniform + 'addColor', 0); gl.uniform1f(uniforms[uniformMap.clampResult], this.clampResult); // gl.setParameter(uniform + 'useConstantColor', this.flags && 0x400); // gl.setParameter(uniform + 'constantColor', this.model.getValue(this.color, sequence, frame)); // gl.setParameter(settings + 'uvSource', this.uvSource); gl.uniform1f(uniforms[uniformMap.uvCoordinate], this.uvCoordinate); } } unbind(shader: Shader): void { if (this.active) { this.gl.uniform1f(shader.uniforms[this.uniformMap.enabled], 0); } } } ================================================ FILE: src/viewer/handlers/m3/model.ts ================================================ import Parser from '../../../parsers/m3/model'; import M3ParserModel from '../../../parsers/m3/modelheader'; import M3ParserDivision from '../../../parsers/m3/division'; import StandardMaterial from '../../../parsers/m3/standardmaterial'; import Sequence from '../../../parsers/m3/sequence'; import Region from '../../../parsers/m3/region'; import Bone from '../../../parsers/m3/bone'; import Stc from '../../../parsers/m3/stc'; import Sts from '../../../parsers/m3/sts'; import Stg from '../../../parsers/m3/stg'; import AttachmentPoint from '../../../parsers/m3/attachmentpoint'; import Camera from '../../../parsers/m3/camera'; import Model from '../../model'; import { M3StandardMaterial } from './standardmaterial'; import M3Bone from './bone'; import M3Sequence from './sequence'; import M3Sts from './sts'; import M3Stc from './stc'; import M3Stg from './stg'; import M3AttachmentPoint from './attachment'; import M3Camera from './camera'; import M3Region from './region'; import M3ModelInstance from './modelinstance'; import M3Batch from './batch'; import { HandlerResourceData } from '../../handlerresource'; import Division from '../../../parsers/m3/division'; import Batch from '../../../parsers/m3/batch'; import MaterialReference from '../../../parsers/m3/materialreference'; /** * An M3 model. */ export default class M3Model extends Model { name = ''; batches: M3Batch[] = []; materials: [unknown[], M3StandardMaterial[]] = [[], []]; // 2D array for the possibility of adding more material types in the future materialMaps: MaterialReference[] = []; bones: M3Bone[] = []; boneLookup: Uint16Array; sequences: M3Sequence[] = []; sts: M3Sts[] = []; stc: M3Stc[] = []; stg: M3Stg[] = []; attachments: M3AttachmentPoint[] = []; cameras: M3Camera[] = []; regions: M3Region[] = []; initialReference: Float32Array[] = []; elementBuffer: WebGLBuffer | null = null; arrayBuffer: WebGLBuffer | null = null; vertexSize = 0; uvSetCount = 0; constructor(bufferOrParser: ArrayBuffer | Parser, resourceData: HandlerResourceData) { super(resourceData); let parser; if (bufferOrParser instanceof Parser) { parser = bufferOrParser; } else { parser = new Parser(); parser.load(bufferOrParser); } const model = parser.model; const div = model.divisions.first(); this.name = model.modelName.get(); this.setupGeometry(model, div); const materialMaps = model.materialReferences.get(); this.materialMaps = materialMaps; // Create concrete material objects for standard materials const standardMaterials = model.materials[0].get(); for (let i = 0, l = standardMaterials.length; i < l; i++) { this.materials[1].push(new M3StandardMaterial(this, i, standardMaterials[i])); } // Create concrete batch objects for (const batch of div.batches.get()) { const regionId = batch.regionIndex; const materialMap = materialMaps[batch.materialReferenceIndex]; if (materialMap.materialType === 1) { this.batches.push(new M3Batch(this.regions[regionId], this.materials[1][materialMap.materialIndex])); } } /* var batchGroups = [[], [], [], [], [], []]; for (i = 0, l = batches.length; i < l; i++) { var blendMode = batches[i].material.blendMode; batchGroups[blendMode].push(batches[i]); } function sortByPriority(a, b) { var a = a.material.priority; var b = b.material.priority; if (a < b) { return 1; } else if (a == b) { return 0; } else { return -1; } } for (i = 0; i < 6; i++) { batchGroups[i].sort(sortByPriority); } */ /* // In the EggPortrait model the batches seem to be sorted by blend mode. Is this true for every model? this.batches.sort(function (a, b) { var ba = a.material.blendMode; var bb = b.material.blendMode; if (ba < bb) { return -1; } else if (ba == bb) { return 0; } else { return 1; } }); */ // this.batches = batchGroups[0].concat(batchGroups[1]).concat(batchGroups[2]).concat(batchGroups[3]).concat(batchGroups[4]).concat(batchGroups[5]); this.initialReference = model.absoluteInverseBoneRestPositions.get(); for (const bone of model.bones.get()) { this.bones.push(new M3Bone(bone)); } this.boneLookup = model.boneLookup.get(); const sequences = model.sequences.get(); if (sequences) { for (const sequence of sequences) { this.sequences.push(new M3Sequence(sequence)); } } const stss = model.sts.get(); if (stss) { for (const sts of stss) { this.sts.push(new M3Sts(sts)); } } const stcs = model.stc.get(); if (stcs) { for (const stc of stcs) { this.stc.push(new M3Stc(stc)); } } const stgs = model.stg.get(); if (stgs) { for (const stg of stgs) { this.stg.push(new M3Stg(stg, this.sts, this.stc)); } } this.addGlobalAnims(); /* if (parser.fuzzyHitTestObjects.length > 0) { for (i = 0, l = parser.fuzzyHitTestObjects.length; i < l; i++) { this.boundingShapes[i] = new M3BoundingShape(parser.fuzzyHitTestObjects[i], parser.bones, gl); } } */ /* if (parser.particleEmitters.length > 0) { this.particleEmitters = []; for (i = 0, l = parser.particleEmitters.length; i < l; i++) { this.particleEmitters[i] = new M3ParticleEmitter(parser.particleEmitters[i], this); } } */ const attachmentPoints = model.attachmentPoints.get(); if (attachmentPoints) { for (const attachment of attachmentPoints) { this.attachments.push(new M3AttachmentPoint(attachment)); } } const cameras = model.cameras.get(); if (cameras) { for (const camera of cameras) { this.cameras.push(new M3Camera(camera)); } } } addInstance(): M3ModelInstance { return new M3ModelInstance(this); } setupGeometry(parser: M3ParserModel, div: M3ParserDivision): void { const gl = this.viewer.gl; let uvSetCount = 1; const vertexFlags = parser.vertexFlags; if (vertexFlags & 0x40000) { uvSetCount = 2; } else if (vertexFlags & 0x80000) { uvSetCount = 3; } else if (vertexFlags & 0x100000) { uvSetCount = 4; } const regions = div.regions.get(); let totalElements = 0; const offsets = []; for (let i = 0, l = regions.length; i < l; i++) { offsets[i] = totalElements; totalElements += regions[i].triangleIndicesCount; } const elementArray = new Uint16Array(totalElements); const triangles = div.triangles.get(); for (let i = 0, l = regions.length; i < l; i++) { this.regions.push(new M3Region(this, regions[i], triangles, elementArray, offsets[i])); } const vertices = parser.vertices.get(); this.elementBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, elementArray, gl.STATIC_DRAW); const arrayBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, arrayBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); this.arrayBuffer = arrayBuffer; this.vertexSize = (7 + uvSetCount) * 4; this.uvSetCount = uvSetCount; } mapMaterial(index: number): M3StandardMaterial { const materialMap = this.materialMaps[index]; // return this.materials[materialMap.materialType][materialMap.materialIndex]; return this.materials[1][materialMap.materialIndex]; } addGlobalAnims(): void { /* var i, l; var glbirth, glstand, gldeath; var stgs = this.stg; var stg, name; for (i = 0, l = stgs.length; i < l; i++) { stg = stgs[i]; name = stg.name.toLowerCase(); // Because obviously there will be a wrong case in some model... if (name === 'glbirth') { glbirth = stg; } else if (name === 'glstand') { glstand = stg; } else if (name === 'gldeath') { gldeath = stg; } } for (i = 0, l = stgs.length; i < l; i++) { stg = stgs[i]; name = stg.name.toLowerCase(); // Because obviously there will be a wrong case in some model... if (name !== 'glbirth' && name !== 'glstand' && name !== 'gldeath') { if (name.indexOf('birth') !== -1 && glbirth) { stg.stcIndices = stg.stcIndices.concat(glbirth.stcIndices); } else if (name.indexOf('death') !== -1 && gldeath) { stg.stcIndices = stg.stcIndices.concat(gldeath.stcIndices); } else if (glstand) { stg.stcIndices = stg.stcIndices.concat(glstand.stcIndices); } } } */ } // getValue(animRef: M3ParserAnimationReference, sequence: number, frame: number) { // if (sequence !== -1) { // return this.stg[sequence].getValue(animRef, frame); // } else { // return animRef.initValue; // } // } } ================================================ FILE: src/viewer/handlers/m3/modelinstance.ts ================================================ import { mat4 } from 'gl-matrix'; import DataTexture from '../../gl/datatexture'; import Scene from '../../scene'; import ModelInstance from '../../modelinstance'; import Texture from '../../texture'; import M3Model from './model'; import M3Skeleton from './skeleton'; import { STANDARD_MATERIAL_OFFSET } from './standardmaterial'; import { M3HandlerObject } from './handler'; import M3Node from './node'; const boneHeap = mat4.create(); /** * An M3 model instance. */ export default class M3ModelInstance extends ModelInstance { skeleton: M3Skeleton | null = null; teamColor = 0; vertexColor = new Float32Array([1, 1, 1, 1]); sequence = -1; frame = 0; sequenceLoopMode = 0; sequenceEnded = false; forced = true; boneTexture: DataTexture | null = null; constructor(model: M3Model) { super(model); this.skeleton = new M3Skeleton(this); // This takes care of calling setSequence before the model is loaded. // In this case, this.sequence will be set, but nothing else is changed. // Now that the model is loaded, set it again to do the real work. if (this.sequence !== -1) { this.setSequence(this.sequence); } this.boneTexture = new DataTexture(model.viewer.gl, 3, model.boneLookup.length * 4, 1); } /** * Override the texture of the layer at the given index in the material at the given index. * * If a texture isn't given, removes the override if there was one. */ setTexture(material: number, layer: number, texture?: Texture): void { this.overrideTexture(material * STANDARD_MATERIAL_OFFSET + layer, texture); } updateSkeletonAndBoneTexture(dt: number): void { const model = this.model; const viewer = model.viewer; const buffer = viewer.buffer; const boneLookup = model.boneLookup; const skeleton = this.skeleton; const nodes = skeleton.nodes; const bindPose = model.initialReference; const count = boneLookup.length; const isAnimated = this.sequence !== -1; const boneTexture = this.boneTexture; skeleton.update(dt); // Ensure there is enough memory for all of the instances data. buffer.reserve(count * 48); const floatView = buffer.floatView; let finalMatrix; if (isAnimated) { finalMatrix = boneHeap; } else { finalMatrix = this.worldMatrix; } for (let i = 0; i < count; i++) { const offset = i * 12; if (isAnimated) { const bone = boneLookup[i]; // Every bone has to be multiplied by its bind pose counterpart for rendering. finalMatrix = mat4.mul(boneHeap, nodes[bone].worldMatrix, bindPose[bone]); } floatView[offset + 0] = finalMatrix[0]; floatView[offset + 1] = finalMatrix[1]; floatView[offset + 2] = finalMatrix[2]; floatView[offset + 3] = finalMatrix[4]; floatView[offset + 4] = finalMatrix[5]; floatView[offset + 5] = finalMatrix[6]; floatView[offset + 6] = finalMatrix[8]; floatView[offset + 7] = finalMatrix[9]; floatView[offset + 8] = finalMatrix[10]; floatView[offset + 9] = finalMatrix[12]; floatView[offset + 10] = finalMatrix[13]; floatView[offset + 11] = finalMatrix[14]; } boneTexture.bindAndUpdate(floatView, boneTexture.width, 1); } override renderOpaque(): void { const model = this.model; const batches = model.batches; if (batches.length) { const viewer = model.viewer; const m3Cache = viewer.sharedCache.get('m3'); const gl = viewer.gl; const vertexSize = model.vertexSize; const uvSetCount = model.uvSetCount; const shader = m3Cache.standardShaders[uvSetCount - 1]; const attribs = shader.attribs; const uniforms = shader.uniforms; const scene = this.scene; const camera = scene.camera; const textureOverrides = this.textureOverrides; const boneTexture = this.boneTexture; shader.use(); gl.uniform1f(uniforms['u_teamColor'], this.teamColor); gl.uniform4fv(uniforms['u_vertexColor'], this.vertexColor); gl.uniformMatrix4fv(uniforms['u_VP'], false, camera.viewProjectionMatrix); gl.uniformMatrix4fv(uniforms['u_MV'], false, camera.viewMatrix); gl.uniform3fv(uniforms['u_eyePos'], camera.location); gl.uniform3fv(uniforms['u_lightPos'], scene.lightPosition); boneTexture.bind(15); gl.uniform1i(uniforms['u_boneMap'], 15); gl.uniform1f(uniforms['u_vectorSize'], 1 / boneTexture.width); gl.uniform1f(uniforms['u_rowSize'], 1); gl.bindBuffer(gl.ARRAY_BUFFER, model.arrayBuffer); gl.vertexAttribPointer(attribs['a_position'], 3, gl.FLOAT, false, vertexSize, 0); gl.vertexAttribPointer(attribs['a_weights'], 4, gl.UNSIGNED_BYTE, false, vertexSize, 12); gl.vertexAttribPointer(attribs['a_bones'], 4, gl.UNSIGNED_BYTE, false, vertexSize, 16); gl.vertexAttribPointer(attribs['a_normal'], 4, gl.UNSIGNED_BYTE, false, vertexSize, 20); for (let i = 0; i < uvSetCount; i++) { gl.vertexAttribPointer(attribs[`a_uv${i}`], 2, gl.SHORT, false, vertexSize, 24 + i * 4); } gl.vertexAttribPointer(attribs['a_tangent'], 4, gl.UNSIGNED_BYTE, false, vertexSize, 24 + uvSetCount * 4); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.elementBuffer); for (const batch of batches) { const material = batch.material; const region = batch.region; material.bind(shader, textureOverrides); region.render(shader); material.unbind(shader); // This is required to not use by mistake layers from this material that were bound and are not overwritten by the next material } } } override updateAnimations(dt: number): void { const sequenceId = this.sequence; if (sequenceId !== -1) { const model = this.model; const sequence = model.sequences[sequenceId]; const interval = sequence.interval; this.frame += dt * 1000; if (this.frame > interval[1]) { if ((this.sequenceLoopMode === 0 && !(sequence.flags & 0x1)) || this.sequenceLoopMode === 2) { this.frame = interval[0]; } else { this.frame = interval[1]; } this.sequenceEnded = true; } else { this.sequenceEnded = false; } } if (this.forced || sequenceId !== -1) { this.forced = false; this.updateSkeletonAndBoneTexture(dt); } } setTeamColor(id: number): this { this.teamColor = id; return this; } setVertexColor(color: Uint8Array): this { this.vertexColor.set(color); return this; } setSequence(id: number): this { const model = this.model; this.sequence = id; this.frame = 0; if (id < -1 || id > model.sequences.length - 1) { id = -1; this.sequence = id; } // Do a forced update, so non-animated data can be skipped in future updates this.forced = true; return this; } setSequenceLoopMode(mode: number): this { this.sequenceLoopMode = mode; return this; } getAttachment(id: number): M3Node | undefined { const model = this.model; const attachment = model.attachments[id]; if (attachment) { return (this.skeleton).nodes[attachment.bone]; } return; } } ================================================ FILE: src/viewer/handlers/m3/node.ts ================================================ import { quat } from 'gl-matrix'; import { SkeletalNode } from '../../skeletalnode'; /** * An M3 node. */ export default class M3Node extends SkeletalNode { override convertBasis(rotation: quat): void { const halfPI = Math.PI / 2; quat.rotateZ(rotation, rotation, halfPI); quat.rotateY(rotation, rotation, -halfPI); } } ================================================ FILE: src/viewer/handlers/m3/region.ts ================================================ import M3ParserRegion from '../../../parsers/m3/region'; import Shader from '../../gl/shader'; import M3Model from './model'; /** * An M3 region. */ export default class M3Region { gl: WebGLRenderingContext; firstBoneLookupIndex: number; boneWeightPairsCount: number; offset: number; verticesCount: number; elements: number; constructor(model: M3Model, region: M3ParserRegion, triangles: Uint16Array, elementArray: Uint16Array, offset: number) { const firstVertexIndex = region.firstVertexIndex; const triangleIndicesCount = region.triangleIndicesCount; const firstTriangleIndex = region.firstTriangleIndex; // Note for implementors: the one original vertex indices array could be used with access to the base-vertex draw elements function. // See https://www.opengl.org/sdk/docs/man3/xhtml/glDrawElementsBaseVertex.xml // firstTriangleIndex is the indices offset. // firstVertexIndex is the base vertex. for (let i = 0; i < triangleIndicesCount; i++) { elementArray[offset + i] = triangles[firstTriangleIndex + i] + firstVertexIndex; } this.gl = model.viewer.gl; this.firstBoneLookupIndex = region.firstBoneLookupIndex; this.boneWeightPairsCount = region.boneWeightPairsCount; this.offset = offset * 2; this.verticesCount = region.verticesCount; this.elements = triangleIndicesCount; } render(shader: Shader): void { const gl = this.gl; gl.uniform1f(shader.uniforms['u_firstBoneLookupIndex'], this.firstBoneLookupIndex); gl.uniform1f(shader.uniforms['u_boneWeightPairsCount'], this.boneWeightPairsCount); gl.drawElements(gl.TRIANGLES, this.elements, gl.UNSIGNED_SHORT, this.offset); } } ================================================ FILE: src/viewer/handlers/m3/sd.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { clamp, lerp } from '../../../common/math'; import { AnimationReference } from '../../../parsers/m3/animationreference'; import M3ParserSd from '../../../parsers/m3/sd'; const vectorHeap = vec3.create(); const quatHeap = quat.create(); /** * Sequence data. */ class M3Sd { keys: Int32Array; values: vec3[] | quat[] | number[]; biggestKey: number; constructor(sd: M3ParserSd) { this.keys = sd.keys.get(); this.values = sd.values.get(); // Fake typecasting to avoid a TS error. this.biggestKey = sd.biggestKey; } } /** * A sequence data container. */ export default class M3SdContainer { sd: M3Sd[] = []; addSds(sds: M3ParserSd[]): void { for (const sd of sds) { this.sd.push(new M3Sd(sd)); } } getValueUnsafe(index: number, animationReference: AnimationReference, frame: number, runsConcurrent: number): number | vec3 | quat | Uint8Array | null { const sd = this.sd[index]; if (runsConcurrent) { frame = frame % sd.biggestKey; } const keys = sd.keys; const values = sd.values; // getInterval let a = keys.length; let b = 0; while (b !== keys.length && frame > keys[b]) { a = b; b++; } const length = keys.length; if (a === length) { if (b === length) { return animationReference.initValue; } else { return values[b]; } } if (b === length || a >= b) { return values[a]; } const t = clamp((frame - keys[a]) / (keys[b] - keys[a]), 0, 1); const va = values[a]; const vb = values[b]; const interpolationType = animationReference.interpolationType; const fakeVa = va; /// UGLY!!! if (fakeVa.length === 4) { if (interpolationType === 0) { return quat.copy(quatHeap, va); } else { return quat.slerp(quatHeap, va, vb, t); } } else if (fakeVa.length === 3) { if (interpolationType === 0) { return vec3.copy(vectorHeap, va); } else { return vec3.lerp(vectorHeap, va, vb, t); } } else { if (interpolationType === 0) { return va; } else { return lerp(va, vb, t); } } } } ================================================ FILE: src/viewer/handlers/m3/sequence.ts ================================================ import M3ParserSequence from '../../../parsers/m3/sequence'; import M3ParserBoundingSphere from '../../../parsers/m3/boundingsphere'; /** * An M3 sequence. */ export default class M3Sequence { name: string; interval: Uint32Array; movementSpeed: number; frequency: number; boundingSphere: M3ParserBoundingSphere; flags: number; constructor(sequence: M3ParserSequence) { this.name = sequence.name.get(); this.interval = sequence.interval; this.movementSpeed = sequence.movementSpeed; this.frequency = sequence.frequency; this.boundingSphere = sequence.boundingSphere; this.flags = sequence.flags; } } ================================================ FILE: src/viewer/handlers/m3/shaders/layers.glsl.ts ================================================ const shader = ` varying vec3 v_normal; varying vec4 v_uv[2]; varying vec3 v_lightDir; // varying vec3 v_eyeVec; varying vec3 v_halfVec; varying vec3 v_teamColor; varying vec4 v_vertexColor; struct LayerSettings { bool enabled; float op; float channels; float teamColorMode; // vec3 multAddAlpha; // bool useAlphaFactor; bool invert; // bool multColor; // bool addColor; bool clampResult; // bool useConstantColor; // vec4 constantColor; // float uvSource; float uvCoordinate; // float fresnelMode; // float fresnelTransformMode; // mat4 fresnelTransform; // bool fresnelClamp; // vec3 fresnelExponentBiasScale; }; uniform float u_specularity; uniform float u_specMult; uniform float u_emisMult; uniform vec4 u_lightAmbient; uniform LayerSettings u_diffuseLayerSettings; uniform sampler2D u_diffuseMap; uniform LayerSettings u_decalLayerSettings; uniform sampler2D u_decalMap; uniform LayerSettings u_specularLayerSettings; uniform sampler2D u_specularMap; uniform LayerSettings u_glossLayerSettings; uniform sampler2D u_glossMap; uniform LayerSettings u_emissiveLayerSettings; uniform sampler2D u_emissiveMap; uniform LayerSettings u_emissive2LayerSettings; uniform sampler2D u_emissive2Map; uniform LayerSettings u_evioLayerSettings; uniform sampler2D u_evioMap; uniform LayerSettings u_evioMaskLayerSettings; uniform sampler2D u_evioMaskMap; uniform LayerSettings u_alphaLayerSettings; uniform sampler2D u_alphaMap; uniform LayerSettings u_alphaMaskLayerSettings; uniform sampler2D u_alphaMaskMap; uniform LayerSettings u_normalLayerSettings; uniform sampler2D u_normalMap; uniform LayerSettings u_heightLayerSettings; uniform sampler2D u_heightMap; uniform LayerSettings u_lightMapLayerSettings; uniform sampler2D u_lightMapMap; uniform LayerSettings u_aoLayerSettings; uniform sampler2D u_aoMap; #define SPECULAR_RGB 0.0 #define SPECULAR_A_ONLY 1.0 #define FRESNELMODE_NONE 0.0 #define FRESNELMODE_STANDARD 1.0 #define FRESNELMODE_INVERTED 2.0 #define FRESNELTRANSFORM_NONE 0.0 #define FRESNELTRANSFORM_SIMPLE 1.0 #define FRESNELTRANSFORM_NORMALIZED 2.0 #define UVMAP_EXPLICITUV0 0.0 #define UVMAP_EXPLICITUV1 1.0 #define UVMAP_REFLECT_CUBICENVIO 2.0 #define UVMAP_REFLECT_SPHERICALENVIO 3.0 #define UVMAP_PLANARLOCALZ 4.0 #define UVMAP_PLANARWORLDZ 5.0 #define UVMAP_PARTICLE_FLIPBOOK 6.0 #define UVMAP_CUBICENVIO 7.0 #define UVMAP_SPHERICALENVIO 8.0 #define UVMAP_EXPLICITUV2 9.0 #define UVMAP_EXPLICITUV3 10.0 #define UVMAP_PLANARLOCALX 11.0 #define UVMAP_PLANARLOCALY 12.0 #define UVMAP_PLANARWORLDX 13.0 #define UVMAP_PLANARWORLDY 14.0 #define UVMAP_SCREENSPACE 15.0 #define UVMAP_TRIPLANAR_LOCAL 16.0 #define UVMAP_TRIPLANAR_WORLD 17.0 #define UVMAP_TRIPLANAR_WORLD_LOCAL_Z 18.0 #define CHANNELSELECT_RGB 0.0 #define CHANNELSELECT_RGBA 1.0 #define CHANNELSELECT_A 2.0 #define CHANNELSELECT_R 3.0 #define CHANNELSELECT_G 4.0 #define CHANNELSELECT_B 5.0 #define TEAMCOLOR_NONE 0.0 #define TEAMCOLOR_DIFFUSE 1.0 #define TEAMCOLOR_EMISSIVE 2.0 #define LAYEROP_MOD 0.0 #define LAYEROP_MOD2X 1.0 #define LAYEROP_ADD 2.0 #define LAYEROP_LERP 3.0 #define LAYEROP_TEAMCOLOR_EMISSIVE_ADD 4.0 #define LAYEROP_TEAMCOLOR_DIFFUSE_ADD 5.0 #define LAYEROP_ADD_NO_ALPHA 6.0 // float calculateFresnelTerm(vec3 normal, vec3 eyeToVertex, float exponent, mat4 fresnelTransform, float fresnelTransformMode, bool fresnelClamp) { // vec3 fresnelDir = eyeToVertex; // float result; // if (fresnelTransformMode != FRESNELTRANSFORM_NONE) { // fresnelDir = (fresnelTransform * vec4(fresnelDir, 1.0)).xyz; // if (fresnelTransformMode == FRESNELTRANSFORM_NORMALIZED) { // fresnelDir = normalize(fresnelDir); // } // } // if (fresnelClamp) { // result = 1.0 - clamp(-dot(normal, fresnelDir), 0.0, 1.0); // } else { // result = 1.0 - abs(dot(normal, fresnelDir)); // } // result = max(result, 0.0000001); // return pow(result, exponent); // } vec3 combineLayerColor(vec4 color, vec3 result, LayerSettings layerSettings) { if (layerSettings.op == LAYEROP_MOD) { result *= color.rgb; } else if (layerSettings.op == LAYEROP_MOD2X) { result *= color.rgb * 2.0; } else if (layerSettings.op == LAYEROP_ADD) { result += color.rgb * color.a; } else if (layerSettings.op == LAYEROP_ADD_NO_ALPHA) { result += color.rgb; } else if (layerSettings.op == LAYEROP_LERP) { result = mix(result, color.rgb, color.a); } else if (layerSettings.op == LAYEROP_TEAMCOLOR_EMISSIVE_ADD) { result += color.a * v_teamColor; } else if (layerSettings.op == LAYEROP_TEAMCOLOR_DIFFUSE_ADD) { result += color.a * v_teamColor; } return result; } vec4 chooseChannel(float channel, vec4 texel) { if (channel == CHANNELSELECT_R) { texel = texel.rrrr; } else if (channel == CHANNELSELECT_G) { texel = texel.gggg; } else if (channel == CHANNELSELECT_B) { texel = texel.bbbb; } else if (channel == CHANNELSELECT_A) { texel = texel.aaaa; } else if (channel == CHANNELSELECT_RGB) { texel.a = 1.0; } return texel; } vec2 getUV(LayerSettings layerSettings) { if (layerSettings.uvCoordinate == 1.0) { return v_uv[0].zw; } else if (layerSettings.uvCoordinate == 2.0) { return v_uv[1].xy; } else if (layerSettings.uvCoordinate == 3.0) { return v_uv[1].zw; } return v_uv[0].xy; } vec4 sampleLayer(sampler2D layer, LayerSettings layerSettings) { // if (layerSettings.useConstantColor) { // return layerSettings.constantColor; // } return texture2D(layer, getUV(layerSettings)); } vec4 computeLayerColor(sampler2D layer, LayerSettings layerSettings) { vec4 color = sampleLayer(layer, layerSettings); // if (layerSettings.useMask) { // result *= mask; // } vec4 result = chooseChannel(layerSettings.channels, color); // if (layerSettings.useAlphaFactor) { // result.a *= layerSettings.multiplyAddAlpha.z; // } if (layerSettings.teamColorMode == TEAMCOLOR_DIFFUSE) { result = vec4(mix(v_teamColor, result.rgb, color.a), 1.0); } else if (layerSettings.teamColorMode == TEAMCOLOR_EMISSIVE) { result = vec4(mix(v_teamColor, result.rgb, color.a), 1.0); } if (layerSettings.invert) { result = vec4(1.0) - result; } // if (layerSettings.multiplyEnable) { // result *= layerSettings.multiplyAddAlpha.x; // } // if (layerSettings.addEnable) { // result += layerSettings.multiplyAddAlpha.y; // } if (layerSettings.clampResult) { result = clamp(result, 0.0, 1.0); } // if (layerSettings.fresnelMode != FRESNELMODE_NONE) { // float fresnelTerm = calculateFresnelTerm(v_normal, v_eyeVec, layerSettings.fresnelExponentBiasScale.x, layerSettings.fresnelTransform, layerSettings.fresnelTransformMode, layerSettings.fresnelClamp); // if (layerSettings.fresnelMode == FRESNELMODE_INVERTED) { // fresnelTerm = 1.0 - fresnelTerm; // } // fresnelTerm = clamp(fresnelTerm * layerSettings.fresnelExponentBiasScale.z + layerSettings.fresnelExponentBiasScale.y, 0.0, 1.0); // result *= fresnelTerm; // } return result; } vec3 decodeNormal(sampler2D map) { vec4 texel = texture2D(map, v_uv[0].xy); vec3 normal; normal.xy = 2.0 * texel.wy - 1.0; normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy))); return normal; } vec4 computeSpecular(sampler2D specularMap, LayerSettings layerSettings, float specularity, float specMult, vec3 normal) { vec4 color; if (layerSettings.enabled) { color = computeLayerColor(specularMap, layerSettings); } else { color = vec4(0); } float factor = pow(max(-dot(v_halfVec, normal), 0.0), specularity) * specMult; return color * factor; } `; export default shader; ================================================ FILE: src/viewer/handlers/m3/shaders/standard.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; import layers from './layers.glsl'; const shader = ` ${precision} ${layers} void main() { vec3 color; vec4 final = u_lightAmbient; vec3 normal; vec3 lightMapDiffuse; if (u_normalLayerSettings.enabled) { normal = decodeNormal(u_normalMap); } else { normal = v_normal; } float lambertFactor = max(dot(normal, v_lightDir), 0.0); if (lambertFactor > 0.0) { if (u_diffuseLayerSettings.enabled) { vec4 diffuseColor = computeLayerColor(u_diffuseMap, u_diffuseLayerSettings); color = combineLayerColor(diffuseColor, color, u_diffuseLayerSettings); } if (u_decalLayerSettings.enabled) { vec4 decalColor = computeLayerColor(u_decalMap, u_decalLayerSettings); color = combineLayerColor(decalColor, color, u_decalLayerSettings); } vec4 specularColor = computeSpecular(u_specularMap, u_specularLayerSettings, u_specularity, u_specMult, normal); if (u_lightMapLayerSettings.enabled) { vec4 lightMapColor = computeLayerColor(u_lightMapMap, u_lightMapLayerSettings) * 2.0; lightMapDiffuse = lightMapColor.rgb; } // final.rgb = color * lightMapDiffuse + specularColor.rgb; final.rgb = (color + specularColor.rgb) * lambertFactor; bool addEmissive = false; vec3 emissiveColor; vec4 tempColor; if (u_emissiveLayerSettings.enabled) { tempColor = computeLayerColor(u_emissiveMap, u_emissiveLayerSettings); if (u_emissiveLayerSettings.op == LAYEROP_MOD || u_emissiveLayerSettings.op == LAYEROP_MOD2X || u_emissiveLayerSettings.op == LAYEROP_LERP) { final.rgb = combineLayerColor(tempColor, final.rgb, u_emissiveLayerSettings); } else { emissiveColor = combineLayerColor(tempColor, emissiveColor, u_emissiveLayerSettings); addEmissive = true; } } if (u_emissive2LayerSettings.enabled) { tempColor = computeLayerColor(u_emissive2Map, u_emissive2LayerSettings); if (!addEmissive && (u_emissive2LayerSettings.op == LAYEROP_MOD || u_emissive2LayerSettings.op == LAYEROP_MOD2X || u_emissive2LayerSettings.op == LAYEROP_LERP)) { final.rgb = combineLayerColor(tempColor, final.rgb, u_emissive2LayerSettings); } else { emissiveColor = combineLayerColor(tempColor, emissiveColor, u_emissive2LayerSettings); addEmissive = true; } } if (addEmissive) { final.rgb += emissiveColor * u_emisMult; } } gl_FragColor = final * v_vertexColor; } `; export default shader; ================================================ FILE: src/viewer/handlers/m3/shaders/standard.vert.ts ================================================ import boneTexture from '../../shaders/bonetexture.glsl'; const shader = ` uniform mat4 u_VP; uniform mat4 u_MV; uniform vec3 u_eyePos; uniform vec3 u_lightPos; uniform float u_firstBoneLookupIndex; uniform float u_boneWeightPairsCount; uniform vec3 u_teamColors[14]; uniform float u_teamColor; uniform vec4 u_vertexColor; attribute vec3 a_position; attribute vec4 a_normal; attribute vec2 a_uv0; #ifdef EXPLICITUV1 attribute vec2 a_uv1; #endif #ifdef EXPLICITUV2 attribute vec2 a_uv1, a_uv2; #endif #ifdef EXPLICITUV3 attribute vec2 a_uv1, a_uv2, a_uv3; #endif attribute vec4 a_tangent; attribute vec4 a_bones; attribute vec4 a_weights; varying vec3 v_normal; varying vec4 v_uv[2]; // Pack 4 vec2 in 2 vec4, to reduce the varyings count varying vec3 v_lightDir; // varying vec3 v_eyeVec; varying vec3 v_halfVec; varying vec3 v_teamColor; varying vec4 v_vertexColor; ${boneTexture} vec3 TBN(vec3 vector, vec3 tangent, vec3 binormal, vec3 normal) { return vec3(dot(vector, tangent), dot(vector, binormal), dot(vector, normal)); } vec4 decodeVector(vec4 v) { return ((v / 255.0) * 2.0) - 1.0; } void transform(inout vec3 position, inout vec3 normal, inout vec3 tangent, inout vec3 binormal, vec4 bones, vec4 weights) { if (u_boneWeightPairsCount > 0.0) { mat4 bone; if (u_boneWeightPairsCount == 1.0) { bone = fetchMatrix(bones[0], 0.0); } else { bone += fetchMatrix(bones[0], 0.0) * weights[0]; bone += fetchMatrix(bones[1], 0.0) * weights[1]; bone += fetchMatrix(bones[2], 0.0) * weights[2]; bone += fetchMatrix(bones[3], 0.0) * weights[3]; } position = vec3(bone * vec4(position, 1.0)); normal = mat3(bone) * normal; tangent = vec3(bone * vec4(tangent, 0.0)); binormal = vec3(bone * vec4(binormal, 0.0)); } } void main() { vec4 decodedNormal = decodeVector(a_normal); vec3 position = a_position; vec3 normal = decodedNormal.xyz; vec3 tangent = vec3(decodeVector(a_tangent)); vec3 binormal = cross(normal, tangent) * decodedNormal.w; transform(position, normal, tangent, binormal, a_bones + u_firstBoneLookupIndex, a_weights / 255.0); vec3 position_mv = vec3(u_MV * vec4(position, 1)); mat3 mv = mat3(u_MV); vec3 t = normalize(mv * tangent); vec3 b = normalize(mv * binormal); vec3 n = normalize(mv * normal); vec3 lightDir = normalize(u_lightPos - position_mv); v_lightDir = normalize(TBN(lightDir, t, b, n)); vec3 eyeVec = normalize(u_eyePos - position_mv); vec3 halfVec = normalize(eyeVec - u_lightPos); // v_eyeVec = TBN(eyeVec, t, b, n); v_halfVec = TBN(halfVec, t, b, n); v_normal = n; vec4 uv0, uv1; uv0.xy = a_uv0 / 2048.0; #ifdef EXPLICITUV1 uv0.zw = a_uv1 / 2048.0; #endif #ifdef EXPLICITUV2 uv0.zw = a_uv1 / 2048.0; uv1.xy = a_uv2 / 2048.0; #endif #ifdef EXPLICITUV3 uv0.zw = a_uv1 / 2048.0; uv1.xy = a_uv2 / 2048.0; uv1.zw = a_uv3 / 2048.0; #endif v_uv[0] = uv0; v_uv[1] = uv1; v_teamColor = u_teamColors[int(u_teamColor)]; v_vertexColor = u_vertexColor; gl_Position = u_VP * vec4(position, 1.0); } `; export default shader; ================================================ FILE: src/viewer/handlers/m3/skeleton.ts ================================================ import { AnimationReference } from '../../../parsers/m3/animationreference'; import { createSkeletalNodes } from '../../skeletalnode'; import M3Node from './node'; import M3ModelInstance from './modelinstance'; import M3Bone from './bone'; import M3Sts from './sts'; import M3Stc from './stc'; import M3Stg from './stg'; import M3Model from './model'; import { quat, vec3 } from 'gl-matrix'; /** * M3 skeleton. */ export default class M3Skeleton { nodes: M3Node[]; worldMatrices: Float32Array; instance: M3ModelInstance; modelNodes: M3Bone[]; initialReference: Float32Array[]; sts: M3Sts[]; stc: M3Stc[]; stg: M3Stg[]; boneLookup: Uint16Array; constructor(instance: M3ModelInstance) { const model = instance.model; const bones = model.bones; const boneLookup = model.boneLookup; const sharedNodeData = createSkeletalNodes(bones.length, M3Node); const nodes = sharedNodeData.nodes; this.nodes = nodes; this.worldMatrices = sharedNodeData.worldMatrices; this.instance = instance; this.modelNodes = bones; this.initialReference = model.initialReference; this.sts = model.sts; this.stc = model.stc; this.stg = model.stg; this.boneLookup = boneLookup; // Set the bone parent references for (let i = 0, l = bones.length; i < l; i++) { const bone = bones[i]; if (bone.parent === -1) { nodes[i].parent = instance; } else { nodes[i].parent = nodes[bone.parent]; } if (bone.billboard1) { nodes[i].billboarded = true; } } } update(dt: number): void { const instance = this.instance; const nodes = this.nodes; const modelNodes = this.modelNodes; for (let i = 0, l = nodes.length; i < l; i++) { const node = nodes[i]; const modelNode = modelNodes[i]; this.getValue4(node.localRotation, modelNode.rotation, instance); this.getValue3(node.localLocation, modelNode.location, instance); this.getValue3(node.localScale, modelNode.scale, instance); node.recalculateTransformation(instance); // Recalculate and update child nodes. // Note that this only affects normal nodes such as instances, and not skeletal nodes. for (const child of node.children) { child.recalculateTransformation(); child.update(dt); } } } getValueUnsafe(animRef: AnimationReference, instance: M3ModelInstance): number | vec3 | quat | Uint8Array | null { const sequence = instance.sequence; if (sequence !== -1) { return this.stg[sequence].getValueUnsafe(animRef, instance); } return animRef.initValue; } getValue(animRef: AnimationReference, instance: M3ModelInstance): number { return this.getValueUnsafe(animRef, instance); } getValue2(out: Float32Array, animRef: AnimationReference, instance: M3ModelInstance): Float32Array { const unsafeHeap = this.getValueUnsafe(animRef, instance); out[0] = unsafeHeap[0]; out[1] = unsafeHeap[1]; return out; } getValue3(out: Float32Array, animRef: AnimationReference, instance: M3ModelInstance): Float32Array { const unsafeHeap = this.getValueUnsafe(animRef, instance); out[0] = unsafeHeap[0]; out[1] = unsafeHeap[1]; out[2] = unsafeHeap[2]; return out; } getValue4(out: Float32Array, animRef: AnimationReference, instance: M3ModelInstance): Float32Array { const unsafeHeap = this.getValueUnsafe(animRef, instance); out[0] = unsafeHeap[0]; out[1] = unsafeHeap[1]; out[2] = unsafeHeap[2]; out[3] = unsafeHeap[3]; return out; } } ================================================ FILE: src/viewer/handlers/m3/standardmaterial.ts ================================================ import M3ParserStandardMaterial from '../../../parsers/m3/standardmaterial'; import Shader from '../../gl/shader'; import Texture from '../../texture'; import M3Model from './model'; import M3Layer from './layer'; export const STANDARD_MATERIAL_OFFSET = 100; /** * An M3 standard material. */ export class M3StandardMaterial { model: M3Model; gl: WebGLRenderingContext; index: number; name: string; flags: number; blendMode: number; priority: number; specularity: number; specMult: number; emisMult: number; layerBlendType: number; emisBlendType: number; emisMode: number; doubleSided: number; layers: M3Layer[]; constructor(model: M3Model, index: number, material: M3ParserStandardMaterial) { this.model = model; this.gl = model.viewer.gl; this.index = index; this.name = material.name.get(); this.flags = material.flags; this.blendMode = material.blendMode; this.priority = material.priority; this.specularity = material.specularity; this.specMult = material.specMult; this.emisMult = material.emisMult; this.layerBlendType = material.layerBlendType; this.emisBlendType = material.emisBlendType; this.emisMode = material.emisMode; this.doubleSided = material.flags & 0x8; this.layers = [ new M3Layer(this, 0, material.diffuseLayer, 'diffuse', 2), new M3Layer(this, 1, material.decalLayer, 'decal', 2), new M3Layer(this, 2, material.specularLayer, 'specular', 2), new M3Layer(this, 3, material.glossLayer, 'gloss', 2), new M3Layer(this, 4, material.emissiveLayer, 'emissive', material.emisBlendType), new M3Layer(this, 5, material.emissive2Layer, 'emissive2', material.emisMode), new M3Layer(this, 6, material.evioLayer, 'evio', 2), new M3Layer(this, 7, material.evioMaskLayer, 'evioMask', 2), new M3Layer(this, 8, material.alphaMaskLayer, 'alphaMask', 2), new M3Layer(this, 9, material.alphaMask2Layer, 'alphaMask2', 2), new M3Layer(this, 10, material.normalLayer, 'normal', 2), new M3Layer(this, 11, material.heightLayer, 'heightMap', 2), new M3Layer(this, 12, material.lightMapLayer, 'lightMap', 2), new M3Layer(this, 13, material.ambientOcclusionLayer, 'ao', 2), ]; } bindCommon(): void { const gl = this.gl; if (this.blendMode === 1) { gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE); } else if (this.blendMode === 2) { gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE); } else { gl.disable(gl.BLEND); } if (this.doubleSided) { gl.disable(gl.CULL_FACE); } else { gl.enable(gl.CULL_FACE); } // Flags somewhere? // Per layer? gl.enable(gl.DEPTH_TEST); gl.depthMask(true); } bind(shader: Shader, textureOverrides: Map): void { const gl = this.gl; this.bindCommon(); gl.uniform1f(shader.uniforms['u_specularity'], this.specularity); gl.uniform1f(shader.uniforms['u_specMult'], this.specMult); gl.uniform1f(shader.uniforms['u_emisMult'], this.emisMult); gl.uniform4f(shader.uniforms['u_lightAmbient'], 0.02, 0.02, 0.02, 0); const layers = this.layers; layers[0].bind(shader, textureOverrides); layers[1].bind(shader, textureOverrides); layers[2].bind(shader, textureOverrides); layers[4].bind(shader, textureOverrides); layers[5].bind(shader, textureOverrides); layers[10].bind(shader, textureOverrides); layers[12].bind(shader, textureOverrides); } unbind(shader: Shader): void { const gl = this.gl; gl.disable(gl.BLEND); gl.enable(gl.CULL_FACE); const layers = this.layers; layers[0].unbind(shader); layers[1].unbind(shader); layers[2].unbind(shader); layers[4].unbind(shader); layers[5].unbind(shader); layers[10].unbind(shader); layers[12].unbind(shader); } } ================================================ FILE: src/viewer/handlers/m3/stc.ts ================================================ import M3ParserStc from '../../../parsers/m3/stc'; import { AnimationReference } from '../../../parsers/m3/animationreference'; import M3ModelInstance from './modelinstance'; import M3SdContainer from './sd'; import M3ParserSd from '../../../parsers/m3/sd'; import { quat, vec3 } from 'gl-matrix'; /** * M3 sequence data. */ export default class M3Stc { name: string; runsConcurrent: number; priority: number; stsIndex: number; animRefs: number[][] = []; sd: M3SdContainer[] = []; constructor(stc: M3ParserStc) { const animIds = stc.animIds.get(); this.name = stc.name.get(); this.runsConcurrent = stc.runsConcurrent; this.priority = stc.priority; this.stsIndex = stc.stsIndex; const uints = stc.animRefs.get(); const animRefs = new Uint16Array(uints.buffer); // Allows direct checks instead of loops for (let i = 0, l = animIds.length; i < l; i++) { this.animRefs[animIds[i]] = [animRefs[i * 2 + 1], animRefs[i * 2]]; } for (const sd of stc.sd) { const container = new M3SdContainer(); const sds = sd.get(); if (sds) { container.addSds(sds); } this.sd.push(container); } } getValueUnsafe(animRef: AnimationReference, instance: M3ModelInstance): number | vec3 | quat | Uint8Array | null { const ref = this.animRefs[animRef.animId]; if (ref) { return this.sd[ref[0]].getValueUnsafe(ref[1], animRef, instance.frame, this.runsConcurrent); } return animRef.initValue; } } ================================================ FILE: src/viewer/handlers/m3/stg.ts ================================================ import M3ParserStg from '../../../parsers/m3/stg'; import { AnimationReference } from '../../../parsers/m3/animationreference'; import M3ModelInstance from './modelinstance'; import M3Sts from './sts'; import M3Stc from './stc'; import { quat, vec3 } from 'gl-matrix'; /** * M3 animation data getter. */ export default class M3Stg { name: string; stcIndices: Uint32Array; sts: M3Sts[]; stc: M3Stc[]; constructor(stg: M3ParserStg, sts: M3Sts[], stc: M3Stc[]) { this.name = stg.name.get(); this.stcIndices = stg.stcIndices.get(); this.sts = sts; this.stc = stc; } getValueUnsafe(animRef: AnimationReference, instance: M3ModelInstance): number | vec3 | quat | Uint8Array | null { const stcIndices = this.stcIndices; const stcs = this.stc; const stss = this.sts; for (let i = 0, l = stcIndices.length; i < l; i++) { const stc = stcs[stcIndices[i]]; const sts = stss[stc.stsIndex]; // First check if this STC actually has data for this animation reference if (sts.hasData(animRef)) { // Since this STC has data for this animation reference, return it return stc.getValueUnsafe(animRef, instance); } } // No STC referenced by the STG had data for this animation reference return animRef.initValue; } } ================================================ FILE: src/viewer/handlers/m3/sts.ts ================================================ import M3ParserSts from '../../../parsers/m3/sts'; import { AnimationReference } from '../../../parsers/m3/animationreference'; /** * M3 animation data validator. */ export default class M3Sts { animIds = new Map(); constructor(sts: M3ParserSts) { const animIds = sts.animIds.get(); // Allows direct checks instead of loops for (let i = 0, l = animIds.length; i < l; i++) { this.animIds.set(animIds[i], i); } } hasData(animRef: AnimationReference): boolean { return this.animIds.has(animRef.animId); } } ================================================ FILE: src/viewer/handlers/m3/texture.ts ================================================ import Texture from '../../texture'; /** * An M3 texture. */ export default class M3Texture { texture: Texture | null = null; wrapS = 0x812f; // CLAMP_TO_EDGE wrapT = 0x812f; constructor(repeatS: boolean, repeatT: boolean) { if (repeatS) { this.wrapS = 0x2901; // REPEAT } if (repeatT) { this.wrapT = 0x2901; } } } ================================================ FILE: src/viewer/handlers/mdx/animatedobject.ts ================================================ import MdlxAnimatedObject from '../../../parsers/mdlx/animatedobject'; import MdxModel from './model'; import { Sd, createTypedSd } from './sd'; /** * An animation object. */ export default class AnimatedObject { model: MdxModel; animations: Map = new Map(); variants: {[key: string]: Uint8Array } = {}; constructor(model: MdxModel, object: MdlxAnimatedObject) { this.model = model; for (const animation of object.animations) { this.animations.set(animation.name, createTypedSd(model, animation)); } } getScalarValue(out: Uint32Array | Float32Array, name: string, sequence: number, frame: number, counter: number, defaultValue: number): number { if (sequence !== -1) { const animation = this.animations.get(name); if (animation) { return animation.getValue(out, sequence, frame, counter); } } out[0] = defaultValue; return -1; } getVectorValue(out: Float32Array, name: string, sequence: number, frame: number, counter: number, defaultValue: Float32Array): number { if (sequence !== -1) { const animation = this.animations.get(name); if (animation) { return animation.getValue(out, sequence, frame, counter); } } out[0] = defaultValue[0]; out[1] = defaultValue[1]; out[2] = defaultValue[2]; return -1; } getQuatValue(out: Float32Array, name: string, sequence: number, frame: number, counter: number, defaultValue: Float32Array): number { if (sequence !== -1) { const animation = this.animations.get(name); if (animation) { return animation.getValue(out, sequence, frame, counter); } } out[0] = defaultValue[0]; out[1] = defaultValue[1]; out[2] = defaultValue[2]; out[3] = defaultValue[3]; return -1; } addVariants(name: string, variantName: string): void { const animation = this.animations.get(name); const sequences = this.model.sequences.length; const variants = new Uint8Array(sequences); if (animation) { for (let i = 0; i < sequences; i++) { if (animation.isVariant(i)) { variants[i] = 1; } } } this.variants[variantName] = variants; } addVariantIntersection(names: string[], variantName: string): void { const sequences = this.model.sequences.length; const variants = new Uint8Array(sequences); for (let i = 0; i < sequences; i++) { for (const name of names) { if (this.variants[name][i]) { variants[i] = 1; } } } this.variants[variantName] = variants; } } ================================================ FILE: src/viewer/handlers/mdx/attachment.ts ================================================ import MdlxAttachment from '../../../parsers/mdlx/attachment'; import GenericObject from './genericobject'; import MdxModel from './model'; /** * An MDX attachment. */ export default class Attachment extends GenericObject { path: string; attachmentId: number; internalModel: MdxModel | null = null; constructor(model: MdxModel, attachment: MdlxAttachment, index: number) { super(model, attachment, index); const path = attachment.path.replace(/\\/g, '/').toLowerCase().replace('.mdl', '.mdx'); this.path = path; this.attachmentId = attachment.attachmentId; // Second condition is against custom resources using arbitrary paths... if (path !== '' && path.indexOf('.mdx') != -1) { const promise = model.viewer.load(path, model.pathSolver, model.solverParams); promise.then((model) => { if (model) { this.internalModel = model; } }); model.blockers.push(promise); } } override getVisibility(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KATV', sequence, frame, counter, 1); } } ================================================ FILE: src/viewer/handlers/mdx/attachmentinstance.ts ================================================ import MdxModel from './model'; import MdxModelInstance from './modelinstance'; import Attachment from './attachment'; // Heap allocations needed for this module. const visibilityHeap = new Float32Array(1); /** * An attachment instance. */ export default class AttachmentInstance { instance: MdxModelInstance; attachment: Attachment; internalInstance: MdxModelInstance; constructor(instance: MdxModelInstance, attachment: Attachment) { const internalModel = attachment.internalModel; const internalInstance = internalModel.addInstance(); internalInstance.setSequenceLoopMode(2); internalInstance.dontInheritScaling = false; internalInstance.hide(); internalInstance.setParent(instance.nodes[attachment.objectId]); this.instance = instance; this.attachment = attachment; this.internalInstance = internalInstance; } update(): void { const instance = this.instance; const internalInstance = this.internalInstance; if (instance.scene && instance.sequence !== -1) { this.attachment.getVisibility(visibilityHeap, instance.sequence, instance.frame, instance.counter); if (visibilityHeap[0] > 0.1) { // The parent instance might not actually be in a scene. // This happens if loading a local model, where loading is instant and adding to a scene always comes afterwards. // Therefore, do it here dynamically. instance.scene.addInstance(internalInstance); if (internalInstance.hidden()) { internalInstance.show(); // Every time the attachment becomes visible again, restart its first sequence. internalInstance.setSequence(0); } } else { internalInstance.hide(); } } } } ================================================ FILE: src/viewer/handlers/mdx/batch.ts ================================================ import Geoset from './geoset'; import Layer from './layer'; import Material from './material'; /** * The type of skinning a batch uses. * * Vertex groups are used for SD batches with a range of 0-4 bones per vertex. * * Extended vertex groups are used for SD batches with a range of 0-8 bones per vertex. * * Skin is used for HD batches with a range of 0-4 bones per vertex. */ export enum SkinningType { VertexGroups, ExtendedVertexGroups, Skin, } /** * An MDX batch. */ export class Batch { index: number; geoset: Geoset; layer: Layer; material: Material | null; skinningType: SkinningType; isHd: boolean; constructor(index: number, geoset: Geoset, layerOrMaterial: Layer | Material, skinningType: SkinningType, isHd: boolean) { let material; let layer; if (isHd) { material = layerOrMaterial; layer = material.layers[0]; } else { material = null; layer = layerOrMaterial; } this.index = index; this.geoset = geoset; this.skinningType = skinningType; this.isHd = isHd; this.layer = layer; this.material = material; } } ================================================ FILE: src/viewer/handlers/mdx/batchgroup.ts ================================================ import Scene from '../../scene'; import Texture from '../../texture'; import MdxModel from './model'; import MdxModelInstance from './modelinstance'; import Material from './material'; import mdxHandler, { MdxHandlerObject } from './handler'; import { SkinningType } from './batch'; /** * A group of batches that are going to be rendered together. */ export default class BatchGroup { model: MdxModel; skinningType: SkinningType; isHd: boolean; objects: number[] = []; constructor(model: MdxModel, skinningType: SkinningType, isHd: boolean) { this.model = model; this.skinningType = skinningType; this.isHd = isHd; } render(instance: MdxModelInstance): void { const scene = instance.scene; const camera = scene.camera; const textureOverrides = instance.textureOverrides; const layerAlphas = instance.layerAlphas; const model = this.model; const textures = model.textures; const batches = model.batches; const viewer = model.viewer; const mdxCache = viewer.sharedCache.get('mdx'); const gl = viewer.gl; const webgl = viewer.webgl; const skinningType = this.skinningType; const isHd = this.isHd; const teamColors = mdxCache.teamColors; const teamGlows = mdxCache.teamGlows; const shader = mdxHandler.getBatchShader(viewer, skinningType, isHd); shader.use(); const uniforms = shader.uniforms; gl.uniformMatrix4fv(uniforms['u_VP'], false, camera.viewProjectionMatrix); const boneTexture = instance.boneTexture; // Instances of models with no bones don't have a bone texture. if (boneTexture) { boneTexture.bind(15); gl.uniform1f(uniforms['u_hasBones'], 1); gl.uniform1i(uniforms['u_boneMap'], 15); gl.uniform1f(uniforms['u_vectorSize'], 1 / boneTexture.width); gl.uniform1f(uniforms['u_rowSize'], 1); } else { gl.uniform1f(uniforms['u_hasBones'], 0); } gl.uniform3fv(uniforms['u_lightPos'], scene.lightPosition); gl.bindBuffer(gl.ARRAY_BUFFER, model.arrayBuffer); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.elementBuffer); if (isHd) { gl.uniform1i(uniforms['u_diffuseMap'], 0); gl.uniform1i(uniforms['u_normalsMap'], 1); gl.uniform1i(uniforms['u_ormMap'], 2); gl.uniform1i(uniforms['u_emissiveMap'], 3); gl.uniform1i(uniforms['u_teamColorMap'], 4); gl.uniform1i(uniforms['u_environmentMap'], 5); // gl.uniform1i(uniforms['u_lutMap'], 6); // gl.uniform1i(uniforms['u_envDiffuseMap'], 7); // gl.uniform1i(uniforms['u_envSpecularMap'], 8); gl.disable(gl.BLEND); gl.enable(gl.DEPTH_TEST); gl.depthMask(true); gl.uniformMatrix4fv(uniforms['u_MV'], false, camera.viewMatrix); gl.uniform3fv(uniforms['u_eyePos'], camera.location); for (const index of this.objects) { const batch = batches[index]; const geoset = batch.geoset; const material = batch.material; const [diffuseLayer, normalsLayer, ormLayer, emissiveLayer, teamColorLayer, environmentMapLayer] = material.layers; const layerAlpha = layerAlphas[diffuseLayer.index]; if (layerAlpha > 0) { gl.uniform1f(uniforms['u_layerAlpha'], layerAlpha); gl.uniform1f(uniforms['u_filterMode'], diffuseLayer.filterMode); const diffuseId = diffuseLayer.textureId; const normalsId = normalsLayer.textureId; const ormId = ormLayer.textureId; const emissiveId = emissiveLayer.textureId; const teamColorId = teamColorLayer.textureId; const environmentMapId = environmentMapLayer.textureId; const diffuseTexture = textures[diffuseId]; const normalsTexture = textures[normalsId]; const ormTexture = textures[ormId]; const emissiveTexture = textures[emissiveId]; let teamColorTexture = textures[teamColorId]; const environmentMapTexture = textures[environmentMapId]; if (teamColorTexture.replaceableId === 0 || teamColorTexture.replaceableId === 1) { teamColorTexture = teamColors[instance.teamColor]; } const actualDiffuseTexture = textureOverrides.get(diffuseId) || diffuseTexture.texture; const actualNormalsTexture = textureOverrides.get(normalsId) || normalsTexture.texture; const actualOrmTexture = textureOverrides.get(ormId) || ormTexture.texture; const actualEmissiveTexture = textureOverrides.get(emissiveId) || emissiveTexture.texture; const actualTeamColorTexture = textureOverrides.get(teamColorId) || teamColorTexture.texture; const actualEnvironmentMapTexture = textureOverrides.get(environmentMapId) || environmentMapTexture.texture; webgl.bindTextureAndWrap(actualDiffuseTexture, 0, diffuseTexture.wrapS, diffuseTexture.wrapT); webgl.bindTextureAndWrap(actualNormalsTexture, 1, normalsTexture.wrapS, normalsTexture.wrapT); webgl.bindTextureAndWrap(actualOrmTexture, 2, ormTexture.wrapS, ormTexture.wrapT); webgl.bindTextureAndWrap(actualEmissiveTexture, 3, emissiveTexture.wrapS, emissiveTexture.wrapT); webgl.bindTextureAndWrap(actualTeamColorTexture, 4, teamColorTexture.wrapS, teamColorTexture.wrapT); webgl.bindTextureAndWrap(actualEnvironmentMapTexture, 5, environmentMapTexture.wrapS, environmentMapTexture.wrapT); // const { lutTexture, envDiffuseTexture, envSpecularTexture }= mdxCache; // if (lutTexture && envDiffuseTexture && envSpecularTexture) { // webgl.bindTextureAndWrap(lutTexture.texture, 6, lutTexture.wrapS, lutTexture.wrapT); // webgl.bindTextureAndWrap(envDiffuseTexture.texture, 7, envDiffuseTexture.wrapS, envDiffuseTexture.wrapT); // webgl.bindTextureAndWrap(envSpecularTexture.texture, 8, envSpecularTexture.wrapS, envSpecularTexture.wrapT); // } geoset.bindHd(shader, batch.skinningType, diffuseLayer.coordId); geoset.render(); } } } else { const geosetColors = instance.geosetColors; const layerTextures = instance.layerTextures; const uvAnims = instance.uvAnims; gl.uniform4fv(uniforms['u_vertexColor'], instance.vertexColor); gl.uniform1i(uniforms['u_texture'], 0); for (const object of this.objects) { const batch = batches[object]; const geoset = batch.geoset; const layer = batch.layer; const geosetIndex = geoset.index; const layerIndex = layer.index; const geosetColor = geosetColors[geosetIndex]; const layerAlpha = layerAlphas[layerIndex]; if (geosetColor[3] > 0.01 && layerAlpha > 0.01) { const textureIndex = layerTextures[layerIndex]; const layerTexture = textures[textureIndex]; const uvAnim = uvAnims[layerIndex]; gl.uniform4fv(uniforms['u_geosetColor'], geosetColor); gl.uniform1f(uniforms['u_layerAlpha'], layerAlpha); gl.uniform1f(uniforms['u_unshaded'], layer.unshaded); gl.uniform2f(uniforms['u_uvTrans'], uvAnim[0], uvAnim[1]); gl.uniform2f(uniforms['u_uvRot'], uvAnim[2], uvAnim[3]); gl.uniform1f(uniforms['u_uvScale'], uvAnim[4]); layer.bind(shader); let texture: Texture | null | undefined = textureOverrides.get(textureIndex); if (!texture) { const replaceable = layerTexture.replaceableId; let mdxTexture; if (replaceable === 1) { mdxTexture = teamColors[instance.teamColor]; } else if (replaceable === 2) { mdxTexture = teamGlows[instance.teamColor]; } else { mdxTexture = layerTexture; } if (mdxTexture) { texture = mdxTexture.texture; } } webgl.bindTextureAndWrap(texture, 0, layerTexture.wrapS, layerTexture.wrapT); if (skinningType === SkinningType.ExtendedVertexGroups) { geoset.bindExtended(shader, layer.coordId); } else { geoset.bind(shader, layer.coordId); } geoset.render(); } } } } } ================================================ FILE: src/viewer/handlers/mdx/bone.ts ================================================ import MdlxBone from '../../../parsers/mdlx/bone'; import MdxModel from './model'; import GenericObject from './genericobject'; import GeosetAnimation from './geosetanimation'; /** * An MDX bone. */ export default class Bone extends GenericObject { geosetAnimation: GeosetAnimation; constructor(model: MdxModel, bone: MdlxBone, index: number) { super(model, bone, index); this.geosetAnimation = model.geosetAnimations[bone.geosetAnimationId]; } override getVisibility(out: Float32Array, sequence: number, frame: number, counter: number): number { if (this.geosetAnimation) { return this.geosetAnimation.getAlpha(out, sequence, frame, counter); } out[0] = 1; return -1; } } ================================================ FILE: src/viewer/handlers/mdx/camera.ts ================================================ import { VEC3_ZERO } from '../../../common/gl-matrix-addon'; import MdlxCamera from '../../../parsers/mdlx/camera'; import AnimatedObject from './animatedobject'; import MdxModel from './model'; /** * An MDX camera. */ export default class Camera extends AnimatedObject { name: string; position: Float32Array; fieldOfView: number; farClippingPlane: number; nearClippingPlane: number; targetPosition: Float32Array; constructor(model: MdxModel, camera: MdlxCamera) { super(model, camera); this.name = camera.name; this.position = camera.position; this.fieldOfView = camera.fieldOfView; this.farClippingPlane = camera.farClippingPlane; this.nearClippingPlane = camera.nearClippingPlane; this.targetPosition = camera.targetPosition; } getTranslation(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KCTR', sequence, frame, counter, VEC3_ZERO); } getTargetTranslation(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KTTR', sequence, frame, counter, VEC3_ZERO); } getRotation(out: Uint32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KCRL', sequence, frame, counter, 0); } } ================================================ FILE: src/viewer/handlers/mdx/collisionshape.ts ================================================ import MdlxCollisionShape, { Shape } from '../../../parsers/mdlx/collisionshape'; import GenericObject from './genericobject'; import MdxModel from './model'; /** * A collision shape. */ export default class CollisionShape extends GenericObject { type: Shape; vertices: Float32Array[]; boundsRadius: number; constructor(model: MdxModel, collisionShape: MdlxCollisionShape, index: number) { super(model, collisionShape, index); this.type = collisionShape.type; this.vertices = collisionShape.vertices; this.boundsRadius = collisionShape.boundsRadius; } } ================================================ FILE: src/viewer/handlers/mdx/emitter.ts ================================================ import Emitter from '../../emitter'; import ParticleEmitterObject from './particleemitterobject'; import ParticleEmitter2Object from './particleemitter2object'; import RibbonEmitterObject from './ribbonemitterobject'; import EventObjectEmitterObject from './eventobjectemitterobject'; import MdxModelInstance from './modelinstance'; /** * The base of all MDX emitters. */ export default abstract class MdxEmitter extends Emitter { emitterObject: ParticleEmitterObject | ParticleEmitter2Object | RibbonEmitterObject | EventObjectEmitterObject; constructor(instance: MdxModelInstance, emitterObject: ParticleEmitterObject | ParticleEmitter2Object | RibbonEmitterObject | EventObjectEmitterObject) { super(instance); this.emitterObject = emitterObject; } override update(dt: number): void { if (this.emitterObject.ok) { super.update(dt); } } } ================================================ FILE: src/viewer/handlers/mdx/emittergroup.ts ================================================ import Scene from '../../scene'; import MdxModel from './model'; import MdxModelInstance from './modelinstance'; import { GeometryEmitter, renderEmitter } from './geometryemitterfuncs'; import { MdxHandlerObject } from './handler'; /** * A group of emitters that are going to be rendered together. */ export default class EmitterGroup { model: MdxModel; objects: number[] = []; constructor(model: MdxModel) { this.model = model; } render(instance: MdxModelInstance): void { const scene = instance.scene; const nodes = instance.nodes; const model = instance.model; const viewer = model.viewer; const gl = viewer.gl; const instancedArrays = viewer.webgl.extensions['ANGLE_instanced_arrays']; const mdxCache = viewer.sharedCache.get('mdx'); const shader = mdxCache.particlesShader; const uniforms = shader.uniforms; const attribs = shader.attribs; const rectBuffer = mdxCache.rectBuffer; gl.depthMask(false); gl.enable(gl.BLEND); gl.disable(gl.CULL_FACE); gl.enable(gl.DEPTH_TEST); shader.use(); gl.uniformMatrix4fv(uniforms['u_VP'], false, scene.camera.viewProjectionMatrix); gl.uniform1i(uniforms['u_texture'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_position'], 0); gl.bindBuffer(gl.ARRAY_BUFFER, rectBuffer); gl.vertexAttribPointer(attribs['a_position'], 1, gl.UNSIGNED_BYTE, false, 0, 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p0'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p1'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p2'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p3'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_health'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_color'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_tail'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_leftRightTop'], 1); for (const index of this.objects) { renderEmitter(nodes[index].object, shader); } instancedArrays.vertexAttribDivisorANGLE(attribs['a_leftRightTop'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_tail'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_color'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_health'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p3'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p2'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p1'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_p0'], 0); } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectemitter.ts ================================================ import MdxModelInstance from './modelinstance'; import MdxEmitter from './emitter'; import EventObjectEmitterObject from './eventobjectemitterobject'; const valueHeap = new Uint32Array(1); /** * The abstract base MDX event object emitter. */ export default abstract class EventObjectEmitter extends MdxEmitter { lastValue = 0; updateEmission(_dt: number): void { const instance = this.instance; if (instance.allowParticleSpawn) { const emitterObject = this.emitterObject; emitterObject.getValue(valueHeap, instance); const value = valueHeap[0]; if (value === 1 && value !== this.lastValue) { this.currentEmission += 1; } this.lastValue = value; } } emit(): void { this.emitObject(); } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectemitterobject.ts ================================================ import EventObject from '../../../parsers/mdlx/eventobject'; import Texture from '../../texture'; import GenericResource from '../../genericresource'; import mdxHandler from './handler'; import MdxModel from './model'; import GenericObject from './genericobject'; import { emitterFilterMode } from './filtermode'; import { EMITTER_SPLAT, EMITTER_UBERSPLAT } from './geometryemitterfuncs'; import MdxModelInstance from './modelinstance'; import MdxTexture from './texture'; import { WrapMode } from '../../../parsers/mdlx/texture'; /** * An event object. */ export default class EventObjectEmitterObject extends GenericObject { geometryEmitterType = -1; type: string; id: string; tracks: Uint32Array; globalSequence = -1; defval = new Uint32Array(1); internalModel: MdxModel | null = null; internalTexture: MdxTexture | null = null; colors: Float32Array[] = []; intervalTimes = new Float32Array(3); scale = 0; columns = 0; rows = 0; lifeSpan = 0; blendSrc = 0; blendDst = 0; intervals: Float32Array[] = []; distanceCutoff = 0; maxDistance = 0; minDistance = 0; pitch = 0; pitchVariance = 0; volume = 0; decodedBuffers: AudioBuffer[] = []; ok = false; constructor(model: MdxModel, eventObject: EventObject, index: number) { super(model, eventObject, index); const viewer = model.viewer; const name = eventObject.name; let type = name.substring(0, 3); const id = name.substring(4); // Same thing if (type === 'FPT') { type = 'SPL'; } if (type === 'SPL') { this.geometryEmitterType = EMITTER_SPLAT; } else if (type === 'UBR') { this.geometryEmitterType = EMITTER_UBERSPLAT; } this.type = type; this.id = id; this.tracks = eventObject.tracks; const globalSequenceId = eventObject.globalSequenceId; if (globalSequenceId !== -1) { this.globalSequence = model.globalSequences[globalSequenceId]; } // If this is a sound event object, and the viewer doesn't have audio enabled, don't do anything. // This saves bandwidth when audio is not desired. if (type === 'SND' && !viewer.audioEnabled) { return; } // It's not possible to know ahead of time what file(s) event objects would need. // This is because the SLKs are lazily loaded, and might not exist at this point. // Therefore make a promise, and resolve it after all of the files loaded. const resolve = viewer.promise(); mdxHandler.getEventObjectData(viewer, type, id, model.hd) .then((data) => { // Now the promise can be resolved to allow the viewer to handle events correctly. resolve(); if (data) { const { row, resources } = data; this.ok = true; if (type === 'SPN') { this.internalModel = resources[0]; } else if (type === 'SPL' || type === 'UBR') { this.internalTexture = new MdxTexture(0, WrapMode.WrapBoth); this.internalTexture.texture = resources[0]; this.scale = row.number('Scale'); this.colors[0] = new Float32Array([row.number('StartR'), row.number('StartG'), row.number('StartB'), row.number('StartA')]); this.colors[1] = new Float32Array([row.number('MiddleR'), row.number('MiddleG'), row.number('MiddleB'), row.number('MiddleA')]); this.colors[2] = new Float32Array([row.number('EndR'), row.number('EndG'), row.number('EndB'), row.number('EndA')]); if (type === 'SPL') { this.columns = row.number('Columns'); this.rows = row.number('Rows'); this.lifeSpan = row.number('Lifespan') + row.number('Decay'); this.intervalTimes[0] = row.number('Lifespan'); this.intervalTimes[1] = row.number('Decay'); this.intervals[0] = new Float32Array([row.number('UVLifespanStart'), row.number('UVLifespanEnd'), row.number('LifespanRepeat')]); this.intervals[1] = new Float32Array([row.number('UVDecayStart'), row.number('UVDecayEnd'), row.number('DecayRepeat')]); } else { this.columns = 1; this.rows = 1; this.lifeSpan = row.number('BirthTime') + row.number('PauseTime') + row.number('Decay'); this.intervalTimes[0] = row.number('BirthTime'); this.intervalTimes[1] = row.number('PauseTime'); this.intervalTimes[2] = row.number('Decay'); } const blendModes = emitterFilterMode(row.number('BlendMode'), viewer.gl); this.blendSrc = blendModes[0]; this.blendDst = blendModes[1]; } else { this.distanceCutoff = row.number('DistanceCutoff'); this.maxDistance = row.number('MaxDistance'); this.minDistance = row.number('MinDistance'); this.pitch = row.number('Pitch'); this.pitchVariance = row.number('PitchVariance'); this.volume = row.number('Volume'); for (const resource of resources) { this.decodedBuffers.push((resource).data); } } } }); } getValue(out: Uint32Array, instance: MdxModelInstance): number { if (this.globalSequence !== -1) { const globalSequence = this.globalSequence; return this.getValueAtTime(out, instance.counter % globalSequence, 0, globalSequence); } else if (instance.sequence !== -1) { const interval = this.model.sequences[instance.sequence].interval; return this.getValueAtTime(out, instance.frame, interval[0], interval[1]); } else { out[0] = this.defval[0]; return -1; } } getValueAtTime(out: Uint32Array, frame: number, start: number, end: number): number { const tracks = this.tracks; if (frame >= start && frame <= end) { for (let i = tracks.length - 1; i > -1; i--) { if (tracks[i] < start) { out[0] = 0; return i; } else if (tracks[i] <= frame) { out[0] = 1; return i; } } } out[0] = 0; return -1; } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectsnd.ts ================================================ import Scene from '../../scene'; import EmittedObject from '../../emittedobject'; import EventObjectEmitterObject from './eventobjectemitterobject'; import MdxModelInstance from './modelinstance'; import EventObjectSndEmitter from './eventobjectsndemitter'; /** * An MDX spawned sound object. */ export default class EventObjectSnd extends EmittedObject { bind(): void { const emitter = this.emitter; const instance = emitter.instance; const viewer = instance.model.viewer; const scene = instance.scene; // Is audio enabled both viewer-wide and in this scene? if (viewer.audioEnabled && scene.audioEnabled) { const emitterObject = emitter.emitterObject; const node = instance.nodes[emitterObject.index]; const audioContext = scene.audioContext; const decodedBuffers = emitterObject.decodedBuffers; const panner = audioContext.createPanner(); const source = audioContext.createBufferSource(); const location = node.worldLocation; // Panner settings. panner.positionX.value = location[0]; panner.positionY.value = location[1]; panner.positionZ.value = location[2]; panner.maxDistance = emitterObject.distanceCutoff; panner.refDistance = emitterObject.minDistance; panner.connect(audioContext.destination); // Source. source.buffer = decodedBuffers[(Math.random() * decodedBuffers.length) | 0]; source.connect(panner); // Make a sound. source.start(0); } } update(_dt: number): void { } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectsndemitter.ts ================================================ import EventObjectEmitter from './eventobjectemitter'; import EventObjectSnd from './eventobjectsnd'; /** * An MDX sound emitter. */ export default class EventObjectSndEmitter extends EventObjectEmitter { createObject(): EventObjectSnd { return new EventObjectSnd(this); } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectsplemitter.ts ================================================ import EventObjectEmitter from './eventobjectemitter'; import EventObjectSplUbr from './eventobjectsplubr'; /** * An MDX splat emitter. */ export default class EventObjectSplEmitter extends EventObjectEmitter { createObject(): EventObjectSplUbr { return new EventObjectSplUbr(this); } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectsplubr.ts ================================================ import { vec3 } from 'gl-matrix'; import EmittedObject from '../../emittedobject'; import EventObjectEmitterObject from './eventobjectemitterobject'; import MdxModelInstance from './modelinstance'; import EventObjectSplEmitter from './eventobjectsplemitter'; import EventObjectUbrEmitter from './eventobjectubremitter'; const vertexHeap = vec3.create(); /** * An MDX splat or ubersplat object. */ export default class EventObjectSplUbr extends EmittedObject { vertices = new Float32Array(12); bind(): void { const emitter = this.emitter; const instance = emitter.instance; const emitterObject = emitter.emitterObject; const vertices = this.vertices; const scale = emitterObject.scale; const { worldLocation, worldRotation } = instance.nodes[emitterObject.index]; this.health = emitterObject.lifeSpan; vec3.set(vertexHeap, scale, scale, 0); vec3.transformQuat(vertexHeap, vertexHeap, worldRotation); vec3.add(vertices.subarray(0, 2), vertexHeap, worldLocation); vec3.set(vertexHeap, -scale, scale, 0); vec3.transformQuat(vertexHeap, vertexHeap, worldRotation); vec3.add(vertices.subarray(3, 5), vertexHeap, worldLocation); vec3.set(vertexHeap, -scale, -scale, 0); vec3.transformQuat(vertexHeap, vertexHeap, worldRotation); vec3.add(vertices.subarray(6, 8), vertexHeap, worldLocation); vec3.set(vertexHeap, scale, -scale, 0); vec3.transformQuat(vertexHeap, vertexHeap, worldRotation); vec3.add(vertices.subarray(9, 11), vertexHeap, worldLocation); } update(dt: number): void { this.health -= dt; } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectspn.ts ================================================ import Scene from '../../scene'; import EmittedObject from '../../emittedobject'; import MdxModel from './model'; import EventObjectEmitterObject from './eventobjectemitterobject'; import MdxModelInstance from './modelinstance'; import EventObjectSpnEmitter from './eventobjectspnemitter'; /** * An MDX spawned model object. */ export default class EventObjectSpn extends EmittedObject { internalInstance: MdxModelInstance; constructor(emitter: EventObjectSpnEmitter) { super(emitter); const emitterObject = emitter.emitterObject; const internalModel = emitterObject.internalModel; this.internalInstance = internalModel.addInstance(); } bind(): void { const emitter = this.emitter; const instance = emitter.instance; const scene = instance.scene; const node = instance.nodes[emitter.emitterObject.index]; const internalInstance = this.internalInstance; internalInstance.setScene(scene); internalInstance.setSequence(0); internalInstance.setTransformation(node.worldLocation, node.worldRotation, node.worldScale); internalInstance.show(); this.health = 1; } update(_dt: number): void{ const instance = this.internalInstance; const model = instance.model; // Once the sequence finishes, this event object dies if (instance.frame >= model.sequences[0].interval[1]) { this.health = 0; instance.hide(); } } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectspnemitter.ts ================================================ import EventObjectEmitter from './eventobjectemitter'; import EventObjectSpn from './eventobjectspn'; /** * An MDX model emitter. */ export default class EventObjectSpnEmitter extends EventObjectEmitter { createObject(): EventObjectSpn { return new EventObjectSpn(this); } } ================================================ FILE: src/viewer/handlers/mdx/eventobjectubremitter.ts ================================================ import EventObjectEmitter from './eventobjectemitter'; import EventObjectSplUbr from './eventobjectsplubr'; /** * An MDX ubersplat emitter. */ export default class EventObjectUbrEmitter extends EventObjectEmitter { createObject(): EventObjectSplUbr { return new EventObjectSplUbr(this); } } ================================================ FILE: src/viewer/handlers/mdx/filtermode.ts ================================================ import { FilterMode as LayerFilterMode } from '../../../parsers/mdlx/layer'; import { FilterMode as Particle2FilterMode } from '../../../parsers/mdlx/particleemitter2'; export function layerFilterMode(filterMode: LayerFilterMode, gl: WebGLRenderingContext): number[] { if (filterMode === LayerFilterMode.Blend) { return [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]; } else if (filterMode === LayerFilterMode.Additive) { return [gl.SRC_ALPHA, gl.ONE]; } else if (filterMode === LayerFilterMode.AddAlpha) { return [gl.SRC_ALPHA, gl.ONE]; } else if (filterMode === LayerFilterMode.Modulate) { return [gl.ZERO, gl.SRC_COLOR]; } else if (filterMode === LayerFilterMode.Modulate2x) { return [gl.DST_COLOR, gl.SRC_COLOR]; } else { return [0, 0]; } } export function emitterFilterMode(filterMode: Particle2FilterMode, gl: WebGLRenderingContext): number[] { if (filterMode === Particle2FilterMode.Blend) { return [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]; } else if (filterMode === Particle2FilterMode.Additive) { return [gl.SRC_ALPHA, gl.ONE]; } else if (filterMode === Particle2FilterMode.Modulate) { return [gl.ZERO, gl.SRC_COLOR]; } else if (filterMode === Particle2FilterMode.Modulate2x) { return [gl.DST_COLOR, gl.SRC_COLOR]; } else if (filterMode === Particle2FilterMode.AlphaKey) { return [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]; } else { return [0, 0]; } } ================================================ FILE: src/viewer/handlers/mdx/genericobject.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { VEC3_ZERO, VEC3_ONE, QUAT_DEFAULT } from '../../../common/gl-matrix-addon'; import MdlxGenericObject, { Flags } from '../../../parsers/mdlx/genericobject'; import AnimatedObject from './animatedobject'; import MdxModel from './model'; /** * An MDX generic object. */ export default class GenericObject extends AnimatedObject { index: number; name: string; objectId: number; parentId: number; pivot: vec3; dontInheritTranslation: boolean; dontInheritRotation: boolean; dontInheritScaling: boolean; billboarded: boolean; billboardedX: boolean; billboardedY: boolean; billboardedZ: boolean; cameraAnchored: boolean; anyBillboarding: boolean; constructor(model: MdxModel, object: MdlxGenericObject, index: number) { super(model, object); this.index = index; this.name = object.name; this.objectId = object.objectId; this.parentId = object.parentId; this.pivot = model.pivotPoints[object.objectId] || vec3.create(); const flags = object.flags; this.dontInheritTranslation = (flags & Flags.DontInheritTranslation) > 0; this.dontInheritRotation = (flags & Flags.DontInheritRotation) > 0; this.dontInheritScaling = (flags & Flags.DontInheritScaling) > 0; this.billboarded = (flags & Flags.Billboarded) > 0; this.billboardedX = (flags & Flags.BillboardedLockX) > 0; this.billboardedY = (flags & Flags.BillboardedLockY) > 0; this.billboardedZ = (flags & Flags.BillboardedLockZ) > 0; this.cameraAnchored = (flags & Flags.CameraAnchored) > 0; this.anyBillboarding = this.billboarded || this.billboardedX || this.billboardedY || this.billboardedZ; if (object.objectId === object.parentId) { this.parentId = -1; } this.addVariants('KGTR', 'translation'); this.addVariants('KGRT', 'rotation'); this.addVariants('KGSC', 'scale'); this.addVariantIntersection(['translation', 'rotation', 'scale'], 'generic'); } /** * Give a consistent visibility getter for all generic objects. * * Many of the generic objects have animated visibilities, and will override this. */ getVisibility(out: Float32Array, _sequence: number, _frame: number, _counter: number): number { out[0] = 1; return -1; } getTranslation(out: vec3, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KGTR', sequence, frame, counter, VEC3_ZERO); } getRotation(out: quat, sequence: number, frame: number, counter: number): number { return this.getQuatValue(out, 'KGRT', sequence, frame, counter, QUAT_DEFAULT); } getScale(out: vec3, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KGSC', sequence, frame, counter, VEC3_ONE); } } ================================================ FILE: src/viewer/handlers/mdx/geometryemitterfuncs.ts ================================================ import { vec3 } from 'gl-matrix'; import Scene from '../../scene'; import Shader from '../../gl/shader'; import ClientBuffer from '../../gl/clientbuffer'; import Texture from '../../texture'; import ParticleEmitter2Object from './particleemitter2object'; import RibbonEmitterObject from './ribbonemitterobject'; import EventObjectEmitterObject from './eventobjectemitterobject'; import MdxModelInstance from './modelinstance'; import ParticleEmitter2 from './particleemitter2'; import RibbonEmitter from './ribbonemitter'; import EventObjectSplEmitter from './eventobjectsplemitter'; import EventObjectUbrEmitter from './eventobjectubremitter'; import Particle2 from './particle2'; import Ribbon from './ribbon'; import EventObjectSplUbr from './eventobjectsplubr'; import MdxTexture from './texture'; import { HeadOrTail } from '../../../parsers/mdlx/particleemitter2'; import { MdxHandlerObject } from './handler'; const locationHeap = vec3.create(); const startHeap = vec3.create(); const endHeap = vec3.create(); // The total storage that emitted objects can use. // This is enough to support all of the MDX geometry emitters. // The memory layout is the same as this C struct: // // struct { // float p0[3] // float p1[3] // float p2[3] // float p3[3] // float health // byte color[4] // byte tail // byte leftRightTop[3] // } // export const BYTES_PER_OBJECT = 60; export const FLOATS_PER_OBJECT = BYTES_PER_OBJECT >> 2; // Offsets into the emitted object structure. export const BYTE_OFFSET_P0 = 0; export const BYTE_OFFSET_P1 = 12; export const BYTE_OFFSET_P2 = 24; export const BYTE_OFFSET_P3 = 36; export const BYTE_OFFSET_HEALTH = 48; export const BYTE_OFFSET_COLOR = 52; export const BYTE_OFFSET_TAIL = 56; export const BYTE_OFFSET_LEFT_RIGHT_TOP = 57; // Offset aliases. export const FLOAT_OFFSET_P0 = BYTE_OFFSET_P0 >> 2; export const FLOAT_OFFSET_P1 = BYTE_OFFSET_P1 >> 2; export const FLOAT_OFFSET_P2 = BYTE_OFFSET_P2 >> 2; export const FLOAT_OFFSET_P3 = BYTE_OFFSET_P3 >> 2; export const FLOAT_OFFSET_HEALTH = BYTE_OFFSET_HEALTH >> 2; export const BYTE_OFFSET_TEAM_COLOR = BYTE_OFFSET_LEFT_RIGHT_TOP; // Emitter types export const EMITTER_PARTICLE2 = 0; export const EMITTER_RIBBON = 1; export const EMITTER_SPLAT = 2; export const EMITTER_UBERSPLAT = 3; // Offsets for overriding emitter textures using setResource(). export const EMITTER_PARTICLE2_TEXTURE_OFFSET = 1000; export const EMITTER_EVENT_TEXTURE_OFFSET = 10000; // The game scales the emission rate of particle emitters depending on the particles setting. // High seems to double the emission. export const SETTING_PARTICLES_HIGH = 2; export type GeometryEmitter = ParticleEmitter2 | RibbonEmitter | EventObjectSplEmitter | EventObjectUbrEmitter; export type GeometryEmitterObject = ParticleEmitter2Object | RibbonEmitterObject | EventObjectEmitterObject; function bindParticleEmitter2Buffer(emitter: ParticleEmitter2, buffer: ClientBuffer): void { const instance = emitter.instance; const objects = emitter.objects; const byteView = buffer.byteView; const floatView = buffer.floatView; const emitterObject = emitter.emitterObject; const modelSpace = emitterObject.modelSpace; const tailLength = emitterObject.tailLength; const node = emitter.node; const teamColor = instance.teamColor; let offset = 0; for (const object of objects) { const byteOffset = offset * BYTES_PER_OBJECT; const floatOffset = offset * FLOATS_PER_OBJECT; const p0Offset = floatOffset + FLOAT_OFFSET_P0; let location = object.location; const scale = object.scale; const tail = object.tail; if (tail === HeadOrTail.Head) { // If this is a model space emitter, the location is in local space, so convert it to world space. if (modelSpace) { location = vec3.transformMat4(locationHeap, location, node.worldMatrix); } floatView[p0Offset + 0] = location[0]; floatView[p0Offset + 1] = location[1]; floatView[p0Offset + 2] = location[2]; // Used to rotate XY particles to face their velocity on the XY plane. floatView[p0Offset + 3] = object.facing; } else { const velocity = object.velocity; let start = startHeap; let end = location; start[0] = end[0] - tailLength * velocity[0]; start[1] = end[1] - tailLength * velocity[1]; start[2] = end[2] - tailLength * velocity[2]; // If this is a model space emitter, the start and end are in local space, so convert them to world space. if (modelSpace) { start = vec3.transformMat4(start, start, node.worldMatrix); end = vec3.transformMat4(endHeap, end, node.worldMatrix); } floatView[p0Offset + 0] = start[0]; floatView[p0Offset + 1] = start[1]; floatView[p0Offset + 2] = start[2]; floatView[p0Offset + 3] = end[0]; floatView[p0Offset + 4] = end[1]; floatView[p0Offset + 5] = end[2]; } floatView[p0Offset + 6] = scale[0]; floatView[p0Offset + 7] = scale[0]; floatView[p0Offset + 8] = scale[0]; floatView[floatOffset + FLOAT_OFFSET_HEALTH] = object.health; byteView[byteOffset + BYTE_OFFSET_TAIL] = tail; byteView[byteOffset + BYTE_OFFSET_TEAM_COLOR] = teamColor; offset += 1; } } function bindParticleEmitter2Shader(emitter: ParticleEmitter2, shader: Shader): void { const instance = emitter.instance; const textureOverrides = instance.textureOverrides; const scene = instance.scene; const camera = scene.camera; const emitterObject = emitter.emitterObject; const model = emitterObject.model; const viewer = model.viewer; const gl = viewer.gl; const mdxCache = viewer.sharedCache.get('mdx'); const uniforms = shader.uniforms; const colors = emitterObject.colors; const intervals = emitterObject.intervals; const replaceable = emitterObject.replaceableId; let vectors; let mdxTexture = emitterObject.internalTexture; gl.blendFunc(emitterObject.blendSrc, emitterObject.blendDst); gl.uniform1f(uniforms['u_filterMode'], emitterObject.filterMode); // Determine where this texture is coming from. // This is to get the texture wrap modes. // The texture is either a replaceable in which case it's stored internally, a team color in which case it's stored in the handler, or a reference to one of the model textures. if (emitterObject.internalTexture) { mdxTexture = emitterObject.internalTexture; } else if (replaceable === 1) { mdxTexture = mdxCache.teamColors[instance.teamColor]; } else if (replaceable === 2) { mdxTexture = mdxCache.teamGlows[instance.teamColor]; } else { mdxTexture = model.textures[emitterObject.textureId]; } // Now get the actual texture itself. // First check if there is an override for this particle emitter. let texture: Texture | null | undefined = textureOverrides.get(EMITTER_PARTICLE2_TEXTURE_OFFSET + emitterObject.index); if (!texture) { // Next check if there is an override for model textures if this is one. if (replaceable === 0) { texture = textureOverrides.get(emitterObject.textureId); } // If there is still no override, get it from the existing texture object. if (!texture) { texture = mdxTexture.texture; } } viewer.webgl.bindTextureAndWrap(texture, 0, mdxTexture.wrapS, mdxTexture.wrapT); // Choose between a default rectangle or a billboarded one if (emitterObject.xYQuad) { vectors = camera.vectors; } else { vectors = camera.billboardedVectors; } gl.uniform1f(uniforms['u_lifeSpan'], emitterObject.lifeSpan); gl.uniform1f(uniforms['u_timeMiddle'], emitterObject.timeMiddle); gl.uniform1f(uniforms['u_columns'], emitterObject.columns); gl.uniform1f(uniforms['u_rows'], emitterObject.rows); gl.uniform1f(uniforms['u_teamColored'], emitterObject.teamColored); gl.uniform3fv(uniforms['u_intervals[0]'], intervals[0]); gl.uniform3fv(uniforms['u_intervals[1]'], intervals[1]); gl.uniform3fv(uniforms['u_intervals[2]'], intervals[2]); gl.uniform3fv(uniforms['u_intervals[3]'], intervals[3]); gl.uniform4fv(uniforms['u_colors[0]'], colors[0]); gl.uniform4fv(uniforms['u_colors[1]'], colors[1]); gl.uniform4fv(uniforms['u_colors[2]'], colors[2]); gl.uniform3fv(uniforms['u_scaling'], emitterObject.scaling); if (emitterObject.head) { gl.uniform3fv(uniforms['u_vertices[0]'], vectors[0]); gl.uniform3fv(uniforms['u_vertices[1]'], vectors[1]); gl.uniform3fv(uniforms['u_vertices[2]'], vectors[2]); gl.uniform3fv(uniforms['u_vertices[3]'], vectors[3]); } if (emitterObject.tail) { gl.uniform3fv(uniforms['u_cameraZ'], camera.directionZ); } } function bindRibbonEmitterBuffer(emitter: RibbonEmitter, buffer: ClientBuffer): void { let object = emitter.first; const byteView = buffer.byteView; const floatView = buffer.floatView; const emitterObject = emitter.emitterObject; const columns = emitterObject.columns; const alive = emitter.alive; const chainLengthFactor = 1 / (alive - 1); let offset = 0; while (object.next) { const next = object.next.vertices; const byteOffset = offset * BYTES_PER_OBJECT; const floatOffset = offset * FLOATS_PER_OBJECT; const p0Offset = floatOffset + FLOAT_OFFSET_P0; const colorOffset = byteOffset + BYTE_OFFSET_COLOR; const leftRightTopOffset = byteOffset + BYTE_OFFSET_LEFT_RIGHT_TOP; const left = ((object.slot % columns) + (1 - (offset * chainLengthFactor) - chainLengthFactor)) / columns; const top = object.slot / columns; const right = left + chainLengthFactor; const vertices = object.vertices; const color = object.color; floatView[p0Offset + 0] = vertices[0]; floatView[p0Offset + 1] = vertices[1]; floatView[p0Offset + 2] = vertices[2]; floatView[p0Offset + 3] = vertices[3]; floatView[p0Offset + 4] = vertices[4]; floatView[p0Offset + 5] = vertices[5]; floatView[p0Offset + 6] = next[3]; floatView[p0Offset + 7] = next[4]; floatView[p0Offset + 8] = next[5]; floatView[p0Offset + 9] = next[0]; floatView[p0Offset + 10] = next[1]; floatView[p0Offset + 11] = next[2]; byteView[colorOffset + 0] = color[0]; byteView[colorOffset + 1] = color[1]; byteView[colorOffset + 2] = color[2]; byteView[colorOffset + 3] = color[3]; byteView[leftRightTopOffset + 0] = left * 255; byteView[leftRightTopOffset + 1] = right * 255; byteView[leftRightTopOffset + 2] = top * 255; object = object.next; offset += 1; } } function bindRibbonEmitterShader(emitter: RibbonEmitter, shader: Shader): void { const textureOverrides = emitter.instance.textureOverrides; const emitterObject = emitter.emitterObject; const layer = emitterObject.layer; const model = emitterObject.model; const gl = model.viewer.gl; const uniforms = shader.uniforms; const texture = model.textures[layer.textureId]; const actualTexture = textureOverrides.get(layer.textureId) || texture.texture; layer.bind(shader); gl.uniform1f(uniforms['u_filterMode'], layer.filterMode); model.viewer.webgl.bindTextureAndWrap(actualTexture, 0, texture.wrapS, texture.wrapT); gl.uniform1f(uniforms['u_columns'], emitterObject.columns); gl.uniform1f(uniforms['u_rows'], emitterObject.rows); } function bindEventObjectEmitterBuffer(emitter: EventObjectSplEmitter | EventObjectUbrEmitter, buffer: ClientBuffer): void { const objects = emitter.objects; const floatView = buffer.floatView; let offset = 0; for (const object of objects) { const floatOffset = offset * FLOATS_PER_OBJECT; const p0Offset = floatOffset + FLOAT_OFFSET_P0; const vertices = object.vertices; floatView[p0Offset + 0] = vertices[0]; floatView[p0Offset + 1] = vertices[1]; floatView[p0Offset + 2] = vertices[2]; floatView[p0Offset + 3] = vertices[3]; floatView[p0Offset + 4] = vertices[4]; floatView[p0Offset + 5] = vertices[5]; floatView[p0Offset + 6] = vertices[6]; floatView[p0Offset + 7] = vertices[7]; floatView[p0Offset + 8] = vertices[8]; floatView[p0Offset + 9] = vertices[9]; floatView[p0Offset + 10] = vertices[10]; floatView[p0Offset + 11] = vertices[11]; floatView[floatOffset + FLOAT_OFFSET_HEALTH] = object.health; offset += 1; } } function bindEventObjectSplEmitterShader(emitter: EventObjectSplEmitter, shader: Shader): void { const textureOverrides = emitter.instance.textureOverrides; const emitterObject = emitter.emitterObject; const intervalTimes = emitterObject.intervalTimes; const intervals = emitterObject.intervals; const colors = emitterObject.colors; const model = emitterObject.model; const gl = model.viewer.gl; const uniforms = shader.uniforms; const texture = emitterObject.internalTexture; const actualTexture = textureOverrides.get(EMITTER_EVENT_TEXTURE_OFFSET + emitterObject.index) || texture.texture; gl.blendFunc(emitterObject.blendSrc, emitterObject.blendDst); model.viewer.webgl.bindTextureAndWrap(actualTexture, 0, texture.wrapS, texture.wrapT); gl.uniform1f(uniforms['u_lifeSpan'], emitterObject.lifeSpan); gl.uniform1f(uniforms['u_columns'], emitterObject.columns); gl.uniform1f(uniforms['u_rows'], emitterObject.rows); // 3 because the uniform is shared with UBR, which has 3 values. gl.uniform3f(uniforms['u_intervalTimes'], intervalTimes[0], intervalTimes[1], 0); gl.uniform3fv(uniforms['u_intervals[0]'], intervals[0]); gl.uniform3fv(uniforms['u_intervals[1]'], intervals[1]); gl.uniform4fv(uniforms['u_colors[0]'], colors[0]); gl.uniform4fv(uniforms['u_colors[1]'], colors[1]); gl.uniform4fv(uniforms['u_colors[2]'], colors[2]); } function bindEventObjectUbrEmitterShader(emitter: EventObjectUbrEmitter, shader: Shader): void { const textureOverrides = emitter.instance.textureOverrides; const emitterObject = emitter.emitterObject; const intervalTimes = emitterObject.intervalTimes; const colors = emitterObject.colors; const model = emitterObject.model; const viewer = model.viewer; const gl = viewer.gl; const uniforms = shader.uniforms; const texture = emitterObject.internalTexture; const actualTexture = textureOverrides.get(EMITTER_EVENT_TEXTURE_OFFSET + emitterObject.index) || texture.texture; gl.blendFunc(emitterObject.blendSrc, emitterObject.blendDst); model.viewer.webgl.bindTextureAndWrap(actualTexture, 0, texture.wrapS, texture.wrapT); gl.uniform1f(uniforms['u_lifeSpan'], emitterObject.lifeSpan); gl.uniform1f(uniforms['u_columns'], emitterObject.columns); gl.uniform1f(uniforms['u_rows'], emitterObject.rows); gl.uniform3fv(uniforms['u_intervalTimes'], intervalTimes); gl.uniform4fv(uniforms['u_colors[0]'], colors[0]); gl.uniform4fv(uniforms['u_colors[1]'], colors[1]); gl.uniform4fv(uniforms['u_colors[2]'], colors[2]); } export function renderEmitter(emitter: GeometryEmitter, shader: Shader): void { let alive = emitter.alive; const emitterObject = emitter.emitterObject; const emitterType = emitterObject.geometryEmitterType; if (emitterType === EMITTER_RIBBON) { alive -= 1; } if (alive > 0) { const viewer = emitter.instance.model.viewer; const buffer = viewer.buffer; const gl = viewer.gl; const instancedArrays = viewer.webgl.extensions['ANGLE_instanced_arrays']; const size = alive * BYTES_PER_OBJECT; const attribs = shader.attribs; buffer.reserve(size); if (emitterType === EMITTER_PARTICLE2) { bindParticleEmitter2Buffer(emitter, buffer); bindParticleEmitter2Shader(emitter, shader); } else if (emitterType === EMITTER_RIBBON) { bindRibbonEmitterBuffer(emitter, buffer); bindRibbonEmitterShader(emitter, shader); } else if (emitterType === EMITTER_SPLAT) { bindEventObjectEmitterBuffer(emitter, buffer); bindEventObjectSplEmitterShader(emitter, shader); } else { bindEventObjectEmitterBuffer(emitter, buffer); bindEventObjectUbrEmitterShader(emitter, shader); } buffer.bindAndUpdate(size); gl.uniform1i(shader.uniforms['u_emitter'], emitterType); gl.vertexAttribPointer(attribs['a_p0'], 3, gl.FLOAT, false, BYTES_PER_OBJECT, BYTE_OFFSET_P0); gl.vertexAttribPointer(attribs['a_p1'], 3, gl.FLOAT, false, BYTES_PER_OBJECT, BYTE_OFFSET_P1); gl.vertexAttribPointer(attribs['a_p2'], 3, gl.FLOAT, false, BYTES_PER_OBJECT, BYTE_OFFSET_P2); gl.vertexAttribPointer(attribs['a_p3'], 3, gl.FLOAT, false, BYTES_PER_OBJECT, BYTE_OFFSET_P3); gl.vertexAttribPointer(attribs['a_health'], 1, gl.FLOAT, false, BYTES_PER_OBJECT, BYTE_OFFSET_HEALTH); gl.vertexAttribPointer(attribs['a_color'], 4, gl.UNSIGNED_BYTE, true, BYTES_PER_OBJECT, BYTE_OFFSET_COLOR); gl.vertexAttribPointer(attribs['a_tail'], 1, gl.UNSIGNED_BYTE, false, BYTES_PER_OBJECT, BYTE_OFFSET_TAIL); gl.vertexAttribPointer(attribs['a_leftRightTop'], 3, gl.UNSIGNED_BYTE, false, BYTES_PER_OBJECT, BYTE_OFFSET_LEFT_RIGHT_TOP); instancedArrays.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, alive); } } ================================================ FILE: src/viewer/handlers/mdx/geoset.ts ================================================ import Shader from '../../gl/shader'; import MdxModel from './model'; import GeosetAnimation from './geosetanimation'; import { SkinningType } from './batch'; /** * A geoset. */ export default class Geoset { model: MdxModel; index: number; positionOffset: number; normalOffset: number; uvOffset: number; tangentOffset: number; skinOffset: number; faceOffset: number; vertices: number; elements: number; faceType: number; geosetAnimation: GeosetAnimation | null = null; constructor(model: MdxModel, index: number, positionOffset: number, normalOffset: number, uvOffset: number, tangentOffset: number, skinOffset: number, faceOffset: number, vertices: number, elements: number, faceType: number) { this.model = model; this.index = index; this.positionOffset = positionOffset; this.normalOffset = normalOffset; this.uvOffset = uvOffset; this.tangentOffset = tangentOffset; this.skinOffset = skinOffset; this.faceOffset = faceOffset; this.vertices = vertices; this.elements = elements; this.faceType = faceType; for (const geosetAnimation of model.geosetAnimations) { if (geosetAnimation.geosetId === index) { this.geosetAnimation = geosetAnimation; } } } bindShared(gl: WebGLRenderingContext, attribs: {[key: string]: number }, coordId: number): void { gl.vertexAttribPointer(attribs['a_position'], 3, gl.FLOAT, false, 0, this.positionOffset); gl.vertexAttribPointer(attribs['a_normal'], 3, gl.FLOAT, false, 0, this.normalOffset); gl.vertexAttribPointer(attribs['a_uv'], 2, gl.FLOAT, false, 0, this.uvOffset + coordId * this.vertices * 8); } bindVertexGroups(gl: WebGLRenderingContext, attribs: {[key: string]: number }): void { const model = this.model; const skinDataType = model.skinDataType; const bytesPerSkinElement = model.bytesPerSkinElement; gl.vertexAttribPointer(attribs['a_bones'], 4, skinDataType, false, 5 * bytesPerSkinElement, this.skinOffset); gl.vertexAttribPointer(attribs['a_boneNumber'], 1, skinDataType, false, 5 * bytesPerSkinElement, this.skinOffset + 4 * bytesPerSkinElement); } bindVertexGroupsExtended(gl: WebGLRenderingContext, attribs: {[key: string]: number }): void { const model = this.model; const skinDataType = model.skinDataType; const bytesPerSkinElement = model.bytesPerSkinElement; gl.vertexAttribPointer(attribs['a_bones'], 4, skinDataType, false, 9 * bytesPerSkinElement, this.skinOffset); gl.vertexAttribPointer(attribs['a_extendedBones'], 4, skinDataType, false, 9 * bytesPerSkinElement, this.skinOffset + 4 * bytesPerSkinElement); gl.vertexAttribPointer(attribs['a_boneNumber'], 1, skinDataType, false, 9 * bytesPerSkinElement, this.skinOffset + 8 * bytesPerSkinElement); } bindSkin(gl: WebGLRenderingContext, attribs: {[key: string]: number }): void { gl.vertexAttribPointer(attribs['a_bones'], 4, gl.UNSIGNED_BYTE, false, 8, this.skinOffset); gl.vertexAttribPointer(attribs['a_weights'], 4, gl.UNSIGNED_BYTE, true, 8, this.skinOffset + 4); } bind(shader: Shader, coordId: number): void { const gl = this.model.viewer.gl; const attribs = shader.attribs; this.bindShared(gl, attribs, coordId); if (attribs['a_weights'] !== undefined) { this.bindSkin(gl, attribs); } else { this.bindVertexGroups(gl, attribs); } } bindExtended(shader: Shader, coordId: number): void{ const gl = this.model.viewer.gl; const attribs = shader.attribs; this.bindShared(gl, attribs, coordId); this.bindVertexGroupsExtended(gl, attribs); } bindHd(shader: Shader, skinningType: SkinningType, coordId: number): void { const gl = this.model.viewer.gl; const attribs = shader.attribs; this.bindShared(gl, attribs, coordId); gl.vertexAttribPointer(attribs['a_tangent'], 4, gl.FLOAT, false, 0, this.tangentOffset); if (skinningType === SkinningType.Skin) { this.bindSkin(gl, attribs); } else if (skinningType === SkinningType.ExtendedVertexGroups) { this.bindVertexGroupsExtended(gl, attribs); } else { this.bindVertexGroups(gl, attribs); } } render(): void { const gl = this.model.viewer.gl; gl.drawElements(this.faceType, this.elements, gl.UNSIGNED_SHORT, this.faceOffset); } } ================================================ FILE: src/viewer/handlers/mdx/geosetanimation.ts ================================================ import { vec3 } from 'gl-matrix'; import MdlxGeosetAnimation from '../../../parsers/mdlx/geosetanimation'; import AnimatedObject from './animatedobject'; import MdxModel from './model'; /** * A geoset animation. */ export default class GeosetAnimation extends AnimatedObject { alpha: number; color: vec3; geosetId: number; constructor(model: MdxModel, geosetAnimation: MdlxGeosetAnimation) { super(model, geosetAnimation); const color = geosetAnimation.color; this.alpha = geosetAnimation.alpha; this.color = vec3.fromValues(color[2], color[1], color[0]); // Stored as RGB, but animated colors are stored as BGR, so sizzle. this.geosetId = geosetAnimation.geosetId; this.addVariants('KGAO', 'alpha'); this.addVariants('KGAC', 'color'); } getAlpha(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KGAO', sequence, frame, counter, this.alpha); } getColor(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KGAC', sequence, frame, counter, this.color); } } ================================================ FILE: src/viewer/handlers/mdx/handler.ts ================================================ import { extname } from '../../../common/path'; import { FetchDataType } from '../../../common/fetchdatatype'; import { decodeAudioData } from '../../../common/audio'; import MdlxModel from '../../../parsers/mdlx/model'; import { isMdx, isMdl } from '../../../parsers/mdlx/isformat'; import { MappedData, MappedDataRow } from '../../../utils/mappeddata'; import ModelViewer, { DebugRenderMode } from '../../viewer'; import Shader from '../../gl/shader'; import { PathSolver, SolverParams } from '../../handlerresource'; import { Resource } from '../../resource'; import GenericResource from '../../genericresource'; import Texture from '../../texture'; import Model from './model'; import MdxTexture from './texture'; import sdVert from './shaders/sd.vert'; import sdFrag from './shaders/sd.frag'; import hdVert from './shaders/hd.vert'; import hdFrag from './shaders/hd.frag'; import particlesVert from './shaders/particles.vert'; import particlesFrag from './shaders/particles.frag'; import { SkinningType } from './batch'; import { WrapMode } from '../../../parsers/mdlx/texture'; export interface EventObjectData { row: MappedDataRow; resources: Resource[]; } export interface MdxHandlerObject { pathSolver?: PathSolver; reforged: boolean; sdShader: Shader; sdSkinShader: Shader; sdExtendedShader: Shader; hdShader: Shader; hdExtendedShader: Shader; hdSkinShader: Shader; particlesShader: Shader; sdDebugShaders: Shader[][]; hdDebugShaders: Shader[][]; rectBuffer: WebGLBuffer; teamColors: MdxTexture[]; teamGlows: MdxTexture[]; eventObjectTables: {[key: string]: GenericResource[] }; // lutTexture: MdxTexture | null; // envDiffuseTexture: MdxTexture | null; // envSpecularTexture: MdxTexture | null; } const mappedDataCallback = (data: FetchDataType): MappedData => new MappedData(data); const decodedDataCallback = (data: FetchDataType): Promise => decodeAudioData(data); export default { load(viewer: ModelViewer, pathSolver?: PathSolver, reforged = false): void { const gl = viewer.gl; const webgl = viewer.webgl; // Bone textures. if (!webgl.ensureExtension('OES_texture_float')) { throw new Error('MDX: No float texture support!'); } // Geometry emitters. if (!webgl.ensureExtension('ANGLE_instanced_arrays')) { throw new Error('MDX: No instanced rendering support!'); } // Shaders. Lots of them. const sdExtendedVert = '#define EXTENDED_BONES\n' + sdVert; const sdDiffuse = '#define ONLY_DIFFUSE\n' + sdFrag; const sdTexcoords = '#define ONLY_TEXCOORDS\n' + sdFrag; const sdNormals = '#define ONLY_NORMALS\n' + sdFrag; const hdExtendedVert = '#define EXTENDED_BONES\n' + hdVert; const hdSkinVert = '#define SKIN\n' + hdVert; const hdDiffuse = '#define ONLY_DIFFUSE\n' + hdFrag; const hdNormalMap = '#define ONLY_NORMAL_MAP\n' + hdFrag; const hdOcclusion = '#define ONLY_OCCLUSION\n' + hdFrag; const hdRoughness = '#define ONLY_ROUGHNESS\n' + hdFrag; const hdMetallic = '#define ONLY_METALLIC\n' + hdFrag; const hdTCFactor = '#define ONLY_TC_FACTOR\n' + hdFrag; const hdEmissive = '#define ONLY_EMISSIVE\n' + hdFrag; const hdTexCoords = '#define ONLY_TEXCOORDS\n' + hdFrag; const hdNormals = '#define ONLY_NORMALS\n' + hdFrag; const hdTangents = '#define ONLY_TANGENTS\n' + hdFrag; const sdShader = webgl.createShader(sdVert, sdFrag); const sdExtendedShader = webgl.createShader(sdExtendedVert, sdFrag); const sdSkinVert = '#define SKIN\n' + sdVert; const sdSkinShader = webgl.createShader(sdSkinVert, sdFrag); const hdShader = webgl.createShader(hdVert, hdFrag); const hdExtendedShader = webgl.createShader(hdExtendedVert, hdFrag); const hdSkinShader = webgl.createShader(hdSkinVert, hdFrag); const particlesShader = webgl.createShader(particlesVert, particlesFrag); const sdDebugShaders: Shader[][] = []; const hdDebugShaders: Shader[][] = []; let shaders: Shader[] = []; shaders[DebugRenderMode.Diffuse] = webgl.createShader(sdVert, sdDiffuse); shaders[DebugRenderMode.TexCoords] = webgl.createShader(sdVert, sdTexcoords); shaders[DebugRenderMode.Normals] = webgl.createShader(sdVert, sdNormals); sdDebugShaders[SkinningType.VertexGroups] = shaders; shaders = []; shaders[DebugRenderMode.Diffuse] = webgl.createShader(sdExtendedVert, sdDiffuse); shaders[DebugRenderMode.TexCoords] = webgl.createShader(sdExtendedVert, sdTexcoords); shaders[DebugRenderMode.Normals] = webgl.createShader(sdExtendedVert, sdNormals); sdDebugShaders[SkinningType.ExtendedVertexGroups] = shaders; shaders = []; shaders[DebugRenderMode.Diffuse] = webgl.createShader(hdVert, hdDiffuse); shaders[DebugRenderMode.NormalMap] = webgl.createShader(hdVert, hdNormalMap); shaders[DebugRenderMode.Occlusion] = webgl.createShader(hdVert, hdOcclusion); shaders[DebugRenderMode.Roughness] = webgl.createShader(hdVert, hdRoughness); shaders[DebugRenderMode.Metallic] = webgl.createShader(hdVert, hdMetallic); shaders[DebugRenderMode.TCFactor] = webgl.createShader(hdVert, hdTCFactor); shaders[DebugRenderMode.Emissive] = webgl.createShader(hdVert, hdEmissive); shaders[DebugRenderMode.TexCoords] = webgl.createShader(hdVert, hdTexCoords); shaders[DebugRenderMode.Normals] = webgl.createShader(hdVert, hdNormals); shaders[DebugRenderMode.Tangents] = webgl.createShader('#define ONLY_TANGENTS\n' + hdVert, hdTangents); hdDebugShaders[SkinningType.VertexGroups] = shaders; shaders = []; shaders[DebugRenderMode.Diffuse] = webgl.createShader(hdExtendedVert, hdDiffuse); shaders[DebugRenderMode.NormalMap] = webgl.createShader(hdExtendedVert, hdNormalMap); shaders[DebugRenderMode.Occlusion] = webgl.createShader(hdExtendedVert, hdOcclusion); shaders[DebugRenderMode.Roughness] = webgl.createShader(hdExtendedVert, hdRoughness); shaders[DebugRenderMode.Metallic] = webgl.createShader(hdExtendedVert, hdMetallic); shaders[DebugRenderMode.TCFactor] = webgl.createShader(hdExtendedVert, hdTCFactor); shaders[DebugRenderMode.Emissive] = webgl.createShader(hdExtendedVert, hdEmissive); shaders[DebugRenderMode.TexCoords] = webgl.createShader(hdExtendedVert, hdTexCoords); shaders[DebugRenderMode.Normals] = webgl.createShader(hdExtendedVert, hdNormals); shaders[DebugRenderMode.Tangents] = webgl.createShader('#define ONLY_TANGENTS\n' + hdExtendedVert, hdTangents); hdDebugShaders[SkinningType.ExtendedVertexGroups] = shaders; shaders = []; shaders[DebugRenderMode.Diffuse] = webgl.createShader(hdSkinVert, hdDiffuse); shaders[DebugRenderMode.NormalMap] = webgl.createShader(hdSkinVert, hdNormalMap); shaders[DebugRenderMode.Occlusion] = webgl.createShader(hdSkinVert, hdOcclusion); shaders[DebugRenderMode.Roughness] = webgl.createShader(hdSkinVert, hdRoughness); shaders[DebugRenderMode.Metallic] = webgl.createShader(hdSkinVert, hdMetallic); shaders[DebugRenderMode.TCFactor] = webgl.createShader(hdSkinVert, hdTCFactor); shaders[DebugRenderMode.Emissive] = webgl.createShader(hdSkinVert, hdEmissive); shaders[DebugRenderMode.TexCoords] = webgl.createShader(hdSkinVert, hdTexCoords); shaders[DebugRenderMode.Normals] = webgl.createShader(hdSkinVert, hdNormals); shaders[DebugRenderMode.Tangents] = webgl.createShader('#define ONLY_TANGENTS\n' + hdSkinVert, hdTangents); hdDebugShaders[SkinningType.Skin] = shaders; const rectBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, rectBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); const handlerData: MdxHandlerObject = { pathSolver, reforged, // Shaders. sdShader, sdSkinShader, sdExtendedShader, hdShader, hdExtendedShader, hdSkinShader, particlesShader, sdDebugShaders, hdDebugShaders, // Geometry emitters buffer. rectBuffer, // Team color/glow textures - loaded when the first model that uses team textures is loaded. teamColors: [], teamGlows: [], eventObjectTables: {}, // lutTexture: null, // envDiffuseTexture: null, // envSpecularTexture: null, }; viewer.sharedCache.set('mdx', handlerData); }, isValidSource(object: unknown): boolean { if (object instanceof MdlxModel) { return true; } return isMdx(object) || isMdl(object); }, resource: Model, // async loadEnv(viewer: ModelViewer) { // const mdxHandler = viewer.sharedCache.get('mdx'); // if (!mdxHandler.lutTexture) { // mdxHandler.lutTexture = new MdxTexture(0, WrapMode.WrapBoth); // mdxHandler.envDiffuseTexture = new MdxTexture(0, WrapMode.WrapBoth); // mdxHandler.envSpecularTexture = new MdxTexture(0, WrapMode.WrapBoth); // const [lutTexture, diffuseTexture, specularTexture] = await Promise.all([ // viewer.load('env/lut.png'), // viewer.load('env/diffuse-sRGB.png'), // viewer.load('env/specular-sRGB.png'), // ]); // mdxHandler.lutTexture.texture = lutTexture; // mdxHandler.envDiffuseTexture.texture = diffuseTexture; // mdxHandler.envSpecularTexture.texture = specularTexture; // } // }, loadTeamTextures(viewer: ModelViewer): void { const { pathSolver, reforged, teamColors, teamGlows } = viewer.sharedCache.get('mdx'); if (teamColors.length === 0) { const teams = reforged ? 28 : 16; const ext = reforged ? 'dds' : 'blp'; const params = reforged ? { reforged: true } : undefined; for (let i = 0; i < teams; i++) { const id = `${i}`.padStart(2, '0'); const end = `${id}.${ext}`; const teamColor = new MdxTexture(1, WrapMode.WrapBoth); const teamGlow = new MdxTexture(2, WrapMode.WrapBoth); viewer.load(`ReplaceableTextures\\TeamColor\\TeamColor${end}`, pathSolver, params) .then((texture) => teamColor.texture = texture); viewer.load(`ReplaceableTextures\\TeamGlow\\TeamGlow${end}`, pathSolver, params) .then((texture) => teamGlow.texture = texture); teamColors[i] = teamColor; teamGlows[i] = teamGlow; } } }, getEventObjectSoundFile(file: string, reforged: boolean, isHd: boolean, tables: GenericResource[]): string | undefined { if (!reforged || extname(file) === '.flac') { return file; } for (let i = 1, l = tables.length; i < l; i++) { const raceRow = (tables[i].data).getRow(file); if (raceRow) { const flags = raceRow.string('Flags'); const filePath = raceRow.string('Filepath'); if (flags === 'SD_ONLY') { if (!isHd) { return filePath; } } else if (flags === 'HD_ONLY') { if (isHd) { return filePath; } } else { return filePath; } } } return; }, async getEventObjectData(viewer: ModelViewer, type: string, id: string, isHd: boolean): Promise { // Units\Critters\BlackStagMale\BlackStagMale.mdx has an event object named "Point01". if (type !== 'SPN' && type !== 'SPL' && type !== 'UBR' && type !== 'SND') { return; } const { pathSolver, reforged, eventObjectTables } = viewer.sharedCache.get('mdx'); const params: SolverParams = reforged ? { reforged: true } : {}; const safePathSolver: PathSolver = (src: unknown, params?: SolverParams): unknown => { if (pathSolver) { return pathSolver(src, params); } return src; }; if (!eventObjectTables[type]) { const paths = []; if (type === 'SPN') { paths.push('Splats\\SpawnData.slk'); } else if (type === 'SPL') { paths.push('Splats\\SplatData.slk'); } else if (type === 'UBR') { paths.push('Splats\\UberSplatData.slk'); } else if (type === 'SND') { paths.push('UI\\SoundInfo\\AnimSounds.slk'); // Reforged changed the data layout. if (reforged) { paths.push( 'UI\\SoundInfo\\DialogueHumanBase.slk', 'UI\\SoundInfo\\DialogueOrcBase.slk', 'UI\\SoundInfo\\DialogueUndeadBase.slk', 'UI\\SoundInfo\\DialogueNightElfBase.slk', 'UI\\SoundInfo\\DialogueNagaBase.slk', 'UI\\SoundInfo\\DialogueDemonBase.slk', 'UI\\SoundInfo\\DialogueCreepsBase.slk'); } else { paths.push('UI\\SoundInfo\\AnimLookups.slk'); } } const promises = paths.map((path) => viewer.loadGeneric(safePathSolver(path, params), 'text', mappedDataCallback)); const resources = await Promise.all(promises); for (const resource of resources) { if (!resource) { return; } } eventObjectTables[type] = resources; } const tables = eventObjectTables[type]; const mappedData = tables[0].data; let row: MappedDataRow | undefined; const promises = []; if (type === 'SND') { // How to get the sound row? // TFT has AnimLookups.slk, which stores a ID->Label. Give it the event object ID, get back the label to look for in AnimSounds.slk. // Reforged removed AnimLookups.slk, and instead has the ID under a new column in AnimSounds.slk called AnimationEventCode. // In addition, Reforged can have SD/HD flags per sound, to determine whether it should load in SD or HD modes. // When a sound has both modes, the path to it in AnimSounds.slk won't be an actual file path (ending with .flac) but rather a label. // This label can be queried in other sound SLKs such as DialogueHumanBase.slk, which contains the full path and the mentioned flags. if (reforged) { row = mappedData.findRow('AnimationEventCode', id); } else { const lookupRow = (tables[1].data).getRow(id); if (lookupRow) { row = mappedData.getRow(lookupRow.string('SoundLabel')); } } if (row) { for (const fileName of (row.string('FileNames')).split(',')) { const file = this.getEventObjectSoundFile(fileName, reforged, isHd, tables); if (file) { promises.push(viewer.loadGeneric(safePathSolver(file, params), 'arrayBuffer', decodedDataCallback)); } } } } else { // Model and texture event objects are simpler than sounds - just get the right model or texture file. row = mappedData.getRow(id); if (row) { if (type === 'SPN') { promises.push(viewer.load((row.string('Model')).replace('.mdl', '.mdx'), safePathSolver, params)); } else if (type === 'SPL' || type === 'UBR') { promises.push(viewer.load(`ReplaceableTextures\\Splats\\${row.string('file')}${reforged ? '.dds' : '.blp'}`, safePathSolver, params)); } } } if (row && promises.length) { const resources = await Promise.all(promises); // Make sure the resources actually loaded properly. const filtered = resources.filter((resource) => resource); if (filtered.length) { return { row, resources: filtered }; } } return; }, getBatchShader(viewer: ModelViewer, skinningType: SkinningType, isHd: boolean): Shader { const mdxCache = viewer.sharedCache.get('mdx'); const debugRenderMode = viewer.debugRenderMode; if (isHd) { if (debugRenderMode !== DebugRenderMode.None) { const shaders = mdxCache.hdDebugShaders[skinningType]; if (shaders) { const shader = shaders[debugRenderMode]; if (shader) { return shader; } } } if (skinningType === SkinningType.Skin) { return mdxCache.hdSkinShader; } else if (skinningType === SkinningType.VertexGroups) { return mdxCache.hdShader; } else { return mdxCache.hdExtendedShader; } } else { if (debugRenderMode !== DebugRenderMode.None) { const shaders = mdxCache.sdDebugShaders[skinningType]; if (shaders) { const shader = shaders[debugRenderMode]; if (shader) { return shader; } } } if (skinningType === SkinningType.Skin) { return mdxCache.sdSkinShader; } else if (skinningType === SkinningType.VertexGroups) { return mdxCache.sdShader; } else { return mdxCache.sdExtendedShader; } } } }; ================================================ FILE: src/viewer/handlers/mdx/helper.ts ================================================ import GenericObject from './genericobject'; /** * An MDX helper. */ export default class Helper extends GenericObject {} ================================================ FILE: src/viewer/handlers/mdx/layer.ts ================================================ import MdlxLayer, { FilterMode, Flags } from '../../../parsers/mdlx/layer'; import MdxModel from './model'; import AnimatedObject from './animatedobject'; import TextureAnimation from './textureanimation'; import { layerFilterMode } from './filtermode'; import Shader from '../../gl/shader'; /** * An MDX layer. */ export default class Layer extends AnimatedObject { index: number; priorityPlane: number; filterMode: FilterMode; textureId = 0; coordId: number; alpha: number; unshaded: number; sphereEnvironmentMap: number; twoSided: number; unfogged: number; noDepthTest: number; noDepthSet: number; depthMaskValue: boolean; blendSrc = 0; blendDst = 0; blended = false; textureAnimation: TextureAnimation | null = null; constructor(model: MdxModel, layer: MdlxLayer, layerId: number, priorityPlane: number) { super(model, layer); let filterMode = layer.filterMode; const textureAnimationId = layer.textureAnimationId; const gl = model.viewer.gl; this.index = layerId; this.priorityPlane = priorityPlane; if (filterMode > FilterMode.Modulate2x) { filterMode = FilterMode.Blend; } this.filterMode = filterMode; if (layer.textureId !== -1) { this.textureId = layer.textureId; } this.coordId = layer.coordId; this.alpha = layer.alpha; const flags = layer.flags; this.unshaded = flags & Flags.Unshaded; this.sphereEnvironmentMap = flags & Flags.SphereEnvMap; this.twoSided = flags & Flags.TwoSided; this.unfogged = flags & Flags.Unfogged; this.noDepthTest = flags & Flags.NoDepthTest; this.noDepthSet = flags & Flags.NoDepthSet; this.depthMaskValue = (filterMode === FilterMode.None || filterMode === FilterMode.Transparent); if (filterMode > FilterMode.Transparent) { this.blended = true; [this.blendSrc, this.blendDst] = layerFilterMode(filterMode, gl); } if (textureAnimationId !== -1) { const textureAnimation = model.textureAnimations[textureAnimationId]; if (textureAnimation) { this.textureAnimation = textureAnimation; } } this.addVariants('KMTA', 'alpha'); this.addVariants('KMTF', 'textureId'); } bind(shader: Shader): void { const gl = this.model.viewer.gl; // gl.uniform1f(shader.uniforms.u_unshaded, this.unshaded); gl.uniform1f(shader.uniforms['u_filterMode'], this.filterMode); if (this.blended) { gl.enable(gl.BLEND); gl.blendFunc(this.blendSrc, this.blendDst); } else { gl.disable(gl.BLEND); } if (this.twoSided) { gl.disable(gl.CULL_FACE); } else { gl.enable(gl.CULL_FACE); } if (this.noDepthTest) { gl.disable(gl.DEPTH_TEST); } else { gl.enable(gl.DEPTH_TEST); } if (this.noDepthSet) { gl.depthMask(false); } else { gl.depthMask(this.depthMaskValue); } } getAlpha(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KMTA', sequence, frame, counter, this.alpha); } getTextureId(out: Uint32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KMTF', sequence, frame, counter, this.textureId); } } ================================================ FILE: src/viewer/handlers/mdx/light.ts ================================================ import MdlxLight, { LightType } from '../../../parsers/mdlx/light'; import MdxModel from './model'; import GenericObject from './genericobject'; /** * An MDX light. */ export default class Light extends GenericObject { type: LightType; attenuation: Float32Array; color: Float32Array; intensity: number; ambientColor: Float32Array; ambientIntensity: number; constructor(model: MdxModel, light: MdlxLight, index: number) { super(model, light, index); this.type = light.type; this.attenuation = light.attenuation; this.color = light.color; this.intensity = light.intensity; this.ambientColor = light.ambientColor; this.ambientIntensity = light.ambientIntensity; } getAttenuationStart(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KLAS', sequence, frame, counter, this.attenuation[0]); } getAttenuationEnd(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KLAE', sequence, frame, counter, this.attenuation[1]); } getIntensity(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KLAI', sequence, frame, counter, this.intensity); } getColor(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KLAC', sequence, frame, counter, this.color); } getAmbientIntensity(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KLBI', sequence, frame, counter, this.ambientIntensity); } getAmbientColor(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KLBC', sequence, frame, counter, this.ambientColor); } } ================================================ FILE: src/viewer/handlers/mdx/material.ts ================================================ import MdxModel from './model'; import Layer from './layer'; /** * An MDX material. */ export default class Material { model: MdxModel; shader: string; layers: Layer[]; constructor(model: MdxModel, shader: string, layers: Layer[]) { this.model = model; this.shader = shader; this.layers = layers; } } ================================================ FILE: src/viewer/handlers/mdx/model.ts ================================================ import Parser from '../../../parsers/mdlx/model'; import Sequence from './sequence'; import { HandlerResourceData } from '../../handlerresource'; import Model from '../../model'; import Texture from '../../texture'; import mdxHandler from './handler'; import TextureAnimation from './textureanimation'; import Layer from './layer'; import Material from './material'; import GeosetAnimation from './geosetanimation'; import replaceableIds from './replaceableids'; import Bone from './bone'; import Light from './light'; import Helper from './helper'; import Attachment from './attachment'; import ParticleEmitterObject from './particleemitterobject'; import ParticleEmitter2Object from './particleemitter2object'; import RibbonEmitterObject from './ribbonemitterobject'; import Camera from './camera'; import EventObjectEmitterObject from './eventobjectemitterobject'; import CollisionShape from './collisionshape'; import setupGeosets from './setupgeosets'; import setupGroups from './setupgroups'; import BatchGroup from './batchgroup'; import EmitterGroup from './emittergroup'; import GenericObject from './genericobject'; import { Batch } from './batch'; import Geoset from './geoset'; import MdxModelInstance from './modelinstance'; import MdxTexture from './texture'; /** * An MDX model. */ export default class MdxModel extends Model { reforged = false; hd = false; solverParams: { reforged?: boolean, hd?: boolean } = {}; name = ''; sequences: Sequence[] = []; globalSequences: number[] = []; materials: Material[] = []; layers: Layer[] = []; textures: MdxTexture[] = []; textureAnimations: TextureAnimation[] = []; geosets: Geoset[] = []; geosetAnimations: GeosetAnimation[] = []; bones: Bone[] = []; lights: Light[] = []; helpers: Helper[] = []; attachments: Attachment[] = []; pivotPoints: Float32Array[] = []; particleEmitters: ParticleEmitterObject[] = []; particleEmitters2: ParticleEmitter2Object[] = []; ribbonEmitters: RibbonEmitterObject[] = []; cameras: Camera[] = []; eventObjects: EventObjectEmitterObject[] = []; collisionShapes: CollisionShape[] = []; hasLayerAnims = false; hasGeosetAnims = false; batches: Batch[] = []; genericObjects: GenericObject[] = []; sortedGenericObjects: GenericObject[] = []; hierarchy: number[] = []; opaqueGroups: BatchGroup[] = []; translucentGroups: (BatchGroup | EmitterGroup)[] = []; arrayBuffer: WebGLBuffer | null = null; elementBuffer: WebGLBuffer | null = null; skinDataType = 0; bytesPerSkinElement = 1; constructor(bufferOrParser: ArrayBuffer | string | Parser, resourceData: HandlerResourceData) { super(resourceData); let parser; if (bufferOrParser instanceof Parser) { parser = bufferOrParser; } else { parser = new Parser(); try { parser.load(bufferOrParser); } catch (e) { // If we get here, the parser failed to load. // It still may have loaded enough data to support rendering though! // I have encountered a model that is missing data, but still works in-game. // So just let the code continue. // If the handler manages to load the model, nothing happened. // If critical data is missing, it will fail and throw its own exception. } } const viewer = this.viewer; const pathSolver = this.pathSolver; const solverParams = this.solverParams; const reforged = parser.version > 800; const texturesExt = reforged ? '.dds' : '.blp'; let hasTeamColors = false; this.reforged = reforged; this.name = parser.name; // Initialize the bounds. const extent = parser.extent; this.bounds.fromExtents(extent.min, extent.max); // Sequences for (const sequence of parser.sequences) { this.sequences.push(new Sequence(sequence)); } // Global sequences for (const globalSequence of parser.globalSequences) { this.globalSequences.push(globalSequence); } // Texture animations for (const textureAnimation of parser.textureAnimations) { this.textureAnimations.push(new TextureAnimation(this, textureAnimation)); } // Materials let layerId = 0; for (const material of parser.materials) { const layers = []; for (const layer of material.layers) { const vLayer = new Layer(this, layer, layerId++, material.priorityPlane); layers.push(vLayer); this.layers.push(vLayer); } this.materials.push(new Material(this, material.shader, layers)); if (material.shader !== '') { this.hd = true; } } if (reforged) { solverParams.reforged = true; } if (this.hd) { solverParams.hd = true; // mdxHandler.loadEnv(viewer); } // Textures. const textures = parser.textures; for (let i = 0, l = textures.length; i < l; i++) { const texture = textures[i]; let path = texture.path; const replaceableId = texture.replaceableId; const wrapMode = texture.wrapMode; if (path === '' && replaceableId !== 0) { path = `ReplaceableTextures\\${replaceableIds[replaceableId]}${texturesExt}`; if (replaceableId === 1 || replaceableId === 2) { hasTeamColors = true; } } const mdxTexture = new MdxTexture(replaceableId, wrapMode); viewer.load(path, pathSolver, solverParams) .then((texture) => { if (texture) { mdxTexture.texture = texture; } }); this.textures[i] = mdxTexture; } // Geoset animations for (const geosetAnimation of parser.geosetAnimations) { this.geosetAnimations.push(new GeosetAnimation(this, geosetAnimation)); } this.pivotPoints = parser.pivotPoints; // Tracks the IDs of all generic objects. let objectId = 0; // Bones for (const bone of parser.bones) { this.bones.push(new Bone(this, bone, objectId++)); } // Lights for (const light of parser.lights) { this.lights.push(new Light(this, light, objectId++)); } // Helpers for (const helper of parser.helpers) { this.helpers.push(new Helper(this, helper, objectId++)); } // Attachments for (const attachment of parser.attachments) { this.attachments.push(new Attachment(this, attachment, objectId++)); } // Particle emitters for (const particleEmitter of parser.particleEmitters) { this.particleEmitters.push(new ParticleEmitterObject(this, particleEmitter, objectId++)); } // Particle emitters 2 for (const particleEmitter2 of parser.particleEmitters2) { const emitter = new ParticleEmitter2Object(this, particleEmitter2, objectId++); this.particleEmitters2.push(emitter); if (emitter.teamColored) { hasTeamColors = true; } } // Ribbon emitters for (const ribbonEmitter of parser.ribbonEmitters) { this.ribbonEmitters.push(new RibbonEmitterObject(this, ribbonEmitter, objectId++)); } // Cameras for (const camera of parser.cameras) { this.cameras.push(new Camera(this, camera)); } // Event objects for (const eventObject of parser.eventObjects) { this.eventObjects.push(new EventObjectEmitterObject(this, eventObject, objectId++)); } // Collision shapes for (const collisionShape of parser.collisionShapes) { this.collisionShapes.push(new CollisionShape(this, collisionShape, objectId++)); } // One array for all generic objects. this.genericObjects.push(...this.bones, ...this.lights, ...this.helpers, ...this.attachments, ...this.particleEmitters, ...this.particleEmitters2, ...this.ribbonEmitters, ...this.eventObjects, ...this.collisionShapes); // Geosets setupGeosets(this, parser.geosets); // Render groups. setupGroups(this); // Creates the sorted indices array of the generic objects. this.setupHierarchy(-1); // Keep a sorted array. for (let i = 0, l = this.genericObjects.length; i < l; i++) { this.sortedGenericObjects[i] = this.genericObjects[this.hierarchy[i]]; } // Lazy loading team colors. if (hasTeamColors) { mdxHandler.loadTeamTextures(viewer); } } addInstance(): MdxModelInstance { return new MdxModelInstance(this); } setupHierarchy(parent: number): void { for (let i = 0, l = this.genericObjects.length; i < l; i++) { const object = this.genericObjects[i]; if (object.parentId === parent) { this.hierarchy.push(i); this.setupHierarchy(object.objectId); } } } } ================================================ FILE: src/viewer/handlers/mdx/modelinstance.ts ================================================ import { vec3, quat } from 'gl-matrix'; import ModelInstance from '../../modelinstance'; import { createSkeletalNodes, SkeletalNode } from '../../skeletalnode'; import DataTexture from '../../gl/datatexture'; import Texture from '../../texture'; import MdxNode from './node'; import AttachmentInstance from './attachmentinstance'; import ParticleEmitter from './particleemitter'; import ParticleEmitter2 from './particleemitter2'; import RibbonEmitter from './ribbonemitter'; import EventObjectEmitter from './eventobjectemitter'; import EventObjectSpnEmitter from './eventobjectspnemitter'; import EventObjectSplEmitter from './eventobjectsplemitter'; import EventObjectUbrEmitter from './eventobjectubremitter'; import EventObjectSndEmitter from './eventobjectsndemitter'; import MdxModel from './model'; import GenericObject from './genericobject'; import { EMITTER_PARTICLE2_TEXTURE_OFFSET, EMITTER_EVENT_TEXTURE_OFFSET } from './geometryemitterfuncs'; import Bounds from '../../bounds'; const visibilityHeap = new Float32Array(1); const translationHeap = vec3.create(); const rotationHeap = quat.create(); const scaleHeap = vec3.create(); const colorHeap = new Float32Array(3); const alphaHeap = new Float32Array(1); const textureIdHeap = new Uint32Array(1); type SkeletalNodeObject = AttachmentInstance | ParticleEmitter | ParticleEmitter2 | RibbonEmitter | EventObjectEmitter; /** * An MDX model instance. */ export default class MdxModelInstance extends ModelInstance { attachments: AttachmentInstance[] = []; particleEmitters: ParticleEmitter[] = []; particleEmitters2: ParticleEmitter2[] = []; ribbonEmitters: RibbonEmitter[] = []; eventObjectEmitters: (EventObjectSpnEmitter | EventObjectSplEmitter | EventObjectUbrEmitter | EventObjectSndEmitter)[] = []; nodes: SkeletalNode[] = []; sortedNodes: SkeletalNode[] = []; frame = 0; // Global sequences counter = 0; sequence = -1; sequenceLoopMode = 0; sequenceEnded = false; teamColor = 0; vertexColor = new Float32Array([1, 1, 1, 1]); // Particles do not spawn when the sequence is -1, or when the sequence finished and it's not repeating allowParticleSpawn = false; // If forced is true, everything will update regardless of variancy. // Any later non-forced update can then use variancy to skip updating things. // It is set to true every time the sequence is set with setSequence(). forced = true; geosetColors: Float32Array[] = []; layerAlphas: number[] = []; layerTextures: number[] = []; uvAnims: Float32Array[] = []; worldMatrices: Float32Array | null = null; boneTexture: DataTexture | null = null; constructor(model: MdxModel) { super(model); for (let i = 0, l = model.geosets.length; i < l; i++) { this.geosetColors[i] = new Float32Array(4); } for (let i = 0, l = model.layers.length; i < l; i++) { this.layerAlphas[i] = 0; this.layerTextures[i] = 0; this.uvAnims[i] = new Float32Array(5); } // Create the needed amount of shared nodes. const sharedNodeData = createSkeletalNodes(model.genericObjects.length, MdxNode); const nodes = sharedNodeData.nodes; let nodeIndex = 0; this.nodes.push(...nodes); // A shared typed array for all world matrices of the internal nodes. this.worldMatrices = sharedNodeData.worldMatrices; // And now initialize all of the nodes and objects for (const bone of model.bones) { this.initNode(nodes, nodes[nodeIndex++], bone); } for (const light of model.lights) { this.initNode(nodes, nodes[nodeIndex++], light); } for (const helper of model.helpers) { this.initNode(nodes, nodes[nodeIndex++], helper); } for (const attachment of model.attachments) { let attachmentInstance; // Attachments may have game models attached to them, such as Undead and Nightelf building animations. if (attachment.internalModel) { attachmentInstance = new AttachmentInstance(this, attachment); this.attachments.push(attachmentInstance); } this.initNode(nodes, nodes[nodeIndex++], attachment, attachmentInstance); } for (const emitterObject of model.particleEmitters) { const emitter = new ParticleEmitter(this, emitterObject); this.particleEmitters.push(emitter); this.initNode(nodes, nodes[nodeIndex++], emitterObject, emitter); } for (const emitterObject of model.particleEmitters2) { const emitter = new ParticleEmitter2(this, emitterObject); this.particleEmitters2.push(emitter); this.initNode(nodes, nodes[nodeIndex++], emitterObject, emitter); } for (const emitterObject of model.ribbonEmitters) { const emitter = new RibbonEmitter(this, emitterObject); this.ribbonEmitters.push(emitter); this.initNode(nodes, nodes[nodeIndex++], emitterObject, emitter); } for (const emitterObject of model.eventObjects) { const type = emitterObject.type; let emitter; if (type === 'SPN') { emitter = new EventObjectSpnEmitter(this, emitterObject); } else if (type === 'SPL') { emitter = new EventObjectSplEmitter(this, emitterObject); } else if (type === 'UBR') { emitter = new EventObjectUbrEmitter(this, emitterObject); } else { emitter = new EventObjectSndEmitter(this, emitterObject); } this.eventObjectEmitters.push(emitter); this.initNode(nodes, nodes[nodeIndex++], emitterObject, emitter); } for (const collisionShape of model.collisionShapes) { this.initNode(nodes, nodes[nodeIndex++], collisionShape); } // Save a sorted array of all of the nodes, such that every child node comes after its parent. // This allows for flat iteration when updating. const hierarchy = model.hierarchy; for (let i = 0, l = nodes.length; i < l; i++) { this.sortedNodes[i] = nodes[hierarchy[i]]; } if (model.bones.length) { this.boneTexture = new DataTexture(model.viewer.gl, 4, model.bones.length * 4, 1); } } /** * Override the texture at the given index. * * If a texture isn't given, removes the override if there was one. */ setTexture(index: number, texture?: Texture): void { this.overrideTexture(index, texture); } /** * Override the texture of the particle emitter the given index. * * If a texture isn't given, removes the override if there was one. */ setParticle2Texture(index: number, texture?: Texture): void { this.overrideTexture(EMITTER_PARTICLE2_TEXTURE_OFFSET + index, texture); } /** * Override the texture of the event emitter the given index. * * If a texture isn't given, removes the override if there was one. */ setEventTexture(index: number, texture?: Texture): void { this.overrideTexture(EMITTER_EVENT_TEXTURE_OFFSET + index, texture); } /** * Clear all of the emitted objects that belong to this instance. */ override clearEmittedObjects(): void { for (const emitter of this.particleEmitters) { emitter.clear(); } for (const emitter of this.particleEmitters2) { emitter.clear(); } for (const emitter of this.ribbonEmitters) { emitter.clear(); } for (const emitter of this.eventObjectEmitters) { emitter.clear(); } } /** * Initialize a skeletal node. */ initNode(nodes: SkeletalNode[], node: SkeletalNode, genericObject: GenericObject, object?: SkeletalNodeObject): void { vec3.copy(node.pivot, genericObject.pivot); if (genericObject.parentId === -1) { node.parent = this; } else { node.parent = nodes[genericObject.parentId]; } node.dontInheritTranslation = genericObject.dontInheritTranslation; node.dontInheritRotation = genericObject.dontInheritRotation; node.dontInheritScaling = genericObject.dontInheritScaling; if (genericObject.billboarded) { node.billboarded = true; } else if (genericObject.billboardedX) { node.billboardedX = true; } else if (genericObject.billboardedY) { node.billboardedY = true; } else if (genericObject.billboardedZ) { node.billboardedZ = true; } if (object) { node.object = object; } } /** * Overriden to hide also attachment models. */ override hide(): void { super.hide(); this.resetAttachments(); } /** * Updates all of this instance internal nodes and objects. * Nodes that are determined to not be visible will not be updated, nor will any of their children down the hierarchy. */ updateNodes(dt: number, forced: boolean): void { const sequence = this.sequence; const frame = this.frame; const counter = this.counter; const sortedNodes = this.sortedNodes; const model = this.model; const sortedGenericObjects = model.sortedGenericObjects; // Update the nodes for (let i = 0, l = sortedNodes.length; i < l; i++) { const genericObject = sortedGenericObjects[i]; const node = sortedNodes[i]; const parent = node.parent; let wasDirty = forced || parent.wasDirty || genericObject.anyBillboarding; const variants = genericObject.variants; // Local node transformation. // Use variants to skip animation data when possible. if (forced || variants['generic'][sequence]) { wasDirty = true; // Translation if (forced || variants['translation'][sequence]) { genericObject.getTranslation(node.localLocation, sequence, frame, counter); } // Rotation if (forced || variants['rotation'][sequence]) { genericObject.getRotation(node.localRotation, sequence, frame, counter); } // Scale if (forced || variants['scale'][sequence]) { genericObject.getScale(node.localScale, sequence, frame, counter); } } node.wasDirty = wasDirty; // If this is a forced update, or this node's local data was updated, or the parent node was updated, do a full world update. if (wasDirty) { node.recalculateTransformation(this); } // If there is an instance object associated with this node (emitter/attachment), and it is visible, update it. if (node.object) { genericObject.getVisibility(visibilityHeap, sequence, frame, counter); // If the attachment/emitter is visible, update it. if (visibilityHeap[0] > 0) { (node.object).update(dt); } } // Recalculate and update child nodes. // Note that this only affects normal nodes such as instances, and not skeletal nodes. for (const child of node.children) { if (wasDirty) { child.recalculateTransformation(); } child.update(dt); } } } /** * If a model has no sequences or is running no sequence, it will only update once since it will never be forced to update. * This is generally the desired behavior, except when it is moved by the client. * Therefore, if an instance is transformed, always do a forced update. */ override recalculateTransformation(): void { super.recalculateTransformation(); this.forced = true; } /** * Update the batch data. */ updateBatches(forced: boolean): void { const sequence = this.sequence; const frame = this.frame; const counter = this.counter; const model = this.model; const geosets = model.geosets; const layers = model.layers; const geosetColors = this.geosetColors; const layerAlphas = this.layerAlphas; const layerTextures = this.layerTextures; const uvAnims = this.uvAnims; // Geosets for (let i = 0, l = geosets.length; i < l; i++) { const geoset = geosets[i]; const geosetAnimation = geoset.geosetAnimation; const geosetColor = geosetColors[i]; if (geosetAnimation) { // Color if (forced || geosetAnimation.variants['color'][sequence]) { geosetAnimation.getColor(colorHeap, sequence, frame, counter); geosetColor[0] = colorHeap[0]; geosetColor[1] = colorHeap[1]; geosetColor[2] = colorHeap[2]; } // Alpha if (forced || geosetAnimation.variants['alpha'][sequence]) { geosetAnimation.getAlpha(alphaHeap, sequence, frame, counter); geosetColor[3] = alphaHeap[0]; } } else if (forced) { geosetColor[0] = 1; geosetColor[1] = 1; geosetColor[2] = 1; geosetColor[3] = 1; } } // Layers for (let i = 0, l = layers.length; i < l; i++) { const layer = layers[i]; const textureAnimation = layer.textureAnimation; const uvAnim = uvAnims[i]; // Alpha if (forced || layer.variants['alpha'][sequence]) { layer.getAlpha(alphaHeap, sequence, frame, counter); layerAlphas[i] = alphaHeap[0]; } // Sprite animation if (forced || layer.variants['textureId'][sequence]) { layer.getTextureId(textureIdHeap, sequence, frame, counter); layerTextures[i] = textureIdHeap[0]; } if (textureAnimation) { // UV translation animation if (forced || textureAnimation.variants['translation'][sequence]) { textureAnimation.getTranslation(translationHeap, sequence, frame, counter); uvAnim[0] = translationHeap[0]; uvAnim[1] = translationHeap[1]; } // UV rotation animation if (forced || textureAnimation.variants['rotation'][sequence]) { textureAnimation.getRotation(rotationHeap, sequence, frame, counter); uvAnim[2] = rotationHeap[2]; uvAnim[3] = rotationHeap[3]; } // UV scale animation if (forced || textureAnimation.variants['scale'][sequence]) { textureAnimation.getScale(scaleHeap, sequence, frame, counter); uvAnim[4] = scaleHeap[0]; } } else if (forced) { uvAnim[0] = 0; uvAnim[1] = 0; uvAnim[2] = 0; uvAnim[3] = 1; uvAnim[4] = 1; } } } updateBoneTexture(): void { if (this.boneTexture) { this.boneTexture.bindAndUpdate(this.worldMatrices); } } override renderOpaque(): void { const model = this.model; for (const group of model.opaqueGroups) { group.render(this); } } override renderTranslucent(): void { const model = this.model; for (const group of model.translucentGroups) { group.render(this); } } override updateAnimations(dt: number): void { const model = this.model; const sequenceId = this.sequence; if (sequenceId !== -1) { const sequence = model.sequences[sequenceId]; const interval = sequence.interval; const frameTime = dt * 1000; this.frame += frameTime; this.counter += frameTime; this.allowParticleSpawn = true; if (this.frame >= interval[1]) { if (this.sequenceLoopMode === 2 || (this.sequenceLoopMode === 0 && sequence.nonLooping === 0)) { this.frame = interval[0]; this.resetEventEmitters(); } else { this.frame = interval[1]; this.counter -= frameTime; this.allowParticleSpawn = false; } this.sequenceEnded = true; } else { this.sequenceEnded = false; } } const forced = this.forced; if (sequenceId !== -1 || forced) { // Update the nodes this.updateNodes(dt, forced); // Update the bone texture. this.updateBoneTexture(); // Update the batches this.updateBatches(forced); } this.forced = false; } /** * Set the team color of this instance. */ setTeamColor(id: number): this { this.teamColor = id; return this; } /** * Set the vertex color of this instance. */ setVertexColor(color: Float32Array | number[]): this { this.vertexColor.set(color); return this; } /** * Set the sequence of this instance. */ setSequence(id: number): this { const model = this.model; const sequences = model.sequences; this.sequence = id; if (id < 0 || id > sequences.length - 1) { this.sequence = -1; this.frame = 0; this.allowParticleSpawn = false; } else { this.frame = sequences[id].interval[0]; } this.resetEventEmitters(); this.resetAttachments(); this.forced = true; return this; } override getBounds(): Bounds { const model = this.model; if (this.sequence === -1) { return model.bounds; } const bounds = model.sequences[this.sequence].bounds; if (bounds.r === 0) { return model.bounds; } return bounds; } /** * Set the sequence loop mode. * 0 to never loop, 1 to loop based on the model, and 2 to always loop. */ setSequenceLoopMode(mode: number): this { this.sequenceLoopMode = mode; return this; } /** * Get an attachment node. */ getAttachment(id: number): SkeletalNode | undefined { const model = this.model; const attachment = model.attachments[id]; if (attachment) { return this.nodes[attachment.index]; } return; } resetEventEmitters(): void { for (const emitter of this.eventObjectEmitters) { emitter.lastValue = 0; } } resetAttachments(): void { for (const attachment of this.attachments) { attachment.internalInstance.hide(); } } } ================================================ FILE: src/viewer/handlers/mdx/node.ts ================================================ import { quat } from 'gl-matrix'; import { SkeletalNode } from '../../skeletalnode'; /** * An MDX node. */ export default class MdxNode extends SkeletalNode { override convertBasis(rotation: quat): void { quat.rotateY(rotation, rotation, -Math.PI / 2); quat.rotateX(rotation, rotation, -Math.PI / 2); } } ================================================ FILE: src/viewer/handlers/mdx/particle.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { VEC3_UNIT_Z } from '../../../common/gl-matrix-addon'; import { randomInRange } from '../../../common/math'; import Scene from '../../scene'; import EmittedObject from '../../emittedobject'; import ParticleEmitterObject from './particleemitterobject'; import MdxModelInstance from './modelinstance'; import ParticleEmitter from './particleemitter'; import MdxModel from './model'; const rotationHeap = quat.create(); const velocityHeap = vec3.create(); const latitudeHeap = new Float32Array(1); // const longitudeHeap = new Float32Array(1); const lifeSpanHeap = new Float32Array(1); const gravityHeap = new Float32Array(1); const speedHeap = new Float32Array(1); /** * A spawned model particle. */ export default class Particle extends EmittedObject { internalInstance: MdxModelInstance; velocity = vec3.create(); gravity = 0; constructor(emitter: ParticleEmitter) { super(emitter); const emitterObject = emitter.emitterObject; const model = emitterObject.internalModel; this.internalInstance = model.addInstance(); } bind(): void { const emitter = this.emitter; const instance = emitter.instance; const sequence = instance.sequence; const frame = instance.frame; const counter = instance.counter; const scene = instance.scene; const emitterObject = emitter.emitterObject; const node = instance.nodes[emitterObject.index]; const internalInstance = this.internalInstance; const scale = node.worldScale; const velocity = this.velocity; emitterObject.getLatitude(latitudeHeap, sequence, frame, counter); // emitterObject.getLongitude(longitudeHeap, sequence, frame, counter); emitterObject.getLifeSpan(lifeSpanHeap, sequence, frame, counter); emitterObject.getGravity(gravityHeap, sequence, frame, counter); emitterObject.getSpeed(speedHeap, sequence, frame, counter); this.health = lifeSpanHeap[0]; this.gravity = gravityHeap[0] * scale[2]; // Local rotation quat.identity(rotationHeap); quat.rotateZ(rotationHeap, rotationHeap, randomInRange(-Math.PI, Math.PI)); quat.rotateY(rotationHeap, rotationHeap, randomInRange(-latitudeHeap[0], latitudeHeap[0])); vec3.transformQuat(velocity, VEC3_UNIT_Z, rotationHeap); // World rotation vec3.transformQuat(velocity, velocity, node.worldRotation); // Apply speed vec3.scale(velocity, velocity, speedHeap[0]); // Apply the parent's scale vec3.mul(velocity, velocity, scale); internalInstance.setScene(scene); internalInstance.setSequence(0); internalInstance.setTransformation(node.worldLocation, quat.setAxisAngle(rotationHeap, VEC3_UNIT_Z, randomInRange(0, Math.PI * 2)), node.worldScale); internalInstance.show(); } update(dt: number): void { const internalInstance = this.internalInstance; this.health -= dt; if (this.health > 0) { const velocity = this.velocity; velocity[2] -= this.gravity * dt; internalInstance.move(vec3.scale(velocityHeap, velocity, dt)); } else { internalInstance.hide(); } } } ================================================ FILE: src/viewer/handlers/mdx/particle2.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { VEC3_UNIT_Z } from '../../../common/gl-matrix-addon'; import { degToRad, randomInRange } from '../../../common/math'; import EmittedObject from '../../emittedobject'; import ParticleEmitter2Object from './particleemitter2object'; import ParticleEmitter2 from './particleemitter2'; import MdxModelInstance from './modelinstance'; const rotationHeap = quat.create(); const widthHeap = new Float32Array(1); const lengthHeap = new Float32Array(1); const latitudeHeap = new Float32Array(1); const variationHeap = new Float32Array(1); const speedHeap = new Float32Array(1); const gravityHeap = new Float32Array(1); /** * A type 2 particle. */ export default class Particle2 extends EmittedObject { tail = 0; gravity = 0; location = vec3.create(); velocity = vec3.create(); scale = vec3.create(); facing = 0; // XYQuad bind(tail: number): void { const emitter = this.emitter; const instance = emitter.instance; const sequence = instance.sequence; const frame = instance.frame; const counter = instance.counter; const emitterObject = emitter.emitterObject; emitterObject.getWidth(widthHeap, sequence, frame, counter); emitterObject.getLength(lengthHeap, sequence, frame, counter); emitterObject.getLatitude(latitudeHeap, sequence, frame, counter); emitterObject.getVariation(variationHeap, sequence, frame, counter); emitterObject.getSpeed(speedHeap, sequence, frame, counter); emitterObject.getGravity(gravityHeap, sequence, frame, counter); const node = emitter.node; const pivot = node.pivot; const scale = node.worldScale; const width = widthHeap[0] * 0.5; const length = lengthHeap[0] * 0.5; const latitude = degToRad(latitudeHeap[0]); const variation = variationHeap[0]; const speed = speedHeap[0]; const location = this.location; const velocity = this.velocity; this.health = emitterObject.lifeSpan; this.tail = tail; this.gravity = gravityHeap[0] * scale[2]; vec3.copy(this.scale, scale); // Local location location[0] = pivot[0] + randomInRange(-width, width); location[1] = pivot[1] + randomInRange(-length, length); location[2] = pivot[2]; // World location if (!emitterObject.modelSpace) { vec3.transformMat4(location, location, node.worldMatrix); } // Local rotation quat.identity(rotationHeap); quat.rotateZ(rotationHeap, rotationHeap, Math.PI / 2); quat.rotateY(rotationHeap, rotationHeap, randomInRange(-latitude, latitude)); // If this is not a line emitter, emit in a sphere rather than a circle. if (!emitterObject.lineEmitter) { quat.rotateX(rotationHeap, rotationHeap, randomInRange(-latitude, latitude)); } // World rotation if (!emitterObject.modelSpace) { quat.mul(rotationHeap, node.worldRotation, rotationHeap); } // Apply the rotation vec3.transformQuat(velocity, VEC3_UNIT_Z, rotationHeap); // Apply speed vec3.scale(velocity, velocity, speed * (1 + randomInRange(-variation, variation))); // Apply the parent's scale if (!emitterObject.modelSpace) { vec3.mul(velocity, velocity, scale); } // XY particles are rotated to face their velocity on the XY plane. if (emitterObject.xYQuad) { this.facing = Math.atan2(velocity[1], velocity[0]) - Math.PI + Math.PI / 8; } } update(dt: number): void { this.health -= dt; if (this.health > 0) { const location = this.location; const velocity = this.velocity; velocity[2] -= this.gravity * dt; location[0] += velocity[0] * dt; location[1] += velocity[1] * dt; location[2] += velocity[2] * dt; } } } ================================================ FILE: src/viewer/handlers/mdx/particleemitter.ts ================================================ import ParticleEmitterObject from './particleemitterobject'; import MdxModelInstance from './modelinstance'; import MdxEmitter from './emitter'; import Particle from './particle'; const emissionRateHeap = new Float32Array(1); /** * An MDX particle emitter. */ export default class ParticleEmitter extends MdxEmitter { updateEmission(dt: number): void { const instance = this.instance; if (instance.allowParticleSpawn) { const emitterObject = this.emitterObject; emitterObject.getEmissionRate(emissionRateHeap, instance.sequence, instance.frame, instance.counter); this.currentEmission += emissionRateHeap[0] * dt; } } emit(): void { this.emitObject(); } createObject(): Particle { return new Particle(this); } } ================================================ FILE: src/viewer/handlers/mdx/particleemitter2.ts ================================================ import ParticleEmitter2Object from './particleemitter2object'; import MdxModelInstance from './modelinstance'; import MdxNode from './node'; import MdxEmitter from './emitter'; import Particle2 from './particle2'; const emissionRateHeap = new Float32Array(1); /** * An MDX particle emitter type 2. */ export default class ParticleEmitter2 extends MdxEmitter { node: MdxNode; lastEmissionKey = -1; constructor(instance: MdxModelInstance, emitterObject: ParticleEmitter2Object) { super(instance, emitterObject); this.node = instance.nodes[emitterObject.index]; } updateEmission(dt: number): void { const instance = this.instance; if (instance.allowParticleSpawn) { const emitterObject = this.emitterObject; const keyframe = emitterObject.getEmissionRate(emissionRateHeap, instance.sequence, instance.frame, instance.counter); if (emitterObject.squirt) { if (keyframe !== this.lastEmissionKey) { this.currentEmission += emissionRateHeap[0]; } this.lastEmissionKey = keyframe; } else { this.currentEmission += emissionRateHeap[0] * dt; } } } emit(): void { const emitterObject = this.emitterObject; if (emitterObject.head) { this.emitObject(0); } if (emitterObject.tail) { this.emitObject(1); } } createObject(): Particle2 { return new Particle2(this); } } ================================================ FILE: src/viewer/handlers/mdx/particleemitter2object.ts ================================================ import MdlxParticleEmitter2, { Flags, HeadOrTail } from '../../../parsers/mdlx/particleemitter2'; import Texture from '../../texture'; import MdxModel from './model'; import GenericObject from './genericobject'; import { emitterFilterMode } from './filtermode'; import replaceableIds from './replaceableids'; import { EMITTER_PARTICLE2, SETTING_PARTICLES_HIGH } from './geometryemitterfuncs'; import MdxTexture from './texture'; import { WrapMode } from '../../../parsers/mdlx/texture'; /** * An MDX particle emitter type 2. */ export default class ParticleEmitter2Object extends GenericObject { geometryEmitterType = EMITTER_PARTICLE2; width: number; length: number; speed: number; latitude: number; gravity: number; emissionRate: number; squirt: number; lifeSpan: number; variation: number; tailLength: number; timeMiddle: number; columns: number; rows: number; teamColored = 0; internalTexture: MdxTexture | null = null; replaceableId: number; textureId: number; head: boolean; tail: boolean; cellWidth: number; cellHeight: number; colors: Float32Array[] = []; scaling: Float32Array; intervals: Float32Array[]; filterMode: number; blendSrc: number; blendDst: number; priorityPlane: number; lineEmitter: number; unfogged: number; modelSpace: number; xYQuad: number; /** * Even if the internal texture isn't loaded, it's fine to run emitters based on this emitter object. * * The particles will simply be black. */ ok = true; constructor(model: MdxModel, emitter: MdlxParticleEmitter2, index: number) { super(model, emitter, index); this.width = emitter.width; this.length = emitter.length; this.speed = emitter.speed; this.latitude = emitter.latitude; this.gravity = emitter.gravity; this.emissionRate = emitter.emissionRate * SETTING_PARTICLES_HIGH; this.squirt = emitter.squirt; this.lifeSpan = emitter.lifeSpan; this.variation = emitter.variation; this.tailLength = emitter.tailLength; this.timeMiddle = emitter.timeMiddle; const flags = emitter.flags; this.lineEmitter = flags & Flags.LineEmitter; this.unfogged = flags & Flags.Unfogged; this.modelSpace = flags & Flags.ModelSpace; this.xYQuad = flags & Flags.XYQuad; const replaceableId = emitter.replaceableId; this.columns = emitter.columns; this.rows = emitter.rows; if (replaceableId === 1 || replaceableId === 2) { this.teamColored = 1; } else if (replaceableId > 2) { const texturesExt = model.reforged ? '.dds' : '.blp'; this.internalTexture = new MdxTexture(replaceableId, WrapMode.RepeatBoth); model.viewer.load(`ReplaceableTextures\\${replaceableIds[replaceableId]}${texturesExt}`, model.pathSolver, model.solverParams) .then((texture) => { if (texture) { (this.internalTexture).texture = texture; } }); } this.replaceableId = emitter.replaceableId; this.textureId = emitter.textureId; const headOrTail = emitter.headOrTail; this.head = (headOrTail === HeadOrTail.Head || headOrTail === HeadOrTail.Both); this.tail = (headOrTail === HeadOrTail.Tail || headOrTail === HeadOrTail.Both); this.cellWidth = 1 / emitter.columns; this.cellHeight = 1 / emitter.rows; const colors = emitter.segmentColors; const alpha = emitter.segmentAlphas; for (let i = 0; i < 3; i++) { const color = colors[i]; this.colors[i] = new Float32Array([color[0], color[1], color[2], alpha[i] / 255]); } this.scaling = emitter.segmentScaling; const headIntervals = emitter.headIntervals; const tailIntervals = emitter.tailIntervals; // Change to Float32Array instead of Uint32Array to be able to pass the intervals directly using uniform3fv(). this.intervals = [ new Float32Array(headIntervals[0]), new Float32Array(headIntervals[1]), new Float32Array(tailIntervals[0]), new Float32Array(tailIntervals[1]), ]; const blendModes = emitterFilterMode(emitter.filterMode, this.model.viewer.gl); this.filterMode = emitter.filterMode; this.blendSrc = blendModes[0]; this.blendDst = blendModes[1]; this.priorityPlane = emitter.priorityPlane; } getWidth(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2N', sequence, frame, counter, this.width); } getLength(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2W', sequence, frame, counter, this.length); } getSpeed(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2S', sequence, frame, counter, this.speed); } getLatitude(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2L', sequence, frame, counter, this.latitude); } getGravity(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2G', sequence, frame, counter, this.gravity); } getEmissionRate(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2E', sequence, frame, counter, this.emissionRate); } getVariation(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2R', sequence, frame, counter, this.variation); } override getVisibility(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KP2V', sequence, frame, counter, 1); } } ================================================ FILE: src/viewer/handlers/mdx/particleemitterobject.ts ================================================ import ParticleEmitter from '../../../parsers/mdlx/particleemitter'; import MdxModel from './model'; import GenericObject from './genericobject'; /** * An MDX particle emitter. */ export default class ParticleEmitterObject extends GenericObject { internalModel: MdxModel | null = null; speed: number; latitude: number; longitude: number; lifeSpan: number; gravity: number; emissionRate: number; ok = false; constructor(model: MdxModel, emitter: ParticleEmitter, index: number) { super(model, emitter, index); this.speed = emitter.speed; this.latitude = emitter.latitude; this.longitude = emitter.longitude; this.lifeSpan = emitter.lifeSpan; this.gravity = emitter.gravity; this.emissionRate = emitter.emissionRate; model.viewer.load(emitter.path.replace(/\\/g, '/').toLowerCase().replace('.mdl', '.mdx'), model.pathSolver, model.solverParams) .then((model) => { if (model) { this.internalModel = model; this.ok = true; } }); } getSpeed(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPES', sequence, frame, counter, this.speed); } getLatitude(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPLTV', sequence, frame, counter, this.latitude); } getLongitude(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPLN', sequence, frame, counter, this.longitude); } getLifeSpan(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPEL', sequence, frame, counter, this.lifeSpan); } getGravity(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPEG', sequence, frame, counter, this.gravity); } getEmissionRate(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPEE', sequence, frame, counter, this.emissionRate); } override getVisibility(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KPEV', sequence, frame, counter, 1); } } ================================================ FILE: src/viewer/handlers/mdx/replaceableids.ts ================================================ export default { 1: 'TeamColor/TeamColor00', 2: 'TeamGlow/TeamGlow00', 11: 'Cliff/Cliff0', 21: '', // Used by all cursor models (HumanCursor, OrcCursor, UndeadCursor, NightElfCursor) 31: 'LordaeronTree/LordaeronSummerTree', 32: 'AshenvaleTree/AshenTree', 33: 'BarrensTree/BarrensTree', 34: 'NorthrendTree/NorthTree', 35: 'Mushroom/MushroomTree', 36: 'RuinsTree/RuinsTree', 37: 'OutlandMushroomTree/MushroomTree', }; ================================================ FILE: src/viewer/handlers/mdx/ribbon.ts ================================================ import { vec3 } from 'gl-matrix'; import EmittedObject from '../../emittedobject'; import RibbonEmitterObject from './ribbonemitterobject'; import MdxModelInstance from './modelinstance'; import RibbonEmitter from './ribbonemitter'; const belowHeap = vec3.create(); const aboveHeap = vec3.create(); const colorHeap = new Float32Array(3); const alphaHeap = new Float32Array(1); const slotHeap = new Uint32Array(1); /** * A ribbon. */ export default class Ribbon extends EmittedObject { vertices = new Float32Array(6); color = new Uint8Array(4); slot = 0; prev: Ribbon | null = null; next: Ribbon | null = null; bind(): void { const emitter = this.emitter; const instance = emitter.instance; const sequence = instance.sequence; const frame = instance.frame; const counter = instance.counter; const emitterObject = emitter.emitterObject; const node = instance.nodes[emitterObject.index]; const [x, y, z] = node.pivot; const worldMatrix = node.worldMatrix; const vertices = this.vertices; this.health = emitter.emitterObject.lifeSpan; emitterObject.getHeightBelow(belowHeap, sequence, frame, counter); emitterObject.getHeightAbove(aboveHeap, sequence, frame, counter); belowHeap[1] = y - belowHeap[0]; belowHeap[0] = x; belowHeap[2] = z; aboveHeap[1] = y + aboveHeap[0]; aboveHeap[0] = x; aboveHeap[2] = z; vec3.transformMat4(belowHeap, belowHeap, worldMatrix); vec3.transformMat4(aboveHeap, aboveHeap, worldMatrix); vertices[0] = aboveHeap[0]; vertices[1] = aboveHeap[1]; vertices[2] = aboveHeap[2]; vertices[3] = belowHeap[0]; vertices[4] = belowHeap[1]; vertices[5] = belowHeap[2]; } update(dt: number): void { this.health -= dt; if (this.health > 0) { const emitter = this.emitter; const instance = emitter.instance; const sequence = instance.sequence; const frame = instance.frame; const counter = instance.counter; const emitterObject = emitter.emitterObject; const color = this.color; const vertices = this.vertices; const gravity = emitterObject.gravity * dt * dt; emitterObject.getColor(colorHeap, sequence, frame, counter); emitterObject.getAlpha(alphaHeap, sequence, frame, counter); emitterObject.getTextureSlot(slotHeap, sequence, frame, counter); vertices[1] -= gravity; vertices[4] -= gravity; color[0] = colorHeap[0] * 255; color[1] = colorHeap[1] * 255; color[2] = colorHeap[2] * 255; color[3] = alphaHeap[0] * 255; this.slot = slotHeap[0]; } } } ================================================ FILE: src/viewer/handlers/mdx/ribbonemitter.ts ================================================ import RibbonEmitterObject from './ribbonemitterobject'; import MdxModelInstance from './modelinstance'; import MdxEmitter from './emitter'; import Ribbon from './ribbon'; /** * A ribbon emitter. */ export default class RibbonEmitter extends MdxEmitter { first: Ribbon | null = null; last: Ribbon | null = null; updateEmission(dt: number): void { const instance = this.instance; if (instance.allowParticleSpawn) { const emitterObject = this.emitterObject; // It doesn't make sense to emit more than 1 ribbon at the same time. this.currentEmission += emitterObject.emissionRate * dt; } } emit(): void { const ribbon = this.emitObject(); const last = this.last; if (last) { last.next = ribbon; ribbon.prev = last; } else { this.first = ribbon; } this.last = ribbon; } override kill(object: Ribbon): void { super.kill(object); const prev = object.prev; const next = object.next; if (object === this.first) { this.first = next; } if (object === this.last) { this.first = null; this.last = null; } if (prev) { prev.next = next; } if (next) { next.prev = prev; } object.prev = null; object.next = null; } createObject(): Ribbon { return new Ribbon(this); } } ================================================ FILE: src/viewer/handlers/mdx/ribbonemitterobject.ts ================================================ import RibbonEmitter from '../../../parsers/mdlx/ribbonemitter'; import MdxModel from './model'; import GenericObject from './genericobject'; import Layer from './layer'; import { EMITTER_RIBBON, SETTING_PARTICLES_HIGH } from './geometryemitterfuncs'; /** * An MDX ribbon emitter. */ export default class RibbonEmitterObject extends GenericObject { geometryEmitterType = EMITTER_RIBBON; layer: Layer; heightAbove: number; heightBelow: number; alpha: number; color: Float32Array; lifeSpan: number; textureSlot: number; emissionRate: number; gravity: number; columns: number; rows: number; /** * Even if the internal texture isn't loaded, it's fine to run emitters based on this emitter object. * * The ribbons will simply be black. */ ok = true; constructor(model: MdxModel, emitter: RibbonEmitter, index: number) { super(model, emitter, index); this.layer = model.materials[emitter.materialId].layers[0]; this.heightAbove = emitter.heightAbove; this.heightBelow = emitter.heightBelow; this.alpha = emitter.alpha; this.color = emitter.color; this.lifeSpan = emitter.lifeSpan; this.textureSlot = emitter.textureSlot; this.emissionRate = emitter.emissionRate * SETTING_PARTICLES_HIGH; this.gravity = emitter.gravity; this.columns = emitter.columns; this.rows = emitter.rows; } getHeightBelow(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KRHB', sequence, frame, counter, this.heightBelow); } getHeightAbove(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KRHA', sequence, frame, counter, this.heightAbove); } getTextureSlot(out: Uint32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KRTX', sequence, frame, counter, 0); } getColor(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KRCO', sequence, frame, counter, this.color); } getAlpha(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getScalarValue(out, 'KRAL', sequence, frame, counter, this.alpha); } /** * Ribbon emitters specifically have an alpha. * * When this alpha is 0, naturally ribbons shouldn't be emitted. * * Therefore first check the alpha animation, and only if it's >0 check the visibility animation. */ override getVisibility(out: Float32Array, sequence: number, frame: number, counter: number): number { const keyframe = this.getAlpha(out, sequence,frame,counter); if (out[0] === 0) { return keyframe; } return this.getScalarValue(out, 'KRVS', sequence, frame, counter, 1); } } ================================================ FILE: src/viewer/handlers/mdx/sd.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { lerp, hermite, bezier } from '../../../common/math'; import { Animation, UintAnimation, FloatAnimation, Vector3Animation, InterpolationType } from '../../../parsers/mdlx/animations'; import MdxModel from './model'; /** * Animated data for a specific sequence. */ class SdSequence { sd: Sd; start: number; end: number; frames: number[] = []; values: (Uint32Array | Float32Array)[] = []; inTans: (Uint32Array | Float32Array)[] = []; outTans: (Uint32Array | Float32Array)[] = []; constant = false; constructor(sd: Sd, start: number, end: number, animation: Animation, isGlobal: boolean) { this.sd = sd; this.start = start; this.end = end; const interpolationType = sd.interpolationType; const frames = animation.frames; const values = animation.values; const inTans = animation.inTans; const outTans = animation.outTans; const defval = sd.defval; // When using a global sequence, where the first key is outside of the sequence's length, it becomes its constant value. // When having one key in the sequence's range, and one key outside of it, results seem to be non-deterministic. // Sometimes the second key is used too, sometimes not. // It also differs depending where the model is viewed - the WE previewer, the WE itself, or the game. // All three show different results, none of them make sense. // Therefore, only handle the case where the first key is outside. // This fixes problems spread over many models, e.g. HeroMountainKing (compare in WE and in Magos). if (isGlobal && frames[0] > end) { this.frames[0] = frames[0]; this.values[0] = values[0]; } // Go over the keyframes, and add all of the ones that are in this sequence (start <= frame <= end). for (let i = 0, l = frames.length; i < l; i++) { const frame = frames[i]; if (frame >= start && frame <= end) { this.frames.push(frame); this.values.push(values[i]); if (interpolationType > 1) { this.inTans.push(inTans[i]); this.outTans.push(outTans[i]); } } } const tracksCount = this.frames.length; if (tracksCount === 0) { // If there are no keys, use the default value directly. this.constant = true; this.frames[0] = start; this.values[0] = defval; } else if (tracksCount === 1) { // If there's only one key, use it directly. this.constant = true; } else { const firstValue = this.values[0]; // If all of the values in this sequence are the same, might as well make it constant. this.constant = this.values.every((value) => firstValue.every((element: number, index: number) => element === value[index])); } } getValue(out: Uint32Array | Float32Array, frame: number): number { const frames = this.frames; const length = frames.length; // Fixed implementation copied directly from Retera's code. Thank you! if (this.constant || frame < this.start) { this.sd.copy(out, this.values[0]); return -1; } else { let startFrameIndex = -1; let endFrameIndex = -1; const lengthLessOne = length - 1; if ((frame < this.frames[0]) || (frame >= this.frames[lengthLessOne])) { startFrameIndex = lengthLessOne; endFrameIndex = 0; } else { for (let i = 1; i < length; i++) { if (this.frames[i] > frame) { startFrameIndex = i - 1; endFrameIndex = i; break; } } } let startFrame = this.frames[startFrameIndex]; const endFrame = this.frames[endFrameIndex]; let timeBetweenFrames = endFrame - startFrame; if (timeBetweenFrames < 0) { timeBetweenFrames += (this.end - this.start); if (frame < startFrame) { startFrame = endFrame; } } const t = ((timeBetweenFrames) == 0 ? 0 : ((frame - startFrame) / timeBetweenFrames)); this.sd.interpolate(out, this.values, this.inTans, this.outTans, startFrameIndex, endFrameIndex, t); return startFrameIndex; } } } const forcedInterpMap = { KLAV: InterpolationType.DontInterp, KATV: InterpolationType.DontInterp, KPEV: InterpolationType.DontInterp, KP2V: InterpolationType.DontInterp, KRVS: InterpolationType.DontInterp, }; const floatDefval = new Float32Array(1); const uintDefval = new Uint32Array(1); const visibilityDefval = new Float32Array([1]); const translationDefval = vec3.create(); const rotationDefval = quat.create(); const scaleDefval = vec3.fromValues(1, 1, 1); const alphaDefval = visibilityDefval; const colorDefval = translationDefval; const defVals = { // LAYS KMTF: floatDefval, KMTA: alphaDefval, // TXAN KTAT: translationDefval, KTAR: rotationDefval, KTAS: scaleDefval, // GEOA KGAO: alphaDefval, KGAC: colorDefval, // LITE KLAS: floatDefval, KLAE: floatDefval, KLAC: colorDefval, KLAI: floatDefval, KLBI: floatDefval, KLBC: colorDefval, KLAV: visibilityDefval, // ATCH KATV: visibilityDefval, // PREM KPEE: floatDefval, KPEG: floatDefval, KPLN: floatDefval, KPLT: floatDefval, KPEL: floatDefval, KPES: floatDefval, KPEV: visibilityDefval, // PRE2 KP2S: floatDefval, KP2R: floatDefval, KP2L: floatDefval, KP2G: floatDefval, KP2E: floatDefval, KP2N: floatDefval, KP2W: floatDefval, KP2V: visibilityDefval, // RIBB KRHA: floatDefval, KRHB: floatDefval, KRAL: new Float32Array([0]), // Ribbon emitter alphas default to 0 rather than 1. KRCO: colorDefval, KRTX: floatDefval, KRVS: visibilityDefval, // CAMS KCTR: translationDefval, KTTR: translationDefval, KCRL: uintDefval, // NODE KGTR: translationDefval, KGRT: rotationDefval, KGSC: scaleDefval, }; /** * Animated data. */ export abstract class Sd { defval: Float32Array | Uint32Array; model: MdxModel; name: string; globalSequence: SdSequence | null = null; sequences: SdSequence[] = []; interpolationType: InterpolationType; abstract copy(out: Uint32Array | Float32Array | vec3 | quat, value: Uint32Array | Float32Array | vec3 | quat): void; abstract interpolate(out: Uint32Array | Float32Array | vec3 | quat, values: (Uint32Array | Float32Array | vec3 | quat)[], inTans: (Uint32Array | Float32Array | vec3 | quat)[], outTans: (Uint32Array | Float32Array | vec3 | quat)[], start: number, end: number, t: number): void; constructor(model: MdxModel, animation: Animation) { const globalSequences = model.globalSequences; const globalSequenceId = animation.globalSequenceId; const forcedInterp = forcedInterpMap[animation.name]; this.model = model; this.name = animation.name; this.defval = defVals[animation.name]; // Allow to force an interpolation type. // The game seems to do this with visibility tracks, where the type is forced to None. // It came up as a bug report by a user who used the wrong interpolation type. this.interpolationType = forcedInterp !== undefined ? forcedInterp : animation.interpolationType; if (globalSequenceId !== -1 && globalSequences) { this.globalSequence = new SdSequence(this, 0, globalSequences[globalSequenceId], animation, true); } else { for (const sequence of model.sequences) { const interval = sequence.interval; this.sequences.push(new SdSequence(this, interval[0], interval[1], animation, false)); } } } getValue(out: Uint32Array | Float32Array, sequence: number, frame: number, counter: number): number { if (this.globalSequence) { return this.globalSequence.getValue(out, counter % this.globalSequence.end); } return this.sequences[sequence].getValue(out, frame); } isVariant(sequence: number): boolean { if (this.globalSequence) { return !this.globalSequence.constant; } else { return !this.sequences[sequence].constant; } } } /** * A scalar animation. */ export class ScalarSd extends Sd { copy(out: T, value: T): void { out[0] = value[0]; } interpolate(out: T, values: T[], inTans: T[], outTans: T[], start: number, end: number, t: number): void { const interpolationType = this.interpolationType; const startValue = values[start][0]; if (interpolationType === InterpolationType.DontInterp) { out[0] = startValue; } else if (interpolationType === InterpolationType.Linear) { out[0] = lerp(startValue, values[end][0], t); } else if (interpolationType === InterpolationType.Hermite) { out[0] = hermite(startValue, outTans[start][0], inTans[end][0], values[end][0], t); } else if (interpolationType === InterpolationType.Bezier) { out[0] = bezier(startValue, outTans[start][0], inTans[end][0], values[end][0], t); } } } /** * A vector animation. */ export class VectorSd extends Sd { copy(out: vec3, value: vec3): void { vec3.copy(out, value); } interpolate(out: vec3, values: vec3[], inTans: vec3[], outTans: vec3[], start: number, end: number, t: number): void { const interpolationType = this.interpolationType; if (interpolationType === InterpolationType.DontInterp) { vec3.copy(out, values[start]); } else if (interpolationType === InterpolationType.Linear) { vec3.lerp(out, values[start], values[end], t); } else if (interpolationType === InterpolationType.Hermite) { vec3.hermite(out, values[start], outTans[start], inTans[end], values[end], t); } else if (interpolationType === InterpolationType.Bezier) { vec3.bezier(out, values[start], outTans[start], inTans[end], values[end], t); } } } /** * A quaternion animation. */ export class QuatSd extends Sd { copy(out: quat, value: quat): void { quat.copy(out, value); } interpolate(out: quat, values: quat[], inTans: quat[], outTans: quat[], start: number, end: number, t: number): void { const interpolationType = this.interpolationType; if (interpolationType === InterpolationType.DontInterp) { quat.copy(out, values[start]); } else if (interpolationType === InterpolationType.Linear) { quat.slerp(out, values[start], values[end], t); } else if (interpolationType === InterpolationType.Hermite || interpolationType === InterpolationType.Bezier) { quat.sqlerp(out, values[start], outTans[start], inTans[end], values[end], t); } } } export function createTypedSd(model: MdxModel, animation: Animation): ScalarSd | VectorSd | QuatSd { if (animation instanceof UintAnimation || animation instanceof FloatAnimation) { return new ScalarSd(model, animation); } else if (animation instanceof Vector3Animation) { return new VectorSd(model, animation); } else { return new QuatSd(model, animation); } } ================================================ FILE: src/viewer/handlers/mdx/sequence.ts ================================================ import MdlxSequence from '../../../parsers/mdlx/sequence'; import Bounds from '../../bounds'; /** * An MDX sequence. */ export default class Sequence { name: string; interval: Uint32Array; nonLooping: number; rarity: number; bounds: Bounds; constructor(sequence: MdlxSequence) { this.name = sequence.name; this.interval = sequence.interval; this.nonLooping = sequence.nonLooping; this.rarity = sequence.rarity; this.bounds = new Bounds(); const extent = sequence.extent; this.bounds.fromExtents(extent.min, extent.max); } } ================================================ FILE: src/viewer/handlers/mdx/setupgeosets.ts ================================================ import MdlxGeoset from '../../../parsers/mdlx/geoset'; import MdxModel from './model'; import Geoset from './geoset'; import { SkinningType, Batch } from './batch'; export default function setupGeosets(model: MdxModel, geosets: MdlxGeoset[]): void { if (geosets.length > 0) { const gl = model.viewer.gl; let positionBytes = 0; let normalBytes = 0; let uvBytes = 0; let tangentBytes = 0; let skinBytes = 0; let faceBytes = 0; const skinTypes: SkinningType[] = []; for (let i = 0, l = geosets.length; i < l; i++) { const geoset = geosets[i]; if (geoset.lod === 0 || geoset.lod === -1) { const vertices = geoset.vertices.length / 3; positionBytes += vertices * 12; normalBytes += vertices * 12; uvBytes += geoset.uvSets.length * vertices * 8; if (geoset.tangents.length) { tangentBytes += vertices * 16; } if (geoset.skin.length) { skinBytes += vertices * 8; skinTypes[i] = SkinningType.Skin; } else { let biggestGroup = 0; for (const group of geoset.matrixGroups) { if (group > biggestGroup) { biggestGroup = group; } } if (biggestGroup > 4) { skinBytes += vertices * 9; skinTypes[i] = SkinningType.ExtendedVertexGroups; } else { skinBytes += vertices * 5; skinTypes[i] = SkinningType.VertexGroups; } } faceBytes += geoset.faces.byteLength; } } let positionOffset = 0; let normalOffset = positionOffset + positionBytes; let uvOffset = normalOffset + normalBytes; let tangentOffset = uvOffset + uvBytes; let skinOffset = tangentOffset + tangentBytes; let faceOffset = 0; let SkinTypedArray: typeof Uint8Array | typeof Uint16Array = Uint8Array; let skinGlType = gl.UNSIGNED_BYTE; if (model.bones.length > 255) { skinBytes *= 2; SkinTypedArray = Uint16Array; skinGlType = gl.UNSIGNED_SHORT; } model.skinDataType = skinGlType; model.bytesPerSkinElement = SkinTypedArray.BYTES_PER_ELEMENT; model.arrayBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, model.arrayBuffer); gl.bufferData(gl.ARRAY_BUFFER, skinOffset + skinBytes, gl.STATIC_DRAW); model.elementBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.elementBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, faceBytes, gl.STATIC_DRAW); for (let i = 0, l = geosets.length; i < l; i++) { const geoset = geosets[i]; if (geoset.lod === 0 || geoset.lod === -1) { const positions = geoset.vertices; const normals = geoset.normals; const uvSets = geoset.uvSets; const tangents = geoset.tangents; const faces = geoset.faces; let skin; const vertices = geoset.vertices.length / 3; const skinType = skinTypes[i]; if (skinType === SkinningType.Skin) { skin = geoset.skin; } else { const matrixIndices = geoset.matrixIndices; const vertexGroups = geoset.vertexGroups; const matrixGroups = []; let offset = 0; // Normally the shader supports up to 4 bones per vertex. // This is enough for almost every existing Warcraft 3 model. // That being said, there are a few models with geosets that need more, for example the Water Elemental. // These geosets use a different shader, which support up to 8 bones per vertex. let maxBones = 4; if (skinType === SkinningType.ExtendedVertexGroups) { maxBones = 8; } skin = new SkinTypedArray(vertices * (maxBones + 1)); // Slice the matrix groups. for (const size of geoset.matrixGroups) { matrixGroups.push(matrixIndices.subarray(offset, offset + size)); offset += size; } // Parse the skinning. for (let i = 0; i < vertices; i++) { const matrixGroup = matrixGroups[vertexGroups[i]]; offset = i * (maxBones + 1); // Somehow in some bad models a vertex group index refers to an invalid matrix group. // Such models are still loaded by the game. if (matrixGroup) { const bones = Math.min(matrixGroup.length, maxBones); for (let j = 0; j < bones; j++) { skin[offset + j] = matrixGroup[j] + 1; // 1 is added to diffrentiate between matrix 0, and no matrix. } skin[offset + maxBones] = bones; } } } const vGeoset = new Geoset(model, model.geosets.length, positionOffset, normalOffset, uvOffset, tangentOffset, skinOffset, faceOffset, vertices, faces.length, geoset.faceTypeGroups[0]); model.geosets.push(vGeoset); const material = model.materials[geoset.materialId]; const isHd = material.shader === 'Shader_HD_DefaultUnit'; if (isHd) { model.batches.push(new Batch(model.batches.length, vGeoset, material, skinType, true)); } else { for (const layer of material.layers) { model.batches.push(new Batch(model.batches.length, vGeoset, layer, skinType, false)); } } // Positions. gl.bufferSubData(gl.ARRAY_BUFFER, positionOffset, positions); positionOffset += positions.byteLength; // Normals. gl.bufferSubData(gl.ARRAY_BUFFER, normalOffset, normals); normalOffset += normals.byteLength; // Texture coordinates. for (const uvSet of uvSets) { gl.bufferSubData(gl.ARRAY_BUFFER, uvOffset, uvSet); uvOffset += uvSet.byteLength; } // Tangents. if (tangents.length) { gl.bufferSubData(gl.ARRAY_BUFFER, tangentOffset, tangents); tangentOffset += tangents.byteLength; } // Skin. gl.bufferSubData(gl.ARRAY_BUFFER, skinOffset, skin); skinOffset += skin.byteLength; // Faces. gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, faceOffset, faces); faceOffset += faces.byteLength; } } } } ================================================ FILE: src/viewer/handlers/mdx/setupgroups.ts ================================================ import MdxModel from './model'; import { Batch } from './batch'; import BatchGroup from './batchgroup'; import EmitterGroup from './emittergroup'; import GenericObject from './genericobject'; import ParticleEmitter2Object from './particleemitter2object'; import RibbonEmitterObject from './ribbonemitterobject'; import EventObjectEmitterObject from './eventobjectemitterobject'; function getPrio(object: Batch | ParticleEmitter2Object | RibbonEmitterObject | EventObjectEmitterObject): number { if (object instanceof Batch || object instanceof RibbonEmitterObject) { return object.layer.priorityPlane; } else if (object instanceof ParticleEmitter2Object) { return object.priorityPlane; } else { return 0; } } function matchingGroup(group: BatchGroup | EmitterGroup, object: Batch | ParticleEmitter2Object | RibbonEmitterObject | EventObjectEmitterObject): boolean { if (group instanceof BatchGroup) { return (object instanceof Batch) && (object.skinningType === group.skinningType) && (object.isHd === group.isHd); } else { // All of the emitter objects are generic objects. return (object instanceof GenericObject); } } function createMatchingGroup(model: MdxModel, object: Batch | ParticleEmitter2Object | RibbonEmitterObject | EventObjectEmitterObject): BatchGroup | EmitterGroup { if (object instanceof Batch) { return new BatchGroup(model, object.skinningType, object.isHd); } else { return new EmitterGroup(model); } } export default function setupGroups(model: MdxModel): void { const opaqueBatches = []; let translucentBatches = []; for (const batch of model.batches) { if (batch.layer.filterMode < 2) { opaqueBatches.push(batch); } else { translucentBatches.push(batch); } } const opaqueGroups = model.opaqueGroups; const translucentGroups = model.translucentGroups; let currentGroup = null; for (const object of opaqueBatches) { if (!currentGroup || !matchingGroup(currentGroup, object)) { currentGroup = createMatchingGroup(model, object); opaqueGroups.push(currentGroup); } currentGroup.objects.push(object.index); } // Sort the translucent batches based on filter mode. translucentBatches = translucentBatches.sort((a, b) => a.layer.filterMode - b.layer.filterMode); // Sort between all of the translucent batches and emitters based on their priority planes. // Event objects have no explicit priority planes, and default to 0. const objects = [...translucentBatches, ...model.eventObjects, ...model.particleEmitters2, ...model.ribbonEmitters].sort((a, b) => getPrio(a) - getPrio(b)); currentGroup = null; for (const object of objects) { if (object instanceof Batch || object.geometryEmitterType !== -1) { if (!currentGroup || !matchingGroup(currentGroup, object)) { currentGroup = createMatchingGroup(model, object); translucentGroups.push(currentGroup); } currentGroup.objects.push(object.index); } } } ================================================ FILE: src/viewer/handlers/mdx/shaders/hd.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; const shader = ` ${precision} uniform sampler2D u_diffuseMap; uniform sampler2D u_normalsMap; uniform sampler2D u_ormMap; uniform sampler2D u_emissiveMap; uniform sampler2D u_teamColorMap; uniform sampler2D u_environmentMap; uniform float u_filterMode; // uniform sampler2D u_lutMap; // uniform sampler2D u_envDiffuseMap; // uniform sampler2D u_envSpecularMap; varying vec2 v_uv; varying float v_layerAlpha; varying vec3 v_lightDir; varying vec3 v_eyeVec; varying vec3 v_normal; // varying vec3 v_lightDirWorld; #if defined(ONLY_TANGENTS) varying vec3 v_tangent; #endif vec3 decodeNormal() { vec2 xy = texture2D(u_normalsMap, v_uv).xy * 2.0 - 1.0; return vec3(xy, sqrt(1.0 - dot(xy, xy))); } const vec2 invAtan = vec2(0.1591, 0.3183); vec2 sampleEnvironmentMap(vec3 normal) { vec2 uv = vec2(atan(normal.x, normal.y), -asin(normal.z)); uv *= invAtan; uv += 0.5; return uv; } vec4 getDiffuseColor() { vec4 color = texture2D(u_diffuseMap, v_uv); // 1bit Alpha if (u_filterMode == 1.0 && color.a < 0.75) { discard; } return color; } vec4 getOrmColor() { return texture2D(u_ormMap, v_uv); } vec3 getEmissiveColor() { return texture2D(u_emissiveMap, v_uv).rgb; } vec3 getTeamColor() { return texture2D(u_teamColorMap, v_uv).rgb; } // const float PI = 3.14159265359; // const float RECIPROCAL_PI = 0.31830988618; // const float RECIPROCAL_PI2 = 0.15915494; // const float LN2 = 0.6931472; // const float ENV_LODS = 6.0; // vec4 SRGBtoLinear(vec4 srgb) { // vec3 linOut = pow(srgb.xyz, vec3(2.2)); // return vec4(linOut, srgb.w);; // } // vec4 RGBMToLinear(in vec4 value) { // float maxRange = 6.0; // return vec4(value.xyz * value.w * maxRange, 1.0); // } // vec3 linearToSRGB(vec3 color) { // return pow(color, vec3(1.0 / 2.2)); // } // // vec3 getNormal() { // // vec3 pos_dx = dFdx(vMPos.xyz); // // vec3 pos_dy = dFdy(vMPos.xyz); // // vec2 tex_dx = dFdx(vUv); // // vec2 tex_dy = dFdy(vUv); // // vec3 t = normalize(pos_dx * tex_dy.t - pos_dy * tex_dx.t); // // vec3 b = normalize(-pos_dx * tex_dy.s + pos_dy * tex_dx.s); // // mat3 tbn = mat3(t, b, normalize(vNormal)); // // vec3 n = texture2D(tNormal, vUv * uNormalUVScale).rgb * 2.0 - 1.0; // // n.xy *= uNormalScale; // // vec3 normal = normalize(tbn * n); // // // Get world normal from view normal (normalMatrix * normal) // // return normalize((vec4(normal, 0.0) * viewMatrix).xyz); // // } // vec3 specularReflection(vec3 specularEnvR0, vec3 specularEnvR90, float VdH) { // return specularEnvR0 + (specularEnvR90 - specularEnvR0) * pow(clamp(1.0 - VdH, 0.0, 1.0), 5.0); // } // float geometricOcclusion(float NdL, float NdV, float roughness) { // float r = roughness; // float attenuationL = 2.0 * NdL / (NdL + sqrt(r * r + (1.0 - r * r) * (NdL * NdL))); // float attenuationV = 2.0 * NdV / (NdV + sqrt(r * r + (1.0 - r * r) * (NdV * NdV))); // return attenuationL * attenuationV; // } // float microfacetDistribution(float roughness, float NdH) { // float roughnessSq = roughness * roughness; // float f = (NdH * roughnessSq - NdH) * NdH + 1.0; // return roughnessSq / (PI * f * f); // } // vec2 cartesianToPolar(vec3 n) { // vec2 uv; // uv.x = atan(n.z, n.x) * RECIPROCAL_PI2 + 0.5; // uv.y = asin(n.y) * RECIPROCAL_PI + 0.5; // return uv; // } // void getIBLContribution(inout vec3 diffuse, inout vec3 specular, float NdV, float roughness, vec3 n, vec3 reflection, vec3 diffuseColor, vec3 specularColor) { // vec3 brdf = SRGBtoLinear(texture2D(u_lutMap, vec2(NdV, roughness))).rgb; // vec3 diffuseLight = RGBMToLinear(texture2D(u_envDiffuseMap, sampleEnvironmentMap(n))).rgb; // // Sample 2 levels and mix between to get smoother degradation // float blend = roughness * ENV_LODS; // float level0 = floor(blend); // float level1 = min(ENV_LODS, level0 + 1.0); // blend -= level0; // // Sample the specular env map atlas depending on the roughness value // vec2 uvSpec = sampleEnvironmentMap(reflection); // uvSpec.y /= 2.0; // vec2 uv0 = uvSpec; // vec2 uv1 = uvSpec; // uv0 /= pow(2.0, level0); // uv0.y += 1.0 - exp(-LN2 * level0); // uv1 /= pow(2.0, level1); // uv1.y += 1.0 - exp(-LN2 * level1); // vec3 specular0 = RGBMToLinear(texture2D(u_envSpecularMap, uv0)).rgb; // vec3 specular1 = RGBMToLinear(texture2D(u_envSpecularMap, uv1)).rgb; // vec3 specularLight = mix(specular0, specular1, blend); // diffuse = diffuseLight * diffuseColor; // // Bit of extra reflection for smooth materials // float reflectivity = pow((1.0 - roughness), 2.0) * 0.05; // specular = specularLight * (specularColor * brdf.x + brdf.y + reflectivity); // // specular *= uEnvSpecular; // } // void PBR() { // vec4 baseDiffuseColor = getDiffuseColor(); // vec3 baseColor = baseDiffuseColor.rgb; // vec4 orm = getOrmColor(); // vec3 tc = getTeamColor(); // float tcFactor = getOrmColor().a; // if (tcFactor > 0.1) { // baseColor *= tc * tcFactor; // } // float roughness = clamp(orm.g, 0.04, 1.0); // float metallic = clamp(orm.b, 0.04, 1.0); // vec3 f0 = vec3(0.04); // vec3 diffuseColor = baseColor * (vec3(1.0) - f0) * (1.0 - metallic); // vec3 specularColor = mix(f0, baseColor, metallic); // vec3 specularEnvR0 = specularColor; // vec3 specularEnvR90 = vec3(clamp(max(max(specularColor.r, specularColor.g), specularColor.b) * 25.0, 0.0, 1.0)); // vec3 N = v_normal; // vec3 V = normalize(v_eyeVec); // vec3 L = normalize(v_lightDirWorld); // vec3 H = normalize(L + V); // vec3 reflection = normalize(reflect(-V, N)); // float NdL = clamp(dot(N, L), 0.001, 1.0); // float NdV = clamp(abs(dot(N, V)), 0.001, 1.0); // float NdH = clamp(dot(N, H), 0.0, 1.0); // float LdH = clamp(dot(L, H), 0.0, 1.0); // float VdH = clamp(dot(V, H), 0.0, 1.0); // vec3 F = specularReflection(specularEnvR0, specularEnvR90, VdH); // float G = geometricOcclusion(NdL, NdV, roughness); // float D = microfacetDistribution(roughness, NdH); // vec3 diffuseContrib = (1.0 - F) * (diffuseColor / PI); // vec3 specContrib = F * G * D / (4.0 * NdL * NdV); // // Shading based off lights // // vec3 color = NdL * uLightColor * (diffuseContrib + specContrib); // vec3 color = NdL * (diffuseContrib + specContrib); // // Calculate IBL lighting // vec3 diffuseIBL; // vec3 specularIBL; // getIBLContribution(diffuseIBL, specularIBL, NdV, roughness, N, reflection, diffuseColor, specularColor); // // Add IBL on top of color // color += specularIBL; // color *= orm.r; // color += getEmissiveColor(); // // Convert to sRGB to display // gl_FragColor.rgb = color; // gl_FragColor.a = baseDiffuseColor.a; // } void onlyDiffuse() { vec4 baseColor = getDiffuseColor(); vec3 tc = getTeamColor(); float tcFactor = getOrmColor().a; if (tcFactor > 0.1) { baseColor.rgb *= tc * tcFactor; } gl_FragColor = baseColor; } void onlyNormalMap() { gl_FragColor = vec4(decodeNormal(), 1.0); } void onlyOcclusion() { gl_FragColor = vec4(getOrmColor().rrr, 1.0); } void onlyRoughness() { gl_FragColor = vec4(getOrmColor().ggg, 1.0); } void onlyMetallic() { gl_FragColor = vec4(getOrmColor().bbb, 1.0); } void onlyTeamColorFactor() { gl_FragColor = vec4(getOrmColor().aaa, 1.0); } void onlyEmissiveMap() { gl_FragColor = vec4(getEmissiveColor(), 1.0); } void onlyTexCoords() { gl_FragColor = vec4(v_uv, 0.0, 1.0); } void onlyNormals() { gl_FragColor = vec4(v_normal, 1.0); } #if defined(ONLY_TANGENTS) void onlyTangents() { gl_FragColor = vec4(v_tangent, 1.0); } #endif void lambert() { vec4 baseColor = getDiffuseColor(); vec3 normal = decodeNormal(); vec4 orm = getOrmColor(); vec3 emissive = getEmissiveColor(); vec3 tc = getTeamColor(); float aoFactor = orm.r; float tcFactor = orm.a; float lambertFactor = clamp(dot(normal, v_lightDir), 0.0, 1.0); vec3 color = baseColor.rgb; if (tcFactor > 0.1) { color *= tc * tcFactor; } color *= clamp(lambertFactor * aoFactor + 0.1, 0.0, 1.0); color += emissive; gl_FragColor = vec4(color, baseColor.a); } void main() { #if defined(ONLY_DIFFUSE) onlyDiffuse(); #elif defined(ONLY_NORMAL_MAP) onlyNormalMap(); #elif defined(ONLY_OCCLUSION) onlyOcclusion(); #elif defined(ONLY_ROUGHNESS) onlyRoughness(); #elif defined(ONLY_METALLIC) onlyMetallic(); #elif defined(ONLY_TC_FACTOR) onlyTeamColorFactor(); #elif defined(ONLY_EMISSIVE) onlyEmissiveMap(); #elif defined(ONLY_TEXCOORDS) onlyTexCoords(); #elif defined(ONLY_NORMALS) onlyNormals(); #elif defined(ONLY_TANGENTS) onlyTangents(); #else lambert(); #endif } `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/shaders/hd.vert.ts ================================================ import boneTexture from '../../shaders/bonetexture.glsl'; import transforms from './transforms.glsl'; const shader = ` uniform mat4 u_VP; uniform mat4 u_MV; uniform vec3 u_eyePos; uniform vec3 u_lightPos; uniform float u_layerAlpha; uniform bool u_hasBones; attribute vec3 a_position; attribute vec3 a_normal; attribute vec2 a_uv; attribute vec4 a_tangent; varying vec2 v_uv; varying float v_layerAlpha; varying vec3 v_lightDir; varying vec3 v_eyeVec; varying vec3 v_normal; // varying vec3 v_lightDirWorld; #if defined(ONLY_TANGENTS) varying vec3 v_tangent; #endif ${boneTexture} ${transforms} vec3 TBN(vec3 vector, vec3 tangent, vec3 binormal, vec3 normal) { return vec3(dot(vector, tangent), dot(vector, binormal), dot(vector, normal)); } void main() { vec3 position = a_position; vec3 normal = a_normal; vec3 tangent = a_tangent.xyz; // Re-orthogonalize the tangent in case it wasnt normalized. // See "One last thing" at https://learnopengl.com/Advanced-Lighting/Normal-Mapping tangent = normalize(tangent - dot(tangent, normal) * normal); vec3 binormal = cross(normal, tangent) * a_tangent.w; if (u_hasBones) { #ifdef SKIN transformSkin(position, normal, tangent, binormal); #else transformVertexGroupsHD(position, normal, tangent, binormal); #endif } vec3 position_mv = vec3(u_MV * vec4(position, 1)); mat3 mv = mat3(u_MV); vec3 t = normalize(mv * tangent); vec3 b = normalize(mv * binormal); vec3 n = normalize(mv * normal); v_eyeVec = normalize(u_eyePos - position_mv); vec3 lightDir = normalize(u_lightPos - position_mv); v_lightDir = normalize(TBN(lightDir, t, b, n)); v_uv = a_uv; v_layerAlpha = u_layerAlpha; v_normal = normal; // v_lightDirWorld = normalize(lightDir); #if defined(ONLY_TANGENTS) v_tangent = tangent; #endif gl_Position = u_VP * vec4(position, 1.0); } `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/shaders/particles.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; const shader = ` ${precision} #define EMITTER_PARTICLE2 0 #define EMITTER_RIBBON 1 uniform sampler2D u_texture; uniform highp int u_emitter; uniform float u_filterMode; varying vec2 v_texcoord; varying vec4 v_color; void main() { vec4 texel = texture2D(u_texture, v_texcoord); vec4 color = texel * v_color; // 1bit Alpha, used by ribbon emitters. if (u_emitter == EMITTER_RIBBON && u_filterMode == 1.0 && color.a < 0.75) { discard; } // "Close to 0 alpha" if (u_emitter == EMITTER_PARTICLE2 && (u_filterMode == 2.0 || u_filterMode == 3.0) && color.a < 0.02) { discard; } // Alpha key. if (u_emitter == EMITTER_PARTICLE2 && (u_filterMode == 4.0) && color.a < 0.75) { discard; } gl_FragColor = color; } `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/shaders/particles.vert.ts ================================================ const shader = ` #define EMITTER_PARTICLE2 0 #define EMITTER_RIBBON 1 #define EMITTER_SPLAT 2 #define EMITTER_UBERSPLAT 3 #define HEAD 0.0 uniform mat4 u_VP; uniform int u_emitter; // Shared uniform vec4 u_colors[3]; uniform vec3 u_vertices[4]; uniform vec3 u_intervals[4]; uniform float u_lifeSpan; uniform float u_columns; uniform float u_rows; // Particle2 uniform vec3 u_scaling; uniform vec3 u_cameraZ; uniform float u_timeMiddle; uniform bool u_teamColored; // Splat and Uber. uniform vec3 u_intervalTimes; // Vertices attribute float a_position; // Instances attribute vec3 a_p0; attribute vec3 a_p1; attribute vec3 a_p2; attribute vec3 a_p3; attribute float a_health; attribute vec4 a_color; attribute float a_tail; attribute vec3 a_leftRightTop; varying vec2 v_texcoord; varying vec4 v_color; float getCell(vec3 interval, float factor) { float start = interval[0]; float end = interval[1]; float repeat = interval[2]; float spriteCount = end - start; if (spriteCount > 0.0) { // Repeating speeds up the sprite animation, which makes it effectively run N times in its interval. // E.g. if repeat is 4, the sprite animation will be seen 4 times, and thus also run 4 times as fast. // The sprite index is limited to the number of actual sprites. return min(start + mod(floor(spriteCount * repeat * factor), spriteCount), u_columns * u_rows - 1.0); } return start; } void particle2() { float factor = (u_lifeSpan - a_health) / u_lifeSpan; int index = 0; if (factor < u_timeMiddle) { factor = factor / u_timeMiddle; index = 0; } else { factor = (factor - u_timeMiddle) / (1.0 - u_timeMiddle); index = 1; } factor = min(factor, 1.0); float scale = mix(u_scaling[index], u_scaling[index + 1], factor); vec4 color = mix(u_colors[index], u_colors[index + 1], factor); float cell = 0.0; if (u_teamColored) { cell = a_leftRightTop[0]; } else { vec3 interval; if (a_tail == HEAD) { interval = u_intervals[index]; } else { interval = u_intervals[index + 2]; } cell = getCell(interval, factor); } float left = floor(mod(cell, u_columns)); float top = floor(cell / u_columns); float right = left + 1.0; float bottom = top + 1.0; left /= u_columns; right /= u_columns; top /= u_rows; bottom /= u_rows; if (a_position == 0.0) { v_texcoord = vec2(right, top); } else if (a_position == 1.0) { v_texcoord = vec2(left, top); } else if (a_position == 2.0) { v_texcoord = vec2(left, bottom); } else if (a_position == 3.0) { v_texcoord = vec2(right, bottom); } v_color = color; if (a_tail == HEAD) { vec3 v = u_vertices[int(a_position)]; float cs = cos(a_p1.x); float sn = sin(a_p1.x); float x = v.x * cs - v.y * sn; float y = v.x * sn + v.y * cs; vec3 fv = vec3( v.x * cs - v.y * sn, v.x * sn + v.y * cs, v.z); gl_Position = u_VP * vec4(a_p0 + fv * scale, 1.0); } else { // Get the normal to the tail in camera space. // This allows to build a 2D rectangle around the 3D tail. vec3 normal = cross(u_cameraZ, normalize(a_p1 - a_p0)); vec3 boundary = normal * scale * a_p2[0]; vec3 position; if (a_position == 0.0) { position = a_p0 - boundary; } else if (a_position == 1.0) { position = a_p1 - boundary; } else if (a_position == 2.0) { position = a_p1 + boundary; } else if (a_position == 3.0) { position = a_p0 + boundary; } gl_Position = u_VP * vec4(position, 1.0); } } void ribbon() { vec3 position; float left = a_leftRightTop[0] / 255.0; float right = a_leftRightTop[1] / 255.0; float top = a_leftRightTop[2] / 255.0; float bottom = top + 1.0; if (a_position == 0.0) { v_texcoord = vec2(right, top); position = a_p0; } else if (a_position == 1.0) { v_texcoord = vec2(right, bottom); position = a_p1; } else if (a_position == 2.0) { v_texcoord = vec2(left, bottom); position = a_p2; } else if (a_position == 3.0) { v_texcoord = vec2(left, top); position = a_p3; } v_texcoord[0] /= u_columns; v_texcoord[1] /= u_rows; v_color = a_color; gl_Position = u_VP * vec4(position, 1.0); } void splat() { float factor = u_lifeSpan - a_health; int index; if (factor < u_intervalTimes[0]) { factor = factor / u_intervalTimes[0]; index = 0; } else { factor = (factor - u_intervalTimes[0]) / u_intervalTimes[1]; index = 1; } float cell = getCell(u_intervals[index], factor); float left = floor(mod(cell, u_columns)); float top = floor(cell / u_columns); float right = left + 1.0; float bottom = top + 1.0; vec3 position; if (a_position == 0.0) { v_texcoord = vec2(left, top); position = a_p0; } else if (a_position == 1.0) { v_texcoord = vec2(left, bottom); position = a_p1; } else if (a_position == 2.0) { v_texcoord = vec2(right, bottom); position = a_p2; } else if (a_position == 3.0) { v_texcoord = vec2(right, top); position = a_p3; } v_texcoord[0] /= u_columns; v_texcoord[1] /= u_rows; v_color = mix(u_colors[index], u_colors[index + 1], factor) / 255.0; gl_Position = u_VP * vec4(position, 1.0); } void ubersplat() { float factor = u_lifeSpan - a_health; vec4 color; if (factor < u_intervalTimes[0]) { color = mix(u_colors[0], u_colors[1], factor / u_intervalTimes[0]); } else if (factor < u_intervalTimes[0] + u_intervalTimes[1]) { color = u_colors[1]; } else { color = mix(u_colors[1], u_colors[2], (factor - u_intervalTimes[0] - u_intervalTimes[1]) / u_intervalTimes[2]); } vec3 position; if (a_position == 0.0) { v_texcoord = vec2(0.0, 0.0); position = a_p0; } else if (a_position == 1.0) { v_texcoord = vec2(0.0, 1.0); position = a_p1; } else if (a_position == 2.0) { v_texcoord = vec2(1.0, 1.0); position = a_p2; } else if (a_position == 3.0) { v_texcoord = vec2(1.0, 0.0); position = a_p3; } v_color = color / 255.0; gl_Position = u_VP * vec4(position, 1.0); } void main() { if (u_emitter == EMITTER_PARTICLE2) { particle2(); } else if (u_emitter == EMITTER_RIBBON) { ribbon(); } else if (u_emitter == EMITTER_SPLAT) { splat(); } else if (u_emitter == EMITTER_UBERSPLAT) { ubersplat(); } } `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/shaders/sd.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; import quatTransform from '../../shaders/quattransform.glsl'; const shader = ` ${precision} ${quatTransform} uniform sampler2D u_texture; uniform float u_filterMode; uniform bool u_unshaded; varying vec2 v_uv; varying vec3 v_normal; varying vec4 v_color; varying vec4 v_uvTransRot; varying float v_uvScale; varying vec3 v_lightDir; vec4 getDiffuseColor() { vec2 uv = v_uv; // Translation animation uv += v_uvTransRot.xy; // Rotation animation uv = quat_transform(v_uvTransRot.zw, uv - 0.5) + 0.5; // Scale animation uv = v_uvScale * (uv - 0.5) + 0.5; vec4 texel = texture2D(u_texture, uv); vec4 color = texel * v_color; // 1bit Alpha if (u_filterMode == 1.0 && color.a < 0.75) { discard; } // "Close to 0 alpha" if (u_filterMode >= 5.0 && color.a < 0.02) { discard; } return color; } void onlyTexCoords() { gl_FragColor = vec4(v_uv, 0.0, 1.0); } void onlyNormals() { gl_FragColor = vec4(v_normal, 1.0); } void onlyDiffuse() { gl_FragColor = getDiffuseColor(); } void lambert() { vec4 color = getDiffuseColor(); if (!u_unshaded) { float lambertFactor = clamp(dot(v_normal, v_lightDir), 0.0, 1.0); lambertFactor = clamp(lambertFactor + 0.7, 0.0, 1.0); color.rgb *= lambertFactor; } gl_FragColor = color; } void main() { #if defined(ONLY_DIFFUSE) onlyDiffuse(); #elif defined(ONLY_TEXCOORDS) onlyTexCoords(); #elif defined(ONLY_NORMALS) onlyNormals(); #else lambert(); #endif } `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/shaders/sd.vert.ts ================================================ import boneTexture from '../../shaders/bonetexture.glsl'; import transforms from './transforms.glsl'; const shader = ` uniform mat4 u_VP; uniform vec3 u_lightPos; uniform vec4 u_vertexColor; uniform vec4 u_geosetColor; uniform float u_layerAlpha; uniform vec2 u_uvTrans; uniform vec2 u_uvRot; uniform float u_uvScale; uniform bool u_hasBones; attribute vec3 a_position; attribute vec3 a_normal; attribute vec2 a_uv; varying vec2 v_uv; varying vec3 v_normal; varying vec4 v_color; varying vec4 v_uvTransRot; varying float v_uvScale; varying vec3 v_lightDir; ${boneTexture} ${transforms} void main() { vec3 position = a_position; vec3 normal = a_normal; if (u_hasBones) { #ifdef SKIN vec3 tangent = vec3(0.0); vec3 binormal = vec3(0.0); transformSkin(position, normal, tangent, binormal); #else transformVertexGroups(position, normal); #endif } v_uv = a_uv; v_normal = normal; v_color = u_vertexColor * u_geosetColor.bgra * vec4(1.0, 1.0, 1.0, u_layerAlpha); v_uvTransRot = vec4(u_uvTrans, u_uvRot); v_uvScale = u_uvScale; v_lightDir = normalize(u_lightPos - position); gl_Position = u_VP * vec4(position, 1.0); } `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/shaders/transforms.glsl.ts ================================================ const shader = ` #ifdef SKIN attribute vec4 a_bones; attribute vec4 a_weights; void transformSkin(inout vec3 position, inout vec3 normal, inout vec3 tangent, inout vec3 binormal) { mat4 bone; bone += fetchMatrix(a_bones[0], 0.0) * a_weights[0]; bone += fetchMatrix(a_bones[1], 0.0) * a_weights[1]; bone += fetchMatrix(a_bones[2], 0.0) * a_weights[2]; bone += fetchMatrix(a_bones[3], 0.0) * a_weights[3]; mat3 rotation = mat3(bone); position = vec3(bone * vec4(position, 1.0)); normal = rotation * normal; tangent = rotation * tangent; binormal = rotation * binormal; } #else attribute vec4 a_bones; #ifdef EXTENDED_BONES attribute vec4 a_extendedBones; #endif attribute float a_boneNumber; mat4 getVertexGroupMatrix() { mat4 bone; // For the broken models out there, since the game supports this. if (a_boneNumber > 0.0) { for (int i = 0; i < 4; i++) { if (a_bones[i] > 0.0) { bone += fetchMatrix(a_bones[i] - 1.0, 0.0); } } #ifdef EXTENDED_BONES for (int i = 0; i < 4; i++) { if (a_extendedBones[i] > 0.0) { bone += fetchMatrix(a_extendedBones[i] - 1.0, 0.0); } } #endif } return bone / a_boneNumber; } void transformVertexGroups(inout vec3 position, inout vec3 normal) { mat4 bone = getVertexGroupMatrix(); mat3 rotation = mat3(bone); position = vec3(bone * vec4(position, 1.0)); normal = normalize(rotation * normal); } void transformVertexGroupsHD(inout vec3 position, inout vec3 normal, inout vec3 tangent, inout vec3 binormal) { mat4 bone = getVertexGroupMatrix(); mat3 rotation = mat3(bone); position = vec3(bone * vec4(position, 1.0)); normal = normalize(rotation * normal); tangent = normalize(rotation * tangent); binormal = normalize(rotation * binormal); } #endif `; export default shader; ================================================ FILE: src/viewer/handlers/mdx/texture.ts ================================================ import { WrapMode } from '../../../parsers/mdlx/texture'; import Texture from '../../texture'; /** * An MDX texture. */ export default class MdxTexture { texture: Texture | null = null; replaceableId: number; wrapS = 0x812f; // CLAMP_TO_EDGE wrapT = 0x812f; constructor(replaceableId: number, wrapMode: WrapMode) { this.replaceableId = replaceableId; if (wrapMode & WrapMode.WrapWidth) { this.wrapS = 0x2901; // REPEAT } if (wrapMode & WrapMode.WrapHeight) { this.wrapT = 0x2901; } } } ================================================ FILE: src/viewer/handlers/mdx/textureanimation.ts ================================================ import { VEC3_ZERO, VEC3_ONE, QUAT_DEFAULT } from '../../../common/gl-matrix-addon'; import MdlxTextureAnimation from '../../../parsers/mdlx/textureanimation'; import AnimatedObject from './animatedobject'; import MdxModel from './model'; /** * An MDX texture animation. */ export default class TextureAnimation extends AnimatedObject { constructor(model: MdxModel, textureAnimation: MdlxTextureAnimation) { super(model, textureAnimation); this.addVariants('KTAT', 'translation'); this.addVariants('KTAR', 'rotation'); this.addVariants('KTAS', 'scale'); } getTranslation(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KTAT', sequence, frame, counter, VEC3_ZERO); } getRotation(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getQuatValue(out, 'KTAR', sequence, frame, counter, QUAT_DEFAULT); } getScale(out: Float32Array, sequence: number, frame: number, counter: number): number { return this.getVectorValue(out, 'KTAS', sequence, frame, counter, VEC3_ONE); } } ================================================ FILE: src/viewer/handlers/shaders/bonetexture.glsl.ts ================================================ const shader = ` uniform sampler2D u_boneMap; uniform float u_vectorSize; uniform float u_rowSize; mat4 fetchMatrix(float column, float row) { column *= u_vectorSize * 4.0; row *= u_rowSize; // Add in half a texel, to sample in the middle of the texel. // Otherwise, since the sample is directly on the boundary, floating point errors can cause the sample to get the wrong pixel. // This is most noticeable with NPOT textures, which the bone maps are. column += 0.5 * u_vectorSize; row += 0.5 * u_rowSize; return mat4(texture2D(u_boneMap, vec2(column, row)), texture2D(u_boneMap, vec2(column + u_vectorSize, row)), texture2D(u_boneMap, vec2(column + u_vectorSize * 2.0, row)), texture2D(u_boneMap, vec2(column + u_vectorSize * 3.0, row))); } `; export default shader; ================================================ FILE: src/viewer/handlers/shaders/precision.glsl.ts ================================================ // Used by all fragment shaders. const shader = ` #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif `; export default shader; ================================================ FILE: src/viewer/handlers/shaders/quattransform.glsl.ts ================================================ const shader = ` // A 2D quaternion*vector. // q is the zw components of the original quaternion. vec2 quat_transform(vec2 q, vec2 v) { vec2 uv = vec2(-q.x * v.y, q.x * v.x); vec2 uuv = vec2(-q.x * uv.y, q.x * uv.x); return v + 2.0 * (uv * q.y + uuv); } `; export default shader; ================================================ FILE: src/viewer/handlers/tga/handler.ts ================================================ import TgaImage from '../../../parsers/tga/image'; import isTga from '../../../parsers/tga/isformat'; import Texture from './texture'; export default { isValidSource(object: unknown): boolean { if (object instanceof TgaImage) { return true; } return isTga(object); }, resource: Texture, }; ================================================ FILE: src/viewer/handlers/tga/texture.ts ================================================ import { isPowerOfTwo } from '../../../common/math'; import TgaImage from '../../../parsers/tga/image'; import { HandlerResourceData } from '../../handlerresource'; import Texture from '../../texture'; /** * A TGA texture handler. */ export default class TgaTexture extends Texture { constructor(bufferOrImage: ArrayBuffer | TgaImage, resourceData: HandlerResourceData) { super(resourceData); let image; if (bufferOrImage instanceof TgaImage) { image = bufferOrImage; } else { image = new TgaImage(); image.load(bufferOrImage); } const width = image.width; const height = image.height; const gl = this.viewer.gl; const id = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, id); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image.data); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); if (isPowerOfTwo(width) && isPowerOfTwo(height)) { gl.generateMipmap(gl.TEXTURE_2D); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); } else { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); } this.webglResource = id; this.width = width; this.height = height; } } ================================================ FILE: src/viewer/handlers/w3x/doodad.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { VEC3_UNIT_Z } from '../../../common/gl-matrix-addon'; import { MappedDataRow } from '../../../utils/mappeddata'; import DooDoodad from '../../../parsers/w3x/doo/doodad'; import MdxModel from '../mdx/model'; import War3MapViewerMap from './map'; import { Widget } from './widget'; /** * A doodad. */ export default class Doodad extends Widget { row: MappedDataRow; constructor(map: War3MapViewerMap, model: MdxModel, row: MappedDataRow, doodad: DooDoodad) { super(map, model); const instance = this.instance; instance.move(doodad.location); instance.rotateLocal(quat.setAxisAngle(quat.create(), VEC3_UNIT_Z, doodad.angle)); instance.scale(doodad.scale); instance.setScene(map.worldScene); this.instance = instance; this.row = row; } } ================================================ FILE: src/viewer/handlers/w3x/map.ts ================================================ import { vec3 } from 'gl-matrix'; import unique from '../../../common/arrayunique'; import War3Map from '../../../parsers/w3x/map'; import War3MapW3i from '../../../parsers/w3x/w3i/file'; import War3MapW3e from '../../../parsers/w3x/w3e/file'; import Corner from '../../../parsers/w3x/w3e/corner'; import War3MapW3u from '../../../parsers/w3x/w3u/file'; import War3MapW3d from '../../../parsers/w3x/w3d/file'; import ModificationTable from '../../../parsers/w3x/w3u/modificationtable'; import { MappedData, MappedDataRow } from '../../../utils/mappeddata'; import Scene from '../../scene'; import Grid from '../../grid'; import { PathSolver } from '../../handlerresource'; import Texture from '../../texture'; import MdxModel from '../mdx/model'; import getCliffVariation from './variations'; import TerrainModel from './terrainmodel'; import Unit from './unit'; import Doodad from './doodad'; import TerrainDoodad from './terraindoodad'; import War3MapViewer from './viewer'; import War3MapDoo from '../../../parsers/w3x/doo/file'; import War3MapUnitsDoo from '../../../parsers/w3x/unitsdoo/file'; import { Resource } from '../../resource'; const normalHeap1 = vec3.create(); const normalHeap2 = vec3.create(); export default class War3MapViewerMap { viewer: War3MapViewer; map: War3Map; pathSolver: PathSolver; buildVersion = 0; solverParams: { tileset: string, reforged?: boolean, hd?: boolean } = { tileset: 'a' }; worldScene: Scene; waterIndex = 0; waterIncreasePerFrame = 0; waterHeightOffset = 0; waterTextures: Texture[] = []; maxDeepColor = new Float32Array(4); minDeepColor = new Float32Array(4); maxShallowColor = new Float32Array(4); minShallowColor = new Float32Array(4); anyReady = false; terrainReady = false; cliffsReady = false; doodads: Doodad[] = []; terrainDoodads: TerrainDoodad[] = []; doodadsReady = false; units: Unit[] = []; unitsReady = false; tilesetTextures: Texture[] = []; cliffTextures: Texture[] = []; cliffModels: TerrainModel[] = []; corners: Corner[][] = []; centerOffset = new Float32Array(2); mapSize = new Int32Array(2); tilesets: MappedDataRow[] = []; blightTextureIndex = -1; cliffTilesets: MappedDataRow[] = []; columns = 0; rows = 0; vertexBuffer: WebGLBuffer | null = null; faceBuffer: WebGLBuffer | null = null; instanceBuffer: WebGLBuffer | null = null; textureBuffer: WebGLBuffer | null = null; variationBuffer: WebGLBuffer | null = null; waterBuffer: WebGLBuffer | null = null; heightMap: WebGLTexture | null = null; waterHeightMap: WebGLTexture | null = null; cliffHeightMap: WebGLTexture | null = null; constructor(viewer: War3MapViewer, buffer: ArrayBuffer | Uint8Array) { this.viewer = viewer; this.worldScene = viewer.addScene(); this.map = new War3Map(); // Readonly mode to optimize memory usage. this.map.load(buffer, true); this.loadMapInformation(); this.pathSolver = (src, params): unknown => { // The type won't be a string for loads from memory, where the final source is the input source. // The primitive constructor is one example of this. if (typeof src === 'string') { // MPQ paths have backwards slashes...always? Don't know. const path = src.replace(/\//g, '\\'); // If the file is in the map, return it. const file = this.map.get(path); if (file) { return file.arrayBuffer(); } // Try to get the file from the server. return viewer.wc3PathSolver(src, params); } return src; }; this.loadTerrainCliffsAndWater(); // Global tables like WC3. It's bad. const modifications = this.map.readModifications(); this.applyModificationFile(viewer.doodadsData, viewer.doodadMetaData, modifications.w3d); this.applyModificationFile(viewer.doodadsData, viewer.destructableMetaData, modifications.w3b); this.applyModificationFile(viewer.unitsData, viewer.unitMetaData, modifications.w3u); this.applyModificationFile(viewer.unitsData, viewer.unitMetaData, modifications.w3t); this.loadDoodadsAndDestructibles(); this.loadUnitsAndItems(); } die(): void { this.worldScene.detach(); } load(src: unknown): Promise { return this.viewer.load(src, this.pathSolver, this.solverParams); } loadMapInformation(): void { const mpqFile = this.map.get('war3map.w3i'); if (!mpqFile) { console.warn('Attempted to load war3map.w3i but it is not there. Using default tileset A.'); return; } const parser = new War3MapW3i(); try { parser.load(mpqFile.bytes()); } catch (e) { console.warn('Failed to correctly parse the map information file'); } this.solverParams.tileset = parser.tileset.toLowerCase(); this.buildVersion = parser.getBuildVersion(); if (this.buildVersion > 131) { this.solverParams.reforged = true; } } async loadTerrainCliffsAndWater(): Promise { const mpqFile = this.map.get('war3map.w3e'); if (!mpqFile) { console.warn('Attempted to load war3map.w3e, but it is not there.'); return; } const parser = new War3MapW3e(); try { parser.load(mpqFile.bytes()); } catch (e) { console.warn(`Failed to load war3map.w3e: ${e}`); return; } const viewer = this.viewer; const centerOffset = parser.centerOffset; const mapSize = parser.mapSize; this.corners = parser.corners; this.centerOffset.set(centerOffset); this.mapSize.set(mapSize); // Override the grid based on the map. this.worldScene.grid = new Grid(centerOffset[0], centerOffset[1], mapSize[0] * 128 - 128, mapSize[1] * 128 - 128, 16 * 128, 16 * 128); const texturesExt = this.solverParams.reforged ? '.dds' : '.blp'; const tileset = parser.tileset; const tilesetTextures = []; const cliffTextures = []; const waterTextures = []; for (const groundTileset of parser.groundTilesets) { const row = viewer.terrainData.getRow(groundTileset); this.tilesets.push(row); tilesetTextures.push(this.load(`${row.string('dir')}\\${row.string('file')}${texturesExt}`)); } const blights = { A: 'Ashen', B: 'Barrens', C: 'Felwood', D: 'Cave', F: 'Lordf', G: 'Dungeon', I: 'Ice', J: 'DRuins', K: 'Citadel', L: 'Lords', N: 'North', O: 'Outland', Q: 'VillageFall', V: 'Village', W: 'Lordw', X: 'Village', Y: 'Village', Z: 'Ruins', }; this.blightTextureIndex = this.tilesetTextures.length; tilesetTextures.push(this.load(`TerrainArt\\Blight\\${blights[tileset]}_Blight${texturesExt}`)); for (const cliffTileset of parser.cliffTilesets) { const row = viewer.cliffTypesData.getRow(cliffTileset); this.cliffTilesets.push(row); cliffTextures.push(this.load(`${row.string('texDir')}\\${row.string('texFile')}${texturesExt}`)); } const waterRow = viewer.waterData.getRow(`${tileset}Sha`); this.waterHeightOffset = waterRow.number('height'); this.waterIncreasePerFrame = waterRow.number('texRate') / 60; this.waterTextures.length = 0; this.maxDeepColor.set([waterRow.number('Dmax_R'), waterRow.number('Dmax_G'), waterRow.number('Dmax_B'), waterRow.number('Dmax_A')]); this.minDeepColor.set([waterRow.number('Dmin_R'), waterRow.number('Dmin_G'), waterRow.number('Dmin_B'), waterRow.number('Dmin_A')]); this.maxShallowColor.set([waterRow.number('Smax_R'), waterRow.number('Smax_G'), waterRow.number('Smax_B'), waterRow.number('Smax_A')]); this.minShallowColor.set([waterRow.number('Smin_R'), waterRow.number('Smin_G'), waterRow.number('Smin_B'), waterRow.number('Smin_A')]); for (let i = 0, l = waterRow.number('numTex'); i < l; i++) { waterTextures.push(this.load(`${waterRow.string('texFile')}${i < 10 ? '0' : ''}${i}${texturesExt}`)); } this.tilesetTextures = await Promise.all(tilesetTextures); this.cliffTextures = await Promise.all(cliffTextures); this.waterTextures = await Promise.all(waterTextures); const corners = parser.corners; const [columns, rows] = this.mapSize; const instanceCount = (columns - 1) * (rows - 1); const cliffHeights = new Float32Array(columns * rows); const cornerHeights = new Float32Array(columns * rows); const waterHeights = new Float32Array(columns * rows); const cornerTextures = new Uint8Array(instanceCount * 4); const cornerVariations = new Uint8Array(instanceCount * 4); const waterFlags = new Uint8Array(instanceCount); let instance = 0; const cliffs: {[key: string]: { locations: number[], textures: number[] }} = {}; this.columns = columns - 1; this.rows = rows - 1; for (let y = 0; y < rows; y++) { for (let x = 0; x < columns; x++) { const bottomLeft = corners[y][x]; const index = y * columns + x; cliffHeights[index] = bottomLeft.groundHeight; cornerHeights[index] = bottomLeft.groundHeight + bottomLeft.layerHeight - 2; waterHeights[index] = bottomLeft.waterHeight; if (y < rows - 1 && x < columns - 1) { // Water can be used with cliffs and normal corners, so store water state regardless. waterFlags[instance] = this.isWater(x, y); // Is this a cliff, or a normal corner? if (this.isCliff(x, y)) { const bottomLeftLayer = bottomLeft.layerHeight; const bottomRightLayer = corners[y][x + 1].layerHeight; const topLeftLayer = corners[y + 1][x].layerHeight; const topRightLayer = corners[y + 1][x + 1].layerHeight; const base = Math.min(bottomLeftLayer, bottomRightLayer, topLeftLayer, topRightLayer); const fileName = this.cliffFileName(bottomLeftLayer, bottomRightLayer, topLeftLayer, topRightLayer, base); if (fileName !== 'AAAA') { let cliffTexture = bottomLeft.cliffTexture; /// ? if (cliffTexture === 15) { cliffTexture = 1; } const cliffRow = this.cliffTilesets[cliffTexture]; const dir = cliffRow.string('cliffModelDir'); const path = `Doodads\\Terrain\\${dir}\\${dir}${fileName}${getCliffVariation(dir, fileName, bottomLeft.cliffVariation)}.mdx`; if (!cliffs[path]) { cliffs[path] = { locations: [], textures: []}; } cliffs[path].locations.push((x + 1) * 128 + centerOffset[0], y * 128 + centerOffset[1], (base - 2) * 128); cliffs[path].textures.push(cliffTexture); } } else { const bottomLeftTexture = this.cornerTexture(x, y); const bottomRightTexture = this.cornerTexture(x + 1, y); const topLeftTexture = this.cornerTexture(x, y + 1); const topRightTexture = this.cornerTexture(x + 1, y + 1); const textures = unique([bottomLeftTexture, bottomRightTexture, topLeftTexture, topRightTexture]).sort(); let texture = textures[0]; cornerTextures[instance * 4] = texture + 1; cornerVariations[instance * 4] = this.getVariation(texture, bottomLeft.groundVariation); textures.shift(); for (let i = 0, l = textures.length; i < l; i++) { let bitset = 0; texture = textures[i]; if (bottomRightTexture === texture) { bitset |= 0b0001; } if (bottomLeftTexture === texture) { bitset |= 0b0010; } if (topRightTexture === texture) { bitset |= 0b0100; } if (topLeftTexture === texture) { bitset |= 0b1000; } cornerTextures[instance * 4 + 1 + i] = texture + 1; cornerVariations[instance * 4 + 1 + i] = bitset; } } instance += 1; } } } const gl = this.viewer.gl; const webgl = this.viewer.webgl; this.vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW); this.faceBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.faceBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 1, 3, 2]), gl.STATIC_DRAW); this.cliffHeightMap = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.cliffHeightMap); webgl.setTextureMode(gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE, gl.NEAREST, gl.NEAREST); gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, columns, rows, 0, gl.ALPHA, gl.FLOAT, cliffHeights); this.heightMap = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.heightMap); webgl.setTextureMode(gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE, gl.NEAREST, gl.NEAREST); gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, columns, rows, 0, gl.ALPHA, gl.FLOAT, cornerHeights); this.waterHeightMap = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.waterHeightMap); webgl.setTextureMode(gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE, gl.NEAREST, gl.NEAREST); gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, columns, rows, 0, gl.ALPHA, gl.FLOAT, waterHeights); this.instanceBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(instanceCount).map((currentValue, index) => index), gl.STATIC_DRAW); this.textureBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer); gl.bufferData(gl.ARRAY_BUFFER, cornerTextures, gl.STATIC_DRAW); this.variationBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.variationBuffer); gl.bufferData(gl.ARRAY_BUFFER, cornerVariations, gl.STATIC_DRAW); this.waterBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.waterBuffer); gl.bufferData(gl.ARRAY_BUFFER, waterFlags, gl.STATIC_DRAW); this.terrainReady = true; this.anyReady = true; const cliffShader = viewer.cliffShader; const cliffPromises = Object.entries(cliffs).map(async (cliff) => { const path = cliff[0]; const { locations, textures } = cliff[1]; const resource = await viewer.loadBaseFile(path, 'arrayBuffer'); if (resource) { return new TerrainModel(this, resource.data, locations, textures, cliffShader); } return; }).filter(x => x); // Sometimes TS isn't the brightest. const cliffPromisesForReal = []>cliffPromises; this.cliffModels = await Promise.all(cliffPromisesForReal); this.cliffsReady = true; } loadDoodadsAndDestructibles(): void { const mpqFile = this.map.get('war3map.doo'); if (!mpqFile) { console.warn('Attempted to load war3map.doo but it is not there'); return; } const parser = new War3MapDoo(); try { parser.load(mpqFile.bytes(), this.buildVersion); } catch (e) { console.warn(`Failed to load war3map.doo: ${e}`); return; } // Doodads and destructibles. for (const doodad of parser.doodads) { try { const row = this.viewer.doodadsData.getRow(doodad.id); if (row) { let file = row.string('file'); if (file) { const numVar = row.number('numVar'); if (file.endsWith('.mdl')) { file = file.slice(0, -4); } let fileVar = file; file += '.mdx'; if (numVar > 1) { fileVar += Math.min(doodad.variation, numVar - 1); } fileVar += '.mdx'; // First see if the model is local. // Doodads refering to local models may have invalid variations, so if the variation doesn't exist, try without a variation. const mpqFile = this.map.get(fileVar) || this.map.get(file); let promise; if (mpqFile) { promise = this.load(mpqFile.name); } else { promise = this.load(fileVar); } promise.then((model) => { if (model) { this.doodads.push(new Doodad(this, model, row, doodad)); } }); } else { console.log('Unknown doodad ID', doodad.id, doodad); } } } catch (e) { console.warn(`Failed to load doodad/destructible ID ${doodad.id}: ${e}`); } } // Cliff/Terrain doodads. for (const doodad of parser.terrainDoodads) { try { const row = this.viewer.doodadsData.getRow(doodad.id); this.load(`${row.string('file')}.mdx`) .then((model) => { if (model) { this.terrainDoodads.push(new TerrainDoodad(this, model, row, doodad)); } }); // let pathTexture = this.load(row.pathTex); // pathTexture.whenLoaded(() => { // let startx = doodad.location[0]; // let starty = doodad.location[1]; // let endx = startx + pathTexture.width / 4; // let endy = starty + pathTexture.height / 4; // for (let x = startx; x < endx; x++) { // for (let y = starty; y < endy; y++) { // } // } // }); } catch (e) { console.warn(`Failed to load cliff/terrain doodad ID ${doodad.id}: ${e}`); } } this.doodadsReady = true; this.anyReady = true; } loadUnitsAndItems(): void { const mpqFile = this.map.get('war3mapUnits.doo'); if (!mpqFile) { console.warn('Attempted to load war3mapUnits.doo but it is not there'); return; } const parser = new War3MapUnitsDoo(); try { parser.load(mpqFile.bytes(), this.buildVersion); } catch (e) { console.warn(`Failed to load war3mapUnits.doo: ${e}`); return; } // Collect the units and items data. for (const unit of parser.units) { try { let row: MappedDataRow | undefined; let path; // Hardcoded? if (unit.id === 'sloc') { path = 'Objects\\StartLocation\\StartLocation.mdx'; } else { row = this.viewer.unitsData.getRow(unit.id); if (row) { path = row.string('file'); if (path) { if (path.endsWith('.mdl')) { path = path.slice(0, -4); } path += '.mdx'; } } } if (path) { this.load(path) .then((model) => { if (model) { this.units.push(new Unit(this, model, row, unit)); } }); } else { console.log('Unknown unit ID', unit.id, unit); } } catch (e) { console.warn(`Failed to load unit/item ID ${unit.id}: ${e}`); } } this.unitsReady = true; this.anyReady = true; } /** * Update the map. */ update(): void { if (this.anyReady) { this.waterIndex += this.waterIncreasePerFrame; if (this.waterIndex >= this.waterTextures.length) { this.waterIndex = 0; } for (const doodad of this.doodads) { doodad.update(); } for (const unit of this.units) { unit.update(); } } } /** * Render the map. */ render(): void { if (this.anyReady) { const worldScene = this.worldScene; worldScene.startFrame(); this.renderGround(); this.renderCliffs(); worldScene.renderOpaque(); this.renderWater(); worldScene.renderTranslucent(); } } renderGround(): void { if (this.terrainReady) { const gl = this.viewer.gl; const webgl = this.viewer.webgl; const instancedArrays = webgl.extensions['ANGLE_instanced_arrays']; const shader = this.viewer.groundShader; const uniforms = shader.uniforms; const attribs = shader.attribs; const tilesetTextures = this.tilesetTextures; const instanceAttrib = attribs['a_InstanceID']; const positionAttrib = attribs['a_position']; const texturesAttrib = attribs['a_textures']; const variationsAttrib = attribs['a_variations']; const tilesetCount = tilesetTextures.length; // This includes the blight texture. gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); webgl.useShader(shader); gl.uniformMatrix4fv(uniforms['u_VP'], false, this.worldScene.camera.viewProjectionMatrix); gl.uniform2fv(uniforms['u_offset'], this.centerOffset); gl.uniform2f(uniforms['u_size'], this.columns, this.rows); gl.uniform1i(uniforms['u_heightMap'], 15); gl.activeTexture(gl.TEXTURE15); gl.bindTexture(gl.TEXTURE_2D, this.heightMap); gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceBuffer); gl.vertexAttribPointer(instanceAttrib, 1, gl.FLOAT, false, 0, 0); instancedArrays.vertexAttribDivisorANGLE(instanceAttrib, 1); gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer); gl.vertexAttribPointer(texturesAttrib, 4, gl.UNSIGNED_BYTE, false, 0, 0); instancedArrays.vertexAttribDivisorANGLE(texturesAttrib, 1); gl.bindBuffer(gl.ARRAY_BUFFER, this.variationBuffer); gl.vertexAttribPointer(variationsAttrib, 4, gl.UNSIGNED_BYTE, false, 0, 0); instancedArrays.vertexAttribDivisorANGLE(variationsAttrib, 1); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.faceBuffer); gl.uniform1f(uniforms['u_baseTileset'], 0); for (let i = 0, l = Math.min(tilesetCount, 15); i < l; i++) { const isExtended = tilesetTextures[i].width > tilesetTextures[i].height ? 1 : 0; gl.uniform1f(uniforms[`u_extended[${i}]`], isExtended); gl.uniform1i(uniforms[`u_tilesets[${i}]`], i); webgl.bindTexture(tilesetTextures[i], i); } instancedArrays.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this.rows * this.columns); if (tilesetCount > 15) { gl.uniform1f(uniforms['u_baseTileset'], 15); for (let i = 0, l = tilesetCount - 15; i < l; i++) { const isExtended = tilesetTextures[i + 15].width > tilesetTextures[i + 15].height ? 1 : 0; gl.uniform1f(uniforms[`u_extended[${i}]`], isExtended); webgl.bindTexture(tilesetTextures[i + 15], i); } instancedArrays.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this.rows * this.columns); } instancedArrays.vertexAttribDivisorANGLE(texturesAttrib, 0); instancedArrays.vertexAttribDivisorANGLE(variationsAttrib, 0); instancedArrays.vertexAttribDivisorANGLE(instanceAttrib, 0); } } renderWater(): void { if (this.terrainReady) { const gl = this.viewer.gl; const webgl = this.viewer.webgl; const instancedArrays = webgl.extensions['ANGLE_instanced_arrays']; const shader = this.viewer.waterShader; const uniforms = shader.uniforms; const attribs = shader.attribs; const instanceAttrib = attribs['a_InstanceID']; const positionAttrib = attribs['a_position']; const isWaterAttrib = attribs['a_isWater']; gl.depthMask(false); gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); webgl.useShader(shader); gl.uniformMatrix4fv(uniforms['u_VP'], false, this.worldScene.camera.viewProjectionMatrix); gl.uniform2fv(uniforms['u_offset'], this.centerOffset); gl.uniform2f(uniforms['u_size'], this.columns, this.rows); gl.uniform1i(uniforms['u_heightMap'], 0); gl.uniform1i(uniforms['u_waterHeightMap'], 1); gl.uniform1i(uniforms['u_waterTexture'], 2); gl.uniform1f(uniforms['u_offsetHeight'], this.waterHeightOffset); gl.uniform4fv(uniforms['u_maxDeepColor'], this.maxDeepColor); gl.uniform4fv(uniforms['u_minDeepColor'], this.minDeepColor); gl.uniform4fv(uniforms['u_maxShallowColor'], this.maxShallowColor); gl.uniform4fv(uniforms['u_minShallowColor'], this.minShallowColor); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, this.heightMap); gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, this.waterHeightMap); webgl.bindTexture(this.waterTextures[this.waterIndex | 0], 2); gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 8, 0); gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceBuffer); gl.vertexAttribPointer(instanceAttrib, 1, gl.FLOAT, false, 4, 0); instancedArrays.vertexAttribDivisorANGLE(instanceAttrib, 1); gl.bindBuffer(gl.ARRAY_BUFFER, this.waterBuffer); gl.vertexAttribPointer(isWaterAttrib, 1, gl.UNSIGNED_BYTE, false, 1, 0); instancedArrays.vertexAttribDivisorANGLE(isWaterAttrib, 1); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.faceBuffer); instancedArrays.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this.rows * this.columns); instancedArrays.vertexAttribDivisorANGLE(isWaterAttrib, 0); instancedArrays.vertexAttribDivisorANGLE(instanceAttrib, 0); } } renderCliffs(): void { if (this.cliffsReady) { const gl = this.viewer.gl; const webgl = this.viewer.webgl; const instancedArrays = webgl.extensions['ANGLE_instanced_arrays']; const vertexArrayObject = webgl.extensions['OES_vertex_array_object']; const shader = this.viewer.cliffShader; const attribs = shader.attribs; const uniforms = shader.uniforms; gl.disable(gl.BLEND); shader.use(); gl.uniformMatrix4fv(uniforms['u_VP'], false, this.worldScene.camera.viewProjectionMatrix); gl.uniform1i(uniforms['u_heightMap'], 0); gl.uniform2f(uniforms['u_pixel'], 1 / (this.columns + 1), 1 / (this.rows + 1)); gl.uniform2fv(uniforms['u_centerOffset'], this.centerOffset); gl.uniform1i(uniforms['u_texture1'], 1); gl.uniform1i(uniforms['u_texture2'], 2); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, this.cliffHeightMap); gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, this.cliffTextures[0].webglResource); if (this.cliffTextures.length > 1) { gl.activeTexture(gl.TEXTURE2); gl.bindTexture(gl.TEXTURE_2D, this.cliffTextures[1].webglResource); } // Set instanced attributes. if (!vertexArrayObject) { instancedArrays.vertexAttribDivisorANGLE(attribs['a_instancePosition'], 1); instancedArrays.vertexAttribDivisorANGLE(attribs['a_instanceTexture'], 1); } // Render the cliffs. for (const cliff of this.cliffModels) { cliff.render(shader); } // Clear instanced attributes. if (!vertexArrayObject) { instancedArrays.vertexAttribDivisorANGLE(attribs['a_instancePosition'], 0); instancedArrays.vertexAttribDivisorANGLE(attribs['a_instanceTexture'], 0); } } } cliffFileName(bottomLeftLayer: number, bottomRightLayer: number, topLeftLayer: number, topRightLayer: number, base: number): string { return String.fromCharCode(65 + bottomLeftLayer - base) + String.fromCharCode(65 + topLeftLayer - base) + String.fromCharCode(65 + topRightLayer - base) + String.fromCharCode(65 + bottomRightLayer - base); } getVariation(groundTexture: number, variation: number): number { const texture = this.tilesetTextures[groundTexture]; // Extended? if (texture.width > texture.height) { if (variation < 16) { return 16 + variation; } else if (variation === 16) { return 15; } else { return 0; } } else { if (variation === 0) { return 0; } else { return 15; } } } /** * Is the corner at the given column and row a cliff? */ isCliff(column: number, row: number): boolean { if (column < 1 || column > this.columns - 1 || row < 1 || row > this.rows - 1) { return false; } const corners = this.corners; const bottomLeft = corners[row][column].layerHeight; const bottomRight = corners[row][column + 1].layerHeight; const topLeft = corners[row + 1][column].layerHeight; const topRight = corners[row + 1][column + 1].layerHeight; return bottomLeft !== bottomRight || bottomLeft !== topLeft || bottomLeft !== topRight; } /** * Is the tile at the given column and row water? */ isWater(column: number, row: number): number { const corners = this.corners; return corners[row][column].water || corners[row][column + 1].water || corners[row + 1][column].water || corners[row + 1][column + 1].water; } /** * Given a cliff index, get its ground texture index. * This is an index into the tilset textures. */ cliffGroundIndex(whichCliff: number): number { const whichTileset = this.cliffTilesets[whichCliff].string('groundTile'); const tilesets = this.tilesets; for (let i = 0, l = tilesets.length; i < l; i++) { if (tilesets[i].string('tileID') === whichTileset) { return i; } } return 0; } /** * Get the ground texture of a corner, whether it's normal ground, a cliff, or a blighted corner. */ cornerTexture(column: number, row: number): number { const corners = this.corners; const columns = this.columns; const rows = this.rows; for (let y = -1; y < 1; y++) { for (let x = -1; x < 1; x++) { if (column + x > 0 && column + x < columns - 1 && row + y > 0 && row + y < rows - 1) { if (this.isCliff(column + x, row + y)) { let texture = corners[row + y][column + x].cliffTexture; if (texture === 15) { texture = 1; } return this.cliffGroundIndex(texture); } } } } const corner = corners[row][column]; // Is this corner blighted? if (corner.blight) { return this.blightTextureIndex; } return corner.groundTexture; } applyModificationFile(dataMap: MappedData, metadataMap: MappedData, modificationFile: War3MapW3u | War3MapW3d | undefined): void { if (modificationFile) { // Modifications to built-in objects this.applyModificationTable(dataMap, metadataMap, modificationFile.originalTable); // Declarations of user-defined objects this.applyModificationTable(dataMap, metadataMap, modificationFile.customTable); } } applyModificationTable(dataMap: MappedData, metadataMap: MappedData, modificationTable: ModificationTable): void { for (const modificationObject of modificationTable.objects) { let row; if (modificationObject.newId !== '') { row = dataMap.getRow(modificationObject.newId); if (!row) { row = new MappedDataRow(); row.map = Object.assign({}, (dataMap.getRow(modificationObject.oldId)).map); dataMap.setRow(modificationObject.newId, row); } } else { row = dataMap.getRow(modificationObject.oldId); } for (const modification of modificationObject.modifications) { const metadata = metadataMap.getRow(modification.id); if (metadata) { row.set(metadata.string('field'), modification.value); } else { console.warn('Unknown modification ID', modification); } } } } groundNormal(out: vec3, x: number, y: number): vec3 { const centerOffset = this.centerOffset; const mapSize = this.mapSize; x = (x - centerOffset[0]) / 128; y = (y - centerOffset[1]) / 128; const cellX = x | 0; const cellY = y | 0; // See if this coordinate is in the map if (cellX >= 0 && cellX < mapSize[0] - 1 && cellY >= 0 && cellY < mapSize[1] - 1) { // See http://gamedev.stackexchange.com/a/24574 const corners = this.corners; const bottomLeft = corners[cellY][cellX].groundHeight; const bottomRight = corners[cellY][cellX + 1].groundHeight; const topLeft = corners[cellY + 1][cellX].groundHeight; const topRight = corners[cellY + 1][cellX + 1].groundHeight; const sqX = x - cellX; const sqY = y - cellY; if (sqX + sqY < 1) { vec3.set(normalHeap1, 1, 0, bottomRight - bottomLeft); vec3.set(normalHeap2, 0, 1, topLeft - bottomLeft); } else { vec3.set(normalHeap1, -1, 0, topRight - topLeft); vec3.set(normalHeap2, 0, 1, topRight - bottomRight); } vec3.normalize(out, vec3.cross(out, normalHeap1, normalHeap2)); } else { vec3.set(out, 0, 0, 1); } return out; } } /* heightAt(location) { let heightMap = this.heightMap, offset = this.offset, x = (location[0] / 128) + offset[0], y = (location[1] / 128) + offset[1]; let minY = Math.floor(y), maxY = Math.ceil(y), minX = Math.floor(x), maxX = Math.ceil(x); // See if this coordinate is in the map if (maxY > 0 && minY < heightMap.length - 1 && maxX > 0 && minX < heightMap[0].length - 1) { // See http://gamedev.stackexchange.com/a/24574 let triZ0 = heightMap[minY][minX], triZ1 = heightMap[minY][maxX], triZ2 = heightMap[maxY][minX], triZ3 = heightMap[maxY][maxX], sqX = x - minX, sqZ = y - minY, height; if ((sqX + sqZ) < 1) { height = triZ0 + (triZ1 - triZ0) * sqX + (triZ2 - triZ0) * sqZ; } else { height = triZ3 + (triZ1 - triZ3) * (1 - sqZ) + (triZ2 - triZ3) * (1 - sqX); } return height * 128; } return 0; } */ ================================================ FILE: src/viewer/handlers/w3x/shaders/cliffs.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; const shader = ` // #extension GL_OES_standard_derivatives : enable ${precision} uniform sampler2D u_texture1; uniform sampler2D u_texture2; varying vec3 v_normal; varying vec2 v_uv; varying float v_texture; varying vec3 v_position; // const vec3 lightDirection = normalize(vec3(-0.3, -0.3, 0.25)); vec4 sample(float texture, vec2 uv) { // int(0.0) == 0 is not always true. int i = int(texture + 0.1); if (i == 0) { return texture2D(u_texture1, uv); } else { return texture2D(u_texture2, uv); } } void main() { vec4 color = sample(v_texture, v_uv); // vec3 faceNormal = cross(dFdx(v_position), dFdy(v_position)); // vec3 normal = normalize((faceNormal + v_normal) * 0.5); // color *= clamp(dot(normal, lightDirection) + 0.45, 0.1, 1.0); gl_FragColor = color; } `; export default shader; ================================================ FILE: src/viewer/handlers/w3x/shaders/cliffs.vert.ts ================================================ const shader = ` uniform mat4 u_VP; uniform sampler2D u_heightMap; uniform vec2 u_pixel; uniform vec2 u_centerOffset; attribute vec3 a_position; attribute vec3 a_normal; attribute vec2 a_uv; attribute vec3 a_instancePosition; attribute float a_instanceTexture; varying vec3 v_normal; varying vec2 v_uv; varying float v_texture; varying vec3 v_position; void main() { // Half of a pixel in the cliff height map. vec2 halfPixel = u_pixel * 0.5; // The bottom left corner of the map tile this vertex is on. vec2 corner = floor((a_instancePosition.xy - vec2(1.0, 0.0) - u_centerOffset.xy) / 128.0); // Get the 4 closest heights in the height map. float bottomLeft = texture2D(u_heightMap, corner * u_pixel + halfPixel).a; float bottomRight = texture2D(u_heightMap, (corner + vec2(1.0, 0.0)) * u_pixel + halfPixel).a; float topLeft = texture2D(u_heightMap, (corner + vec2(0.0, 1.0)) * u_pixel + halfPixel).a; float topRight = texture2D(u_heightMap, (corner + vec2(1.0, 1.0)) * u_pixel + halfPixel).a; // Do a bilinear interpolation between the heights to get the final value. float bottom = mix(bottomRight, bottomLeft, -a_position.x / 128.0); float top = mix(topRight, topLeft, -a_position.x / 128.0); float height = mix(bottom, top, a_position.y / 128.0); v_normal = a_normal; v_uv = a_uv; v_texture = a_instanceTexture; v_position = a_position + vec3(a_instancePosition.xy, a_instancePosition.z + height * 128.0); gl_Position = u_VP * vec4(v_position, 1.0); } `; export default shader; ================================================ FILE: src/viewer/handlers/w3x/shaders/ground.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; const shader = ` ${precision} uniform sampler2D u_tilesets[15]; varying vec4 v_tilesets; varying vec2 v_uv[4]; varying vec3 v_normal; const vec3 lightDirection = normalize(vec3(-0.3, -0.3, 0.25)); vec4 sample(float tileset, vec2 uv) { // 1.0 - 1.0 == 0.0 is not always true. int i = int(tileset - 0.6); if (i == 0) { return texture2D(u_tilesets[0], uv); } else if (i == 1) { return texture2D(u_tilesets[1], uv); } else if (i == 2) { return texture2D(u_tilesets[2], uv); } else if (i == 3) { return texture2D(u_tilesets[3], uv); } else if (i == 4) { return texture2D(u_tilesets[4], uv); } else if (i == 5) { return texture2D(u_tilesets[5], uv); } else if (i == 6) { return texture2D(u_tilesets[6], uv); } else if (i == 7) { return texture2D(u_tilesets[7], uv); } else if (i == 8) { return texture2D(u_tilesets[8], uv); } else if (i == 9) { return texture2D(u_tilesets[9], uv); } else if (i == 10) { return texture2D(u_tilesets[10], uv); } else if (i == 11) { return texture2D(u_tilesets[11], uv); } else if (i == 12) { return texture2D(u_tilesets[12], uv); } else if (i == 13) { return texture2D(u_tilesets[13], uv); } else if (i == 14) { return texture2D(u_tilesets[14], uv); } } vec4 blend(vec4 color, float tileset, vec2 uv) { vec4 texel = sample(tileset, uv); return mix(color, texel, texel.a); } void main() { vec4 color = sample(v_tilesets[0], v_uv[0]); if (v_tilesets[1] > 0.5) { color = blend(color, v_tilesets[1], v_uv[1]); } if (v_tilesets[2] > 0.5) { color = blend(color, v_tilesets[2], v_uv[2]); } if (v_tilesets[3] > 0.5) { color = blend(color, v_tilesets[3], v_uv[3]); } //color *= clamp(dot(v_normal, lightDirection) + 0.45, 0.0, 1.0); gl_FragColor = vec4(color.rgb, 1.0); } `; export default shader; ================================================ FILE: src/viewer/handlers/w3x/shaders/ground.vert.ts ================================================ const shader = ` uniform mat4 u_VP; uniform sampler2D u_heightMap; uniform vec2 u_size; uniform vec2 u_offset; uniform bool u_extended[14]; uniform float u_baseTileset; attribute vec2 a_position; attribute float a_InstanceID; attribute vec4 a_textures; attribute vec4 a_variations; varying vec4 v_tilesets; varying vec2 v_uv[4]; varying vec3 v_normal; vec2 getCell(float variation) { if (variation < 16.0) { return vec2(mod(variation, 4.0), floor(variation / 4.0)); } else { variation -= 16.0; return vec2(4.0 + mod(variation, 4.0), floor(variation / 4.0)); } } vec2 getUV(vec2 position, bool extended, float variation) { vec2 cell = getCell(variation); vec2 cellSize = vec2(extended ? 0.125 : 0.25, 0.25); vec2 uv = vec2(position.x, 1.0 - position.y); vec2 pixelSize = vec2(1.0 / 512.0, 1.0 / 256.0); /// Note: hardcoded to 512x256 for now. return clamp((cell + uv) * cellSize, cell * cellSize + pixelSize, (cell + 1.0) * cellSize - pixelSize); } void main() { vec4 textures = a_textures - u_baseTileset; if (textures[0] > 0.0 || textures[1] > 0.0 || textures[2] > 0.0 || textures[3] > 0.0) { v_tilesets = textures; v_uv[0] = getUV(a_position, u_extended[int(textures[0]) - 1], a_variations[0]); v_uv[1] = getUV(a_position, u_extended[int(textures[1]) - 1], a_variations[1]); v_uv[2] = getUV(a_position, u_extended[int(textures[2]) - 1], a_variations[2]); v_uv[3] = getUV(a_position, u_extended[int(textures[3]) - 1], a_variations[3]); vec2 corner = vec2(mod(a_InstanceID, u_size.x), floor(a_InstanceID / u_size.x)); vec2 base = corner + a_position; float height = texture2D(u_heightMap, base / u_size).a; float hL = texture2D(u_heightMap, vec2(base - vec2(1.0, 0.0)) / (u_size)).a; float hR = texture2D(u_heightMap, vec2(base + vec2(1.0, 0.0)) / (u_size)).a; float hD = texture2D(u_heightMap, vec2(base - vec2(0.0, 1.0)) / (u_size)).a; float hU = texture2D(u_heightMap, vec2(base + vec2(0.0, 1.0)) / (u_size)).a; v_normal = normalize(vec3(hL - hR, hD - hU, 2.0)); gl_Position = u_VP * vec4(base * 128.0 + u_offset, height * 128.0, 1.0); } else { v_tilesets = vec4(0.0); v_uv[0] = vec2(0.0); v_uv[1] = vec2(0.0); v_uv[2] = vec2(0.0); v_uv[3] = vec2(0.0); v_normal = vec3(0.0); gl_Position = vec4(0.0); } } `; export default shader; ================================================ FILE: src/viewer/handlers/w3x/shaders/water.frag.ts ================================================ import precision from '../../shaders/precision.glsl'; const shader = ` ${precision} uniform sampler2D u_waterTexture; varying vec2 v_uv; varying vec4 v_color; void main() { gl_FragColor = texture2D(u_waterTexture, v_uv) * v_color; } `; export default shader; ================================================ FILE: src/viewer/handlers/w3x/shaders/water.vert.ts ================================================ const shader = ` uniform mat4 u_VP; uniform sampler2D u_heightMap; uniform sampler2D u_waterHeightMap; uniform vec2 u_size; uniform vec2 u_offset; uniform float u_offsetHeight; uniform vec4 u_minDeepColor; uniform vec4 u_maxDeepColor; uniform vec4 u_minShallowColor; uniform vec4 u_maxShallowColor; attribute vec2 a_position; attribute float a_InstanceID; attribute float a_isWater; varying vec2 v_uv; varying vec4 v_color; const float minDepth = 10.0 / 128.0; const float deepLevel = 64.0 / 128.0; const float maxDepth = 72.0 / 128.0; void main() { if (a_isWater > 0.5) { v_uv = a_position; vec2 corner = vec2(mod(a_InstanceID, u_size.x), floor(a_InstanceID / u_size.x)); vec2 base = corner + a_position; float height = texture2D(u_heightMap, base / u_size).a; float waterHeight = texture2D(u_waterHeightMap, base / u_size).a + u_offsetHeight; float value = clamp(waterHeight - height, 0.0, 1.0); if (value <= deepLevel) { value = max(0.0, value - minDepth) / (deepLevel - minDepth); v_color = mix(u_minShallowColor, u_maxShallowColor, value) / 255.0; } else { value = clamp(value - deepLevel, 0.0, maxDepth - deepLevel) / (maxDepth - deepLevel); v_color = mix(u_minDeepColor, u_maxDeepColor, value) / 255.0; } gl_Position = u_VP * vec4(base * 128.0 + u_offset, waterHeight * 128.0, 1.0); } else { v_uv = vec2(0.0); v_color = vec4(0.0); gl_Position = vec4(0.0); } } `; export default shader; ================================================ FILE: src/viewer/handlers/w3x/standsequence.ts ================================================ import Sequence from '../mdx/sequence'; import MdxModel from '../mdx/model'; import MdxModelInstance from '../mdx/modelinstance'; interface FilteredSequence { sequence: Sequence; index: number; } function sequenceSorter(a: FilteredSequence, b: FilteredSequence): number { return a.sequence.rarity - b.sequence.rarity; } function filterSequences(type: string, sequences: Sequence[]): FilteredSequence[] { const filtered = []; for (let i = 0, l = sequences.length; i < l; i++) { const sequence = sequences[i], name = sequence.name.split('-')[0].replace(/\d/g, '').trim().toLowerCase(); if (name === type) { filtered.push({ sequence, index: i }); } } return filtered; } function selectSequence(type: string, sequences: Sequence[]): FilteredSequence { const filtered = filterSequences(type, sequences); let i, l; filtered.sort(sequenceSorter); for (i = 0, l = filtered.length; i < l; i++) { const sequence = filtered[i].sequence; const rarity = sequence.rarity; if (rarity === 0) { break; } if (Math.random() * 10 > rarity) { return filtered[i]; } } const sequencesLeft = filtered.length - i; const random = i + Math.floor(Math.random() * sequencesLeft); const sequence = filtered[random]; return sequence; } export default function randomStandSequence(target: MdxModelInstance): void { const model = target.model; const sequences = model.sequences; const sequence = selectSequence('stand', sequences); if (sequence) { target.setSequence(sequence.index); } } ================================================ FILE: src/viewer/handlers/w3x/terraindoodad.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { VEC3_UNIT_Z } from '../../../common/gl-matrix-addon'; import { degToRad } from '../../../common/math'; import { MappedDataRow } from '../../../utils/mappeddata'; import DooTerrainDoodad from '../../../parsers/w3x/doo/terraindoodad'; import MdxModel from '../mdx/model'; import MdxModelInstance from '../mdx/modelinstance'; import War3MapViewerMap from './map'; const locationHeap = vec3.create(); /** * A cliff/terrain doodad. */ export default class TerrainDoodad { instance: MdxModelInstance; row: MappedDataRow; constructor(map: War3MapViewerMap, model: MdxModel, row: MappedDataRow, doodad: DooTerrainDoodad) { const centeroffset = map.centerOffset; const instance = model.addInstance(); locationHeap[0] = doodad.location[0] * 128 + centeroffset[0] + 128; locationHeap[1] = doodad.location[1] * 128 + centeroffset[1] + 128; instance.move(locationHeap); instance.rotateLocal(quat.setAxisAngle(quat.create(), VEC3_UNIT_Z, degToRad(row.number('fixedRot')))); instance.setScene(map.worldScene); this.instance = instance; this.row = row; } } ================================================ FILE: src/viewer/handlers/w3x/terrainmodel.ts ================================================ import MdlxModel from '../../../parsers/mdlx/model'; import Shader from '../../gl/shader'; import War3MapViewerMap from './map'; /** * A static terrain model. */ export default class TerrainModel { map: War3MapViewerMap; vertexBuffer: WebGLBuffer; faceBuffer: WebGLBuffer; normalsOffset: number; uvsOffset: number; elements: number; locationAndTextureBuffer: WebGLBuffer; texturesOffset: number; instances: number; vao: WebGLVertexArrayObjectOES | null; constructor(map: War3MapViewerMap, arrayBuffer: ArrayBuffer, locations: number[], textures: number[], shader: Shader) { const gl = map.viewer.gl; const webgl = map.viewer.webgl; const instancedArrays = webgl.extensions['ANGLE_instanced_arrays']; const vertexArrayObject = webgl.extensions['OES_vertex_array_object']; const parser = new MdlxModel(); parser.load(arrayBuffer); const geoset = parser.geosets[0]; const vertices = geoset.vertices; const normals = geoset.normals; const uvs = geoset.uvSets[0]; const faces = geoset.faces; const normalsOffset = vertices.byteLength; const uvsOffset = normalsOffset + normals.byteLength; let vao = null; const attribs = shader.attribs; if (vertexArrayObject) { vao = vertexArrayObject.createVertexArrayOES(); vertexArrayObject.bindVertexArrayOES(vao); } const vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, uvsOffset + uvs.byteLength, gl.STATIC_DRAW); gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertices); gl.bufferSubData(gl.ARRAY_BUFFER, normalsOffset, normals); gl.bufferSubData(gl.ARRAY_BUFFER, uvsOffset, uvs); if (vertexArrayObject) { gl.vertexAttribPointer(attribs['a_position'], 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(attribs['a_position']); gl.vertexAttribPointer(attribs['a_normal'], 3, gl.FLOAT, false, 0, normalsOffset); gl.enableVertexAttribArray(attribs['a_normal']); gl.vertexAttribPointer(attribs['a_uv'], 2, gl.FLOAT, false, 0, uvsOffset); gl.enableVertexAttribArray(attribs['a_uv']); } const texturesOffset = locations.length * 4; const locationAndTextureBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, locationAndTextureBuffer); gl.bufferData(gl.ARRAY_BUFFER, texturesOffset + textures.length, gl.STATIC_DRAW); gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(locations)); gl.bufferSubData(gl.ARRAY_BUFFER, texturesOffset, new Uint8Array(textures)); if (vertexArrayObject) { gl.vertexAttribPointer(attribs['a_instancePosition'], 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(attribs['a_instancePosition']); instancedArrays.vertexAttribDivisorANGLE(attribs['a_instancePosition'], 1); gl.vertexAttribPointer(attribs['a_instanceTexture'], 1, gl.UNSIGNED_BYTE, false, 0, texturesOffset); gl.enableVertexAttribArray(attribs['a_instanceTexture']); instancedArrays.vertexAttribDivisorANGLE(attribs['a_instanceTexture'], 1); } const faceBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, faceBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW); if (vertexArrayObject) { vertexArrayObject.bindVertexArrayOES(null); } this.map = map; this.vertexBuffer = vertexBuffer; this.faceBuffer = faceBuffer; this.normalsOffset = normalsOffset; this.uvsOffset = uvsOffset; this.elements = faces.length; this.locationAndTextureBuffer = locationAndTextureBuffer; this.texturesOffset = texturesOffset; this.instances = locations.length / 3; this.vao = vao; } render(shader: Shader): void { const viewer = this.map.viewer; const gl = viewer.gl; const webgl = viewer.webgl; const instancedArrays = webgl.extensions['ANGLE_instanced_arrays']; const vertexArrayObject = webgl.extensions['OES_vertex_array_object']; const attribs = shader.attribs; if (vertexArrayObject) { vertexArrayObject.bindVertexArrayOES(this.vao); } else { // Locations and textures. gl.bindBuffer(gl.ARRAY_BUFFER, this.locationAndTextureBuffer); gl.vertexAttribPointer(attribs['a_instancePosition'], 3, gl.FLOAT, false, 0, 0); gl.vertexAttribPointer(attribs['a_instanceTexture'], 1, gl.UNSIGNED_BYTE, false, 0, this.texturesOffset); // Vertices. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.vertexAttribPointer(attribs['a_position'], 3, gl.FLOAT, false, 0, 0); gl.vertexAttribPointer(attribs['a_normal'], 3, gl.FLOAT, false, 0, this.normalsOffset); gl.vertexAttribPointer(attribs['a_uv'], 2, gl.FLOAT, false, 0, this.uvsOffset); // Faces. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.faceBuffer); } // Draw. instancedArrays.drawElementsInstancedANGLE(gl.TRIANGLES, this.elements, gl.UNSIGNED_SHORT, 0, this.instances); if (vertexArrayObject) { vertexArrayObject.bindVertexArrayOES(null); } } } ================================================ FILE: src/viewer/handlers/w3x/unit.ts ================================================ import { vec3, quat } from 'gl-matrix'; import { VEC3_UNIT_Z } from '../../../common/gl-matrix-addon'; import { MappedDataRow } from '../../../utils/mappeddata'; import DooUnit from '../../../parsers/w3x/unitsdoo/unit'; import MdxModel from '../mdx/model'; import War3MapViewerMap from './map'; import { Widget } from './widget'; const heapZ = vec3.create(); /** * A unit. */ export default class Unit extends Widget { /** * StartLocation.mdx (and others?) seems to be built-in, and has no row. */ row: MappedDataRow | undefined; constructor(map: War3MapViewerMap, model: MdxModel, row: MappedDataRow | undefined, unit: DooUnit) { super(map, model); const instance = this.instance; instance.move(unit.location); instance.rotateLocal(quat.setAxisAngle(quat.create(), VEC3_UNIT_Z, unit.angle)); instance.scale(unit.scale); instance.setTeamColor(unit.player); instance.setScene(map.worldScene); if (row) { heapZ[2] = row.number('moveHeight'); instance.move(heapZ); instance.setVertexColor([row.number('red') / 255, row.number('green') / 255, row.number('blue') / 255, 1]); instance.uniformScale(row.number('modelScale')); } this.instance = instance; this.row = row; } } ================================================ FILE: src/viewer/handlers/w3x/variations.ts ================================================ const cliffVariations = { AAAB: 1, AAAC: 1, AABA: 1, AABB: 2, AABC: 0, AACA: 1, AACB: 0, AACC: 1, ABAA: 1, ABAB: 1, ABAC: 0, ABBA: 2, ABBB: 1, ABBC: 0, ABCA: 0, ABCB: 0, ABCC: 0, ACAA: 1, ACAB: 0, ACAC: 1, ACBA: 0, ACBB: 0, ACBC: 0, ACCA: 1, ACCB: 0, ACCC: 1, BAAA: 1, BAAB: 1, BAAC: 0, BABA: 1, BABB: 1, BABC: 0, BACA: 0, BACB: 0, BACC: 0, BBAA: 1, BBAB: 1, BBAC: 0, BBBA: 1, BBCA: 0, BCAA: 0, BCAB: 0, BCAC: 0, BCBA: 0, BCCA: 0, CAAA: 1, CAAB: 0, CAAC: 1, CABA: 0, CABB: 0, CABC: 0, CACA: 1, CACB: 0, CACC: 1, CBAA: 0, CBAB: 0, CBAC: 0, CBBA: 0, CBCA: 0, CCAA: 1, CCAB: 0, CCAC: 1, CCBA: 0, CCCA: 1, }; const cityCliffVariations = { AAAB: 2, AAAC: 1, AABA: 1, AABB: 3, AABC: 0, AACA: 1, AACB: 0, AACC: 3, ABAA: 1, ABAB: 2, ABAC: 0, ABBA: 3, ABBB: 0, ABBC: 0, ABCA: 0, ABCB: 0, ABCC: 0, ACAA: 1, ACAB: 0, ACAC: 2, ACBA: 0, ACBB: 0, ACBC: 0, ACCA: 3, ACCB: 0, ACCC: 1, BAAA: 1, BAAB: 3, BAAC: 0, BABA: 2, BABB: 0, BABC: 0, BACA: 0, BACB: 0, BACC: 0, BBAA: 3, BBAB: 1, BBAC: 0, BBBA: 1, BBCA: 0, BCAA: 0, BCAB: 0, BCAC: 0, BCBA: 0, BCCA: 0, CAAA: 1, CAAB: 0, CAAC: 3, CABA: 0, CABB: 0, CABC: 0, CACA: 2, CACB: 0, CACC: 1, CBAA: 0, CBAB: 0, CBAC: 0, CBBA: 0, CBCA: 0, CCAA: 3, CCAB: 0, CCAC: 1, CCBA: 0, CCCA: 1, }; export default function getCliffVariation(dir: string, tag: string, variation: number): number { if (dir === 'Cliffs') { return Math.min(variation, cliffVariations[tag]); } else { return Math.min(variation, cityCliffVariations[tag]); } } ================================================ FILE: src/viewer/handlers/w3x/viewer.ts ================================================ import { FetchDataTypeName } from '../../../common/fetchdatatype'; import { MappedData } from '../../../utils/mappeddata'; import ModelViewer from '../../viewer'; import Shader from '../../gl/shader'; import { PathSolver } from '../../handlerresource'; import mdxHandler from '../mdx/handler'; import blpHandler from '../blp/handler'; import tgaHandler from '../tga/handler'; import ddsHandler from '../dds/handler'; import groundVert from './shaders/ground.vert'; import groundFrag from './shaders/ground.frag'; import waterVert from './shaders/water.vert'; import waterFrag from './shaders/water.frag'; import cliffsVert from './shaders/cliffs.vert'; import cliffsFrag from './shaders/cliffs.frag'; import War3MapViewerMap from './map'; import GenericResource from '../../genericresource'; export default class War3MapViewer extends ModelViewer { wc3PathSolver: PathSolver; isReforged: boolean; groundShader: Shader; waterShader: Shader; cliffShader: Shader; terrainData = new MappedData(); cliffTypesData = new MappedData(); waterData = new MappedData(); doodadsData = new MappedData(); doodadMetaData = new MappedData(); destructableMetaData = new MappedData(); unitsData = new MappedData(); unitMetaData = new MappedData(); loadedBaseFiles = false; map: War3MapViewerMap | null = null; constructor(canvas: HTMLCanvasElement, wc3PathSolver: PathSolver, isReforged: boolean) { super(canvas); const webgl = this.webgl; // Data textures. if (!webgl.ensureExtension('OES_texture_float')) { throw new Error('War3MapViewer: No float texture support!'); } // Optionally used for cliff renering. if (!webgl.ensureExtension('OES_vertex_array_object')) { console.warn('War3MapViewer: No vertex array object support! This might reduce performance.'); } this.on('error', (e) => console.log(e)); this.addHandler(mdxHandler, wc3PathSolver, isReforged); this.addHandler(blpHandler); this.addHandler(tgaHandler); this.addHandler(ddsHandler); this.wc3PathSolver = wc3PathSolver; this.isReforged = isReforged; this.groundShader = this.webgl.createShader(groundVert, groundFrag); this.waterShader = this.webgl.createShader(waterVert, waterFrag); this.cliffShader = this.webgl.createShader(cliffsVert, cliffsFrag); this.loadBaseFiles(); } async loadBaseFiles(): Promise { const promises = [ this.loadBaseFile('TerrainArt\\Terrain.slk', 'text'), this.loadBaseFile('TerrainArt\\CliffTypes.slk', 'text'), this.loadBaseFile('TerrainArt\\Water.slk', 'text'), this.loadBaseFile('Doodads\\Doodads.slk', 'text'), this.loadBaseFile('Doodads\\DoodadMetaData.slk', 'text'), this.loadBaseFile('Units\\DestructableData.slk', 'text'), this.loadBaseFile('Units\\DestructableMetaData.slk', 'text'), this.loadBaseFile('Units\\UnitData.slk', 'text'), this.loadBaseFile('Units\\unitUI.slk', 'text'), this.loadBaseFile('Units\\ItemData.slk', 'text'), this.loadBaseFile('Units\\UnitMetaData.slk', 'text'), ]; let reforgedPromises; if (this.isReforged) { reforgedPromises = [ this.loadBaseFile('Doodads\\doodadSkins.txt', 'text'), this.loadBaseFile('Units\\destructableSkin.txt', 'text'), this.loadBaseFile('Units\\unitSkin.txt', 'text'), this.loadBaseFile('Units\\itemSkin.txt', 'text'), ]; } const [terrain, cliffTypes, water, doodads, doodadMetaData, destructableData, destructableMetaData, unitData, unitUi, itemData, unitMetaData] = await Promise.all(promises); if (!terrain || !cliffTypes || !water || !doodads || !doodadMetaData || !destructableData || !destructableMetaData || !unitData || !unitUi || !itemData || !unitMetaData) { throw new Error('Failed to load the base files'); } this.terrainData.load(terrain.data); this.cliffTypesData.load(cliffTypes.data); this.waterData.load(water.data); this.doodadsData.load(doodads.data); this.doodadMetaData.load(doodadMetaData.data); this.doodadsData.load(destructableData.data); this.destructableMetaData.load(destructableMetaData.data); this.unitsData.load(unitData.data); this.unitsData.load(unitUi.data); this.unitsData.load(itemData.data); this.unitMetaData.load(unitMetaData.data); if (reforgedPromises) { const [doodadSkins, destructableSkin, unitSkin, itemSkin] = await Promise.all(reforgedPromises); if (!doodadSkins || !destructableSkin || !unitSkin || !itemSkin) { throw new Error('Failed to load the base Reforged files'); } this.doodadsData.load(doodadSkins.data); this.doodadsData.load(destructableSkin.data); this.unitsData.load(unitSkin.data); this.unitsData.load(itemSkin.data); } this.loadedBaseFiles = true; this.emit('loadedbasefiles'); } loadBaseFile(path: string, dataType: FetchDataTypeName): Promise { return super.loadGeneric(this.wc3PathSolver(path), dataType); } /** * Load a map from a buffer. */ loadMap(buffer: ArrayBuffer | Uint8Array): void { if (this.loadedBaseFiles) { if (this.map) { this.map.die(); } this.map = new War3MapViewerMap(this, buffer); } } /** * Update the map. */ override update(): void { if (this.map) { super.update(); this.map.update(); } } /** * Render the map. */ override render(): void { if (this.map) { this.map.render(); } } } ================================================ FILE: src/viewer/handlers/w3x/widget.ts ================================================ import MdxModel from '../mdx/model'; import MdxModelInstance from '../mdx/modelinstance'; import War3MapViewerMap from './map'; import randomStandSequence from './standsequence'; export enum WidgetState { IDLE, WALK, } /** * A widget. */ export class Widget { instance: MdxModelInstance; state = WidgetState.IDLE; constructor(map: War3MapViewerMap, model: MdxModel) { this.instance = model.addInstance(); this.instance.setScene(map.worldScene); } update(): void { if (this.instance.sequenceEnded || this.instance.sequence === -1) { if (this.state === WidgetState.IDLE) { randomStandSequence(this.instance); } } } } ================================================ FILE: src/viewer/imagetexture.ts ================================================ import { isPowerOfTwo } from '../common/math'; import { isGif, isJpeg, isPng, isWebP } from '../common/isformat'; import Texture from './texture'; import { HandlerResourceData } from './handlerresource'; /** * Checks if the given source is a supported image texture source. */ export function isImageSource(src: unknown): boolean { return src instanceof ImageData || src instanceof HTMLImageElement || src instanceof HTMLCanvasElement || src instanceof HTMLVideoElement; } /** * Detects whether the given buffer is a supported format, and if so returns the mime. * The supported formats are PNG, JPEG, GIF, and WebP. */ export function detectMime(buffer: Uint8Array): string { if (isPng(buffer)) { return 'image/png'; } if (isJpeg(buffer)) { return 'image/jpeg'; } if (isGif(buffer)) { return 'image/gif'; } if (isWebP(buffer)) { return 'image/webp'; } return ''; } /** * A texture handler for image sources. */ export class ImageTexture extends Texture { constructor(src: TexImageSource, resourceData: HandlerResourceData) { super(resourceData); const gl = this.viewer.gl; this.webglResource = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.webglResource); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); if (isPowerOfTwo(src.width) && isPowerOfTwo(src.height)) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); gl.generateMipmap(gl.TEXTURE_2D); } else { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // Required for NPOT textures. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); } this.width = src.width; this.height = src.height; } } ================================================ FILE: src/viewer/index.ts ================================================ import ModelViewer, { DebugRenderMode } from './viewer'; import Scene from './scene'; import Camera from './camera'; import { Node } from './node'; import Model from './model'; import ModelInstance from './modelinstance'; import Texture from './texture'; import GenericResource from './genericresource'; import gl from './gl'; import handlers from './handlers'; export default { ModelViewer, DebugRenderMode, Scene, Camera, Node, Model, ModelInstance, Texture, GenericResource, gl, handlers, }; ================================================ FILE: src/viewer/model.ts ================================================ import { HandlerResource } from './handlerresource'; import Bounds from './bounds'; import ModelInstance from './modelinstance'; /** * A model. */ export default abstract class Model extends HandlerResource { bounds = new Bounds(); /** * Create a new instance and return it. */ abstract addInstance(): ModelInstance; } ================================================ FILE: src/viewer/modelinstance.ts ================================================ import { testSphere, distanceToPlane3 } from '../common/gl-matrix-addon'; import { Node } from './node'; import Model from './model'; import Scene from './scene'; import Camera from './camera'; import Texture from './texture'; import Bounds from './bounds'; /** * A model instance. */ export default abstract class ModelInstance extends Node { scene: Scene | null = null; left = -1; right = -1; bottom = -1; top = -1; plane = -1; depth = 0; updateFrame = 0; model: Model; /** * Allows to slow down or speed up animations of this instance, and any children. */ timeScale = 1; /** * If false, this instance won't be rendered. * * When working with Warcraft 3 instances, it is preferable to use hide() and show(). * These hide and show also internal instances of this instance. */ rendered = true; textureOverrides: Map = new Map(); constructor(model: Model) { super(); this.model = model; } /** * This instance should be shown. */ show(): void { this.rendered = true; } /** * This instance should be hidden. */ hide(): void { this.rendered = false; } /** * Should the instance be shown? */ shown(): boolean { return this.rendered; } /** * Should the instance be hidden? */ hidden(): boolean { return !this.rendered; } /** * Detach this instance from the scene it's in. * * Equivalent to scene.removeInstance(instance). */ detach(): boolean { if (this.scene) { return this.scene.removeInstance(this); } return false; } overrideTexture(index: number, texture?: Texture): void { if (texture) { this.textureOverrides.set(index, texture); } else { this.textureOverrides.delete(index); } } /** * Called for instance culling. */ getBounds(): Bounds { return this.model.bounds; } /** * Clears any objects that were emitted by this instance. */ clearEmittedObjects(): void { } /** * Sets the scene of this instance. * * This is equivalent to scene.addInstance(instance). */ setScene(scene: Scene): boolean { return scene.addInstance(this); } override recalculateTransformation(): void { super.recalculateTransformation(); if (this.scene) { this.scene.grid.moved(this); } } override update(dt: number): void { const scene = this.scene; if (scene && this.rendered && this.isVisible(scene.camera)) { // Add this instance to the render list. scene.renderInstance(this); // Update this instance. this.updateAnimations(dt * this.timeScale); // Update child nodes if there are any, such as instances parented to instances. super.update(dt); } } updateAnimations(_dt: number): void { } renderOpaque(): void { } renderTranslucent(): void { } isVisible(camera: Camera): boolean { const [x, y, z] = this.worldLocation; const [sx, sy, sz] = this.worldScale; const bounds = this.getBounds(); const planes = camera.planes; let biggest = sx; // Get the biggest scaling dimension. if (sy > biggest) { biggest = sy; } if (sz > biggest) { biggest = sz; } this.plane = testSphere(planes, x + bounds.x, y + bounds.y, z + bounds.z, bounds.r * biggest, this.plane); if (this.plane === -1) { this.depth = distanceToPlane3(planes[4], x, y, z); return true; } return false; } } ================================================ FILE: src/viewer/node.ts ================================================ import { vec3, quat, mat4 } from 'gl-matrix'; import { VEC3_ZERO, VEC3_ONE, QUAT_DEFAULT, quatLookAt } from '../common/gl-matrix-addon'; import { SkeletalNode } from './skeletalnode'; const locationHeap = vec3.create(); const rotationHeap = quat.create(); const scalingHeap = vec3.create(); /** * A node. */ export class Node { pivot = vec3.create(); localLocation = vec3.create(); localRotation = quat.create(); localScale = vec3.fromValues(1, 1, 1); worldLocation = vec3.create(); worldRotation = quat.create(); worldScale = vec3.fromValues(1, 1, 1); inverseWorldLocation = vec3.create(); inverseWorldRotation = quat.create(); inverseWorldScale = vec3.fromValues(1, 1, 1); localMatrix = mat4.create(); worldMatrix = mat4.create(); dontInheritTranslation = false; dontInheritRotation = false; dontInheritScaling = true; parent: Node | SkeletalNode | null = null; children: Node[] = []; /** * Sets the node's pivot. */ setPivot(pivot: vec3): this { vec3.copy(this.pivot, pivot); this.recalculateTransformation(); return this; } /** * Sets the node's local location. */ setLocation(location: vec3): this { vec3.copy(this.localLocation, location); this.recalculateTransformation(); return this; } /** * Sets the node's local rotation. */ setRotation(rotation: quat): this { quat.copy(this.localRotation, rotation); this.recalculateTransformation(); return this; } /** * Sets the node's local scale. */ setScale(varying: vec3): this { vec3.copy(this.localScale, varying); this.recalculateTransformation(); return this; } /** * Sets the node's local scale uniformly. */ setUniformScale(uniform: number): this { vec3.set(this.localScale, uniform, uniform, uniform); this.recalculateTransformation(); return this; } /** * Sets the node's local location, rotation, and scale. */ setTransformation(location: vec3, rotation: quat, scale: vec3): this { const localLocation = this.localLocation; const localRotation = this.localRotation; const localScale = this.localScale; localLocation[0] = location[0]; localLocation[1] = location[1]; localLocation[2] = location[2]; // vec3.copy(this.localLocation, location); localRotation[0] = rotation[0]; localRotation[1] = rotation[1]; localRotation[2] = rotation[2]; localRotation[3] = rotation[3]; // quat.copy(this.localRotation, rotation); localScale[0] = scale[0]; localScale[1] = scale[1]; localScale[2] = scale[2]; // vec3.copy(this.localScale, scale); this.recalculateTransformation(); return this; } /** * Resets the node's local location, pivot, rotation, and scale, to the default values. */ resetTransformation(): this { vec3.copy(this.pivot, VEC3_ZERO); vec3.copy(this.localLocation, VEC3_ZERO); quat.copy(this.localRotation, QUAT_DEFAULT); vec3.copy(this.localScale, VEC3_ONE); this.recalculateTransformation(); return this; } /** * Moves the node's pivot. */ movePivot(offset: vec3): this { vec3.add(this.pivot, this.pivot, offset); this.recalculateTransformation(); return this; } /** * Moves the node's local location. */ move(offset: vec3): this { vec3.add(this.localLocation, this.localLocation, offset); this.recalculateTransformation(); return this; } /** * Rotates the node's local rotation in world space. */ rotate(rotation: quat): this { quat.mul(this.localRotation, this.localRotation, rotation); this.recalculateTransformation(); return this; } /** * Rotates the node's local rotation in local space. */ rotateLocal(rotation: quat): this { quat.mul(this.localRotation, rotation, this.localRotation); this.recalculateTransformation(); return this; } /** * Scales the node. */ scale(scale: vec3): this { vec3.mul(this.localScale, this.localScale, scale); this.recalculateTransformation(); return this; } /** * Scales the node uniformly. */ uniformScale(scale: number): this { vec3.scale(this.localScale, this.localScale, scale); this.recalculateTransformation(); return this; } face(to: vec3, worldUp: vec3): this { quat.conjugate(this.localRotation, quatLookAt(this.localRotation, this.localLocation, to, worldUp)); this.recalculateTransformation(); return this; } /** * Sets the node's parent. */ setParent(parent?: Node | SkeletalNode): this { // If the node already had a parent, detach from it first. if (this.parent) { const children = this.parent.children; const index = children.indexOf(this); if (index !== -1) { children.splice(index, 1); } } this.parent = parent || null; // If the new parent is an actual thing, add this node as a child. if (parent) { parent.children.push(this); } this.recalculateTransformation(); return this; } /** * Recalculate this node's transformation data. */ recalculateTransformation(): void { const parent = this.parent; const localMatrix = this.localMatrix; const localLocation = this.localLocation; const localRotation = this.localRotation; const localScale = this.localScale; const worldMatrix = this.worldMatrix; const worldLocation = this.worldLocation; const worldRotation = this.worldRotation; const worldScale = this.worldScale; const inverseWorldLocation = this.inverseWorldLocation; const inverseWorldRotation = this.inverseWorldRotation; const inverseWorldScale = this.inverseWorldScale; if (parent) { const computedLocation = locationHeap; const parentPivot = parent.pivot; let computedRotation; let computedScaling; computedLocation[0] = localLocation[0] + parentPivot[0]; computedLocation[1] = localLocation[1] + parentPivot[1]; computedLocation[2] = localLocation[2] + parentPivot[2]; // vec3.add(computedLocation, localLocation, parentPivot); // If this node shouldn't inherit the parent's rotation, rotate it by the inverse. if (this.dontInheritRotation) { computedRotation = rotationHeap; quat.mul(computedRotation, localRotation, parent.inverseWorldRotation); } else { computedRotation = localRotation; } // If this node shouldn't inherit the parent's translation, translate it by the inverse. // if (this.dontInheritTranslation) { // mat4.translate(worldMatrix, worldMatrix, parent.inverseWorldLocation); // } if (this.dontInheritScaling) { computedScaling = scalingHeap; const parentInverseScale = parent.inverseWorldScale; computedScaling[0] = parentInverseScale[0] * localScale[0]; computedScaling[1] = parentInverseScale[1] * localScale[1]; computedScaling[2] = parentInverseScale[2] * localScale[2]; // vec3.mul(computedScaling, parent.inverseWorldScale, localScale); worldScale[0] = localScale[0]; worldScale[1] = localScale[1]; worldScale[2] = localScale[2]; // vec3.copy(worldScale, localScale); } else { computedScaling = localScale; const parentScale = parent.worldScale; worldScale[0] = parentScale[0] * localScale[0]; worldScale[1] = parentScale[1] * localScale[1]; worldScale[2] = parentScale[2] * localScale[2]; // vec3.mul(worldScale, parentScale, localScale); } mat4.fromRotationTranslationScale(localMatrix, computedRotation, computedLocation, computedScaling); mat4.mul(worldMatrix, parent.worldMatrix, localMatrix); quat.mul(worldRotation, parent.worldRotation, computedRotation); } else { // Local matrix mat4.fromRotationTranslationScale(localMatrix, localRotation, localLocation, localScale); // World matrix worldMatrix[0] = localMatrix[0]; worldMatrix[1] = localMatrix[1]; worldMatrix[2] = localMatrix[2]; worldMatrix[3] = localMatrix[3]; worldMatrix[4] = localMatrix[4]; worldMatrix[5] = localMatrix[5]; worldMatrix[6] = localMatrix[6]; worldMatrix[7] = localMatrix[7]; worldMatrix[8] = localMatrix[8]; worldMatrix[9] = localMatrix[9]; worldMatrix[10] = localMatrix[10]; worldMatrix[11] = localMatrix[11]; worldMatrix[12] = localMatrix[12]; worldMatrix[13] = localMatrix[13]; worldMatrix[14] = localMatrix[14]; worldMatrix[15] = localMatrix[15]; // mat4.copy(worldMatrix, localMatrix); // World rotation worldRotation[0] = localRotation[0]; worldRotation[1] = localRotation[1]; worldRotation[2] = localRotation[2]; worldRotation[3] = localRotation[3]; // quat.copy(worldRotation, localRotation); // World scale worldScale[0] = localScale[0]; worldScale[1] = localScale[1]; worldScale[2] = localScale[2]; // vec3.copy(worldScale, localScale); } // Inverse world rotation inverseWorldRotation[0] = -worldRotation[0]; inverseWorldRotation[1] = -worldRotation[1]; inverseWorldRotation[2] = -worldRotation[2]; inverseWorldRotation[3] = worldRotation[3]; // quat.conjugate(inverseWorldRotation, worldRotation); // Inverse world scale inverseWorldScale[0] = 1 / worldScale[0]; inverseWorldScale[1] = 1 / worldScale[1]; inverseWorldScale[2] = 1 / worldScale[2]; // vec3.inverse(this.inverseWorldScale, worldScale); // World location worldLocation[0] = worldMatrix[12]; worldLocation[1] = worldMatrix[13]; worldLocation[2] = worldMatrix[14]; // Inverse world location inverseWorldLocation[0] = -worldLocation[0]; inverseWorldLocation[1] = -worldLocation[1]; inverseWorldLocation[2] = -worldLocation[2]; // vec3.negate(this.inverseWorldLocation, worldLocation); for (const child of this.children) { child.recalculateTransformation(); } } /** * Update this node, and continue down the node hierarchy. */ update(dt: number): void { for (const child of this.children) { child.update(dt); } } } ================================================ FILE: src/viewer/resource.ts ================================================ import ModelViewer from './viewer'; /** * The data sent to every resource as a part of the loading process. */ export type ResourceData = { viewer: ModelViewer, fetchUrl: string }; /** * A viewer resource. * * Generally speaking resources are created via viewer.load(), or viewer.loadGeneric(). */ export abstract class Resource { viewer: ModelViewer; fetchUrl: string; blockers: Promise[] = []; constructor(resourceData: ResourceData) { this.viewer = resourceData.viewer; this.fetchUrl = resourceData.fetchUrl; } /** * Remove this resource from its viewer's cache. * * Equivalent to viewer.unload(resource). */ detach(): boolean { return this.viewer.unload(this); } } ================================================ FILE: src/viewer/scene.ts ================================================ import { vec3, vec4 } from 'gl-matrix'; import ModelViewer from './viewer'; import Camera from './camera'; import Grid from './grid'; import ModelInstance from './modelinstance'; import EmittedObjectUpdater from './emittedobjectupdater'; /** * A scene. * * Every scene has its own list of model instances, and its own camera and viewport. * * In addition, every scene may have its own AudioContext if enableAudio() is called. * If audio is enabled, the AudioContext's listener's location will be updated automatically. * Note that due to browser policies, this may be done only after user interaction with the web page. */ export default class Scene { viewer: ModelViewer; camera = new Camera(); grid = new Grid(-100000, -100000, 200000, 200000, 200000, 200000); visibleCells = 0; visibleInstances = 0; updatedParticles = 0; audioEnabled = false; audioContext: AudioContext | null = null; instances: ModelInstance[] = []; emittedObjectUpdater = new EmittedObjectUpdater(); /** * Similar to WebGL's own `alpha` parameter. * * If false, the scene will be cleared before rendering, meaning that scenes behind it won't be visible through it. * * If true, alpha works as usual. */ alpha = false; /** * The scene's background color. * * Only used if `alpha` is false. */ color = vec3.create(); /** * The area on the canvas in which this scene is rendered. * * Defaults to the entire canvas. * * The vector defines [x, y, width, height], sizes are in pixels, and everything is related to the bottom left corner of the canvas. */ viewport = vec4.create(); /** * The position of the light that is used when rendering. * * Affects HD MDX and M3 models. */ lightPosition = vec3.fromValues(0, 0, 10000); constructor(viewer: ModelViewer) { this.viewer = viewer; const canvas = viewer.canvas; const width = canvas.width; const height = canvas.height; // Use the whole canvas by default. this.viewport[2] = width; this.viewport[3] = height; // And standard perspective projection. this.camera.perspective(Math.PI / 4, width / height, 8, 10000); } /** * Creates an AudioContext if one wasn't created already, and resumes it if needed. * * The returned promise will resolve to whether it is actually running or not. * * It may stay in suspended state indefinitly until the user interacts with the page, due to browser policies. */ async enableAudio(): Promise { if (typeof AudioContext === 'function') { if (!this.audioContext) { this.audioContext = new AudioContext(); } if (this.audioContext.state !== 'suspended') { await this.audioContext.resume(); } this.audioEnabled = this.audioContext.state === 'running'; return this.audioEnabled; } return false; } /** * Suspend the audio context. */ disableAudio(): void { if (this.audioContext) { this.audioContext.suspend(); } this.audioEnabled = false; } /** * Sets the scene of the given instance. * * Equivalent to instance.setScene(scene). */ addInstance(instance: ModelInstance): boolean { if (instance.scene !== this) { if (instance.scene) { instance.scene.removeInstance(instance); } instance.scene = this; this.grid.moved(instance); return true; } return false; } /** * Remove the given instance from this scene. * * Equivalent to ModelInstance.detach(). */ removeInstance(instance: ModelInstance): boolean { if (instance.scene === this) { this.grid.remove(instance); instance.scene = null; return true; } return false; } /** * Clear this scene. */ clear(): void { // First remove references to this scene stored in the instances. for (const cell of this.grid.cells) { for (const instance of cell.instances) { instance.scene = null; } } // Then remove references to the instances. this.grid.clear(); } /** * Detach this scene from the viewer. * * Equivalent to viewer.removeScene(scene). */ detach(): boolean { if (this.viewer) { return this.viewer.removeScene(this); } return false; } /** * Update this scene. */ update(dt: number): void { const camera = this.camera; // Update the audio context's position if it exists. if (this.audioContext) { const listener = this.audioContext.listener; const position = camera.location; const forward = camera.directionY; const up = camera.directionZ; listener.positionX.value = -position[0]; listener.positionY.value = -position[1]; listener.positionZ.value = -position[2]; listener.forwardX.value = forward[0]; listener.forwardY.value = forward[1]; listener.forwardZ.value = forward[2]; listener.upX.value = up[0]; listener.upY.value = up[1]; listener.upZ.value = up[2]; } const frame = this.viewer.frame; const instances = this.instances; this.visibleCells = 0; this.visibleInstances = 0; // Update and collect all of the visible instances. for (const cell of this.grid.cells) { if (cell.isVisible(camera)) { this.visibleCells += 1; for (const instance of cell.instances) { // If an instance is rendered, wasn't updated on this frame, and has no parent, update it. // If the instance is visible, it will be updated, all of its children will be updated, and it will be added to the render list. // Note that the update frame is needed because instances can exist in any number of cells at the same time. if (instance.rendered && instance.updateFrame < frame && !instance.parent) { instance.updateFrame = frame; instance.update(dt); } } } } // Sort the visible instances based on depth. instances.length = this.visibleInstances; instances.sort((a, b) => a.depth - b.depth); this.emittedObjectUpdater.update(dt); this.updatedParticles = this.emittedObjectUpdater.alive; } renderInstance(instance: ModelInstance): void { this.instances[this.visibleInstances++] = instance; } /** * Use the scene's viewport. * * Should be called before `renderOpaque()` and `renderTranslucent()`. * * Called automatically by `render()`. */ startFrame(): void { const gl = this.viewer.gl; const viewport = this.viewport; // Set the viewport. gl.viewport(viewport[0], viewport[1], viewport[2], viewport[3]); // Allow to render only in the viewport. gl.scissor(viewport[0], viewport[1], viewport[2], viewport[3]); // If this scene doesn't want alpha, clear it. if (!this.alpha) { const color = this.color; gl.depthMask(true); gl.clearColor(color[0], color[1], color[2], 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } } /** * Render opaque things in this scene. * * They are rendered front to back. */ renderOpaque(): void { const instances = this.instances; for (let i = 0, l = instances.length; i < l; i++) { instances[i].renderOpaque(); } } /** * Renders translucent things in this scene. * * They are rendered back to front. */ renderTranslucent(): void { const instances = this.instances; for (let i = instances.length - 1; i >= 0; i--) { instances[i].renderTranslucent(); } } /** * Render this scene. */ render(): void { this.startFrame(); this.renderOpaque(); this.renderTranslucent(); } /** * Clear all of the emitted objects in this scene. */ clearEmittedObjects(): void { for (const object of this.emittedObjectUpdater.objects) { object.health = 0; } } } ================================================ FILE: src/viewer/skeletalnode.ts ================================================ import { vec3, quat, mat4 } from 'gl-matrix'; import { VEC3_UNIT_X, VEC3_UNIT_Y, VEC3_UNIT_Z } from '../common/gl-matrix-addon'; import Scene from './scene'; import { Node } from './node'; import ModelInstance from './modelinstance'; const locationHeap = vec3.create(); const rotationHeap = quat.create(); const scalingHeap = vec3.create(); const cameraRayHeap = vec3.create(); const rotationHeap2 = quat.create(); /** * A skeletal node used for skeletons. * * Expected to be created with createSkeletalNodes() below. */ export class SkeletalNode { pivot: vec3; localLocation: vec3; localRotation: quat; localScale: vec3; worldLocation: vec3; worldRotation: quat; worldScale: vec3; inverseWorldLocation: vec3; inverseWorldRotation: quat; inverseWorldScale: vec3; localMatrix: mat4; worldMatrix: mat4; dontInheritTranslation = false; dontInheritRotation = false; dontInheritScaling = false; billboarded = false; billboardedX = false; billboardedY = false; billboardedZ = false; dirty = true; wasDirty = false; parent: SkeletalNode | Node | null = null; children: Node[] = []; /** * The object associated with this node, if there is any. */ object: unknown = null; constructor(pivot: vec3, localLocation: vec3, localRotation: quat, localScale: vec3, worldLocation: vec3, worldRotation: quat, worldScale: vec3, inverseWorldLocation: vec3, inverseWorldRotation: quat, inverseWorldScale: vec3, localMatrix: mat4, worldMatrix: mat4) { this.pivot = pivot; this.localLocation = localLocation; this.localRotation = localRotation; this.localScale = localScale; this.worldLocation = worldLocation; this.worldRotation = worldRotation; this.worldScale = worldScale; this.inverseWorldLocation = inverseWorldLocation; this.inverseWorldRotation = inverseWorldRotation; this.inverseWorldScale = inverseWorldScale; this.localMatrix = localMatrix; this.worldMatrix = worldMatrix; this.localRotation[3] = 1; this.localScale.fill(1); this.localMatrix[0] = 1; this.localMatrix[5] = 1; this.localMatrix[10] = 1; this.localMatrix[15] = 1; } /** * Recalculate this skeletal node. */ recalculateTransformation(instance: ModelInstance): void { const scene = instance.scene; const localMatrix = this.localMatrix; const localLocation = this.localLocation; const localRotation = this.localRotation; const localScale = this.localScale; const worldMatrix = this.worldMatrix; const worldLocation = this.worldLocation; const worldRotation = this.worldRotation; const worldScale = this.worldScale; const pivot = this.pivot; const inverseWorldLocation = this.inverseWorldLocation; const inverseWorldRotation = this.inverseWorldRotation; const inverseWorldScale = this.inverseWorldScale; const parent = this.parent; let computedLocation; let computedRotation; let computedScaling; if (this.dontInheritTranslation) { vec3.add(locationHeap, parent.inverseWorldLocation, worldLocation); computedLocation = vec3.add(locationHeap, locationHeap, localLocation); } else { computedLocation = localLocation; } if (this.dontInheritScaling) { vec3.mul(locationHeap, parent.inverseWorldScale, instance.worldScale); computedScaling = vec3.mul(locationHeap, locationHeap, localScale); } else { computedScaling = localScale; } if (this.billboarded) { computedRotation = rotationHeap; quat.copy(computedRotation, parent.inverseWorldRotation); quat.mul(computedRotation, computedRotation, scene.camera.inverseRotation); this.convertBasis(computedRotation); quat.mul(computedRotation, computedRotation, localRotation); } else { const { billboardedX, billboardedY, billboardedZ } = this; if (billboardedX || billboardedY || billboardedZ) { if (billboardedX) { if (computedScaling === localScale) { computedScaling = scalingHeap; vec3.copy(computedScaling, localScale); } // (Original comment from Retera's Warsmash) // It took me many hours to deduce from playing around that this negative one // multiplier should be here. I suggest a lot of testing before you remove it. computedScaling[2] *= -1; } // Inverse that local rotation rotationHeap2[0] = -localRotation[0]; rotationHeap2[1] = -localRotation[1]; rotationHeap2[2] = -localRotation[2]; quat.mul(rotationHeap2, rotationHeap2, parent.inverseWorldRotation); vec3.transformQuat(cameraRayHeap, scene.camera.billboardedVectors[6], rotationHeap2); if (billboardedX) { quat.setAxisAngle(rotationHeap2, VEC3_UNIT_X, Math.atan2(cameraRayHeap[2], cameraRayHeap[1])); } else if (billboardedY) { quat.setAxisAngle(rotationHeap2, VEC3_UNIT_Y, Math.atan2(-cameraRayHeap[2], cameraRayHeap[0])); } else { quat.setAxisAngle(rotationHeap2, VEC3_UNIT_Z, Math.atan2(cameraRayHeap[1], cameraRayHeap[0])); } computedRotation = rotationHeap; quat.mul(computedRotation, localRotation, rotationHeap2); } else { computedRotation = localRotation; } } if (this.dontInheritRotation) { quat.mul(rotationHeap2, parent.inverseWorldRotation, instance.worldRotation); computedRotation = quat.mul(rotationHeap, rotationHeap2, computedRotation); } // Local matrix mat4.fromRotationTranslationScaleOrigin(localMatrix, computedRotation, computedLocation, computedScaling, pivot); // World matrix mat4.mul(worldMatrix, parent.worldMatrix, localMatrix); // World location // vec3.transformMat4(worldLocation, pivot, worldMatrix); const x = pivot[0]; const y = pivot[1]; const z = pivot[2]; worldLocation[0] = worldMatrix[0] * x + worldMatrix[4] * y + worldMatrix[8] * z + worldMatrix[12]; worldLocation[1] = worldMatrix[1] * x + worldMatrix[5] * y + worldMatrix[9] * z + worldMatrix[13]; worldLocation[2] = worldMatrix[2] * x + worldMatrix[6] * y + worldMatrix[10] * z + worldMatrix[14]; // Inverse world location inverseWorldLocation[0] = -worldLocation[0]; inverseWorldLocation[1] = -worldLocation[1]; inverseWorldLocation[2] = -worldLocation[2]; // World rotation quat.mul(worldRotation, parent.worldRotation, computedRotation); // Inverse world rotation inverseWorldRotation[0] = -worldRotation[0]; inverseWorldRotation[1] = -worldRotation[1]; inverseWorldRotation[2] = -worldRotation[2]; inverseWorldRotation[3] = worldRotation[3]; // World scale const parentScale = parent.worldScale; worldScale[0] = parentScale[0] * computedScaling[0]; worldScale[1] = parentScale[1] * computedScaling[1]; worldScale[2] = parentScale[2] * computedScaling[2]; // Inverse world scale inverseWorldScale[0] = 1 / worldScale[0]; inverseWorldScale[1] = 1 / worldScale[1]; inverseWorldScale[2] = 1 / worldScale[2]; } /** * Allows inherited node classes to run extra transformations when billboarding. * * This is needed because the different model formats are in different vector spaces. */ convertBasis(_rotation: quat): void { } } interface SkeletalNodesData { data: Float32Array; nodes: SkeletalNode[]; pivots: Float32Array; localLocations: Float32Array; localRotations: Float32Array; localScales: Float32Array; worldLocations: Float32Array; worldRotations: Float32Array; worldScales: Float32Array; inverseWorldLocations: Float32Array; invereseWorldRotations: Float32Array; inverseWorldScales: Float32Array; localMatrices: Float32Array; worldMatrices: Float32Array; } const NODE_SHARED_SIZE = 65; /** * Creates an array of skeletal nodes with shared memory. * * The returned object contains the node array itself, the backing buffer, and all of the different shared arrays. */ export function createSkeletalNodes(count: number, Node = SkeletalNode): SkeletalNodesData { const data = new Float32Array(count * NODE_SHARED_SIZE); const nodes = []; let offset = 0; const count3 = count * 3; const count4 = count * 4; const count16 = count * 16; const pivots = data.subarray(offset, offset + count3); offset += count3; const localLocations = data.subarray(offset, offset + count3); offset += count3; const localRotations = data.subarray(offset, offset + count4); offset += count4; const localScales = data.subarray(offset, offset + count3); offset += count3; const worldLocations = data.subarray(offset, offset + count3); offset += count3; const worldRotations = data.subarray(offset, offset + count4); offset += count4; const worldScales = data.subarray(offset, offset + count3); offset += count3; const inverseWorldLocations = data.subarray(offset, offset + count3); offset += count3; const invereseWorldRotations = data.subarray(offset, offset + count4); offset += count4; const inverseWorldScales = data.subarray(offset, offset + count3); offset += count3; const localMatrices = data.subarray(offset, offset + count16); offset += count16; const worldMatrices = data.subarray(offset, offset + count16); for (let i = 0; i < count; i++) { const i3 = i * 3; const i33 = i3 + 3; const i4 = i * 4; const i44 = i4 + 4; const i16 = i * 16; const i1616 = i16 + 16; nodes[i] = new Node( pivots.subarray(i3, i33), localLocations.subarray(i3, i33), localRotations.subarray(i4, i44), localScales.subarray(i3, i33), worldLocations.subarray(i3, i33), worldRotations.subarray(i4, i44), worldScales.subarray(i3, i33), inverseWorldLocations.subarray(i3, i33), invereseWorldRotations.subarray(i4, i44), inverseWorldScales.subarray(i3, i33), localMatrices.subarray(i16, i1616), worldMatrices.subarray(i16, i1616), ); } return { data, nodes, pivots, localLocations, localRotations, localScales, worldLocations, worldRotations, worldScales, inverseWorldLocations, invereseWorldRotations, inverseWorldScales, localMatrices, worldMatrices, }; } ================================================ FILE: src/viewer/texture.ts ================================================ import { HandlerResource } from './handlerresource'; /** * A texture. */ export default abstract class Texture extends HandlerResource { webglResource: WebGLTexture | null = null; width = 0; height = 0; } ================================================ FILE: src/viewer/viewer.ts ================================================ import { EventEmitter } from 'events'; import { FetchDataTypeName, FetchDataType, FetchResult, fetchDataType } from '../common/fetchdatatype'; import WebGL from './gl/gl'; import Scene from './scene'; import { Resource } from './resource'; import { PathSolver, HandlerResourceData, HandlerResource, SolverParams } from './handlerresource'; import GenericResource from './genericresource'; import ClientBuffer from './gl/clientbuffer'; import { isImageSource, ImageTexture, detectMime } from './imagetexture'; import { blobToImage } from '../common/canvas'; export enum DebugRenderMode { None, Diffuse, NormalMap, Occlusion, Roughness, Metallic, TCFactor, Emissive, TexCoords, Normals, Tangents, } /** * A viewer handler. */ export interface Handler { load?: (viewer: ModelViewer, ...args: any[]) => void; isValidSource: (src: unknown) => boolean; resource: new (src: any, resourceData: HandlerResourceData) => HandlerResource } /** * A model viewer. */ export default class ModelViewer extends EventEmitter { /** * The viewer's canvas. */ canvas: HTMLCanvasElement; /** * The viewer's WebGL context. */ gl: WebGLRenderingContext; /** * A wrapper around the viewer's WebGL context with utility functions. */ webgl: WebGL; /** * All of the loaded resources. */ resources: Resource[] = []; /** * A map from urls to their resources. * * Only used by fetched resources. */ resourceMap: Map = new Map(); /** * A map from urls to the promises that load them. * * Only used by fetched resources. */ promiseMap: Map> = new Map(); /** * The viewer's handlers, added with `addHandler()`. */ handlers: Set = new Set(); /** * The viewer's scenes, added with `addScene()`. */ scenes: Scene[] = []; /** * The current frame. */ frame = 0; /** * The number of visible cells on the current frame. */ visibleCells = 0; /** * The number of visible instances on the current frame. */ visibleInstances = 0; /** * The number of particles being updated on the current frame. */ updatedParticles = 0; /** * A viewer-wide flag. * * If it is false, not only will audio not run, but in fact audio files won't even be fetched in the first place. * * If audio is desired, this should be set to true before loading models that use audio. * * Note that it is preferable to call enableAudio(), which checks for the existence of AudioContext. */ audioEnabled = false; /** * A resizeable buffer that can be used by any part of the library. * * The data it contains is temporary, and can be overwritten at any time. */ buffer: ClientBuffer; /** * A cache of arbitrary data, shared between all of the handlers. */ sharedCache: Map = new Map(); /** * Debug rendering mode. * * How it affects the rendering ultimately depends on the handlers. */ debugRenderMode = DebugRenderMode.None; directLoadId = 0; constructor(canvas: HTMLCanvasElement, options?: WebGLContextAttributes) { super(); const webgl = new WebGL(canvas, options); const gl = webgl.gl; this.canvas = canvas; this.gl = gl; this.webgl = webgl; this.buffer = webgl.createClientBuffer(); // The only initial setup, the rest should be handled by the handlers. gl.depthFunc(gl.LEQUAL); gl.enable(gl.DEPTH_TEST); gl.enable(gl.SCISSOR_TEST); } /** * Enable audio if AudioContext is available. */ enableAudio(): boolean { if (typeof AudioContext === 'function') { this.audioEnabled = true; return true; } return false; } /** * Add an handler. */ addHandler(handler: Handler, ...args: unknown[]): boolean { if (handler) { const handlers = this.handlers; // Check to see if this handler was added already. if (!handlers.has(handler)) { if (!handler.isValidSource) { this.emit('error', { viewer: this, error: 'Handler missing the isValidSource function', handler }); return false; } // Check if the handler has a loader, and if so load it. if (handler.load) { try { handler.load(this, ...args); } catch (e) { this.emit('error', { viewer: this, error: `Handler failed to load`, handler, reason: e }); return false; } } handlers.add(handler); return true; } } return false; } /** * Add a scene. */ addScene(): Scene { const scene = new Scene(this); this.scenes.push(scene); return scene; } /** * Remove a scene. */ removeScene(scene: Scene): boolean { const scenes = this.scenes; const index = scenes.indexOf(scene); if (index !== -1) { scenes.splice(index, 1); return true; } return false; } /** * Removes all of the scenes in the viewer. */ clear(): void { this.scenes.length = 0; } /** * Given a source and an optional path solver, loads a resource and returns a promise to it. */ async load(src: unknown, pathSolver?: PathSolver, solverParams?: SolverParams): Promise { let finalSrc: unknown; let fetchUrl = ''; let promise; // Run the path solver if there is one. if (pathSolver) { try { finalSrc = pathSolver(src, solverParams); } catch (e) { this.emit('error', { viewer: this, error: `Path solver failed`, src, reason: e, pathSolver, solverParams }); return; } } else { finalSrc = src; } if (!finalSrc) { return; } // Allow path solvers to return promises. if (finalSrc instanceof Promise) { finalSrc = await finalSrc; } // Give path solvers the option to inject resources. if (finalSrc instanceof Resource) { return finalSrc; } // If the final source is a string, and doesn't match any handler, it is assumed to be an URL to fetch. if (typeof finalSrc === 'string' && !this.detectFormat(finalSrc)) { fetchUrl = finalSrc; // Check the promise cache and return a promise if one exists. promise = this.promiseMap.get(fetchUrl); if (promise) { return promise; } // Check the fetch cache and return a resource if one exists. const resource = this.resourceMap.get(fetchUrl); if (resource) { return resource; } // Otherwise promise to fetch the data and construct a resource. promise = fetchDataType(fetchUrl, 'arrayBuffer') .then((value) => { if (value.ok) { return value.data; } else { this.emit('error', { viewer: this, error: `Failed to fetch a resource: ${value.error}`, fetchUrl, reason: value.data }); return; } }); } else { fetchUrl = `__DIRECT_LOAD_${this.directLoadId++}`; promise = Promise.resolve(finalSrc); } promise = promise .then(async (actualSrc) => { // finalSrc will be undefined if this is a fetch and the fetch failed. if (actualSrc) { if (actualSrc instanceof ArrayBuffer) { actualSrc = new Uint8Array(actualSrc); } // If the source is an image source, load it directly. if (isImageSource(actualSrc)) { return new ImageTexture(actualSrc, { viewer: this, fetchUrl, pathSolver }); } // If the source is a buffer of an image, convert it to an image, and load it directly. if (actualSrc instanceof Uint8Array) { const type = detectMime(actualSrc); if (type.length) { return new ImageTexture(await blobToImage(new Blob([actualSrc.buffer], { type })), { viewer: this, fetchUrl, pathSolver }); } } // Attempt to match the source to a handler. const handler = this.detectFormat(actualSrc); if (handler) { try { const resource = new handler.resource(actualSrc, { viewer: this, fetchUrl, pathSolver }); // If the resource is blocked by internal resources being loaded, wait for them and then clear them. await Promise.all(resource.blockers); resource.blockers.length = 0; return resource; } catch (e) { this.emit('error', { viewer: this, error: 'Failed to create a resource', fetchUrl, src, reason: e }); } } else { this.emit('error', { viewer: this, error: 'Source has no matching handler', fetchUrl, src }); } } return; }) .then((resource) => { this.promiseMap.delete(fetchUrl); if (resource) { this.resourceMap.set(fetchUrl, resource); this.resources.push(resource); this.emit('load', { viewer: this, fetchUrl, resource }); } this.emit('loadend', { viewer: this, fetchUrl, resource }); this.checkLoadingStatus(); return resource; }); this.promiseMap.set(fetchUrl, promise); this.emit('loadstart', { viewer: this, fetchUrl, promise }); return promise; } detectFormat(src: unknown): Handler | undefined { for (const handler of this.handlers) { if (handler.isValidSource(src)) { return handler; } } return; } /** * Check whether the given string maps to a resource in the cache. */ has(key: string): boolean { return this.resourceMap.has(key); } /** * Get a resource from the cache. */ get(key: string): Resource | undefined { return this.resourceMap.get(key); } /** * Load something generic. * * Unlike load(), this does not use handlers or construct any internal objects. * * `dataType` can be one of: `"image"`, `"string"`, `"arrayBuffer"`, `"bytes"`, `"blob"`. * * If `callback` isn't given, the resource's `data` is the fetch data, according to `dataType`. * * If `callback` is given, the resource's `data` is the value returned by it when called with the fetch data. * * If `callback` returns a promise, the resource's `data` will be whatever the promise resolved to. */ async loadGeneric(fetchUrl: string, dataType: FetchDataTypeName, callback?: (data: FetchDataType) => unknown): Promise { // Check the promise cache and return a promise if one exists. const promise = this.promiseMap.get(fetchUrl); if (promise) { return >promise; } // Check the fetch cache and return a resource if one exists. const resource = this.resourceMap.get(fetchUrl); if (resource) { return resource; } const fetchPromise = fetchDataType(fetchUrl, dataType) .then(async (value: FetchResult) => { // Once the resource finished loading (successfully or not), the promise can be removed from the promise cache. this.promiseMap.delete(fetchUrl); let resource; if (value.ok) { let data: unknown = value.data; if (callback) { data = await callback(data); } resource = new GenericResource(data, { viewer: this, fetchUrl }); this.resourceMap.set(fetchUrl, resource); this.resources.push(resource); this.emit('load', { viewer: this, fetchUrl, resource }); } else { this.emit('error', { viewer: this, error: 'Failed to fetch a generic resource', fetchUrl }); } this.emit('loadend', { viewer: this, fetchUrl, resource }); this.checkLoadingStatus(); return resource; }); this.promiseMap.set(fetchUrl, fetchPromise); this.emit('loadstart', { viewer: this, fetchUrl }); return fetchPromise; } /** * Unload a resource. * Note that this only removes the resource from the viewer's cache. * If it's being referenced and used e.g. by a scene, it will not be garbage collected. */ unload(resource: Resource): boolean { const fetchUrl = resource.fetchUrl; if (fetchUrl !== '') { this.resourceMap.delete(fetchUrl); } const resources = this.resources; const index = resources.indexOf(resource); if (index !== -1) { resources.splice(index, 1); return true; } return false; } /** * Starts loading a new empty resource, and returns it. * This empty resource will block the "idle" event (and thus whenAllLoaded) until it's resolved. * This is used when a resource might get loaded in the future, but it is not known what it is yet. */ promise(): () => void { const promise = Promise.resolve(undefined); const key = `${performance.now()}`; this.promiseMap.set(key, promise); return (): void => { this.promiseMap.delete(key); this.checkLoadingStatus(); }; } checkLoadingStatus(): void { if (this.promiseMap.size === 0) { // A timeout is used so that this event will arrive after the current frame to let everything settle. setTimeout(() => this.emit('idle'), 0); } } /** * Wait for all of the resources to load. * * If a callback is given, it will be called, otherwise, a promise is returned. */ whenAllLoaded(): Promise; whenAllLoaded(callback: (viewer: ModelViewer) => void): void; whenAllLoaded(callback?: (viewer: ModelViewer) => void): Promise | void { const promise = new Promise((resolve: (viewer: ModelViewer) => void) => { if (this.promiseMap.size === 0) { resolve(this); } else { this.once('idle', () => resolve(this)); } }); if (callback) { promise.then(() => callback(this)); } else { return promise; } } /** * Get a blob representing the contents of the viewer's canvas. * * If a callback is given, it will be called, otherwise, a promise is returned. */ toBlob(): Promise; toBlob(callback: BlobCallback): void; toBlob(callback?: BlobCallback): Promise | void { const promise = new Promise((resolve: BlobCallback) => this.canvas.toBlob((blob) => resolve(blob))); if (callback) { promise.then((blob) => callback(blob)); } else { return promise; } } /** * Update and render a frame. */ updateAndRender(dt = 1000 / 60): void { this.update(dt); this.startFrame(); this.render(); } /** * Update all of the scenes, which includes updating their cameras, audio context if one exists, and all of the instances they hold. */ update(dt = 1000 / 60): void { // Animations are in milliseconds, while particle movement and such is in seconds. // It's easier to pass the time in seconds here, and turn it back to milliseconds for each instance, than it is to do the opposite for each particle. dt *= 0.001; this.frame += 1; this.visibleCells = 0; this.visibleInstances = 0; this.updatedParticles = 0; for (const scene of this.scenes) { scene.update(dt); this.visibleCells += scene.visibleCells; this.visibleInstances += scene.visibleInstances; this.updatedParticles += scene.updatedParticles; } } /** * Clears the WebGL buffer. * * Called automatically by updateAndRender(). * * Call this at some point before render() if you need more control. */ startFrame(): void { const gl = this.gl; // See https://www.opengl.org/wiki/FAQ#Masking gl.depthMask(true); gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } /** * Render. */ render(): void { for (const scene of this.scenes) { scene.render(); } } /** * Clear all of the emitted objects in this viewer. */ clearEmittedObjects(): void { for (const scene of this.scenes) { scene.clearEmittedObjects(); } } } ================================================ FILE: tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "target": "es2017", "lib": ["es2020", "dom"], "outDir": "./dist/cjs", "moduleResolution": "node", "typeRoots": ["./types", "./node_modules/@types"], "types": ["node"], "sourceMap": true, "declaration": true, "strict": true, "allowJs": true, "forceConsistentCasingInFileNames": true, "noImplicitOverride": true, "noImplicitAny": true, "noImplicitThis": true, "noImplicitReturns": true, "noPropertyAccessFromIndexSignature": true, "suppressImplicitAnyIndexErrors": true }, "exclude": ["clients", "clean.js", "webpack.config.js", "dist"] } ================================================ FILE: types/fengari.d.ts ================================================ declare module 'fengari/src/lstate' { export class lua_State {} // module.exports.CallInfo = CallInfo; // module.exports.CIST_OAH = (1<<0); /* original value of 'allowhook' */ // module.exports.CIST_LUA = (1<<1); /* call is running a Lua function */ // module.exports.CIST_HOOKED = (1<<2); /* call is running a debug hook */ // module.exports.CIST_FRESH = (1<<3); /* call is running on a fresh invocation of luaV_execute */ // module.exports.CIST_YPCALL = (1<<4); /* call is a yieldable protected call */ // module.exports.CIST_TAIL = (1<<5); /* call was tail called */ // module.exports.CIST_HOOKYIELD = (1<<6); /* last hook called yielded */ // module.exports.CIST_LEQ = (1<<7); /* using __lt for __le */ // module.exports.CIST_FIN = (1<<8); /* call is running a finalizer */ // module.exports.EXTRA_STACK = EXTRA_STACK; // module.exports.lua_close = lua_close; // module.exports.lua_newstate = lua_newstate; const lua_newthread: (L: lua_State) => lua_State; // module.exports.luaE_extendCI = luaE_extendCI; // module.exports.luaE_freeCI = luaE_freeCI; // module.exports.luaE_freethread = luaE_freethread; } declare module 'fengari/src/lauxlib' { import { lua_State } from 'fengari/src/lstate'; // module.exports.LUA_ERRFILE = LUA_ERRFILE; // module.exports.LUA_FILEHANDLE = LUA_FILEHANDLE; // module.exports.LUA_LOADED_TABLE = LUA_LOADED_TABLE; // module.exports.LUA_NOREF = LUA_NOREF; // module.exports.LUA_PRELOAD_TABLE = LUA_PRELOAD_TABLE; // module.exports.LUA_REFNIL = LUA_REFNIL; // module.exports.luaL_Buffer = luaL_Buffer; // module.exports.luaL_addchar = luaL_addchar; // module.exports.luaL_addlstring = luaL_addlstring; // module.exports.luaL_addsize = luaL_addsize; // module.exports.luaL_addstring = luaL_addstring; // module.exports.luaL_addvalue = luaL_addvalue; // module.exports.luaL_argcheck = luaL_argcheck; // module.exports.luaL_argerror = luaL_argerror; // module.exports.luaL_buffinit = luaL_buffinit; // module.exports.luaL_buffinitsize = luaL_buffinitsize; // module.exports.luaL_callmeta = luaL_callmeta; // module.exports.luaL_checkany = luaL_checkany; const luaL_checkinteger: (L: lua_State, arg: number) => number; const luaL_checklstring: (L: lua_State, arg: number) => string; const luaL_checknumber: (L: lua_State, arg: number) => number; // module.exports.luaL_checkoption = luaL_checkoption; // module.exports.luaL_checkstack = luaL_checkstack; const luaL_checkstring: (L: lua_State, arg: number) => string; // module.exports.luaL_checktype = luaL_checktype; // module.exports.luaL_checkudata = luaL_checkudata; // module.exports.luaL_checkversion = luaL_checkversion; // module.exports.luaL_checkversion_ = luaL_checkversion_; // module.exports.luaL_dofile = luaL_dofile; // module.exports.luaL_dostring = luaL_dostring; // module.exports.luaL_error = luaL_error; // module.exports.luaL_execresult = luaL_execresult; // module.exports.luaL_fileresult = luaL_fileresult; // module.exports.luaL_getmetafield = luaL_getmetafield; // module.exports.luaL_getmetatable = luaL_getmetatable; // module.exports.luaL_getsubtable = luaL_getsubtable; // module.exports.luaL_gsub = luaL_gsub; // module.exports.luaL_len = luaL_len; // module.exports.luaL_loadbuffer = luaL_loadbuffer; // module.exports.luaL_loadbufferx = luaL_loadbufferx; // module.exports.luaL_loadfile = luaL_loadfile; // module.exports.luaL_loadfilex = luaL_loadfilex; const luaL_loadstring: (L: lua_State, s: Uint8Array) => string; // module.exports.luaL_newlib = luaL_newlib; // module.exports.luaL_newlibtable = luaL_newlibtable; // module.exports.luaL_newmetatable = luaL_newmetatable; const luaL_newstate: () => lua_State; // module.exports.luaL_opt = luaL_opt; // module.exports.luaL_optinteger = luaL_optinteger; // module.exports.luaL_optlstring = luaL_optlstring; // module.exports.luaL_optnumber = luaL_optnumber; // module.exports.luaL_optstring = luaL_optstring; // module.exports.luaL_prepbuffer = luaL_prepbuffer; // module.exports.luaL_prepbuffsize = luaL_prepbuffsize; // module.exports.luaL_pushresult = luaL_pushresult; // module.exports.luaL_pushresultsize = luaL_pushresultsize; const luaL_ref: (L: lua_State, t: number) => number; // module.exports.luaL_requiref = luaL_requiref; // module.exports.luaL_setfuncs = luaL_setfuncs; // module.exports.luaL_setmetatable = luaL_setmetatable; // module.exports.luaL_testudata = luaL_testudata; const luaL_tolstring: (L: lua_State, idx: number) => Uint8Array; // module.exports.luaL_traceback = luaL_traceback; // module.exports.luaL_typename = luaL_typename; const luaL_unref: (L: lua_State, t: number, ref: number) => void; // module.exports.luaL_where = luaL_where; // module.exports.lua_writestringerror = lua_writestringerror; } declare module 'fengari/src/lapi' { import { lua_State } from 'fengari/src/lstate'; // module.exports.api_incr_top = api_incr_top; // module.exports.api_checknelems = api_checknelems; // module.exports.lua_absindex = lua_absindex; // module.exports.lua_arith = lua_arith; // module.exports.lua_atpanic = lua_atpanic; const lua_atnativeerror: (L: lua_State, errorf: (L: lua_State) => number) => void; // module.exports.lua_call = lua_call; // module.exports.lua_callk = lua_callk; // module.exports.lua_checkstack = lua_checkstack; // module.exports.lua_compare = lua_compare; // module.exports.lua_concat = lua_concat; // module.exports.lua_copy = lua_copy; // module.exports.lua_createtable = lua_createtable; // module.exports.lua_dump = lua_dump; // module.exports.lua_error = lua_error; // module.exports.lua_gc = lua_gc; // module.exports.lua_getallocf = lua_getallocf; // module.exports.lua_getextraspace = lua_getextraspace; // module.exports.lua_getfield = lua_getfield; const lua_getglobal: (L: lua_State, name: string) => unknown; // module.exports.lua_geti = lua_geti; // module.exports.lua_getmetatable = lua_getmetatable; // module.exports.lua_gettable = lua_gettable; // module.exports.lua_gettop = lua_gettop; // module.exports.lua_getupvalue = lua_getupvalue; // module.exports.lua_getuservalue = lua_getuservalue; // module.exports.lua_insert = lua_insert; // module.exports.lua_isboolean = lua_isboolean; // module.exports.lua_iscfunction = lua_iscfunction; // module.exports.lua_isfunction = lua_isfunction; // module.exports.lua_isinteger = lua_isinteger; // module.exports.lua_islightuserdata = lua_islightuserdata; // module.exports.lua_isnil = lua_isnil; // module.exports.lua_isnone = lua_isnone; // module.exports.lua_isnoneornil = lua_isnoneornil; // module.exports.lua_isnumber = lua_isnumber; // module.exports.lua_isproxy = lua_isproxy; // module.exports.lua_isstring = lua_isstring; // module.exports.lua_istable = lua_istable; // module.exports.lua_isthread = lua_isthread; // module.exports.lua_isuserdata = lua_isuserdata; // module.exports.lua_len = lua_len; // module.exports.lua_load = lua_load; // module.exports.lua_newtable = lua_newtable; // module.exports.lua_newuserdata = lua_newuserdata; // module.exports.lua_next = lua_next; const lua_pcall: (L: lua_State, n: number, r: number, f: number) => number; // module.exports.lua_pcallk = lua_pcallk; const lua_pop: (L: lua_State, n: number) => void; const lua_pushboolean: (L: lua_State, b: boolean) => void; // module.exports.lua_pushcclosure = lua_pushcclosure; // module.exports.lua_pushcfunction = lua_pushcfunction; // module.exports.lua_pushfstring = lua_pushfstring; // module.exports.lua_pushglobaltable = lua_pushglobaltable; const lua_pushinteger: (L: lua_State, n: number) => void; // module.exports.lua_pushjsclosure = lua_pushjsclosure; // module.exports.lua_pushjsfunction = lua_pushjsfunction; const lua_pushlightuserdata: (L: lua_State, p: unknown) => void; // module.exports.lua_pushliteral = lua_pushliteral; // module.exports.lua_pushlstring = lua_pushlstring; const lua_pushnil: (L: lua_State) => void; const lua_pushnumber: (L: lua_State, n: number) => void; const lua_pushstring: (L: lua_State, s: string) => string; // module.exports.lua_pushthread = lua_pushthread; // module.exports.lua_pushvalue = lua_pushvalue; // module.exports.lua_pushvfstring = lua_pushvfstring; // module.exports.lua_rawequal = lua_rawequal; // module.exports.lua_rawget = lua_rawget; const lua_rawgeti: (L: lua_State, idx: number, n: number) => unknown; // module.exports.lua_rawgetp = lua_rawgetp; // module.exports.lua_rawlen = lua_rawlen; // module.exports.lua_rawset = lua_rawset; // module.exports.lua_rawseti = lua_rawseti; // module.exports.lua_rawsetp = lua_rawsetp; const lua_register: (L: lua_State, n: string, f: (L: lua_State) => number) => void; // module.exports.lua_remove = lua_remove; // module.exports.lua_replace = lua_replace; // module.exports.lua_rotate = lua_rotate; // module.exports.lua_setallocf = lua_setallocf; // module.exports.lua_setfield = lua_setfield; // module.exports.lua_setglobal = lua_setglobal; // module.exports.lua_seti = lua_seti; // module.exports.lua_setmetatable = lua_setmetatable; // module.exports.lua_settable = lua_settable; // module.exports.lua_settop = lua_settop; // module.exports.lua_setupvalue = lua_setupvalue; // module.exports.lua_setuservalue = lua_setuservalue; // module.exports.lua_status = lua_status; // module.exports.lua_stringtonumber = lua_stringtonumber; const lua_toboolean: (L: lua_State, idx: number) => boolean; // module.exports.lua_tocfunction = lua_tocfunction; // module.exports.lua_todataview = lua_todataview; // module.exports.lua_tointeger = lua_tointeger; // module.exports.lua_tointegerx = lua_tointegerx; // module.exports.lua_tojsstring = lua_tojsstring; // module.exports.lua_tolstring = lua_tolstring; // module.exports.lua_tonumber = lua_tonumber; // module.exports.lua_tonumberx = lua_tonumberx; // module.exports.lua_topointer = lua_topointer; // module.exports.lua_toproxy = lua_toproxy; // module.exports.lua_tostring = lua_tostring; // module.exports.lua_tothread = lua_tothread; const lua_touserdata: (L: lua_State, idx: number) => unknown; // module.exports.lua_type = lua_type; // module.exports.lua_typename = lua_typename; // module.exports.lua_upvalueid = lua_upvalueid; // module.exports.lua_upvaluejoin = lua_upvaluejoin; // module.exports.lua_version = lua_version; // module.exports.lua_xmove = lua_xmove; } declare module 'fengari/src/ldo' { import { lua_State } from 'fengari/src/lstate'; // module.exports.adjust_top = adjust_top; // module.exports.luaD_call = luaD_call; // module.exports.luaD_callnoyield = luaD_callnoyield; // module.exports.luaD_checkstack = luaD_checkstack; // module.exports.luaD_growstack = luaD_growstack; // module.exports.luaD_hook = luaD_hook; // module.exports.luaD_inctop = luaD_inctop; // module.exports.luaD_pcall = luaD_pcall; // module.exports.luaD_poscall = luaD_poscall; // module.exports.luaD_precall = luaD_precall; // module.exports.luaD_protectedparser = luaD_protectedparser; // module.exports.luaD_rawrunprotected = luaD_rawrunprotected; // module.exports.luaD_reallocstack = luaD_reallocstack; // module.exports.luaD_throw = luaD_throw; // module.exports.lua_isyieldable = lua_isyieldable; const lua_resume: (L: lua_State, from: lua_State, nargs: number) => number; const lua_yield: (L: lua_State, n: number) => void; // module.exports.lua_yieldk = lua_yieldk; } declare module 'fengari/src/defs' { // module.exports.luastring_from = luastring_from; // module.exports.luastring_indexOf = luastring_indexOf; // module.exports.luastring_of = luastring_of; // module.exports.is_luastring = is_luastring; // module.exports.luastring_eq = luastring_eq; const to_jsstring: (value: Uint8Array, from?: number, to?: number, replacement_char?: boolean) => string; // module.exports.to_uristring = to_uristring; const to_luastring: (str: string, cache?: boolean) => Uint8Array; // module.exports.from_userstring = from_userstring; // module.exports.LUA_SIGNATURE = LUA_SIGNATURE; // module.exports.LUA_VERSION_MAJOR = LUA_VERSION_MAJOR; // module.exports.LUA_VERSION_MINOR = LUA_VERSION_MINOR; // module.exports.LUA_VERSION_NUM = LUA_VERSION_NUM; // module.exports.LUA_VERSION_RELEASE = LUA_VERSION_RELEASE; // module.exports.LUA_VERSION = LUA_VERSION; // module.exports.LUA_RELEASE = LUA_RELEASE; // module.exports.LUA_COPYRIGHT = LUA_COPYRIGHT; // module.exports.LUA_AUTHORS = LUA_AUTHORS; // module.exports.LUA_HOOKCALL = LUA_HOOKCALL; // module.exports.LUA_HOOKCOUNT = LUA_HOOKCOUNT; // module.exports.LUA_HOOKLINE = LUA_HOOKLINE; // module.exports.LUA_HOOKRET = LUA_HOOKRET; // module.exports.LUA_HOOKTAILCALL = LUA_HOOKTAILCALL; // module.exports.LUA_MASKCALL = LUA_MASKCALL; // module.exports.LUA_MASKCOUNT = LUA_MASKCOUNT; // module.exports.LUA_MASKLINE = LUA_MASKLINE; // module.exports.LUA_MASKRET = LUA_MASKRET; // module.exports.LUA_MINSTACK = LUA_MINSTACK; // module.exports.LUA_MULTRET = -1; // module.exports.LUA_OPADD = LUA_OPADD; // module.exports.LUA_OPBAND = LUA_OPBAND; // module.exports.LUA_OPBNOT = LUA_OPBNOT; // module.exports.LUA_OPBOR = LUA_OPBOR; // module.exports.LUA_OPBXOR = LUA_OPBXOR; // module.exports.LUA_OPDIV = LUA_OPDIV; // module.exports.LUA_OPEQ = LUA_OPEQ; // module.exports.LUA_OPIDIV = LUA_OPIDIV; // module.exports.LUA_OPLE = LUA_OPLE; // module.exports.LUA_OPLT = LUA_OPLT; // module.exports.LUA_OPMOD = LUA_OPMOD; // module.exports.LUA_OPMUL = LUA_OPMUL; // module.exports.LUA_OPPOW = LUA_OPPOW; // module.exports.LUA_OPSHL = LUA_OPSHL; // module.exports.LUA_OPSHR = LUA_OPSHR; // module.exports.LUA_OPSUB = LUA_OPSUB; // module.exports.LUA_OPUNM = LUA_OPUNM; const LUA_REGISTRYINDEX: number; // module.exports.LUA_RIDX_GLOBALS = LUA_RIDX_GLOBALS; // module.exports.LUA_RIDX_LAST = LUA_RIDX_LAST; // module.exports.LUA_RIDX_MAINTHREAD = LUA_RIDX_MAINTHREAD; // module.exports.constant_types = constant_types; // module.exports.lua_Debug = lua_Debug; // module.exports.lua_upvalueindex = lua_upvalueindex; const thread_status: { LUA_OK: 0, LUA_YIELD: 1, LUA_ERRRUN: 2, LUA_ERRSYNTAX: 3, LUA_ERRMEM: 4, LUA_ERRGCMM: 5, LUA_ERRERR: 6 }; } ================================================ FILE: types/tga-js.d.ts ================================================ declare module 'tga-js' { export default class TgaLoader { header: { idLength: number; colorMapType: number; imageType: number; colorMapIndex: number; colorMapLength: number; colorMapDepth: number; offsetX: number; offsetY: number; width: number; height: number; pixelDepth: number; flags: number; }; open(path: string, callback: () => void): void; load(data: Uint8Array): void; getImageData(imageData: ImageData): ImageData; getCanvas(): HTMLCanvasElement; getDataUrl(type: string): string; } } ================================================ FILE: webpack.config.js ================================================ const fs = require('fs'); const webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); module.exports = (env, argv) => { let entry; if (env.umd) { // The repo as a library. entry = { 'viewer': { import: './src/index.ts', filename: 'umd/viewer.min.js', library: { name: 'ModelViewer', type: 'var' } }, }; } else { // Built-in clients. entry = { 'example': { import: './clients/example/index.js', filename: 'clients/example.min.js' }, 'downgrader': { import: './clients/downgrader/index.js', filename: 'clients/downgrader.min.js' }, 'map': { import: './clients/map/index.js', filename: 'clients/map.min.js' }, 'mdlx': { import: './clients/mdlx/index.js', filename: 'clients/mdlx.min.js' }, 'rebuild': { import: './clients/rebuild/index.js', filename: 'clients/rebuild.min.js' }, 'sanitytest': { import: './clients/sanitytest/index.js', filename: 'clients/sanitytest.min.js' }, 'tests': { import: './clients/tests/index.js', filename: 'clients/tests.min.js' }, 'weu': { import: './clients/weu/index.js', filename: 'clients/weu.min.js' }, 'mdlxoptimizer': { import: './clients/mdlxoptimizer/index.ts', filename: 'clients/mdlxoptimizer.min.js' }, }; } return { entry, plugins: [ new webpack.BannerPlugin(fs.readFileSync('LICENSE', 'utf8')), // Note: this is needed to compile fengari for the web. new webpack.DefinePlugin({ 'process.env.FENGARICONF': 'void 0', 'typeof process': JSON.stringify('undefined'), }), ], performance: { hints: false, }, module: { rules: [ { test: /\.ts$/, exclude: /node_modules/, loader: 'ts-loader', options: { compilerOptions: { module: 'esnext', declaration: false } } }, ], }, resolve: { extensions: ['.js', '.ts'], }, devtool: argv.mode === 'development' ? 'eval-cheap-module-source-map' : 'source-map', optimization: { minimizer: [new TerserPlugin({ extractComments: false, })], }, }; };