shopper plugin

Other plugins for extending OpenKore's functionality. This forum is only for posting new plugins and commenting on existing plugins. For support, use the Support forum.

Moderator: Moderators

Message
Author
kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

shopper plugin

#1 Post by kali »

A couple of years ago I wrote a shopper plugin as some sort of a mentoring response to edeline, who wrote a similar (but a bit unpolished) plugin. It can be found at the old openkore forum http://bibian.ath.cx/openkore/viewtopic.php?t=19654

I still think it's useful, even if it has limitations :)
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

Kleenex
Human
Human
Posts: 28
Joined: 13 Apr 2008, 14:47

Re: shopper plugin

#2 Post by Kleenex »

I was actually just about to start looking for something like this.
thanks

Motivus
Developers
Developers
Posts: 157
Joined: 04 Apr 2008, 13:33
Noob?: Yes

Re: shopper plugin

#3 Post by Motivus »

If anyone finds this useful, go ahead and use it. I based it on edeline's merchant plugin, but I rewrote alot of the code (all of the code?). You can find a macro file and stuff on bibian's archive forum in the yamd thread, but I included an example below anyway.

Code: Select all

package YAMDB;

#YAMD by edeline
#	YAMDB fork by Motivus aka Dishonru aka Belial

#Config Start
#use constant LOG_PATH => "marketlog.txt"; 
use constant BASE_DELAY => 0.1; 
use constant RAND_DELAY => 0.1;

use constant SEP_DATA => "\n";
use constant SEP_OBJECTS => "\n";
use constant SEP_SHOPS => "\n";
use constant SEP_NEWCRAWL => "CLEAR\n";
use constant SEP_CARDS => " ";

use constant MAX_TRIES => 100; 
#Config End

#If you want to use a database scroll down to "Logging functions" and go to town

use strict;

use Globals;
use Log qw(message debug error warning);
use Network::Send;
use Settings;
use Plugins;
use Skill;
use Utils;
use Misc;
use AI;
use Actor;

Plugins::register('YAMDB', 'Requests and parses vender information', \&unload);

my $hooks = Plugins::addHooks(
	['AI_pre', \&visitShop, undef],
	['packet_vender', \& venderFound, undef],
	['packet_vender_store2', \&dumpShop, undef],
);

my $commandsID = Commands::register(
	["yamdb_info", "displays number of shops visited so far", \&countVisited],
	["yamdb_flush", "empties the market log information & issues CLEAR command", \&emptyBuffer],
);

sub unload {
	Plugins::delHooks($hooks);
	Commands::unregister($commandsID);
	writeCon("Plugin unloaded."); 
}

my %venderVisited;
my $timeLastVisit = time();
my @shopList;
my $iterate;

###
# Hooks
###

sub dumpShop {
	my $hookName = shift;
	my $args=shift;
	my $vender = Actor::get($args->{'venderID'});
	my @venderItemList = @{$args->{'itemList'}};

	my ($playerName, $vendName, $vendPos);
	
	$playerName = $vender->name;
	
	if (defined $venderLists{$args->{'venderID'}}{'title'}) {
		$vendName = $venderLists{$args->{'venderID'}}{'title'};
	}
	else { 
		writeCon("Shop from $playerName has no name.  It's possible we walked off screen.");
		return;
	}
	
	if (!(defined $venderVisited{$args->{'venderID'}}) || $venderVisited{$args->{'venderID'}} ne $vendName) {
		if (defined $vender->{pos_to}{x} && defined $vender->{pos_to}{y}) {
			$vendPos = "$vender->{pos_to}{x},$vender->{pos_to}{y}";
		}
		else { 
			writeCon("Shop from player ".$playerName." (".$args->{'venderID'}.") has no position.  It's possible we walked off screen.");
			return;
		}
		
		#Register vender information	
		my ($playerFace, $playerCart, $playerStrID);
		$playerFace = sprintf("%02d%02d", $vender->{hair_style}, $vender->{hair_color});
		$playerCart = getCartType($vender->{param3});
		
		$playerStrID = formatID($args->{'venderID'});
		
		registerVend($playerStrID, $playerName, $vendName, $field{name}, $vendPos, $playerFace, 
			$vender->{type}, $playerCart, $vender->{headgear}{top}, $vender->{headgear}{mid}, $vender->{headgear}{low}, 
			$vender->{lv}, $vender->{sex}, $vender->{sitting} |0);

		#Register items in vend
		for (my $itemID = 0; $itemID < @venderItemList; $itemID++) {
			if (defined $venderItemList[$itemID]) {
				my ($itemName, $itemPrice, $itemAmount, $itemTypeID, $itemUpgrade, $itemSlots, $itemSlotData, $itemType);	
				$itemTypeID = $venderItemList[$itemID]->{nameID};
				$itemName = $venderItemList[$itemID]->{name};
				$itemPrice = $venderItemList[$itemID]->{price};
				$itemAmount = $venderItemList[$itemID]->{amount};
				$itemUpgrade = $venderItemList[$itemID]->{upgrade};
				$itemSlots = countCards($itemTypeID);
				$itemSlotData = formatCards($venderItemList[$itemID]->{cards});
				
				registerItem($playerStrID, $itemTypeID, $itemName, $itemPrice, $itemAmount, $itemUpgrade, $itemSlots, $itemSlotData);
			}
		}
		
		#Mark vender as visited, end current vend
		$venderVisited{$args->{'venderID'}} = $vendName;
		endVend();
		
		#Show shops visited
		countVisited();
	}
}

sub venderFound {
	my ($packet, $args) = @_;
	my $ID = $args->{ID};
	
	if ($ID && !defined($venderVisited{$ID})) {
		$messageSender->sendGetPlayerInfo($ID);
		pushShop({vendorID => $ID, try => 0});
		if (!AI::is('checkShop')) {
			AI::queue('checkShop', {shopsToVisit => 1});
		}
		else {
			my $shopsToVisit = @shopList;
			AI::dequeue;
			AI::queue('checkShop', {shopsToVisit => $shopsToVisit});
		}
	}
}

sub visitShop {
	if (AI::is('checkShop') && timeOut($timeLastVisit, getDelay())) {
		my $shop = shift @shopList;
		my $venderID = $shop->{vendorID};
		my $try = $shop->{try};
		my $vender = Actor::get($venderID);
		my $venderName = $vender->name;

		if (!(defined $venderVisited{$venderID}) || $venderLists{$venderID}{'title'} ne $venderVisited{$venderID}) {
			if (rindex($venderName, "Unknown #") == -1 || $config{'shopfast'} || $try > MAX_TRIES) {
				sendEnteringVender(\$remote_socket, $venderID);
			}
			elsif ($vender->distance() <= 20) { #If vendor is in range re-queue it until we get its name
				$try++;
				pushShop({vendorID => $venderID, try => $try});
				
				return;
			}
		}
		
		#If we visited the vend or the vender is >20 tiles away we need to queue a new list
		if (@shopList == 0) { #No more venders, allow normal AI to resume
			AI::dequeue;
			#countVisited();
		}
		else  {
			my $shopsToVisit = @shopList;
			AI::dequeue;
			AI::queue('checkShop', {shopsToVisit => $shopsToVisit});
		}
		
		$timeLastVisit = time;
	}
}	

###
# Commands
###	

sub emptyBuffer {
	writeCon("Resetting marketlog.txt and visited vend list");
	%venderVisited = ();
	resetLog(1, time()."\n");
}

sub countVisited {
	writeCon("Shops Visited: ".scalar(keys(%venderVisited)));
}

###
# Logging Functions
###

sub registerVend {
	my $playerID = shift;
	my $playerName = shift;
	my $vendTitle = shift;
	my $vendMap = shift;
	my $vendPos = shift;
	my $playerFace = shift;
	my $playerClass = shift;
	my $playerCart = shift;
	my $playerHeadTop = shift;
	my $playerHeadMid = shift;
	my $playerHeadBot = shift;
	my $playerLevel = shift;
	my $playerGender = shift;
	my $playerSitting = shift;
	
	addLog($playerID.SEP_DATA
		.$playerName.SEP_DATA
		.$vendTitle.SEP_DATA
		.$vendMap.SEP_DATA
		.$vendPos.SEP_DATA
		.$playerFace.SEP_DATA
		.$playerClass.SEP_DATA
		.$playerCart.SEP_DATA
		.$playerHeadTop.SEP_DATA
		.$playerHeadMid.SEP_DATA
		.$playerHeadBot.SEP_DATA
		.$playerLevel.SEP_DATA
		.$playerGender.SEP_DATA
		.$playerSitting.SEP_OBJECTS);
}

sub registerItem {
	my $parentID = shift;
	my $itemID = shift;
	my $itemName = shift;
	my $itemPrice = shift;
	my $itemAmount = shift;
	my $itemUpgrade = shift;
	my $itemSlots = shift;
	my $itemSlotData = shift;
	
	addLog($itemID.SEP_DATA
		.$itemName.SEP_DATA
		.$itemPrice.SEP_DATA
		.$itemAmount.SEP_DATA
		.$itemUpgrade.SEP_DATA
		.$itemSlots.SEP_DATA
		.$itemSlotData.SEP_OBJECTS);
}

sub endVend {
	addLog(SEP_SHOPS);
}

###
# Text file logging functions
###

sub addLog {
	my $logText = shift;
	my $logPath = "marketlog_".$config{'server'}.".txt";
	
	open(F, ">>".$logPath);
		
	print F $logText;
	close(F);
}

sub resetLog {
	my $clear = shift;
	my $logBuffer = shift;
	my $logPath = "marketlog_".$config{'server'}.".txt";
	
	open(F, ">".$logPath);
	
	if ($clear) {
		$iterate = 0;
		print F SEP_NEWCRAWL;
	}
		
	print F $logBuffer;
	
	close(F);
}

###
# Information Format Functions
###

sub getCartType {
	my $effects = shift;
	
	if ($effects &8) {
		return 1;
	}
	elsif ($effects &128) {
		return 2;
	}
	elsif ($effects &256) {
		return 3;
	}
	elsif ($effects &512) {
		return 4;
	}
	elsif ($effects &1024) {
		return 5;
	}
	
	return 0;
}

sub formatID {
	my $DWORD = shift;
	
	$DWORD = unpack("l", $DWORD);
	$DWORD = sprintf("%010d", $DWORD);
	
	return $DWORD;
}

sub formatCards {
	my $cardMess = shift;
	my @cards;
	
	for (my $i = 0; $i < 4; $i++) {
		my $card = unpack("v1", substr($cardMess, $i*2, 2));
		last unless $card;
		push(@cards, $card);
	}
	
	my $cardStr;
	
	$cardStr = sprintf("%05d%s%05d%s%05d%s%05d", $cards[0], SEP_CARDS, $cards[1], SEP_CARDS, $cards[2], SEP_CARDS, $cards[3]);
	
	return $cardStr;
}

sub countCards {
	my $itemID = shift;
	my $count;
	
	$count = $itemSlotCount_lut{$itemID};
	
	if (!$count)
	{
		$count = "0";
	}
	
	return $count;
}

sub itemHash {
	#Put your function to generate unique item hashes based on id/cards/upgrade here (I removed mine)
}

###
# Utility Functions
###

sub writeCon() {
	my $msg = shift;
	
	message "[YAMDB] ".$msg."\n";
}

sub pushShop {
	my $args = shift;
	push @shopList, ((defined $args) ? $args : {});
}

sub getDelay {
	my $delay = BASE_DELAY + rand(RAND_DELAY);
	
	return $delay;
}

1;
I use a combination of wget/curl to upload the file to the site, and I chose it over directly adding to the database because I wrote the site in another language and didn't want to double write hasing functions and similar things. Plus, this is generally run from a different system than the website.

Code: Select all

automacro crawlChaos {
	map prontera
	run-once 1
	call marketwatch
}

macro marketwatch {
	do yamdb_flush
	call move
	do relog 1100
	do eval system "parse"

	release crawlChaos

}

macro move {
	do move 115 118
	do move 121 104
	do move 121 90
	do move 130 94
	do move 130 111
	do move 133 120
	do move 145 119
	do move 143 91
	do move 152 115
	do move 153 107
	do move 153 99
	do move 150 89
	do move 151 80
	do move 155 66
	do move 155 48
	do move 156 33
	do move 156 137
	do move 155 156
	do move 155 173
	do move 156 189
	do move 171 191
	do move 136 214
	do move 138 201

	do move 115 118
}
batch file it runs

Code: Select all

del <filename from site>
curl -T marketlog_2.txt <site> --user username:password
wget <site>
Oh no.

iamanoob
Plain Yogurt
Plain Yogurt
Posts: 82
Joined: 04 Apr 2008, 09:49

Re: shopper plugin

#4 Post by iamanoob »

Motivus wrote:

Code: Select all

automacro crawlChaos {
	map prontera
	run-once 1
	call marketwatch
}

macro marketwatch {
	do yamdb_flush
	call move
	do relog 1100
	do eval system "parse"

	release crawlChaos

}

macro move {
	do move 115 118
	do move 121 104
	do move 121 90
	do move 130 94
	do move 130 111
	do move 133 120
	do move 145 119
	do move 143 91
	do move 152 115
	do move 153 107
	do move 153 99
	do move 150 89
	do move 151 80
	do move 155 66
	do move 155 48
	do move 156 33
	do move 156 137
	do move 155 156
	do move 155 173
	do move 156 189
	do move 171 191
	do move 136 214
	do move 138 201

	do move 115 118
}

Code: Select all

sub crawlChaos {
return if ($field{name} ne "prontera");
emptyBuffer();
my $i = 0
while ($i < 23) {
	if (!AI::inQueue("route")) {
		do {
			my $mx = int(rand(57)+115);
			my $my = int(rand(182)+33);
		} while (!$field->isWalkable($mx, $my);
		main::ai_route($field{name}, $mx, $my,
				attackOnRoute => 1,
				noSitAuto => 1,
				notifyUponArrival => 1);
		$i++;
	}
}
Commands::run("relog 1100");
Commands::run("eval system \"parse\"");
return;
}
Image
DARKest Ninja

House
Noob
Noob
Posts: 11
Joined: 04 May 2008, 08:25
Noob?: No
Location: Brasil

Re: shopper plugin

#5 Post by House »

I am trying to create a site of search of prices in the Brazilian server and vi this topic, I have advanced knowledge of the Kore more I am lay in what it is necessary for creation of the site, assist could me in some ideas? Already I have host that it supports PHP/MySQL (host good). Debtor.
Image

cazanova000
Human
Human
Posts: 26
Joined: 29 Oct 2008, 22:18
Noob?: No

Re: shopper plugin

#6 Post by cazanova000 »

just asking, the mod by "motivus" prints all in column in a .txt file
what should be modified to print all on line? i mean =x

a normal print by the plugin
ID
Nick of Merchant
Name of Shop
City
Coord
ID
ItemID
ItemName
Price
Etc.
a line print D:
ID
Nick of Merchant,Name of Shop,City,Coord,ID,ItemID,ItemName,Price,Etc.

alangos
Noob
Noob
Posts: 1
Joined: 18 Jan 2010, 23:35
Noob?: Yes

Re: shopper plugin

#7 Post by alangos »

I installed it on my openkore but no results. please tell me the correct format to install.
thanks

Motivus
Developers
Developers
Posts: 157
Joined: 04 Apr 2008, 13:33
Noob?: Yes

Re: shopper plugin

#8 Post by Motivus »

cazanova000 wrote: a line print D:
Change the "\n" to "whateveryouwanttoseperate"

Code: Select all

use constant SEP_DATA => "\n";
It's at the top of the file. I'm aware this is like six months late.
Oh no.

Sophos
Human
Human
Posts: 22
Joined: 20 Jul 2009, 01:58
Noob?: Yes

shopper plugin

#9 Post by Sophos »

Had already tested this plugin and it worked. It happens that today it no longer works, I believe that because of some update BRO.
The bot walks into a store and when he comes close is the checkshop.
Do not list any item on the console (as It did), so I think it is not working.

Can anyone help me (I don´t know nothing about plugin) ?
I do not know anything about plugin.
[]s

SophoS

Technology
Super Moderators
Super Moderators
Posts: 801
Joined: 06 May 2008, 12:47
Noob?: No

Re: shopper plugin

#10 Post by Technology »

Sophos wrote:Had already tested this plugin and it worked. It happens that today it no longer works, I believe that because of some update BRO.
The bot walks into a store and when he comes close is the checkshop.
Do not list any item on the console (as It did), so I think it is not working.

Can anyone help me (I don´t know nothing about plugin) ?
I do not know anything about plugin.
I've seen a similar problem as yours before on bRO, which i then solved by adding a new packet into kore.
In case you are not using latest kore's svn, you should probably then try that.
One ST0 to rule them all? One PE viewer to find them!
One ST_kRO to bring them all and in the darkness bind them...

Mount Doom awaits us, fellowship of OpenKore!

Post Reply