PDA

View Full Version : Eluna Grumbo'z Lottery System

slp13at420
07-27-2014, 07:57 PM
Grumbo'z Loco Lottery System

This allows players to enter a lottery by talking to a Lottery Vendor and purchasing an entry or many entries.

--Built Tested and Approved for TC2 3.3.5a Eluna ONLY--

THIS IS A FAST PACED LOTTO. (So if winner is NOT online then they get skipped) Designed to help promote online player activity.

there is a timer(30 minute) that picks a random player who has entered the lottery for the xx amount of custom item(your choice). all the currency will be placed in a pot and issued to the winner.
IF the player exists AND IF the player is online then they will receive the pot PLUS a random multiplier applied for there own entries.
Other-wise it will roll all entries over and start a new timer.
the timer can be changed via sql table entry. currently set to 30 minutes.

For TC2 3.3.5a Eluna

>> Grumbo'z Loco Lottery System (https://github.com/BlackWolfsDen/Grumboz_Loco_Lottery_System)<<

Vendor/currency Sql:

REPLACE INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction_A`, `faction_H`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `spell5`, `spell6`, `spell7`, `spell8`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Armor_mod`, `RacialLeader`, `questItem1`, `questItem2`, `questItem3`, `questItem4`, `questItem5`, `questItem6`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified`, `equipment_id`) VALUES
(390000, 0, 0, 0, 0, 0, 31048, 0, 0, 0, 'Lottery', 'Vendor', 'Buy', 0, 80, 80, 0, 35, 35, 129, 1, 1.14286, 3.5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '', 1, NULL);

REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `WDBVerified`) VALUES
(44209, 10, 0, -1, 'Magic Gold', 32282, 1, 64, 0, 1, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2147483647, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 'custom currency', 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 12340);

Lotto Sql Table:

-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 5.5.9-log - MySQL Community Server (GPL)
-- Server OS: Win32
-- HeidiSQL Version: 8.3.0.4694
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

-- Dumping database structure for lotto
CREATE DATABASE IF NOT EXISTS `lotto` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `lotto`;

-- Dumping structure for table lotto.entries
CREATE TABLE IF NOT EXISTS `entries` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`guid` int(11) NOT NULL,
`count` int(11) unsigned NOT NULL DEFAULT '0',
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table lotto.entries: ~0 rows (approximately)
/*!40000 ALTER TABLE `entries` DISABLE KEYS */;
/*!40000 ALTER TABLE `entries` ENABLE KEYS */;

-- Dumping structure for table lotto.settings
CREATE TABLE IF NOT EXISTS `settings` (
`item` int(11) unsigned NOT NULL,
`cost` tinyint(3) unsigned NOT NULL,
`timer` int(10) unsigned NOT NULL,
`operation` tinyint(1) unsigned NOT NULL DEFAULT '0',
`rndmax` int(3) unsigned NOT NULL DEFAULT '1',
`require` tinyint(3) unsigned NOT NULL DEFAULT '4',
`maxcount` tinyint(3) unsigned NOT NULL DEFAULT '0',
`display_pot` tinyint(1) unsigned NOT NULL DEFAULT '0',
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=1;

-- Dumping data for table lotto.settings: 1 rows
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
INSERT INTO `settings` (`item`, `cost`, `timer`, `operation`, `rndmax`, `require`, `maxcount`, `comments`) VALUES
(44209, 1, 1800000, 1, 10, 4, 0, 1, 'item :\r\nthe item id for what they will win(custom currency)\r\n\r\ncost:\r\nhow many of (item) per entry\r\n\r\ntimer:\r\n604800000 == 1 week\r\n86400000 == 1 day\r\n3600000 == 1 hour\r\n1800000 == 30 minutes\r\n900000 == 15 minutes\r\n600000 == 10 minutes\r\n60000 == 1 minute\r\n\r\nrequire:\r\nhow many entrries are required for the lotto to search for a winner.\r\ndefault = 4\r\nmaxcount:\r\nhow many times a player can enter a lotto\r\n0 == infinate amount of entries.\r\n1+ == max amount a player can enter per lotto');
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

Script:

-- From the mad scientist slp13at420 of EmuDevs.com
print("-----------------------------------")
print("Grumbo\'z Loco Lotto starting ...\n")
local npcid = 390000
Lotto = {};
LottoSettings = {};
LottoEntries = {};

local LS = WorldDBQuery("SELECT * FROM lotto.settings;");
if(LS)then
repeat
LottoSettings = {
item = LS:GetUInt32(0),
cost = LS:GetUInt32(1),
timer = LS:GetUInt32(2),
operation = LS:GetUInt32(3),
rndmax = LS:GetUInt32(4),
require = LS:GetUInt32(5),
maxcount = LS:GetUInt32(6)
display_pot = LS:GetUInt32(7)
};
until not LS:NextRow()
end

local LE = WorldDBQuery("SELECT * FROM lotto.entries;");
if(LE)then
LottoEntries.pot = 0
repeat
LottoEntries[LE:GetUInt32(0)] = {
id = LE:GetUInt32(0),
name = LE:GetString(1),
guid = LE:GetUInt32(2),
count = LE:GetUInt32(3)
};
LottoEntries.pot = LottoEntries.pot + LE:GetUInt32(3)
until not LE:NextRow()
end
end

local function GetItemNameById(id)
local err = "ERROR GetItemById() name value is nil(Item "..id.." May not exist in database)"
local search = WorldDBQuery("SELECT `name` FROM `item_template` WHERE `entry` = '"..id.."';");

if(search)then
local itemname = search:GetString(0)
return(itemname)
else
error(err)
end
end

local currency_name = GetItemById(LottoSettings.item)

local function GetId(name)
for id=1, #LottoEntries do
if(LottoEntries[id].name==name)then
return id;
end
end
end

local function NewLottoEntry(name, guidlow)
local NLEID = (#LottoEntries+1)

CharDBExecute("REPLACE INTO lotto.entries SET `name`='"..name.."';")
CharDBExecute("UPDATE lotto.entries SET `guid`='"..guidlow.."' WHERE `name`='"..name.."';")

LottoEntries[NLEID] = {
id = NLEID,
name = name,
guid = guidlow,
count = 0
};
end

local function EnterLotto(name, id)
local elcount = LottoEntries[id].count + 1
WorldDBQuery("UPDATE lotto.entries SET `count` = '"..elcount.."' WHERE `name` = '"..name.."';")
LottoEntries[id].count = elcount
LottoEntries.pot = LottoEntries.pot + LottoSettings.cost
end

local function FlushLotto(id)
WorldDBQuery("UPDATE lotto.entries SET `count` = '0';")

for a=1, #LottoEntries do
LottoEntries[a].count = 0
end
end

local function GetEntriez()
LottoEntriez = {};
Lotto = {
pot = 0
};

for a=1, #LottoEntries do

if(LottoEntries[a].count > 0)then
LottoEntriez[(#LottoEntriez+1)] = {
id = LottoEntries[a].id,
name = LottoEntries[a].name,
count = LottoEntries[a].count
};
Lotto.pot = ((Lotto.pot)+(LottoEntries[a].count))
end
end
return #LottoEntriez;
end

local function Tally(event)
local entriez = GetEntriez()
if(entriez < LottoSettings.require)then
SendWorldMessage("Not enough Loco Lotto Entries this round.")
SendWorldMessage("Visit a Loco Lotto Vendor to join.")
else
math.randomseed(tonumber(os.time()*os.time()))
local multiplier = math.random(1, LottoSettings.rndmax)
local win = math.random(1, entriez)
local name = LottoEntriez[win].name
local player = GetPlayerByName(name)

if(player)then
local bet = ((LottoEntriez[win].count * LottoSettings.cost) * multiplier)
local pot = ((Lotto.pot - LottoEntriez[win].count) * LottoSettings.cost)
SendWorldMessage("Contgratulations to "..LottoEntriez[win].name.." our new winner. Total:"..(pot + bet)..". Its LOCO!!")
print("Loco Lotto -- :Name:"..name..".:Pot:"..pot..".:Wager:"..LottoEntriez[win].count..".:Multiplier:"..multiplier)
FlushLotto(a)
LottoEntries.pot = 0
else
SendWorldMessage("You must be logged in to recieve winnings from the Loco Lotto.")
SendWorldMessage("No Winners this Loco lotto round.")
end
end

if (LottoSettings.operation ~= 1) then
RemoveEventById(LottoTimer)
LottoTimer = nil
end
end

local function LottoOnHello(event, player, unit)
local lohid = GetId(player:GetName())
local entered = GetEntriez()
if(entered==nil)then
local entered = 0
end
if(lohid==nil)then
NewLottoEntry(player:GetName(), player:GetGUIDLow())
LottoOnHello(event, player, unit)
else

if(LottoSettings.display_pot == 1)then
end

end
end

local function LottoOnSelect(event, player, unit, sender, intid, code)

if(intid<=10)then
LottoOnHello(1, player, unit)
end

if(intid==11)then
player:GossipComplete()
end

if(intid==100)then

if(player:GetItemCount(LottoSettings.item) >= LottoSettings.cost)then

local id = GetId(player:GetName())

if(id)then
if(LottoEntries[id].count < LottoSettings.maxcount)or(LottoSettings.maxcount== 0)then
player:RemoveItem(LottoSettings.item, LottoSettings.cost)
EnterLotto(player:GetName(), id)
else
player:SendBroadcastMessage("You Loco .. you can only enter "..LottoSettings.maxcount.." times.")
end
LottoOnHello(1, player, unit)
end
else
player:SendBroadcastMessage("You Loco .. you dont have enough currency to enter.")
player:GossipComplete()
end
end
end

RegisterCreatureGossipEvent(npcid, 1, LottoOnHello)
RegisterCreatureGossipEvent(npcid, 2, LottoOnSelect)

print("Grumbo'z Loco Lotto Operational.")

if(LottoSettings.operation==1)then
LottoTimer = CreateLuaEvent(Tally, LottoSettings.timer, 0)
print("...Lotto Started...")
else
print("...System idle...")
end
print("-----------------------------------")

8-3-14 updated:
moved the minimum required players value to the sql lotto.settings table for easier manipulation.

8-6-14 updated:
Vendor now states the cost (how much of what is the cost per round)

8-6-14 updated:
added a setting `maxcount` to allow a fixed max or infinite amount of entries per character .

9-8-2014 updated:
added to the gossip screen the dynamic actual value of the pot.
this feature can be turned on/off in the lotto sql settings `display_pot`.

Foereaper
07-27-2014, 08:16 PM
You should send the player an ingame mail if they're not online.

slp13at420
07-27-2014, 09:00 PM
You should send the player an ingame mail if they're not online.

yea I started with it using GetPlayerBy GUID/name but was having issues but may still put it back in if I can get it to work the sendmail method.

Rochet2
07-27-2014, 09:20 PM
if(GetPlayerByName(name))then
local player = GetPlayerByName(name)

Just FYI, things like GetPlayer.., get players in range .. get nearest creature ..
are heavy on the server.
It basically gets a player from ALL players on the server, or requires computing what is nearest etc.
Better make the variable first and then check if it is nil instead of getting it twice. Basically never do anything twice if you dont have to.
Cant check right now, but I also recall that getting player by name was even heavier when comparing player names.

As DB model I suggest having the values in memory when ever possible.
Then only use REPLACE INTO and SELECT statements to DB.
and delete from maybe.
Also when running REPLACE INTO or DELETE FROM, use the WorldDBExecute, which is async and will happen when the machine thinks it has resources to do it, instead of halting the code to wait for reply from SQL server which isnt used anyways.
Since the values are in memory all the time (in tables ?), you wont likely need to query so much all the time.
Table lookup with number keys (use low guid etc) should be really fast. When I tested, the speed seemed constant.

slp13at420
07-27-2014, 09:49 PM
yea its a Work in Progress.... lol
still needs some working over.
thnx for the info guyz :D

slp13at420
07-28-2014, 05:19 PM
-- fixed -- 7-28-14
fixed nil pot. now winner will receive there bonus plus the pot.
still needs some cleaning up but its doing exactly what I want it to do :D.

and YES I will be writing a second one that will be slow paced and pay a winner thru :SendMail() method so if they are offline they will still receive there winnings. -- :GetPlayerByGUID only works when players are online so the in game mail is dead for now.

slp13at420
07-29-2014, 01:17 AM
-- updated --
cleaned it up, dropped a bunch o crap , straightened it up , shredded it, dropped a table, dropped some dead weight, threw it against the wall a few times n here it is.
its fast paced 30 minute timer. so its only for players online. .. .... . yes I will make 1 for daily/weekly that will include off-line players. but that is for later.

http://i.imgur.com/P0Jk8Np.png

http://i.imgur.com/aAA9UyU.png

lol

slp13at420
07-30-2014, 12:21 AM
Putting it onto my live server caused it to freak out n shit a clay brick lol. so once again I shredded it and rebuilt it better. put it back on my live server and poof:

http://i.imgur.com/9E5Wv7q.png

so-far so-good

Rochet2
08-01-2014, 09:25 AM
Do not use GetUInt32 with BIGINT.
INT unsigned is uint32. I suggest you change the DB to use INT unsigned, as bigint is represented as a string in lua.
Even if it would work for you, it may not work for everyone if you set it up wrong like that. You also wont be able to use any bigger numbers that way and have no actual benefit.
If you do wish to use bigger number capacity, use float or double, or then keep in mind that you should not even try to represent any uint64 value in lua.
We could make some new object type for uint64 values though, that would support math etc, but Im not exactly sure if there is some point to this as uint32 should be plenty

LottoEntriez[(#LottoEntriez+1)]
I suggest you use table.insert(LottoEntriez, value)

There is no need for VendorRemoveAllItems. Unsure why it is there at all.

You should consider adding some safety limits, even though one is unlikely ever met.

I suggest you use the character database for scripts like this that require multiple trasactions with DB.
Char DB is configured better for that by default and usually as it is for that purpose, while world database is only queried seldom

Your SQL has an error. The data row insert for entries is incomplete.

I made a version I looked through some.. did not test it.
The benefits are among other: cleaner code, less table spam, local variables, efficiency
DB is bothered only when player is saved and if his data for lotto is not saved yet. Also on startup and when lotto ends.

--[[
-- --------------------------------------------------------
-- Host: localhost
-- Server version: 5.6.10 - MySQL Community Server (GPL)
-- Server OS: Win64
-- HeidiSQL Version: 8.3.0.4796
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

-- Dumping database structure for lotto
CREATE DATABASE IF NOT EXISTS `lotto` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `lotto`;

-- Dumping structure for table lotto.entries
CREATE TABLE IF NOT EXISTS `entries` (
`guid` int(11) unsigned NOT NULL COMMENT 'player db guid',
`count` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table lotto.entries: ~0 rows (approximately)
/*!40000 ALTER TABLE `entries` DISABLE KEYS */;
/*!40000 ALTER TABLE `entries` ENABLE KEYS */;

-- Dumping structure for table lotto.settings
CREATE TABLE IF NOT EXISTS `settings` (
`id` int(1) unsigned NOT NULL AUTO_INCREMENT,
`item` int(11) unsigned DEFAULT NULL,
`timer` int(10) unsigned NOT NULL,
`operation` tinyint(1) unsigned NOT NULL DEFAULT '0',
`mumax` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 MAX_ROWS=1;

-- Dumping data for table lotto.settings: ~0 rows (approximately)
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
INSERT INTO `settings` (`id`, `item`, `timer`, `operation`, `mumax`, `comments`) VALUES
(1, 44209, 1800000, 1, 10, 'item :\r\nthe item id for what they will win(custom currency)\r\n\r\ntimer :\r\n604800000 == 1 week\r\n86400000 == 1 day\r\n3600000 == 1 hour\r\n60000 == 1 minute');
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

]]

print("\n-----------------------------------")
print("Grumbo\'z Loco Lotto starting ...\n")
local npcid = 390000
local LottoTimer
local LottoSettings
local LottoEntries = {}

local function GetLotto(guidlow)
return LottoEntries[guidlow]
end

local function GetOrCreateLotto(guidlow)
LottoEntries[guidlow] = LottoEntries[guidlow] or {guid = guidlow, count = 0}
return GetLotto(guidlow)
end

local function LottoSave(lowguid)
local lotto = GetLotto(lowguid)
if (lotto and not lotto.saved) then
CharDBExecute("REPLACE INTO lotto.entries (`guid`, `count`) VALUES ("..lowguid..", "..lotto.count..")")
end
end

local function LottoDeleteAll()
LottoEntries = nil
CharDBExecute("DELETE FROM lotto.entries")
end

local LS = CharDBQuery("SELECT * FROM lotto.settings")
if (LS) then
LottoSettings = {
item = LS:GetUInt32(1),
timer = LS:GetUInt32(2),
operation = LS:GetUInt32(3),
mumax = LS:GetUInt32(4)
}
else
error("No settings found for lotto, cant start")
end

local LE = CharDBQuery("SELECT `guid`, `count` FROM lotto.entries")
if (LE) then
repeat
LottoEntries[LE:GetUInt32(0)] = {
guid = LE:GetUInt32(0),
count = LE:GetUInt32(1),
saved = true,
}
until not LE:NextRow()
end
end

local function Tally(event)

-- Make this a config
if (#LottoEntries < 4) then
SendWorldMessage("Not enough Loco Lotto Entries this round.")
return
end

local pot = 0
local entries = {}
for k,v in pairs(LottoEntries) do
pot = pot + v.count
table.insert(entries, k)
end

print("tally")

local winkey = entries[math.random(1, #entries)]
local winlotto = LottoEntries[winkey]
local player = GetPlayerByName(winlotto.name)

if (player) then
local multiplier = math.random(1, LottoSettings.mumax)
local bet = winlotto.count*multiplier
SendWorldMessage("Contgratulations to "..winlotto.name.." our new winner. Total:"..(pot+bet)..". Its LOCO!!")

for a=1, #LottoEntries do
FlushLotto(a)
end
else
-- Instead of this, could just get a new winner that is online, since atm there sorta is always a winner if all players are online
-- Or then think of some other logic that this isnt so random
SendWorldMessage("No Winners this Loco lotto round.")
end

if (LottoSettings.operation ~= 1) then
RemoveEventById(LottoTimer)
LottoTimer = nil
end

LottoDeleteAll()
end

local function LottoOnHello(event, player, unit)
local lotto = GetLotto(player:GetGUIDLow())
local count = lotto and lotto.count or 0
end

local function LottoOnSelect(event, player, unit, sender, intid, code)
if (intid == 0) then
player:GossipComplete()
return
end

if (intid == 1) then
if (player:GetItemCount(LottoSettings.item) == 0) then
player:SendBroadcastMessage("You Loco .. you dont have enough currency to enter.")
else
local guid = player:GetGUIDLow()
local lotto = GetOrCreateLotto(guid)
if (lotto) then
lotto.saved = nil
lotto.count = lotto.count+1
end
end
end

LottoOnHello(1, player, unit)
end

local function OnSave(event, player)
LottoSave(player:GetGUIDLow())
end

RegisterCreatureGossipEvent(npcid, 1, LottoOnHello)
RegisterCreatureGossipEvent(npcid, 2, LottoOnSelect)
RegisterPlayerEvent(25, OnSave)

print("Grumbo'z Loco Lotto Operational.")

if (LottoSettings.operation == 1) then
LottoTimer = CreateLuaEvent(Tally, LottoSettings.timer, 0)
print("...Lotto Started...")
else
print("...System idle...")
end
print("-----------------------------------\n")

slp13at420
08-02-2014, 11:20 PM
You should send the player an ingame mail if they're not online.

I have tried that but it appears that :GetPlayerByGUID/Name only works when the player character is online.

lines 175-178

SendWorldMessage("Contgratulations to "..LottoEntriez[win].name.." our new winner. Total:"..(pot + bet)..". Its LOCO!!")
print(GetPlayerByName(LottoEntriez[win].name))
print(GetPlayerByGUID(LottoEntriez[win].guid))
print("Loco Lotto -- :Name:"..name..".:Pot:"..pot..".:Wager:"..LottoEntriez[win].count..".:Multiplier:"..multiplier)

below I have 4 characters entered into the lotto (all same acct) but only 1 is online (nitestryke).

http://i.imgur.com/74Q5VYy.png

--[[-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 5.5.9-log - MySQL Community Server (GPL)
-- Server OS: Win32
-- HeidiSQL Version: 8.3.0.4694
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

-- Dumping database structure for lotto
CREATE DATABASE IF NOT EXISTS `lotto` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `lotto`;

-- Dumping structure for table lotto.entries
CREATE TABLE IF NOT EXISTS `entries` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`guid` bigint(20) NOT NULL,
`count` int(255) unsigned NOT NULL,
KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;

-- Dumping data for table lotto.entries: ~4 rows (approximately)
/*!40000 ALTER TABLE `entries` DISABLE KEYS */;
/*!40000 ALTER TABLE `entries` ENABLE KEYS */;

-- Dumping structure for table lotto.settings
CREATE TABLE IF NOT EXISTS `settings` (
`id` int(1) unsigned NOT NULL AUTO_INCREMENT,
`item` int(11) unsigned NOT NULL,
`cost` tinyint(3) unsigned NOT NULL,
`timer` int(10) unsigned NOT NULL,
`operation` tinyint(1) unsigned NOT NULL DEFAULT '0',
`rndmax` tinyint(1) unsigned NOT NULL DEFAULT '0',
`require` tinyint(3) unsigned NOT NULL DEFAULT '4',
`chaos` tinyint(1) unsigned NOT NULL DEFAULT '1',
KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 MAX_ROWS=1;

-- Dumping data for table lotto.settings: ~1 rows (approximately)
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
REPLACE INTO `settings` (`id`, `item`, `cost`, `timer`, `operation`, `rndmax`, `require`, `chaos`, `comments`) VALUES
(1, 44209, 1, 30000, 1, 10, 4, 0, 'item :\r\nthe item id for what they will win(custom currency)\r\n\r\ncost:\r\nhow many of (item) per entry\r\n\r\ntimer :\r\n604800000 == 1 week\r\n86400000 == 1 day\r\n3600000 == 1 hour\r\n60000 == 1 minute\r\n\r\nchaos:\r\n0-off/1-on\r\n0 - just pays thru :SendMail()\r\n1- if winner is off line then it just rolls all entries over and starts a new lotto.\r\n\r\nrequire:\r\nhow many entrries are required for the lotto to search for a winner.\r\ndefault = 4');
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;]]--

print("\n-----------------------------------")
print("Grumbo\'z Loco Lotto starting ...\n")
local npcid = 390000
Lotto = {};
LottoSettings = {};
LottoEntries = {};

local LS = WorldDBQuery("SELECT * FROM lotto.settings;");
if(LS)then
repeat
LottoSettings = {
item = LS:GetUInt32(1),
cost = LS:GetUInt32(2),
timer = LS:GetUInt32(3),
operation = LS:GetUInt32(4),
rndmax = LS:GetUInt32(5),
require = LS:GetUInt32(6),
chaos = LS:GetUInt32(7)
};
until not LS:NextRow()
end

local LE = WorldDBQuery("SELECT * FROM lotto.entries;");
if(LE)then
repeat
LottoEntries[LE:GetUInt32(0)] = {
id = LE:GetUInt32(0),
name = LE:GetString(1),
guid = LE:GetUInt32(2),
count = LE:GetUInt32(3)
};
until not LE:NextRow()
end
end

local function GetId(name)
for id=1, #LottoEntries do
if(LottoEntries[id].name==name)then
return id;
end
end
end

local function NewLottoEntry(name, guid, chain)
local NLEID = (#LottoEntries+1)

WorldDBExecute("REPLACE INTO lotto.entries SET `name`='"..name.."';")
WorldDBExecute("UPDATE lotto.entries SET `guid`='"..guid.."' WHERE `name`='"..name.."';")

LottoEntries[NLEID] = {
id = NLEID,
name = name,
guid = guid,
count = 0
};
end

local function EnterLotto(name, id)
local elcount = LottoEntries[id].count + 1
WorldDBQuery("UPDATE lotto.entries SET `count` = '"..elcount.."' WHERE `name` = '"..name.."';")
LottoEntries[id].count = elcount
end

local function FlushLotto(id)
WorldDBQuery("UPDATE lotto.entries SET `count` = '0';")

for a=1, #LottoEntries do
LottoEntries[a].count = 0
end
end

local function GetEntriez()
LottoEntriez = {};
Lotto = {
pot = 0
};

for a=1, #LottoEntries do

if(LottoEntries[a].count > 0)then
LottoEntriez[(#LottoEntriez+1)] = {
id = LottoEntries[a].id,
name = LottoEntries[a].name,
guid = LottoEntries[a].guid,
count = LottoEntries[a].count
};
Lotto.pot = ((Lotto.pot)+(LottoEntries[a].count))
end
end
return #LottoEntriez;
end

local function Tally(event)
local entriez = GetEntriez()
if(entriez < LottoSettings.require)then
SendWorldMessage("Not enough Loco Lotto Entries this round.")
SendWorldMessage("Visit a Loco Lotto Vendor to join.")
else
local multiplier = math.random(1, LottoSettings.rndmax)
local win = math.random(1, entriez)
local name = LottoEntriez[win].name
local player = GetPlayerByName(name)
local bet = ((LottoEntriez[win].count * LottoSettings.cost) * multiplier)
local pot = ((Lotto.pot - LottoEntriez[win].count) * LottoSettings.cost)

if(LottoSettings.chaos==1)then
if(player)then
SendWorldMessage("Contgratulations to "..LottoEntriez[win].name.." our new winner. Total:"..(pot + bet)..". Its LOCO!!")
print("Loco Lotto -- :Name:"..name..".:Pot:"..pot..".:Wager:"..LottoEntriez[win].count..".:Multiplier:"..multiplier)
FlushLotto(a)
else
SendWorldMessage("You must be logged in to recieve winnings from the Loco Lotto.")
SendWorldMessage("No Winners this Loco lotto round.")
end
else
SendWorldMessage("Contgratulations to "..LottoEntriez[win].name.." our new winner. Total:"..(pot + bet)..". Its LOCO!!")
print(GetPlayerByName(LottoEntriez[win].name)) -- SendMail("Test1", "Text1", LottoEntriez[win].guid, 1, 1, LottoSettings.item, (pot+bet))
print(GetPlayerByGUID(LottoEntriez[win].guid)) -- SendMail("Test1", "Text1", LottoEntriez[win].guid, 1, 1, LottoSettings.item, (pot+bet))
print("Loco Lotto -- :Name:"..name..".:Pot:"..pot..".:Wager:"..LottoEntriez[win].count..".:Multiplier:"..multiplier)
-- FlushLotto(a)
end
end

if(LottoSettings.operation==1)then
CreateLuaEvent(Tally, LottoSettings.timer, 1)
end
end

local function LottoOnHello(event, player, unit)
local lohid = GetId(player:GetName())

if(lohid==nil)then
NewLottoEntry(player:GetName(), player:GetGUIDLow(), 0)
LottoOnHello(event, player, unit)
else
VendorRemoveAllItems(npcid)
end
end

local function LottoOnSelect(event, player, unit, sender, intid, code)

if(intid<=10)then
LottoOnHello(1, player, unit)
end

if(intid==11)then
player:GossipComplete()
end

if(intid==100)then
local id = GetId(player:GetName())
if(id)then
if(player:GetItemCount(LottoSettings.item) < LottoSettings.cost)then
player:SendBroadcastMessage("You Loco .. you dont have enough currency to enter.")
else
player:RemoveItem(LottoSettings.item, LottoSettings.cost)
EnterLotto(player:GetName(), id)
end
end
LottoOnHello(1, player, unit)
end
end

RegisterCreatureGossipEvent(npcid, 1, LottoOnHello)
RegisterCreatureGossipEvent(npcid, 2, LottoOnSelect)

print("Grumbo'z Loco Lotto Operational.")

if(LottoSettings.operation==1)then
CreateLuaEvent(Tally, LottoSettings.timer, 1)
print("...Lotto Started...")
else
print("...System idle...")
end
print("-----------------------------------\n")

so I made it roll all entries over and starts a new lotto. I also tried a loop if picked player is off-line then run the tally again. but... if all entered players are offline then it loops until it crashes lol. or if only 1 of ALL entered players is on line then it loops until it finally picks the online player if it doesn't crash first from loops lol. sooo I sped this up to help promote online player activity.

Recommended setting:
10 to 15 minutes --> 600000 to 900000 ms

slp13at420
08-03-2014, 04:01 PM
Do not use GetUInt32 with BIGINT.
INT unsigned is uint32. I suggest you change the DB to use INT unsigned, as bigint is represented as a string in lua.
Even if it would work for you, it may not work for everyone if you set it up wrong like that. You also wont be able to use any bigger numbers that way and have no actual benefit.
If you do wish to use bigger number capacity, use float or double, or then keep in mind that you should not even try to represent any uint64 value in lua.
We could make some new object type for uint64 values though, that would support math etc, but Im not exactly sure if there is some point to this as uint32 should be plenty

LottoEntriez[(#LottoEntriez+1)]
I suggest you use table.insert(LottoEntriez, value)

There is no need for VendorRemoveAllItems. Unsure why it is there at all.

You should consider adding some safety limits, even though one is unlikely ever met.

I suggest you use the character database for scripts like this that require multiple trasactions with DB.
Char DB is configured better for that by default and usually as it is for that purpose, while world database is only queried seldom

Your SQL has an error. The data row insert for entries is incomplete.

I made a version I looked through some.. did not test it.
The benefits are among other: cleaner code, less table spam, local variables, efficiency
DB is bothered only when player is saved and if his data for lotto is not saved yet. Also on startup and when lotto ends.

o.O wow a lot more advanced than mine but I understand what it's doing. does have a few hic-ups . if there are gaps between GUIDs then it drops them. i.e. if these GUID's are entered 1,2,3,5 then it only see's 3 GUIDs entered and wont trigger a tally.

I did add the minimum required entries to the lotto.settings sql table for easy changing.
also added a cost to the lotto.settings sql table so it can charge 1 custom coin or more now per entry.
also removed the (vendorRemoveItems) .. I just copied another vendor and forgot to remove that lol.

so I uploaded yours to my GitHub so I can experiment n play with it and get it to function properly.

https://github.com/BlackWolfsDen/testing/blob/master/lottory1/lottery1.lua

Rochet2
08-03-2014, 09:41 PM
o.O wow a lot more advanced than mine but I understand what it's doing. does have a few hic-ups . if there are gaps between GUIDs then it drops them. i.e. if these GUID's are entered 1,2,3,5 then it only see's 3 GUIDs entered and wont trigger a tally.

You are right, should check the amount of players after getting the entries. So #entries instead.

Xaver
08-16-2014, 03:11 PM
hello

this script have one problem

wen i logen in game and talk npc and join the lotto and log out = crash the server

slp13at420
08-16-2014, 05:06 PM
hello this script have one problem when i logen in game and talk npc and join the lotto and log out = crash the server
what error if any are you getting in your console. i tried to recreate the event but with no success.
what core rev?

Rochet2
08-17-2014, 08:21 AM
hello this script have one problem when i logen in game and talk npc and join the lotto and log out = crash the server

Post the script you are using and see Eluna.log for the error messages if any.
Also it would be nice if you could compile in debug mode and get a crash log (crash it again)

Additionally you could tell us when exactly does the script crash after player has logged out?
Is it instant? Is it when the lotto is processed?