log-profile.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. #!/usr/bin/python3
  2. import sys
  3. import os
  4. import sqlite3
  5. import json
  6. import math
  7. """
  8. Reads the API KEY, that must be passed as first command line argument.
  9. :returns: Recovered API KEY.
  10. :raises Exception: Th KEY couldn't be red.
  11. """
  12. def readKey():
  13. try:
  14. #print(sys.argv[1])
  15. key = sys.argv[1]
  16. return key
  17. except Exception as e:
  18. print("Error parsing API KEY: " + str(e))
  19. raise
  20. """
  21. Reads the JSON data, that must be passed as second command line argument.
  22. :returns: Recovered data, in JSON format.
  23. :raises Exception: The data couldn't be red or converted to JSON.
  24. """
  25. def readData():
  26. try:
  27. #print(sys.argv[1])
  28. #data = json.loads(sys.argv[1])
  29. with open(sys.argv[2], 'r') as f:
  30. content = f.read()
  31. data = json.loads(content)
  32. return data
  33. except Exception as e:
  34. print("Error parsing data: " + str(e))
  35. raise
  36. """
  37. Verifies that the API key matches the player data and that it exists in th DB.
  38. :param db: Connection to the database.
  39. :returns: Connection to the database.
  40. :param data: Data in json format.
  41. :param key: API KEY.
  42. :returns: True if key and player match, False otherwise.
  43. :raises IntegrityError: The queryes couldn't bre executed.
  44. """
  45. def verifyKey(db, data, key):
  46. print('Verifying KEY...')
  47. status = False
  48. try:
  49. uid = data["wizard_info"]["wizard_id"]
  50. cursor = db.cursor()
  51. #print('SELECT count(uid) AS c FROM player WHERE uid = ? AND api_key = ?;')
  52. #print(uid)
  53. #print(key)
  54. cursor.execute('SELECT count(uid) AS c FROM player WHERE uid = ? AND api_key = ?;', (uid, key))
  55. if cursor.fetchone()[0] == 1:
  56. status = True
  57. cursor.close()
  58. except sqlite3.IntegrityError as e:
  59. print("Error executing statement: " + str(e))
  60. raise
  61. return status
  62. """
  63. Opens the database file and cleans the user tables.
  64. It also disables referencial integrity.
  65. :param name: The path to the sqlite database.
  66. :returns: Connection to the database.
  67. :raises IntegrityError: The queryes couldn't bre executed.
  68. :raises IOError: The sqlite file couldn't be created.
  69. """
  70. def openDatabase(name):
  71. print('Configuring database...')
  72. try:
  73. db = sqlite3.connect(name)
  74. cursor = db.cursor()
  75. cursor.execute('PRAGMA foreign_keys = OFF;')
  76. cursor.execute('DELETE FROM scenario')
  77. cursor.execute('DELETE FROM defense')
  78. cursor.execute('DELETE FROM unit')
  79. cursor.execute('DELETE FROM unit_skill')
  80. cursor.execute('DELETE FROM rune')
  81. cursor.execute('DELETE FROM building')
  82. cursor.execute('DELETE FROM decoration')
  83. cursor.execute('DELETE FROM inventory')
  84. cursor.execute('DELETE FROM summon_special')
  85. cursor.execute('DELETE FROM guild')
  86. cursor.execute('DELETE FROM guild_member')
  87. cursor.execute('DELETE FROM rune_craft')
  88. db.commit()
  89. cursor.close()
  90. return db
  91. except sqlite3.IntegrityError as e:
  92. print("Error executing statement: " + str(e))
  93. raise
  94. except IOError as e:
  95. print("I/O Error creating database " + name + ": " + str(e))
  96. raise
  97. """
  98. Closes the database.
  99. Before doing so, it also disables referencial integrity.
  100. :param db: Connection to the database.
  101. :returns: Connection to the database.
  102. :raises IntegrityError: The queryes couldn't bre executed.
  103. """
  104. def closeDatabase(name):
  105. print('Closing database connection...')
  106. try:
  107. cursor = db.cursor()
  108. cursor.execute('PRAGMA foreign_keys = ON;')
  109. cursor.close()
  110. db.commit()
  111. db.close()
  112. except sqlite3.IntegrityError as e:
  113. print("Error executing statement: " + str(e))
  114. raise
  115. """
  116. Inserts a row into the database.
  117. :param db: Connection to the database.
  118. :param table: Name of the table to insert into.
  119. :param values: List of values to insert.
  120. :raises IntegrityError: The insert query was unsuccesfull.
  121. """
  122. def insert(db, table, values):
  123. cursor = db.cursor()
  124. db.execute('PRAGMA foreign_keys = OFF;')
  125. placeholders = ''
  126. for x in range(0, len(values)):
  127. placeholders = placeholders + '?, '
  128. placeholders = placeholders[:len(placeholders) - 2]
  129. query = 'INSERT INTO ' + table + ' VALUES (' + placeholders + ')'
  130. try:
  131. cursor.execute(query, values)
  132. except sqlite3.IntegrityError as e:
  133. print('Error Inserting into ' + table + ' with values (' + str(values) + '): ' + str(e))
  134. raise
  135. cursor.close;
  136. """
  137. Parses player (table player).
  138. :param db: Sqlite database connection.
  139. :param data: Data in json format.
  140. """
  141. def parsePlayer(db, data):
  142. print("Parsing player...")
  143. cursor = db.cursor()
  144. uid = data["wizard_info"]["wizard_id"]
  145. name = data["wizard_info"]["wizard_name"]
  146. # TODO: Generate data
  147. mail = data["wizard_info"]["wizard_name"]
  148. password = data["wizard_info"]["wizard_name"]
  149. api_key = data["wizard_info"]["wizard_name"]
  150. mana = data["wizard_info"]["wizard_mana"]
  151. crystal = data["wizard_info"]["wizard_crystal"]
  152. country = data["wizard_info"]["wizard_last_country"]
  153. lang = data["wizard_info"]["wizard_last_lang"]
  154. level = data["wizard_info"]["wizard_level"]
  155. experience = data["wizard_info"]["experience"]
  156. energy = data["wizard_info"]["wizard_energy"]
  157. energy_max = data["wizard_info"]["energy_max"]
  158. energy_per_min = data["wizard_info"]["energy_per_min"]
  159. arena_energy = data["wizard_info"]["arena_energy"]
  160. arena_energy_max = data["wizard_info"]["arena_energy_max"]
  161. rep = data["wizard_info"]["rep_unit_id"]
  162. social_point = data["wizard_info"]["social_point_current"]
  163. honor_point = data["wizard_info"]["honor_point"]
  164. guild_point = data["wizard_info"]["guild_point"]
  165. darkportal_energy = data["wizard_info"]["darkportal_energy"]
  166. darkportal_energy_max = data["wizard_info"]["darkportal_energy_max"]
  167. dimension_energy = data["dimension_hole_info"]["energy"]
  168. dimension_energy_max = data["dimension_hole_info"]["energy_max"]
  169. costume_point = data["wizard_info"]["costume_point"]
  170. costume_point_max = data["wizard_info"]["costume_point_max"]
  171. honor_medal = data["wizard_info"]["honor_medal"]
  172. honor_mark = data["wizard_info"]["honor_mark"]
  173. event_coin = data["wizard_info"]["event_coin"]
  174. storage_slots = data["unit_depository_slots"]["number"]
  175. island_upgrade = 0
  176. for island in data["island_info"]:
  177. if island["id"] <= 7 and island["open"] == 1:
  178. island_upgrade = island["id"]
  179. query = '''
  180. UPDATE player
  181. SET mana = ?,
  182. crystal = ?,
  183. country = ?,
  184. lang = ?,
  185. level = ?,
  186. experience = ?,
  187. energy = ?,
  188. energy_max = ?,
  189. energy_per_min = ?,
  190. arena_energy = ?,
  191. arena_energy_max = ?,
  192. rep = ?,
  193. social_point = ?,
  194. honor_point = ?,
  195. guild_point = ?,
  196. darkportal_energy = ?,
  197. darkportal_energy_max = ?,
  198. dimension_energy = ?,
  199. dimension_energy_max = ?,
  200. costume_point = ?,
  201. costume_point_max = ?,
  202. honor_medal = ?,
  203. honor_medal = ?,
  204. event_coin = ?,
  205. storage_slots = ?,
  206. island = ?
  207. WHERE uid = ?;
  208. '''
  209. values = (
  210. mana, crystal, country,
  211. lang, level, experience,
  212. energy, energy_max, energy_per_min,
  213. arena_energy, arena_energy_max, rep,
  214. social_point, honor_point, guild_point,
  215. darkportal_energy, darkportal_energy_max, dimension_energy,
  216. dimension_energy_max, costume_point, costume_point_max,
  217. honor_medal, honor_medal, event_coin,
  218. storage_slots, island_upgrade, uid
  219. )
  220. try:
  221. cursor.execute(query, values)
  222. db.commit()
  223. except sqlite3.IntegrityError as e:
  224. print('Error updating player table with: ' + str(query) + ' <== ' + str(values) + ' || Error message:' + str(e))
  225. raise
  226. """
  227. Parses scenarios (table scenario).
  228. :param db: Sqlite database connection.
  229. :param data: Data in json format.
  230. """
  231. def parseScenarios(db, data):
  232. print("Parsing scenarios...")
  233. uid = data["wizard_info"]["wizard_id"]
  234. for sce in data["scenario_list"]:
  235. region = sce["region_id"]
  236. difficulty = sce["difficulty"]
  237. cleared = sce["cleared"]
  238. max_cleared = 0
  239. for stage in sce["stage_list"]:
  240. if stage["cleared"] == 1:
  241. max_cleared = stage["stage_no"]
  242. insert(db, "scenario", (uid, region, difficulty, cleared, max_cleared))
  243. db.commit()
  244. """
  245. Parses arena defense units (table defense).
  246. :param db: Sqlite database connection.
  247. :param data: Data in json format.
  248. """
  249. def parseDefense(db, data):
  250. print("Parsing arena defense...")
  251. uid = data["wizard_info"]["wizard_id"]
  252. for defense in data["defense_unit_list"]:
  253. unit = defense["unit_id"]
  254. position = defense["pos_id"]
  255. insert(db, "defense", (uid, unit, position))
  256. db.commit()
  257. """
  258. Parses buildings (table building).
  259. :param db: Sqlite database connection.
  260. :param data: Data in json format.
  261. """
  262. def parseBuildings(db, data):
  263. print("Parsing buildings...")
  264. uid = data["wizard_info"]["wizard_id"]
  265. for bui in data["building_list"]:
  266. building = bui["building_master_id"]
  267. gain = bui["gain_per_hour"]
  268. insert(db, "building", (uid, building, gain))
  269. db.commit()
  270. """
  271. Parses decoration buildings (table dcoration).
  272. :param db: Sqlite database connection.
  273. :param data: Data in json format.
  274. """
  275. def parseDecorations(db, data):
  276. print("Parsing decorations...")
  277. uid = data["wizard_info"]["wizard_id"]
  278. for bui in data["deco_list"]:
  279. building = bui["master_id"]
  280. level = bui["level"]
  281. insert(db, "decoration", (uid, building, level))
  282. db.commit()
  283. """
  284. Parses unit data (tables unit, unit_skill).
  285. :param db: Sqlite database connection.
  286. :param data: Data in json format.
  287. """
  288. def parseUnits(db, data):
  289. print("Parsing monsters...")
  290. uid = data["wizard_info"]["wizard_id"]
  291. lock_list = data["unit_lock_list"]
  292. for mon in data["unit_list"]:
  293. id = mon["unit_id"]
  294. building = mon["building_id"]
  295. monster = mon["unit_master_id"]
  296. level = mon["unit_level"]
  297. stars = mon["class"]
  298. hp = mon["con"] * 15 # Always x15
  299. attack = mon["atk"]
  300. defense = mon["def"]
  301. speed = mon["spd"]
  302. crit_rate = mon["critical_rate"]
  303. crit_damage = mon["critical_damage"]
  304. resistance = mon["resist"]
  305. accuracy = mon["accuracy"]
  306. experience = mon["experience"]
  307. exp_gained = mon["exp_gained"]
  308. exp_gain_rate = mon["exp_gain_rate"]
  309. costume = mon["costume_master_id"]
  310. attribute = mon["attribute"]
  311. source = mon["source"]
  312. create_time = mon["create_time"]
  313. homunculus = mon["homunculus"]
  314. homunculus_name = mon["homunculus_name"]
  315. lock = 0
  316. if id in lock_list:
  317. lock = 1
  318. insert(db, "unit", (uid, id, building, monster, level, stars, hp, attack, defense, speed, crit_rate, crit_damage, resistance, accuracy, experience, exp_gained, exp_gain_rate, costume, attribute, source, create_time, homunculus, homunculus_name, lock))
  319. for skill in mon["skills"]:
  320. skill_id = skill[0]
  321. skill_level = skill[1]
  322. insert(db, "unit_skill", (id, skill_id, skill_level))
  323. db.commit()
  324. """
  325. Parses inventory data (table inventory).
  326. :param db: Sqlite database connection.
  327. :param data: Data in json format.
  328. """
  329. def parseInventory(db, data):
  330. print("Parsing inventory...")
  331. uid = data["wizard_info"]["wizard_id"]
  332. for item in data["inventory_info"]:
  333. id = item["item_master_id"]
  334. type = item["item_master_type"]
  335. # TODO: Master id?
  336. amount = item["item_quantity"]
  337. insert(db, "inventory", (uid, id, type, amount))
  338. """
  339. Parses summon stone list (table summon_special).
  340. :param db: Sqlite database connection.
  341. :param data: Data in json format.
  342. """
  343. def parseSummonSpecial(db, data):
  344. print("Parsing Summon stone monster list...")
  345. uid = data["wizard_info"]["wizard_id"]
  346. for unit in data["summon_special_info"]["this"]:
  347. insert(db, "summon_special", (0, unit))
  348. for unit in data["summon_special_info"]["next"]:
  349. insert(db, "summon_special", (1, unit))
  350. for unit in data["summon_special_info"]["third"]:
  351. insert(db, "summon_special", (2, unit))
  352. for unit in data["summon_special_info"]["fourth"]:
  353. insert(db, "summon_special", (3, unit))
  354. """
  355. Parses rune data (table rune).
  356. :param db: Sqlite database connection.
  357. :param data: Data in json format.
  358. """
  359. def parseRunes(db, data):
  360. print("Parsing runes...")
  361. STAT_HP = 1
  362. STAT_HP_PCT = 2
  363. STAT_ATK = 3
  364. STAT_ATK_PCT = 4
  365. STAT_DEF = 5
  366. STAT_DEF_PCT = 6
  367. STAT_SPD = 8
  368. STAT_CRIT_RATE_PCT = 9
  369. STAT_CRIT_DMG_PCT = 10
  370. STAT_RESIST_PCT = 11
  371. STAT_ACCURACY_PCT = 12
  372. MAIN_STAT_VALUES = {
  373. # [stat][stars][level]: value
  374. STAT_HP: {
  375. 1: [40, 85, 130, 175, 220, 265, 310, 355, 400, 445, 490, 535, 580, 625, 670, 804],
  376. 2: [70, 130, 190, 250, 310, 370, 430, 490, 550, 610, 670, 730, 790, 850, 910, 1092],
  377. 3: [100, 175, 250, 325, 400, 475, 550, 625, 700, 775, 850, 925, 1000, 1075, 1150, 1380],
  378. 4: [160, 250, 340, 430, 520, 610, 700, 790, 880, 970, 1060, 1150, 1240, 1330, 1420, 1704],
  379. 5: [270, 375, 480, 585, 690, 795, 900, 1005, 1110, 1215, 1320, 1425, 1530, 1635, 1740, 2088],
  380. 6: [360, 480, 600, 720, 840, 960, 1080, 1200, 1320, 1440, 1560, 1680, 1800, 1920, 2040, 2448],
  381. },
  382. STAT_HP_PCT: {
  383. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  384. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  385. 3: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 38],
  386. 4: [5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 27, 29, 31, 33, 36, 43],
  387. 5: [8, 10, 12, 15, 17, 20, 22, 24, 27, 29, 32, 34, 37, 40, 43, 51],
  388. 6: [11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 63],
  389. },
  390. STAT_ATK: {
  391. 1: [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 54],
  392. 2: [5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 73],
  393. 3: [7, 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77, 92],
  394. 4: [10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, 88, 94, 112],
  395. 5: [15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99, 106, 113, 135],
  396. 6: [22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 160],
  397. },
  398. STAT_ATK_PCT: {
  399. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  400. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  401. 3: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 38],
  402. 4: [5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 27, 29, 31, 33, 36, 43],
  403. 5: [8, 10, 12, 15, 17, 20, 22, 24, 27, 29, 32, 34, 37, 40, 43, 51],
  404. 6: [11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 63],
  405. },
  406. STAT_DEF: {
  407. 1: [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 54],
  408. 2: [5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 73],
  409. 3: [7, 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77, 92],
  410. 4: [10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, 88, 94, 112],
  411. 5: [15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99, 106, 113, 135],
  412. 6: [22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 160],
  413. },
  414. STAT_DEF_PCT: {
  415. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  416. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  417. 3: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 38],
  418. 4: [5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 27, 29, 31, 33, 36, 43],
  419. 5: [8, 10, 12, 15, 17, 20, 22, 24, 27, 29, 32, 34, 37, 40, 43, 51],
  420. 6: [11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 63],
  421. },
  422. STAT_SPD: {
  423. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  424. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  425. 3: [3, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18, 19, 21, 25],
  426. 4: [4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 30],
  427. 5: [5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 39],
  428. 6: [7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 42],
  429. },
  430. STAT_CRIT_RATE_PCT: {
  431. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  432. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  433. 3: [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 37],
  434. 4: [4, 6, 8, 11, 13, 15, 17, 19, 22, 24, 26, 28, 30, 33, 35, 41],
  435. 5: [5, 7, 10, 12, 15, 17, 19, 22, 24, 27, 29, 31, 34, 36, 39, 47],
  436. 6: [7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 58],
  437. },
  438. STAT_CRIT_DMG_PCT: {
  439. 1: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  440. 2: [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 37],
  441. 3: [4, 6, 9, 11, 13, 16, 18, 20, 22, 25, 27, 29, 32, 34, 36, 43],
  442. 4: [6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 57],
  443. 5: [8, 11, 15, 18, 21, 25, 28, 31, 34, 38, 41, 44, 48, 51, 54, 65],
  444. 6: [11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 67, 80],
  445. },
  446. STAT_RESIST_PCT: {
  447. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  448. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  449. 3: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 38],
  450. 4: [6, 8, 10, 13, 15, 17, 19, 21, 24, 26, 28, 30, 32, 35, 37, 44],
  451. 5: [9, 11, 14, 16, 19, 21, 23, 26, 28, 31, 33, 35, 38, 40, 43, 51],
  452. 6: [12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 64],
  453. },
  454. STAT_ACCURACY_PCT: {
  455. 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18],
  456. 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19],
  457. 3: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 38],
  458. 4: [6, 8, 10, 13, 15, 17, 19, 21, 24, 26, 28, 30, 32, 35, 37, 44],
  459. 5: [9, 11, 14, 16, 19, 21, 23, 26, 28, 31, 33, 35, 38, 40, 43, 51],
  460. 6: [12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 64],
  461. },
  462. }
  463. SUBSTAT_INCREMENTS = {
  464. # [stat][stars]: value
  465. # Max possible substat value can be found by multiplying by 5
  466. STAT_HP: {
  467. 1: 60,
  468. 2: 105,
  469. 3: 165,
  470. 4: 225,
  471. 5: 300,
  472. 6: 375,
  473. },
  474. STAT_HP_PCT: {
  475. 1: 2,
  476. 2: 3,
  477. 3: 5,
  478. 4: 6,
  479. 5: 7,
  480. 6: 8,
  481. },
  482. STAT_ATK: {
  483. 1: 4,
  484. 2: 5,
  485. 3: 8,
  486. 4: 10,
  487. 5: 15,
  488. 6: 20,
  489. },
  490. STAT_ATK_PCT: {
  491. 1: 2,
  492. 2: 3,
  493. 3: 5,
  494. 4: 6,
  495. 5: 7,
  496. 6: 8,
  497. },
  498. STAT_DEF: {
  499. 1: 4,
  500. 2: 5,
  501. 3: 8,
  502. 4: 10,
  503. 5: 15,
  504. 6: 20,
  505. },
  506. STAT_DEF_PCT: {
  507. 1: 2,
  508. 2: 3,
  509. 3: 5,
  510. 4: 6,
  511. 5: 7,
  512. 6: 8,
  513. },
  514. STAT_SPD: {
  515. 1: 1,
  516. 2: 2,
  517. 3: 3,
  518. 4: 4,
  519. 5: 5,
  520. 6: 6,
  521. },
  522. STAT_CRIT_RATE_PCT: {
  523. 1: 1,
  524. 2: 2,
  525. 3: 3,
  526. 4: 4,
  527. 5: 5,
  528. 6: 6,
  529. },
  530. STAT_CRIT_DMG_PCT: {
  531. 1: 2,
  532. 2: 3,
  533. 3: 4,
  534. 4: 5,
  535. 5: 6,
  536. 6: 7,
  537. },
  538. STAT_RESIST_PCT: {
  539. 1: 2,
  540. 2: 3,
  541. 3: 5,
  542. 4: 6,
  543. 5: 7,
  544. 6: 8,
  545. },
  546. STAT_ACCURACY_PCT: {
  547. 1: 2,
  548. 2: 3,
  549. 3: 5,
  550. 4: 6,
  551. 5: 7,
  552. 6: 8,
  553. },
  554. }
  555. uid = data["wizard_info"]["wizard_id"]
  556. # Unequipped runes
  557. for rune in data["runes"]:
  558. id = rune["rune_id"]
  559. assigned_to = rune["occupied_id"]
  560. if assigned_to == 0:
  561. assigned_to = None
  562. runeset = rune["set_id"]
  563. slot = rune["slot_no"]
  564. stars = rune["class"]
  565. ancient = 0
  566. level = rune["upgrade_curr"]
  567. original_quality = rune["extra"]
  568. value = rune["sell_value"]
  569. if stars > 10:
  570. ancient = 1
  571. stars = stars - 10
  572. original_quality = original_quality - 10
  573. if level >= 12:
  574. quality = 4
  575. elif level >= 9:
  576. quality = 3
  577. elif level >= 6:
  578. quality = 2
  579. elif level >= 3:
  580. quality = 1
  581. else:
  582. quality = 0
  583. if original_quality > quality:
  584. quality = original_quality
  585. # TODO: Calculate
  586. #efficiency = rune["efficiency"]
  587. #max_efficiency = rune["max_efficiency"]
  588. efficiency = 0
  589. max_efficiency = 0
  590. main_stat = rune["pri_eff"][0]
  591. main_stat_value = rune["pri_eff"][1]
  592. if rune["prefix_eff"][0] > 0:
  593. innate_stat = rune["prefix_eff"][0]
  594. innate_stat_value = rune["prefix_eff"][1]
  595. else:
  596. innate_stat = None
  597. innate_stat_value = 0
  598. if len(rune["sec_eff"]) > 0:
  599. substat_1 = rune["sec_eff"][0][0]
  600. substat_1_value = rune["sec_eff"][0][1]
  601. substat_1_enchant = rune["sec_eff"][0][2]
  602. substat_1_grind = rune["sec_eff"][0][3]
  603. else:
  604. substat_1 = None
  605. substat_1_value = 0
  606. substat_1_enchant = 0
  607. substat_1_grind = 0
  608. if len(rune["sec_eff"]) > 1:
  609. substat_2 = rune["sec_eff"][1][0]
  610. substat_2_value = rune["sec_eff"][1][1]
  611. substat_2_enchant = rune["sec_eff"][1][2]
  612. substat_2_grind = rune["sec_eff"][1][3]
  613. else:
  614. substat_2 = None
  615. substat_2_value = 0
  616. substat_2_enchant = 0
  617. substat_2_grind = 0
  618. if len(rune["sec_eff"]) > 2:
  619. substat_3 = rune["sec_eff"][2][0]
  620. substat_3_value = rune["sec_eff"][2][1]
  621. substat_3_enchant = rune["sec_eff"][2][2]
  622. substat_3_grind = rune["sec_eff"][2][3]
  623. else:
  624. substat_3 = None
  625. substat_3_value = 0
  626. substat_3_enchant = 0
  627. substat_3_grind = 0
  628. if len(rune["sec_eff"]) > 3:
  629. substat_4 = rune["sec_eff"][0][0]
  630. substat_4_value = rune["sec_eff"][3][1]
  631. substat_4_enchant = rune["sec_eff"][3][2]
  632. substat_4_grind = rune["sec_eff"][3][3]
  633. else:
  634. substat_4 = None
  635. substat_4_value = 0
  636. substat_4_enchant = 0
  637. substat_4_grind = 0
  638. # Calculate efficiences
  639. efficiency = 0
  640. substats = []
  641. efficiency += float(MAIN_STAT_VALUES[main_stat][stars][15]) / float(MAIN_STAT_VALUES[main_stat][6][15])
  642. if innate_stat is not None:
  643. efficiency += innate_stat_value / float(SUBSTAT_INCREMENTS[innate_stat][6] * 5)
  644. if substat_1 is not None:
  645. substats.append(substat_1)
  646. efficiency += substat_1_value / float(SUBSTAT_INCREMENTS[substat_1][6] * 5)
  647. if substat_2 is not None:
  648. substats.append(substat_2)
  649. efficiency += substat_2_value / float(SUBSTAT_INCREMENTS[substat_2][6] * 5)
  650. if substat_3 is not None:
  651. substats.append(substat_3)
  652. efficiency += substat_3_value / float(SUBSTAT_INCREMENTS[substat_3][6] * 5)
  653. if substat_4 is not None:
  654. substats.append(substat_4)
  655. efficiency += substat_4_value / float(SUBSTAT_INCREMENTS[substat_4][6] * 5)
  656. efficiency = efficiency / 2.8 * 100
  657. max_efficiency = get_max_efficiency(substats, efficiency, level, stars, original_quality)
  658. if efficiency > 100:
  659. efficiency = 100;
  660. if max_efficiency > 100:
  661. max_efficiency = 100;
  662. insert(db, "rune", (uid, id, assigned_to, runeset, slot, stars, ancient, level, quality, original_quality, value, efficiency, max_efficiency, main_stat, main_stat_value, innate_stat, innate_stat_value, substat_1, substat_1_value, substat_1_enchant, substat_1_grind, substat_2, substat_2_value, substat_2_enchant, substat_2_grind, substat_3, substat_3_value, substat_3_enchant, substat_3_grind, substat_4, substat_4_value, substat_4_enchant, substat_4_grind))
  663. # Equipped runes
  664. for mon in data["unit_list"]:
  665. for rune in mon["runes"]:
  666. id = rune["rune_id"]
  667. assigned_to = rune["occupied_id"]
  668. if assigned_to == 0:
  669. assigned_to = None
  670. runeset = rune["set_id"]
  671. slot = rune["slot_no"]
  672. stars = rune["class"]
  673. ancient = 0
  674. level = rune["upgrade_curr"]
  675. original_quality = rune["extra"]
  676. value = rune["sell_value"]
  677. if stars > 10:
  678. ancient = 1
  679. stars = stars - 10
  680. original_quality = original_quality - 10
  681. if level >= 12:
  682. quality = 4
  683. elif level >= 9:
  684. quality = 3
  685. elif level >= 6:
  686. quality = 2
  687. elif level >= 3:
  688. quality = 1
  689. else:
  690. quality = 0
  691. if original_quality > quality:
  692. quality = original_quality
  693. # TODO: Calculate
  694. #efficiency = rune["efficiency"]
  695. #max_efficiency = rune["max_efficiency"]
  696. efficiency = 0
  697. max_efficiency = 0
  698. main_stat = rune["pri_eff"][0]
  699. main_stat_value = rune["pri_eff"][1]
  700. if rune["prefix_eff"][0] > 0:
  701. innate_stat = rune["prefix_eff"][0]
  702. innate_stat_value = rune["prefix_eff"][1]
  703. else:
  704. innate_stat = None
  705. innate_stat_value = 0
  706. if len(rune["sec_eff"]) > 0:
  707. substat_1 = rune["sec_eff"][0][0]
  708. substat_1_value = rune["sec_eff"][0][1]
  709. substat_1_enchant = rune["sec_eff"][0][2]
  710. substat_1_grind = rune["sec_eff"][0][3]
  711. else:
  712. substat_1 = None
  713. substat_1_value = 0
  714. substat_1_enchant = 0
  715. substat_1_grind = 0
  716. if len(rune["sec_eff"]) > 1:
  717. substat_2 = rune["sec_eff"][1][0]
  718. substat_2_value = rune["sec_eff"][1][1]
  719. substat_2_enchant = rune["sec_eff"][1][2]
  720. substat_2_grind = rune["sec_eff"][1][3]
  721. else:
  722. substat_2 = None
  723. substat_2_value = 0
  724. substat_2_enchant = 0
  725. substat_2_grind = 0
  726. if len(rune["sec_eff"]) > 2:
  727. substat_3 = rune["sec_eff"][2][0]
  728. substat_3_value = rune["sec_eff"][2][1]
  729. substat_3_enchant = rune["sec_eff"][2][2]
  730. substat_3_grind = rune["sec_eff"][2][3]
  731. else:
  732. substat_3 = None
  733. substat_3_value = 0
  734. substat_3_enchant = 0
  735. substat_3_grind = 0
  736. if len(rune["sec_eff"]) > 3:
  737. substat_4 = rune["sec_eff"][3][0]
  738. substat_4_value = rune["sec_eff"][3][1]
  739. substat_4_enchant = rune["sec_eff"][3][2]
  740. substat_4_grind = rune["sec_eff"][3][3]
  741. else:
  742. substat_4 = None
  743. substat_4_value = 0
  744. substat_4_enchant = 0
  745. substat_4_grind = 0
  746. # Calculate efficiences
  747. efficiency = 0
  748. substats = []
  749. efficiency += float(MAIN_STAT_VALUES[main_stat][stars][15]) / float(MAIN_STAT_VALUES[main_stat][6][15])
  750. if innate_stat is not None:
  751. efficiency += innate_stat_value / float(SUBSTAT_INCREMENTS[innate_stat][6] * 5)
  752. if substat_1 is not None:
  753. substats.append(substat_1)
  754. efficiency += substat_1_value / float(SUBSTAT_INCREMENTS[substat_1][6] * 5)
  755. if substat_2 is not None:
  756. substats.append(substat_2)
  757. efficiency += substat_2_value / float(SUBSTAT_INCREMENTS[substat_2][6] * 5)
  758. if substat_3 is not None:
  759. substats.append(substat_3)
  760. efficiency += substat_3_value / float(SUBSTAT_INCREMENTS[substat_3][6] * 5)
  761. if substat_4 is not None:
  762. substats.append(substat_4)
  763. efficiency += substat_4_value / float(SUBSTAT_INCREMENTS[substat_4][6] * 5)
  764. efficiency = efficiency / 2.8 * 100
  765. max_efficiency = get_max_efficiency(substats, efficiency, level, stars, original_quality)
  766. if efficiency > 100:
  767. efficiency = 100;
  768. if max_efficiency > 100:
  769. max_efficiency = 100;
  770. insert(db, "rune", (uid, id, assigned_to, runeset, slot, stars, ancient, level, quality, original_quality, value, efficiency, max_efficiency, main_stat, main_stat_value, innate_stat, innate_stat_value, substat_1, substat_1_value, substat_1_enchant, substat_1_grind, substat_2, substat_2_value, substat_2_enchant, substat_2_grind, substat_3, substat_3_value, substat_3_enchant, substat_3_grind, substat_4, substat_4_value, substat_4_enchant, substat_4_grind))
  771. db.commit()
  772. """
  773. calculates the max efficiency of a rune.
  774. :param substats: Array of substat types, dont include empty ones.
  775. :param efficiency: Current rune efficiency.
  776. :param level: Current rune level.
  777. :param stars: Rune stars.
  778. :param quality: Rune original quality.
  779. :return Max. efficiency.
  780. """
  781. def get_max_efficiency(substats, efficiency, level, stars, quality):
  782. STAT_HP = 1
  783. STAT_HP_PCT = 2
  784. STAT_ATK = 3
  785. STAT_ATK_PCT = 4
  786. STAT_DEF = 5
  787. STAT_DEF_PCT = 6
  788. STAT_SPD = 8
  789. STAT_CRIT_RATE_PCT = 9
  790. STAT_CRIT_DMG_PCT = 10
  791. STAT_RESIST_PCT = 11
  792. STAT_ACCURACY_PCT = 12
  793. SUBSTAT_INCREMENTS = {
  794. # [stat][stars]: value
  795. STAT_HP: {
  796. 1: 60,
  797. 2: 105,
  798. 3: 165,
  799. 4: 225,
  800. 5: 300,
  801. 6: 375,
  802. },
  803. STAT_HP_PCT: {
  804. 1: 2,
  805. 2: 3,
  806. 3: 5,
  807. 4: 6,
  808. 5: 7,
  809. 6: 8,
  810. },
  811. STAT_ATK: {
  812. 1: 4,
  813. 2: 5,
  814. 3: 8,
  815. 4: 10,
  816. 5: 15,
  817. 6: 20,
  818. },
  819. STAT_ATK_PCT: {
  820. 1: 2,
  821. 2: 3,
  822. 3: 5,
  823. 4: 6,
  824. 5: 7,
  825. 6: 8,
  826. },
  827. STAT_DEF: {
  828. 1: 4,
  829. 2: 5,
  830. 3: 8,
  831. 4: 10,
  832. 5: 15,
  833. 6: 20,
  834. },
  835. STAT_DEF_PCT: {
  836. 1: 2,
  837. 2: 3,
  838. 3: 5,
  839. 4: 6,
  840. 5: 7,
  841. 6: 8,
  842. },
  843. STAT_SPD: {
  844. 1: 1,
  845. 2: 2,
  846. 3: 3,
  847. 4: 4,
  848. 5: 5,
  849. 6: 6,
  850. },
  851. STAT_CRIT_RATE_PCT: {
  852. 1: 1,
  853. 2: 2,
  854. 3: 3,
  855. 4: 4,
  856. 5: 5,
  857. 6: 6,
  858. },
  859. STAT_CRIT_DMG_PCT: {
  860. 1: 2,
  861. 2: 3,
  862. 3: 4,
  863. 4: 5,
  864. 5: 6,
  865. 6: 7,
  866. },
  867. STAT_RESIST_PCT: {
  868. 1: 2,
  869. 2: 3,
  870. 3: 5,
  871. 4: 6,
  872. 5: 7,
  873. 6: 8,
  874. },
  875. STAT_ACCURACY_PCT: {
  876. 1: 2,
  877. 2: 3,
  878. 3: 5,
  879. 4: 6,
  880. 5: 7,
  881. 6: 8,
  882. },
  883. }
  884. UPGRADE_VALUES = {
  885. rune_type: {
  886. stars: value/level_data[6]
  887. for stars, value in level_data.items()
  888. }
  889. for rune_type, level_data in SUBSTAT_INCREMENTS.items()
  890. }
  891. #substat_upgrades_remaining = (4 - math.floor((min(level, 12) / 3))) - (3 - quality)
  892. substat_upgrades_remaining = (4 - math.floor((min(level, 12) / 3))) - max((3 - quality), 0)
  893. new_stats = max(min(4 - len(substats), substat_upgrades_remaining), 0)
  894. old_stats = substat_upgrades_remaining - new_stats
  895. #if id == 16042097882:
  896. # print("substat_upgrades_remaining: " + str(substat_upgrades_remaining))
  897. # print("quality: " + str(quality))
  898. # print("level: " + str(level))
  899. # print("math.floor((min(level, 12) / 3)): " + str(math.floor((min(level, 12) / 3))))
  900. # print("old_stats: " + str(old_stats))
  901. # print("new_stats: " + str(new_stats))
  902. if old_stats > 0:
  903. # we can repeatedly upgrade the most value of the existing stats
  904. best_stat = max(
  905. 0, # ensure max() doesn't error if we only have one stat
  906. *[UPGRADE_VALUES[stat][stars] for stat in substats]
  907. )
  908. efficiency += best_stat * old_stats * 0.2 / 2.8 * 100
  909. if new_stats:
  910. # add the top N stats
  911. available_upgrades = sorted(
  912. [
  913. upgrade_value[stars]
  914. for stat, upgrade_value in UPGRADE_VALUES.items()
  915. if stat not in substats
  916. ],
  917. reverse=True
  918. )
  919. efficiency += sum(available_upgrades[:new_stats]) * 0.2 / 2.8 * 100
  920. return efficiency
  921. """
  922. Parses rune craft item data (table rune_craft).
  923. :param db: Sqlite database connection.
  924. :param data: Data in json format.
  925. """
  926. def parseRuneCraft(db, data):
  927. print("Parsing rune craft itmes...")
  928. uid = data["wizard_info"]["wizard_id"]
  929. for item in data["rune_craft_item_list"]:
  930. id = item["craft_item_id"]
  931. type = item["craft_type"]
  932. value = item["sell_value"]
  933. info = str(item["craft_type_id"])
  934. """
  935. info : 5 or 6 digit number: RRSSQ
  936. RR: Rune
  937. SS: Stat
  938. Q: Quality
  939. """
  940. quality = int(info[-1:])
  941. stat = int(info[-4:-2])
  942. rune = int(info[:-4])
  943. insert(db, "rune_craft", (uid, id, type, quality, rune, stat, value))
  944. """
  945. Parses guild data (tables guild, guild_member).
  946. :param db: Sqlite database connection.
  947. :param data: Data in json format.
  948. """
  949. def parseGuild(db, data):
  950. print("Parsing guild...")
  951. if len(data["guild"]["guild_info"]) < 1:
  952. return
  953. guild = data["guild"]["guild_info"]
  954. id = guild["guild_id"]
  955. name = guild["name"]
  956. level = guild["level"]
  957. experience = guild["experience"]
  958. recruiting = guild["recruit_status"]
  959. members = guild["member_now"]
  960. leader = guild["master_wizard_id"]
  961. comment = guild["comment"]
  962. notice = guild["notice"]
  963. insert(db, "guild", (id, name, level, experience, recruiting, members, leader, comment, notice))
  964. # Single quates ahead, dirty fix
  965. for k, member in data["guild"]["guild_members"].items():
  966. m = json.loads(str(member).replace("'", '"'))
  967. id = m["wizard_id"]
  968. guild = member["guild_id"]
  969. grade = member["grade"]
  970. name = member["wizard_name"]
  971. level = member["wizard_level"]
  972. rating = member["rating_id"]
  973. arena_score = member["arena_score"]
  974. joined = member["join_timestamp"]
  975. last_login = member["last_login_timestamp"]
  976. in_war = 0 # Checked later
  977. has_defense = 0 # Checked later
  978. insert(db, "guild_member", (id, guild, grade, name, level, rating, arena_score, joined, last_login, in_war, has_defense))
  979. cursor = db.cursor()
  980. for war in data["guildwar_member_list"]:
  981. cursor.execute("UPDATE guild_member SET in_war = 1 WHERE guild = ? AND id = ?;", (war["guild_id"], war["wizard_id"]))
  982. for defense in data["guild_member_defense_list"]:
  983. if len(defense["unit_list"]) > 0:
  984. cursor.execute("UPDATE guild_member SET has_defense = 1 WHERE id = '" + str(defense["wizard_id"]) + "';")
  985. db.commit()
  986. cursor.close()
  987. """
  988. Deletes teams whose members no longer exists.
  989. :param db: Sqlite database connection.
  990. """
  991. def reconfigureTeams(db):
  992. print("Fixing teams...")
  993. uid = data["wizard_info"]["wizard_id"]
  994. cursor = db.cursor()
  995. cursor.execute("DELETE FROM team WHERE id IN (SELECT DISTINCT team FROM team_unit WHERE unit NOT IN (SELECT DISTINCT id FROM unit WHERE uid = " + str(uid) + ")) AND uid = " + str(uid) + ";")
  996. cursor.execute("DELETE FROM team_unit WHERE unit NOT IN (SELECT DISTINCT id FROM unit) OR team NOT IN (SELECT DISTINCT id FROM team);")
  997. db.commit()
  998. cursor.close()
  999. """
  1000. Begin script
  1001. """
  1002. data = readData()
  1003. key = readKey()
  1004. db = openDatabase(os.path.dirname(os.path.realpath(sys.argv[0])) + '/../sw.sqlite')
  1005. if verifyKey(db, data, key) == False:
  1006. print("Invalid API KEY...")
  1007. sys.exit(-1)
  1008. else:
  1009. parsePlayer(db, data)
  1010. parseScenarios(db, data)
  1011. parseDefense(db, data)
  1012. parseBuildings(db, data)
  1013. parseDecorations(db, data)
  1014. # TODO homunculus_skill_list
  1015. parseUnits(db, data)
  1016. parseSummonSpecial(db, data)
  1017. parseInventory(db, data)
  1018. parseRunes(db, data)
  1019. parseRuneCraft(db, data)
  1020. parseGuild(db, data)
  1021. reconfigureTeams(db)
  1022. closeDatabase(db)
  1023. sys.exit(0);