Beispiel #1
0
	function copyBuildInfo()
	{
		if(process.argv[3]==="dev")
			return this();

		base.info("Copying latest .build.info file...");
		fileUtil.copy(path.join(HOTS_PATH, ".build.info"), path.join(HOTS_DATA_PATH, ".build.info"), this);
	},
Beispiel #2
0
	function clearOut()
	{
		if(process.argv[3]==="dev")
			return this();

		base.info("Clearing 'out' directory...");
		rimraf(OUT_PATH, this);
	},
Beispiel #3
0
	function extractFiles()
	{
		if(process.argv[3]==="dev")
			return this();

		base.info("Extracting %d needed files...", NEEDED_FILE_PATHS.length);
		NEEDED_FILE_PATHS.parallelForEach(function(NEEDED_FILE_PATH, subcb)
		{
			runUtil.run(CASCEXTRATOR_PATH, [HOTS_DATA_PATH, "-o", OUT_PATH, "-f", NEEDED_FILE_PATH], {silent:true}, subcb);
		}, this, 10);
	},
Beispiel #4
0
	function finish(err)
	{
		if(err)
		{
			base.error(err);
			process.exit(1);
		}

		base.info("Done.");

		process.exit(0);
	}
Beispiel #5
0
		xmlDoc.find("/Catalog/*").forEach(function(node)
		{
			var nodeType = NODE_MAP_TYPES.filter(function(NODE_MAP_TYPE) { return node.name()===("C" + NODE_MAP_TYPE); }).concat(NODE_MAP_PREFIX_TYPES.filter(function(NODE_MAP_PREFIX_TYPE) { return node.name().startsWith(NODE_MAP_PREFIX_TYPES); })).unique();
			if(!nodeType || nodeType.length!==1)
				return;

			nodeType = nodeType[0];

			if(node.attr("id") || attributeValue(node, "default")!=="1")
				return;

			if(DEFAULT_NODES.hasOwnProperty(nodeType))
			{
				base.info(DEFAULT_NODES[nodeType].toString());
				base.info(node.toString());
				base.error("MORE THAN ONE DEFAULT! NOT GOOD!");
				process.exit(1);
			}

			DEFAULT_NODES[nodeType] = node;
		});
Beispiel #6
0
function validateHero(hero)
{
	var validator = jsen(C.HERO_JSON_SCHEMA);
	if(!validator(hero))
	{
		base.warn("Hero %s (%s) has FAILED VALIDATION", hero.id, hero.name);
		base.info(validator.errors);
	}

	Object.forEach(hero.abilities, function(unitName, abilities)
	{
		if(abilities.length!==abilities.map(function(ability) { return ability.name; }).unique().length)
			base.warn("Hero %s has multiple abilities with the same name!", hero.name);
	});
}
Beispiel #7
0
	function loadDataAndSaveJSON()
	{
		var xmlDocs = [];

		base.info("Loading data...");
		NEEDED_FILE_PATHS.forEach(function(NEEDED_FILE_PATH)
		{
			var diskPath = path.join(OUT_PATH, NEEDED_FILE_PATH.replaceAll("\\\\", "/"));
			if(!fs.existsSync(diskPath))
			{
				//base.info("Missing file: %s", NEEDED_FILE_PATH);
				return;
			}
			var fileData = fs.readFileSync(diskPath, {encoding:"utf8"});
			if(diskPath.endsWith("GameStrings.txt"))
			{
				fileData.split("\n").forEach(function(line) {
					S[line.substring(0, line.indexOf("="))] = line.substring(line.indexOf("=")+1).trim();
				});
			}
			else if(diskPath.endsWith(".xml"))
			{
				xmlDocs.push(libxmljs.parseXml(fileData));
			}
		});

		loadMergedNodeMap(xmlDocs);

		mergeNodeParents();

		base.info("\nProcessing heroes...");
		var heroes = Object.values(NODE_MAPS["Hero"]).map(function(heroNode) { return processHeroNode(heroNode); }).filterEmpty();
		heroes.sort(function(a, b) { return (a.name.startsWith("The ") ? a.name.substring(4) : a.name).localeCompare((b.name.startsWith("The ") ? b.name.substring(4) : b.name)); });

		base.info("\nValidating %d heroes...", heroes.length);
		heroes.forEach(validateHero);

		base.info("\nProcessing mounts...");
		var mounts = Object.values(NODE_MAPS["Mount"]).map(function(mountNode) { return processMountNode(mountNode); }).filterEmpty();

		base.info("\nValidating %d mounts...", mounts.length);
		mounts.forEach(validateMount);
		mounts.sort(function(a, b) { return (a.name.startsWith("The ") ? a.name.substring(4) : a.name).localeCompare((b.name.startsWith("The ") ? b.name.substring(4) : b.name)); });

		base.info("\nSaving JSON...");

		fs.writeFile(HEROES_OUT_PATH, JSON.stringify(heroes), {encoding:"utf8"}, this.parallel());
		fs.writeFile(MOUNTS_OUT_PATH, JSON.stringify(mounts), {encoding:"utf8"}, this.parallel());
	},
Beispiel #8
0
function validateMount(mount, index, mounts)
{
	var validator = jsen(C.MOUNT_JSON_SCHEMA);
	if(!validator(mount))
	{
		// For every fail (usually a variation), copy it from the parent)
		validator.errors.forEach(function(elem) {
			var parent = findParentMount(mounts, "productid", mount.productid);
			for (var item in parent) {
				if (mount[item] === undefined) {
					mount[item] = parent[item];
				}
			};
		});
    // WARNING: I may have a race condition here...
		// Revalidate
		if (!validator(mount)) {
			base.warn("Mount %s (%s) has FAILED VALIDATION", mount.id, mount.name);
			base.info(validator.errors);
		}
	}
}
Beispiel #9
0
		alternateUnitArrayNodes.forEach(function(alternateUnitArrayNode)
		{
			var alternateHeroid = attributeValue(alternateUnitArrayNode, "value");
      base.info("Alternate: ", alternateHeroid);
			heroUnitids.push(alternateHeroid);
		});
Beispiel #10
0
function processHeroNode(heroNode)
{
	var hero = {};

	// Core hero data
	hero.id = attributeValue(heroNode, "id");

	if(C.SKIP_HERO_IDS.contains(hero.id))
		return;
	
	hero.attributeid = getValue(heroNode, "AttributeId");
	hero.name = S["Unit/Name/" + getValue(heroNode, "Unit", "Hero" + hero.id)] || S[getValue(heroNode, "Name")];
	
	if(!hero.name)
	{
		base.info(heroNode.toString());
		throw new Error("Failed to get name for hero: " + hero.id);
	}

	base.info("Processing hero: %s (%s)", hero.name, hero.id);
	hero.title =  S["Hero/Title/" + hero.id];
	hero.description = S["Hero/Description/" + hero.id];

	hero.icon = "ui_targetportrait_hero_" + (C.HERO_ID_TEXTURE_RENAMES.hasOwnProperty(hero.id) ? C.HERO_ID_TEXTURE_RENAMES[hero.id] : hero.id) + ".dds";

	hero.role = getValue(heroNode, "Role");
	if(hero.role==="Damage")
		hero.role = "Assassin";
	if(!hero.role)
		hero.role = "Warrior";

	hero.type = !!getValue(heroNode, "Melee") ? "Melee" : "Ranged";
	hero.gender = getValue(heroNode, "Gender", "Male");
	hero.franchise = getValue(heroNode, "Universe", "Starcraft");
	hero.difficulty = getValue(heroNode, "Difficulty", "Easy");
	if(hero.difficulty==="VeryHard")
		hero.difficulty = "Very Hard";

	var ratingsNode = heroNode.get("Ratings");
	if(ratingsNode)
	{
		hero.ratings =
		{
			damage        : +getValue(ratingsNode, "Damage", attributeValue(ratingsNode, "Damage", 1)),
			utility       : +getValue(ratingsNode, "Utility", attributeValue(ratingsNode, "Utility", 1)),
			survivability : +getValue(ratingsNode, "Survivability", attributeValue(ratingsNode, "Survivability", 1)),
			complexity    : +getValue(ratingsNode, "Complexity", attributeValue(ratingsNode, "Complexity", 1)),
		};
	}

	hero.releaseDate = processReleaseDate(heroNode.get("ReleaseDate"));

	var heroUnitids = [ hero.id ];
	var alternateUnitArrayNodes = heroNode.find("AlternateUnitArray");
	if(alternateUnitArrayNodes && alternateUnitArrayNodes.length>0)
	{
		alternateUnitArrayNodes.forEach(function(alternateUnitArrayNode)
		{
			var alternateHeroid = attributeValue(alternateUnitArrayNode, "value");
      base.info("Alternate: ", alternateHeroid);
			heroUnitids.push(alternateHeroid);
		});
	}

	heroUnitids = heroUnitids.concat(C.ADDITIONAL_HERO_SUBUNIT_IDS[hero.id] || []);
  base.info("Sub-units:", hero.id, heroUnitids);

	// Level Scaling Info
	HERO_LEVEL_SCALING_MODS[hero.id] = [];
	addHeroLevelScalingMods(hero.id, DEFAULT_NODES["Hero"]);
	addHeroLevelScalingMods(hero.id, heroNode);

	// Hero Stats
	hero.stats = {};
	heroUnitids.forEach(function(heroUnitid)
	{
		hero.stats[heroUnitid] = getHeroStats(heroUnitid);
		if(Object.keys(hero.stats[heroUnitid]).length===0)
			delete hero.stats[heroUnitid];
	});

	// Abilities
	hero.abilities = getHeroAbilities(hero.id, hero.name, heroUnitids);

	// Talents
	hero.talents = {};
	C.HERO_TALENT_LEVELS.forEach(function(HERO_TALENT_LEVEL) { hero.talents[HERO_TALENT_LEVEL] = []; });
	var talentTreeNodes = heroNode.find("TalentTreeArray").filter(function(talentTreeNode) { return !!!attributeValue(talentTreeNode, "removed"); });
	talentTreeNodes.sort(function(a, b) { return (+((+attributeValue(a, "Tier"))*10)+(+attributeValue(a, "Column")))-(+((+attributeValue(b, "Tier"))*10)+(+attributeValue(b, "Column"))); });

	talentTreeNodes.forEach(function(talentTreeNode)
	{
		var talent = {};

		talent.id = attributeValue(talentTreeNode, "Talent");

		var talentNode = NODE_MAPS["Talent"][talent.id];
		var faceid = getValue(talentNode, "Face");

		var talentDescription = S["Button/Tooltip/" + faceid];

		if(!talentDescription && faceid==="TyrandeHuntersMarkTrueshotAuraTalent")
			talentDescription = S["Button/Tooltip/TyrandeTrueshotBowTalent"];

		if(!talentDescription)
		{
			base.warn("Missing talent description for hero [%s] and talentid [%s] and faceid [%s]", hero.id, talent.id, faceid);
			return;
		}

		if(talentDescription.contains("StandardTooltipHeader"))
			talent.name = talentDescription.replace(/<s val="StandardTooltipHeader">([^<]+)<.+/, "$1").replace(/<s\s*val\s*=\s*"StandardTooltip">/gm, "").trim();
		else
			talent.name = S[getValue(NODE_MAPS["Button"][faceid], "Name")];

		if(!talent.name)
			talent.name = S["Button/Name/" + faceid];

		//if(hero.id==="L90ETC") { base.info("Talent: %s\n", talent.id); }
		talent.description = getFullDescription(talent.id, talentDescription, hero.id, 0);
		talent.icon = getValue(NODE_MAPS["Button"][faceid], "Icon");
		if(!talent.icon)
			talent.icon = getValue(NODE_MAPS["Button"][attributeValue(NODE_MAPS["Button"][faceid], "parent")], "Icon");

		if(!talent.icon)
			delete talent.icon;
		else
			talent.icon = talent.icon.replace(/Assets\\Textures\\/, "");

		addCooldownInfo(talent, "description");

		if(!talent.cooldown)
			talent.cooldown = getAbilityCooldown(NODE_MAPS["Abil"][getValue(talentNode, "Abil")]);

		var talentPrerequisiteNode = talentTreeNode.get("PrerequisiteTalentArray");
		if(talentPrerequisiteNode)
			talent.prerequisite = attributeValue(talentPrerequisiteNode, "value");

		hero.talents[C.HERO_TALENT_LEVELS[((+attributeValue(talentTreeNode, "Tier"))-1)]].push(talent);
	});
	
	// Final modifications
    performHeroModifications(hero);

	return hero;
}