(over)commented talent code

All development conversation and discussion takes place here

Moderator: Moderator

Post Reply
Message
Author
lukep
Sher'Tul Godslayer
Posts: 1712
Joined: Mon Mar 14, 2011 10:32 am
Location: Canada

(over)commented talent code

#1 Post by lukep »

EDIT: much nicer html version here

I added a bunch of comments to the arcane power talent, and plan on doing a few others as well. This is to give anyone interested in learning to develop new talents, modify existing ones, or simply understand them better a solid starting point, and outline what all of the common functions and terms do.

Most of this is quite obvious by the names, but some have nuances and features that would not be apparent at first look.

I'm planning on doing a few other talents as well, at least one spell attack, one martial attack, and one passive, with others added in as needed. They would not have nearly this much information added to them, as I would not duplicate information across multiple talents.

Here's what I have so far: (corrections, additions, comments, and clarifications would be appreciated)

Code: Select all

newTalent{
-- Start here
	name = "Arcane Power",
-- the name that is displayed to the player.  It also determines the short name and image, unless they are overridden by their own entries.
	-- short_name = "ARCANE_POWER"
-- what the code refers to this talent by.  This must be unique, or else problems arise.  Within the code for this talent, it is also referred to as "t".  This is usually automatically based on the name.
	-- image = "talents/arcane_power.png"
-- the icon for the talent that is displayed in the levelup screen as well as on the talent bar.  This is usually automatically based on the name.
	type = {"spell/arcane", 1},
-- The tree and tier of the talent.
	mode = "sustained",
-- The three modes are activated, sustained, and passive.  Talents are passive by default.
	require = spells_req1,
-- The requirements to get this talent, usually a stat and character level.  It is found in data/talents/spells/spells.lua
	sustain_mana = 50,
-- sustain_mana and any other sustain resources reduce your maximum capacity of the resource instead of costing some amount of your current.
	points = 5,
-- How many class or generic points can be invested into the talent.  This is (almost) always 5.
	cooldown = 30,
-- How long you need to wait before using the talent again.  For sustains this starts when the sustain is deactivated, not when it is started.
	tactical = { BUFF = 2 },
-- Information for the tactical AI used by elite and better enemies.
	spellpower_increase = { 5, 9, 13, 16, 18 },
-- a variable.  It can be retrieved within the talent by t.spellpower_increase, or anywhere else by defining local t = self:getTalentFromId(self.T_ARCANE_POWER), then using it.
	getSpellpowerIncrease = function(self, t)
-- a function.  It can be retrieved within the talent by t.getSpellpowerincrease(self, t), or anywhere else by defining local t = self:getTalentFromId(self.T_ARCANE_POWER), then using it.
		local v = t.spellpower_increase[self:getTalentLevelRaw(t)]
-- a local variable.  It can be retrieved until the next line that is tabbed out less than where it was defined by using its name (without putting "local" in front).   
-- Call a entry in a table (things inside {}) by using an integer in square brackets like [].  1 returns the first entry, 2 returns the second etc…
		if v then return v else return 18 + (self:getTalentLevelRaw(t) - 5) * 2 end
-- boolean operators are if, then, else, and, or, not
-- The return statement is the value, true/false, or anything else.  To return nothing, use return nil.
	end,
-- this marks the end of the function
	activate = function(self, t)
-- This function is called when you activate the sustain
		game:playSoundNear(self, "talents/arcane")
-- This plays a sound if the player is near the source.  This sound file is data/sound/talents/arcane.ogg
		-- game:playSound (self, "talents/arcane")
-- This plays a sound, regardless of the source.  Do not use this in most cases.  
		return {
-- This is what using the sustained talent does.  Note that this is called when it is started being sustained, and is not updated with changing stats after that.
			power = self:addTemporaryValue("combat_spellpower", t.getSpellpowerIncrease(self, t)),
-- Adds a temporary bonus/malus to the character, in this case as much spellpower as is determined by the function.
			particle = self:addParticles(Particles.new("arcane_power", 1)),
-- Adds a particle effect to the character.  This particle file is data/gfx/particles/arcane_power.lua
		}
	end,
	deactivate = function(self, t, p)
-- This is called when the sustain is deactivated.  It should remove everything that activating it adds, or else problems result.
		self:removeParticles(p.particle)
		self:removeTemporaryValue("combat_spellpower", p.power)
		return true
	end,
	info = function(self, t)
-- the description that the player sees when mousing over the talent.
		local spellpowerinc = t.getSpellpowerIncrease(self, t)
-- creating local variables that call talent functions for the description is good because it is easier to read and it is resistant to breaking with balancing updates.
		return ([[Your mastery of magic allows you to enter a deep concentration state, increasing your spellpower by %d.]]):
-- The description that the player sees.  Anything starting in a % sign is replaced by the term in "format" below.  
-- %d = whole number, %0.2f = two decimal places, %0.3f = three decimal places, %% = "%" is displayed, 
		format(spellpowerinc)
-- Terms that replace the % things in the description, separated by commas.
	end,
}
-- end here
Last edited by lukep on Sun Feb 26, 2012 9:35 pm, edited 1 time in total.
Some of my tools for helping make talents:
Melee Talent Creator
Annotated Talent Code (incomplete)

Rectifier
Archmage
Posts: 386
Joined: Mon Aug 29, 2011 8:06 am

Re: (over)commented talent code

#2 Post by Rectifier »

Here's a prettified version of luke's code...yes I'm ocd about commenting.

Code: Select all

/* Each line with two preceding dashes is a comment, /* and */ are block comments. For the 
** purposes of this example, each comment will be in block form to emphasize the optional variables 
** that are commented by two preceding dashes.
**
** Note: The block comments for this example should be read in a top-down manner, meaning that 
** the code directly below a block comment is what the comment is talking about.
*/

/* Start Here
**
** Notice that we begin with the statement 'newTalent' and end the statement with a pretty left 
** bracket {. This tells the game that all the code after that left bracket is part of the new talent, 
** and only when this new talent is closed with a pretty right bracket } will our talent be 
** considered complete.
*/
newTalent{
/* 'name' is the name displayed to the player.  'short_name' and 'image' default to this unless 
** overridden. 
*/
   name = "Arcane Power",
/* 'short_name' is the name referenced internally. This must be unique. This example talent is also 
** referred to as "t".  Short names are usually based on the name.
*/
   -- short_name = "ARCANE_POWER"
/* Icon for the talent which is displayed on the levelup screen and the talent bar. Usually based on 
** the name variable.
*/
   -- image = "talents/arcane_power.png"
/* The tree ("spell/arcane") and tier (1) of the talent.
*/
   type = {"spell/arcane", 1},
/* The three modes the game uses are activated, sustained, and passive.  Talents are considered 
** passive by default.
*/
   mode = "sustained",
/* Talent requirements, usually a stat and character level.
** This is found in "...tomedir/game/modules/tome/data/talents/spells/spells.lua"
*/
   require = spells_req1,
/* 'sustain_mana' and any other sustain reduces the maximum capacity of the specified resource for 
** a particular character instead of subtracting the value from the current amount of the relevant 
** resource. In this case, this would lower the character's maximum mana capacity by 50 points.
*/
   sustain_mana = 50,
/* Maximum class or generic points that can be invested into the talent.  This is (almost) always 5.
*/
   points = 5,
/* Amount of turns to wait before the character is allowed to use the talent again.  For sustains 
** this countdown begins when the sustain is deactivated, not when it is started.
*/
   cooldown = 30,
/* Information for the tactical AI used by elite and better enemies. Tactical AI is out of the scope 
** of this example.
*/
   tactical = { BUFF = 2 },
/* This array can be retrieved within the talent by 't.spellpower_increase', or anywhere else by 
** defining 'local t = self:getTalentFromId(self.T_ARCANE_POWER)', then using it.
*/
   spellpower_increase = { 5, 9, 13, 16, 18 },
/* This function can be retrieved within the talent by t.getSpellpowerincrease(self, t), or anywhere 
** else by defining local t = self:getTalentFromId(self.T_ARCANE_POWER), then using it.
*/
   getSpellpowerIncrease = function(self, t)
/* This local variable can be retrieved except when the next line is indented less than where it was
** originally defined. You can do this by using its name without the word 'local' in front of it.
*/
      local v = t.spellpower_increase[self:getTalentLevelRaw(t)]

/* You can call an entry in a table, the values inside the pretty brackets {}, by using an integer in 
** square brackets like []. The integer references the location of the value within the table. For 
** example, 1 returns the first entry, 2 returns the second, etcetera.
*/

/* Boolean operators for working with tome are the familiar: "if, then, else, and, or, not"
** The statement 'return' is the output of an expression, such as an integer, true/false, or anything 
** else. If you do not wish to return any value at all, use the statement 'return nil'.
*/
    if v then return v else return 18 + (self:getTalentLevelRaw(t) - 5) * 2 end
/* This marks the end of the function, it is very important that end statements are placed in the 
** correct place, or you will more than likely receive syntax errors.
*/
   end,
/* This function is called when you activate the sustain.
*/
   activate = function(self, t)

/* This plays a sound in the game if the player is near the source of the talent, such as an npc 
** activating the talent.  This sound file is located in ".../tomedir/game/modules/tome/data/sound/
** talents/arcane.ogg"
*/
      game:playSoundNear(self, "talents/arcane")
/* This plays a sound regardless of the source.  Do not use this in most cases.
*/
      -- game:playSound (self, "talents/arcane")
/* This begins a return block, when return is called, the code within the block is called. Pay 
** particular attention to the pretty left bracket { after the return statement, this is what keeps 
** our return block together in one piece and must have a corresponding pretty right bracket.
*/
      return {
/* The code within this return block is how using the talent is performed within the code.  Note that 
** the talent is called when it is beginning to be sustained, and is not updated after that. This 
** includes sustains that are based on the stats of the character.
*/

/* Adds a temporary bonus/malus to the character, in this case as much spellpower as is determined 
** by the function's definition.
*/
         power = self:addTemporaryValue("combat_spellpower", t.getSpellpowerIncrease(self, t)),
/* Adds a particle effect to the character. 
** This particle file is located in:
** ".../tomedir/game/modules/tome/data/gfx/particles/arcane_power.lua"
*/
         particle = self:addParticles(Particles.new("arcane_power", 1)),

/* The return block is now complete, which we show with a pretty right bracket } aligned with the 
** pretty bracket that started the block. The block is then terminated with the 'end,' statement 
** one line below the pretty bracket.
*/
      }
   end,
/* This block is called when the sustain is deactivated.  Make sure it removes everything 
** that the activation added to the character unless you enjoy looking at error messages.
** Begin the block with the word 'deactivate' and finish it with an 'end,' statement. Also make sure 
** that you indent the code within the block.
*/
   deactivate = function(self, t, p)
      self:removeParticles(p.particle)
      self:removeTemporaryValue("combat_spellpower", p.power)
      return true
   end,

/* Description the player sees when mousing over the talent.
*/
   info = function(self, t)

/* Using new local variables to call talent functions for the description is good because it is easier to 
** read and is more resistant to breaking when the balance of the game changes. Basically this 
** makes your own code easier to maintain when things are going wrong and when things are going 
** right.
*/
      local spellpowerinc = t.getSpellpowerIncrease(self, t)
/* The description that the player sees. Anything starting with a % sign is replaced by the 'format'
** function below the return statement. In other settings, this % sign could be a backslash or any 
** other character.
**
** In the programming world, our % is called an escape character, and it is used to present data 
** more easily and in a more readable manner. In this particular case, the escape character and 
** how it works is similar to how the built-in function printf works in the C programming language.
**
** How to translate the escape characters in your code into english:
** %d = a whole number or integer
** %0.2f = a number with two decimal places
** %0.3f = a number with three decimal places
** %% = a percent sign
*/
      return ([[Your mastery of magic allows you to enter a deep concentration state, increasing your spellpower by %d.]]):

/* 'spellpowerinc' is a value that replaces the escape character in the description. If your 
** description has multiple values, then the corresponding variables are added onto the statement 
** in left to right order, and are separated by commas.
**
** For example, if my description has a %d first and a %0.2f second, then my variables must be in 
** that order as well as shown here: format(first_integer, second_decimal)
** We wouldn't want to tell the game that the decimal value is a whole number and that the whole 
** number is a decimal now would we? This is why the order is so important.
*/
      format(spellpowerinc)
   end,
}
/* Finally we have reached the end of our talent's code, we close the code block with an interior 
** 'end,' statement to tell the game that 'newTalent' is done and we finish it off with a pretty right 
** bracket }.
*/

bricks
Sher'Tul
Posts: 1262
Joined: Mon Jun 13, 2011 4:10 pm

Re: (over)commented talent code

#3 Post by bricks »

I didn't think you could do block comments like that in lua (I've used --[[...]] and --[=[..]=]).

Regardless, this is very cool. If more work is done in this direction (actors, zones for example) it would be great for a distinction to be drawn between core features and features specific to the TOME module.

Also, it would be very good to point out when a property can be a value or a function. There's a lot of powerful functionality there that isn't entirely obvious. I know that I was (happily!) surprised to see that the T-Engine was designed in many cases to handle both.
Sorry about all the parentheses (sometimes I like to clarify things).

lukep
Sher'Tul Godslayer
Posts: 1712
Joined: Mon Mar 14, 2011 10:32 am
Location: Canada

Re: (over)commented talent code

#4 Post by lukep »

I've started a blog to host the html comments, and have added Arcane Power and (most of) Manathrust to it. The information is contained in tooltips, as well as some examples added in green text. Check it out at http://tometalentcomments.blogspot.com/.
Some of my tools for helping make talents:
Melee Talent Creator
Annotated Talent Code (incomplete)

catwhowalksbyhimself
Wyrmic
Posts: 249
Joined: Sun Aug 15, 2004 1:19 am
Location: Plainville, CT

Re: (over)commented talent code

#5 Post by catwhowalksbyhimself »

I applaud this effort. I makes figuring how to do this a lot easier. Would have made things easier for me, that's for sure.
"I am the cat that walks by himself. All ways are alike to me."
--Rudyard Kipling, "The Cat That Walked By Himself"

Post Reply