FANDOM


Blood Brothers is a living game in that it updates and new content is added weekly. In order to keep up with the amount of information this site produces for the fans, a standard update process is recommended. Here I am documenting all the work that is done during a weekly game update to make sure as much of the information is available as we can produce.

Tools

In order to produce an update, a small arsenal of tools will be required and are all freely available.



Files & Links

1100 Pre-created Familiar Pages
Downloadable BB Database/Calculators Spreadsheet - Updated 2/5/2013
1100 Cropped Figure Images

Blood Brothers JSON

Most of the information produced here is derived from a text files stored in the game's folder called "bb_game_data.json". JSON is a text format that permits the transfer of large quantities of data from one system to another and still permit the data to be restored on the receiving system.

Online JSON File



An example of a JSON file can be found at http://blood-a.denagames.com/gamedata?v=.

The server also acts as a repository for older revisions of the JSON file.

http://blood-a.denagames.com/gamedata?v=207 this is the JSON version 207. It is not possible to determine the current version of the JSON on the server at this time.

Local JSON File

NOTE: Since the "Add New Skill" Update, Blood Brothers has been appearing in several different numbered folders, so you will need to browse through each folder and verity the "bb_game_data_version.json" to ensure you have the most recent one.

You can also view and manipulate the local copy of your JSON file straight off of your mobile device. The file is stored in
.ngmoco/516.../bb_game_data_version.json

.ngmoco/516.../bb_game_data.json

The version file will contain a single value which is the version the game_data.json file is. This is the current versioning used by this Wiki in our Blood Brothers Data File page. Any time an update occurs, the details of that update should be documented on the Blood Brothers Data File page.



Other JSON Data

By installing a packet sniffer on your PC or your mobile device, it is possible to capture other JSON data as it is being sent to your mobile device. In informing you of this, I am warning you now...

DO NOT MODIFY OR ATTEMPT TO ALTER TRAFFIC BETWEEN YOUR MACHINES AND DENA/MOBAGE's SERVERS. DOING SO CONSTITUTES HACKING AND UNAUTHORIZED ACCESS. THIS IS ILLEGAL IN MOST COUNTRIES AND MOST LIKELY WILL RESULT IN YOUR ACCOUNT BEING BANNED OR WORSE, A VISIT FROM AN ALPHABET SOUP ORGANIZATION.

Packet Sniffing

Packet sniffing is simply capturing data as it is being transmitted or received by your application. In doing so, you can see the specifics behind some behavior in these applications.

Blue Stacks - To sniff packets in Blue Stacks, you will need to either install Wireshark (Free Packet Capture Tool) or ProxyCap and Fiddler2. ProxyCap is a tool that routes all traffic to one port on your machine. This allows you to proxy all traffic into a Proxy Server Software, Web Content Filter, Monitor Software (For spying on your kids), etc. Fiddler 2 is that Proxy Monitor tool. Wireshark on the other hand, captures all traffic as it passes through the network interface. It's display is much more of a technical nature, but captures more raw data.
Android - Install tPacketCapture from the Play Store. This records your traffic to a PCAP file which can be viewed in Wireshark on your desktop.
iOS - I don't deal with the iOS, so unless you have your own solution, mine is to sell your iOS, get an Android device and see above.
What to Look For
step - when you move in the game, you will either enter a PvE combat, PvP Combat, or other event. The complete details of that event are sent to your phone or Bluestacsk as /step. It is in JSON format and URL Encoded. This means you will need to parse the information out of the JSON and you will have to DECODE the string to plain-text. There are a variety of URL Encoder/Decoders available free online.

The data you will find includes information about the enemy you are facing including their familiars, all their stats, the formation, etc.
Bazaar - I do not know the name of the json file that is transmitted, however I have seen detailed information about trades including the person who won the trade and the person they won the trade from as well all details about the familiars and items involved in the trade. This includes serial numbers assigned to each familiar which I suspect they use to track the familiar across accounts and devices and aids in finding multi-account abusers.
Note that while combat details are available, actual values and actions taken in the battle are not. The battle is resolved server-side and an encrypted sequence is sent to your device which likely contains the actions and values we see in the game. I wrote a blog about using this packet sniffing technique and video capture on Blue Stacks to create a complete combat log including video evidence of the actions taken to associate with the Enemy and Player data extracted from the JSON.

Building Update Templates and Spreadsheets

In order to update the wiki, you need to determine what changes and additions were made, creating spreadsheets, adding PE data, creating templates, pulling down Figurine and/or boss images, cropping them, and then uploading all these to the Wiki.

Determining Changes

The fastest way to determining the changes is to open the version prior to the current update in Notepad++ or other text editor and run a comparison against the current and previous version. Notepad++ has a plugin that makes a side by side comparison of two documents highlighting changes. This makes it very easy to see even the smallest change such as when a Familiar switches from non-tradable to tradable. The following steps assume you are using Notepad++ and have the Compare plugin installed. The plugin is part of the default plugin library and can be installed by clicking on Plugins > Plugin Manager > Show Plugin Manager. Select "Compare" from the list and click on Install.

Note: I recommend renaming all JSON files to a standard format that includes the version number. I rename all my JSON files to "bb_game_data_<version>.json"

  1. Open current version JSON in Notepad++
  2. Open previous version JSON in Notepad++
  3. Press CTRL+H to bring up the "Replace" menu.
  4. Check "Extended" in the Search Mode section
  5. In the Find What: Box, type in "{"
  6. In the Replace With: Box, type in "\n\t{" to add a new line and tab once before every {.
  7. Click on Replace All in All Opened Documents. You should have more than 3900 changes
  8. Press CTRL+H again
  9. In the Find What: Box, type in "],"
  10. In the Replace With: Box, type in "],\n" to add a new line after every ]
  11. Click on Replace All in All Opened Documents. You should have about 30 changes
  12. Press ALT+D to perform the comparison
  13. The screen will split and a navigation frame will appear on the Right.
  14. If you want to change the orientation of the split (from left/right to top/bottom), right click on the seperator and select "Rotate Left/Right".
  15. Press CTRL+PG DN or CTRL+PG UP to move from change to change.
  16. Note all changes.



Creating the Spreadsheets

The good news is that I've developed a ruby program to handle this for you. Before the program, every spreadsheet had to be created by hand and then updated manually every week. The ruby program splits the one json file into multiple Comma Seperated Value (CSV) formatted files which can be opened by any spreadsheet program.

User_blog:OKRedleg/Blood_Brothers_JSON_Parser provides the code to the Ruby script. You will need to install the Ruby Interpreter linked at the top of this page. If you are in windows, copy and paste the code to a text editor and save the file with a .rb extension where you can access it. NOTE: in the code is a reference to "bb_game_data.json". This file needs to be the same as the json you are working with. If you renamed your JSON to "bb_game_data_<version>.json", then the file reference in the code needs to reflect this. In Windows, you can double click the ruby program. It will spew out one CSV file for each section of the JSON. The ones you want to use the most are "Cards.csv", "Items.csv", and "Skills.csv".

If you using Linux, you will have to run the program from a command shell by typing "Ruby <file>.rb"

Spreadsheets

Open the "Cards.csv" and insert 5 columns after the maxAGI column. This will be where you put in PE data.


  • Online Spreadsheet - This file is the Google Docs Spreadsheet. It's live and parts are editable by anonymous users. However, because of how Google Docs implements "Edit/View" Rights, people are still able to damage the document like remove validation fields and alter lookups. I have to constantly patch this file to return it to a version prior to someone modifying it negatively.



NOTE: The online sheet will become inoperable roughtly 12 hours after I stop managing it. Cells B1 on the EvoCalculator2 Tab and B1 on the LevelCalculator Tab contain "Data Validation" which forces the user to select from a list of familiars. If someone "pastes" values into those fields, it removes the data validation and allows for invalid values which will result in incorrect data being returned. This must be fixed regularly (roughly twice a day) in order to sustain it's operability.

EvoCalculator2 - Data Validation is from the Families Tab, Column A. This is the 1* Familiar in every family
LevelCalculator - Data Validation is from the Cards Tab, Column B. This is the name of the familiar.



To maintain this sheet, the following tabs need to be updated with every JSON update:

Cards - Add new cards and input the PE stats
Skills - Add new skills or update existing ones
Families - Manually enter the names of each family member in a single row. Col A is rank 1, Col B is rank 2, etc.
CardLevelMapping - May need to be updated if/when they modify or add new values. It is used in the LevelCalculator Sheet
All other tabs are purely informational only and do not need updates for functionality.



  • Downloadable Excel Spreadsheet - This is the same version last updated on January 23, 2013. You can download this file and all of the formulas, lookup, and other calculations should still be intact.



Copy the rows for all new or change familiars into your working spreadsheet. You should do this at the end of the sheet. Most often, you will be pasting new or changed familiars into the Cards tab, new skills into the Skills tab.

Note: For all new familiars or changed evolutions, you MUST add the names of all evolutions into the "Families" tab. The EvoCalculator2 functions by looking for the 1* version of a familiar in this tab and pulling the others in the same family into the calculator.

Enter the name of the 1* into the calculator and transfer the PE stats to the Cards Tab. You can expedite this by adding "N/A" to all 1* familiars.

Calculator Instructions

EvoCalculator2

This calculator will take the selected rank 1 familiar, (Agrias, Walking Dead for example) and generate the Base, Max, Perfect Stats for that familiar and all Family members, as well as all possible non-perfect evolution combinations with Max Level Stats and Percent Evolved for that particular Familiar. 1. From the drop down list, select the 1* familiar you wish to inquire about. (You may type the name, but it must be spelled exactly as it appears in the "Families" sheet. 2. Base is Level 1 Pact stats 3. Max is Max Level Pact Stats 4. EP is Evolved Perfect Max Level Stats 5. Non-Perfect Evolutions assumes the Seed is max level. 6. Spawns are always to the left of the seed in the evolution annotation. So [2+1] represents a 2* spawn and 1* seed.

LevelCalculator

This calculator will take the selected familiar, (Odin, Stormgod II for example), the level entered, and the stats you enter for your familiar and show you the Growth Data, Max Level, Curve value, and Max Curve value. The following information is also provided:

Base - The Level 1 Base Pact stats (As if you captured in the wild or acquired from coins)
Max - The Max Level Base Pact stats (As if you maxed the level of a captured or coin acquired familiar without crystals or evolution).
EP - Evolved Perfect Stats at Max Level
Pact @ LVL - The stats your selected familiar would have at the level given if he/she were from a Pact
Perfect @ LVL - The stats your selected familiar would have at the level given if it were Perfect Evolved.
Over Pact - Number of points between your familiar and Pact. As you level, the bonus gained from evolution does not change, this number is indicative of how well your familiar is evolved.
Stats @ Max LVL - Since the Evolution Bonus does not change and we know the formula for distribution of stats per level, this field gives you an accurate view of the stats your familiar will have at max level.
PCT Evolved - This field represents the Percent Perfect your familiar is. It is derived from the (SUM OF 'STATS @ MAX LVL') divided by (SUM OF PE).

Creating or Updating Familiar Pages

Once you have all familiars with PE stats, copy the rows to a new spreadsheet and save that spreadsheet as "bb_fams.csv". Copy the Blood Brothers Familiar Template into a text file and save it as "bb_template.txt".

NOTE: If the template on the wiki changes, this file must also be edited to reflect the changes. The ruby program will also have to be edited to accommodate the changed entries.

The following is the Template used in my template generator ruby script:

{{Familiar
| name = <!-- defaults to page name -->
| image = <!-- defaults to placeholder -->
| race = <!-- defaults to Unknown -->
| evolutionstep = 
| maxlvl = 
| rarity = 
| nextrarity = <!-- rarity of the next evolutionary step, leave blank if unknown or next evo step doesn't exist -->
| elite = <!-- leave blank unless familiar is or was elite -->
| event = <!-- event familiar was/is elite for -->
| growth = 
| worth = 
| skill = 
| skill2 = <!-- leave blank unless mounted familiar with second skill -->
| nontradable = <!-- leave blank if the familiar can be traded on the bazaar -->
| lastwords = <!-- last words of a dying familiar in battle -->
| basehp = <!-- Base Stat when captured or pact received -->
| baseatk = 
| basedef = 
| basewis = 
| baseagi = 
| basemaxhp = <!-- Max Stat without evolving or empowering -->
| basemaxatk = 
| basemaxdef = 
| basemaxwis = 
| basemaxagi = 
| maxhp = <!-- Max Stat via evolution only -->
| maxatk = 
| maxdef = 
| maxwis = 
| maxagi = 
| confident = <!-- unless you are ABSOLUTELY Positive the max stats are correct, please leave this blank -->
| Special = <!-- Special information about the familiar -->
| loc1 = 
| loc2 = 
| loc3 = 
| loc4 = 
| loc5 = 
| loc6 = 
| loc7 = 
| loc8 = 
| loc9 = 
| loc10 = 
| evostep1 = 
| evostep2 = 
| evostep3 = 
| evostep4 = 
}}

Now, copy the following code and save it as "bb_template.rb":

#FF Squadmate Template
#Author: OKRedleg
#Updated: 05Dec2012

require 'json'
require 'csv'

#Assign variables
$rarity = ["Common", "Uncommon", "Rare", "Epic", "Legendary"]
$growth = ["Normal", "Fast", "Late", "???"]
ff = JSON.parse(File.open("bb_game_data_228.json").read)
squadmates = []
template = []

#Definitions!  Handle a few tasks for us


#Converts the "Growth" value into a string
def growth(s)
  case s
  when 1
    return "Normal"
  when 2
    return "Fast"
  when 3
    return "Late"
  when 11
    return "???"
  end
end



#Converts the skillId value into a string
def skills(id,ff) 
  ff["skills"].each{|skill| return skill["name"] if skill["id"].to_i == id.to_i}
end

#Finds the other members of the entities family.
def evolution(id, ff)
  #p ff["cardEvolutions"][0].keys
  #First, find the familiar's family id
  family_id = 0
  family = [id.to_i]
  family_names = []
  ff["cardEvolutions"].each{|evolution|
    if evolution["masterCardId"] == id.to_i or evolution["afterCardId"] == id.to_i
      family_id = evolution["evolutionId"]
      break
    end
  }
  #Now, find all the familiar's in that family
  ff["cardEvolutions"].each{|evolution|
    if evolution["evolutionId"] == family_id
      family << evolution["masterCardId"] if not family.include?(evolution["masterCardId"])
      family << evolution["afterCardId"] if not family.include?(evolution["afterCardId"])
    end
  }
  ff["cards"].each{|card|
    family_names << card["name"] if family.include?(card["id"])
  }
  return family_names
end

#Takes the template file and the data from the fams.txt file (our fams we want to create pages for), combines them, and spits out a file to copy.
def format_template(template, squadmates, ff)
  
	squadmates.each{|squadmate|
		output = []
		evo = ""
		#Because of the <!-- --> tags, we need to insert the data between the = sign and the <!-- tag.
		#insert the name of the fam which should be the 2nd field (or item 1)
		output << template[0] 																			#{{familiar
		output << template[1].gsub(/=/, "= "+squadmate[1])												#| name = <!-- defaults to page name -->
		output << template[2] 																			#| image = <!-- defaults to placeholder -->
		output << template[3] 																			#| race = <!-- defaults to Unknown -->
		output << template[4].gsub(/=/, "= "+squadmate[27]+"/"+squadmate[28])							#| evolutionstep = 
		output << template[5].gsub(/=/, "= " + squadmate[23])											#| maxlvl = 
		output << template[6].gsub(/=/, "= " + $rarity[(squadmate[3].to_i-1)])							#| rarity = 
		output << template[7]																			#| nextrarity = <!-- rarity of the next evolutionary step, leave blank if unknown or next evo step doesn't exist -->
		output << template[8]																			#| elite = <!-- leave blank unless familiar is or was elite -->
		output << template[9]																			#| event = <!-- event familiar was/is elite for -->
		output << template[10].gsub(/=/, "= " + growth(squadmate[24].to_i))								#| growth =
		output << template[11].gsub(/=/, "= " + squadmate[6])											#| worth =
		if squadmate[25].nil? || squadmate[25].to_i == 0
		   output << template[12]
		else
		   output << template[12].gsub(/=/, "= " + skills(squadmate[25].to_i,ff))							#| skill = 
		end
		if squadmate[26].to_i > 0 || squadmate[26].nil?
			output << template[13].gsub(/=/, "= " + skills(squadmate[26].to_i,ff))
		else 
			output << template[13]																		#| skill2 = <!-- leave blank unless mounted familiar with second skill -->
		end	
		if squadmate[29].to_i == 0
			output << template[14].gsub(/=/, "= Y")															#| nontradable = <!-- leave blank if the familiar can be traded on the bazaar -->
		else
			output << template[14]
		end
		output << template[15].gsub(/=/, "= " + squadmate[2])											#| lastwords = <!-- last words of a dying familiar in battle -->
		output << template[16].gsub(/=/, "= " + squadmate[8])											#| basehp = <!-- Base Stats when captured or pact received -->
		output << template[17].gsub(/=/, "= " + squadmate[9])											#| baseatk =
		output << template[18].gsub(/=/, "= " + squadmate[10])											#| basedef = 
		output << template[19].gsub(/=/, "= " + squadmate[11])											#| basewis = 
		output << template[20].gsub(/=/, "= " + squadmate[12])											#| baseagi =
		output << template[21].gsub(/=/, "= " + squadmate[13])											#| basemaxhp = 											
		output << template[22].gsub(/=/, "= " + squadmate[14])											#| basemaxatk = 
		output << template[23].gsub(/=/, "= " + squadmate[15])											#| basemaxdef =
		output << template[24].gsub(/=/, "= " + squadmate[16])											#| basemaxwis =
		output << template[25].gsub(/=/, "= " + squadmate[17])											#| basemaxagi =
		if squadmate[18].nil?
			output << template[26]
		else
			output << template[26].gsub(/=/, "= " + squadmate[18])	
		end																								#| maxhp =
		if squadmate[19].nil?
			output << template[27] 
		else 
			output << template[27].gsub(/=/, "= " + squadmate[19])										#| maxatk =
		end
		if squadmate[20].nil?
			output << template[28]
		else
			output << template[28].gsub(/=/, "= " + squadmate[20])										#| maxdef =
		end
		if squadmate[21].nil?
			output << template[29] 
		else
			output << template[29].gsub(/=/, "= " + squadmate[21])										#| maxwis =
		end
		if squadmate[22].nil?
			output << template[30]
		else
			output << template[30].gsub(/=/, "= " + squadmate[22])										#| maxagi =
		end
		output << template[31].gsub(/=/, "= ~~~~") unless squadmate[18].nil? || squadmate[19].nil? || squadmate[20].nil? || squadmate[21].nil? || squadmate[22].nil?#| confident = <!-- unless you are ABSOLUTELY Positive the max stats are correct, please leave this blank -->
		33.upto(42) {|i| output << template[i]}															#| locations
		family = evolution(squadmate[0], ff)
		1.upto(4){|i|
        ff["cards"].each{|card| output << template[i+42].gsub(/=/, "= " + card["name"]) if family.include?(card["name"]) and card["evolution"].to_i == i}
		}
		output << "}}"
		Dir.chdir("\Templates")
		filename = squadmate[1] + '.txt'
		out_file = File.open(filename, "w")
		output.each{|item| out_file.puts item}
		out_file.close()
		puts "#{filename} successfully created."
		Dir.chdir("..")
	}
	
end

#Ok, lets begin
#Open the file containing the fams we want to work with and dump the data into an array
CSV.foreach("bb_fams.csv") do |row|
  squadmates << row
end

#Open the template file.
file = File.open("bb_template.txt")
file.each{|line|
  template << line.strip
}
file.close() unless file.nil?

#Go get the skill name
#skill = skills(squadmates[0][25].to_i, ff)

#Go get the other members of this person's family


format_template(template, squadmates, ff)

The "bb_template.rb", "bb_template.txt", "bb_fams.csv", and "bb_game_data_<version>.json" must all be in the same directory in order for the program to work. Also, make sure that the json version number is current.

Add a new folder to this directory called "Templates". When you run this program, all familiars in the CSV file "bb_fams.csv" will be created and dumped into the templates directory.

For your convenience, I've upload all of the templates that I've generated here.

Adding Images

Now that you have the templates created, it's time to get photos to add to the wiki pages. There are generally 3 types of photos we look for.

  • Profile Photo - Image of the familiars' card. Can be Base, Max, Evolved, etc.
  • Figure Photo - Image of the familiars' Figure. This is recognized as the Familiar posing on a small round platform. The wiki is by default designed to look for this image and automatically assign it to the familiar's page. If the image does not exist, it will look in the template to see if a user added an image. The image should be uploaded as "<Familiar Name>_Figure.png
  • Boss Photo - Image of the familiar in their "Boss" pose. Only certain familiars will have boss images and those should be uploaded as "<Familiar Name>_Boss.png"



To retrieve the files before they are released in the game, look on these servers:

  • Boss Images -
    http://blood-a.denagames.com//DownloadContent/common/card/boss/<Familiar ID>l.png
  • Figure Images -
    http://blood-a.denagames.com//DownloadContent/common/card/figure/<Familiar ID>l.png



For most figure images, except the boss images, you can either use a script program with a command line image editing tool like ImageMagic or a GUI like Gimp 2.

Editing Images in Gimp 2:

1.  Load image in Gimp 2 (CTRL+O)
2.  Right Click on image, select "Image" > "Auto-crop Image.
3.  Windows: Save the image (CTRL+S)
3a. Linux: Export the image (CTRL+E)
4.  Overwrite the existing image (Familiar_Name_Figure.png)
5.  Uncheck "Save background color" to keep transparency.
6.  Save

You may also download the "Figure Image Repository" which contains roughly 1100 cropped Familiar and Boss images.

Special:MultipleUpload is the page you may use to upload multiple files at a time. Currently, it is the most expedient method for uploading the images.

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.