Lua scripts pack. It is a part of PvPGN now.
First large implementation in Lua is Trivia Quiz Game (/quiz command) http://i.imgur.com/8QV3blt.png
This commit is contained in:
parent
4d862593b4
commit
ee04fdd23d
36 changed files with 7534 additions and 22 deletions
|
@ -30,5 +30,9 @@ option(WITH_PGSQL "include PostgreSQL user accounts support" OFF)
|
|||
option(WITH_ODBC "include ODBC user accounts support" OFF)
|
||||
include(ConfigureChecks.cmake)
|
||||
|
||||
subdirs(src conf man files lua)
|
||||
subdirs(src conf man files)
|
||||
if(WITH_LUA)
|
||||
add_subdirectory(lua)
|
||||
endif(WITH_LUA)
|
||||
|
||||
ENABLE_TESTING()
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
--------------------------------------------------------
|
||||
/games all
|
||||
Displays a list of all games.
|
||||
/games [l]obby
|
||||
/games l[obby]
|
||||
Displays a list of games in lobby.
|
||||
|
||||
%channels chs
|
||||
|
@ -383,11 +383,11 @@
|
|||
--------------------------------------------------------
|
||||
/mail <command> [options]
|
||||
--------------------------------------------------------
|
||||
/mail [s]end <receiver> <message>
|
||||
/mail s[end] <receiver> <message>
|
||||
Sends mail to <receiver> with <message>.
|
||||
/mail [r]ead [index]
|
||||
/mail r[ead] [index]
|
||||
Reads mail [index]
|
||||
/mail [del]ete {all|<index>}
|
||||
/mail del[ete] {all|<index>}
|
||||
Deletes mail <index> or [all] mail.
|
||||
|
||||
%flag
|
||||
|
@ -411,7 +411,7 @@
|
|||
--------------------------------------------------------
|
||||
/ipban <command> [option] [time]
|
||||
--------------------------------------------------------
|
||||
/ipban [l[ist]]
|
||||
/ipban l[ist]
|
||||
Displays a list of banned IP addresses
|
||||
/ipban c[heck] <IP>
|
||||
Checks if IP address <IP> is banned or not.
|
||||
|
@ -460,25 +460,25 @@
|
|||
Create a new clan (max <clantag> length = 4; spaces are allowed in <clanname>)
|
||||
|
||||
Commands for clan members:
|
||||
/clan [m]sg <message> (alias [w]hisper)
|
||||
/clan m[sg] <message> (alias [w]hisper)
|
||||
Whispers a message to all your fellow clan members
|
||||
/clan [inv]ite <username>
|
||||
/clan inv[ite] <username>
|
||||
Invite <username> to your clan.
|
||||
/clan [inv]ite get
|
||||
/clan inv[ite] get
|
||||
Show clanname which you have been invited
|
||||
/clan [inv]ite accept
|
||||
/clan inv[ite] accept
|
||||
Accept invitation to clan
|
||||
/clan [inv]ite decline
|
||||
/clan inv[ite] decline
|
||||
Decline invitation to clan
|
||||
|
||||
Commands for clan chieftain:
|
||||
/clan motd <message>
|
||||
Update the clan's Message of the Day to <message>.
|
||||
/clan [pub]lic (alias: pub)
|
||||
/clan pub[lic] (alias: pub)
|
||||
Opens the clan channel up to the public so that anyone may enter.
|
||||
/clan [priv]ate (alias: priv)
|
||||
/clan priv[ate] (alias: priv)
|
||||
Closes the clan channel such that only members of the clan may enter.
|
||||
/clan [dis]band
|
||||
/clan dis[band]
|
||||
Disband your clan.
|
||||
|
||||
%ping p latency
|
||||
|
@ -589,13 +589,27 @@ Commands for clan chieftain:
|
|||
Use /icon without [name] to display list of available icons in your stash.
|
||||
--------------------------------------------------------
|
||||
Syntax for operator/admin:
|
||||
/icon [a]dd <username> <icon>
|
||||
/icon a[dd] <username> <icon>
|
||||
Add icon into user stash
|
||||
/icon [d]el <username> <icon>
|
||||
/icon d[el] <username> <icon>
|
||||
Remove icon from user stash
|
||||
/icon [s]et <username> <icon>
|
||||
/icon s[et] <username> <icon>
|
||||
Set custom icon to user without adding it in user stash
|
||||
/icon [l]ist <username>
|
||||
/icon l[ist] <username>
|
||||
Display icons in user's stash
|
||||
/icon [l]ist
|
||||
/icon l[ist]
|
||||
Display availaible icons in server stash that can be assigned to users
|
||||
|
||||
%quiz
|
||||
--------------------------------------------------------
|
||||
/quiz <command> [option]
|
||||
Trivia Quiz Game
|
||||
--------------------------------------------------------
|
||||
/quiz start <name>
|
||||
Start game with given dictionary name in current channel
|
||||
/quiz stop
|
||||
Finish game by force
|
||||
/quiz stats [username]
|
||||
Display record statistics for user
|
||||
/quiz stats
|
||||
Display Top records
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
# TODO: add lua files here
|
||||
# copy all files from lua directory
|
||||
|
||||
file(GLOB DEPLOY_FILES_AND_DIRS "${PROJECT_SOURCE_DIR}/lua/*")
|
||||
|
||||
foreach(ITEM ${DEPLOY_FILES_AND_DIRS})
|
||||
IF( IS_DIRECTORY "${ITEM}" )
|
||||
LIST( APPEND DIRS_TO_DEPLOY "${ITEM}" )
|
||||
ELSE()
|
||||
IF(NOT ${ITEM} MATCHES "CMakeLists.txt")
|
||||
LIST( APPEND FILES_TO_DEPLOY "${ITEM}" )
|
||||
ENDIF(NOT ${ITEM} MATCHES "CMakeLists.txt")
|
||||
ENDIF()
|
||||
endforeach()
|
||||
|
||||
INSTALL( FILES ${FILES_TO_DEPLOY} DESTINATION ${LOCALSTATEDIR}/lua )
|
||||
INSTALL( DIRECTORY ${DIRS_TO_DEPLOY} DESTINATION ${LOCALSTATEDIR}/lua )
|
||||
|
||||
install(FILES
|
||||
DESTINATION ${LOCALSTATEDIR}/lua)
|
||||
|
|
32
lua/command/redirect.lua
Normal file
32
lua/command/redirect.lua
Normal file
|
@ -0,0 +1,32 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Send text to user from server. Works like /announce,
|
||||
-- but directly to user and message text is not red.
|
||||
-- /redirect <username> <message>
|
||||
function command_redirect(account, text)
|
||||
|
||||
local args = split_command(text, 2)
|
||||
|
||||
if not args[1] or not args[2] then
|
||||
api.describe_command(account.name, args[0])
|
||||
return 1
|
||||
end
|
||||
|
||||
-- get destination account
|
||||
local dest = api.account_get_by_name(args[1])
|
||||
|
||||
if next(dest) == nil or dest.online == "false" then
|
||||
api.message_send_text(account.name, message_type_error, account.name, "User '" ..args[1].. "' is offline")
|
||||
return 1
|
||||
end
|
||||
|
||||
api.message_send_text(dest.name, message_type_info, dest.name, args[2])
|
||||
|
||||
return 1
|
||||
end
|
29
lua/command/w3motd.lua
Normal file
29
lua/command/w3motd.lua
Normal file
|
@ -0,0 +1,29 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
--
|
||||
-- Read file w3motd.txt line by line and send text to user
|
||||
--
|
||||
|
||||
local username = nil
|
||||
|
||||
function command_w3motd(account, text)
|
||||
-- allow warcraft 3 client only
|
||||
if not (account.clienttag == "W3XP" or account.clienttag == "WAR3") then
|
||||
return 0
|
||||
end
|
||||
|
||||
username = account.name
|
||||
local data = file_load(config.motdw3file, w3motd_sendline_callback)
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
function w3motd_sendline_callback(line)
|
||||
api.message_send_text(username, message_type_info, nil, line)
|
||||
end
|
23
lua/config.lua
Normal file
23
lua/config.lua
Normal file
|
@ -0,0 +1,23 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Config table can be extended here with your own variables
|
||||
-- values are preloaded from bnetd.conf
|
||||
config = {
|
||||
-- Quiz settings
|
||||
quiz = true,
|
||||
quiz_filelist = "misc, dota, warcraft", -- display available files in "/quiz start"
|
||||
quiz_competitive_mode = true, -- top players loses half of points which last player received; at the end top of records loses half of points which players received in current game
|
||||
quiz_max_questions = 100, -- from start to end
|
||||
quiz_question_delay = 5, -- delay before send next question
|
||||
quiz_hint_delay = 20, -- delay between prompts
|
||||
quiz_users_in_top = 15, -- how many users display in TOP list
|
||||
quiz_channel = nil, -- (do not modify!) channel when quiz has started (it assigned with start)
|
||||
|
||||
}
|
||||
|
26
lua/extend/account.lua
Normal file
26
lua/extend/account.lua
Normal file
|
@ -0,0 +1,26 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Get count of all online users
|
||||
function users_get_count()
|
||||
local count = 0
|
||||
for id,username in pairs(api.server_get_users()) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
-- Get count of all server account
|
||||
function accounts_get_count()
|
||||
local count = 0
|
||||
for id,username in pairs(api.server_get_users(true)) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
516
lua/extend/account_wrap.lua
Normal file
516
lua/extend/account_wrap.lua
Normal file
|
@ -0,0 +1,516 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- All attribute get/set actions must have a wrapper to avoid write a wrong type into database
|
||||
|
||||
--
|
||||
-- Profile
|
||||
--
|
||||
|
||||
function account_get_acct_email(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\email", attr_type_str)
|
||||
end
|
||||
function account_set_acct_email(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\email", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_auth_admin(username, channelname)
|
||||
if channelname then
|
||||
return api.account_get_attr(username, "BNET\\auth\\admin\\" .. channelname, attr_type_bool)
|
||||
else
|
||||
return api.account_get_attr(username, "BNET\\auth\\admin", attr_type_bool)
|
||||
end
|
||||
end
|
||||
function account_set_auth_admin(username, channelname, value)
|
||||
if channelname then
|
||||
return api.account_set_attr(username, "BNET\\auth\\admin\\" .. channelname, attr_type_bool, value)
|
||||
else
|
||||
return api.account_set_attr(username, "BNET\\auth\\admin", attr_type_bool, value)
|
||||
end
|
||||
end
|
||||
|
||||
function account_get_auth_operator(username, channelname)
|
||||
if channelname then
|
||||
return api.account_get_attr(username, "BNET\\auth\\operator\\" .. channelname, attr_type_bool)
|
||||
else
|
||||
return api.account_get_attr(username, "BNET\\auth\\operator", attr_type_bool)
|
||||
end
|
||||
end
|
||||
function account_set_auth_operator(username, channelname, value)
|
||||
if channelname then
|
||||
return api.account_set_attr(username, "BNET\\auth\\operator\\" .. channelname, attr_type_bool, value)
|
||||
else
|
||||
return api.account_set_attr(username, "BNET\\auth\\operator", attr_type_bool, value)
|
||||
end
|
||||
end
|
||||
|
||||
function account_get_auth_voice(username, channelname)
|
||||
if channelname then
|
||||
return api.account_get_attr(username, "BNET\\auth\\voice\\" .. channelname, attr_type_bool)
|
||||
else
|
||||
return api.account_get_attr(username, "BNET\\auth\\voice", attr_type_bool)
|
||||
end
|
||||
end
|
||||
function account_set_auth_voice(username, channelname, value)
|
||||
if channelname then
|
||||
return api.account_set_attr(username, "BNET\\auth\\voice\\" .. channelname, attr_type_bool, value)
|
||||
else
|
||||
return api.account_set_attr(username, "BNET\\auth\\voice", attr_type_bool, value)
|
||||
end
|
||||
end
|
||||
|
||||
function account_is_operator_or_admin(username, channelname)
|
||||
return account_get_auth_operator(username, channelname) or account_get_auth_admin(username, channelname) or account_get_auth_operator(username, nil) or account_get_auth_admin(username, nil)
|
||||
end
|
||||
|
||||
|
||||
function account_get_auth_announce(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\announce", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_announce(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\announce", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_botlogin(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\botlogin", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_botlogin(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\botlogin", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_lock(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\lockk", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_lock(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\lockk", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_locktime(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\locktime", attr_type_int)
|
||||
end
|
||||
function account_set_auth_locktime(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\locktime", attr_type_int, value)
|
||||
end
|
||||
|
||||
function account_get_auth_lockreason(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\lockreason", attr_type_str)
|
||||
end
|
||||
function account_set_auth_lockreason(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\lockreason", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_auth_lockby(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\lockby", attr_type_str)
|
||||
end
|
||||
function account_set_auth_lockby(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\lockby", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_auth_mute(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\mute", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_mute(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\mute", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_mutetime(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\mutetime", attr_type_int)
|
||||
end
|
||||
function account_set_auth_mutetime(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\mutetime", attr_type_int, value)
|
||||
end
|
||||
|
||||
function account_get_auth_mutereason(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\mutereason", attr_type_str)
|
||||
end
|
||||
function account_set_auth_mutereason(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\mutereason", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_auth_muteby(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\muteby", attr_type_str)
|
||||
end
|
||||
function account_set_auth_muteby(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\muteby", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_auth_command_groups(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\command_groups", attr_type_int)
|
||||
end
|
||||
function account_set_auth_command_groups(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\command_groups", attr_type_int, value)
|
||||
end
|
||||
|
||||
function account_get_acct_lastlogin_time(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\lastlogin_time", attr_type_int)
|
||||
end
|
||||
function account_set_acct_lastlogin_time(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\lastlogin_time", attr_type_int, value)
|
||||
end
|
||||
|
||||
function account_get_acct_lastlogin_owner(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\lastlogin_owner", attr_type_str)
|
||||
end
|
||||
function account_set_acct_lastlogin_owner(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\lastlogin_owner", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_acct_createtime(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\ctime", attr_type_int)
|
||||
end
|
||||
function account_set_acct_createtime(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\ctime", attr_type_int, value)
|
||||
end
|
||||
|
||||
function account_get_acct_lastlogin_clienttag(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\lastlogin_clienttag", attr_type_str)
|
||||
end
|
||||
function account_set_acct_lastlogin_clienttag(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\lastlogin_clienttag", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_acct_lastlogin_ip(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\lastlogin_ip", attr_type_str)
|
||||
end
|
||||
function account_set_acct_lastlogin_ip(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\lastlogin_ip", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_acct_passhash(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\passhash1", attr_type_str)
|
||||
end
|
||||
function account_set_acct_passhash(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\passhash1", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_acct_verifier(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\verifier", attr_type_raw)
|
||||
end
|
||||
function account_set_acct_verifier(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\verifier", attr_type_raw, value)
|
||||
end
|
||||
|
||||
function account_get_acct_salt(username)
|
||||
return api.account_get_attr(username, "BNET\\acct\\salt", attr_type_raw)
|
||||
end
|
||||
function account_set_acct_salt(username, value)
|
||||
return api.account_set_attr(username, "BNET\\acct\\salt", attr_type_raw, value)
|
||||
end
|
||||
|
||||
--
|
||||
-- Profile
|
||||
--
|
||||
|
||||
function account_get_auth_adminnormallogin(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\adminnormallogin", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_adminnormallogin(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\adminnormallogin", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_changepass(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\changepass", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_changepass(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\changepass", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_changeprofile(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\changeprofile", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_changeprofile(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\changeprofile", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_createnormalgame(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\createnormalgame", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_createnormalgame(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\createnormalgame", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_joinnormalgame(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\joinnormalgame", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_joinnormalgame(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\joinnormalgame", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_createladdergame(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\createladdergame", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_createladdergame(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\createladdergame", attr_type_bool, value)
|
||||
end
|
||||
|
||||
function account_get_auth_joinladdergame(username)
|
||||
return api.account_get_attr(username, "BNET\\auth\\joinladdergame", attr_type_bool)
|
||||
end
|
||||
function account_set_auth_joinladdergame(username, value)
|
||||
return api.account_set_attr(username, "BNET\\auth\\joinladdergame", attr_type_bool, value)
|
||||
end
|
||||
|
||||
--
|
||||
-- Profile
|
||||
--
|
||||
|
||||
function account_get_sex(username)
|
||||
return api.account_get_attr(username, "profile\\sex", attr_type_str)
|
||||
end
|
||||
function account_set_sex(username, value)
|
||||
return api.account_set_attr(username, "profile\\sex", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_age(username)
|
||||
return api.account_get_attr(username, "profile\\age", attr_type_str)
|
||||
end
|
||||
function account_set_age(username, value)
|
||||
return api.account_set_attr(username, "profile\\age", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_location(username)
|
||||
return api.account_get_attr(username, "profile\\location", attr_type_str)
|
||||
end
|
||||
function account_set_location(username, value)
|
||||
return api.account_set_attr(username, "profile\\location", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_description(username)
|
||||
return api.account_get_attr(username, "profile\\description", attr_type_str)
|
||||
end
|
||||
function account_set_description(username, value)
|
||||
return api.account_set_attr(username, "profile\\description", attr_type_str, value)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Warcraft 3
|
||||
--
|
||||
|
||||
function account_get_soloxp(username)
|
||||
return api.account_get_attr(username, "Record\\W3XP\\solo_xp", attr_type_num)
|
||||
end
|
||||
function account_set_soloxp(username, value)
|
||||
return api.account_set_attr(username, "Record\\W3XP\\solo_xp", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_sololevel(username)
|
||||
return api.account_get_attr(username, "Record\\W3XP\\solo_level", attr_type_num)
|
||||
end
|
||||
function account_set_sololevel(username, value)
|
||||
return api.account_set_attr(username, "Record\\W3XP\\solo_level", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_solowins(username)
|
||||
return api.account_get_attr(username, "Record\\W3XP\\solo_wins", attr_type_num)
|
||||
end
|
||||
function account_set_solowins(username, value)
|
||||
return api.account_set_attr(username, "Record\\W3XP\\solo_wins", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_sololosses(username)
|
||||
return api.account_get_attr(username, "Record\\W3XP\\solo_losses", attr_type_num)
|
||||
end
|
||||
function account_set_sololosses(username, value)
|
||||
return api.account_set_attr(username, "Record\\W3XP\\solo_losses", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_solorank(username)
|
||||
return api.account_get_attr(username, "Record\\W3XP\\solo_rank", attr_type_num)
|
||||
end
|
||||
function account_set_solorank(username, value)
|
||||
return api.account_set_attr(username, "Record\\W3XP\\solo_rank", attr_type_num, value)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Starcraft
|
||||
--
|
||||
|
||||
function account_get_normal_wins(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\0\\wins", attr_type_num)
|
||||
end
|
||||
function account_set_normal_wins(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\0\\wins", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_losses(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\0\\losses", attr_type_num)
|
||||
end
|
||||
function account_set_normal_losses(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\0\\losses", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_draws(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\0\\draws", attr_type_num)
|
||||
end
|
||||
function account_set_normal_draws(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\0\\draws", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_disconnects(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\0\\disconnects", attr_type_num)
|
||||
end
|
||||
function account_set_normal_disconnects(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\0\\disconnects", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_last_time(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\0\\last game", attr_type_num)
|
||||
end
|
||||
function account_set_normal_last_time(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\0\\last game", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_last_result(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\0\\last game result", attr_type_num)
|
||||
end
|
||||
function account_set_normal_last_result(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\0\\last game result", attr_type_num, value)
|
||||
end
|
||||
|
||||
|
||||
function account_get_ladder_wins(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\wins", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_wins(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\wins", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_losses(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\losses", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_losses(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\losses", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_draws(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\draws", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_draws(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\draws", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_disconnects(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\disconnects", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_disconnects(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\disconnects", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_last_time(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\last game", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_last_time(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\last game", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_last_result(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\last game result", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_last_result(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\last game result", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_rating(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\rating", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_rating(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\rating", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_ladder_rank(username)
|
||||
return api.account_get_attr(username, "Record\\SEXP\\1\\rank", attr_type_num)
|
||||
end
|
||||
function account_set_ladder_rank(username, value)
|
||||
return api.account_set_attr(username, "Record\\SEXP\\1\\rank", attr_type_num, value)
|
||||
end
|
||||
|
||||
-- TODO: wrappers for 2x2
|
||||
|
||||
|
||||
--
|
||||
-- Warcraft 2
|
||||
--
|
||||
|
||||
--[[ Warcraft 2 has the same functions as Starcraft, but "W2BN" instead of "SEXP" in path. Replace it if you have a single 2 server. ]]--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Diablo
|
||||
--
|
||||
|
||||
function account_get_normal_level(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\level", attr_type_num)
|
||||
end
|
||||
function account_set_normal_level(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\level", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_class(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\class", attr_type_num)
|
||||
end
|
||||
function account_set_normal_class(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\class", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_diablo_kills(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\diablo kills", attr_type_num)
|
||||
end
|
||||
function account_set_normal_diablo_kills(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\diablo kills", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_strength(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\strength", attr_type_num)
|
||||
end
|
||||
function account_set_normal_strength(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\strength", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_dexterity(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\dexterity", attr_type_num)
|
||||
end
|
||||
function account_set_normal_dexterity(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\dexterity", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_vitality(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\vitality", attr_type_num)
|
||||
end
|
||||
function account_set_normal_vitality(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\vitality", attr_type_num, value)
|
||||
end
|
||||
|
||||
function account_get_normal_gold(username)
|
||||
return api.account_get_attr(username, "Record\\DRTL\\0\\gold", attr_type_num)
|
||||
end
|
||||
function account_set_normal_gold(username, value)
|
||||
return api.account_set_attr(username, "Record\\DRTL\\0\\gold", attr_type_num, value)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Westwood Online
|
||||
--
|
||||
|
||||
function account_get_wol_apgar(username)
|
||||
return api.account_get_attr(username, "Record\\WOL\\auth\\apgar", attr_type_str)
|
||||
end
|
||||
function account_set_wol_apgar(username, value)
|
||||
return api.account_set_attr(username, "Record\\WOL\\auth\\apgar", attr_type_str, value)
|
||||
end
|
||||
|
||||
function account_get_locale(username)
|
||||
return api.account_get_attr(username, "Record\\WOL\\auth\\locale", attr_type_str)
|
||||
end
|
||||
function account_set_locale(username, value)
|
||||
return api.account_set_attr(username, "Record\\WOL\\auth\\locale", attr_type_str, value)
|
||||
end
|
43
lua/extend/channel.lua
Normal file
43
lua/extend/channel.lua
Normal file
|
@ -0,0 +1,43 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Return channel id by name (if channel not found then return -1)
|
||||
function channel_get_id_by_name(channel_name)
|
||||
for id,name in pairs(api.server_get_channels()) do
|
||||
if name == channel_name then
|
||||
return id
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
|
||||
-- Send message in channel
|
||||
-- message_type: message_type_info | message_type_error
|
||||
function channel_send_message(channel_name, text, message_type)
|
||||
channel_id = channel_get_id_by_name(channel_name)
|
||||
if (channel_id == -1) then
|
||||
return nil
|
||||
end
|
||||
|
||||
channel = api.channel_get_by_id(channel_id)
|
||||
|
||||
for username in string.split(channel.memberlist,",") do
|
||||
api.message_send_text(username, message_type, nil, text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Get count of all channels
|
||||
function channels_get_count()
|
||||
local count = 0
|
||||
for id,channelname in pairs(api.server_get_channels()) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
13
lua/extend/enum/attr.lua
Normal file
13
lua/extend/enum/attr.lua
Normal file
|
@ -0,0 +1,13 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
attr_type_str,
|
||||
attr_type_num,
|
||||
attr_type_bool,
|
||||
attr_type_raw
|
||||
= 0,1,2,3
|
17
lua/extend/enum/eventlog.lua
Normal file
17
lua/extend/enum/eventlog.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
eventlog_level_none,
|
||||
eventlog_level_trace,
|
||||
eventlog_level_debug,
|
||||
eventlog_level_info,
|
||||
eventlog_level_warn,
|
||||
eventlog_level_error,
|
||||
eventlog_level_fatal,
|
||||
eventlog_level_gui -- Win32 GUI
|
||||
= 0,1,2,4,8,16,32,64
|
133
lua/extend/enum/game.lua
Normal file
133
lua/extend/enum/game.lua
Normal file
|
@ -0,0 +1,133 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
game_type_none,
|
||||
game_type_all,
|
||||
game_type_topvbot,
|
||||
game_type_melee,
|
||||
game_type_ffa,
|
||||
game_type_oneonone,
|
||||
game_type_ctf,
|
||||
game_type_greed,
|
||||
game_type_slaughter,
|
||||
game_type_sdeath,
|
||||
game_type_ladder,
|
||||
game_type_ironman,
|
||||
game_type_mapset,
|
||||
game_type_teammelee,
|
||||
game_type_teamffa,
|
||||
game_type_teamctf,
|
||||
game_type_pgl,
|
||||
game_type_diablo,
|
||||
game_type_diablo2open,
|
||||
game_type_diablo2closed,
|
||||
game_type_anongame
|
||||
= 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
|
||||
|
||||
|
||||
game_status_started,
|
||||
game_status_full,
|
||||
game_status_open,
|
||||
game_status_loaded,
|
||||
game_status_done
|
||||
= 0,1,2,3,4
|
||||
|
||||
|
||||
game_result_none,
|
||||
game_result_win,
|
||||
game_result_loss,
|
||||
game_result_draw,
|
||||
game_result_disconnect,
|
||||
game_result_observer,
|
||||
game_result_playing
|
||||
= 0,1,2,3,4,5,6
|
||||
|
||||
|
||||
game_option_none,
|
||||
game_option_melee_normal,
|
||||
game_option_ffa_normal,
|
||||
game_option_oneonone_normal,
|
||||
game_option_ctf_normal,
|
||||
game_option_greed_10000,
|
||||
game_option_greed_7500,
|
||||
game_option_greed_5000,
|
||||
game_option_greed_2500,
|
||||
game_option_slaughter_60,
|
||||
game_option_slaughter_45,
|
||||
game_option_slaughter_30,
|
||||
game_option_slaughter_15,
|
||||
game_option_sdeath_normal,
|
||||
game_option_ladder_countasloss,
|
||||
game_option_ladder_nopenalty,
|
||||
game_option_mapset_normal,
|
||||
game_option_teammelee_4,
|
||||
game_option_teammelee_3,
|
||||
game_option_teammelee_2,
|
||||
game_option_teamffa_4,
|
||||
game_option_teamffa_3,
|
||||
game_option_teamffa_2,
|
||||
game_option_teamctf_4,
|
||||
game_option_teamctf_3,
|
||||
game_option_teamctf_2,
|
||||
game_option_topvbot_7,
|
||||
game_option_topvbot_6,
|
||||
game_option_topvbot_5,
|
||||
game_option_topvbot_4,
|
||||
game_option_topvbot_3,
|
||||
game_option_topvbot_2,
|
||||
game_option_topvbot_1
|
||||
= 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
|
||||
|
||||
|
||||
game_maptype_none,
|
||||
game_maptype_selfmade,
|
||||
game_maptype_blizzard,
|
||||
game_maptype_ladder,
|
||||
game_maptype_pgl,
|
||||
game_maptype_kbk,
|
||||
game_maptype_compusa
|
||||
= 0,1,2,3,4,5,6
|
||||
|
||||
|
||||
game_tileset_none,
|
||||
game_tileset_badlands,
|
||||
game_tileset_space,
|
||||
game_tileset_installation,
|
||||
game_tileset_ashworld,
|
||||
game_tileset_jungle,
|
||||
game_tileset_desert,
|
||||
game_tileset_ice,
|
||||
game_tileset_twilight
|
||||
= 0,1,2,3,4,5,6,7,8,9
|
||||
|
||||
|
||||
game_speed_none,
|
||||
game_speed_slowest,
|
||||
game_speed_slower,
|
||||
game_speed_slow,
|
||||
game_speed_normal,
|
||||
game_speed_fast,
|
||||
game_speed_faster,
|
||||
game_speed_fastest
|
||||
= 0,1,2,3,4,5,6,7
|
||||
|
||||
|
||||
game_difficulty_none,
|
||||
game_difficulty_normal,
|
||||
game_difficulty_nightmare,
|
||||
game_difficulty_hell,
|
||||
game_difficulty_hardcore_normal,
|
||||
game_difficulty_hardcore_nightmare,
|
||||
game_difficulty_hardcore_hell
|
||||
= 0,1,2,3,4,5,6
|
||||
|
||||
|
||||
game_flag_none,
|
||||
game_flag_private
|
||||
= 0,1
|
||||
|
46
lua/extend/enum/message.lua
Normal file
46
lua/extend/enum/message.lua
Normal file
|
@ -0,0 +1,46 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
message_type_adduser,
|
||||
message_type_join,
|
||||
message_type_part,
|
||||
message_type_whisper,
|
||||
message_type_talk,
|
||||
message_type_broadcast,
|
||||
message_type_channel,
|
||||
message_type_userflags,
|
||||
message_type_whisperack,
|
||||
message_type_friendwhisperack,
|
||||
message_type_channelfull,
|
||||
message_type_channeldoesnotexist,
|
||||
message_type_channelrestricted,
|
||||
message_type_info,
|
||||
message_type_error,
|
||||
message_type_emote,
|
||||
message_type_uniqueid, -- bad message type?
|
||||
message_type_mode, -- bad message type?
|
||||
message_type_kick,
|
||||
message_type_quit,
|
||||
-- IRC specific messages
|
||||
message_type_nick,
|
||||
message_type_notice,
|
||||
message_type_namreply,
|
||||
message_type_topic,
|
||||
-- Westwood Online Extensions
|
||||
message_type_host,
|
||||
message_type_invmsg,
|
||||
message_type_page,
|
||||
message_type_wol_joingame,
|
||||
message_type_gameopt_talk,
|
||||
message_type_gameopt_whisper,
|
||||
message_type_wol_start_game,
|
||||
message_type_wol_advertr,
|
||||
message_type_wol_chanchk,
|
||||
message_type_wol_userip,
|
||||
message_type_null
|
||||
= 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
|
51
lua/extend/enum/messagebox.lua
Normal file
51
lua/extend/enum/messagebox.lua
Normal file
|
@ -0,0 +1,51 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- https://github.com/HarpyWar/pvpgn/issues/15
|
||||
-- http://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx
|
||||
--
|
||||
-- use math_or(mb_type1, mb_type2) to combine two messagebox types
|
||||
--[[ Example code to display Windows MessageBox:
|
||||
local mb_type = math_or(MB_DEFBUTTON2, math_or(MB_ABORTRETRYIGNORE, MB_ICONEXCLAMATION) )
|
||||
api.messagebox_show(account.name, "aaaaaaaaaaaaaaaaaaaaaaaaawwadwwadawdawdawdwadawdaaw", "MessageBox from " .. config.servername, mb_type)
|
||||
]]--
|
||||
|
||||
MB_ABORTRETRYIGNORE,
|
||||
MB_CANCELTRYCONTINUE,
|
||||
MB_HELP,
|
||||
MB_OK,
|
||||
MB_OKCANCEL,
|
||||
MB_RETRYCANCEL,
|
||||
MB_YESNO,
|
||||
MB_YESNOCANCEL,
|
||||
|
||||
MB_ICONEXCLAMATION,
|
||||
MB_ICONWARNING,
|
||||
MB_ICONINFORMATION,
|
||||
MB_ICONASTERISK,
|
||||
MB_ICONQUESTION,
|
||||
MB_ICONSTOP,
|
||||
MB_ICONERROR,
|
||||
MB_ICONHAND,
|
||||
|
||||
MB_DEFBUTTON1,
|
||||
MB_DEFBUTTON2,
|
||||
MB_DEFBUTTON3,
|
||||
MB_DEFBUTTON4,
|
||||
|
||||
MB_APPLMODAL,
|
||||
MB_SYSTEMMODAL,
|
||||
MB_TASKMODAL,
|
||||
|
||||
MB_DEFAULT_DESKTOP_ONLY,
|
||||
MB_RIGHT,
|
||||
MB_RTLREADING,
|
||||
MB_SETFOREGROUND,
|
||||
MB_TOPMOST,
|
||||
MB_SERVICE_NOTIFICATION
|
||||
= 0x00000002,0x00000006,0x00004000,0x00000000,0x00000001,0x00000005,0x00000004,0x00000003,0x00000030,0x00000030,0x00000040,0x00000040,0x00000020,0x00000010,0x00000010,0x00000010,0x00000000,0x00000100,0x00000200,0x00000300,0x00000000,0x00001000,0x00002000,0x00020000,0x00080000,0x00100000,0x00010000,0x00040000,0x00200000
|
17
lua/extend/game.lua
Normal file
17
lua/extend/game.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Get count of all games
|
||||
function games_get_count()
|
||||
local count = 0
|
||||
for id,gamename in pairs(api.server_get_games()) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
15
lua/extend/message.lua
Normal file
15
lua/extend/message.lua
Normal file
|
@ -0,0 +1,15 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Send announce to all connected users
|
||||
function message_send_all(text)
|
||||
for id,username in pairs(api.server_get_users()) do
|
||||
api.message_send_text(username, message_type_broadcast, nil, text)
|
||||
end
|
||||
end
|
||||
|
22
lua/handle_channel.lua
Normal file
22
lua/handle_channel.lua
Normal file
|
@ -0,0 +1,22 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
function handle_channel_message(channel, account, text, message_type)
|
||||
if config.quiz and channel.name == config.quiz_channel then
|
||||
quiz_handle_message(account.name, text)
|
||||
end
|
||||
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, text)
|
||||
--return 1
|
||||
end
|
||||
function handle_channel_userjoin(channel, account)
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, account.name.." joined "..channel.name)
|
||||
end
|
||||
function handle_channel_userleft(channel, account)
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, account.name.." left "..channel.name)
|
||||
end
|
83
lua/handle_command.lua
Normal file
83
lua/handle_command.lua
Normal file
|
@ -0,0 +1,83 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- List of available lua commands
|
||||
-- (To create a new command - create a new file in directory "commands")
|
||||
local lua_command_table = {
|
||||
[1] = {
|
||||
["/w3motd"] = command_w3motd,
|
||||
|
||||
-- Quiz
|
||||
["/quiz"] = command_quiz,
|
||||
},
|
||||
[8] = {
|
||||
["/redirect"] = command_redirect,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
-- Global function to handle commands
|
||||
-- ("return 1" from a command will break next C++ code execution)
|
||||
function handle_command(account, text)
|
||||
-- find command in table
|
||||
for cg,cmdlist in pairs(lua_command_table) do
|
||||
for cmd,func in pairs(cmdlist) do
|
||||
if string.starts(text, cmd) then
|
||||
|
||||
-- check if command group is in account.commandgroups
|
||||
if not math_and(account.commandgroups, cg) then
|
||||
api.message_send_text(account.name, message_type_error, account.name, "This command is reserved for admins.")
|
||||
return 1
|
||||
end
|
||||
|
||||
-- FIXME: we can use _G[func] if func is a text but not a function,
|
||||
-- like ["/dotastats"] = "command_dotastats"
|
||||
-- and function command_dotastats can be defined below, not only before
|
||||
return func(account, text)
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
-- Split command to arguments,
|
||||
-- index 0 is always a command name without a slash
|
||||
-- return table with arguments
|
||||
function split_command(text, args_count)
|
||||
local count = args_count
|
||||
local result = {}
|
||||
local tmp = ""
|
||||
|
||||
-- remove slash from the command
|
||||
if not string:empty(text) then
|
||||
text = string.sub(text, 2)
|
||||
end
|
||||
|
||||
i = 0
|
||||
-- split by space
|
||||
for token in string.split(text) do
|
||||
if not string:empty(token) then
|
||||
if (i < count) then
|
||||
result[i] = token
|
||||
i = i + 1
|
||||
else
|
||||
if not string:empty(tmp) then
|
||||
tmp = tmp .. " "
|
||||
end
|
||||
tmp = tmp .. token
|
||||
end
|
||||
end
|
||||
end
|
||||
-- push remaining text at the end
|
||||
if not string:empty(tmp) then
|
||||
result[count] = tmp
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
63
lua/handle_game.lua
Normal file
63
lua/handle_game.lua
Normal file
|
@ -0,0 +1,63 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Global function to handle game create
|
||||
function handle_game_create(game)
|
||||
--for i,j in pairs(game) do
|
||||
-- api.message_send_text(game.owner, message_type_info, game.owner, i.." = "..j)
|
||||
--end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-- Global function to handle user join to game
|
||||
function handle_game_userjoin(game, account)
|
||||
--for i,j in pairs(game) do
|
||||
-- message_send_text(account.name, message_type_info, account.name, i.." = "..j)
|
||||
--end
|
||||
end
|
||||
|
||||
|
||||
-- Global function to handle user left from game
|
||||
function handle_game_userleft(game, account)
|
||||
--for username in string.split(str,",") do
|
||||
-- if (account.name ~= username) then
|
||||
-- api.message_send_text(username, message_type_whisper, nil, "Bye ".. account.name)
|
||||
-- end
|
||||
--end
|
||||
end
|
||||
|
||||
-- Global function to handle game end
|
||||
function handle_game_end(game)
|
||||
--api.message_send_text(game.owner, message_type_whisper, nil, "End game")
|
||||
end
|
||||
|
||||
-- Global function to handle game report
|
||||
function handle_game_report(game)
|
||||
|
||||
--for i,j in pairs(game) do
|
||||
-- api.message_send_text("harpywar", message_type_info, game.owner, i.." = "..j)
|
||||
-- api.message_send_text(game.owner, message_type_info, game.owner, i.." = "..j)
|
||||
--end
|
||||
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, game.last_access)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Global function to handle game destroy
|
||||
function handle_game_destroy(game)
|
||||
--api.message_send_text(game.owner, message_type_whisper, nil, "Destroy game")
|
||||
end
|
||||
|
||||
|
||||
-- Global function to handle game status
|
||||
function handle_game_changestatus(game)
|
||||
--api.message_send_text(game.owner, message_type_info, nil, "Change status of the game to ".. game.status)
|
||||
end
|
17
lua/handle_server.lua
Normal file
17
lua/handle_server.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Loop each second
|
||||
function handle_server_mainloop()
|
||||
-- Tick all timers
|
||||
for t in pairs(__timers) do
|
||||
__timers[t]:tick()
|
||||
end
|
||||
|
||||
-- api.eventlog(eventlog_level_gui, __FUNCTION__, os.time())
|
||||
end
|
20
lua/handle_user.lua
Normal file
20
lua/handle_user.lua
Normal file
|
@ -0,0 +1,20 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
function handle_user_whisper(account_src, account_dst, text)
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, account_src.name.."->"..account_dst.name.. ": ".. text)
|
||||
--return 1;
|
||||
end
|
||||
function handle_user_login(account)
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, account.name.." logged in")
|
||||
--return 1;
|
||||
end
|
||||
function handle_user_disconnect(account)
|
||||
--api.eventlog(eventlog_level_gui, __FUNCTION__, account.name.." disconnected")
|
||||
end
|
||||
|
33
lua/include/bitwise.lua
Normal file
33
lua/include/bitwise.lua
Normal file
|
@ -0,0 +1,33 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
--
|
||||
-- Bitwise functions:
|
||||
-- math_not, math_and, math_or, math_xor
|
||||
--
|
||||
|
||||
local function nand(x,y,z)
|
||||
z=z or 2^16
|
||||
if z<2 then
|
||||
return 1-x*y
|
||||
else
|
||||
return nand((x-x%z)/z,(y-y%z)/z,math.sqrt(z))*z+nand(x%z,y%z,math.sqrt(z))
|
||||
end
|
||||
end
|
||||
function math_not(y,z)
|
||||
return nand(nand(0,0,z),y,z)
|
||||
end
|
||||
function math_and(x,y,z)
|
||||
return nand(math_not(0,z),nand(x,y,z),z)
|
||||
end
|
||||
function math_or(x,y,z)
|
||||
return nand(math_not(x,z),math_not(y,z),z)
|
||||
end
|
||||
function math_xor(x,y,z)
|
||||
return math_and(nand(x,y,z),math_or(x,y,z),z)
|
||||
end
|
19
lua/include/common.lua
Normal file
19
lua/include/common.lua
Normal file
|
@ -0,0 +1,19 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Return the script path and line of the function where it is executed
|
||||
__FUNCTION__ = nil
|
||||
setmetatable(_G, {__index =
|
||||
function(t, k)
|
||||
if k == '__FUNCTION__' then
|
||||
local w = debug.getinfo(2, "S")
|
||||
return w.short_src..":"..w.linedefined
|
||||
end
|
||||
end
|
||||
})
|
||||
|
76
lua/include/file.lua
Normal file
76
lua/include/file.lua
Normal file
|
@ -0,0 +1,76 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Read file line by line
|
||||
-- callback 2 is optional
|
||||
-- You can process line with function callback1(line, callback2)
|
||||
function file_load(filename, callback1, callback2)
|
||||
local file = io.open(filename, "r")
|
||||
if file then
|
||||
for line in file:lines() do
|
||||
if callback2 then
|
||||
callback1(line, callback2)
|
||||
else
|
||||
callback1(line)
|
||||
end
|
||||
end
|
||||
file.close(file)
|
||||
api.eventlog(eventlog_level_trace, __FUNCTION__, "File readed " .. filename)
|
||||
else
|
||||
api.eventlog(eventlog_level_error, __FUNCTION__, "Could not open file " .. filename)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- (callback) for "file_load" to load file with each line format like "key = value"
|
||||
function file_load_dictionary_callback(line, callback)
|
||||
if string:empty(line) then return 0 end
|
||||
|
||||
local idx = 0
|
||||
local a, b
|
||||
for v in string.split(line, "=") do
|
||||
if idx == 0 then
|
||||
a = string:trim(v)
|
||||
else
|
||||
b = string:trim(v)
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
if not string:empty(b) and not string:empty(a) then
|
||||
callback(a, b)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Save raw text "data" into a filename
|
||||
function file_save(data, filename)
|
||||
local file = io.open(filename, "w")
|
||||
|
||||
file:write(data)
|
||||
file:close()
|
||||
end
|
||||
|
||||
-- Save file using callback
|
||||
function file_save2(filename, callback)
|
||||
local file = io.open(filename, "w")
|
||||
|
||||
callback(file)
|
||||
file:close()
|
||||
end
|
||||
-- Check file for exist
|
||||
function file_exists(filename)
|
||||
local f=io.open(filename, "r")
|
||||
if f~=nil then io.close(f) return true else return false end
|
||||
end
|
||||
|
||||
|
59
lua/include/string.lua
Normal file
59
lua/include/string.lua
Normal file
|
@ -0,0 +1,59 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Split text into table by delimeter
|
||||
-- Usage example: string.split("one,two",",")
|
||||
function string:split(str)
|
||||
str = str or '%s+'
|
||||
local st, g = 1, self:gmatch("()("..str..")")
|
||||
local function getter(segs, seps, sep, cap1, ...)
|
||||
st = sep and seps + #sep
|
||||
return self:sub(segs, (seps or 0) - 1), cap1 or sep, ...
|
||||
end
|
||||
return function() if st then return getter(st, g()) end end
|
||||
end
|
||||
|
||||
-- Check string is nil or empty
|
||||
-- bool
|
||||
function string:empty(str)
|
||||
return str == nil or str == ''
|
||||
end
|
||||
|
||||
-- bool
|
||||
function string.starts(str, starts)
|
||||
if string:empty(str) then return false end
|
||||
return string.sub(str,1,string.len(starts))==starts
|
||||
end
|
||||
|
||||
-- bool
|
||||
function string.ends(str, ends)
|
||||
if string:empty(str) then return false end
|
||||
return ends=='' or string.sub(str,-string.len(ends))==ends
|
||||
end
|
||||
|
||||
-- Replace string
|
||||
function string.replace(str, pattern, replacement)
|
||||
if string:empty(str) then return str end
|
||||
local s, n = string.gsub(str, pattern, replacement)
|
||||
return s
|
||||
end
|
||||
|
||||
function string:trim(str)
|
||||
if string:empty(str) then return str end
|
||||
return (str:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Replace char in specified position of string
|
||||
function replace_char(pos, str, replacement)
|
||||
if string:empty(str) then return str end
|
||||
return str:sub(1, pos-1) .. replacement .. str:sub(pos+1)
|
||||
end
|
||||
|
||||
|
160
lua/include/table.lua
Normal file
160
lua/include/table.lua
Normal file
|
@ -0,0 +1,160 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Clear table
|
||||
function table.clear(_table)
|
||||
for k in pairs(_table) do
|
||||
_table[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Get table size
|
||||
function table.count(T)
|
||||
if not T or not next(t) then return 0 end
|
||||
|
||||
local count = 0
|
||||
for _ in pairs(T) do count = count + 1 end
|
||||
return count
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Save Table to File
|
||||
Load Table from File
|
||||
v 1.0
|
||||
|
||||
Lua 5.2 compatible
|
||||
|
||||
Only Saves Tables, Numbers and Strings
|
||||
Insides Table References are saved
|
||||
Does not save Userdata, Metatables, Functions and indices of these
|
||||
----------------------------------------------------
|
||||
table.save( table , filename )
|
||||
|
||||
on failure: returns an error msg
|
||||
|
||||
----------------------------------------------------
|
||||
table.load( filename or stringtable )
|
||||
|
||||
Loads a table that has been saved via the table.save function
|
||||
|
||||
on success: returns a previously saved table
|
||||
on failure: returns as second argument an error msg
|
||||
----------------------------------------------------
|
||||
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
do
|
||||
-- declare local variables
|
||||
--// exportstring( string )
|
||||
--// returns a "Lua" portable version of the string
|
||||
local function exportstring( s )
|
||||
return string.format("%q", s)
|
||||
end
|
||||
|
||||
--// The Save Function
|
||||
function table.save( tbl,filename )
|
||||
local charS,charE = " ","\n"
|
||||
local file,err = io.open( filename, "wb" )
|
||||
if err then return err end
|
||||
|
||||
-- initiate variables for save procedure
|
||||
local tables,lookup = { tbl },{ [tbl] = 1 }
|
||||
file:write( "return {"..charE )
|
||||
|
||||
for idx,t in ipairs( tables ) do
|
||||
file:write( "-- Table: {"..idx.."}"..charE )
|
||||
file:write( "{"..charE )
|
||||
local thandled = {}
|
||||
|
||||
for i,v in ipairs( t ) do
|
||||
thandled[i] = true
|
||||
local stype = type( v )
|
||||
-- only handle value
|
||||
if stype == "table" then
|
||||
if not lookup[v] then
|
||||
table.insert( tables, v )
|
||||
lookup[v] = #tables
|
||||
end
|
||||
file:write( charS.."{"..lookup[v].."},"..charE )
|
||||
elseif stype == "string" then
|
||||
file:write( charS..exportstring( v )..","..charE )
|
||||
elseif stype == "number" then
|
||||
file:write( charS..tostring( v )..","..charE )
|
||||
end
|
||||
end
|
||||
|
||||
for i,v in pairs( t ) do
|
||||
-- escape handled values
|
||||
if (not thandled[i]) then
|
||||
|
||||
local str = ""
|
||||
local stype = type( i )
|
||||
-- handle index
|
||||
if stype == "table" then
|
||||
if not lookup[i] then
|
||||
table.insert( tables,i )
|
||||
lookup[i] = #tables
|
||||
end
|
||||
str = charS.."[{"..lookup[i].."}]="
|
||||
elseif stype == "string" then
|
||||
str = charS.."["..exportstring( i ).."]="
|
||||
elseif stype == "number" then
|
||||
str = charS.."["..tostring( i ).."]="
|
||||
end
|
||||
|
||||
if str ~= "" then
|
||||
stype = type( v )
|
||||
-- handle value
|
||||
if stype == "table" then
|
||||
if not lookup[v] then
|
||||
table.insert( tables,v )
|
||||
lookup[v] = #tables
|
||||
end
|
||||
file:write( str.."{"..lookup[v].."},"..charE )
|
||||
elseif stype == "string" then
|
||||
file:write( str..exportstring( v )..","..charE )
|
||||
elseif stype == "number" then
|
||||
file:write( str..tostring( v )..","..charE )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
file:write( "},"..charE )
|
||||
end
|
||||
file:write( "}" )
|
||||
file:close()
|
||||
end
|
||||
|
||||
--// The Load Function
|
||||
function table.load( sfile )
|
||||
local ftables,err = loadfile( sfile )
|
||||
if err or not ftables() then return _,err end
|
||||
local tables = ftables()
|
||||
|
||||
for idx = 1,#tables do
|
||||
local tolinki = {}
|
||||
for i,v in pairs( tables[idx] ) do
|
||||
if type( v ) == "table" then
|
||||
tables[idx][i] = tables[v[1]]
|
||||
end
|
||||
if type( i ) == "table" and tables[i[1]] then
|
||||
table.insert( tolinki,{ i,tables[i[1]] } )
|
||||
end
|
||||
end
|
||||
-- link indices
|
||||
for _,v in ipairs( tolinki ) do
|
||||
tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil
|
||||
end
|
||||
end
|
||||
return tables[1]
|
||||
end
|
||||
-- close do
|
||||
end
|
||||
|
||||
-- ChillCode
|
65
lua/include/timer.lua
Normal file
65
lua/include/timer.lua
Normal file
|
@ -0,0 +1,65 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Global table with timers
|
||||
__timers = {}
|
||||
|
||||
function timer_add(id, interval, callback)
|
||||
timer_object = timer:new(id, interval, callback)
|
||||
table.insert(__timers, timer_object)
|
||||
end
|
||||
|
||||
function timer_del(id)
|
||||
-- safe remove from the timers (we can not just use __timers = nil here)
|
||||
local i = 0
|
||||
for k,v in pairs(__timers) do
|
||||
i = i + 1
|
||||
if (v.id == id) then
|
||||
table.remove(__timers, i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function timer_get(id)
|
||||
local i = 0
|
||||
for k,v in pairs(__timers) do
|
||||
i = i + 1
|
||||
if (v.id == id) then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Timer class
|
||||
--
|
||||
timer = {}
|
||||
|
||||
-- Create a new timer with unique id and given interval
|
||||
function timer:new(id, interval, callback)
|
||||
options = { id = id, interval = interval, prev_time = 0, callback = callback }
|
||||
self.__index = self
|
||||
return setmetatable(options, self)
|
||||
end
|
||||
|
||||
-- Event when timer executes
|
||||
function timer:tick()
|
||||
if os.time() < self.prev_time + self.interval then return 0 end
|
||||
self.prev_time = os.time()
|
||||
|
||||
-- Debug: display time when the timer ticks
|
||||
-- api.eventlog(eventlog_level_gui, __FUNCTION__, self.interval .. ": " .. os.time())
|
||||
|
||||
-- execute callback function
|
||||
return self.callback(self)
|
||||
end
|
||||
|
||||
|
13
lua/main.lua
Normal file
13
lua/main.lua
Normal file
|
@ -0,0 +1,13 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- this function executes after preload all the lua scripts
|
||||
function main()
|
||||
|
||||
|
||||
end
|
128
lua/quiz/command.lua
Normal file
128
lua/quiz/command.lua
Normal file
|
@ -0,0 +1,128 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- /quiz <start|stop|stats>
|
||||
function command_quiz(account, text)
|
||||
if not config.quiz then
|
||||
return 0
|
||||
end
|
||||
|
||||
local args = split_command(text, 2)
|
||||
|
||||
if (args[1] == "start") then
|
||||
return q_command_start(account, args[2])
|
||||
|
||||
elseif (args[1] == "stop") then
|
||||
return q_command_stop(account)
|
||||
|
||||
elseif (args[1] == "stats") then
|
||||
if not args[2] then
|
||||
return q_command_toplist(account)
|
||||
else
|
||||
return q_command_stats(account, args[2])
|
||||
end
|
||||
end
|
||||
|
||||
api.describe_command(account.name, args[0])
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
-- Start quiz in current channel
|
||||
function q_command_start(account, filename)
|
||||
|
||||
local channel = api.channel_get_by_id(account.channel_id)
|
||||
if not channel then
|
||||
api.message_send_text(account.name, message_type_error, account.name, "This command can only be used inside a channel.")
|
||||
return 1
|
||||
end
|
||||
|
||||
if not account_is_operator_or_admin(account.name, channel.name) then
|
||||
api.message_send_text(account.name, message_type_error, account.name, "You must be at least a Channel Operator to use this command.")
|
||||
return 1
|
||||
end
|
||||
|
||||
if config.quiz_channel then
|
||||
api.message_send_text(account.name, message_type_error, account.name, 'Quiz has already ran in channel "'..config.quiz_channel..'". Use /qstop to force finish.')
|
||||
return 1
|
||||
end
|
||||
|
||||
-- check if file exists
|
||||
if not filename or not file_exists(q_directory() .. "/questions/" .. filename .. ".txt") then
|
||||
api.message_send_text(account.name, message_type_error, account.name, "Available Quiz dictionaries: ")
|
||||
api.message_send_text(account.name, message_type_error, account.name, " " .. config.quiz_filelist)
|
||||
return 1
|
||||
end
|
||||
|
||||
quiz:start(channel.name, filename)
|
||||
return 1
|
||||
end
|
||||
|
||||
-- Stop quiz
|
||||
function q_command_stop(account)
|
||||
|
||||
if not config.quiz_channel then
|
||||
api.message_send_text(account.name, message_type_error, account.name, 'Quiz is not running.')
|
||||
return 1
|
||||
end
|
||||
|
||||
quiz:stop(account.name)
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
-- Display Quiz Top players record
|
||||
function q_command_toplist(account)
|
||||
|
||||
-- load records (if it was not loaded yet)
|
||||
if not q_load_records() then
|
||||
return 0
|
||||
end
|
||||
|
||||
local output = "Top " .. config.quiz_users_in_top .. " Quiz records:"
|
||||
api.message_send_text(account.name, message_type_info, account.name, output)
|
||||
|
||||
-- display TOP of total records
|
||||
for i,t in pairs(q_records_total) do
|
||||
if (i > config.quiz_users_in_top) then break end
|
||||
|
||||
local output = string.format(" %d. %s [%d points]", i, t.username, t.points)
|
||||
api.message_send_text(account.name, message_type_info, account.name, output)
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
-- Display single player's record
|
||||
function q_command_stats(account, username)
|
||||
|
||||
-- load records (if it was not loaded yet)
|
||||
if not q_load_records() then
|
||||
return 0
|
||||
end
|
||||
|
||||
local found = false
|
||||
-- find user in records
|
||||
for i,t in pairs(q_records_total) do
|
||||
if string.upper(t.username) == string.upper(username) then
|
||||
api.message_send_text(account.name, message_type_info, account.name, t.username.. "'s Quiz record:")
|
||||
|
||||
local output = string.format(" %d. %s [%d points]", i, t.username, t.points)
|
||||
api.message_send_text(account.name, message_type_info, account.name, output)
|
||||
|
||||
found = true
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
api.message_send_text(account.name, message_type_info, account.name, username .. " has never played Quiz.")
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
54
lua/quiz/helper.lua
Normal file
54
lua/quiz/helper.lua
Normal file
|
@ -0,0 +1,54 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
-- Get path to Quiz directory
|
||||
function q_directory()
|
||||
return config.scriptdir .. "/quiz"
|
||||
end
|
||||
|
||||
-- Replace each symbol in string with *
|
||||
-- Example: input = "hello world", return = "***** *****"
|
||||
function q_hide_unswer(input)
|
||||
local output = input
|
||||
for i = 1, #input do
|
||||
local c = input:sub(i,i)
|
||||
if not (c == " ") then
|
||||
output = replace_char(i, output, "*")
|
||||
end
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
-- Open one random symbol in hidden (with *) string from original string
|
||||
-- Example: hidden = "***** *****", original = "hello world", return = "***l* *****"
|
||||
function q_show_next_symbol(hidden, original)
|
||||
local output = hidden
|
||||
|
||||
if hidden == original then
|
||||
return output
|
||||
end
|
||||
|
||||
local replaced = false
|
||||
while not replaced do
|
||||
local i = math.random(#hidden)
|
||||
local c = hidden:sub(i,i)
|
||||
if c == "*" then
|
||||
local c2 = original:sub(i,i)
|
||||
output = replace_char(i, hidden, c2)
|
||||
replaced = true
|
||||
end
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Callback to sort records table descending
|
||||
function q_compare_desc(a,b)
|
||||
return tonumber(a.points) > tonumber(b.points)
|
||||
end
|
155
lua/quiz/questions/dota.txt
Normal file
155
lua/quiz/questions/dota.txt
Normal file
|
@ -0,0 +1,155 @@
|
|||
**************************************************
|
||||
Category: DotA
|
||||
Author: AGOES
|
||||
**************************************************
|
||||
|
||||
One of illegal tools for playing dota? = Maphack
|
||||
How many kills needed for the title killing spree? = three
|
||||
How many kills needed for the title Dominating? = four
|
||||
How many kills needed for the title Megakill? = five
|
||||
How many kills needed for the title Unstoppable? = six
|
||||
How many kills needed for the title Whicked Sick? = seven
|
||||
How many kills needed for the title Monster Kill? = eight
|
||||
How many kills needed for the title GodLike? = nine
|
||||
How many kills needed for the title Beyond Godlike(Holy Shit!)? = ten
|
||||
First kill of the Game? = First Blood
|
||||
Two Kills simutaneously. = Double Kill
|
||||
Three Kills simutaneously. = Triple Kill
|
||||
Hero Nicknames: Vengeful Spirit. = Vs
|
||||
Hero Nicknames: Leshrac the Malicious Tormented Soul. = Leshrac
|
||||
Hero Nicknames: Kel'Thuzad the Lich King. = Lich
|
||||
Hero Nicknames: Krobelus the Death Prophet. = Dp
|
||||
Hero Nicknames: Lion the Demon Witch. = Lion
|
||||
Hero Nicknames: Lesale Deathbringer the Venomancer. = Veno
|
||||
Hero Nicknames: Magnus the Magnataur. = Magnataur
|
||||
Hero Nicknames: Visage The Necro'lic. = Visage
|
||||
Hero Nicknames: Nessaj the Chaos Knight. = Ck
|
||||
Hero Nicknames: Banehallow the Lycanthrope. = Lycan
|
||||
Hero Nicknames: Black Arachnia the Broodmother. = Brood
|
||||
Hero Nicknames: Mortred the Phantom Assassin. = Pa
|
||||
Hero Nicknames: Medusa the Gorgon. = Medusa
|
||||
Hero Nicknames: Balanar the NightStalker. = Ns
|
||||
Hero Nicknames: King Leoric the Skeleton King. = Leo
|
||||
Hero Nicknames: Lucifer the DoomBringer. = Lucy
|
||||
Hero Nicknames: Pharoh'moth the Nerubian Assassin. = Na
|
||||
Hero Nicknames: Slardar the Slithereen Guard. = Slardar
|
||||
Hero Nicknames: Akasha the Queen of Pain. = QoP
|
||||
Hero Nicknames: Bone Clinkz the Bone Fletcher. = Clinkz
|
||||
Hero Nicknames: Darkterror the Faceless Void. = Void
|
||||
Hero Nicknames: Viper the Netherdrake. = Viper
|
||||
Hero Nicknames: Razor the Lightning Revenant. = Razor
|
||||
Hero Nicknames: Nai'x the Lifestealer. = Naix
|
||||
Hero Nicknames: Pugna the Oblivion. = Pugna
|
||||
Hero Nicknames: Leviathan the Tidehunter. = Levi
|
||||
Hero Nicknames: Atropos the Bane Elemental. = Bane
|
||||
Hero Nicknames: Rotund'jere the Necrolyte. = Necro
|
||||
Hero Nicknames: Pudge the Butcher. = Pudge
|
||||
Hero Nicknames: Barathrum the Spiritbreaker. = Sb
|
||||
Hero Nicknames: Anub'seran the Nerubian Weaver. = Weaver
|
||||
Hero Nicknames: Crixalis the Sandking. = Sk
|
||||
Hero Nicknames: Mogul Kahn the Axe. = Axe
|
||||
Hero Nicknames: Strygwyr the BloodSeeker. = seeker
|
||||
Ultimate: Nether Swap. = Vengeful Spirit
|
||||
Ultimate: Thunder God's Wrath. = Lord of Olympia
|
||||
Ultimate: Untouchable. = Enchantress
|
||||
Ultimate: Replicate. = Morphling
|
||||
Ultimate: Freezing Field. = Crystal Maiden
|
||||
Ultimate: God's Strength. = Rogue Knight
|
||||
Ultimate: Song of the Siren. = Naga Siren
|
||||
Ultimate: Echo Slam. = Earth Shaker
|
||||
Ultimate: Permanent Invisibility. = Stealth Assassin
|
||||
Ultimate: True Form. = Lone Druid
|
||||
Ultimate: Laguna Blade. = Slayer
|
||||
Ultimate: Omnislash. = Juggernaught
|
||||
Ultimate: Global Silence. = Silencer
|
||||
Ultimate: Overgrowth. = Treant Protector
|
||||
Ultimate: Blackhole. = Enigma
|
||||
Ultimate: Ignis Fatuus. = Keeper of the Light
|
||||
Ultimate: Enrage. = Ursa Warrior
|
||||
Ultimate: Phantom Edge. = Phantom Lancer
|
||||
Ultimate: Mutli Cast. = Ogre Magi
|
||||
Ultimate: Rearm. = Tinker
|
||||
Ultimate: Wrath of Nature. = Prophet
|
||||
Ultimate: Grow. = Stone Giant
|
||||
Ultimate: Remote Mines. = Goblin Techies
|
||||
Ultimate: Hand of God. = Holy Knight
|
||||
Ultimate: Eclispe. = Moon rider
|
||||
Ultimate: Assassinate. = Dwarven Sniper
|
||||
Ultimate: Rampage. = Troll Warlord
|
||||
Ultimate: Mass Serpent Wards. = Shadow Shaman
|
||||
Ultimate: Warpath. = Bristleback
|
||||
Ultimate: Primal Split. = Pandaren Battlemaster
|
||||
Ultimate: Great Fortitude. = Centaur Warchief
|
||||
Ultimate: Track. = Bounty Hunter
|
||||
Ultimate: Elder Dragon Form. = Dragon Knight
|
||||
Ultimate: Mana Void. = Anti-Mage
|
||||
Ultimate: Marksmanship. = Drow Ranger
|
||||
Ultimate: Guardian Angel. = Omni Knight
|
||||
Ultimate: Sunder. = Soul Keeper
|
||||
Ultimate: Pulse Nova. = Tormented Soul
|
||||
Ultimate: Chain Frost. = Lich
|
||||
Ultimate: Exorcism. = Death Prophet
|
||||
Ultimate: Finger of Death. = Demon Witch
|
||||
Ultimate: Poison Nova. = Venomancer
|
||||
Ultimate: Reverse Polarity. = Magnataur
|
||||
Ultimate: Raise Revenants. = Necro'lic
|
||||
Ultimate: Phantasm. = Chaos Knight
|
||||
Ultimate: Shapeshift. = Lycanthrope
|
||||
Ultimate: Insatiable Hunger. = Broodmother
|
||||
Ultimate: Coupe De Grace. = Phantom Assassin
|
||||
Ultimate: Purge. = Gorgon
|
||||
Ultimate: Darkness. = Night Stalker
|
||||
Ultimate: Reincarnation. = Skeleton King
|
||||
Ultimate: Doom. = Doom Bringer
|
||||
Ultimate: Vendetta. = Nerubian Assassin
|
||||
Ultimate: Amplify Damage. = Slithereen Guard
|
||||
Ultimate: Sonic Wave. = Queen of Pain
|
||||
Ultimate: Death Pact. = Bone Fletcher
|
||||
Ultimate: Chronosphere. = Faceless Void
|
||||
Ultimate: Viper Strike. = Netherdrake
|
||||
Ultimate: Rage. = Lifestealer
|
||||
Ultimate: Life Drain. = Oblivion
|
||||
Ultimate: Ravage. = Tidehunter
|
||||
Ultimate: Fiend's Grip. = Bane Elemental
|
||||
Ultimate: Reaper's Scythe. = Necrolyte
|
||||
Ultimate: Disember. = Butcher
|
||||
Ultimate: Nether Strike. = Spiritbreaker
|
||||
Ultimate: Time Lapse. = Nerubian Weaver
|
||||
Ultimate: Requim of Souls. = Shadow Fiend
|
||||
Ultimate: Epicenter. = Sand King
|
||||
Ultimate: Culling Blade. = Axe
|
||||
Ultimate: Rupture. = Bloodseeker
|
||||
Armor Type: Spirit Tower = Fortified
|
||||
Armor Type: The Frozen Throne = Fortified
|
||||
Cost: Belt of Giant Strength = 450
|
||||
Cost: Blades of Alarcrity = 1000
|
||||
Cost: Blades of Attack in map 6.73c = 450
|
||||
Cost: Boots of Elvenskin = 450
|
||||
Cost: Boots of Speed = 500
|
||||
Cost: Broadsword = 1200
|
||||
Cost: Claymore = 1400
|
||||
Cost: Dagger of Escape = 2150
|
||||
Cost: Demon Edge = 2400
|
||||
Cost: Eaglehorn = 3300
|
||||
Cost: Gauntlets of Ogre Strength = 150
|
||||
Cost: Gem of True Sight = 700
|
||||
Cost: Helm of Iron Will = 950
|
||||
Cost: Mantle of Intelligence = 150
|
||||
Cost: Mask of Death = 900
|
||||
Cost: Mithril Hammer = 1600
|
||||
Cost: Ogre Axe = 1000
|
||||
Cost: Platemail = 1400
|
||||
Cost: Robe of the Magi = 450
|
||||
Cost: Sacred Relic = 3800
|
||||
Cost: Scroll for Black King Bar = 1300
|
||||
Cost: Scroll for Dagon = 1350
|
||||
Cost: Scroll for Heart of Tarrasque = 1200
|
||||
Cost: Scroll for Null Talisman = 170
|
||||
Cost: Scroll for Radiance = 1325
|
||||
Cost: Scroll for Stygian Desolator = 1200
|
||||
Cost: Slippers of Agility = 150
|
||||
Cost: Staff of Wizardry = 1000
|
||||
Cost: Ultimate Orb = 2100
|
||||
Cost: Vitality Booster = 1200
|
||||
Cost: Void Stone = 875
|
||||
|
5150
lua/quiz/questions/misc.txt
Normal file
5150
lua/quiz/questions/misc.txt
Normal file
File diff suppressed because it is too large
Load diff
42
lua/quiz/questions/warcraft.txt
Normal file
42
lua/quiz/questions/warcraft.txt
Normal file
|
@ -0,0 +1,42 @@
|
|||
**************************************************
|
||||
Category: Warcraft
|
||||
Author: Blizzard
|
||||
**************************************************
|
||||
|
||||
This Horde ship was crafted by goblins. Originally intended to bring Thrall and Aggra to the Maelstrom, the ship was destroyed in a surprise attack by the Alliance. = Draka's Fury
|
||||
What are undead murlocs called? = Murghouls
|
||||
What is the name of Tirion Fordring's gray stallion? = Mirador
|
||||
Which of these is the correct name for King Varian Wrynn's first wife? = Tiffin Ellerlan Wrynn
|
||||
Who was the first satyr to be created? = Xavius
|
||||
Before Ripsnarl became a worgen, he had a family. What was his wife's name? = Calissa Harrington
|
||||
This structure, located in Zangarmarsh was controlled by naga who sought to drain a precious and limited resource: the water of Outland. = Coilfang Reservoir
|
||||
One name for this loa is "Night's Friend" = Mueh'zala
|
||||
This defender of the Scarlet Crusade was killed while slaying the dreadlord Beltheris = Holia Sunshield
|
||||
Brown-skinned orcs first began showing up on Azeroth several years after the Third War, when the Dark Portal was reactivated. What are these orcs called? = Mag'har
|
||||
Succubus demons revel in causing anguish, and they serve the Legion by conducting nightmarish interrogations. What species is the succubus? = Sayaad
|
||||
While working as a tutor, Stalvan Mistmantle became obsessed with one of his students, a young woman named Tilloa. What was the name of her younger brother? = Giles
|
||||
Who was the mighty proto-dragon captured by Loken and tranformed into Razorscale? = Veranus
|
||||
This emissary of the Horde felt that Silvermoon City was a little too bright and clean. = Tatal
|
||||
This queen oversaw the evacuation of her people after the Cataclysm struck and the Forsaken attacked her nation. = Mia Greymane
|
||||
Not long ago, this frail Zandalari troll sought to tame a direhorn. Although he journeyed to the Isle of Giants, he was slain in his quest. What was his name? = Talak
|
||||
Arthas's death knights were trained in a floating citadel that was taken by force when many of them rebelled against the Lich King. What was the fortress's name? = Acherus
|
||||
White wolves were once the favored mounts of which orc clan? = Frostwolf Clan
|
||||
In Taur-ahe, the language of the tauren, what does lar'korwi mean? = Sharp claw
|
||||
Name the homeworld of the ethereals. = K'aresh
|
||||
Who was the first death knight to be created on Azeroth? = Teron Gorefiend
|
||||
In the assault on Icecrown, Horde forces dishonorably attacked Alliance soldiers who were busy fighting Scourge and trying to capture this gate. = Mord'rethar
|
||||
What evidence drove Prince Arthas to slaughter the people in Stratholme during the Third War? = Grain
|
||||
Who is the current leader of the gnomish people? = Gelbin Mekkatorque
|
||||
Malfurion Stormrage helped found this group which is the primary druidic organization of Azeroth = Cenarion Circle
|
||||
The draenei like to joke that in the language of the naaru, the word Exodar has this meaning = Defective elekk turd
|
||||
Thane Kurdran Wildhammer recently suffered a tragic loss when his valiant gryphon was killed in a fire. What was this gryphon's name? = Sky'ree
|
||||
Before she was raised from the dead by Arthas to serve the Scourge, Sindragosa was a part of what dragonflight? = Blue
|
||||
The Ironforge library features a replica of an unusually large ram's skeleton. What was the name of this legendary ram? = Toothgnasher
|
||||
Name the titan lore-keeper who was a member of the elite Pantheon = Norgannon
|
||||
What did the dragon aspects give the night elves after the War of the Ancients? = Nordrassil
|
||||
Formerly a healthy paladin, this draenei fell ill after fighting the Burning Legion and becoming one of the Broken. He later became a powerful shaman. = Nobundo
|
||||
Who were the three young twilight drakes guarding the twilight dragon eggs in the Obsidian Sanctum? = Shadron Tenebron Vesperon
|
||||
What phrase means "Thank you" in Draconic, the language of the dragons? = Belan Shi
|
||||
Before the original Horde formed, a highly contagious sickness began spreading rapidly among the orcs. What did the orcs call it? = Red pox
|
||||
What is the highest rank bestowed on a druid? = Archdruid
|
||||
Whose tomb includes the inscription "May the bloodied crown stay lost and forgotten"? = Terenas Menethil 2
|
274
lua/quiz/quiz.lua
Normal file
274
lua/quiz/quiz.lua
Normal file
|
@ -0,0 +1,274 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
|
||||
quiz = {} -- object
|
||||
q_dictionary = {} -- dictionary word=question
|
||||
q_records_current = { } -- table with current player records
|
||||
q_records_total = {} -- table with total player records
|
||||
q_records_diff = {} -- table with current diffs
|
||||
|
||||
-- counter of questions
|
||||
local _q_question_counter = 0
|
||||
-- count of current question's hints
|
||||
local _q_hint_counter = 0
|
||||
-- count of current question's hints
|
||||
local _q_current_index = 0
|
||||
-- current hint
|
||||
local _q_hint = nil
|
||||
-- time when question was shown
|
||||
local _q_time_start = 0
|
||||
-- last user streaks
|
||||
local _q_streak = { username = nil, count = 0 }
|
||||
|
||||
-- delay flag for next_question timer
|
||||
local _q_next_question_skip_first = false
|
||||
|
||||
function quiz:start(channelname, quizname)
|
||||
local filename = q_directory() .. "/questions/" .. string.lower(quizname) .. ".txt"
|
||||
|
||||
if not file_exists(filename) then
|
||||
channel_send_message(config.quiz_channel, filename, message_type_error)
|
||||
return false
|
||||
end
|
||||
|
||||
config.quiz_channel = channelname
|
||||
|
||||
-- reset
|
||||
_q_question_counter = 0
|
||||
_q_streak.username = nil
|
||||
_q_streak.count = 0
|
||||
-- clear tables
|
||||
table.clear(q_dictionary)
|
||||
table.clear(q_records_current)
|
||||
table.clear(q_records_diff)
|
||||
-- table.clear(q_records_total) -- do not clear it, it should be cached
|
||||
|
||||
-- load records (if it was not loaded yet)
|
||||
q_load_records()
|
||||
|
||||
-- fill dictionary from file
|
||||
if file_load(filename, file_load_dictionary_callback, q_read_dictionary_callback) then
|
||||
channel_send_message(config.quiz_channel, string.format("Quiz \"%s\" started!", quizname), message_type_error)
|
||||
q_next_question()
|
||||
end
|
||||
end
|
||||
function q_read_dictionary_callback(a, b)
|
||||
table.insert(q_dictionary, { question = a, word = b })
|
||||
end
|
||||
|
||||
|
||||
function quiz:stop(username)
|
||||
|
||||
timer_del("q_hint")
|
||||
timer_del("q_question")
|
||||
|
||||
local output = nil
|
||||
if username then
|
||||
output = "Quiz stopped by "..username
|
||||
else
|
||||
output = "Quiz finished!"
|
||||
end
|
||||
channel_send_message(config.quiz_channel, output, message_type_error)
|
||||
|
||||
-- display current records
|
||||
if (q_records_current) and next(q_records_current) then
|
||||
table.sort(q_records_current, q_compare_desc)
|
||||
|
||||
channel_send_message(config.quiz_channel, "Records of this game:", message_type_info)
|
||||
for i,t in pairs(q_records_current) do
|
||||
channel_send_message(config.quiz_channel, string.format(" %d. %s [%d points]", i, t.username, t.points), message_type_info)
|
||||
end
|
||||
end
|
||||
|
||||
-- merge current with total records
|
||||
if (q_records_total) and next(q_records_total) then
|
||||
for i,t in pairs(q_records_current) do
|
||||
|
||||
-- steal points from players in total table accordingly with half points of current table players
|
||||
if (config.quiz_competitive_mode) then
|
||||
if q_records_total[i] and not (q_records_total[i].username == t.username) then
|
||||
-- remove half points
|
||||
local points = math.floor(t.points / 2)
|
||||
q_records_diff[q_records_total[i].username] = points * -1
|
||||
q_records_total[i].points = q_records_total[i].points - points
|
||||
-- avoid negative value
|
||||
if q_records_total[i].points <= 0 then
|
||||
q_records_total[i].points = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add non exist users from current to total table
|
||||
-- and increase total users points
|
||||
local idx = q_records_total_find(t.username)
|
||||
-- set diff as winned points
|
||||
local tusername = q_records_total[idx].username
|
||||
q_records_diff[tusername] = t.points
|
||||
|
||||
-- if user not found (new user with 0 points)
|
||||
if q_records_total[idx].points == 0 then
|
||||
q_records_total[idx].points = t.points
|
||||
else
|
||||
-- update diff if it was changed to negative
|
||||
if q_records_diff[tusername] < 0 then
|
||||
q_records_diff[tusername] = q_records_diff[tusername] + t.points
|
||||
end
|
||||
q_records_total[idx].points = q_records_total[idx].points + t.points
|
||||
end
|
||||
end
|
||||
|
||||
-- sort by points
|
||||
table.sort(q_records_total, q_compare_desc)
|
||||
|
||||
quiz_display_top_players()
|
||||
else
|
||||
-- if records.txt is empty then save first records
|
||||
q_records_total = q_records_current
|
||||
end
|
||||
q_save_records()
|
||||
|
||||
config.quiz_channel = nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- handle channel message
|
||||
function quiz_handle_message(username, text)
|
||||
|
||||
local q = q_dictionary[_q_current_index]
|
||||
|
||||
if string.upper(q.word) == string.upper(text) then
|
||||
-- time from question to unswer
|
||||
local time_diff = os.clock() - _q_time_start
|
||||
|
||||
local points, total = 0,0
|
||||
-- calc points
|
||||
points = 1+(#q.word - _q_hint_counter) - math.floor(time_diff / config.quiz_hint_delay)
|
||||
-- avoid negative value
|
||||
if (points <= 0) then points = 1 end
|
||||
|
||||
-- remember previous streak
|
||||
local prev_streak = _q_streak
|
||||
-- increase streaks
|
||||
if (_q_streak.username == username) then
|
||||
_q_streak.count = _q_streak.count + 1
|
||||
else
|
||||
_q_streak.username = username
|
||||
_q_streak.count = 0
|
||||
end
|
||||
|
||||
local bonus = ""
|
||||
-- add bonus points for streaks
|
||||
if (_q_streak.count > 0) then
|
||||
points = points + _q_streak.count
|
||||
bonus = string.format(" +%s streak bonus", _q_streak.count)
|
||||
end
|
||||
|
||||
local idx = q_records_current_find(username)
|
||||
total = q_records_current[idx].points + points
|
||||
q_records_current[idx].points = total
|
||||
|
||||
-- lose half points for previous user
|
||||
if config.quiz_competitive_mode and not (prev_streak.username == username) then
|
||||
local lose_points = math.floor(total / 2)
|
||||
local idx = q_records_current_find(prev_streak.username)
|
||||
q_records_current[idx].points = q_records_current[idx].points - lose_points
|
||||
-- avoid negative value
|
||||
if q_records_current[idx].points <= 0 then
|
||||
q_records_current[idx].points = 0
|
||||
end
|
||||
end
|
||||
|
||||
channel_send_message(config.quiz_channel, string.format("%s is correct! The unswer is: %s (+%d points%s, %d total) [%d sec]", username, q.word, (points-_q_streak.count), bonus, total, time_diff), message_type_info)
|
||||
|
||||
q_next_question()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- go to next question
|
||||
function q_next_question()
|
||||
_q_question_counter = _q_question_counter + 1
|
||||
if (_q_question_counter > config.quiz_max_questions) then
|
||||
quiz:stop()
|
||||
return 0
|
||||
end
|
||||
|
||||
timer_del("q_hint")
|
||||
|
||||
_q_next_question_skip_first = false
|
||||
timer_add("q_question", config.quiz_question_delay, q_tick_next_question)
|
||||
end
|
||||
|
||||
-- write random question
|
||||
function q_tick_next_question(options)
|
||||
-- skip first tick
|
||||
if not _q_next_question_skip_first then
|
||||
_q_next_question_skip_first = true
|
||||
return 0
|
||||
end
|
||||
_q_time_start = os.clock()
|
||||
_q_current_index = math.random(#q_dictionary)
|
||||
|
||||
local q = q_dictionary[_q_current_index]
|
||||
-- send question
|
||||
channel_send_message(config.quiz_channel, "--------------------------------------------------------", message_type_info)
|
||||
channel_send_message(config.quiz_channel, string.format(" %s (%d letters)", q.question, #q.word), message_type_info)
|
||||
|
||||
-- hide hint
|
||||
_q_hint = q_hide_unswer(q.word)
|
||||
|
||||
-- stop this timer
|
||||
timer_del(options.id)
|
||||
|
||||
_q_hint_counter = 0
|
||||
-- start timer to hint unswer
|
||||
timer_add("q_hint", config.quiz_hint_delay, q_tick_hint_unswer)
|
||||
end
|
||||
|
||||
-- write hint for unswer
|
||||
function q_tick_hint_unswer(options)
|
||||
-- skip first tick
|
||||
if _q_hint_counter == 0 then
|
||||
_q_hint_counter = _q_hint_counter + 1
|
||||
return 0
|
||||
end
|
||||
_q_hint_counter = _q_hint_counter + 1
|
||||
|
||||
local q = q_dictionary[_q_current_index]
|
||||
-- update hint
|
||||
_q_hint = q_show_next_symbol(_q_hint, q.word)
|
||||
|
||||
if not (_q_hint == q.word) then
|
||||
-- show hint
|
||||
channel_send_message(config.quiz_channel, "Hint: ".._q_hint, message_type_info)
|
||||
else
|
||||
-- reset counter
|
||||
_q_hint_counter = 0
|
||||
|
||||
-- show unswer
|
||||
q_nounswer(nil)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- nobody unswered
|
||||
function q_nounswer(username)
|
||||
channel_send_message(config.quiz_channel, 'Nobody unswered. The unswer was: '.._q_hint, message_type_info)
|
||||
|
||||
-- decrease streaks
|
||||
if (_q_streak.count > 0) then
|
||||
_q_streak.count = _q_streak.count - 1
|
||||
end
|
||||
|
||||
q_next_question()
|
||||
end
|
||||
|
||||
|
87
lua/quiz/records.lua
Normal file
87
lua/quiz/records.lua
Normal file
|
@ -0,0 +1,87 @@
|
|||
--[[
|
||||
Copyright (C) 2014 HarpyWar (harpywar@gmail.com)
|
||||
|
||||
This file is a part of the PvPGN Project http://pvpgn.pro
|
||||
Licensed under the same terms as Lua itself.
|
||||
]]--
|
||||
|
||||
-- Load total records from records.txt to table
|
||||
function q_load_records()
|
||||
local filename = q_directory() .. "/records.txt"
|
||||
if not q_records_total or not next(q_records_total) then
|
||||
-- fill records table
|
||||
return file_load(filename, file_load_dictionary_callback, q_read_records_callback)
|
||||
end
|
||||
return true
|
||||
end
|
||||
function q_read_records_callback(a, b)
|
||||
table.insert(q_records_total, { username = a, points = b })
|
||||
end
|
||||
|
||||
-- Save total records from table to records.txt
|
||||
function q_save_records()
|
||||
local filename = q_directory() .. "/records.txt"
|
||||
file_save2(filename, q_save_records_callback)
|
||||
end
|
||||
function q_save_records_callback(file)
|
||||
if (q_records_total) and next(q_records_total) then
|
||||
for i,t in pairs(q_records_total) do
|
||||
file:write(t.username .. " = " .. t.points)
|
||||
file:write("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Print Top X players records
|
||||
function quiz_display_top_players()
|
||||
|
||||
local output = "Top " .. config.quiz_users_in_top .. " Quiz players:"
|
||||
channel_send_message(config.quiz_channel, output, message_type_info)
|
||||
|
||||
-- display TOP of total records
|
||||
for i,t in pairs(q_records_total) do
|
||||
if (i > config.quiz_users_in_top) then break end
|
||||
|
||||
local diff = ""
|
||||
if q_records_diff[t.username] then
|
||||
if q_records_diff[t.username] < 0 then
|
||||
diff = "(" .. q_records_diff[t.username] .. ")" -- minus points
|
||||
elseif q_records_diff[t.username] > 0 then
|
||||
diff = "(+" .. q_records_diff[t.username] .. ")" -- plus points
|
||||
end
|
||||
end
|
||||
|
||||
local output = string.format(" %d. %s [%d points] %s", i, t.username, t.points, diff)
|
||||
channel_send_message(config.quiz_channel, output, message_type_info)
|
||||
end
|
||||
end
|
||||
|
||||
-- find username and return table index
|
||||
-- preventnew - do not add user in table if it is not found
|
||||
function q_records_current_find(username, preventnew)
|
||||
-- find username
|
||||
for i,t in pairs(q_records_current) do
|
||||
if (t.username == username) then return i end
|
||||
end
|
||||
if preventnew then return nil end
|
||||
|
||||
-- if not found then insert
|
||||
table.insert(q_records_current, {username = username, points = 0})
|
||||
return #q_records_current
|
||||
end
|
||||
|
||||
-- find username and return table index
|
||||
-- prevent_new = do not add user in table if it is not found
|
||||
function q_records_total_find(username, prevent_new)
|
||||
for i,t in pairs(q_records_total) do
|
||||
if (t.username == username) then return i end
|
||||
end
|
||||
if prevent_new then return nil end
|
||||
|
||||
-- if not found then insert
|
||||
table.insert(q_records_total, {username = username, points = 0})
|
||||
return #q_records_total
|
||||
end
|
||||
|
||||
|
0
lua/quiz/records.txt
Normal file
0
lua/quiz/records.txt
Normal file
Loading…
Reference in a new issue