* @license https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License V3 * @package SWDB */ require_once(PATH::ENTITY . "Entity.php"); require_once(PATH::ENTITY . "Rune_Set.php"); require_once(PATH::ENTITY . "Rune_Stat.php"); /** * Owned rune. * * Represents a rune. * * @category Entity */ class Rune extends Entity{ /** * @var int Owner identifier. */ private $player; /** * @var int Rune identifier. */ private $id; /** * @var Rune_Set Rune set. */ private $type; /** * @var int Position of the rune type (1-6). */ private $slot; /** * @var int Rune stars. */ private $stars; /** * @var bool Indicates if the rune is ancient. */ private $ancient; /** * @var int Level of the rune. */ private $level; /** * @var int Rune quality. * @see QUALITY_ID */ private $quality; /** * @var int Rune original quality. * @see QUALITY_ID */ private $original_quality; /** * @var string Rune quality name (uppercase). */ private $quality_name; /** * @var string Rune original quality name (uppercase). */ private $original_quality_name; /** * @var int Price of the rune. */ private $value; /** * @var float Current efficiency of the rune. */ private $efficiency; /** * @var float Maximum potential efficiency of the rune. */ private $max_efficiency; /** * @var int Indicates if the rune is locked. */ private $locked; /** * @var bool Internal flag to check if the rune stats have been loaded into the entity. */ private $flag_stats = false; /** * @var Rune_Stat Main stat of the rune. */ private $main_stat; /** * @var Rune_Stat Extra stat of the rune. */ private $innate_stat; /** * @var Rune_Stat[] Substats of the rune. */ private $substats = []; /** * @var Rune_Stat[] All stats. * * Includes main, innate and substats */ private $stats = []; /** * @var bool Internal flag to check if the unit who equips the rune has been loaded. */ private $flag_unit = false; /** * @var Unit Unit the rune is assigned to. */ private $unit; /** * Constructor. * * Searches the database and retrieves the information about the * rune, populating it and it's items. * * @param int $id Rune id. */ public function __construct($id){ $statement = get_context()->get_db()->prepare(" SELECT id, type, slot, stars, level, ancient, quality, original_quality, value, efficiency, max_efficiency, locked FROM rune WHERE id = :id; "); $statement->bindValue(':id', $id, SQLITE3_TEXT); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r){ $this->id = $r["id"]; $this->type = new Rune_Set($r["type"]); $this->slot = $r["slot"]; $this->stars = $r["stars"]; $this->level = $r["level"]; $this->ancient = $r["ancient"]; $this->quality = $r["quality"]; $this->original_quality = $r["original_quality"]; $this->value = $r["value"]; $this->efficiency = $r["efficiency"]; $this->max_efficiency = $r["max_efficiency"]; $this->locked = filter_var($r["locked"], FILTER_VALIDATE_BOOLEAN); $this->quality_name = $this->map_quality_name($this->quality); $this->original_quality_name = $this->map_quality_name($this->original_quality); // Read efficiencies. If not set in DB, calculate and update. if ($this->efficiency == null || $this->efficiency == "" || intval($this->efficiency) == 0){ $this->efficiency = $this->calculate_efficiency(); $this->max_efficiency = $this->calculate_maximum_efficiency(); $statement = get_context()->get_db()->prepare(" UPDATE rune SET efficiency = :efficiency, max_efficiency = :max_efficiency WHERE id = :rune "); $statement->bindValue(':efficiency', $this->efficiency, SQLITE3_FLOAT); $statement->bindValue(':max_efficiency', $this->max_efficiency, SQLITE3_FLOAT); $statement->bindValue(':rune', $this->id, SQLITE3_INTEGER); $statement->execute(); } } else{ // Not found, maybe reading from a drop? $this->read_drop($id); } } private function read_drop($id){ $statement = get_context()->get_db()->prepare(" SELECT id, type, slot, stars, ancient, quality, value, efficiency, max_efficiency, main_stat, innate_stat, substat_1, substat_2, substat_3, substat_4 FROM run_drop_rune WHERE id = :id; "); $statement->bindValue(':id', $id, SQLITE3_TEXT); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r){ $this->id = $r["id"]; $this->type = new Rune_Set($r["type"]); $this->slot = $r["slot"]; $this->stars = $r["stars"]; $this->level = 0; $this->ancient = $r["ancient"]; $this->quality = $r["quality"]; $this->original_quality = $r["quality"]; $this->value = $r["value"]; $this->efficiency = $r["efficiency"]; $this->max_efficiency = $r["max_efficiency"]; $this->locked = false; $this->quality_name = $this->map_quality_name($this->quality); $this->original_quality_name = $this->map_quality_name($this->quality); $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::MAIN); $this->main_stat = $stat; array_push($this->stats, $stat); if (is_int($r["innate_stat"])){ $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::INNATE); $this->innate_stat = $stat; array_push($this->stats, $stat); } if (is_int($r["substat_1"])){ $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_1); array_push($this->substats, $stat); array_push($this->stats, $stat); } if (is_int($r["substat_2"])){ $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_2); array_push($this->substats, $stat); array_push($this->stats, $stat); } if (is_int($r["substat_3"])){ $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_3); array_push($this->substats, $stat); array_push($this->stats, $stat); } if (is_int($r["substat_4"])){ $stat = new Rune_Stat($this->id, RUNE_STAT_SLOT_ID::SUBSTAT_4); array_push($this->substats, $stat); array_push($this->stats, $stat); } $this->flag_stats = true; // Read efficiencies. If not set in DB, calculate and update. if ($this->efficiency == null || $this->efficiency == "" || intval($this->efficiency) == 0){ $this->efficiency = $this->calculate_efficiency(); $this->max_efficiency = $this->calculate_maximum_efficiency(); $statement = get_context()->get_db()->prepare(" UPDATE run_drop_rune SET efficiency = :efficiency, max_efficiency = :max_efficiency WHERE id = :rune "); $statement->bindValue(':efficiency', $this->efficiency, SQLITE3_FLOAT); $statement->bindValue(':max_efficiency', $this->max_efficiency, SQLITE3_FLOAT); $statement->bindValue(':rune', $this->id, SQLITE3_INTEGER); $statement->execute(); } } } /** * Loads the stats. * * Must be called only once before trying to get any of the stats (main, innate or subs) or * efficiencies. Sets the flag {@link Rune:$flag_stats} to true. */ private function load_stats(){ $statement = get_context()->get_db()->prepare(" SELECT slot FROM rune_stat WHERE rune = :rune ORDER BY slot; "); $statement->bindValue(':rune', $this->id, SQLITE3_TEXT); $q = $statement->execute(); while ($r = $q->fetchArray(SQLITE3_ASSOC)){ $stat = new Rune_Stat($this->id, $r["slot"]); array_push($this->stats, $stat); switch ($r["slot"]){ case RUNE_STAT_SLOT_ID::MAIN: $this->main_stat = $stat; break; case RUNE_STAT_SLOT_ID::INNATE: $this->innate_stat = $stat; break; default: array_push($this->substats, $stat); break; } } $this->flag_stats = true; } /** * Loads the unit into the entity. * * Must be called only once before trying to get the unit. Sets the flag * {@link Rune:$flag_unit} to true. */ private function load_unit(){ $statement = get_context()->get_db()->prepare(" SELECT unit FROM unit_rune WHERE rune = :rune AND rta = :mode; "); $statement->bindValue(':rune', $this->id, SQLITE3_TEXT); $statement->bindValue(':mode', get_context()->get_game_mode(), SQLITE3_TEXT); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r){ $this->unit = new Unit($r["unit"]); } $this->flag_unit = true; } /** * Retrieves the owner's player identifier. * * @return int Player ID. */ public function get_player(){ return $this->player; } /** * Retrieves the rune identifier. * * @return int Rune ID. */ public function get_id(){ return $this->id; } /** * Retrieves the rune set. * * @return Rune_Set Set of the rune. */ public function get_set(){ return $this->type; } /** * Retrieves the rune slot. * * @return int Rune slot (1-6). */ public function get_slot(){ return $this->slot; } /** * Retrieves the rune stars (the grade). * * @return int Rune stars (1-6). */ public function get_stars(){ return $this->stars; } /** * Checks if it's an ancient rune. * * @return bool True for ancient, false for normal. */ public function is_ancient(){ return $this->ancient; } /** * Retrieves the rune level * * @return int Rune level (0-15). */ public function get_level(){ return $this->level; } /** * Retrieves the rune quality identifier. * * @see QUALITY_ID * * @return int Quality identifier. */ public function get_quality(){ return $this->quality; } /** * Retrieves the rune original quality identifier. * * @see QUALITY_ID * * @return int Original quality identifier. */ public function get_original_quality(){ return $this->original_quality; } /** * Retrieves the rune quality name. * * @return string Quality name. */ public function get_quality_name(){ return $this->quality_name; } /** * Retrieves the rune original quality name. * * @return string Original quality name. */ public function get_original_quality_name(){ return $this->original_quality_name; } /** * Retrieves the rune value. * * @return int Rune value in mana stones. */ public function get_value(){ return $this->value; } /** * Retrieves the rune efficiency. * * @return int Rune efficiency (0-100) */ public function get_efficiency(){ return $this->efficiency; } /** * Retrieves the rune efficiency. * * @return int Rune efficiency (0-100) */ public function get_max_efficiency(){ return $this->max_efficiency; } /** * Checks if the rune is locked. * * @return bool True if locked, false otherwise. */ public function is_locked(){ return $this->locked; } /** * Retrieves the rune main_stat. * * @return Rune_Stat The main stat. */ public function get_main_stat(){ if (! $this->flag_stats){ $this->load_stats(); } return $this->main_stat; } /** * Retrieves the rune innate stat. * * @return Rune_Stat Innate stat, null if it hasn't. */ public function get_innate_stat(){ if (! $this->flag_stats){ $this->load_stats(); } return $this->innate_stat; } /** * Retrieves as many substats as the rune has, sorted. * * @return Rune_Stat[] Sorted array of the rune substats. */ public function get_substats(){ if (! $this->flag_stats){ $this->load_stats(); } return $this->substats; } /** * Retrieves all the rune stats, including main, innate and substats, in an unsorted array. * * @return Rune_Stat Every rune stat. */ public function get_stats(){ if (! $this->flag_stats){ $this->load_stats(); } return $this->stats; } /** * Retrieves the unit that has equipped the rune in the current game mode. * * @return Unit Unit that has the rune. */ public function get_unit(){ if (! $this->flag_unit){ $this->load_unit(); } return $this->unit; } /** * Gets the value of the main stat at an arbitrary level. * * @param int $level Desired level. * @return int Value of the main stat at the selected level. */ public function get_main_stat_at_level($level){ $level = intval($level); if ($level < 0 || $level > 15){ return 0; } switch ($this->main_stat->get_stat()){ case RUNE_STAT_ID::HP: return RUNE_STAT_VALUES::HP[$this->stars][$level]; case RUNE_STAT_ID::HP_P: return RUNE_STAT_VALUES::HP_P[$this->stars][$level]; case RUNE_STAT_ID::ATK: return RUNE_STAT_VALUES::ATK[$this->stars][$level]; case RUNE_STAT_ID::ATK_P: return RUNE_STAT_VALUES::ATK_P[$this->stars][$level]; case RUNE_STAT_ID::DEF: return RUNE_STAT_VALUES::DEF[$this->stars][$level]; case RUNE_STAT_ID::DEF_P: return RUNE_STAT_VALUES::DEF_P[$this->stars][$level]; case RUNE_STAT_ID::SPD: return RUNE_STAT_VALUES::SPD[$this->stars][$level]; case RUNE_STAT_ID::CRR: return RUNE_STAT_VALUES::CRR[$this->stars][$level]; case RUNE_STAT_ID::CRD: return RUNE_STAT_VALUES::CRD[$this->stars][$level]; case RUNE_STAT_ID::RES: return RUNE_STAT_VALUES::RES[$this->stars][$level]; case RUNE_STAT_ID::ACC: return RUNE_STAT_VALUES::ACC[$this->stars][$level]; default: return 0; } } /** * Gets a stat name frm the mappings. * * @param int $q Quality id. * @return string Quality (Uppercase) */ private function map_quality_name($q){ switch ($q){ case QUALITY_ID::NORMAL: return "NORMAL"; case QUALITY_ID::MAGIC: return "MAGIC"; case QUALITY_ID::RARE: return "RARE"; case QUALITY_ID::HERO: return "HERO"; case QUALITY_ID::LEGEND: return "LEGEND"; default: return ""; } } /** * Calcuates the efficiency of the rune. * * @return float Efficiency */ private function calculate_efficiency(){ if (! $this->flag_stats){ $this->load_stats(); } $eff = [0.0, 0.0, 0.0, 0.0, 0.0]; $query = " SELECT min, max FROM rune_roll_type, rune_stat_roll WHERE rune_roll_type.id = rune_stat_roll.type AND rune_roll_type.ancient = :ancient AND rune_roll_type.initial = :initial AND rune_roll_type.upgrade = :upgrade AND rune_stat_roll.stars = :stars AND rune_stat_roll.stat = :stat "; // Fixed stat if ($this->innate_stat != null && $this->innate_stat->get_value() > 0){ $value = $this->innate_stat->get_value(); $statement = get_context()->get_db()->prepare($query); $statement->bindValue(':ancient', $this->ancient, SQLITE3_TEXT); $statement->bindValue(':initial', 1, SQLITE3_TEXT); $statement->bindValue(':upgrade', 0, SQLITE3_TEXT); $statement->bindValue(':stars', $this->stars, SQLITE3_TEXT); $statement->bindValue(':stat', $this->innate_stat->get_stat(), SQLITE3_TEXT); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r){ $min_initial = 0;//$r["min"]; $max_initial = $r["max"]; $eff[0] = ($value - $min_initial) / (9 * ($max_initial - $min_initial)); } } for ($i = 1; $i <= 4; $i ++){ if (sizeof($this->stats) > $i && $this->stats[$i] != null && $this->stats[$i]->get_value() > 0){ $value = $this->stats[$i]->get_value(); $value = $this->stats[$i]->get_value(); $statement = get_context()->get_db()->prepare($query); $statement->bindValue(':ancient', $this->ancient, SQLITE3_TEXT); $statement->bindValue(':initial', 1, SQLITE3_TEXT); $statement->bindValue(':upgrade', 0, SQLITE3_TEXT); $statement->bindValue(':stars', $this->stars, SQLITE3_TEXT); $statement->bindValue(':stat', $this->stats[$i]->get_stat(), SQLITE3_TEXT); $r_initial = $statement->execute()->fetchArray(SQLITE3_ASSOC); $statement = get_context()->get_db()->prepare($query); $statement->bindValue(':ancient', $this->ancient, SQLITE3_TEXT); $statement->bindValue(':initial', 0, SQLITE3_TEXT); $statement->bindValue(':upgrade', 1, SQLITE3_TEXT); $statement->bindValue(':stars', $this->stars, SQLITE3_TEXT); $statement->bindValue(':stat', $this->stats[$i]->get_stat(), SQLITE3_TEXT); $r_upgrade = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r_initial && $r_upgrade){ $min_initial = 0;//$r_initial["min"]; $max_initial = $r_initial["max"]; $min_upgrade = 0;//$r_upgrade["min"]; $max_upgrade = $r_upgrade["max"]; $eff[$i] = ((5 * $value) - ( 4 * $min_upgrade + $min_initial)) / ( 9 * ($max_initial - $min_initial + (4 * ($max_upgrade + $min_upgrade)))); } } } $efficiency = 0.0; for ($i = 0; $i <= 4; $i ++){ $efficiency += $eff[$i]; } $efficiency *= 100; return $efficiency; } /** * Calcuates the maximum efficiency of the rune. * * @return float Max efficiency */ private function calculate_maximum_efficiency(){ $max_efficiency = $this->efficiency; if ($this->level < 12){ $max_efficiency += (1/9); } if ($this->level < 9){ $max_efficiency += (1/9); } if ($this->level < 6){ $max_efficiency += (1/9); } if ($this->level < 3){ $max_efficiency += (1/9); } return $max_efficiency; } }