- Joined
- Jan 15, 2014
- Messages
- 1,318
- Solutions
- 35
- Reaction score
- 435
Hello OtLand Community, today I will release the upgraded Bounty Hunter system for TFS 1.X
Original System: TalkAction - Bounty Hunters System (Player Hunt System) (http://otland.net/threads/bounty-hunters-system-player-hunt-system.27721/)
Thanks to @kamilwxx for helping me understand how to store db results back in 2014 when this thread was started.
Customized for TFS 1.x, here we go:
library:
data/talkactions/talkactions.xml
data/talkactions/scripts/bounty_hunter.lua
data/creaturescripts/creaturescripts.xml
data/creaturescripts/scripts/bounty_hunter.lua
data/creaturescripts/scripts/others/login.lua
Web Page:
List of things to do:
Original System: TalkAction - Bounty Hunters System (Player Hunt System) (http://otland.net/threads/bounty-hunters-system-player-hunt-system.27721/)
Thanks to @kamilwxx for helping me understand how to store db results back in 2014 when this thread was started.
Customized for TFS 1.x, here we go:
- At the top of the Library file and the PHP file there is a small CONFIG section. I wrote comments on all the spots so you know what each thing means.
- Supports Coins/PremiumPoints and a Custom Currency if you choose it
library:
Code:
-- create table in database if one does not already exist
db.query("CREATE TABLE IF NOT EXISTS `bounty_hunter_system` (`id` int(11) NOT NULL auto_increment, `hunter_id` int(11) NOT NULL, `target_id` int(11) NOT NULL, `killer_id` int(11) NOT NULL, `prize` bigint(20) NOT NULL, `currencyType` varchar(32) NOT NULL, `dateAdded` int(15) NOT NULL, `killed` int(11) NOT NULL, `dateKilled` int(15) NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;")
--------------------------------------
---------- START OF CONFIG -----------
--------------------------------------
local customCurrency = '' -- by default bank balance and premium points are included but you can add other stackable currencies like gold nuggets etc here eg, 'gold nugget' or you can use the itemID or the item name
local config = {
ipCheck = true, -- players from same IP can not place bounty on each other
minLevelToAddBounty = 20, -- min lvl req to place a bounty
minLevelToBeTargeted = 20, -- min lvl req to be targeted by a bounty
broadcastKills = true, -- Should it broadcast a message to the whole game-world when someone was killed?
broadcastHunt = false, -- Should it broadcast a message to the whole game-world when someone is added to the bounty list?
mailbox_position = Position(32351,32223,6), -- If you are using a custom currency then we will send it to the players Mailbox, in order to do it you just need to put the location of one mailbox from your map here, doesn't matter which
currencies = {
['gold'] = {
minAmount = 1000000, -- Min amount of Gold allowed
maxAmount = 1000000000, -- Max amount of gold allowed
func =
function(player, prize, currency)
return player:setBankBalance(player:getBankBalance() + prize)
end,
check =
function(player, amount, currency)
if player:getBankBalance() >= amount then
return player:setBankBalance(player:getBankBalance() - amount)
end
return false
end,
},
['points'] = {
minAmount = 10, -- Min amount of premium points allowed
maxAmount = 500, -- Max amount of premium points allowed
func =
function(player, prize, currency)
return player:addPremiumPoints(prize)
end,
check =
function(player, prize, currency)
if player:getPremiumPoints() > prize then
return player:removePremiumPoints(prize)
end
return false
end
},
[customCurrency] = {
minAmount = 10, -- Min amount of custom item allowed
maxAmount = 3000, -- Max amount of custom item allowed
func =
function(player, prize, currency)
return player:sendParcel(prize)
end,
check =
function(player, amount, currency)
local itemID = ItemType(customCurrency):getId()
if itemID > 0 and player:getItemCount(itemID) >= amount then
player:removeItem(itemID, amount)
return true
end
return false
end,
}
}
}
--------------------------------------
----------- END OF CONFIG ------------
--------------------------------------
-- Only edit below if you know what you are doing --
local function trimString(str)
return (str:gsub("^%s*(.-)%s*$", "%1"))
end
local function addItemsToBag(bpID, itemID, count)
local masterBag = Game.createItem(bpID,1)
local stackable = ItemType(itemID):isStackable()
if stackable then
if count > 2000 then
local bp = Game.createItem(bpID,1)
masterBag:addItemEx(bp)
for i = 1, count do
if bp:getEmptySlots() < 1 then
bp = Game.createItem(bpID,1)
masterBag:addItemEx(bp)
end
bp:addItem(itemID)
end
end
return masterBag
end
if count > 20 then
local bp = Game.createItem(bpID,1)
masterBag:addItemEx(bp)
for i = 1, count do
if bp:getEmptySlots() < 1 then
bp = Game.createItem(bpID,1)
masterBag:addItemEx(bp)
end
bp:addItem(itemID)
end
return masterBag
end
for i = 1, count do
masterBag:addItem(itemID)
end
return masterBag
end
function Player:sendParcel(amount)
local itemID = ItemType(customCurrency):getId()
if itemID == 0 then
print('Error in sending parcel. Custom currency was not set properly double check the spelling.')
return
end
local container = Game.createItem(2595, 1)
container:setAttribute(ITEM_ATTRIBUTE_NAME, 'Bounty Hunters Mail')
local label = container:addItem(2599, 1)
label:setAttribute(ITEM_ATTRIBUTE_TEXT, self:getName())
label:setAttribute(ITEM_ATTRIBUTE_WRITER, "Bounty Hunters Mail")
local parcel = addItemsToBag(1988, itemID, amount)
container:addItemEx(parcel)
container:moveTo(config.mailbox_position)
end
function Player:getPremiumPoints(points)
local points = db.storeQuery("SELECT `premium_points` FROM `accounts` WHERE `id` = " .. self:getAccountId() .. ";")
if points then
local pointTotal = result.getDataInt(points, "premium_points")
result.free(points)
return pointTotal
end
return 0
end
function Player:addPremiumPoints(points)
return db.query("UPDATE accounts SET premium_points = premium_points + "..points.." where id = "..self:getAccountId()..";")
end
function Player:removePremiumPoints(points)
return db.query("UPDATE accounts SET premium_points = premium_points - "..points.." where id = "..self:getAccountId()..";")
end
function Player:getBountyInfo()
local result_plr = db.storeQuery("SELECT prize, id, currencyType FROM `bounty_hunter_system` WHERE `target_id` = "..self:getGuid().." AND `killed` = 0;")
if (result_plr == false) then
return {false, 0, 0, 0, 0}
end
local prize = tonumber(result.getDataInt(result_plr, "prize"))
local id = tonumber(result.getDataInt(result_plr, "id"))
local bounty_type = tostring(result.getDataString(result_plr, "currencyType"))
result.free(result_plr)
return {true, prize, id, bounty_type, currency}
end
local function addBountyKill(killer, target, prize, id, bounty_type, currency)
if not config.currencies[bounty_type] then
print('error in adding bounty prize')
return true
end
config.currencies[bounty_type].func(killer, prize, currency)
db.query("UPDATE `bounty_hunter_system` SET `killed` = 1, `killer_id`="..killer:getGuid()..", `dateKilled` = " .. os.time() .. " WHERE `id` = "..id..";")
killer:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE,'[BOUNTY HUNTER SYSTEM] You killed ' .. target:getName() .. ' and earned a reward of ' .. prize .. ' ' .. bounty_type .. 's!')
if config.broadcastKills then
Game.broadcastMessage("Bounty Hunter Update:\n " .. killer:getName() .. " has killed " .. target:getName() .. " and earned a reward of " .. prize .. " " .. bounty_type .. "!", MESSAGE_EVENT_ADVANCE)
end
return true
end
local function addBountyHunt(player, target, amount, currencyType)
db.query("INSERT INTO `bounty_hunter_system` VALUES (NULL," .. player:getGuid() .. "," .. target:getGuid() .. ",0," .. amount .. ", '" .. currencyType .. "', " .. os.time() .. ", 0, 0);")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BOUNTY HUNTER SYSTEM] You have placed bounty on " .. target:getName() .. " for a reward of " .. amount .. " " .. currencyType .. "!")
if config.broadcastHunt then
Game.broadcastMessage("[BOUNTY_HUNTER_SYSTEM]\n " .. player:getName() .. " has put a bounty on " .. target:getName() .. " for " .. amount .. " " .. t[2] .. ".", MESSAGE_EVENT_ADVANCE)
end
return false
end
function onBountyHunterSay(player, words, param)
if player:getLevel() < config.minLevelToAddBounty then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] You need level ' .. config.minLevelToAddBounty .. ' to use this command.')
return false
end
local t = param:split(",")
local name = t[1]
local currencyType = t[2] and trimString(t[2]) or nil
local amount = t[3] and tonumber(t[3]) or nil
if not (name and currencyType and amount) then
local item = ItemType(customCurrency)
local text = '[BOUNTY HUNTER SYSTEM GUIDE]\n\nCommand Usage:\n!hunt playerName, type(gold/' .. customCurrency .. '/points), amount' .. '\n\n' .. 'Hunting for Gold:\n' .. '--> !hunt Joe,gold,150000\n' .. '--> Placed a bounty on Joe for the amount of 150,000 gps.' .. '\n\n' .. 'Hunting for Premium Points:\n' .. '--> !hunt Joe,points,100\n' .. '--> Placed a bounty on Joe for the amount of 100 premium points.'
text = text .. (item:getId() > 0 and ('\n\n' .. 'Hunting for ' .. item:getPluralName() .. ':\n' .. '--> !hunt Joe,' .. customCurrency .. ',50\n' .. '--> Placed a bounty on Joe for the amount of 50 ' .. item:getPluralName()) or '')
player:popupFYI(text)
return false
end
local target = Player(name)
if not target then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] A player with the name of ' .. name .. ' is not online.')
return false
end
if target:getGuid() == player:getGuid() then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] You may not place a bounty on yourself!')
return false
end
if config.ipCheck and target:getIp() == player:getIp() then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] You may not place a bounty on a player from the same IP Address!')
return false
end
if target:getLevel() < config.minLevelToBeTargeted then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] You may only target players level ' .. config.minLevelToBeTargeted .. ' and above!')
return false
end
local info = target:getBountyInfo()
if info[1] then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BOUNTY HUNTER SYSTEM] This player has already been hunted.")
return false
end
local typ = config.currencies[currencyType]
if not typ then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] The currency type "' .. currencyType .. '" is not a valid bounty currency. [Currencies: gold/points' .. (customCurrency ~= '' and '/'..customCurrency..'' or '') .. ']')
return false
end
local minA, maxA = typ.minAmount, typ.maxAmount
if amount < minA or amount > maxA then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] The currency type of "' .. currencyType .. '" allows the amount to be in the range of ' .. minA .. ' --> ' .. maxA .. '.')
return false
end
if not typ.check(player, amount, currencyType) then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[BOUNTY_HUNTER_SYSTEM] You do not have ' .. amount .. ' ' .. currencyType .. '. [Error: Insufficient Funds]')
return false
end
return addBountyHunt(player, target, amount, currencyType)
end
function onBountyHunterKill(creature, target)
if not target:isPlayer() then
return true
end
if creature:getTile():hasFlag(TILESTATE_PVPZONE) then
return true
end
local info = target:getBountyInfo()
if not info[1] then
return true
end
return addBountyKill(creature, target, info[2], info[3], info[4], info[5])
end
data/talkactions/talkactions.xml
Code:
<talkaction words="!hunt" separator=" " script="bounty_hunter.lua" />
data/talkactions/scripts/bounty_hunter.lua
Code:
function onSay(player, words, param)
return onBountyHunterSay(player, words, param)
end
data/creaturescripts/creaturescripts.xml
Code:
<event type="kill" name="BountyHunterKill" script="bounty_hunter.lua"/>
data/creaturescripts/scripts/bounty_hunter.lua
Code:
function onKill(player, target)
return onBountyHunterKill(player, target)
end
data/creaturescripts/scripts/others/login.lua
Code:
player:registerEvent('BountyHunterKill')
Web Page:
PHP:
<style>
.bounty_hunter_header {
font-size: 22px;
font-weight: bold;
text-align: center;
}
.bounty_hunter_table_header {
font-size: 14px;
color: white;
background-color: #505050;
text-align: center;
font-weight: bold;
}
.lightRow {
font-size: 14px;
color: black;
background-color: #F1E0C6;
text-align: center;
}
.darkRow {
font-size: 14px;
color: black;
background-color: #D4C0A1;
text-align: center;
}
.bh_name {
color: maroon;
}
.bh_type {
color: blue;
}
.bh_amount {
color: green;
}
</style>
<?php
////////////// CONFIG START /////////////////////////
$customCurrency = ''; // If you are using a custom currency add the name here
$imgPath = 'http://outfit-images.ots.me/animatedOutfits1090/animoutfit.php'; // Path to your images (default is Gesior 10.90 animated outfit images)
////////////// CONFIG END /////////////////////////
$main_content .= '
<center><h1>Bounty Hunters</h1><br/>
<table border="2" cellpadding="4" cellspacing="1" width="100%">
<tr class="bounty_hunter_table_header">
<td class="bounty_hunter_header" colspan="2">General Information</td>
</tr>
<tr class="lightRow">
<td><strong>Command:</strong></td>
<td><strong>!hunt <span class="bh_name">playerName</span>, <span class="bh_type">points/gold'. (($customCurrency != '') ? '/'. $customCurrency.'' : '') . '</span>, <span class="bh_amount">amount</span></strong></td>
</tr>
<tr class="bounty_hunter_table_header">
<td class="bounty_hunter_header" colspan="2">Examples</td>
</tr>
<tr class="lightRow">
<td><strong>Add by points</strong></td>
<td><strong>!hunt <span class="bh_name">John</span>, <span class="bh_type">points</span>, <span class="bh_amount">10</span></strong><br/>Add bounty on player named John worth 10 points.</td>
</tr>
<tr class="darkRow">
<td><strong>Add by gold</strong></td>
<td><strong>!hunt <span class="bh_name">John</span>, <span class="bh_type">gold</span>, <span class="bh_amount">100000</span></strong><br/>Add bounty on player named John worth 100,000 gold coins.</td>
</tr>
';
if ($customCurrency != '') {
$main_content .= '
<tr class="lightRow">
<td><strong>Add by '.$customCurrency.'</strong></td>
<td><strong>!hunt <span class="bh_name">John</span>, <span class="bh_type">'.$customCurrency.'</span>, <span class="bh_amount">20</span></strong><br/>Add bounty on player named John worth 20 '.$customCurrency.'.</td>
</tr>
';
}
$main_content .= '
</table><br/><br/>
';
$main_content .= '
<table border="2" cellpadding="4" cellspacing="1" width="100%">
<tr class="bounty_hunter_table_header">
<td class="bounty_hunter_header" colspan="5">Bounty List</td>
</tr>
<tr class="bounty_hunter_table_header">
<td>Hunted by</td>
<td>Reward</td>
<td>Player Hunted</td>
<td>Outfit</td>
<td>Killed by</td>
</tr>';
$num = 0;
$bountys = $SQL->query('SELECT A.* , B.name AS hunted_by, C.name AS player_hunted, D.name AS killed_by
FROM bounty_hunter_system AS A
LEFT JOIN players AS B ON A.hunter_id = B.id
LEFT JOIN players AS C ON A.target_id = C.id
LEFT JOIN players AS D ON A.killer_id = D.id
ORDER BY A.killed,A.prize DESC');
if ($bountys->rowCount() > 0) {
foreach($bountys as $bounty)
{
if ($bounty['killed_by']){
$killed_by = '<a href="?subtopic=characters&name='.$bounty['killed_by'].'">'.$bounty['killed_by'].'</a>';
} else {
$killed_by = 'still alive';
}
$skill = $SQL->query('SELECT * FROM '.$SQL->tableName('players').' WHERE '.$SQL->fieldName('id').' = '.$bounty['target_id'].'')->fetch();
$main_content .= '
<tr class="'.(($num % 2 == 0) ? "lightRow" : "darkRow").'">
<td><a href="?subtopic=characters&name='.$bounty['hunted_by'].'">'.$bounty['hunted_by'].'</a></td>
<td>'.$bounty['prize'].' '.$bounty['currencyType'].'</td>
<td><a href="?subtopic=characters&name='.$bounty['player_hunted'].'">'.$bounty['player_hunted'].'</a></td>
<td><div style="position: relative; width: 32px; height: 32px;"><div style="background-image: url(\''.$imgPath.'?id='.$skill['looktype'].'&addons='.$skill['lookaddons'].'&head='.$skill['lookhead'].'&body='.$skill['lookbody'].'&legs='.$skill['looklegs'].'&feet='.$skill['lookfeet'].'\'); position: absolute; width: 64px; height: 80px; background-position: bottom right; background-repeat: no-repeat; right: 0px; bottom: 0px;"></div></div></td>
<td>'.$killed_by.'</td>
</tr>';
$num++;
}
} else {
$main_content.='<tr class="lightRow"><td colspan=5>Currently there are not any bounty hunter offers.</td></tr>';
}
$main_content .='</table>';
?>
List of things to do:
- Add in global broadcast that was requested somewhere in this thread
- Add in Bounty NPC
- Add in talkaction to check for active bounties
- Make webpage look prettier
- Allow players to add multiple bounties to 1 person
- Open for ideas
- Fixed not removing Bank Balance
- Fixed not checking Premium Points balance before removing. (Was putting into negative values)
- No longer able to place bounty on self
- Added option in config to check for ips (add ipCheck = true/false to your config or re-copy library)
Last edited: