Initial commit (unfinished)
commit
c973475017
@ -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.
|
@ -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);
|
@ -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
|
@ -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])
|
||||
|
||||
-------------------------------------------------------------------------------
|
@ -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;
|
||||
}
|
@ -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"
|
@ -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
|
@ -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)
|
Loading…
Reference in New Issue