Initial commit (unfinished)

This commit is contained in:
Alexander Yakovlev 2015-03-25 14:11:58 +07:00
commit c973475017
8 changed files with 583 additions and 0 deletions

27
README.md Normal file
View File

@ -0,0 +1,27 @@
Prosody RPG module
==================
This is a module for Prosody 0.9 (maybe lower, but only maybe) that adds /roll command to every MUC.
The syntax is this:
/roll <times>d<sides>+<bonus>
/roll <times>d<sides>-<bonus>
The `<times>` bit is optional (default 1), the `d` letter is optional too if `times` = 1 and `bonus` = 0.
Example:
/roll 1d4
/roll 2d5-2
/roll d20+3
/roll 20
Installation
------------
This module uses Mersenne-Twister random-number library for better random number generation.
You can get the newest library version [here.](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html)
The library uses BSD license so it's included here (for Lua 5.2). Just compile the `random.so` and put it in plugin directory.
Then, drop the module to Prosody dir (usually `/usr/lib/prosody/modules`) and turn it on in your config.

88
mod_muc_rpg.lua Normal file
View File

@ -0,0 +1,88 @@
-- Throw RPG dice in any room
-- By Alexander Yakovlev <keloero@oreolek.ru>
-- based on mod_muc_intercom by Kim Alvefur <zash@zash.se>
local host_session = prosody.hosts[module.host];
local st_msg = require "util.stanza".message;
local jid = require "util.jid";
local random=require"random"
r=random.new(os.time())
local function get_room_by_jid(mod_muc, jid)
if mod_muc.get_room_by_jid then
return mod_muc.get_room_by_jid(jid);
elseif mod_muc.rooms then
return mod_muc.rooms[jid]; -- COMPAT 0.9, 0.10
end
end
function roll (times, sides, bonus)
local result = {}
result.dice = {}
bonus = bonus or 0
for i = 1, times do
result.dice[#result.dice + 1] = r(sides)
end
result.bonus = bonus
return result
end
function parseroll(message)
local result = {}
result.times = 1
result.sides = 20
result.bonus = 0
message = string.gsub(message, 'D', 'd')
message = string.gsub(message, '^%s+', '')
message = string.gsub(message, '%s+$', '')
if string.match(message, '^%d+$') then
result.sides = tonumber(message)
return result
end
if not string.match(message, '^%s*d') then
result.times = tonumber(string.match(message, '^(%d+)%s*d'))
end
if string.match(message, '+') then
result.bonus = tonumber(string.match(message, '+%s*(%d+)'))
end
if string.match(message, '-') then
result.bonus = -1 * tonumber(string.match(message, '-%s*(%d+)'))
end
result.sides = string.match(message, 'd%s*([0-9F]+)')
if string.match(sides, 'F') then
result.sides = '3'
result.bonus = result.bonus - (2 * result.times)
else
sides = tonumber(sides)
end
end
function check_message(data)
local origin, stanza = data.origin, data.stanza;
local mod_muc = host_session.muc;
if not mod_muc then return; end
local this_room = get_room_by_jid(mod_muc, stanza.attr.to);
if not this_room then return; end -- no such room
local from_room_jid = this_room._jid_nick[stanza.attr.from];
if not from_room_jid then return; end -- no such nick
local from_room, from_host, from_nick = jid.split(from_room_jid);
local body = stanza:get_child("body");
if not body then return; end -- No body, like topic changes
body = body and body:get_text();
if not string.match(body, '^%s*/roll%s') then return; end -- No command
local message = body:match("^@([^:]+):(.*)");
if not message then return; end
local forward_stanza = st_msg({from = sender, to = this_room, type = "groupchat"}, message);
this_room:broadcast_message(forward_stanza);
end
module:hook("message/bare", check_message, 10);

50
random/Makefile Normal file
View File

@ -0,0 +1,50 @@
# makefile for random library for Lua
# change these to reflect your Lua installation
#LUA=/home/alexander/Programming/neovim/.deps/build/src/luajit
#LUAINC= $(LUA)/src
#LUALIB= $(LUA)/src
#LUABIN= $(LUA)/src
# these will probably work if Lua has been installed globally
LUA= /usr
LUAINC= $(LUA)/include
LUALIB= $(LUA)/lib
LUABIN= $(LUA)/bin
# probably no need to change anything below here
CC= gcc
CFLAGS= $(INCS) $(WARN) -O2 -fPIC $G
WARN= -ansi -pedantic -Wall -Wextra
INCS= -I$(LUAINC)
MAKESO= $(CC) -shared
#MAKESO= $(CC) -bundle -undefined dynamic_lookup
MYNAME= random
MYLIB= l$(MYNAME)
T= $(MYNAME).so
OBJS= $(MYLIB).o
TEST= test.lua
all: test
test: $T
$(LUABIN)/lua $(TEST)
o: $(MYLIB).o
so: $T
$T: $(OBJS)
$(MAKESO) -o $@ $(OBJS)
$(OBJS): random.c
clean:
rm -f $(OBJS) $T core core.*
doc:
@echo "$(MYNAME) library:"
@fgrep '/**' $(MYLIB).c | cut -f2 -d/ | tr -d '*' | sort | column
# eof

25
random/README Normal file
View File

@ -0,0 +1,25 @@
This is a random-number library for Lua 5.2. It is based on the Mersenne
Twister random number generator available at
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
To try the library, just edit Makefile to reflect your installation of Lua and
then run make. This will build the library and run a simple test. For detailed
installation instructions, see
http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/install.html
There is no manual but the library is simple and intuitive; see the summary
below. Read also test.lua, which shows the library in action.
This code is hereby placed in the public domain, except random.c, which is
subject to the BSD license.
Please send comments, suggestions, and bug reports to lhf@tecgraf.puc-rio.br .
-------------------------------------------------------------------------------
random library:
__call(c) new([seed]) version
__tostring(c) seed(c,[seed])
clone(c) value(c,[a,b])
-------------------------------------------------------------------------------

120
random/lrandom.c Normal file
View File

@ -0,0 +1,120 @@
/*
* lrandom.c
* random-number library for Lua 5.2 based on the Mersenne Twister
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 30 Apr 2012 14:10:37
* This code is hereby placed in the public domain.
*/
#include <math.h>
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
/* #define GENRAND32 if you want a 32-bit generator instead of a 53-bit one */
#include "random.c"
#define MYNAME "random"
#define MYVERSION MYNAME " library for " LUA_VERSION " / Apr 2012 / "\
"using " AUTHOR
#define MYTYPE MYNAME " handle"
#define SEED 2012UL
static MT *Pget(lua_State *L, int i)
{
return luaL_checkudata(L,i,MYTYPE);
}
static MT *Pnew(lua_State *L)
{
MT *c=lua_newuserdata(L,sizeof(MT));
luaL_setmetatable(L,MYTYPE);
return c;
}
static int Lnew(lua_State *L) /** new([seed]) */
{
lua_Number seed=luaL_optnumber(L,1,SEED);
MT *c=Pnew(L);
init_genrand(c,seed);
return 1;
}
static int Lclone(lua_State *L) /** clone(c) */
{
MT *c=Pget(L,1);
MT *d=Pnew(L);
*d=*c;
return 1;
}
static int Lseed(lua_State *L) /** seed(c,[seed]) */
{
MT *c=Pget(L,1);
init_genrand(c,luaL_optnumber(L,2,SEED));
lua_settop(L,1);
return 1;
}
static int Lvalue(lua_State *L) /** value(c,[a,b]) */
{
MT *c=Pget(L,1);
double a,b,r=genrand(c);
switch (lua_gettop(L))
{
case 1:
lua_pushnumber(L,r);
return 1;
case 2:
a=1;
b=luaL_checknumber(L,2);
break;
default:
a=luaL_checknumber(L,2);
b=luaL_checknumber(L,3);
break;
}
if (a>b) { double t=a; a=b; b=t; }
a=ceil(a);
b=floor(b);
if (a>b) return 0;
r=a+floor(r*(b-a+1));
lua_pushnumber(L,r);
return 1;
}
static int Ltostring(lua_State *L)
{
MT *c=Pget(L,1);
lua_pushfstring(L,"%s %p",MYTYPE,(void*)c);
return 1;
}
static const luaL_Reg R[] =
{
{ "__tostring", Ltostring }, /** __tostring(c) */
{ "clone", Lclone },
{ "new", Lnew },
{ "seed", Lseed },
{ "value", Lvalue },
{ NULL, NULL }
};
LUALIB_API int luaopen_random(lua_State *L)
{
luaL_newmetatable(L,MYTYPE);
luaL_setfuncs(L,R,0);
lua_pushliteral(L,"version"); /** version */
lua_pushliteral(L,MYVERSION);
lua_settable(L,-3);
lua_pushliteral(L,"__index");
lua_pushvalue(L,-2);
lua_settable(L,-3);
lua_pushliteral(L,"__call"); /** __call(c) */
lua_pushliteral(L,"value");
lua_gettable(L,-3);
lua_settable(L,-3);
return 1;
}

142
random/random.c Normal file
View File

@ -0,0 +1,142 @@
/*
* random.c
* Mersenne Twister random number generator
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 18 Nov 2010 19:10:52
* slightly modified from mt19937ar.c available at
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
*/
/*
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Before using, initialize the state by using init_genrand(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
typedef struct {
unsigned long v[N]; /* the array for the state vector */
int i;
} MT;
#define mt (o->v)
#define mti (o->i)
/* initializes mt[N] with a seed */
static void init_genrand(MT *o, unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
/* generates a random number on [0,0xffffffff]-interval */
static unsigned long genrand_int32(MT *o)
{
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(o,5489UL); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
/* These real versions are due to Isaku Wada, 2002/01/09 added */
#ifdef GENRAND32
/* generates a random number on [0,1)-real-interval */
static double genrand_real2(MT *o)
{
return genrand_int32(o)*(1.0/4294967296.0);
/* divided by 2^32 */
}
#define genrand genrand_real2
#else
/* generates a random number on [0,1) with 53-bit resolution*/
static double genrand_res53(MT *o)
{
unsigned long a=genrand_int32(o)>>5, b=genrand_int32(o)>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
#define genrand genrand_res53
#endif
#define AUTHOR "Mersenne Twister"

74
random/test.lua Normal file
View File

@ -0,0 +1,74 @@
-- test random library
local random=require"random"
print(random.version)
print""
function test(w,r)
print(w,r(),r(),r())
end
r=random.new(12345)
test("new",r)
test("more",r)
test("reset",r:seed(12345))
test("seed",r:seed(56789))
test("seed",r:seed(3063121584))
test("seed",r:seed(2428144928))
s=r:seed():clone()
test("seed",r)
test("more",r)
test("clone",s)
r:seed(os.time())
N=100000
print""
print("range","","distribution",N)
print("","",1,2,3,4,5,6,7,8)
function test(N,a,b)
local S={0,0,0,0,0,0,0,0,0,0,0}
for i=1,N do
local i=r:value(a,b)
if i~=nil then S[i]=S[i]+1 end
end
for i=1,9 do
S[i]=math.floor(100*S[i]/N+0.5)
end
print(a..":"..b,"",S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[8])
end
test(N,1,8)
test(N,2,4)
test(N,3,7)
test(N,7,3)
test(N,1.2,4.6)
test(N,4.6,1.2)
test(N,7.1,2.9)
test(N,2.9,7.1)
test(N,2.1,2.2)
test(N,2.2,2.1)
function test(w,f)
local t=os.clock()
for i=1,N do
f()
end
t=os.clock()-t
print(w,math.floor(N/t/1000),N,t)
end
N=4*N
print""
print("","1000/s","N","time")
test("math",function () return math.random() end)
test("math",math.random)
test("random",function () return random.value(r) end)
test("random",function () return r:value() end)
test("random",r)
print""
print(random.version)
-- eof

57
test.lua Normal file
View File

@ -0,0 +1,57 @@
local random=require"random"
r=random.new(os.time())
function roll (times, sides, bonus)
local result = {}
result.dice = {}
bonus = bonus or 0
for i = 1, times do
result.dice[#result.dice + 1] = r(sides)
end
result.bonus = bonus
return result
end
function printt(tab)
for key,value in pairs(tab) do print(key,value) end
end
--message = io.read()
local times = 1
local sides = 20
local bonus = 0
message = string.gsub(message, 'D', 'd')
message = string.gsub(message, '^%s+', '')
message = string.gsub(message, '%s+$', '')
if string.match(message, '^%d+$') then
printt(roll(1,tonumber(message),0))
return
end
if not string.match(message, '^%s*d') then
-- times != 1
times = tonumber(string.match(message, '^(%d+)%s*d'))
end
if string.match(message, '+') then
bonus = tonumber(string.match(message, '+%s*(%d+)'))
end
if string.match(message, '-') then
bonus = -1 * tonumber(string.match(message, '-%s*(%d+)'))
end
sides = string.match(message, 'd%s*([0-9F]+)')
if string.match(sides, 'F') then
sides = '3'
bonus = bonus - (2 * times)
else
sides = tonumber(sides)
end
if sides == nil then
print "No sides?"
return
end
print ("Times: ", times)
print ("Sides", sides)
print ("Bonus", bonus)