commit c973475017cf7a38545853a150cfcebbde4374ca Author: Oreolek Date: Wed Mar 25 14:11:58 2015 +0700 Initial commit (unfinished) diff --git a/README.md b/README.md new file mode 100644 index 0000000..c072bea --- /dev/null +++ b/README.md @@ -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 d+ + /roll d- + +The `` 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. diff --git a/mod_muc_rpg.lua b/mod_muc_rpg.lua new file mode 100644 index 0000000..d4f85c7 --- /dev/null +++ b/mod_muc_rpg.lua @@ -0,0 +1,88 @@ +-- Throw RPG dice in any room +-- By Alexander Yakovlev +-- based on mod_muc_intercom by Kim Alvefur + +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); diff --git a/random/Makefile b/random/Makefile new file mode 100644 index 0000000..6b41121 --- /dev/null +++ b/random/Makefile @@ -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 diff --git a/random/README b/random/README new file mode 100644 index 0000000..17d4d38 --- /dev/null +++ b/random/README @@ -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]) + +------------------------------------------------------------------------------- diff --git a/random/lrandom.c b/random/lrandom.c new file mode 100644 index 0000000..8cbfe19 --- /dev/null +++ b/random/lrandom.c @@ -0,0 +1,120 @@ +/* +* lrandom.c +* random-number library for Lua 5.2 based on the Mersenne Twister +* Luiz Henrique de Figueiredo +* 30 Apr 2012 14:10:37 +* This code is hereby placed in the public domain. +*/ + +#include +#include + +#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; +} diff --git a/random/random.c b/random/random.c new file mode 100644 index 0000000..16686de --- /dev/null +++ b/random/random.c @@ -0,0 +1,142 @@ +/* +* random.c +* Mersenne Twister random number generator +* Luiz Henrique de Figueiredo +* 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> 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> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 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" diff --git a/random/test.lua b/random/test.lua new file mode 100644 index 0000000..2d8035e --- /dev/null +++ b/random/test.lua @@ -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 diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..edb84b1 --- /dev/null +++ b/test.lua @@ -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)