* added new tooltip to view characters equipment item name

* this requires loaded items - go to admin panel and select Items menu, then reload
* added items.xml loader class and weapons.xml loader class
* load also runes into spells table
* (internal) changed spells.vocations database field to store json data instead of comma separated
* (internal) renamed existing Items class to Items_Images
This commit is contained in:
slawkens 2017-10-19 17:11:49 +02:00
parent 23c1df72aa
commit 913b4297cf
17 changed files with 1297 additions and 298 deletions

View File

@ -43,6 +43,7 @@
'Statistics' => 'statistics',
'Visitors' => 'visitors',
'Players' => 'players',
'Items' => 'items',
'Tools' => array(
'phpinfo' => 'phpinfo'
),

View File

@ -28,7 +28,7 @@ session_start();
define('MYAAC', true);
define('MYAAC_VERSION', '0.6.1');
define('DATABASE_VERSION', 11);
define('DATABASE_VERSION', 12);
define('TABLE_PREFIX', 'myaac_');
define('START_TIME', microtime(true));
define('MYAAC_OS', (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? 'WINDOWS' : (strtoupper(PHP_OS) == 'DARWIN' ? 'MAC' : 'LINUX'));

View File

@ -128,6 +128,16 @@ CREATE TABLE `myaac_hooks`
PRIMARY KEY (`id`)
) ENGINE = MyISAM;
CREATE TABLE `myaac_items`
(
`id` INT(11) NOT NULL,
`article` VARCHAR(5) NOT NULL DEFAULT '',
`name` VARCHAR(50) NOT NULL DEFAULT '',
`plural` VARCHAR(50) NOT NULL DEFAULT '',
`attributes` VARCHAR(500) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE = MyISAM;
CREATE TABLE `myaac_monsters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hide_creature` tinyint(1) NOT NULL default '0',
@ -235,17 +245,18 @@ CREATE TABLE `myaac_spells`
`name` VARCHAR(255) NOT NULL,
`words` VARCHAR(255) NOT NULL,
`category` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - attack, 2 - healing, 3 - summon, 4 - supply, 5 - support',
`type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - instant, 2 - rune',
`type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - instant, 2 - conjure, 3 - rune',
`level` INT(11) NOT NULL DEFAULT 0,
`maglevel` INT(11) NOT NULL DEFAULT 0,
`mana` INT(11) NOT NULL DEFAULT 0,
`soul` TINYINT(3) NOT NULL DEFAULT 0,
`conjure_count` TINYINT(3) NOT NULL DEFAULT 0,
`item_id` INT(11) NOT NULL DEFAULT 0,
`premium` TINYINT(1) NOT NULL DEFAULT 0,
`vocations` VARCHAR(32) NOT NULL,
`vocations` VARCHAR(100) NOT NULL DEFAULT '',
`hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE (`spell`)
UNIQUE (`name`)
) ENGINE = MyISAM;
CREATE TABLE `myaac_visitors`
@ -255,3 +266,12 @@ CREATE TABLE `myaac_visitors`
`page` VARCHAR(100) NOT NULL,
UNIQUE (`ip`)
) ENGINE = MyISAM;
CREATE TABLE `myaac_weapons`
(
`id` INT(11) NOT NULL,
`level` INT(11) NOT NULL DEFAULT 0,
`maglevel` INT(11) NOT NULL DEFAULT 0,
`vocations` VARCHAR(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE = MyISAM;

View File

@ -119,12 +119,21 @@ function getGuildLink($name, $generate = true)
function getItemImage($id, $count = 1)
{
global $db;
$tooltip = '';
$query = $db->query('SELECT `name` FROM `' . TABLE_PREFIX . 'items` WHERE `id` = ' . $db->quote($id) . ' LIMIT 1;');
if($query->rowCount() == 1) {
$item = $query->fetch();
$tooltip = ' class="tooltip" title="' . $item['name'] . '"';
}
$file_name = $id;
if($count > 1)
$file_name .= '-' . $count;
global $config;
return '<img src="' . $config['item_images_url'] . $file_name . '.gif" width="32" height="32" border="0" alt=" ' .$id . '" />';
return '<img src="' . $config['item_images_url'] . $file_name . '.gif"' . $tooltip . ' width="32" height="32" border="0" alt=" ' .$id . '" />';
}
function getFlagImage($country)

View File

@ -9,17 +9,17 @@
* @link http://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
require_once(SYSTEM . 'libs/items.php');
require_once(SYSTEM . 'libs/items_images.php');
Items::$files = array(
Items_Images::$files = array(
'otb' => SYSTEM . 'data/items.otb',
'spr' => SYSTEM . 'data/Tibia.spr',
'dat' => SYSTEM . 'data/Tibia.dat'
);
Items::$outputDir = BASE . 'images/items/';
Items_Images::$outputDir = BASE . 'images/items/';
function generateItem($id = 100, $count = 1) {
Items::generate($id, $count);
Items_Images::generate($id, $count);
}
function itemImageExists($id, $count = 1)
@ -31,7 +31,7 @@ function itemImageExists($id, $count = 1)
if($count > 1)
$file_name .= '-' . $count;
$file_name = Items::$outputDir . $file_name . '.gif';
$file_name = Items_Images::$outputDir . $file_name . '.gif';
return file_exists($file_name);
}
@ -43,7 +43,7 @@ function outputItem($id = 100, $count = 1)
if(!itemImageExists($id, $count))
{
//echo 'plik istnieje';
Items::generate($id, $count);
Items_Images::generate($id, $count);
}
$expires = 60 * 60 * 24 * 30; // 30 days
@ -56,7 +56,7 @@ function outputItem($id = 100, $count = 1)
if($count > 1)
$file_name .= '-' . $count;
$file_name = Items::$outputDir . $file_name . '.gif';
$file_name = Items_Images::$outputDir . $file_name . '.gif';
readfile($file_name);
}
?>

View File

@ -3,6 +3,7 @@
* Items class
*
* @package MyAAC
* @author Gesior <jerzyskalski@wp.pl>
* @author Slawkens <slawkens@gmail.com>
* @copyright 2017 MyAAC
* @version 0.6.1
@ -10,257 +11,135 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
if ( !function_exists( 'stackId' ) )
{
function stackId( $count )
class Items {
private static $error = '';
public static function loadFromXML($show = false)
{
if ( $count >= 50 )
$stack = 8;
elseif ( $count >= 25 )
$stack = 7;
elseif ( $count >= 10 )
$stack = 6;
elseif ( $count >= 5 )
$stack = 5;
elseif ( $count >= 4 )
$stack = 4;
elseif ( $count >= 3 )
$stack = 3;
elseif ( $count >= 2 )
$stack = 2;
else
$stack = 1;
global $config, $db;
return $stack;
}
}
class Items
{
public static $outputDir = '';
public static $files = array();
private static $otb, $dat, $spr;
private static $lastItem;
private static $loaded = false;
public function __destruct()
{
if(self::$otb)
fclose(self::$otb);
if(self::$dat)
fclose(self::$dat);
if(self::$spr)
fclose(self::$spr);
try {
$db->query("DELETE FROM `myaac_items`;");
} catch (PDOException $error) {
}
public static function generate($id = 100, $count = 1)
{
if(!self::$loaded)
self::load();
$originalId = $id;
if($id < 100)
$file_path = $config['data_path'] . 'items/items.xml';
if (!file_exists($file_path)) {
self::$error = 'Cannot load file ' . $file_path;
return false;
//die('ID cannot be lower than 100.');
rewind(self::$otb);
rewind(self::$dat);
rewind(self::$spr);
$nostand = false;
$init = false;
$originalId = $id;
// parse info from otb
while( false !== ( $char = fgetc( self::$otb ) ) )
{
$byte = HEX_PREFIX.bin2hex( $char );
if ( $byte == 0xFE )
$init = true;
elseif ( $byte == 0x10 and $init ) {
extract( unpack( 'x2/Ssid', fread( self::$otb, 4 ) ) );
if ( $id == $sid ) {
if ( HEX_PREFIX.bin2hex( fread( self::$otb, 1 ) ) == 0x11 ) {
extract( unpack( 'x2/Sid', fread( self::$otb, 4 ) ) );
break;
}
}
$init = false;
}
}
self::$lastItem = array_sum( unpack( 'x4/S*', fread( self::$dat, 12 )));
if($id > self::$lastItem)
return false;
$xml = new DOMDocument;
$xml->load($file_path);
//ini_set('max_execution_time', 300);
// parse info from dat
for( $i = 100; $i <= $id; $i++ ) {
while( ( $byte = HEX_PREFIX.bin2hex( fgetc( self::$dat ) ) ) != 0xFF ) {
$offset = 0;
switch( $byte ) {
case 0x00:
case 0x09:
case 0x0A:
case 0x1A:
case 0x1D:
case 0x1E:
$offset = 2;
break;
foreach ($xml->getElementsByTagName('item') as $item) {
if ($item->getAttribute('fromid')) {
for ($id = $item->getAttribute('fromid'); $id <= $item->getAttribute('toid'); $id++) {
self::parseNode($id, $item, $show);
}
} else
self::parseNode($item->getAttribute('id'), $item, $show);
case 0x16:
case 0x19:
$offset = 4;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x17:
case 0x18:
case 0x1B:
case 0x1C:
case 0x1F:
case 0x20:
break;
default:
return false; #trigger_error( sprintf( 'Unknown .DAT byte %s (previous byte: %s; address %x)', $byte, $prev, ftell( $dat ), E_USER_ERROR ) );
break;
}
$prev = $byte;
fseek( self::$dat, $offset, SEEK_CUR );
}
extract( unpack( 'Cwidth/Cheight', fread( self::$dat, 2 ) ) );
if ( $width > 1 or $height > 1 ) {
fseek( self::$dat, 1, SEEK_CUR );
$nostand = true;
return true;
}
$sprites_c = array_product( unpack( 'C*', fread( self::$dat, 5 ) ) ) * $width * $height;
$sprites = unpack( 'S*', fread( self::$dat, 2 * $sprites_c ) );
public static function parseNode($id, $node, $show = false) {
global $db;
$name = $node->getAttribute('name');
$article = $node->getAttribute('article');
$plural = $node->getAttribute('plural');
$attributes = array();
foreach($node->getElementsByTagName('attribute') as $attr) {
$attributes[strtolower($attr->getAttribute('key'))] = $attr->getAttribute('value');
}
if ( array_key_exists( stackId( $count ), $sprites ) ) {
$sprites = (array) $sprites[stackId( $count )];
$exist = $db->query('SELECT `id` FROM `' . TABLE_PREFIX . 'items` WHERE `id` = ' . $id);
if($exist->rowCount() > 0) {
if($show) {
warning('Duplicated item with id: ' . $id);
}
}
else {
$sprites = (array) $sprites[array_rand( $sprites ) ];
}
fseek( self::$spr, 6 );
$sprite = imagecreatetruecolor( 32 * $width, 32 * $height );
imagecolortransparent( $sprite, imagecolorallocate( $sprite, 0, 0, 0 ) );
foreach( $sprites as $key => $value ) {
fseek( self::$spr, 6 + ( $value - 1 ) * 4 );
extract( unpack( 'Laddress', fread( self::$spr, 4 ) ) );
fseek( self::$spr, $address + 3 );
extract( unpack( 'Ssize', fread( self::$spr, 2 ) ) );
list( $num, $bit ) = array( 0, 0 );
while( $bit < $size ) {
$pixels = unpack( 'Strans/Scolored', fread( self::$spr, 4 ) );
$num += $pixels['trans'];
for( $i = 0; $i < $pixels['colored']; $i++ )
{
extract( unpack( 'Cred/Cgreen/Cblue', fread( self::$spr, 3 ) ) );
$red = ( $red == 0 ? ( $green == 0 ? ( $blue == 0 ? 1 : $red ) : $red ) : $red );
imagesetpixel( $sprite,
$num % 32 + ( $key % 2 == 1 ? 32 : 0 ),
$num / 32 + ( $key % 4 != 1 and $key % 4 != 0 ? 32 : 0 ),
imagecolorallocate( $sprite, $red, $green, $blue ) );
$num++;
}
$bit += 4 + 3 * $pixels['colored'];
$db->insert(TABLE_PREFIX . 'items', array('id' => $id, 'article' => $article, 'name' => $name, 'plural' => $plural, 'attributes' => json_encode($attributes)));
}
}
if ( $count >= 2 ) {
if ( $count > 100 )
$count = 100;
$font = 3;
$length = imagefontwidth( $font ) * strlen( $count );
$pos = array(
'x' => ( 32 * $width ) - ( $length + 1 ),
'y' => ( 32 * $height ) - 13
);
imagestring( $sprite, $font, $pos['x'] - 1, $pos['y'] - 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'], $pos['y'] - 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'] - 1, $pos['y'], $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'], $pos['y'] + 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'] + 1, $pos['y'], $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'] + 1, $pos['y'] + 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'], $pos['y'], $count, imagecolorallocate( $sprite, 219, 219, 219 ) );
public static function getError() {
return self::$error;
}
$imagePath = self::$outputDir . ($count > 1 ? $originalId . '-' . $count : $originalId ) . '.gif';
public static function getItem($id) {
global $db;
// save image
imagegif($sprite, $imagePath);
$item = $db->select(TABLE_PREFIX . 'items', array('id' => $id));
$item['attributes'] = json_decode($item['attributes']);
return $item;
}
public static function load()
{
if(!defined( 'HEX_PREFIX'))
define('HEX_PREFIX', '0x');
public static function getDescription($id, $count = 1) {
global $config, $db;
self::$otb = fopen(self::$files['otb'], 'rb');
self::$dat = fopen(self::$files['dat'], 'rb');
self::$spr = fopen(self::$files['spr'], 'rb');
$item = self::getItem($id);
if(!self::$otb || !self::$dat || !self::$spr)
die('ERROR: Cannot load data files.');
/*
if ( $nostand )
{
for( $i = 0; $i < sizeof( $sprites ) / 4; $i++ )
{
$sprites = array_merge( (array) $sprites, array_reverse( array_slice( $sprites, $i * 4, 4 ) ) );
$attr = $item['attributes'];
$s = '';
if(!empty($item['name'])) {
if($count > 1) {
if($attr['showcount']) {
$s .= $count . ' ';
}
if(!empty($item['plural'])) {
$s .= $item['plural'];
}
else if((int)$attr['showcount'] == 0) {
$s .= $item['name'];
}
else {
$s .= $item['name'] . 's';
}
}
else {
if(!empty($item['aticle'])) {
$s .= $item['article'] . ' ';
}
$s .= $item['name'];
}
}
else
{
$sprites = (array) $sprites[array_rand( $sprites ) ];
}
*/
$s .= 'an item of type ' . $item['id'];
self::$loaded = true;
if(strtolower($attr['type']) == 'rune') {
$query = $db->query('SELECT `level`, `maglevel`, `vocations` FROM `' . TABLE_PREFIX . 'spells` WHERE `item_id` = ' . $id);
if($query->rowCount() == 1) {
$query = $query->fetch();
if($query['level'] > 0 && $query['maglevel'] > 0) {
$s .= '. ' . ($count > 1 ? "They" : "It") . ' can only be used by ';
}
public static function loaded() {
return self::$loaded;
if(!empty(trim($query['vocations']))) {
$vocations = json_decode($query['vocations']);
if(count($vocations) > 0) {
foreach($vocations as $voc => $show) {
$vocations[$config['vocations'][$voc]] = $show;
}
}
}
else {
$s .= 'players';
}
$s .= ' with';
}
}
return $s;
}
}

View File

@ -0,0 +1,266 @@
<?php
/**
* Items_Images class
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2017 MyAAC
* @version 0.6.1
* @link http://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
if ( !function_exists( 'stackId' ) )
{
function stackId( $count )
{
if ( $count >= 50 )
$stack = 8;
elseif ( $count >= 25 )
$stack = 7;
elseif ( $count >= 10 )
$stack = 6;
elseif ( $count >= 5 )
$stack = 5;
elseif ( $count >= 4 )
$stack = 4;
elseif ( $count >= 3 )
$stack = 3;
elseif ( $count >= 2 )
$stack = 2;
else
$stack = 1;
return $stack;
}
}
class Items_Images
{
public static $outputDir = '';
public static $files = array();
private static $otb, $dat, $spr;
private static $lastItem;
private static $loaded = false;
public function __destruct()
{
if(self::$otb)
fclose(self::$otb);
if(self::$dat)
fclose(self::$dat);
if(self::$spr)
fclose(self::$spr);
}
public static function generate($id = 100, $count = 1)
{
if(!self::$loaded)
self::load();
$originalId = $id;
if($id < 100)
return false;
//die('ID cannot be lower than 100.');
rewind(self::$otb);
rewind(self::$dat);
rewind(self::$spr);
$nostand = false;
$init = false;
$originalId = $id;
// parse info from otb
while( false !== ( $char = fgetc( self::$otb ) ) )
{
$byte = HEX_PREFIX.bin2hex( $char );
if ( $byte == 0xFE )
$init = true;
elseif ( $byte == 0x10 and $init ) {
extract( unpack( 'x2/Ssid', fread( self::$otb, 4 ) ) );
if ( $id == $sid ) {
if ( HEX_PREFIX.bin2hex( fread( self::$otb, 1 ) ) == 0x11 ) {
extract( unpack( 'x2/Sid', fread( self::$otb, 4 ) ) );
break;
}
}
$init = false;
}
}
self::$lastItem = array_sum( unpack( 'x4/S*', fread( self::$dat, 12 )));
if($id > self::$lastItem)
return false;
//ini_set('max_execution_time', 300);
// parse info from dat
for( $i = 100; $i <= $id; $i++ ) {
while( ( $byte = HEX_PREFIX.bin2hex( fgetc( self::$dat ) ) ) != 0xFF ) {
$offset = 0;
switch( $byte ) {
case 0x00:
case 0x09:
case 0x0A:
case 0x1A:
case 0x1D:
case 0x1E:
$offset = 2;
break;
case 0x16:
case 0x19:
$offset = 4;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x17:
case 0x18:
case 0x1B:
case 0x1C:
case 0x1F:
case 0x20:
break;
default:
return false; #trigger_error( sprintf( 'Unknown .DAT byte %s (previous byte: %s; address %x)', $byte, $prev, ftell( $dat ), E_USER_ERROR ) );
break;
}
$prev = $byte;
fseek( self::$dat, $offset, SEEK_CUR );
}
extract( unpack( 'Cwidth/Cheight', fread( self::$dat, 2 ) ) );
if ( $width > 1 or $height > 1 ) {
fseek( self::$dat, 1, SEEK_CUR );
$nostand = true;
}
$sprites_c = array_product( unpack( 'C*', fread( self::$dat, 5 ) ) ) * $width * $height;
$sprites = unpack( 'S*', fread( self::$dat, 2 * $sprites_c ) );
}
if ( array_key_exists( stackId( $count ), $sprites ) ) {
$sprites = (array) $sprites[stackId( $count )];
}
else {
$sprites = (array) $sprites[array_rand( $sprites ) ];
}
fseek( self::$spr, 6 );
$sprite = imagecreatetruecolor( 32 * $width, 32 * $height );
imagecolortransparent( $sprite, imagecolorallocate( $sprite, 0, 0, 0 ) );
foreach( $sprites as $key => $value ) {
fseek( self::$spr, 6 + ( $value - 1 ) * 4 );
extract( unpack( 'Laddress', fread( self::$spr, 4 ) ) );
fseek( self::$spr, $address + 3 );
extract( unpack( 'Ssize', fread( self::$spr, 2 ) ) );
list( $num, $bit ) = array( 0, 0 );
while( $bit < $size ) {
$pixels = unpack( 'Strans/Scolored', fread( self::$spr, 4 ) );
$num += $pixels['trans'];
for( $i = 0; $i < $pixels['colored']; $i++ )
{
extract( unpack( 'Cred/Cgreen/Cblue', fread( self::$spr, 3 ) ) );
$red = ( $red == 0 ? ( $green == 0 ? ( $blue == 0 ? 1 : $red ) : $red ) : $red );
imagesetpixel( $sprite,
$num % 32 + ( $key % 2 == 1 ? 32 : 0 ),
$num / 32 + ( $key % 4 != 1 and $key % 4 != 0 ? 32 : 0 ),
imagecolorallocate( $sprite, $red, $green, $blue ) );
$num++;
}
$bit += 4 + 3 * $pixels['colored'];
}
}
if ( $count >= 2 ) {
if ( $count > 100 )
$count = 100;
$font = 3;
$length = imagefontwidth( $font ) * strlen( $count );
$pos = array(
'x' => ( 32 * $width ) - ( $length + 1 ),
'y' => ( 32 * $height ) - 13
);
imagestring( $sprite, $font, $pos['x'] - 1, $pos['y'] - 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'], $pos['y'] - 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'] - 1, $pos['y'], $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'], $pos['y'] + 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'] + 1, $pos['y'], $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'] + 1, $pos['y'] + 1, $count, imagecolorallocate( $sprite, 1, 1, 1 ) );
imagestring( $sprite, $font, $pos['x'], $pos['y'], $count, imagecolorallocate( $sprite, 219, 219, 219 ) );
}
$imagePath = self::$outputDir . ($count > 1 ? $originalId . '-' . $count : $originalId ) . '.gif';
// save image
imagegif($sprite, $imagePath);
}
public static function load()
{
if(!defined( 'HEX_PREFIX'))
define('HEX_PREFIX', '0x');
self::$otb = fopen(self::$files['otb'], 'rb');
self::$dat = fopen(self::$files['dat'], 'rb');
self::$spr = fopen(self::$files['spr'], 'rb');
if(!self::$otb || !self::$dat || !self::$spr)
die('ERROR: Cannot load data files.');
/*
if ( $nostand )
{
for( $i = 0; $i < sizeof( $sprites ) / 4; $i++ )
{
$sprites = array_merge( (array) $sprites, array_reverse( array_slice( $sprites, $i * 4, 4 ) ) );
}
}
else
{
$sprites = (array) $sprites[array_rand( $sprites ) ];
}
*/
self::$loaded = true;
}
public static function loaded() {
return self::$loaded;
}
}

View File

@ -315,19 +315,50 @@ class OTS_Spell
*/
public function getVocations()
{
global $config;
if(!isset($config['vocation_ids']))
$config['vocations_ids'] = array_flip($config['vocations']);
$vocations = array();
foreach( $this->element->getElementsByTagName('vocation') as $vocation)
{
if($vocation->getAttribute('id') != NULL)
$vocations[] = $vocation->getAttribute('id');
else
$vocations[] = $vocation->getAttribute('name');
if($vocation->getAttribute('id') != NULL) {
$voc_id = $vocation->getAttribute('id');
}
else {
$voc_id = $config['vocations_ids'][$vocation->getAttribute('name')];
}
$vocations[] = $voc_id;
}
return $vocations;
}
public function getVocationsFull()
{
global $config;
if(!isset($config['vocation_ids']))
$config['vocations_ids'] = array_flip($config['vocations']);
$vocations = array();
foreach( $this->element->getElementsByTagName('vocation') as $vocation)
{
$show = $vocation->getAttribute('showInDescription');
if($vocation->getAttribute('id') != NULL) {
$voc_id = $vocation->getAttribute('id');
}
else {
$voc_id = $config['vocations_ids'][$vocation->getAttribute('name')];
}
$vocations[$voc_id] = strlen($show) == 0 || $show != '0';
}
return $vocations;
}
/**
* Creates conjure item.
*

View File

@ -50,22 +50,8 @@ class Spells {
$name = $spell->getName();
$soul = $spell->getSoul();
$spell_txt = $spell->getWords();
$vocations = $spell->getVocations();
$nr_of_vocations = count($vocations);
$vocations_to_db = "";
$voc_nr = 0;
foreach($vocations as $vocation_to_add) {
if(Validator::number($vocation_to_add)) {
$vocations_to_db .= $vocation_to_add;
}
else
$vocations_to_db .= $vocations_ids[$vocation_to_add];
$voc_nr++;
if($voc_nr != $nr_of_vocations) {
$vocations_to_db .= ',';
}
}
$vocations = $spell->getVocations();
$enabled = $spell->isEnabled();
if($enabled) {
@ -84,7 +70,7 @@ class Spells {
$type = 2;
$count = $spell->getConjureCount();
try {
$db->query('INSERT INTO myaac_spells (spell, name, words, type, mana, level, maglevel, soul, premium, vocations, conjure_count, hidden) VALUES (' . $db->quote($spell_txt) . ', ' . $db->quote($name) . ', ' . $db->quote($spell_txt) . ', ' . $db->quote($type) . ', ' . $db->quote($mana) . ', ' . $db->quote($lvl) . ', ' . $db->quote($mlvl) . ', ' . $db->quote($soul) . ', ' . $db->quote($pacc) . ', ' . $db->quote($vocations_to_db) . ', ' . $db->quote($count) . ', ' . $db->quote($hide_spell) . ')');
$db->query('INSERT INTO myaac_spells (spell, name, words, type, mana, level, maglevel, soul, premium, vocations, conjure_count, hidden) VALUES (' . $db->quote($spell_txt) . ', ' . $db->quote($name) . ', ' . $db->quote($spell_txt) . ', ' . $db->quote($type) . ', ' . $db->quote($mana) . ', ' . $db->quote($lvl) . ', ' . $db->quote($mlvl) . ', ' . $db->quote($soul) . ', ' . $db->quote($pacc) . ', ' . $db->quote(json_encode($vocations)) . ', ' . $db->quote($count) . ', ' . $db->quote($hide_spell) . ')');
if($show) {
success("Added: " . $name . "<br>");
}
@ -114,21 +100,7 @@ class Spells {
continue;
$vocations = $spell->getVocations();
$nr_of_vocations = count($vocations);
$vocations_to_db = "";
$voc_nr = 0;
foreach($vocations as $vocation_to_add) {
if(Validator::number($vocation_to_add)) {
$vocations_to_db .= $vocation_to_add;
}
else
$vocations_to_db .= $vocations_ids[$vocation_to_add];
$voc_nr++;
if($voc_nr != $nr_of_vocations) {
$vocations_to_db .= ',';
}
}
$enabled = $spell->isEnabled();
if($enabled) {
$hide_spell = 0;
@ -145,8 +117,10 @@ class Spells {
}
$type = 1;
$count = 0;
try {
$db->query("INSERT INTO myaac_spells (spell, name, words, type, mana, level, maglevel, soul, premium, vocations, conjure_count, hidden) VALUES (".$db->quote($spell_txt).", ".$db->quote($name).", ".$db->quote($spell_txt).", '".$type."', '".$mana."', '".$lvl."', '".$mlvl."', '".$soul."', '".$pacc."', '".$vocations_to_db."', '".$count."', '".$hide_spell."')");
$db->query("INSERT INTO myaac_spells (spell, name, words, type, mana, level, maglevel, soul, premium, vocations, conjure_count, hidden) VALUES (".$db->quote($spell_txt).", ".$db->quote($name).", ".$db->quote($spell_txt).", '".$type."', '".$mana."', '".$lvl."', '".$mlvl."', '".$soul."', '".$pacc."', ".$db->quote(json_encode($vocations)).", '".$count."', '".$hide_spell."')");
if($show) {
success("Added: ".$name."<br/>");
}
@ -158,6 +132,53 @@ class Spells {
}
}
//add runes
$runeslist = self::$spellsList->getRunesList();
if($show) {
echo "<h3>Runes:</h3>";
}
// runes
foreach($runeslist as $spellname) {
$spell = self::$spellsList->getRune($spellname);
$lvl = $spell->getLevel();
$mlvl = $spell->getMagicLevel();
$mana = $spell->getMana();
$name = $spell->getName() . ' (rune)';
$soul = $spell->getSoul();
$spell_txt = $spell->getWords();
$vocations = $spell->getVocations();
$id = $spell->getID();
$enabled = $spell->isEnabled();
if($enabled) {
$hide_spell = 0;
}
else {
$hide_spell = 1;
}
$pacc = $spell->isPremium();
if($pacc) {
$pacc = '1';
}
else {
$pacc = '0';
}
$type = 3;
$count = $spell->getConjureCount();
try {
$db->query('INSERT INTO myaac_spells (spell, name, words, type, mana, level, maglevel, soul, premium, vocations, conjure_count, item_id, hidden) VALUES (' . $db->quote($spell_txt) . ', ' . $db->quote($name) . ', ' . $db->quote($spell_txt) . ', ' . $db->quote($type) . ', ' . $db->quote($mana) . ', ' . $db->quote($lvl) . ', ' . $db->quote($mlvl) . ', ' . $db->quote($soul) . ', ' . $db->quote($pacc) . ', ' . $db->quote(json_encode($vocations)) . ', ' . $db->quote($count) . ', ' . $db->quote($id) . ', ' . $db->quote($hide_spell) . ')');
if($show) {
success("Added: " . $name . "<br>");
}
}
catch(PDOException $error) {
if($show) {
warning('Error while adding spell (' . $name . '): ' . $error->getMessage());
}
}
}
return true;
}

82
system/libs/weapons.php Normal file
View File

@ -0,0 +1,82 @@
<?php
/**
* Weapons class
*
* @package MyAAC
* @author Gesior <jerzyskalski@wp.pl>
* @author Slawkens <slawkens@gmail.com>
* @copyright 2017 MyAAC
* @version 0.6.1
* @link http://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
class Weapons {
private static $error = '';
public static function loadFromXML($show = false)
{
global $config, $db;
try {
$db->query("DELETE FROM `myaac_weapons`;");
} catch (PDOException $error) {
}
$file_path = $config['data_path'] . 'weapons/weapons.xml';
if (!file_exists($file_path)) {
self::$error = 'Cannot load file ' . $file_path;
return false;
}
$xml = new DOMDocument;
$xml->load($file_path);
foreach ($xml->getElementsByTagName('wand') as $weapon) {
self::parseNode($weapon, $show);
}
foreach ($xml->getElementsByTagName('melee') as $weapon) {
self::parseNode($weapon, $show);
}
foreach ($xml->getElementsByTagName('distance') as $weapon) {
self::parseNode($weapon, $show);
}
return true;
}
public static function parseNode($node, $show = false) {
global $config, $db;
$id = (int)$node->getAttribute('id');
$vocations_ids = array_flip($config['vocations']);
$level = (int)$node->getAttribute('level');
$maglevel = (int)$node->getAttribute('maglevel');
$vocations = array();
foreach($node->getElementsByTagName('vocation') as $vocation) {
$show = $vocation->getAttribute('showInDescription');
if(!empty($vocation->getAttribute('id')))
$voc_id = $vocation->getAttribute('id');
else {
$voc_id = $vocations_ids[$vocation->getAttribute('name')];
}
$vocations[$voc_id] = strlen($show) == 0 || $show != '0';
}
$exist = $db->query('SELECT `id` FROM `' . TABLE_PREFIX . 'weapons` WHERE `id` = ' . $id);
if($exist->rowCount() > 0) {
if($show) {
warning('Duplicated weapon with id: ' . $id);
}
}
else {
$db->insert(TABLE_PREFIX . 'weapons', array('id' => $id, 'level' => $level, 'maglevel' => $maglevel, 'vocations' => json_encode($vocations)));
}
}
public static function getError() {
return self::$error;
}
}

49
system/migrations/12.php Normal file
View File

@ -0,0 +1,49 @@
<?php
// add new item_id field for runes
if(!fieldExist('item_id', TABLE_PREFIX . 'spells'))
$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` ADD `item_id` INT(11) NOT NULL DEFAULT 0 AFTER `conjure_count`;");
// change unique index from spell to name
$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` DROP INDEX `spell`;");
$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` ADD UNIQUE INDEX (`name`);");
// change comment of spells.type
$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` MODIFY `type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - instant, 2 - conjure, 3 - rune';");
// new items table
if(!tableExist(TABLE_PREFIX . 'items'))
$db->query("
CREATE TABLE `" . TABLE_PREFIX . "items`
(
`id` INT(11) NOT NULL,
`article` VARCHAR(5) NOT NULL DEFAULT '',
`name` VARCHAR(50) NOT NULL DEFAULT '',
`plural` VARCHAR(50) NOT NULL DEFAULT '',
`attributes` VARCHAR(500) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE = MyISAM;");
// new weapons table
if(!tableExist(TABLE_PREFIX . 'weapons'))
$db->query("
CREATE TABLE `" . TABLE_PREFIX . "weapons`
(
`id` INT(11) NOT NULL,
`level` INT(11) NOT NULL DEFAULT 0,
`maglevel` INT(11) NOT NULL DEFAULT 0,
`vocations` VARCHAR(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE = MyISAM;");
// modify vocations to support json data
$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` MODIFY `vocations` VARCHAR(100) NOT NULL DEFAULT '';");
$query = $db->query('SELECT `id`, `vocations` FROM `' . TABLE_PREFIX . 'spells`');
foreach($query->fetchAll() as $spell) {
$tmp = explode(',', $spell['vocations']);
foreach($tmp as &$v) {
$v = (int)$v;
}
$db->update(TABLE_PREFIX . 'spells', array('vocations' => json_encode($tmp)), array('id' => $spell['id']));
}
?>

View File

@ -0,0 +1,31 @@
<?php
/**
* Load items.xml
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2017 MyAAC
* @version 0.6.1
* @link http://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Load items.xml';
require(LIBS . 'items.php');
require(LIBS . 'weapons.php');
echo $twig->render('admin.items.html.twig');
$reload = isset($_REQUEST['reload']) && (int)$_REQUEST['reload'] == 1;
if($reload) {
if(Items::loadFromXML(true))
success('Successfully loaded items.');
else
error(Items::getError());
if(Weapons::loadFromXML(true))
success('Successfully loaded weapons.');
else
error(Weapons::getError());
}

View File

@ -111,19 +111,21 @@ if(!in_array($order, array('spell', 'words', 'type', 'mana', 'level', 'maglevel'
<?php
$i = 0;
$spells = $db->query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'spells') . ' WHERE ' . $db->fieldName('hidden') . ' != 1 ORDER BY ' . $order . ', level');
$spells = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'spells` WHERE `hidden` != 1 AND `type` < 3 ORDER BY ' . $order . ', level');
if(isset($vocation_id) && $vocation_id != 'All' && $vocation_id != '')
{
foreach($spells as $spell)
{
$spell_vocations = explode(",", $spell['vocations']);
if(in_array($vocation_id, $spell_vocations) || empty($spell['vocations']))
$spell_vocations = json_decode($spell['vocations'], true);
if(in_array($vocation_id, $spell_vocations) || count($spell_vocations) == 0)
{
echo '<TR BGCOLOR="' . getStyle(++$i) . '"><TD>' . $spell['name'] . '</TD><TD>' . $spell['words'] . '</TD>';
if($spell['type'] == 2)
if($spell['type'] == 1)
echo '<TD>Instant</TD>';
else if($spell['type'] == 2)
echo '<TD>Conjure ('.$spell['conjure_count'].')</TD>';
else
echo '<TD>Instant</TD>';
echo '<TD>Rune</TD>';
echo '<TD>' . $spell['mana'] . '</TD><TD>' . $spell['level'] . '</TD><TD>' . $spell['maglevel'] . '</TD><TD>' . $spell['soul'] . '</TD><TD>' . ($spell ['premium'] == 1 ? 'yes' : 'no') . '</TD><TD>' . $config['vocations'][$vocation_id] . '</TD></TR>';
}
@ -133,13 +135,15 @@ else
{
foreach($spells as $spell)
{
$spell_vocations = explode(",", $spell['vocations']);
$spell_vocations = json_decode($spell['vocations'], true);
echo '<TR BGCOLOR="' . getStyle(++$i) . '"><TD>' .$spell['name'] . '</TD><TD>' . $spell['words'] . '</TD>';
if($spell['type'] == 1)
echo '<TD>Instant</TD>';
else
else if($spell['type'] == 2)
echo '<TD>Conjure ('.$spell['conjure_count'].')</TD>';
else
echo '<TD>Rune</TD>';
echo '<TD>' . $spell['mana'] . '</TD><TD>' . $spell['level'] . '</TD><TD>' . $spell['maglevel'] . '</TD><TD>' . $spell['soul'] . '</TD><TD>'. ($spell ['premium'] == 1 ? 'yes' : 'no') .'</TD><TD><font size="1">';

View File

@ -0,0 +1,4 @@
<form method="post" action="{{ constant('ADMIN_URL') }}?p=items">
<input type="hidden" name="reload" value="1" />
<input type="submit" value="Reload items and weapons (it may take some time to finish)" />
</form>

View File

@ -1,3 +1,10 @@
<script type="text/javascript" src="tools/tipped.js"></script>
<link rel="stylesheet" type="text/css" href="tools/tipped.css"/>
<script>
$(document).ready(function() {
Tipped.create('.tooltip');
});
</script>
{% set rows = 0 %}
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr>
<td><img src="<{{ template_path }}/images/general/blank.gif" width="10" height="1" border="0"></td>
@ -145,6 +152,7 @@
<table border="0" width="100%">
<tr>
{% if config.characters.skills %}
<!-- SKILLS -->
<td width="30%" valign="top">
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder }}">
@ -160,9 +168,11 @@
{% endfor %}
</table>
</td>
<!-- SKILLS_END -->
{% endif %}
{% if quests_enabled %}
<!-- QUESTS -->
<td width="40%" valign="top">
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder }}">
@ -178,9 +188,11 @@
{% endfor %}
</table>
</td>
<!-- QUESTS_END -->
{% endif %}
{% if config.characters.equipment %}
<!-- EQUIPMENT -->
<td width="100" valign="top">
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder}}">
@ -212,11 +224,13 @@
</tr>
</table>
</td>
<!-- EQUIPMENT_END -->
{% endif %}
</tr>
</table>
{% if deaths|length > 0 %}
<!-- DEATHS -->
<br/>
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder }}">
@ -231,8 +245,10 @@
{% set i = i + 1 %}
{% endfor %}
<!-- DEATHS_END -->
{% endif %}
{% if frags|length > 0 %}
<!-- FRAGS -->
<br/>
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder }}">
@ -246,11 +262,13 @@
</tr>
{% endfor %}
</table>
<!-- FRAGS_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_BEFORE_SIGNATURE')) }}
{% if config.signature_enabled %}
<!-- SIGNATURE -->
<script type="text/javascript">
function showSignLinks()
{
@ -289,10 +307,12 @@
</table>
</td></tr>
</table>
<!-- SIGNATURE_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_SIGNATURE')) }}
{% if hidden != 1 %}
{% set rows = 0 %}
<!-- ACCOUNT_INFORMATION -->
<br/><br/>
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder }}">
@ -338,7 +358,9 @@
</td>
</tr>
</table>
<!-- ACCOUNT_INFORMATION_END -->
{{ hook(constant('HOOK_CHARACTERS_AFTER_ACCOUNT')) }}
<!-- CHARACTERS_LIST -->
<br/><br/>
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tr bgcolor="{{ config.vdarkborder }}">
@ -381,6 +403,7 @@
{% endif %}
{% endfor %}
</table>
<!-- CHARACTERS_LIST_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_CHARACTERS')) }}
</td>

568
tools/tipped.css Executable file
View File

@ -0,0 +1,568 @@
/*
* Tipped - A Complete Javascript Tooltip Solution - v4.6.1
* (c) 2012-2017 Nick Stakenburg
*
* http://www.tippedjs.com
*
* License: http://www.tippedjs.com/license
*/
.tpd-tooltip {
position: absolute;
}
/* Fix for CSS frameworks that don't keep the use of box-sizing: border-box
within their own namespace */
.tpd-tooltip { box-sizing: content-box; }
.tpd-tooltip [class^="tpd-"] { box-sizing: inherit; }
/* Content */
.tpd-content-wrapper {
position: absolute;
top: 0;
left: 0;
float: left;
width: 100%;
height: 100%;
overflow: hidden;
}
.tpd-content-spacer,
.tpd-content-relative,
.tpd-content-relative-padder {
float: left;
position: relative;
}
.tpd-content-relative {
width: 100%;
}
.tpd-content {
float: left;
clear: both;
position: relative;
padding: 10px;
font-size: 11px;
line-height: 16px;
color: #fff;
box-sizing: border-box !important;
}
.tpd-has-inner-close .tpd-content-relative .tpd-content { padding-right: 0 !important; }
.tpd-tooltip .tpd-content-no-padding { padding: 0 !important; }
.tpd-title-wrapper {
float: left;
position: relative;
overflow: hidden;
}
.tpd-title-spacer {
float: left;
}
.tpd-title-relative,
.tpd-title-relative-padder {
float: left;
position: relative;
}
.tpd-title-relative { width: 100%; }
.tpd-title {
float: left;
position: relative;
font-size: 11px;
line-height: 16px;
padding: 10px;
font-weight: bold;
text-transform: uppercase;
color: #fff;
box-sizing: border-box !important;
}
.tpd-has-title-close .tpd-title { padding-right: 0 !important; }
.tpd-close {
position: absolute;
top: 0;
right: 0;
width: 28px;
height: 28px;
cursor: pointer;
overflow: hidden;
color: #fff;
}
.tpd-close-icon {
float: left;
font-family: Arial, Baskerville, monospace;
font-weight: normal;
font-style: normal;
text-decoration: none;
width: 28px;
height: 28px;
font-size: 28px;
line-height: 28px;
text-align: center;
}
/* Skin */
.tpd-skin {
position: absolute;
top: 0;
left: 0;
}
.tpd-frames {
position: absolute;
top: 0;
left: 0;
}
.tpd-frames .tpd-frame {
float: left;
width: 100%;
height: 100%;
clear: both;
display: none;
}
.tpd-visible-frame-top .tpd-frame-top { display: block; }
.tpd-visible-frame-bottom .tpd-frame-bottom { display: block; }
.tpd-visible-frame-left .tpd-frame-left { display: block; }
.tpd-visible-frame-right .tpd-frame-right { display: block; }
.tpd-backgrounds {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-transform-origin: 0% 0%;
transform-origin: 0% 0%;
}
.tpd-background-shadow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
pointer-events: none;
}
.tpd-no-shadow .tpd-skin .tpd-background-shadow { box-shadow: none !important; }
.tpd-background-box {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
/* only the top background box should be shown when not using a stem */
.tpd-no-stem .tpd-background-box,
.tpd-no-stem .tpd-shift-stem { display: none; }
.tpd-no-stem .tpd-background-box-top { display: block; }
.tpd-background-box-shift,
.tpd-background-box-shift-further {
position: relative;
float: left;
width: 100%;
height: 100%;
}
.tpd-background {
border-radius: 10px;
float: left;
clear: both;
background: none;
-webkit-background-clip: padding-box; /* Safari */
background-clip: padding-box; /* IE9+, Firefox 4+, Opera, Chrome */
border-style: solid;
border-width: 1px;
border-color: rgba(255,255,255,.1); /* opacity here bugs out in firefox, .tpd-background-content should have no opacity if this opacity is less than 1 */
}
.tpd-background-loading { display: none; }
/* no radius */
.tpd-no-radius .tpd-skin .tpd-frames .tpd-frame .tpd-backgrounds .tpd-background { border-radius: 0; }
.tpd-background-title {
float: left;
clear: both;
width: 100%;
background-color: #282828;
}
.tpd-background-content {
float: left;
clear: both;
width: 100%;
background-color: #282828;
}
.tpd-background-border-hack {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-style: solid;
}
.tpd-background-box-top { top: 0; }
.tpd-background-box-bottom { bottom: 0; }
.tpd-background-box-left { left: 0; }
.tpd-background-box-right { right: 0; }
/* Skin / Stems */
.tpd-shift-stem {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
}
.tpd-shift-stem-side {
position: absolute;
}
.tpd-frame-top .tpd-shift-stem-side,
.tpd-frame-bottom .tpd-shift-stem-side { width: 100%; }
.tpd-frame-left .tpd-shift-stem-side,
.tpd-frame-right .tpd-shift-stem-side { height: 100%; }
.tpd-stem {
position: absolute;
top: 0;
left: 0;
overflow: hidden; /* shows possible invalid subpx rendering */
width: 16px; /* best cross browser stem: width = 2 x height (90deg angle) */
height: 8px;
margin-left: 3px; /* space from the side */
margin-top: 2px; /* space between target and stem */
-webkit-transform-origin: 0% 0%;
transform-origin: 0% 0%;
}
/* remove margins once we're done measuring */
.tpd-tooltip .tpd-skin .tpd-frames .tpd-frame .tpd-shift-stem .tpd-stem-reset { margin: 0 !important; }
.tpd-stem-spacer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.tpd-stem-reset .tpd-stem-spacer { margin-top: 0; }
.tpd-stem-point {
width: 100px;
position: absolute;
top: 0;
left: 50%;
}
.tpd-stem-downscale,
.tpd-stem-transform {
float: left;
width: 100%;
height: 100%;
-webkit-transform-origin: 0% 0%;
transform-origin: 0% 0%;
position: relative;
}
.tpd-stem-side {
width: 50%;
height: 100%;
float: left;
position: relative;
overflow: hidden;
}
.tpd-stem-side-inversed {
-webkit-transform: scale(-1,1);
transform: scale(-1,1);
}
.tpd-stem-triangle {
width: 0;
height: 0;
border-bottom-style: solid;
border-left-color: transparent;
border-left-style: solid;
position: absolute;
top: 0;
left: 0;
}
.tpd-stem-border {
width: 20px;
height: 100%;
position: absolute;
top: 0;
left: 50%;
background-color: #fff; /* will become transparent */
border-right-color: #fff;
border-right-style: solid;
border-right-width: 0;
}
.tpd-stem-border-corner {
position: absolute;
top: 0;
left: 50%;
height: 100%;
border-right-style: solid;
border-right-width: 0;
}
/* fixes rendering issue in IE */
.tpd-stem * { z-index: 0; zoom: 1; }
/* used by IE < 9 */
.tpd-stem-border-center-offset,
.tpd-stem-border-center-offset-inverse {
float: left;
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.tpd-stem-notransform {
float: left;
width: 100%;
height: 100%;
position: relative;
}
.tpd-stem-notransform .tpd-stem-border {
height: 100%;
position: relative;
float: left;
top: 0;
left: 0;
margin: 0;
}
.tpd-stem-notransform .tpd-stem-border-center {
position: absolute;
}
.tpd-stem-notransform .tpd-stem-border-corner {
background: #fff;
border: 0;
top: auto;
left: auto;
}
.tpd-stem-notransform .tpd-stem-border-center,
.tpd-stem-notransform .tpd-stem-triangle {
height: 0;
border: 0;
left: 50%;
}
/* transformations for left/right/bottom */
.tpd-stem-transform-left {
-webkit-transform: rotate(-90deg) scale(-1,1);
transform: rotate(-90deg) scale(-1,1);
}
.tpd-stem-transform-right {
-webkit-transform: rotate(90deg) translate(0, -100%);
transform: rotate(90deg) translate(0, -100%);
}
.tpd-stem-transform-bottom {
-webkit-transform: scale(1,-1) translate(0, -100%);
transform: scale(1,-1) translate(0, -100%);
}
/* Spinner */
.tpd-spinner {
position: absolute;
top: 50%;
left: 50%;
width: 46px;
height: 36px;
}
.tpd-spinner-spin {
position: relative;
float: left;
margin: 8px 0 0 13px;
text-indent: -9999em;
border-top: 2px solid rgba(255, 255, 255, 0.2);
border-right: 2px solid rgba(255, 255, 255, 0.2);
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
border-left: 2px solid #fff;
-webkit-animation: tpd-spinner-animation 1.1s infinite linear;
animation: tpd-spinner-animation 1.1s infinite linear;
box-sizing: border-box !important;
}
.tpd-spinner-spin,
.tpd-spinner-spin:after {
border-radius: 50%;
width: 20px;
height: 20px;
}
@-webkit-keyframes tpd-spinner-animation {
0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
}
@keyframes tpd-spinner-animation {
0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
}
/* show the loader while loading and hide all the content */
.tpd-is-loading .tpd-content-wrapper,
.tpd-is-loading .tpd-title-wrapper { display: none; }
.tpd-is-loading .tpd-background { display: none; }
.tpd-is-loading .tpd-background-loading { display: block; }
/* Resets while measuring content */
.tpd-tooltip-measuring {
top: 0;
left: 0;
position: absolute;
max-width: 100%;
width: 100%;
}
.tpd-tooltip-measuring .tpd-skin,
.tpd-tooltip-measuring .tpd-spinner {
display: none;
}
.tpd-tooltip-measuring .tpd-content-wrapper,
.tpd-tooltip-measuring .tpd-title-wrapper { display: block; }
/* Links */
.tpd-tooltip a,
.tpd-tooltip a:hover { color: #808080; text-decoration: underline; }
.tpd-tooltip a:hover { color: #6c6c6c; }
/*
* Sizes
*/
/* x-small */
.tpd-size-x-small .tpd-content,
.tpd-size-x-small .tpd-title {
padding: 7px 8px;
font-size: 10px;
line-height: 15px;
}
.tpd-size-x-small .tpd-background { border-radius: 5px; }
.tpd-size-x-small .tpd-stem {
width: 12px;
height: 6px;
margin-left: 4px;
margin-top: 2px; /* space between target and stem */
}
.tpd-size-x-small.tpd-no-radius .tpd-stem { margin-left: 7px; }
.tpd-size-x-small .tpd-close { margin-bottom: 1px; }
.tpd-size-x-small .tpd-spinner {
width: 35px;
height: 29px;
}
.tpd-size-x-small .tpd-spinner-spin { margin: 6px 0 0 9px; }
.tpd-size-x-small .tpd-spinner-spin,
.tpd-size-x-small .tpd-spinner-spin:after {
width: 17px;
height: 17px;
}
/* small */
.tpd-size-small .tpd-content,
.tpd-size-small .tpd-title {
padding: 8px;
font-size: 10px;
line-height: 16px;
}
.tpd-size-small .tpd-background { border-radius: 6px; }
.tpd-size-small .tpd-stem {
width: 14px;
height: 7px;
margin-left: 5px;
margin-top: 2px; /* space between target and stem */
}
.tpd-size-small.tpd-no-radius .tpd-stem { margin-left: 8px; }
.tpd-size-small .tpd-close { margin: 2px 1px; }
.tpd-size-small .tpd-spinner {
width: 42px;
height: 32px;
}
.tpd-size-small .tpd-spinner-spin { margin: 7px 0 0 13px; }
.tpd-size-small .tpd-spinner-spin,
.tpd-size-small .tpd-spinner-spin:after {
width: 18px;
height: 18px;
}
/* medium (default) */
.tpd-size-medium .tpd-content,
.tpd-size-medium .tpd-title {
padding: 10px;
font-size: 11px;
line-height: 16px;
}
.tpd-size-medium .tpd-background { border-radius: 8px; }
.tpd-size-medium .tpd-stem {
width: 16px; /* best cross browser stem width is 2xheight, for a 90deg angle */
height: 8px;
margin-left: 6px; /* space from the side */
margin-top: 2px; /* space between target and stem */
}
.tpd-size-medium.tpd-no-radius .tpd-stem { margin-left: 10px; }
.tpd-size-medium .tpd-close { margin: 4px 2px; }
/* ideal spinner dimensions don't cause movement op top and
on the stem when switching to text using position:'topleft' */
.tpd-size-medium .tpd-spinner {
width: 50px;
height: 36px;
}
.tpd-size-medium .tpd-spinner-spin { margin: 8px 0 0 15px; }
.tpd-size-medium .tpd-spinner-spin,
.tpd-size-medium .tpd-spinner-spin:after {
width: 20px;
height: 20px;
}
/* large */
.tpd-size-large .tpd-content,
.tpd-size-large .tpd-title {
padding: 10px;
font-size: 13px;
line-height: 18px;
}
.tpd-size-large .tpd-background { border-radius: 8px; }
.tpd-size-large .tpd-stem {
width: 18px;
height: 9px;
margin-left: 7px;
margin-top: 2px; /* space between target and stem */
}
.tpd-size-large.tpd-no-radius .tpd-stem { margin-left: 10px; }
.tpd-size-large .tpd-close { margin: 5px 2px 5px 2px; }
.tpd-size-large .tpd-spinner {
width: 54px;
height: 38px;
}
.tpd-size-large .tpd-spinner-spin { margin: 9px 0 0 17px; }
.tpd-size-large .tpd-spinner-spin,
.tpd-size-large .tpd-spinner-spin:after {
width: 20px;
height: 20px;
}
/* Skins */
/* default (dark) */
.tpd-skin-dark .tpd-content,
.tpd-skin-dark .tpd-title,
.tpd-skin-dark .tpd-close { color: #fff; }
.tpd-skin-dark .tpd-background-content,
.tpd-skin-dark .tpd-background-title {
background-color: #282828;
}
.tpd-skin-dark .tpd-background {
border-width: 1px;
border-color: rgba(255,255,255,.1);
}
/* line below the title */
.tpd-skin-dark .tpd-title-wrapper { border-bottom: 1px solid #404040; }
/* spinner */
.tpd-skin-dark .tpd-spinner-spin {
border-color: rgba(255,255,255,.2);
border-left-color: #fff;
}
/* links */
.tpd-skin-dark a { color: #ccc; }
.tpd-skin-dark a:hover { color: #c0c0c0; }

11
tools/tipped.js Executable file

File diff suppressed because one or more lines are too long