Rune.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. <?php
  2. /**
  3. * Rune entity file.
  4. *
  5. * Creates the entity and makes it available.
  6. *
  7. * @author Iñigo Valentin <i@inigovalentin.com>
  8. * @license https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License V3
  9. * @package SWDB
  10. */
  11. require_once(PATH::ENTITY . "Entity.php");
  12. require_once(PATH::ENTITY . "Rune_Set.php");
  13. require_once(PATH::ENTITY . "Rune_Stat.php");
  14. /**
  15. * Owned rune.
  16. *
  17. * Represents a rune.
  18. *
  19. * @category Entity
  20. */
  21. class Rune extends Entity{
  22. /**
  23. * @var int Owner identifier.
  24. */
  25. private $player;
  26. /**
  27. * @var int Rune identifier.
  28. */
  29. private $id;
  30. /**
  31. * @var Rune_Set Rune set.
  32. */
  33. private $type;
  34. /**
  35. * @var int Position of the rune type (1-6).
  36. */
  37. private $slot;
  38. /**
  39. * @var int Rune stars.
  40. */
  41. private $stars;
  42. /**
  43. * @var bool Indicates if the rune is ancient.
  44. */
  45. private $ancient;
  46. /**
  47. * @var int Level of the rune.
  48. */
  49. private $level;
  50. /**
  51. * @var int Rune quality.
  52. * @see QUALITY_ID
  53. */
  54. private $quality;
  55. /**
  56. * @var int Rune original quality.
  57. * @see QUALITY_ID
  58. */
  59. private $original_quality;
  60. /**
  61. * @var string Rune quality name (uppercase).
  62. */
  63. private $quality_name;
  64. /**
  65. * @var string Rune original quality name (uppercase).
  66. */
  67. private $original_quality_name;
  68. /**
  69. * @var int Price of the rune.
  70. */
  71. private $value;
  72. /**
  73. * @var float Current efficiency of the rune.
  74. */
  75. private $efficiency;
  76. /**
  77. * @var float Maximum potential efficiency of the rune.
  78. */
  79. private $max_efficiency;
  80. /**
  81. * @var int Indicates if the rune is locked.
  82. */
  83. private $locked;
  84. /**
  85. * @var bool Internal flag to check if the rune stats have been loaded into the entity.
  86. */
  87. private $flag_stats = false;
  88. /**
  89. * @var Rune_Stat Main stat of the rune.
  90. */
  91. private $main_stat;
  92. /**
  93. * @var Rune_Stat Extra stat of the rune.
  94. */
  95. private $innate_stat;
  96. /**
  97. * @var Rune_Stat[] Substats of the rune.
  98. */
  99. private $substats = [];
  100. /**
  101. * @var Rune_Stat[] All stats.
  102. *
  103. * Includes main, innate and substats
  104. */
  105. private $stats = [];
  106. /**
  107. * @var bool Internal flag to check if the unit who equips the rune has been loaded.
  108. */
  109. private $flag_unit = false;
  110. /**
  111. * @var Unit Unit the rune is assigned to.
  112. */
  113. private $unit;
  114. /**
  115. * Constructor.
  116. *
  117. * Searches the database and retrieves the information about the
  118. * rune, populating it and it's items.
  119. *
  120. * @param int $id Rune id.
  121. */
  122. public function __construct($id){
  123. $statement = get_context()->get_db()->prepare("
  124. SELECT
  125. id,
  126. type,
  127. slot,
  128. stars,
  129. level,
  130. ancient,
  131. quality,
  132. original_quality,
  133. value,
  134. efficiency,
  135. max_efficiency,
  136. locked
  137. FROM rune
  138. WHERE id = :id;
  139. ");
  140. $statement->bindValue(':id', $id, SQLITE3_TEXT);
  141. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  142. if ($r){
  143. $this->id = $r["id"];
  144. $this->type = new Rune_Set($r["type"]);
  145. $this->slot = $r["slot"];
  146. $this->stars = $r["stars"];
  147. $this->level = $r["level"];
  148. $this->ancient = $r["ancient"];
  149. $this->quality = $r["quality"];
  150. $this->original_quality = $r["original_quality"];
  151. $this->value = $r["value"];
  152. $this->efficiency = $r["efficiency"];
  153. $this->max_efficiency = $r["max_efficiency"];
  154. $this->locked = filter_var($r["locked"], FILTER_VALIDATE_BOOLEAN);
  155. $this->quality_name = $this->map_quality_name($this->quality);
  156. $this->original_quality_name = $this->map_quality_name($this->original_quality);
  157. // Read efficiencies. If not set in DB, calculate and update.
  158. if ($this->efficiency == null || $this->efficiency == "" || intval($this->efficiency) == 0){
  159. $this->efficiency = $this->calculate_efficiency();
  160. $this->max_efficiency = $this->calculate_maximum_efficiency();
  161. $statement = get_context()->get_db()->prepare("
  162. UPDATE rune
  163. SET
  164. efficiency = :efficiency,
  165. max_efficiency = :max_efficiency
  166. WHERE id = :rune
  167. ");
  168. $statement->bindValue(':efficiency', $this->efficiency, SQLITE3_FLOAT);
  169. $statement->bindValue(':max_efficiency', $this->max_efficiency, SQLITE3_FLOAT);
  170. $statement->bindValue(':rune', $this->id, SQLITE3_INTEGER);
  171. $statement->execute();
  172. }
  173. }
  174. else{
  175. // Not found, maybe reading from a drop?
  176. $this->read_drop($id);
  177. }
  178. }
  179. private function read_drop($id){
  180. $statement = get_context()->get_db()->prepare("
  181. SELECT
  182. id,
  183. type,
  184. slot,
  185. stars,
  186. ancient,
  187. quality,
  188. value,
  189. efficiency,
  190. max_efficiency,
  191. main_stat,
  192. innate_stat,
  193. substat_1,
  194. substat_2,
  195. substat_3,
  196. substat_4
  197. FROM run_drop_rune
  198. WHERE id = :id;
  199. ");
  200. $statement->bindValue(':id', $id, SQLITE3_TEXT);
  201. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  202. if ($r){
  203. $this->id = $r["id"];
  204. $this->type = new Rune_Set($r["type"]);
  205. $this->slot = $r["slot"];
  206. $this->stars = $r["stars"];
  207. $this->level = 0;
  208. $this->ancient = $r["ancient"];
  209. $this->quality = $r["quality"];
  210. $this->original_quality = $r["quality"];
  211. $this->value = $r["value"];
  212. $this->efficiency = $r["efficiency"];
  213. $this->max_efficiency = $r["max_efficiency"];
  214. $this->locked = false;
  215. $this->quality_name = $this->map_quality_name($this->quality);
  216. $this->original_quality_name = $this->map_quality_name($this->quality);
  217. $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::MAIN);
  218. $this->main_stat = $stat;
  219. array_push($this->stats, $stat);
  220. if (is_int($r["innate_stat"])){
  221. $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::INNATE);
  222. $this->innate_stat = $stat;
  223. array_push($this->stats, $stat);
  224. }
  225. if (is_int($r["substat_1"])){
  226. $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_1);
  227. array_push($this->substats, $stat);
  228. array_push($this->stats, $stat);
  229. }
  230. if (is_int($r["substat_2"])){
  231. $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_2);
  232. array_push($this->substats, $stat);
  233. array_push($this->stats, $stat);
  234. }
  235. if (is_int($r["substat_3"])){
  236. $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_3);
  237. array_push($this->substats, $stat);
  238. array_push($this->stats, $stat);
  239. }
  240. if (is_int($r["substat_4"])){
  241. $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_4);
  242. array_push($this->substats, $stat);
  243. array_push($this->stats, $stat);
  244. }
  245. $this->flag_stats = true;
  246. // Read efficiencies. If not set in DB, calculate and update.
  247. if ($this->efficiency == null || $this->efficiency == "" || intval($this->efficiency) == 0){
  248. $this->efficiency = $this->calculate_efficiency();
  249. $this->max_efficiency = $this->calculate_maximum_efficiency();
  250. $statement = get_context()->get_db()->prepare("
  251. UPDATE run_drop_rune
  252. SET
  253. efficiency = :efficiency,
  254. max_efficiency = :max_efficiency
  255. WHERE id = :rune
  256. ");
  257. $statement->bindValue(':efficiency', $this->efficiency, SQLITE3_FLOAT);
  258. $statement->bindValue(':max_efficiency', $this->max_efficiency, SQLITE3_FLOAT);
  259. $statement->bindValue(':rune', $this->id, SQLITE3_INTEGER);
  260. $statement->execute();
  261. }
  262. }
  263. }
  264. /**
  265. * Loads the stats.
  266. *
  267. * Must be called only once before trying to get any of the stats (main, innate or subs) or
  268. * efficiencies. Sets the flag {@link Rune:$flag_stats} to true.
  269. */
  270. private function load_stats(){
  271. $statement = get_context()->get_db()->prepare("
  272. SELECT slot
  273. FROM rune_stat
  274. WHERE rune = :rune
  275. ORDER BY slot;
  276. ");
  277. $statement->bindValue(':rune', $this->id, SQLITE3_TEXT);
  278. $q = $statement->execute();
  279. while ($r = $q->fetchArray(SQLITE3_ASSOC)){
  280. $stat = new Rune_Stat($this->id, $r["slot"]);
  281. array_push($this->stats, $stat);
  282. switch ($r["slot"]){
  283. case RUNE_STAT_SLOT_ID::MAIN:
  284. $this->main_stat = $stat;
  285. break;
  286. case RUNE_STAT_SLOT_ID::INNATE:
  287. $this->innate_stat = $stat;
  288. break;
  289. default:
  290. array_push($this->substats, $stat);
  291. break;
  292. }
  293. }
  294. $this->flag_stats = true;
  295. }
  296. /**
  297. * Loads the unit into the entity.
  298. *
  299. * Must be called only once before trying to get the unit. Sets the flag
  300. * {@link Rune:$flag_unit} to true.
  301. */
  302. private function load_unit(){
  303. $statement = get_context()->get_db()->prepare("
  304. SELECT unit
  305. FROM unit_rune
  306. WHERE
  307. rune = :rune AND
  308. rta = :mode;
  309. ");
  310. $statement->bindValue(':rune', $this->id, SQLITE3_TEXT);
  311. $statement->bindValue(':mode', get_context()->get_game_mode(), SQLITE3_TEXT);
  312. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  313. if ($r){
  314. $this->unit = new Unit($r["unit"]);
  315. }
  316. $this->flag_unit = true;
  317. }
  318. /**
  319. * Retrieves the owner's player identifier.
  320. *
  321. * @return int Player ID.
  322. */
  323. public function get_player(){
  324. return $this->player;
  325. }
  326. /**
  327. * Retrieves the rune identifier.
  328. *
  329. * @return int Rune ID.
  330. */
  331. public function get_id(){
  332. return $this->id;
  333. }
  334. /**
  335. * Retrieves the rune set.
  336. *
  337. * @return Rune_Set Set of the rune.
  338. */
  339. public function get_set(){
  340. return $this->type;
  341. }
  342. /**
  343. * Retrieves the rune slot.
  344. *
  345. * @return int Rune slot (1-6).
  346. */
  347. public function get_slot(){
  348. return $this->slot;
  349. }
  350. /**
  351. * Retrieves the rune stars (the grade).
  352. *
  353. * @return int Rune stars (1-6).
  354. */
  355. public function get_stars(){
  356. return $this->stars;
  357. }
  358. /**
  359. * Checks if it's an ancient rune.
  360. *
  361. * @return bool True for ancient, false for normal.
  362. */
  363. public function is_ancient(){
  364. return $this->ancient;
  365. }
  366. /**
  367. * Retrieves the rune level
  368. *
  369. * @return int Rune level (0-15).
  370. */
  371. public function get_level(){
  372. return $this->level;
  373. }
  374. /**
  375. * Retrieves the rune quality identifier.
  376. *
  377. * @see QUALITY_ID
  378. *
  379. * @return int Quality identifier.
  380. */
  381. public function get_quality(){
  382. return $this->quality;
  383. }
  384. /**
  385. * Retrieves the rune original quality identifier.
  386. *
  387. * @see QUALITY_ID
  388. *
  389. * @return int Original quality identifier.
  390. */
  391. public function get_original_quality(){
  392. return $this->original_quality;
  393. }
  394. /**
  395. * Retrieves the rune quality name.
  396. *
  397. * @return string Quality name.
  398. */
  399. public function get_quality_name(){
  400. return $this->quality_name;
  401. }
  402. /**
  403. * Retrieves the rune original quality name.
  404. *
  405. * @return string Original quality name.
  406. */
  407. public function get_original_quality_name(){
  408. return $this->original_quality_name;
  409. }
  410. /**
  411. * Retrieves the rune value.
  412. *
  413. * @return int Rune value in mana stones.
  414. */
  415. public function get_value(){
  416. return $this->value;
  417. }
  418. /**
  419. * Retrieves the rune efficiency.
  420. *
  421. * @return int Rune efficiency (0-100)
  422. */
  423. public function get_efficiency(){
  424. return $this->efficiency;
  425. }
  426. /**
  427. * Retrieves the rune efficiency.
  428. *
  429. * @return int Rune efficiency (0-100)
  430. */
  431. public function get_max_efficiency(){
  432. return $this->max_efficiency;
  433. }
  434. /**
  435. * Checks if the rune is locked.
  436. *
  437. * @return bool True if locked, false otherwise.
  438. */
  439. public function is_locked(){
  440. return $this->locked;
  441. }
  442. /**
  443. * Retrieves the rune main_stat.
  444. *
  445. * @return Rune_Stat The main stat.
  446. */
  447. public function get_main_stat(){
  448. if (! $this->flag_stats){
  449. $this->load_stats();
  450. }
  451. return $this->main_stat;
  452. }
  453. /**
  454. * Retrieves the rune innate stat.
  455. *
  456. * @return Rune_Stat Innate stat, null if it hasn't.
  457. */
  458. public function get_innate_stat(){
  459. if (! $this->flag_stats){
  460. $this->load_stats();
  461. }
  462. return $this->innate_stat;
  463. }
  464. /**
  465. * Retrieves as many substats as the rune has, sorted.
  466. *
  467. * @return Rune_Stat[] Sorted array of the rune substats.
  468. */
  469. public function get_substats(){
  470. if (! $this->flag_stats){
  471. $this->load_stats();
  472. }
  473. return $this->substats;
  474. }
  475. /**
  476. * Retrieves all the rune stats, including main, innate and substats, in an unsorted array.
  477. *
  478. * @return Rune_Stat Every rune stat.
  479. */
  480. public function get_stats(){
  481. if (! $this->flag_stats){
  482. $this->load_stats();
  483. }
  484. return $this->stats;
  485. }
  486. /**
  487. * Retrieves the unit that has equipped the rune in the current game mode.
  488. *
  489. * @return Unit Unit that has the rune.
  490. */
  491. public function get_unit(){
  492. if (! $this->flag_unit){
  493. $this->load_unit();
  494. }
  495. return $this->unit;
  496. }
  497. /**
  498. * Gets the value of the main stat at an arbitrary level.
  499. *
  500. * @param int $level Desired level.
  501. * @return int Value of the main stat at the selected level.
  502. */
  503. public function get_main_stat_at_level($level){
  504. $level = intval($level);
  505. if ($level < 0 || $level > 15){
  506. return 0;
  507. }
  508. switch ($this->main_stat->get_stat()){
  509. case RUNE_STAT_ID::HP:
  510. return RUNE_STAT_VALUES::HP[$this->stars][$level];
  511. case RUNE_STAT_ID::HP_P:
  512. return RUNE_STAT_VALUES::HP_P[$this->stars][$level];
  513. case RUNE_STAT_ID::ATK:
  514. return RUNE_STAT_VALUES::ATK[$this->stars][$level];
  515. case RUNE_STAT_ID::ATK_P:
  516. return RUNE_STAT_VALUES::ATK_P[$this->stars][$level];
  517. case RUNE_STAT_ID::DEF:
  518. return RUNE_STAT_VALUES::DEF[$this->stars][$level];
  519. case RUNE_STAT_ID::DEF_P:
  520. return RUNE_STAT_VALUES::DEF_P[$this->stars][$level];
  521. case RUNE_STAT_ID::SPD:
  522. return RUNE_STAT_VALUES::SPD[$this->stars][$level];
  523. case RUNE_STAT_ID::CRR:
  524. return RUNE_STAT_VALUES::CRR[$this->stars][$level];
  525. case RUNE_STAT_ID::CRD:
  526. return RUNE_STAT_VALUES::CRD[$this->stars][$level];
  527. case RUNE_STAT_ID::RES:
  528. return RUNE_STAT_VALUES::RES[$this->stars][$level];
  529. case RUNE_STAT_ID::ACC:
  530. return RUNE_STAT_VALUES::ACC[$this->stars][$level];
  531. default:
  532. return 0;
  533. }
  534. }
  535. /**
  536. * Gets a stat name frm the mappings.
  537. *
  538. * @param int $q Quality id.
  539. * @return string Quality (Uppercase)
  540. */
  541. private function map_quality_name($q){
  542. switch ($q){
  543. case QUALITY_ID::NORMAL:
  544. return "NORMAL";
  545. case QUALITY_ID::MAGIC:
  546. return "MAGIC";
  547. case QUALITY_ID::RARE:
  548. return "RARE";
  549. case QUALITY_ID::HERO:
  550. return "HERO";
  551. case QUALITY_ID::LEGEND:
  552. return "LEGEND";
  553. default:
  554. return "";
  555. }
  556. }
  557. /**
  558. * Calcuates the efficiency of the rune.
  559. *
  560. * @return float Efficiency
  561. */
  562. private function calculate_efficiency(){
  563. if (! $this->flag_stats){
  564. $this->load_stats();
  565. }
  566. $eff = [0.0, 0.0, 0.0, 0.0, 0.0];
  567. $query = "
  568. SELECT
  569. min,
  570. max
  571. FROM
  572. rune_roll_type,
  573. rune_stat_roll
  574. WHERE
  575. rune_roll_type.id = rune_stat_roll.type AND
  576. rune_roll_type.ancient = :ancient AND
  577. rune_roll_type.initial = :initial AND
  578. rune_roll_type.upgrade = :upgrade AND
  579. rune_stat_roll.stars = :stars AND
  580. rune_stat_roll.stat = :stat
  581. ";
  582. // Fixed stat
  583. if ($this->innate_stat != null && $this->innate_stat->get_value() > 0){
  584. $value = $this->innate_stat->get_value();
  585. $statement = get_context()->get_db()->prepare($query);
  586. $statement->bindValue(':ancient', $this->ancient, SQLITE3_TEXT);
  587. $statement->bindValue(':initial', 1, SQLITE3_TEXT);
  588. $statement->bindValue(':upgrade', 0, SQLITE3_TEXT);
  589. $statement->bindValue(':stars', $this->stars, SQLITE3_TEXT);
  590. $statement->bindValue(':stat', $this->innate_stat->get_stat(), SQLITE3_TEXT);
  591. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  592. if ($r){
  593. $min_initial = 0;//$r["min"];
  594. $max_initial = $r["max"];
  595. $eff[0] = ($value - $min_initial) / (9 * ($max_initial - $min_initial));
  596. }
  597. }
  598. for ($i = 1; $i <= 4; $i ++){
  599. if (sizeof($this->stats) > $i && $this->stats[$i] != null && $this->stats[$i]->get_value() > 0){
  600. $value = $this->stats[$i]->get_value();
  601. $value = $this->stats[$i]->get_value();
  602. $statement = get_context()->get_db()->prepare($query);
  603. $statement->bindValue(':ancient', $this->ancient, SQLITE3_TEXT);
  604. $statement->bindValue(':initial', 1, SQLITE3_TEXT);
  605. $statement->bindValue(':upgrade', 0, SQLITE3_TEXT);
  606. $statement->bindValue(':stars', $this->stars, SQLITE3_TEXT);
  607. $statement->bindValue(':stat', $this->stats[$i]->get_stat(), SQLITE3_TEXT);
  608. $r_initial = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  609. $statement = get_context()->get_db()->prepare($query);
  610. $statement->bindValue(':ancient', $this->ancient, SQLITE3_TEXT);
  611. $statement->bindValue(':initial', 0, SQLITE3_TEXT);
  612. $statement->bindValue(':upgrade', 1, SQLITE3_TEXT);
  613. $statement->bindValue(':stars', $this->stars, SQLITE3_TEXT);
  614. $statement->bindValue(':stat', $this->stats[$i]->get_stat(), SQLITE3_TEXT);
  615. $r_upgrade = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  616. if ($r_initial && $r_upgrade){
  617. $min_initial = 0;//$r_initial["min"];
  618. $max_initial = $r_initial["max"];
  619. $min_upgrade = 0;//$r_upgrade["min"];
  620. $max_upgrade = $r_upgrade["max"];
  621. $eff[$i] = ((5 * $value) - ( 4 * $min_upgrade + $min_initial)) / ( 9 * ($max_initial - $min_initial + (4 * ($max_upgrade + $min_upgrade))));
  622. }
  623. }
  624. }
  625. $efficiency = 0.0;
  626. for ($i = 0; $i <= 4; $i ++){
  627. $efficiency += $eff[$i];
  628. }
  629. $efficiency *= 100;
  630. return $efficiency;
  631. }
  632. /**
  633. * Calcuates the maximum efficiency of the rune.
  634. *
  635. * @return float Max efficiency
  636. */
  637. private function calculate_maximum_efficiency(){
  638. $max_efficiency = $this->efficiency;
  639. if ($this->level < 12){
  640. $max_efficiency += (1/9);
  641. }
  642. if ($this->level < 9){
  643. $max_efficiency += (1/9);
  644. }
  645. if ($this->level < 6){
  646. $max_efficiency += (1/9);
  647. }
  648. if ($this->level < 3){
  649. $max_efficiency += (1/9);
  650. }
  651. return $max_efficiency;
  652. }
  653. }