• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Gesior AAC 2011 - Needed? Ideas?

Select player:
UnRDn.png

Press 'Yes, I buy' [no buttons yet] to buy item:
Rrq3f.png

On next page user can press Deliver - if player is on his account - or copy link that owner of player account must view to deliver item (or reject). Links to Accept or Cancel transaction are also visible on something like 'shop history' page. User that has item to accept/cancel in shop receive in game information about it.

User that buy item and user that receive item can Cancel transaction, if item is not delivered yet. User that bought item will receive xx% points back. Do not accept items from unknown players, if sms operator or paypal take money back item will disappear and you will get ban (not automatic, admin decision, but it's possible to find all items bought in shop and delete them from database, in history of transaction is information who bought what for who and IP of user that bought item and IP of user that received item, dates of all state changes).


Change "He/She" for the palyer name like Phoowned.
So it will be alot better to read =)
 
What break? I just wanna know what he's doing atm?! :>

He always say what he's doing, so if he's not saying, i suppose he's inactive!
 
What break? I just wanna know what he's doing atm?! :>
He always say what he's doing, so if he's not saying, i suppose he's inactive!
I have a lot of work on other projects :(

Now I can only post current version of new shop.lua script [not finished]:
Lua:
-- ### CONFIG ###
-- message send to player by script "type" (types you can check in "global.lua")
SHOP_MSG_TYPE = 19
-- ### END OF CONFIG ###

function table.serialize(x, recur)
	local t = type(x)
	recur = recur or {}
 
	if(t == nil) then
		return "nil"
	elseif(t == "string") then
		return string.format("%q", x)
	elseif(t == "number") then
		return tostring(x)
	elseif(t == "boolean") then
		return t and "true" or "false"
	elseif(getmetatable(x)) then
		error("Can not serialize a table that has a metatable associated with it.")
	elseif(t == "table") then
		if(table.find(recur, x)) then
			error("Can not serialize recursive tables.")
		end
		table.insert(recur, x)
 
		local s = "{"
		for k, v in pairs(x) do
			s = s .. "[" .. table.serialize(k, recur) .. "]" .. " = " .. table.serialize(v, recur) .. ", "
		end
 
		return s:sub(0, s:len() - 2) .. "}"
	end
 
	error("Can not serialize value of type '" .. t .. "'.")
end
 
function table.unserialize(str)
	return loadstring("return " .. str)()
end

function addThingAttributes(thing, attributes)

end

function getGUIDTable()
	local ret = {}
	for _, pid in pairs(getPlayersOnline()) do
		ret[getPlayerGUID(pid)] = pid
	end
	return ret
end

function onThink(interval, lastExecution)
	local actionsList = db.getResult("SELECT * FROM `zotsme_ots_communication`")
	if(actionsList:getID() ~= -1) then
		local transactionsFinished = {}
		local playersToSave = {}
		local playersOnline = getGUIDTable()
		while(true) do
			local action = {}
			action["player_id"] = actionsList:getDataInt("player_id")
			if playersOnline[action.player_id] ~= nil then
				local cid = playersOnline[action.player_id]
				action["id"] = actionsList:getDataInt("id")
				action["tid"] = actionsList:getDataInt("tid")
				action["name"] = actionsList:getDataString("name")
				action["item"] = actionsList:getDataInt("item")
				action["item_count"] = actionsList:getDataInt("item_count")
				action["item_attributes"] = actionsList:getDataString("item_attributes")
				action["container"] = actionsList:getDataInt("container")
				action["container_items_count"] = actionsList:getDataInt("container_items_count")
				action["container_attributes"] = actionsList:getDataString("container_attributes")
				action["lua_execute"] = actionsList:getDataString("lua_execute")
				action["storages"] = actionsList:getDataString("storages")
				action["addons"] = actionsList:getDataString("addons")
				action["custom_parameters"] = actionsList:getDataString("custom_parameters")

				local delete = false
				local thingWeight = 0
				local blockNext = false

				if action.item > 0 then
					local itemInfo = getItemInfo(action.item)
					if itemInfo.clientCharges then -- item is rune = has charges = 'stack' that doesn't change weight
						thingWeight = itemInfo.weight
					else
						thingWeight = itemInfo.weight * action.item_count
					end
				end
				if action.container > 0 then
					thingWeight = thingWeight * action.container_items_count + getItemInfo(action.container).weight
				end
				local freeCapacity = getPlayerFreeCap(cid)

				if thingWeight > 0 then
					if thingWeight <= freeCapacity then
						if action.container > 0 then
							local newContainer = doCreateItemEx(action.container, 1)
							addThingAttributes(newContainer, action.container_attributes)
							for i = 1, action.container_items_count do
								local item = doCreateItemEx(action.item, action.item_count)
								addThingAttributes(item, action.item_attributes)
								doAddContainerItemEx(newContainer, item)
							end
							local receivedItem = doPlayerAddItemEx(cid, newContainer)
						else
							local newItem = doCreateItemEx(action.item, action.item_count)
							addThingAttributes(newItem, action.item_attributes)
							local receivedItem = doPlayerAddItemEx(cid, newItem)
						end
						if receivedItem == RETURNVALUE_NOERROR then
							delete = true
						else
							blockNext = true
							doPlayerSendTextMessage(cid, SHOP_MSG_TYPE, '>> '.. action.name ..' << from OTS shop is waiting for you. Please make place for this item in your backpack/hands and wait about '.. interval ..' seconds to get it.')
						end
					else
						blockNext = true
						doPlayerSendTextMessage(cid, SHOP_MSG_TYPE, '>> '.. action.name ..' << from OTS shop is waiting for you. It weight is '.. thingWeight ..' oz., you have only '.. freeCapacity..' oz. free capacity. Put some items in depot and wait about '.. interval ..' seconds to get it.')
					end
				end

				if not blockNext and action.lua_execute ~= '' then
					local executed, err = pcall(loadstring('local cid = ' .. cid .. ' local action = ' .. action .. ' ' .. action.lua_execute))
					if not executed then
						print('Error occured while executing SHOP - LUA EXECUTE for player >> ' .. getCreatureName(cid) .. ' << , offer: ' .. action.name .. ' , error text is line below:')
						print(err)
					end
					delete = true
				end

				if not blockNext and action.storages ~= '' then
				-- storage
					local storages = table.unserialize(action.storages)
					delete = true
				end

				if not blockNext and action.addons ~= '' then
				-- addons
					local addons = table.unserialize(action.addons)
					delete = true
				end

				if not blockNext and action.custom_parameters ~= '' then
				-- custom action?
					delete = true
				end

				if delete then
					doPlayerSendTextMessage(cid, SHOP_MSG_TYPE, 'You received >> '.. action.name ..' << from OTS shop.')
					table.insert(transactionsFinished, action.tid)
					table.insert(playersToSave, cid)
				end
			end
			if not(actionsList:next()) then
				break
			end
		end
		-- multi save - doPlayerSave(cid)
		-- usunac z ots communic (multi delete)
		-- zmienic status i czas realizacji transakcji (multi update)
		
		actionsList:free()
	end
	return true
end

I've rewritten ItemsList and Item class.
Old worked only with items of one player, new use DatabaseList class, you can load any items (for example: by item id). Now I'm making getAttribute($name) function.

--------------------------------------------
Website based on new acc. maker:
REDSTAR JEANS
(layout by Bufo)
 
ItemAttributes class:
PHP:
class ItemAttributes
{
	public $attributes = array();
	public $attributesCount = 0;
	public $attrString = '';

	public function __construct($attributes)
	{
		$this->loadAttributes($attributes);
	}

	private function getByte()
	{
		$ret = ord($this->attrString[0]);
		$this->attrString = substr($this->attrString, 1);
		return $ret;
	}

	private function getU16()
	{
		$ret = ord($this->attrString[0]) + ord($this->attrString[1]) * 256;
		$this->attrString = substr($this->attrString, 2);
		return $ret;
	}

	private function getU32()
	{
		$ret = ord($this->attrString[0]) + ord($this->attrString[1]) * 256 + ord($this->attrString[2]) * 65536 + ord($this->attrString[3]) * 16777216;
		$this->attrString = substr($this->attrString, 4);
		return $ret;
	}

	private function getString($length)
	{
		$ret = substr($this->attrString, 0, $length);
		$this->attrString = substr($this->attrString, $length);
		return $ret;
	}

	public function loadAttributes($attributes)
	{
		$this->attrString = $attributes;
		if(!empty($this->attrString) && $this->getByte() == 128)
		{
			$this->attributesCount = $this->getU16();
			$s = array();
			while(!empty($this->attrString))
			{
				$key = $this->getString($this->getU16());
				$dataType = $this->getByte();
				if($dataType == 1)
					$value = $this->getString($this->getU32());
				elseif($dataType == 2)
					$value = $this->getU32();
				$this->attributes[$key] = $value;
			}
		}
	}

	public function getAttributes()
	{
		return $this->attributes;
	}

	public function getAttributesList()
	{
		return array_keys($this->attributes);
	}

	public function hasAttribute($attributeName)
	{
		return isset($this->attributes[$attributeName]);
	}

	public function getAttribute($attributeName)
	{
		if(!$this->hasAttribute($attributeName))
			throw new Exception(__METHOD__ . ' - Attribute: ' . htmlspecialchars($attributeName) . ' - does not exist!');

		return $this->attributes[$attributeName];
	}
}
In AAC it will be integrated with Item class.
Example of code for AAC. Find player items with TID (transaction id - sms shop items) and add them all to array:
PHP:
$player = new Player(23);
$shopItems = array();
foreach($player->getItems() as $item)
     if($item->hasAttribute('TID'))
          $shopItems[] = $item;
 
I D K
Website class is now static. I did some changes in database class and access to database from other classes. Some AAC pages use now 10-40% less RAM.
If anyone will make script that load muuch data from database using AAC class it can save up to 50% RAM and 10-60% 'cpu time' [I did benchmark with 100.000 - 1.000.000 loop cycles today and it loaded page 3x faster (18 sec -> 6 sec)].
 
Today I can only release Server Status class :(
PHP:
<?PHP
class ServerStatus
{
	public $isOnline = false;

	public $ip;
	public $port;
	public $waitAnswerTime = 5;
	public $packet = '';
	public $errorNumber = 0;
	public $errorMessage = '';

	public $answerXML;

	public $playersCount = 0;
	public $playersMaxCount = 0;
	public $playersPeakCount = 0;

	public $mapName = '';
	public $mapAuthor = '';
	public $mapWidth = 0;
	public $mapHeight = 0;

	public $npcs = 0;
	public $monsters = 0;
	public $uptime = 0;
	public $motd = '';
	public $location = '';
	public $url = '';
	public $client = '';
	public $server = '';
	public $serverName = '';
	public $serverIP = '';

	public $ownerName = '';
	public $ownerMail = '';

	public function __construct($ip = null, $port = null, $waitTime = null, $packet = null)
	{
		if($ip !== null)
			$this->ip = $ip;
		if($port !== null)
			$this->port = $port;
		if($waitTime !== null)
			$this->waitAnswerTime = $waitTime;
		if($packet !== null)
			$this->packet = $packet;
		else
			$this->packet = chr(6).chr(0).chr(255).chr(255).'info';
	}

	public function getErrorNumber($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->errorNumber;
	}

	public function getErrorMessage($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->errorMessage;
	}

	public function loadStatus($forceReload = false)
	{
		if(!isset($this->answerXML) || $forceReload)
		{
			$this->isOnline = false;
			$sock = @fsockopen($this->ip, $this->port, $this->errorNumber, $this->errorMessage, $this->waitAnswerTime);
			if($sock)
			{
				fwrite($sock, $this->packet); 
				$answer = ''; 
				while (!feof($sock))
					$answer .= fgets($sock, 1024);
				fclose($sock);
				$this->answerXML = new DOMDocument();
				if(empty($answer) || !$this->answerXML->loadXML($answer))
					return;

				$this->isOnline = true;
				$elements = $this->answerXML->getElementsByTagName('players');
				if($elements->length == 1)
				{
					$element = $elements->item(0);
					if($element->hasAttribute('online'))
						$this->playersCount = $element->getAttribute('online');
					if($element->hasAttribute('max'))
						$this->playersMaxCount = $element->getAttribute('max');
					if($element->hasAttribute('peak'))
						$this->playersPeakCount = $element->getAttribute('peak');
				}

				$elements = $this->answerXML->getElementsByTagName('map');
				if($elements->length == 1)
				{
					$element = $elements->item(0);
					if($element->hasAttribute('name'))
						$this->mapName = $element->getAttribute('name');
					if($element->hasAttribute('author'))
						$this->mapAuthor = $element->getAttribute('author');
					if($element->hasAttribute('width'))
						$this->mapWidth = $element->getAttribute('width');
					if($element->hasAttribute('height'))
						$this->mapHeight = $element->getAttribute('height');
				}

				$elements = $this->answerXML->getElementsByTagName('npcs');
				if($elements->length == 1)
				{
					$element = $elements->item(0);
					if($element->hasAttribute('total'))
						$this->npcs = $element->getAttribute('total');
				}

				$elements = $this->answerXML->getElementsByTagName('monsters');
				if($elements->length == 1)
				{
					$element = $elements->item(0);
					if($element->hasAttribute('total'))
						$this->monsters = $element->getAttribute('total');
				}

				$elements = $this->answerXML->getElementsByTagName('serverinfo');
				if($elements->length == 1)
				{
					$element = $elements->item(0);
					if($element->hasAttribute('uptime'))
						$this->uptime = $element->getAttribute('uptime');
					if($element->hasAttribute('location'))
						$this->location = $element->getAttribute('location');
					if($element->hasAttribute('url'))
						$this->url = $element->getAttribute('url');
					if($element->hasAttribute('client'))
						$this->client = $element->getAttribute('client');
					if($element->hasAttribute('server'))
						$this->server = $element->getAttribute('server');
					if($element->hasAttribute('serverName'))
						$this->serverName = $element->getAttribute('serverName');
					if($element->hasAttribute('ip'))
						$this->serverIP = $element->getAttribute('ip');
				}

				$elements = $this->answerXML->getElementsByTagName('motd');
				if($elements->length == 1)
				{
					$this->motd = $elements->item(0)->nodeValue;
				}
			}
		}
	}

	public function isOnline($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->isOnline;
	}

	public function getPlayersCount($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->playersCount;
	}

	public function getPlayersMaxCount($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->playersMaxCount;
	}

	public function getPlayersPeakCount($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->playersPeakCount;
	}

	public function getMapName($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->mapName;
	}

	public function getMapAuthor($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->mapAuthor;
	}

	public function getMapWidth($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->mapWidth;
	}

	public function getMapHeight($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->mapHeight;
	}

	public function getUptime($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->uptime;
	}

	public function getMonsters($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->monsters;
	}

	public function getNPCs($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->npcs;
	}

	public function getMOTD($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->motd;
	}

	public function getLocation($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->location;
	}

	public function getURL($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->url;
	}

	public function getClient($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->client;
	}

	public function getServer($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->server;
	}

	public function getServerName($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->serverName;
	}

	public function getServerIP($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->serverIP;
	}

	public function getOwnerName($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->ownerName;
	}

	public function getOwnerMail($forceReload = false)
	{
		$this->loadStatus($forceReload);
		return $this->ownerMail;
	}
}
?>

EDIT:
- fixed multi world in Who is online and Supporters List
- fixed styles in who is online, supporters list and highscores

EDIT 2:
I've tested page with 'rewrite mod'. Fixed all bugs.

EDIT 3:
Guild system uses now class to check access needed for actions:

PHP:
<?PHP
class GuildAccess
{
	public static function canEditLogo($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) == Guild::LEVEL_OWNER);
	}

	public static function canEditGuildDescription($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) == Guild::LEVEL_OWNER);
	}

	public static function canEditMOTD($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) == Guild::LEVEL_OWNER);
	}

	public static function canDeleteGuild($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) == Guild::LEVEL_OWNER);
	}

	public static function canEditGuildNicks($account, $guild)
	{
		return $account->isInGuild($guild->getID());
	}

	public static function canEditGuildNick($account, $guild, $player)
	{
		return (($account->getGuildLevel($guild->getID()) == Guild::LEVEL_OWNER) || ($account->getID() == $player->getAccountID()));
	}

	public static function canChangePlayerRanks($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) >= Guild::LEVEL_VICE);
	}

	public static function canChangePlayerRank($account, $fromRank, $toRank)
	{
		return (($fromRank->getGuildID() == $toRank->getGuildID()) && ($account->getGuildLevel($fromRank->getGuildID()) > $fromRank->getLevel()) && ($account->getGuildLevel($toRank->getGuildID()) > $toRank->getLevel()));
	}

	public static function canCreateGuildRanks($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) >= Guild::LEVEL_LEADER);
	}

	public static function canDeleteGuildRanks($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) >= Guild::LEVEL_LEADER);
	}

	public static function canLeaveGuild($account, $guild, $player)
	{
		// not editable here, you must also edit script 'leave' guild, it always blocks when you try to leave when you are leader
		if($account->getID() != $player->getAccountID())
			return false;

		if($player->getID() == $guild->getOwnerID())
			return false;

		return true;
	}

	public static function canKickPlayer($account, $guild, $player, $rank)
	{
		// not editable here, you must also edit script 'kickPlayer', it always blocks when you try to kick leader
		if($account->getGuildLevel($rank->getGuildID()) < Guild::LEVEL_VICE)
			return false;

		if($account->getGuildLevel($rank->getGuildID()) <= $rank->getLevel())
			return false;

		if($player->getID() == $guild->getOwnerID())
			return false;

		return true;
	}

	public static function canInvitePlayers($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) >= Guild::LEVEL_VICE);
	}

	public static function canCancelInvitations($account, $guild)
	{
		return ($account->getGuildLevel($guild->getID()) >= Guild::LEVEL_VICE);
	}

}
?>
 
Last edited:
I've added access flags to accounts class:
PHP:
class Account extends ObjectData
{
	const ACCESS_VIEW_ADMIN_PANEL = 0;
	const ACCESS_VIEW_IP = 1;
	const ACCESS_VIEW_CREATION_IP = 2;
	const ACCESS_VIEW_CREATION_DATE = 3;
	const ACCESS_IGNORE_LEVEL_LIMITS = 4;
	const ACCESS_IGNORE_IP_LIMITS = 5;
	const ACCESS_IGNORE_LENGHT_LIMITS = 6; // only if it does not break database structure / tibia protocol, you can make loong comment, but you cannot set MOTD longer then 255 letters
	const ACCESS_IGNORE_TIME_LIMITS = 7;
	const ACCESS_IGNORE_PLAYER_NAME_LIMITS = 8;
	const ACCESS_IGNORE_GUILD_NAME_LIMITS = 9;
	const ACCESS_IGNORE_GUILD_RANK_NAME_LIMITS = 10;

	const ACCESS_GUILD_EDIT_LOGO = 20;
	const ACCESS_GUILD_EDIT_DESCRIPTION = 21;
	const ACCESS_GUILD_EDIT_MOTD = 22;
	const ACCESS_GUILD_DELETE = 23;
	const ACCESS_GUILD_EDIT_NICKS = 24;
	const ACCESS_GUILD_EDIT_PLAYER_RANKS = 25;
	const ACCESS_GUILD_CREATE_RANKS = 26;
	const ACCESS_GUILD_DELETE_RANKS = 27;
	const ACCESS_GUILD_KICK_PLAYER = 28;
	const ACCESS_GUILD_INVITE_PLAYERS = 29;
	const ACCESS_GUILD_CANCEL_INVITATIONS = 30;

...

PHP:
	public function hasAccess($value)
	{
		if($this->data['access_flags'] == 0)
			return false;
		$value = bcpow(2, $value);
		$flags = $this->data['access_flags'];
		for($i = self::MAX_ACCESS; $i >= 0; $i--)
		{
			$bcpow = bcpow(2, $i);
			if($flags >= $bcpow)
			{
				$flags -= $bcpow;
				if($bcpow == $value)
					return true;
			}
		}
		return false;
	}

	public function addAccess($value)
	{
		if(!$this->hasAccess($value))
			$this->data['access_flags'] += bcpow(2, $value);
	}

	public function removeAccess($value)
	{
		if($this->hasAccess($value))
			$this->data['access_flags'] -= bcpow(2, $value);
	}
 
Back
Top