PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Flux.php

https://github.com/chokoleytdesignoper/fluxcp_choko
PHP | 898 lines | 589 code | 76 blank | 233 comment | 43 complexity | 87fced723f6e4dbac203e4c2929da813 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, BSD-3-Clause
  1. <?php
  2. require_once 'Flux/Config.php';
  3. require_once 'Flux/Error.php';
  4. require_once 'Flux/Connection.php';
  5. require_once 'Flux/LoginServer.php';
  6. require_once 'Flux/CharServer.php';
  7. require_once 'Flux/MapServer.php';
  8. require_once 'Flux/Athena.php';
  9. require_once 'Flux/LoginAthenaGroup.php';
  10. require_once 'Flux/Addon.php';
  11. require_once 'functions/svn_version.php';
  12. // Get the SVN revision of the top-level directory (FLUX_ROOT).
  13. define('FLUX_SVNVERSION', svn_version());
  14. /**
  15. * The Flux class contains methods related to the application on the larger
  16. * scale. For the most part, it handles application initialization such as
  17. * parsing the configuration files and whatnot.
  18. */
  19. class Flux {
  20. /**
  21. * Current version.
  22. */
  23. const VERSION = '1.0.0';
  24. /**
  25. * Top-level revision.
  26. */
  27. const SVNVERSION = FLUX_SVNVERSION;
  28. /**
  29. * Application-specific configuration object.
  30. *
  31. * @access public
  32. * @var Flux_Config
  33. */
  34. public static $appConfig;
  35. /**
  36. * Servers configuration object.
  37. *
  38. * @access public
  39. * @var Flux_Config
  40. */
  41. public static $serversConfig;
  42. /**
  43. * Messages configuration object.
  44. *
  45. * @access public
  46. * @var Flux_Config
  47. */
  48. public static $messagesConfig;
  49. /**
  50. * Collection of Flux_Athena objects.
  51. *
  52. * @access public
  53. * @var array
  54. */
  55. public static $servers = array();
  56. /**
  57. * Registry where Flux_LoginAthenaGroup instances are kept for easy
  58. * searching.
  59. *
  60. * @access public
  61. * @var array
  62. */
  63. public static $loginAthenaGroupRegistry = array();
  64. /**
  65. * Registry where Flux_Athena instances are kept for easy searching.
  66. *
  67. * @access public
  68. * @var array
  69. */
  70. public static $athenaServerRegistry = array();
  71. /**
  72. * Object containing all of Flux's session data.
  73. *
  74. * @access public
  75. * @var Flux_SessionData
  76. */
  77. public static $sessionData;
  78. /**
  79. *
  80. */
  81. public static $numberOfQueries = 0;
  82. /**
  83. *
  84. */
  85. public static $addons = array();
  86. /**
  87. * Initialize Flux application. This will handle configuration parsing and
  88. * instanciating of objects crucial to the control panel.
  89. *
  90. * @param array $options Options to pass to initializer.
  91. * @throws Flux_Error Raised when missing required options.
  92. * @access public
  93. */
  94. public static function initialize($options = array())
  95. {
  96. //$required = array('appConfigFile', 'serversConfigFile', 'messagesConfigFile');
  97. $required = array('appConfigFile', 'serversConfigFile');
  98. foreach ($required as $option) {
  99. if (!array_key_exists($option, $options)) {
  100. self::raise("Missing required option `$option' in Flux::initialize()");
  101. }
  102. }
  103. // Parse application and server configuration files, this will also
  104. // handle configuration file normalization. See the source for the
  105. // below methods for more details on what's being done.
  106. self::$appConfig = self::parseAppConfigFile($options['appConfigFile']);
  107. self::$serversConfig = self::parseServersConfigFile($options['serversConfigFile']);
  108. //self::$messagesConfig = self::parseMessagesConfigFile($options['messagesConfigFile']); // Deprecated.
  109. // Using newer language system.
  110. self::$messagesConfig = self::parseLanguageConfigFile();
  111. // Initialize server objects.
  112. self::initializeServerObjects();
  113. // Initialize add-ons.
  114. self::initializeAddons();
  115. }
  116. /**
  117. * Initialize each Login/Char/Map server object and contain them in their
  118. * own collective Athena object.
  119. *
  120. * This is also part of the Flux initialization phase.
  121. *
  122. * @access public
  123. */
  124. public static function initializeServerObjects()
  125. {
  126. foreach (self::$serversConfig->getChildrenConfigs() as $key => $config) {
  127. $connection = new Flux_Connection($config->getDbConfig(), $config->getLogsDbConfig());
  128. $loginServer = new Flux_LoginServer($config->getLoginServer());
  129. // LoginAthenaGroup maintains the grouping of a central login
  130. // server and its underlying Athena objects.
  131. self::$servers[$key] = new Flux_LoginAthenaGroup($config->getServerName(), $connection, $loginServer);
  132. // Add into registry.
  133. self::registerServerGroup($config->getServerName(), self::$servers[$key]);
  134. foreach ($config->getCharMapServers()->getChildrenConfigs() as $charMapServer) {
  135. $charServer = new Flux_CharServer($charMapServer->getCharServer());
  136. $mapServer = new Flux_MapServer($charMapServer->getMapServer());
  137. // Create the collective server object, Flux_Athena.
  138. $athena = new Flux_Athena($charMapServer, $loginServer, $charServer, $mapServer);
  139. self::$servers[$key]->addAthenaServer($athena);
  140. // Add into registry.
  141. self::registerAthenaServer($config->getServerName(), $charMapServer->getServerName(), $athena);
  142. }
  143. }
  144. }
  145. /**
  146. *
  147. */
  148. public static function initializeAddons()
  149. {
  150. if (!is_dir(FLUX_ADDON_DIR)) {
  151. return false;
  152. }
  153. foreach (glob(FLUX_ADDON_DIR.'/*') as $addonDir) {
  154. if (is_dir($addonDir)) {
  155. $addonName = basename($addonDir);
  156. $addonObject = new Flux_Addon($addonName, $addonDir);
  157. self::$addons[$addonName] = $addonObject;
  158. // Merge configurations.
  159. self::$appConfig->merge($addonObject->addonConfig);
  160. self::$messagesConfig->merge($addonObject->messagesConfig, false);
  161. }
  162. }
  163. }
  164. /**
  165. * Wrapper method for setting and getting values from the appConfig.
  166. *
  167. * @param string $key
  168. * @param mixed $value
  169. * @param arary $options
  170. * @access public
  171. */
  172. public static function config($key, $value = null, $options = array())
  173. {
  174. if (!is_null($value)) {
  175. return self::$appConfig->set($key, $value, $options);
  176. }
  177. else {
  178. return self::$appConfig->get($key);
  179. }
  180. }
  181. /**
  182. * Wrapper method for setting and getting values from the messagesConfig.
  183. *
  184. * @param string $key
  185. * @param mixed $value
  186. * @param arary $options
  187. * @access public
  188. */
  189. public static function message($key, $value = null, $options = array())
  190. {
  191. if (!is_null($value)) {
  192. return self::$messagesConfig->set($key, $value, $options);
  193. }
  194. else {
  195. return self::$messagesConfig->get($key);
  196. }
  197. }
  198. /**
  199. * Convenience method for raising Flux_Error exceptions.
  200. *
  201. * @param string $message Message to pass to constructor.
  202. * @throws Flux_Error
  203. * @access public
  204. */
  205. public static function raise($message)
  206. {
  207. throw new Flux_Error($message);
  208. }
  209. /**
  210. * Parse PHP array into Flux_Config instance.
  211. *
  212. * @param array $configArr
  213. * @access public
  214. */
  215. public static function parseConfig(array $configArr)
  216. {
  217. return new Flux_Config($configArr);
  218. }
  219. /**
  220. * Parse a PHP array returned as the result of an included file into a
  221. * Flux_Config configuration object.
  222. *
  223. * @param string $filename
  224. * @access public
  225. */
  226. public static function parseConfigFile($filename, $cache=true)
  227. {
  228. $basename = basename(str_replace(' ', '', ucwords(str_replace(array('/', '\\', '_'), ' ', $filename))), '.php').'.cache.php';
  229. $cachefile = FLUX_DATA_DIR."/tmp/$basename";
  230. if ($cache && file_exists($cachefile) && filemtime($cachefile) > filemtime($filename)) {
  231. return unserialize(file_get_contents($cachefile, null, null, 28));
  232. }
  233. else {
  234. ob_start();
  235. // Uses require, thus assumes the file returns an array.
  236. $config = require $filename;
  237. ob_end_clean();
  238. // Cache config file.
  239. $cf = self::parseConfig($config);
  240. if ($cache) {
  241. $fp = fopen($cachefile, 'w');
  242. fwrite($fp, '<?php exit("Forbidden."); ?>');
  243. fwrite($fp, $s=serialize($cf), strlen($s));
  244. fclose($fp);
  245. }
  246. return $cf;
  247. }
  248. }
  249. /**
  250. * Parse a file in an application-config specific manner.
  251. *
  252. * @param string $filename
  253. * @access public
  254. */
  255. public static function parseAppConfigFile($filename)
  256. {
  257. $config = self::parseConfigFile($filename, false);
  258. if (!$config->getServerAddress()) {
  259. self::raise("ServerAddress must be specified in your application config.");
  260. }
  261. if (!$config->getThemeName()) {
  262. self::raise('ThemeName is required in application configuration.');
  263. }
  264. elseif (!self::themeExists($themeName=$config->getThemeName())) {
  265. self::raise("The selected theme '$themeName' does not exist.");
  266. }
  267. elseif (!($config->getPayPalReceiverEmails() instanceOf Flux_Config)) {
  268. self::raise("PayPalReceiverEmails must be an array.");
  269. }
  270. // Sanitize BaseURI. (leading forward slash is mandatory.)
  271. $baseURI = $config->get('BaseURI');
  272. if (strlen($baseURI) && $baseURI[0] != '/') {
  273. $config->set('BaseURI', "/$baseURI");
  274. }
  275. elseif (trim($baseURI) === '') {
  276. $config->set('BaseURI', '/');
  277. }
  278. return $config;
  279. }
  280. /**
  281. * Parse a file in a servers-config specific manner. This method gets a bit
  282. * nasty so beware of ugly code ;)
  283. *
  284. * @param string $filename
  285. * @access public
  286. */
  287. public static function parseServersConfigFile($filename)
  288. {
  289. $config = self::parseConfigFile($filename);
  290. $options = array('overwrite' => false, 'force' => true); // Config::set() options.
  291. $serverNames = array();
  292. $athenaServerNames = array();
  293. if (!count($config->toArray())) {
  294. self::raise('At least one server configuration must be present.');
  295. }
  296. foreach ($config->getChildrenConfigs() as $topConfig) {
  297. //
  298. // Top-level normalization.
  299. //
  300. if (!($serverName = $topConfig->getServerName())) {
  301. self::raise('ServerName is required for each top-level server configuration, check your servers configuration file.');
  302. }
  303. elseif (in_array($serverName, $serverNames)) {
  304. self::raise("The server name '$serverName' has already been configured. Please use another name.");
  305. }
  306. $serverNames[] = $serverName;
  307. $athenaServerNames[$serverName] = array();
  308. $topConfig->setDbConfig(array(), $options);
  309. $topConfig->setLogsDbConfig(array(), $options);
  310. $topConfig->setLoginServer(array(), $options);
  311. $topConfig->setCharMapServers(array(), $options);
  312. $dbConfig = $topConfig->getDbConfig();
  313. $logsDbConfig = $topConfig->getLogsDbConfig();
  314. $loginServer = $topConfig->getLoginServer();
  315. foreach (array($dbConfig, $logsDbConfig) as $_dbConfig) {
  316. $_dbConfig->setHostname('localhost', $options);
  317. $_dbConfig->setUsername('ragnarok', $options);
  318. $_dbConfig->setPassword('ragnarok', $options);
  319. $_dbConfig->setPersistent(true, $options);
  320. }
  321. $loginServer->setDatabase($dbConfig->getDatabase(), $options);
  322. $loginServer->setUseMD5(true, $options);
  323. // Raise error if missing essential configuration directives.
  324. if (!$loginServer->getAddress()) {
  325. self::raise('Address is required for each LoginServer section in your servers configuration.');
  326. }
  327. elseif (!$loginServer->getPort()) {
  328. self::raise('Port is required for each LoginServer section in your servers configuration.');
  329. }
  330. if (!$topConfig->getCharMapServers() || !count($topConfig->getCharMapServers()->toArray())) {
  331. self::raise('CharMapServers must be an array and contain at least 1 char/map server entry.');
  332. }
  333. foreach ($topConfig->getCharMapServers()->getChildrenConfigs() as $charMapServer) {
  334. //
  335. // Char/Map normalization.
  336. //
  337. $charMapServer->setBaseExpRates(1, $options);
  338. $charMapServer->setJobExpRates(1, $options);
  339. $charMapServer->setMvpExpRates(1, $options);
  340. $charMapServer->setDropRates(1, $options);
  341. $charMapServer->setMvpDropRates(1, $options);
  342. $charMapServer->setCardDropRates(1, $options);
  343. $charMapServer->setCharServer(array(), $options);
  344. $charMapServer->setMapServer(array(), $options);
  345. $charMapServer->setDatabase($dbConfig->getDatabase(), $options);
  346. if (!($athenaServerName = $charMapServer->getServerName())) {
  347. self::raise('ServerName is required for each CharMapServers pair in your servers configuration.');
  348. }
  349. elseif (in_array($athenaServerName, $athenaServerNames[$serverName])) {
  350. self::raise("The server name '$athenaServerName' under '$serverName' has already been configured. Please use another name.");
  351. }
  352. $athenaServerNames[$serverName][] = $athenaServerName;
  353. $charServer = $charMapServer->getCharServer();
  354. if (!$charServer->getAddress()) {
  355. self::raise('Address is required for each CharServer section in your servers configuration.');
  356. }
  357. elseif (!$charServer->getPort()) {
  358. self::raise('Port is required for each CharServer section in your servers configuration.');
  359. }
  360. $mapServer = $charMapServer->getMapServer();
  361. if (!$mapServer->getAddress()) {
  362. self::raise('Address is required for each MapServer section in your servers configuration.');
  363. }
  364. elseif (!$mapServer->getPort()) {
  365. self::raise('Port is required for each MapServer section in your servers configuration.');
  366. }
  367. }
  368. }
  369. return $config;
  370. }
  371. /**
  372. * Parses a messages configuration file. (Deprecated)
  373. *
  374. * @param string $filename
  375. * @access public
  376. */
  377. public static function parseMessagesConfigFile($filename)
  378. {
  379. $config = self::parseConfigFile($filename);
  380. // Nothing yet.
  381. return $config;
  382. }
  383. /**
  384. * Parses a language configuration file, can also parse a language config
  385. * for any addon.
  386. *
  387. * @param string $addonName
  388. * @access public
  389. */
  390. public static function parseLanguageConfigFile($addonName=null)
  391. {
  392. $default = $addonName ? FLUX_ADDON_DIR."/$addonName/lang/en_us.php" : FLUX_LANG_DIR.'/en_us.php';
  393. $current = $default;
  394. if ($lang=self::config('DefaultLanguage')) {
  395. $current = $addonName ? FLUX_ADDON_DIR."/$addonName/lang/$lang.php" : FLUX_LANG_DIR."/$lang.php";
  396. }
  397. if (file_exists($default)) {
  398. $def = self::parseConfigFile($default);
  399. }
  400. else {
  401. $tmp = array();
  402. $def = new Flux_Config($tmp);
  403. }
  404. if ($current != $default && file_exists($current)) {
  405. $cur = self::parseConfigFile($current);
  406. $def->merge($cur, false);
  407. }
  408. return $def;
  409. }
  410. /**
  411. * Check whether or not a theme exists.
  412. *
  413. * @return bool
  414. * @access public
  415. */
  416. public static function themeExists($themeName)
  417. {
  418. return is_dir(FLUX_THEME_DIR."/$themeName");
  419. }
  420. /**
  421. * Register the server group into the registry.
  422. *
  423. * @param string $serverName Server group's name.
  424. * @param Flux_LoginAthenaGroup Server group object.
  425. * @return Flux_LoginAthenaGroup
  426. * @access private
  427. */
  428. private function registerServerGroup($serverName, Flux_LoginAthenaGroup $serverGroup)
  429. {
  430. self::$loginAthenaGroupRegistry[$serverName] = $serverGroup;
  431. return $serverGroup;
  432. }
  433. /**
  434. * Register the Athena server into the registry.
  435. *
  436. * @param string $serverName Server group's name.
  437. * @param string $athenaServerName Athena server's name.
  438. * @param Flux_Athena $athenaServer Athena server object.
  439. * @return Flux_Athena
  440. * @access private
  441. */
  442. private function registerAthenaServer($serverName, $athenaServerName, Flux_Athena $athenaServer)
  443. {
  444. if (!array_key_exists($serverName, self::$athenaServerRegistry) || !is_array(self::$athenaServerRegistry[$serverName])) {
  445. self::$athenaServerRegistry[$serverName] = array();
  446. }
  447. self::$athenaServerRegistry[$serverName][$athenaServerName] = $athenaServer;
  448. return $athenaServer;
  449. }
  450. /**
  451. * Get Flux_LoginAthenaGroup server object by its ServerName.
  452. *
  453. * @param string
  454. * @return mixed Returns Flux_LoginAthenaGroup instance or false on failure.
  455. * @access public
  456. */
  457. public static function getServerGroupByName($serverName)
  458. {
  459. $registry = &self::$loginAthenaGroupRegistry;
  460. if (array_key_exists($serverName, $registry) && $registry[$serverName] instanceOf Flux_LoginAthenaGroup) {
  461. return $registry[$serverName];
  462. }
  463. else {
  464. return false;
  465. }
  466. }
  467. /**
  468. * Get Flux_Athena instance by its group/server names.
  469. *
  470. * @param string $serverName Server group name.
  471. * @param string $athenaServerName Athena server name.
  472. * @return mixed Returns Flux_Athena instance or false on failure.
  473. * @access public
  474. */
  475. public static function getAthenaServerByName($serverName, $athenaServerName)
  476. {
  477. $registry = &self::$athenaServerRegistry;
  478. if (array_key_exists($serverName, $registry) && array_key_exists($athenaServerName, $registry[$serverName]) &&
  479. $registry[$serverName][$athenaServerName] instanceOf Flux_Athena) {
  480. return $registry[$serverName][$athenaServerName];
  481. }
  482. else {
  483. return false;
  484. }
  485. }
  486. /**
  487. * Hashes a password for use in comparison with the login.user_pass column.
  488. *
  489. * @param string $password Plain text password.
  490. * @return string Returns hashed password.
  491. * @access public
  492. */
  493. public static function hashPassword($password)
  494. {
  495. // Default hashing schema is MD5.
  496. return md5($password);
  497. }
  498. /**
  499. * Get the job class name from a job ID.
  500. *
  501. * @param int $id
  502. * @return mixed Job class or false.
  503. * @access public
  504. */
  505. public static function getJobClass($id)
  506. {
  507. $key = "JobClasses.$id";
  508. $class = self::config($key);
  509. if ($class) {
  510. return $class;
  511. }
  512. else {
  513. return false;
  514. }
  515. }
  516. /**
  517. * Get the job ID from a job class name.
  518. *
  519. * @param string $class
  520. * @return mixed Job ID or false.
  521. * @access public
  522. */
  523. public static function getJobID($class)
  524. {
  525. $index = self::config('JobClassIndex')->toArray();
  526. if (array_key_exists($class, $index)) {
  527. return $index[$class];
  528. }
  529. else {
  530. return false;
  531. }
  532. }
  533. /**
  534. * Get the homunculus class name from a homun class ID.
  535. *
  536. * @param int $id
  537. * @return mixed Class name or false.
  538. * @access public
  539. */
  540. public static function getHomunClass($id)
  541. {
  542. $key = "HomunClasses.$id";
  543. $class = self::config($key);
  544. if ($class) {
  545. return $class;
  546. }
  547. else {
  548. return false;
  549. }
  550. }
  551. /**
  552. * Get the item type name from an item type.
  553. *
  554. * @param int $id
  555. * @return mixed Item Type or false.
  556. * @access public
  557. */
  558. public static function getItemType($id)
  559. {
  560. $key = "ItemTypes.$id";
  561. $type = self::config($key);
  562. if ($type) {
  563. return $type;
  564. }
  565. else {
  566. return false;
  567. }
  568. }
  569. /**
  570. * Process donations that have been put on hold.
  571. */
  572. public static function processHeldCredits()
  573. {
  574. $txnLogTable = self::config('FluxTables.TransactionTable');
  575. $creditsTable = self::config('FluxTables.CreditsTable');
  576. $trustTable = self::config('FluxTables.DonationTrustTable');
  577. $loginAthenaGroups = self::$loginAthenaGroupRegistry;
  578. list ($cancel, $accept) = array(array(), array());
  579. foreach ($loginAthenaGroups as $loginAthenaGroup) {
  580. $sql = "SELECT account_id, payer_email, credits, mc_gross, txn_id, hold_until ";
  581. $sql .= "FROM {$loginAthenaGroup->loginDatabase}.$txnLogTable ";
  582. $sql .= "WHERE account_id > 0 AND hold_until IS NOT NULL AND payment_status = 'Completed'";
  583. $sth = $loginAthenaGroup->connection->getStatement($sql);
  584. if ($sth->execute() && ($txn=$sth->fetchAll())) {
  585. foreach ($txn as $t) {
  586. $sql = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$txnLogTable ";
  587. $sql .= "WHERE payment_status IN ('Cancelled_Reversed', 'Reversed', 'Refunded') AND parent_txn_id = ? LIMIT 1";
  588. $sth = $loginAthenaGroup->connection->getStatement($sql);
  589. if ($sth->execute(array($t->txn_id)) && ($r=$sth->fetch()) && $r->id) {
  590. $cancel[] = $t->txn_id;
  591. }
  592. elseif (strtotime($t->hold_until) <= time()) {
  593. $accept[] = $t;
  594. }
  595. }
  596. }
  597. if (!empty($cancel)) {
  598. $ids = implode(', ', array_fill(0, count($cancel), '?'));
  599. $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.$txnLogTable ";
  600. $sql .= "SET credits = 0, hold_until = NULL WHERE txn_id IN ($ids)";
  601. $sth = $loginAthenaGroup->connection->getStatement($sql);
  602. $sth->execute($cancel);
  603. }
  604. $sql2 = "INSERT INTO {$loginAthenaGroup->loginDatabase}.$trustTable (account_id, email, create_date)";
  605. $sql2 .= "VALUES (?, ?, NOW())";
  606. $sth2 = $loginAthenaGroup->connection->getStatement($sql2);
  607. $sql3 = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$trustTable WHERE ";
  608. $sql3 .= "delete_date IS NULL AND account_id = ? AND email = ? LIMIT 1";
  609. $sth3 = $loginAthenaGroup->connection->getStatement($sql3);
  610. $idvals = array();
  611. foreach ($accept as $txn) {
  612. $loginAthenaGroup->loginServer->depositCredits($txn->account_id, $txn->credits, $txn->mc_gross);
  613. $sth3->execute(array($txn->account_id, $txn->payer_email));
  614. $row = $sth3->fetch();
  615. if (!$row) {
  616. $sth2->execute(array($txn->account_id, $txn->payer_email));
  617. }
  618. $idvals[] = $txn->txn_id;
  619. }
  620. if (!empty($idvals)) {
  621. $ids = implode(', ', array_fill(0, count($idvals), '?'));
  622. $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.$txnLogTable ";
  623. $sql .= "SET hold_until = NULL WHERE txn_id IN ($ids)";
  624. $sth = $loginAthenaGroup->connection->getStatement($sql);
  625. $sth->execute($idvals);
  626. }
  627. }
  628. }
  629. /**
  630. * Get array of equip_location bits. (bit => loc_name pairs)
  631. * @return array
  632. */
  633. public static function getEquipLocationList()
  634. {
  635. return array(
  636. 256 => 'Upper Headgear',
  637. 512 => 'Middle Headgear',
  638. 1 => 'Lower Headgear',
  639. 16 => 'Armor',
  640. 2 => 'Weapon',
  641. 32 => 'Shield',
  642. 4 => 'Garment',
  643. 64 => 'Footgear',
  644. 8 => 'Accessory 1',
  645. 128 => 'Accessory 2'
  646. );
  647. }
  648. /**
  649. * Get array of equip_upper bits. (bit => upper_name pairs)
  650. * @return array
  651. */
  652. public static function getEquipUpperList()
  653. {
  654. return array(
  655. 1 => 'Normal',
  656. 2 => 'Upper',
  657. 4 => 'Baby'
  658. );
  659. }
  660. /**
  661. * Get array of equip_jobs bits. (bit => job_name pairs)
  662. */
  663. public static function getEquipJobsList()
  664. {
  665. return array(
  666. pow(2, 0) => 'Novice',
  667. pow(2, 1) => 'Swordman',
  668. pow(2, 2) => 'Mage',
  669. pow(2, 3) => 'Archer',
  670. pow(2, 4) => 'Acolyte',
  671. pow(2, 5) => 'Merchant',
  672. pow(2, 6) => 'Thief',
  673. pow(2, 7) => 'Knight',
  674. pow(2, 8) => 'Priest',
  675. pow(2, 9) => 'Wizard',
  676. pow(2, 10) => 'Blacksmith',
  677. pow(2, 11) => 'Hunter',
  678. pow(2, 12) => 'Assassin',
  679. pow(2, 13) => 'Unused',
  680. pow(2, 14) => 'Crusader',
  681. pow(2, 15) => 'Monk',
  682. pow(2, 16) => 'Sage',
  683. pow(2, 17) => 'Rogue',
  684. pow(2, 18) => 'Alchemist',
  685. pow(2, 19) => 'Bard/Dancer',
  686. pow(2, 20) => 'Unused',
  687. pow(2, 21) => 'Taekwon',
  688. pow(2, 22) => 'Star Gladiator',
  689. pow(2, 23) => 'Soul Linker',
  690. pow(2, 24) => 'Gunslinger',
  691. pow(2, 25) => 'Ninja'
  692. );
  693. }
  694. /**
  695. * Check whether a particular item type is stackable.
  696. * @param int $type
  697. * @return bool
  698. */
  699. public static function isStackableItemType($type)
  700. {
  701. $nonstackables = array(1, 4, 5, 7, 8, 9);
  702. return !in_array($type, $nonstackables);
  703. }
  704. /**
  705. * Perform a bitwise AND from each bit in getEquipLocationList() on $bitmask
  706. * to determine which bits have been set.
  707. * @param int $bitmask
  708. * @return array
  709. */
  710. public static function equipLocationsToArray($bitmask)
  711. {
  712. $arr = array();
  713. $bits = self::getEquipLocationList();
  714. foreach ($bits as $bit => $name) {
  715. if ($bitmask & $bit) {
  716. $arr[] = $bit;
  717. }
  718. }
  719. return $arr;
  720. }
  721. /**
  722. * Perform a bitwise AND from each bit in getEquipUpperList() on $bitmask
  723. * to determine which bits have been set.
  724. * @param int $bitmask
  725. * @return array
  726. */
  727. public static function equipUpperToArray($bitmask)
  728. {
  729. $arr = array();
  730. $bits = self::getEquipUpperList();
  731. foreach ($bits as $bit => $name) {
  732. if ($bitmask & $bit) {
  733. $arr[] = $bit;
  734. }
  735. }
  736. return $arr;
  737. }
  738. /**
  739. * Perform a bitwise AND from each bit in getEquipJobsList() on $bitmask
  740. * to determine which bits have been set.
  741. * @param int $bitmask
  742. * @return array
  743. */
  744. public static function equipJobsToArray($bitmask)
  745. {
  746. $arr = array();
  747. $bits = self::getEquipJobsList();
  748. foreach ($bits as $bit => $name) {
  749. if ($bitmask & $bit) {
  750. $arr[] = $bit;
  751. }
  752. }
  753. return $arr;
  754. }
  755. /**
  756. *
  757. */
  758. public static function monsterModeToArray($bitmask)
  759. {
  760. $arr = array();
  761. $bits = self::config('MonsterModes')->toArray();
  762. foreach ($bits as $bit => $name) {
  763. if ($bitmask & $bit) {
  764. $arr[] = $bit;
  765. }
  766. }
  767. return $arr;
  768. }
  769. /**
  770. *
  771. */
  772. public static function elementName($ele)
  773. {
  774. $neutral = Flux::config('Elements.0');
  775. $element = Flux::config("Elements.$ele");
  776. return is_null($element) ? $neutral : $element;
  777. }
  778. /**
  779. *
  780. */
  781. public static function monsterRaceName($race)
  782. {
  783. $race = Flux::config("MonsterRaces.$race");
  784. return $race;
  785. }
  786. }
  787. ?>