Modding Resources: Installing Mods | Creating Mods | Basic Code Examples | Creating a Character | Audio and Visual Effects | The Automator | User Interface | Graph Editor

Creating a Character

Characters are made up of several different components that can work together. Some of the things a character can have are a Level Graph (aka Skill Tree), Skills, Traits, Stats, and Buffs, and we will be looking at some of the ways these can be implemented and manipulated here.

See ExampleCharacterMain.as in the Clicker Heroes 2\mods\examples folder for a mod made using the code described here.

Basic Character Creation and Info

Note: At the moment the character name must be exactly the same as the mod name defined in the MOD_INFO object.

Adding new art assets is currently not supported, however for the time being you can use Cid's artwork to create a new character by setting your character's assetGroupName to "HelpfulAdventurer" in the onStartup function.

Creating a character requires creating a new Character object, filling out the basic information for this new Character, and then adding it to Characters' startingDefaultInstances.

To do this, you will need to import models.Characters in your mod. Then create a new Character in a public variable in your main class, outside of the other functions, so that any function can access the new character you're creating:

	
	public var newCharacter:Character = new Character();
	

Here is a template for setting up a new character that uses Cid's ("HelpfulAdventurer"'s) art assets, it should go in the onStartup function:

	
	newCharacter.assetGroupName = "HelpfulAdventurer";
	newCharacter.name = "Example Character";
	newCharacter.flavorName = "Newbie";
	newCharacter.flavorClass = "New Character";
	newCharacter.flavor = "A character who is new.";
	newCharacter.availableForCreation = true;
	newCharacter.visibleOnCharacterSelect = true;
	newCharacter.startingSkills = [ ];
	newCharacter.upgradeableStats = Character.DEFAULT_UPGRADEABLE_STATS;
	
	Characters.startingDefaultInstances[newCharacter.name] = newCharacter;
	

You will also want to add a mod dependency so that saves created with your new character will indicate that this mod is required to be installed. See the Mod Dependencies section for more information.

Creating a Level Graph (aka Skill Tree)

To create a level graph you will need to define the node types that will be in the graph, then set the location of the nodes and the edges that will connect them in the levelGraphObject, and finally have your character load the levelGraphObject you created.

First you will need to import heroclickerlib.LevelGraph. Here is the basic outline for creating a level graph for the character newCharacter that was defined in the previous example, this is all done from within the onStartup function:

	
	newCharacter.levelGraphNodeTypes = { }

	newCharacter.levelGraphObject = { }

	newCharacter.levelGraph = LevelGraph.loadGraph(newCharacter.levelGraphObject, newCharacter);

	
Level Graph Nodes

A character has a levelGraphNodeTypes object that contains information about all of the nodes that are available to purchase in that character's skill tree. Template for creating new nodes:

	
	newCharacter.levelGraphNodeTypes = { 
		"N1": { 
			"name": "Example Node",
			"tooltip": "" ,
			"flavorText": null,
			"alwaysAvailable": true,
			"setupFunction": function() {},
			"purchaseFunction": function() {},
			"icon": ""
		    },
		"N2": {
			"name": "Another Node",
			"tooltip": "",
			"flavorText": null,
			"alwaysAvailable": false,
			"setupFunction": function() {},        
			"purchaseFunction": function() {},
			"icon": ""
		    }
	}
	

N1 and N2 are IDs that you can use to reference the individual nodes. What you put in the purchaseFunction field is what happens when a player purchases that node in the skill tree. Some examples are to give the player a new skill, a trait, or to increase their stats, all of which will be detailed below.

The setupFunction is for code that needs to run when the character is created, before the node in purchased. For an example of how the setup function can be used, see The Automator section.

Level Graph Object

The level graph object defines the location where each node will be in the graph, and which nodes are connected to each other. Each edge (connecting line) connects two nodes, and each node has an x-coordinate and a y-coordinate for where it is located within the Skill Tree panel. Here is an example level graph object that places and connects the nodes N1 and N2 from the previous example:

	
	newCharacter.levelGraphObject = {"edges":[{"1":[1,2]}], "nodes":[{"1":{"val":"N1", "x": 0, "y": 0}},{"2":{"val":"N2","x":75,"y":0}}]};
	

The above line of code has one edge,1, that connects nodes 1 and 2. The first node, 1, is set to have the value of N1 at the coordinates (0,0) and the second node, 2, has the value N2 at the coordinates (75, 0).

You can use the same nodes multiple times within the level graph, for example, you can have two or more nodes with the "val" of N2, so characters can get the same effect multiple times. This can be useful to use with the addTrait function, which is explained in the Creating and Using Traits section.

To help with the visual layout of your graph you can create or edit level graph objects using the Graph Editor tool. See the Graph Editor section for how to use this.

Editing Pre-Existing Level Graphs

WARNING: Uninstalling a mod that adds level graph nodes after the node has been purchased will break saves. Be sure to use Mod Dependencies to let players know that saves that have used this kind of mod will require it to be installed in order to load properly.

The levelGraphObject is used to add data like that created by the Graph Editor tool into the game. The game uses the information in this object to make a LevelGraph. This is mostly useful for creating an entirely new level graph for a new character. However, if you want to edit an already existing level graph, like Cid's, a more useful approach is to edit the already existing levelGraph for that character instead of their levelGraphObject. This allows you to add new nodes without overwriting the entire pre-existing level graph, making it more likely to work together with other mods that also add new nodes, and less likely to break with game updates.

For this mod you will need to import models.Character, models.Characters, heroclickerlib.LevelGraphNode, and heroclickerlib.LevelGraph.

To add a new node to a character's level graph in this way you will first need to add information about the node type to the character's levelGraphNodeTypes. Above we created a couple of node types, "N1" and "N2" in a new levelGraphNodeTypes object. Cid already has her own levelGraphNodeTypes object, though, so if we want to add one of these nodes types to Cid, we want to add to that existing one instead of creating our own. The following will create and add the N1 node type to Cid's levelGraphNodeTypes and fill in all of the same information for it as above:

	
	public function onStartup(game:IdleHeroMain):void
	{
		var character:Character = Characters.startingDefaultInstances["Helpful Adventurer"];
		
		character.levelGraphNodeTypes["N1"] = new Object();
		character.levelGraphNodeTypes["N1"]["name"] = "Example Node";
		character.levelGraphNodeTypes["N1"]["tooltip"] = "";
		character.levelGraphNodeTypes["N1"]["flavorText"] = null;
		character.levelGraphNodeTypes["N1"]["alwaysAvailable"] = false;
		character.levelGraphNodeTypes["N1"]["setupFunction"] = function() { };
		character.levelGraphNodeTypes["N1"]["purchaseFunction"] = function() { };
		character.levelGraphNodeTypes["N1"]["icon"] = "";
	}
	

Next, we need to create a new LevelGraphNode and add it to the nodes array in the character's levelGraph. The following would create a new LevelGraphNode that references the N1 node type we just defined above, and should also be within the onStartup function:

	
	var exampleNode:LevelGraphNode = new LevelGraphNode();
	exampleNode.x = 0 * LevelGraph.SCALE;
	exampleNode.y = 0 * LevelGraph.SCALE;
	exampleNode.type = "N1";
	exampleNode.special = false;
	exampleNode.deluxe = false;
	exampleNode.alwaysAvailable = false;
	

The x and y values are the location in the graph you want your node to appear, and each need to be multiplied by the LevelGraph.SCALE constant so it scales to the correct size. This example will put the node at (0,0), which is the exact center of the graph. The type is the string that the game will look for in the character's levelGraphNodeTypes object, "N1" in this case. The special and deluxe fields are booleans for whether or not the node is one of the shiny yellow or blue nodes. alwaysAvailable is a boolean for whether or not the node can be purchased without having purchased any of the other nodes it's connected to on the graph.

One last thing we need before we add this node to the nodes array is a unique id that will be used by nodes to reference each other in the graph.

We can use the length of Cid's nodes array to create an id that's guaranteed to be unique, regardless of other mods installed, or future updates to the game that may add more nodes.

	
	exampleNode.id = characterInstance.levelGraph.nodes.length;
	characterInstance.levelGraph.nodes[exampleNode.id] = exampleNode;
	

All that's left to do now is create the edges and connections that connect our node to some nodes that already exist in the graph. Since we're sticking our node right near the start, let's connect it to Cid's "Skill: Big Clicks" node. We'll need to know what the level graph node id is, which means we'll have to find it by searching the source code, which is in the helpfulAdventurerMain.as file provided in the mods\active folder. If we first search for the name "Skill: Big Clicks" in levelGraphNodeTypes, we can see that it's type "T1". We can then search for "T1" to find the node with the matching value in the levelGraphObject, and there we can see the node id. In this case, it's simply 1, and we can use that to reference the node we want from the nodes the character has in their level graph:

	
	var nodeToConnect:LevelGraphNode = character.levelGraph.nodes[1];
	

And now we can add the connections:

	
	exampleNode.connections.push(nodeToConnect.id);
	nodeToConnect.connections.push(exampleNode.id);
	

The first push function above adds the id of the "Skill: Big Clicks" node to our node's array of connections. The second line adds our node's id to the "Skill: Big Clicks" node's array of connections. Now each node knows about the other and this allows the game to correctly unlock nodes after those connected to them are purchased. Next is to add an array with the information needed to create the edge between the two nodes. This will be used to create the graphical line that let's players see which two nodes are connected:

	
	character.levelGraph.edges.push([exampleNode.x, exampleNode.y, nodeToConnect.x, nodeToConnect.y, exampleNode.id, nodeToConnect.id]);
	

First in this array are the x and y coordinates of our node, then the x and y coordinates of the node we want it to connect to, followed by the id of our node, and finally the id of the node we are connecting to. We can repeat adding connections and edges with other nodes if we want to connect to more than one.

All together, our code to add a new node to Cid would look something like this:

	
	public function onStartup(game:IdleHeroMain):void
	{
		var character:Character = Characters.startingDefaultInstances["Helpful Adventurer"];
			
		// Creates and adds level graph node type N1 to Cid's levelGraphNodeTypes object
		character.levelGraphNodeTypes["N1"] = new Object();
		character.levelGraphNodeTypes["N1"]["name"] = "Example Node";
		character.levelGraphNodeTypes["N1"]["tooltip"] = "";
		character.levelGraphNodeTypes["N1"]["flavorText"] = null;
		character.levelGraphNodeTypes["N1"]["alwaysAvailable"] = false;
		character.levelGraphNodeTypes["N1"]["setupFunction"] = function() { };
		character.levelGraphNodeTypes["N1"]["purchaseFunction"] = function() { CH2.currentCharacter.levelUpStat(CH2.STAT_MOVEMENT_SPEED, 500); };
		character.levelGraphNodeTypes["N1"]["icon"] = "";
			
		// Creates a new node that references level graph node type N1 at location (0,0)
		var exampleNode:LevelGraphNode = new LevelGraphNode();
		exampleNode.x = 0 * LevelGraph.SCALE;
		exampleNode.y = 0 * LevelGraph.SCALE;
		exampleNode.type = "N1";
		exampleNode.special = false;
		exampleNode.deluxe = false;
		exampleNode.alwaysAvailable = false;
			
		// Sets node id and adds the node with that id to Cid's array of nodes if it doesn't already exist
		exampleNode.id = character.levelGraph.nodes.length;
		character.levelGraph.nodes[exampleNode.id] = exampleNode;					
			
		// Adds connections for each node to each other and an edge between them
		var nodeToConnect:LevelGraphNode = character.levelGraph.nodes[1];
		exampleNode.connections.push(nodeToConnect.id);
		nodeToConnect.connections.push(exampleNode.id);
		character.levelGraph.edges.push([exampleNode.x, exampleNode.y, nodeToConnect.x, nodeToConnect.y, exampleNode.id, nodeToConnect.id]);
	}

	public function onCharacterCreated(characterInstance:Character):void
	{
		if (characterInstance.name == "Helpful Adventurer")
		{
			// Adds mod dependency to Helpful Adventurer (required to prevent game crash if mod is removed)
			characterInstance.modDependencies[MOD_INFO["name"]] = true;
		}
	}
	
See ExampleNewNode.as in the Clicker Heroes 2\mods\examples folder for a completed mod made using the code described here.

Adding Skills

First you will need to have a skill created. You can use any skill that already exists and has been added to to Character.staticSkillInstances, or you can create a new skill, as outlined here: Creating a Skill

Once you have a skill you want to use, there are a couple of ways to add it to a character. One way is through the skill tree, by adding it through the purchaseFunction field of a node:

	
	"purchaseFunction": function() {
		var skill:Skill = CH2.currentCharacter.getStaticSkill("Example Skill");
		CH2.currentCharacter.activateSkill(skill.uid);

		CH2.currentCharacter.hasPurchasedFirstSkill = true;
	}
	

The above code will give the skill "Example Skill", which was created in the Creating a Skill section, to a character when they purchase this node from the skill tree. If this skill can be one of the first skills your character can purchase from the level graph, you will want to set hasPurchasedFirstSkill to true, otherwise you can leave this part out.

Another way to add the skill to your character is to list it in your character's startingSkills array:

	
	newCharacter.startingSkills = ["Example Skill"];
	

With the above code, your character will start out with this skill available, without the need to have a node in the skill tree for it.

Note: If you are using a pre-existing skill that has a sound effect you will need to load that sound for your character as explained in Adding Sounds.

Creating and Using Traits

Traits are simple attributes that a character can have that can be used in multiple ways. A trait only has two parts, a name and a numerical value. You create a trait as you add it to a character by using one of the following functions:

	
	CH2.currentCharacter.addTrait("ExampleTrait", 1);

	CH2.currentCharacter.setTrait("ExampleTrait",1);
	

addTrait will add the value you input (in this case 1) to the current value of the trait (which will be 0 if this is the first time the character is being assigned this trait), and setTrait will overwrite whatever the current trait value is and set it to the value you input.

You can access a trait your character might have, either to see if they have it, or to use the numerical value assigned to it with the getTrait function:

	
	CH2.currentCharacter.getTrait("ExampleTrait");
	

Example use:

In levelGraphNodeTypes we can use the addTrait function in the Node's purchaseFunction field to add a trait when a that node is purchased:

	
	"purchaseFunction": function() { CH2.currentCharacter.addTrait("ExampleTrait", 1); }
	

Now that the character has the trait, one way we can use it is to affect skills. For example, we can edit the exampleEffect we created in the Creating a Skill section to do more damage if the character has this particular trait:

	
	public function exampleEffect():void 
	{
    	var monster:Monster =  CH2.world.getNextMonster();        
            
    	if (monster) 
	{                
    		var attackData:AttackData = new AttackData();         
                
                
    		var damage:Number;
    		if (CH2.currentCharacter.getTrait("ExampleTrait")) 
		{
			damage = 100 * (1 + CH2.currentCharacter.getTrait("ExampleTrait"));
		}
		else 
		{
        		damage = 100;
    		}
                
    		var damageNumber:BigNumber = new BigNumber(damage);
                
    		attackData.damage = damageNumber;
    		CH2.currentCharacter.attack(attackData);
		}
	}
	

This example uses the getTrait function twice, once to see if the current character has had the trait added with the statement if (CH2.currentCharacter.getTrait("ExampleTrait")), and again with the expression 100 * (1 + CH2.currentCharacter.getTrait), which uses the value we assigned to the trait, in this case 1, and thus setting the damage variable to 200 (or 100 * (1 + 1)). If we wanted, we could create more nodes in the level graph that use the same trait name, and have them add to the number, so you can do things like have the skill do more and more damage as a player gets more nodes in the skill tree.

For example, if we create another node with the purchaseFunction value of CH2.currentCharacter.addTrait("ExampleTrait", 2), the value of 2 would be added to the previous ExampleTrait value of 1, assuming that node was previously purchased, so that the getTrait function will return a value of 3. It would be the same if the value 2 trait node were purchased first, so then purchasing the value 1 node after it would add to the value, again coming to a total of 3. If we instead used the setTrait function here however, it would completely replace any previous data, and purchasing this node would then mean that the value of ExampleTrait would be set to 2, regardless of what other ExampleTrait nodes the player may have purchased previously. If you want to get rid of a trait entirely, you can use the setTrait function to set the value to 0.

Levelling Character Stats

One way you can increase a character's stats is by using the character's levelUpStat function:

	
	CH2.currentCharacter.levelUpStat(CH2.STAT_CRIT_CHANCE);
	

If you put the above line of code in a node's purchaseFunction, it will level up the Crit Chance stat for the current character when they purchase that node. By default it will increase the stat's level by 1, but if you want to level it up more you can specify a value, for example, the following will level up Crit Chance 2 times:

	
	CH2.currentCharacter.levelUpStat(CH2.STAT_CRIT_CHANCE, 2);
	

What happens when you level up a stat is determined by a character's statValueFunctions and the specific stat's calculationType (whether it's an additive or multiplicative stat). A character has a default function for each stat which has a default value that will be used to determine how much to increase that stat's value by when it is levelled up. You can replace the default statValueFunctions and their values for a character in the onStartup function:

	
	newCharacter.statValueFunctions[CH2.STAT_CRIT_CHANCE] = Character.linear(0.05);
	

The above will make it so that 5% crit chance is added to our example character every time their crit chance stat is levelled up. The linear function is used to get the value of 0.05 times the level of the stat, and because Crit Chance is an additive stat, that total will be added to the base value of the stat (the starting value for the character). For other stats we might want to use the exponentialMultiplier function:

	
	newCharacter.statValueFunctions[CH2.STAT_CRIT_DAMAGE] = Character.exponentialMultiplier(1.5);
	

The exponentialMultiplier function will be used to multiply 1.5 to itself once for each level of the stat. In other words, the current stat level will be the power that the value you give to this function is raised to. So at stat level 0, 1.5^0 = 1; at level 1, 1.5^1 = 1.5; at level 2, 1.5^2 = 2.25; and so on. Then, because crit damage is a multiplicative stat, that total will be multiplied to the character's base value of that stat.

The base value of a stat that our character starts out with can be modified in a similar way:

	
	newCharacter.statBaseValues[CH2.STAT_CRIT_CHANCE] = 0.1;
	

The above will set the base value of our example character's crit chance to 10%.

These are all of the current stats and their default Value Functions:

	
	statValueFunctions[CH2.STAT_GOLD] = exponentialMultiplier(1.1);
	statValueFunctions[CH2.STAT_MOVEMENT_SPEED] = exponentialMultiplier(1.05);
	statValueFunctions[CH2.STAT_CRIT_CHANCE] = linear(0.02);
	statValueFunctions[CH2.STAT_CRIT_DAMAGE] = exponentialMultiplier(1.20);
	statValueFunctions[CH2.STAT_HASTE] = exponentialMultiplier(1.05);
	statValueFunctions[CH2.STAT_MANA_REGEN] = exponentialMultiplier(1.1);
	statValueFunctions[CH2.STAT_IDLE_GOLD] = exponentialMultiplier(1.25);
	statValueFunctions[CH2.STAT_IDLE_DAMAGE] = exponentialMultiplier(1.25);
	statValueFunctions[CH2.STAT_CLICKABLE_GOLD] = exponentialMultiplier(1.5);
	statValueFunctions[CH2.STAT_CLICK_DAMAGE] = exponentialMultiplier(1.1);
	statValueFunctions[CH2.STAT_TREASURE_CHEST_CHANCE] = linear(0.02);
	statValueFunctions[CH2.STAT_MONSTER_GOLD] = exponentialMultiplier(1.12);
	statValueFunctions[CH2.STAT_ITEM_COST_REDUCTION] = exponentialMultiplier(0.92);
	statValueFunctions[CH2.STAT_TOTAL_MANA] = linear(25);
	statValueFunctions[CH2.STAT_TOTAL_ENERGY] = linear(25);
	statValueFunctions[CH2.STAT_CLICKABLE_CHANCE] = linear(0.1);
	statValueFunctions[CH2.STAT_BONUS_GOLD_CHANCE] = linear(0.01);
	statValueFunctions[CH2.STAT_TREASURE_CHEST_GOLD] = exponentialMultiplier(1.25);
	statValueFunctions[CH2.STAT_PIERCE_CHANCE] = linear(0.01);
	statValueFunctions[CH2.STAT_ENERGY_REGEN] = linear(0.00);
	statValueFunctions[CH2.STAT_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ENERGY_COST_REDUCTION] = linear(0);
	statValueFunctions[CH2.STAT_ITEM_WEAPON_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_HEAD_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_CHEST_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_RING_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_LEGS_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_HANDS_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_FEET_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_ITEM_BACK_DAMAGE] = exponentialMultiplier(1.50);
	statValueFunctions[CH2.STAT_AUTOMATOR_SPEED] = exponentialMultiplier(1.25);
	

These are all of the current stats and their default Base Values:

	
	statBaseValues[CH2.STAT_GOLD] = 1;
	statBaseValues[CH2.STAT_MOVEMENT_SPEED] = 1;
	statBaseValues[CH2.STAT_CRIT_CHANCE] = 0.05;
	statBaseValues[CH2.STAT_CRIT_DAMAGE] = 3;
	statBaseValues[CH2.STAT_HASTE] = 1;
	statBaseValues[CH2.STAT_MANA_REGEN] = 1;
	statBaseValues[CH2.STAT_IDLE_GOLD] = 1;
	statBaseValues[CH2.STAT_IDLE_DAMAGE] = 1;
	statBaseValues[CH2.STAT_CLICKABLE_GOLD] = 1;
	statBaseValues[CH2.STAT_CLICK_DAMAGE] = 1;
	statBaseValues[CH2.STAT_TREASURE_CHEST_CHANCE] = 0.02;
	statBaseValues[CH2.STAT_MONSTER_GOLD] = 1;
	statBaseValues[CH2.STAT_ITEM_COST_REDUCTION] = 1;
	statBaseValues[CH2.STAT_TOTAL_MANA] = 100;
	statBaseValues[CH2.STAT_TOTAL_ENERGY] = 100;
	statBaseValues[CH2.STAT_CLICKABLE_CHANCE] = 0.00;
	statBaseValues[CH2.STAT_BONUS_GOLD_CHANCE] = 0;
	statBaseValues[CH2.STAT_TREASURE_CHEST_GOLD] = 1;
	statBaseValues[CH2.STAT_PIERCE_CHANCE] = 0;
	statBaseValues[CH2.STAT_ENERGY_REGEN] = 0;
	statBaseValues[CH2.STAT_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ENERGY_COST_REDUCTION] = 0;
	statBaseValues[CH2.STAT_ITEM_WEAPON_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_HEAD_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_CHEST_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_RING_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_LEGS_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_HANDS_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_FEET_DAMAGE] = 1;
	statBaseValues[CH2.STAT_ITEM_BACK_DAMAGE] = 1;
	statBaseValues[CH2.STAT_AUTOMATOR_SPEED] = 1;
	

These are all of the current stats and their default calculation types:

	
	STAT_GOLD = MULTIPLICATIVE
	STAT_MOVEMENT_SPEED = MULTIPLICATIVE
	STAT_CRIT_CHANCE = ADDITIVE
	STAT_CRIT_DAMAGE = MULTIPLICATIVE
	STAT_HASTE = MULTIPLICATIVE
	STAT_MANA_REGEN = MULTIPLICATIVE
	STAT_IDLE_GOLD = MULTIPLICATIVE
	STAT_IDLE_DAMAGE = MULTIPLICATIVE
	STAT_CLICKABLE_GOLD = MULTIPLICATIVE
	STAT_CLICK_DAMAGE = MULTIPLICATIVE
	STAT_TREASURE_CHEST_CHANCE = ADDITIVE
	STAT_MONSTER_GOLD = MULTIPLICATIVE
	STAT_ITEM_COST_REDUCTION = MULTIPLICATIVE
	STAT_TOTAL_MANA = ADDITIVE
	STAT_TOTAL_ENERGY = ADDITIVE
	STAT_CLICKABLE_CHANCE = ADDITIVE
	STAT_BONUS_GOLD_CHANCE = ADDITIVE
	STAT_TREASURE_CHEST_GOLD = MULTIPLICATIVE
	STAT_PIERCE_CHANCE = ADDITIVE
	STAT_ENERGY_REGEN = ADDITIVE
	STAT_DAMAGE = MULTIPLICATIVE
	STAT_ENERGY_COST_REDUCTION = ADDITIVE
	STAT_ITEM_WEAPON_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_HEAD_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_CHEST_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_RING_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_LEGS_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_HANDS_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_FEET_DAMAGE = MULTIPLICATIVE
	STAT_ITEM_BACK_DAMAGE = MULTIPLICATIVE
	STAT_AUTOMATOR_SPEED = MULTIPLICATIVE
	

Creating and Using Buffs

Buffs are a versatile feature that can be used to affect many aspects of a character. One way to apply a buff to a character is through skills, by creating the buff within a function that a skill's effectFunction references (see the Creating a Skill section for information about the effectFunction). You will need to create a buff object, fill out information about the buff, including what you want the buff to do, and then add the buff to the list of Character's buffs.

First you will need to import models.buff. Here is a simple example of a function that creates a buff:

	
	public function buffExampleEffect():void 
	{
		var buff:Buff = new Buff();

		buff.name = "Example Buff";
		buff.iconId = 200;
		buff.duration = 5000;
		buff.tickRate = 1000;
		buff.tickFunction = function() {
			CH2.currentCharacter.addEnergy(5);
		}
		buff.tooltipFunction = function() {
			return {
				"header": "Example Buff",
				"body": "Restoring " + (5 * CH2.currentCharacter.hasteRating).toFixed(2) + " energy per second."
			};
		}

		CH2.currentCharacter.buffs.addBuff(buff);
	}

	

The tickFunction is what happens whenever a buff "ticks". The tickRate is how often it ticks, ie. how often the tickFunction is run while the buff is active. The above code will add 5 energy to the current character every 1000 milliseconds for the next 5000 milliseconds.

By default, a buff's tickRate is affected by how much haste a character has, which is why the tooltip description is coded to take hasteRating into account. The toFixed function simply limits how many decimal places of a number will be shown.

Other attributes you can use when creating a buff:

	
	buff.isFinished = true;

	buff.onFinish();
	

The above boolean and function can be used together to end a buff before the set duration runs out, for example, if some other condition is met.

	
	buff.isUntimedBuff

	buff.stacks

	buff.maximumStacks
	

If isUntimedBuff is set to true you can create a buff that does not have a set time duration. With stacks and maximumStacks you can create a buff that has a set number of charges.

	
	buff.timeLeft

	buff.timeSinceActivated:Number

	buff.buffStat(id, buffModifier)
	

The buffStat function works similarly to the levelUpStat function, but the effect only lasts while the buff is active. It requires one of the stat IDs listed in the Levelling Character Stats section, and a Number for the amount you want the buff to modify the stat.

	
	buff.attackFunction = function(attackDatas:Array) { }
	

The attackFunction allows a buff to run code when a character attacks, and can be used in place of, or in addition to, the tickFunction.

	
	buff.finishFunction = function() { }
	

In the finishFunction you can add code that runs when a buff ends.

You can check whether or not a character currently has a buff using the hasBuffByName function, which returns a boolean value (true or false):

	
	CH2.currentCharacter.buffs.hasBuffByName("Example Buff");
	

Overriding Character Functions

There is basic functionality for all characters that is pre-set in the game that determines what happens when a character does basic things like attack, use a skill, or kill a monster. This means if you like how these things work by default you don't have to touch them and they will just work, however if you want your character to work differently you can override many of these functions. This is also useful if you generally want things to work like default, but want to add traits to your character that change how things work in certain circumstances.

In order to override one of these functions you first need to have your mod tell the game that it's going to be handling that function in the onCharacterCreated function. You do this by setting the specific Handler variable for the function you're overriding (See a list of all Handler variables here). Here is an example that tells the game our Example Character mod will be handling the attack function:

	
	public function onCharacterCreated(characterInstance:Character):void 
	{
		if (characterInstance.name == "Example Character")
		{
		    characterInstance.attackHandler = this;
		}  
	}
	

After you've told the game your mod will be handling it, you will need to create an override function for what the game should do instead. The function you create must have a specific name and requires a certain parameter list and return type. You can see a list of all of those here. To continue our example, here is what it would look like to override the attack function:

	
	public function attackOverride(attackData:AttackData):void 
	{                
		var character:Character = CH2.currentCharacter;
		if (character.getTrait("Example Trait"))
		{
			attackData.damage.timesEqualsN(2);
		}
		    
		character.attackDefault(attackData);
	}
	

In this example, whenever the character attacks it first checks to see if they have the "Example Trait" that was created in the Creating and Using Traits section. If they do, their damage gets doubled before being sent to the default attack function, so that other than the increased damage everything proceeds exactly the same as the default. If they do not have the trait, nothing gets changed and the character continues to attack as normal. This is how it's possible to take advantage of the default code without having to completely rewrite it, while still making certain changes specific to a certain character.

List of Overridable Character Functions

Creating and Using World Traits

Characters have the option of having character-specific world traits that are applied to every world in a gild. In order to implement these traits, you need to determine how many traits each world will have in a gild, and then list the traits your character will have.

Setting Number of Traits

Characters have a getWorldTraitCount function that can be overridden. See the Overriding Character Functions section for a detailed explanation of how to override these kinds of functions. By default, characters do not have any world traits. The following example would simply set each world to have 2 traits, which will be picked at random from the available traits for your character:

	
	public function getWorldTraitCountOverride(worldNumber:int):int
	{
		return 2;
	}
	
Adding World Traits

The world traits that are available for your character will be objects that need to be stored in their worldTraits array with the name and description of what each trait will do. The constants should be outside of any functions in your class, and the objects should be defined in the onStartup Function:

	
	public static const WT_1:int = 0;
	public static const WT_2:int = 1;
	
	
	newCharacter.worldTraits[WT_1] = {
		"name": "Trait 1",
		"description": "Trait 1 description."
	};
	newCharacter.worldTraits[WT_2] = {
		"name": "Trait 2",
		"description": "Trait 2 description."
	};
	

The above will add an object with name and description of Trait 1 as the first element of the array, and another with the name and description of Trait 2 as the second element in the array. The constants, WT_1 and WT_2 make it easy to refer to the correct array element without having to remember which trait was is in which index of the array. You can now do things like check to see if the world your character is currently in has a specific trait:

	
	if (CH2.currentAscensionWorld.traits[WT_1])
	{
		// Your Code Here
	}
	

You can use a conditional like the above in places like the override functions described in the Overriding Character Functions section to change how things happen if the world has a specific trait.

A particularly useful function to use for this purpose is applyWorldTraits, which is run whenever a world is started and takes a world number as a parameter, so you can change things that affect the world, such as the amount of monsters in the world, or how much health they have. The following example would set worlds with Trait 1 to have 25 monsters with twice the health, and set it back to 50 (the default) monsters with normal health for worlds that don't have the trait:

	
	public function applyWorldTraitsOverride(worldNumber:Number):void
	{
		var character:Character = CH2.currentCharacter;

		if (CH2.currentAscensionWorld.traits[WT_1])
		{
			character.monstersPerZone = 25;
			character.monsterHealthMultiplier = 2;
		}
		else
		{
			character.monstersPerZone = 50;
			character.monsterHealthMultiplier = 1;
		}
	}
	
Hardcoded World Traits

The game is set up to randomly pick world traits from the array of all traits your character has. However, if you want to set specific world traits for a particular gild, you can create a hardcodedWorldTraits object for your character in the onStartup function.

	
	newCharacter.hardcodedWorldTraits = {
		"31": {
			"traitIDs": [WT_1]
		}
	}
	

In the above code, the number 31 is the number of the first world of the gild you want to hardcode world traits for (by default there are 30 worlds per gild, so the next world, 31 would be the start of the first gild). All worlds after this until the next gild will have the traits that you list in the traitIDs array. In this example, all worlds starting with and including world 31 will have Trait 1, as defined above. Even if we have the number of world traits set higher than the amount of traits listed in this array with the getWorldTraitCountOverride, the worlds in this gild will only have exactly the traits you list and no more.