system.lua 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. MAX_INVENTORY_SLOTS = 320
  2. MAX_KEY_SLOTS = 50
  3. MAX_MATERIA_SLOTS = 200
  4. --- Export character names to the text manager.
  5. --
  6. -- Used to compose dialog with character names. Must be called on start and when a character is
  7. -- renamed.
  8. export_character_names = function()
  9. for c = 0, 8 do
  10. if Characters[c] ~= nil then
  11. text_manager:set_character_name(c, Characters[c].name)
  12. end
  13. end
  14. end
  15. --- Export party members to the text manager.
  16. --
  17. -- Used to compose dialog with party character names. Must be called when the party formation is
  18. -- changed in any way.
  19. export_party_members = function()
  20. if Party[1] == nil then
  21. c1 = -1
  22. else
  23. c1 = Party[1]
  24. end
  25. if Party[2] == nil then
  26. c2 = -1
  27. else
  28. c2 = Party[2]
  29. end
  30. if Party[3] == nil then
  31. c3 = -1
  32. else
  33. c3 = Party[3]
  34. end
  35. text_manager:set_party(c1, c2, c3)
  36. end
  37. --- Sets the current party.
  38. --
  39. -- @param character1 The first member character ID, the party leader.
  40. -- @param character2 The second member character ID, can be nil.
  41. -- @param character3 The third member character ID, can be nil.
  42. set_party = function(character1, character2, character3)
  43. Party[1] = character1
  44. Party[2] = character2
  45. Party[3] = character3
  46. Party[1] = character1
  47. Party[2] = character2
  48. Party[3] = character3
  49. export_party_members()
  50. end
  51. --- Checks if a a character ID actually belongs to a character.
  52. --
  53. -- @param character The ID to check.
  54. -- @return True if the ID is a valid character ID, false otherwise.
  55. is_character = function(character)
  56. if Characters[character] == nil then
  57. return false
  58. end
  59. return true
  60. end
  61. --- Adds a character to the curent party.
  62. --
  63. -- @param character ID of the character to add.
  64. add_party_character = function(character)
  65. if Characters[character] == nil then
  66. print("Tried add to party invalid character \"" .. character .. "\".");
  67. return
  68. end
  69. if Characters[character].party_lock == true then
  70. print("Tried add to party locked character \"" .. character .. "\".");
  71. return
  72. end
  73. -- Check if character already in party
  74. for x = 1, 3 do
  75. if Party[i] == character then
  76. print("Character \"" .. character .. "\" already in party.");
  77. return
  78. end
  79. end
  80. -- Try to add in first free slot.
  81. for x = 1, 3 do
  82. if Party[i] == nil then
  83. Party[i] = character
  84. export_party_members()
  85. return
  86. end
  87. end
  88. end
  89. --- Removes a character from the curent party.
  90. --
  91. -- @param character ID of the character to remove.
  92. remove_party_character = function(character)
  93. if Characters[character] == nil then
  94. print("Tried remove from party invalid character \"" .. character .. "\".");
  95. return
  96. end
  97. if Characters[character].party_lock == true then
  98. print("Tried remove from party locked character \"" .. character .. "\".");
  99. return
  100. end
  101. for x = 1, 3 do
  102. if Party[i] == character then
  103. Party[i] = nil
  104. export_party_members()
  105. return
  106. end
  107. end
  108. end
  109. --- Locks a character in the party.
  110. --
  111. -- Locked characters can't be manually swapped in or out of the party.
  112. --
  113. -- @param character ID of the character to lock.
  114. set_party_lock = function(character, lock)
  115. if Characters[character] == nil then
  116. print("Tried set/unset party lock to invalid character \"" .. character .. "\".");
  117. return
  118. end
  119. Characters[character].party_lock = lock;
  120. end
  121. --- Checks if a character is locked in the party.
  122. --
  123. -- Locked characters can't be manually swapped in or out of the party.
  124. --
  125. -- @param character ID of the character to check for locks.
  126. get_party_lock = function(character)
  127. if Characters[character] == nil then
  128. print("Tried get party lock from invalid character \"" .. character .. "\".");
  129. return false
  130. end
  131. return Characters[character].party_lock
  132. end
  133. --- Enables or disables a character is the PHS.
  134. --
  135. -- Disabled characters don't appear in the PHS.
  136. --
  137. -- @param character ID of the character to enable or disable.
  138. -- @param enable True to enable, false to disable.
  139. set_character_enable = function(character, enable)
  140. if Characters[character] == nil then
  141. print("Tried enable/disable invalid character \"" .. character .. "\".");
  142. return
  143. end
  144. Characters[character].enable = enable;
  145. end
  146. --- Checks if a character is enabled in the PHS.
  147. --
  148. -- Disabled characters don't appear in the PHS.
  149. --
  150. -- @param character ID of the character to check.
  151. -- @return True if enabled, false if disables.
  152. get_character_enable = function(character)
  153. if Characters[character] == nil then
  154. print("Tried get enabled from invalid character \"" .. character .. "\".");
  155. return false
  156. end
  157. return Characters[character].enable;
  158. end
  159. --- Adds items to the inventory.
  160. --
  161. -- Inventory quantities will be capped at 99.
  162. --
  163. -- @param item Item ID.
  164. -- @param quantity Quantity to add.
  165. Inventory.add_item = function(item, quantity)
  166. -- TODO: Also check weapons, armors and accessories.
  167. if Game.Items[item] == nil then
  168. print("Tried add invalid item \"" .. item .. "\".");
  169. return
  170. end
  171. for i = 1, MAX_INVENTORY_SLOTS do
  172. if Inventory[i] ~= nil and Inventory[i].item == item then
  173. -- Item already in inventory, add quantity
  174. Inventory[i].quantity = Inventory[i].quantity + quantity
  175. if Inventory[i].quantity > 99 then
  176. Inventory[i].quantity = 99
  177. end
  178. return
  179. end
  180. end
  181. -- Item not in inventory, search for the first available position.
  182. for i = 1, MAX_INVENTORY_SLOTS do
  183. if Inventory[i] == nil then
  184. Inventory[i] = {item = item, quantity = quantity}
  185. if Inventory[i].quantity > 99 then
  186. Inventory[i].quantity = 99
  187. end
  188. return
  189. end
  190. end
  191. -- If reached this point, it means that the item is not in inventory, and all slots are full.
  192. -- TODO: The orignal game does nothing, but in here?
  193. return
  194. end
  195. --- Checks how many items of a type are in the inventory.
  196. --
  197. -- @param item The item ID.
  198. -- @return Number of the items in the inventory.
  199. Inventory.get_item_quantity = function(item)
  200. local qty = 0
  201. for i = 1, MAX_INVENTORY_SLOTS do
  202. if Inventory[i] ~= nil and Inventory[i].item == item then
  203. qty = qty + Inventory[i].quantity
  204. end
  205. end
  206. return qty
  207. end
  208. --- Removes items from the inventory.
  209. --
  210. -- Negative quantities can't remain in the inventory. If there are less than requested to remove,
  211. -- all of them will be removed.
  212. --
  213. -- @param item Item ID.
  214. -- @param quantity Quantity to remove.
  215. Inventory.remove_item = function(item, quantity)
  216. for i = 1, MAX_INVENTORY_SLOTS do
  217. if Inventory[i] ~= nil and Inventory[i].item == item then
  218. -- Item already in inventory, add quantity
  219. Inventory[i].quantity = Inventory[i].quantity - quantity
  220. if Inventory[i].quantity <= 0 then
  221. Inventory[i] = nil
  222. end
  223. return
  224. end
  225. end
  226. end
  227. --- Adds a key item.
  228. --
  229. -- @param item ID of the key item (0-50).
  230. Inventory.add_key_item = function(item)
  231. Inventory.key[item] = true
  232. return
  233. end
  234. --- Removes a key item.
  235. --
  236. -- @param item ID of the key item (0-50).
  237. Inventory.remove_key_item = function(item)
  238. Inventory.key[item] = false
  239. return
  240. end
  241. --- Checks if the party has a key item.
  242. --
  243. -- @param item ID of the key item (0-50).
  244. -- @return True if the party has the key item, false otherwise.
  245. Inventory.has_key_item = function(item)
  246. return Inventory.key[item]
  247. end
  248. --- Adds money.
  249. --
  250. -- @param amount The money to add.
  251. Inventory.add_money = function(amount)
  252. Inventory.money = Inventory.money + amount
  253. if Inventory.money > 99999999 then
  254. Inventory.money = 99999999
  255. end
  256. end
  257. --- Removes money.
  258. --
  259. -- Negative quantities can't remain as money. If there are less than requested to remove, all of
  260. -- it will be removed.
  261. --
  262. -- @param amount Money to remove.
  263. Inventory.remove_money = function(amount)
  264. Inventory.money = Inventory.money - amount
  265. if Inventory.money < 0 then
  266. Inventory.money = 0
  267. end
  268. end
  269. --- Copies the amount of gil the party has into data banks
  270. --
  271. -- As the gil amount is a four-byte value, in the original game the arguments require two
  272. -- destination addresses to place two two-byte values into. Address 1 takes the lower two bytes of
  273. -- the gil amount, while address 2 takes the higher two bytes.
  274. --
  275. -- @param b1 First destination bank.
  276. -- @param b2 Second destination address.
  277. -- @param a1 First destination bank.
  278. -- @param a2 Second destination address.
  279. Inventory.money_to_2_banks = function(b1, b2, a1, a2)
  280. Banks[b1][a1] = math.floor(Inventory.money / 65535)
  281. Banks[b2][a2] = math.floor(Inventory.money % 65535) - math.floor(Inventory.money / 65535)
  282. end
  283. --- Sorts the items in the inventory.
  284. --
  285. -- @param criteria {@see Inventory.ORDER.CUSTOM} (unimplemented), {@see Inventory.ORDER.FIELD.},
  286. -- {@see Inventory.ORDER.BATTLE}, {@see Inventory.ORDER.THROW}, {@see Inventory.ORDER.TYPE},
  287. -- {@see Inventory.ORDER.NAME}, {@see Inventory.ORDER.MOST} or {@see Inventory.ORDER.LEAST}. Any
  288. -- othe rvalue and the items will not be sorted.
  289. Inventory.sort = function(criteria)
  290. if criteria == Inventory.ORDER.CUSTOM then
  291. print("Custom order unimplemented")
  292. elseif criteria == Inventory.ORDER.FIELD then
  293. table.sort(Inventory, function (left, right)
  294. if Game.Items[left.item].menu ~= Game.Items[right.item].menu then
  295. return Game.Items[left.item].menu > Game.Items[right.item].menu
  296. end
  297. return left.item < right.item
  298. end
  299. )
  300. elseif criteria == Inventory.ORDER.BATTLE then
  301. table.sort(Inventory, function (left, right)
  302. if Game.Items[left.item].battle ~= Game.Items[right.item].battle then
  303. return Game.Items[left.item].battle > Game.Items[right.item].battle
  304. end
  305. return left.item < right.item
  306. end
  307. )
  308. elseif criteria == Inventory.ORDER.THROW then
  309. table.sort(Inventory, function (left, right)
  310. if Game.Items[left.item].throw ~= Game.Items[right.item].throw then
  311. return Game.Items[left.item].throw > Game.Items[right.item].throw
  312. end
  313. return left.item < right.item
  314. end
  315. )
  316. elseif criteria == Inventory.ORDER.TYPE then
  317. table.sort(Inventory, function (left, right)
  318. return left.item < right.item
  319. end
  320. )
  321. elseif criteria == Inventory.ORDER.NAME then
  322. table.sort(Inventory, function (left, right)
  323. return Game.Items[left.item].name < Game.Items[right.item].name
  324. end
  325. )
  326. elseif criteria == Inventory.ORDER.MOST then
  327. table.sort(Inventory, function (left, right)
  328. if left.quantity ~= right.quantity then
  329. return left.quantity > right.quantity
  330. end
  331. return left.item < right.item
  332. end
  333. )
  334. elseif criteria == Inventory.ORDER.LEAST then
  335. table.sort(Inventory, function (left, right)
  336. if left.quantity ~= right.quantity then
  337. return left.quantity < right.quantity
  338. end
  339. return left.item < right.item
  340. end
  341. )
  342. end
  343. end
  344. Characters.recalculate_stats = function(id)
  345. -- Initialize
  346. local stats = Characters[id].stats
  347. stats.str.total = stats.str.base
  348. stats.vit.total = stats.vit.base
  349. stats.mag.total = stats.mag.base
  350. stats.spr.total = stats.spr.base
  351. stats.dex.total = stats.dex.base
  352. stats.lck.total = stats.lck.base
  353. stats.hp.max = stats.hp.base
  354. stats.mp.max = stats.mp.base
  355. -- Weapon bonus. HP and MP are percents of base, the rest absolutes.
  356. local weapon = Game.Items[Characters[id].weapon.id]
  357. for stat, value in ipairs(weapon.stats) do
  358. if stat == "str" then
  359. stats.str.total = stats.str.total + value
  360. elseif stat == "vit" then
  361. stats.vit.total = stats.vit.total + value
  362. elseif stat == "mag" then
  363. stats.mag.total = stats.mag.total + value
  364. elseif stat == "spr" then
  365. stats.spr.total = stats.spr.total + value
  366. elseif stat == "dex" then
  367. stats.dex.total = stats.dex.total + value
  368. elseif stat == "lck" then
  369. stats.lck.total = stats.lck.total + value
  370. elseif stat == "hp" then
  371. stats.hp.max = stats.hp.max + (value * stats.hp.max / 100)
  372. elseif stat == "mp" then
  373. stats.mp.max = stats.mp.max + (value * stats.mp.max / 100)
  374. end
  375. end
  376. -- Armor bonus. HP and MP are percents of bsae, the rest absolutes.
  377. local armor = Game.Items[Characters[id].armor.id]
  378. for stat, value in ipairs(armor.stats) do
  379. if stat == "str" then
  380. stats.str.total = stats.str.total + value
  381. elseif stat == "vit" then
  382. stats.vit.total = stats.vit.total + value
  383. elseif stat == "mag" then
  384. stats.mag.total = stats.mag.total + value
  385. elseif stat == "spr" then
  386. stats.spr.total = stats.spr.total + value
  387. elseif stat == "dex" then
  388. stats.dex.total = stats.dex.total + value
  389. elseif stat == "lck" then
  390. stats.lck.total = stats.lck.total + value
  391. elseif stat == "hp" then
  392. stats.hp.max = stats.hp.max + (value * stats.hp.max / 100)
  393. elseif stat == "mp" then
  394. stats.mp.max = stats.mp.max + (value * stats.mp.max / 100)
  395. end
  396. end
  397. -- Accesory bonus
  398. local accessory = Game.Items[Characters[id].accessory]
  399. if (accessory ~= nil) then
  400. for stat, value in ipairs(armor.stats) do
  401. if stat == "str" then
  402. stats.str.total = stats.str.total + value
  403. elseif stat == "vit" then
  404. stats.vit.total = stats.vit.total + value
  405. elseif stat == "mag" then
  406. stats.mag.total = stats.mag.total + value
  407. elseif stat == "spr" then
  408. stats.spr.total = stats.spr.total + value
  409. elseif stat == "dex" then
  410. stats.dex.total = stats.dex.total + value
  411. elseif stat == "lck" then
  412. stats.lck.total = stats.lck.total + value
  413. elseif stat == "hp" then
  414. stats.hp.max = stats.hp.max + (value * stats.hp.max / 100)
  415. elseif stat == "mp" then
  416. stats.mp.max = stats.mp.max + (value * stats.mp.max / 100)
  417. end
  418. end
  419. end
  420. -- Get a list of materias
  421. local materias = {}
  422. for m = 0, 7 do
  423. if Characters[id].weapon.materia[m] ~= nil then
  424. table.insert(materias, Game.Materia[Characters[id].weapon.materia[m].id])
  425. end
  426. if Characters[id].armor.materia[m] ~= nil then
  427. table.insert(materias, Game.Materia[Characters[id].weapon.materia[m].id])
  428. end
  429. end
  430. -- Get materia bonuses. All are percents of base.
  431. for _, materia in ipairs(materias) do
  432. for stat, value in ipairs(materia.stats) do
  433. if stat == "str" then
  434. stats.str.total = stats.str.total + (value * stats.str.base / 100)
  435. elseif stat == "vit" then
  436. stats.vit.total = stats.vit.total + (value * stats.vit.base / 100)
  437. elseif stat == "mag" then
  438. stats.mag.total = stats.mag.total + (value * stats.mag.base / 100)
  439. elseif stat == "spr" then
  440. stats.spr.total = stats.spr.total + (value * stats.spr.base / 100)
  441. elseif stat == "dex" then
  442. stats.dex.total = stats.dex.total + (value * stats.dex.base / 100)
  443. elseif stat == "lck" then
  444. stats.lck.total = stats.lck.total + (value * stats.lck.base / 100)
  445. elseif stat == "hp" then
  446. stats.hp.max = stats.hp.max + (value * stats.hp.max / 100)
  447. elseif stat == "mp" then
  448. stats.mp.max = stats.mp.max + (value * stats.mp.max / 100)
  449. end
  450. end
  451. end
  452. -- Round down all basic stats
  453. stats.str.total = math.floor(stats.str.total)
  454. stats.vit.total = math.floor(stats.vit.total)
  455. stats.mag.total = math.floor(stats.mag.total)
  456. stats.spr.total = math.floor(stats.spr.total)
  457. stats.dex.total = math.floor(stats.dex.total)
  458. stats.lck.total = math.floor(stats.lck.total)
  459. stats.hp.max = math.floor(stats.hp.max)
  460. stats.mp.max = math.floor(stats.mp.max)
  461. if stats.str.total < 1 then
  462. stats.str.total = 1
  463. end
  464. if stats.vit.total < 1 then
  465. stats.vit.total = 1
  466. end
  467. if stats.mag.total < 1 then
  468. stats.mag.total = 1
  469. end
  470. if stats.spr.total < 1 then
  471. stats.spr.total = 1
  472. end
  473. if stats.dex.total < 1 then
  474. stats.dex.total = 1
  475. end
  476. if stats.lck.total < 1 then
  477. stats.lck.total = 1
  478. end
  479. if stats.hp.max < 1 then
  480. stats.hp.max = 1
  481. end
  482. if stats.mp.max < 1 then
  483. stats.mp.max = 1
  484. end
  485. -- Calculate composed stats.
  486. stats.atk = stats.str.total + weapon.power
  487. stats.acc = weapon.accuracy
  488. stats.def = stats.vit.total + armor.defense.physical
  489. stats.eva = armor.evasion.physical
  490. stats.matk = stats.mag.total
  491. stats.mdef = stats.spr.total + armor.defense.magical
  492. stats.meva = armor.evasion.magical
  493. -- Cap composed stats. TODO: Max caps?
  494. if stats.atk < 1 then
  495. stats.atk = 1
  496. end
  497. if stats.acc < 1 then
  498. stats.acc = 1
  499. end
  500. if stats.def < 1 then
  501. stats.def = 1
  502. end
  503. if stats.eva < 1 then
  504. stats.eva = 1
  505. end
  506. if stats.matk < 1 then
  507. stats.matk = 1
  508. end
  509. if stats.mdef < 1 then
  510. stats.mdef = 1
  511. end
  512. if stats.meva < 1 then
  513. stats.meva = 1
  514. end
  515. -- TODO: If HP<->MP materia, invert values.
  516. -- Cap current HP/MP
  517. if stats.hp.current > stats.hp.max then
  518. stats.hp.current = stats.hp.max
  519. end
  520. if stats.mp.current > stats.mp.max then
  521. stats.mp.current = stats.mp.max
  522. end
  523. -- Assign
  524. Characters[id].stats = stats
  525. end
  526. --- Equips an item on a character.
  527. --
  528. -- Works for weapons, armors and accessories. If there is a previously equiped item, it
  529. -- will be unequiped and added to the inventory. The equiped item will be removed form the
  530. -- inventory. For armors and weapons, if the newly equiped item has less materia slots than
  531. -- the previuos one, remainig materia will be unequiped and added to the materia inventory.
  532. --
  533. -- @param char_id ID of the character to equip the item to.
  534. -- @param item_id ID of the item to equip.
  535. -- @return True if the item was equipped. False if the character or item don't exist, if
  536. -- the item is not in the inventory, or if the item is not equippable or not equippable by
  537. -- the selected character. In any of those cases, an error message will be printed.
  538. Characters.equip = function(char_id, item_id)
  539. -- Error checks
  540. if Characters[char_id] == nil then
  541. print("Tried to equip item on wrong character: " .. tostring(char_id))
  542. return false
  543. elseif Game.Items[item_id] == nil then
  544. print("Tried to equip invalid item: " .. tostring(character))
  545. return false
  546. elseif Inventory.get_item_quantity(item_id) < 1 then
  547. print("Tried to equip item not in inventory: " .. item_id .. " (" .. Game.Items[item.id].name .. ")")
  548. return false
  549. end
  550. local type = Game.Items[item_id].type
  551. if type ~= Inventory.ITEM_TYPE.WEAPON and type ~= Inventory.ITEM_TYPE.ARMOR and type ~= Inventory.ITEM_TYPE.ACCESSORY then
  552. print("Tried to equip non-equipable item: " .. item_id .. " (" .. Game.Items[item.id].name .. ")")
  553. return false
  554. end
  555. local equipable = false
  556. for _, u in ipairs(Game.Items[item_id].users) do
  557. if u == char_id then
  558. equipable = true
  559. break
  560. end
  561. end
  562. if equipable == false then
  563. print("Tried to equip item " .. tostring(item_id) .. " (" .. Game.Items[item.id].name .. ") on a non valid character: " .. tostring(char_id) .. " (" .. Characters[char_id].name .. ")")
  564. return false
  565. end
  566. -- All is good, equip.
  567. if type == Inventory.ITEM_TYPE.ACCESSORY then
  568. -- Equip accessory. If any was equipped, send it to the inventory.
  569. if Characters[char_id].accessory ~= nil then
  570. Inventory.add_item(Characters[char_id].accessory, 1)
  571. end
  572. Characters[char_id].accessory = item_id
  573. Inventory.remove_item(item_id, 1)
  574. elseif type == Inventory.ITEM_TYPE.WEAPON then
  575. -- Weapon. Remove excess materia, send previuos one to the inventory.
  576. for m = 0, 7 do
  577. if Characters[char_id].weapon.materia[i] ~= nil and #(Game.Items[item_id].slots) < m then
  578. -- Materia to inventory
  579. Materia.add(Characters[char_id].weapon.materia[i].id, Characters[char_id].weapon.materia[i].ap)
  580. Characters[char_id].weapon.materia[i] = nil
  581. end
  582. end
  583. Inventory.add_item(Characters[char_id].weapon.id, 1)
  584. Characters[char_id].weapon.id = item_id
  585. Inventory.remove_item(item_id, 1)
  586. elseif type == Inventory.ITEM_TYPE.ARMOR then
  587. -- Armor. Remove excess materia, send previuos one to the inventory.
  588. for m = 0, 7 do
  589. if Characters[char_id].armor.materia[i] ~= nil and #(Game.Items[item_id].slots) < m then
  590. -- Materia to inventory
  591. Materia.add(Characters[char_id].armor.materia[i].id, Characters[char_id].armor.materia[i].ap)
  592. Characters[char_id].armor.materia[i] = nil
  593. end
  594. end
  595. Inventory.add_item(Characters[char_id].armor.id, 1)
  596. Characters[char_id].armor.id = item_id
  597. Inventory.remove_item(item_id, 1)
  598. else
  599. return false
  600. end
  601. return true
  602. end
  603. --- Removes all materia from a character.
  604. --
  605. -- @param id ID of the character to remove materia from.
  606. Characters.remove_materia = function(id)
  607. -- TODO: Implement
  608. end
  609. --- Restores all materia to a character.
  610. --
  611. -- @param id ID of the character to restore materia to.
  612. Characters.restore_materia = function(id)
  613. -- TODO: Implement
  614. end
  615. Materia.add = function(id, ap)
  616. local ap = ap or 0
  617. if Game.Materia[id] == nil then
  618. print("Tried to add invalid materia \"" .. item .. "\".");
  619. return
  620. end
  621. -- TODO Cap AP?
  622. for i = 1, MAX_MATERIA_SLOTS do
  623. if Materia[i] == nil then
  624. Materia[i] = {id = id, ap = ap}
  625. if Materia[i].id == Materia.ENEMY_SKILL_ID then
  626. Materia[i].ap = 0
  627. Materia[i].skills = {}
  628. for s = 1, 24 do
  629. Materia[i].skills[s] = false
  630. end
  631. end
  632. return
  633. end
  634. end
  635. -- If reached this point, it means that the materia wasn't added because all slots are full.
  636. -- TODO: Do something.
  637. return
  638. end
  639. --- Splits the party in teams.
  640. --
  641. -- @param number Number of teams (only 2 or 3).
  642. Party.split_teams = function(number)
  643. if number < 2 then
  644. number = 2
  645. elseif number > 3 then
  646. number = 3
  647. end
  648. -- TODO: Implement.
  649. end
  650. --- Displays a menu to choose a party of three.
  651. Party.choose_party = function()
  652. -- TODO: Implement
  653. end
  654. --- Special event. Removes all materia from the party, equipped and unequipped.
  655. Party.steal_materia = function()
  656. -- TODO: Implement.
  657. -- TODO: How is this reversed?
  658. end