org.guifications.plugins: 8274eb3fcb71be37c1b30eafdda48088cb14a15a

grim at guifications.org grim at guifications.org
Mon Nov 19 00:55:04 CST 2007


-----------------------------------------------------------------
Revision: 8274eb3fcb71be37c1b30eafdda48088cb14a15a
Ancestor: 3a137b5d101c6d4ff52c4174ca8f0aa904989ab3
Author: grim at guifications.org
Date: 2007-11-19T06:51:18
Branch: org.guifications.plugins

Modified files:
        dice/dice.c

ChangeLog: 

Lot's of updates for the dice notation.  Nesting works now, but multiplication and division are all fubar'd and may cause crashes, *USE WITH CAUTION*


-----------------------------------------------------------------
This revision's diffstat output:
 dice.c |  334 +++++++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 242 insertions(+), 92 deletions(-)
-------------- next part --------------
============================================================
--- dice/dice.c	9dd37518a405fe71a0ade111bece4f3cb653aa75
+++ dice/dice.c	8cf0ba6c0e6353c44b45faac04c796b17f52b6a6
@@ -16,44 +16,215 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
  */
-#ifdef HAVE_CONFIG_H
-# include "../pp_config.h"	/* Purple Plugin Pack common configuration header. */
-#endif /* HAVE_CONFIG_H */
 
-#define PURPLE_PLUGINS	/* I get the impression this is necessary somehow... */
+#include "../common/pp_internal.h"
 
-#include <glib.h>	/* For glib wrappers of the standard C types and my beloved string functions. */
-#include <time.h>	/* For the random number seed. */
-#include <stdlib.h>	/* Gratuitous, Ubiquitous, Includimust! */
+#include <time.h>
+#include <stdlib.h>
 
-#include <cmds.h>			/* Must be related to extending Purple's /command set. */
-#include <conversation.h>	/* For being able to put stuff in a conversation? */
-#include <debug.h>			/* Always a good idea. */
-#include <plugin.h>			/* 'Cause this is a plugin, I'd think. */
-#include <version.h>		/* Also always a good idea. */
+#include <cmds.h>
+#include <conversation.h>
+#include <debug.h>
+#include <plugin.h>
 
-#include "../common/pp_internal.h"	/* No idea what this is for. */
+#define DEFAULT_DICE	2
+#define DEFAULT_SIDES	6
 
-static PurpleCmdId dice_cmd_id = 0;	/* No idea what this does. */
+#define BOUNDS_CHECK(var, min, min_def, max, max_def) { \
+	if((var) < (min)) \
+		(var) = (min_def); \
+	else if((var) > (max)) \
+		(var) = (max_def); \
+}
 
+#define ROUND(val) ((gdouble)(val) + 0.5f)
+
+static PurpleCmdId dice_cmd_id = 0;
+
+static gchar *
+old_school_roll(gint dice, gint sides) {
+	GString *str = g_string_new("");
+	gchar *ret = NULL;
+	gint c = 0, v = 0;
+
+	BOUNDS_CHECK(dice, 1, 2, 15, 15);
+	BOUNDS_CHECK(sides, 2, 2, 999, 999);
+
+	g_string_append_printf(str, "Rolls %d %d-sided %s:",
+						   dice, sides,
+						   (dice == 1) ? "die" : "dice");
+
+	for(c = 0; c < dice; c++) {
+		v = rand() % sides + 1;
+
+		g_string_append_printf(str, " %d", v);
+	}
+
+	ret = str->str;
+	g_string_free(str, FALSE);
+
+	return ret;
+}
+
+static inline gboolean
+is_dice_notation(const gchar *str) {
+	return (g_utf8_strchr(str, -1, 'd') != NULL);
+}
+
+static gchar *
+dice_notation_roll_helper(const gchar *dn, gint *value) {
+	GString *str = g_string_new("");
+	gchar *ret = NULL;
+	gint dice = 0, sides = 0, i = 0, t = 0, v = 0;
+	gdouble multiplier = 1.0;
+
+	if(!dn || *dn == '\0')
+		return NULL;
+
+	/* at this point, all we have is +/- number for our bonus, so we add it to
+	 * our value
+	 */
+	if(!is_dice_notation(dn)) {
+		gint bonus = atoi(dn);
+
+		*value += bonus;
+
+		/* the + makes sure we always have a + or - */
+		g_string_append_printf(str, "%s %d",
+							   (bonus < 0) ? "-" : "+",
+							   ABS(bonus));
+
+		ret = str->str;
+		g_string_free(str, FALSE);
+
+		return ret;
+	}
+
+	/**************************************************************************
+	 * Process our block
+	 *************************************************************************/
+	purple_debug_info("dice", "processing '%s'\n", dn);
+
+	/* get the number of dice */
+	dice = atoi(dn);
+	BOUNDS_CHECK(dice, 1, 1, 999, 999);
+
+	/* find and move to the character after the d */
+	dn = g_utf8_strchr(dn, -1, 'd');
+	dn++;
+
+	/* get the number of sides */
+	sides = atoi(dn);
+	BOUNDS_CHECK(sides, 2, 2, 999, 999);
+
+	/* i've struggled with a better way to determine the next operator, i've 
+	 * opted for this.
+	 */
+	for(t = sides; t > 0; t /= 10) {
+		dn++;
+		purple_debug_info("dice", "looking for the next operator: %s\n", dn);
+	}
+
+	/* check if we're multiplying or dividing this block */
+	if(*dn == 'x' || *dn == '/') {
+		gchar op;
+
+		v = atof(dn);
+
+		op = *dn;
+		dn++;
+
+		multiplier = v;
+
+		/* move past our multiplier */
+		for(t = v; t > 0; t /= 10) {
+			dn++;
+		}
+
+		if(op == '/')
+			multiplier = 1 / multiplier;
+	}
+
+	purple_debug_info("dice", "d=%d;s=%d;m=%f;\n", dice, sides, multiplier);
+
+	/* calculate and output our block */
+	g_string_append_printf(str, " (");
+	for(i = 0; i < dice; i++) {
+		t = rand() % sides + 1;
+		v = ROUND(t * multiplier);
+
+		g_string_append_printf(str, "%s%d", (i > 0) ? " " : "", v);
+		
+		purple_debug_info("dice", "die %d: %d(%d)\n", i, v, t);
+
+		*value += v;
+	}
+	g_string_append_printf(str, ")");
+
+	purple_debug_info("dice", "value=%d;str=%s\n", *value, str->str);
+
+	/* we have more in our string, recurse! */
+	if(*dn != '\0') {
+		gchar *s = dice_notation_roll_helper(dn, value);
+		
+		if(s)
+			str = g_string_append(str, s);
+
+		g_free(s);
+	}
+
+	ret = str->str;
+	g_string_free(str, FALSE);
+
+	return ret;
+}
+
+static gchar *
+dice_notation_roll(const gchar *dn) {
+	GString *str = g_string_new("");
+	gchar *ret = NULL, *normalized = NULL;
+	gint value = 0;
+
+	g_string_append_printf(str, "%s:", dn);
+
+	/* normalize the input and process it */
+	normalized = g_utf8_strdown(dn, -1);
+	g_string_append_printf(str, "%s",
+						   dice_notation_roll_helper(normalized, &value));
+	g_free(normalized);
+
+	g_string_append_printf(str, " = %d", value);
+
+	ret = str->str;
+	g_string_free(str, FALSE);
+
+	return ret;
+}
+
 static PurpleCmdRet
-roll(PurpleConversation *conv, const gchar *cmd, gchar **args,
-	 gchar *error, void *data)
+roll(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar *error,
+	 void *data)
 {
-	gchar **splitted = NULL, **resplitted = NULL;	/* Variables for splitting up a dice notation string */
-	GString *str = NULL;	/* Our output */
-	gint dice = 2, sides = 6, bonus = 0, accumulator = 0, roll, i = 0;	/* How many dice, sides for each, the bonus for each, an accumulator to gather the total, our roll each time, and an iterator which I abuse before it's used. */
+	gchar *str = NULL;
 
-	srand(time(NULL));	/* Seed our random number generator. */
-
-	if(args[0]) /* If we got an argument */
-	{
-		if(g_strstr_len(args[0], -1, "d") == NULL) /* There's no 'd' in our string. */
+	if(!args[0]) {
+		str = old_school_roll(DEFAULT_DICE, DEFAULT_SIDES);
+	} else {
+		if(is_dice_notation(args[0])) {
+			str = dice_notation_roll(args[0]);
+		} else {
+			gint dice, sides;
+			
 			dice = atoi(args[0]);
-		else	/* Process dice notation: xdy+-z */
-		{
+			sides = (args[1]) ? atoi(args[1]) : DEFAULT_SIDES;
+
+			str = old_school_roll(dice, sides);
+		}
+	}
+
+#if 0
 			i = 1;	/* Abuse that iterator!  We're saying "We think this is dice notation!" */
 			splitted = g_strsplit(args[0], "d", 2);	/* Split the description into two parts: (1)d(20+5); discard the 'd'. */
 			dice = atoi(splitted[0]);	/* We should have the number of dice easily now. */
@@ -80,33 +251,7 @@ roll(PurpleConversation *conv, const gch
 	if(args[1] && i == 0)	/* If there was a second argument, and we care about it (not dice notation) */
 		sides = atoi(args[1]);	/* Grab it and make it the number of sides the dice have. */
 
-	/*
-	 * These next four lines make sure we're rolling a sane
-	 * number of dice.
-	 */
-	if(dice < 1)
-		dice = 2;
-	if(dice > 15)
-		dice = 15;
-
-	/*
-	 * These next four lines make sure our dice have a (relatively)
-	 * sane number of sides each.
-	 */
-	if(sides < 2)
-		sides = 2;
-	if(sides > 999)
-		sides = 999;
-	
-	/*
-	 * These next four lines make sure our bonus/penalty is sane.
-	 */
-	if(bonus < -999)
-		bonus = -999;
-	if(bonus > 999)
-		bonus = 999;
-
-	str = g_string_new("");	/* Allocate ourselves an empty string for output. */
+	str = g_string_new("");
 	if(i)	/* Show the output in dice notation format. */
 	{
 		g_string_append_printf(str, "%dd%d", dice, sides);	/* For example, 1d20 */
@@ -116,11 +261,6 @@ roll(PurpleConversation *conv, const gch
 			g_string_append_printf(str, "%d", bonus);	/* 1d20-3 (saying "-%d" would be redundant, since the '-' gets output with bonus automatically) */
 		g_string_append_printf(str, ":");	/* Final colon.  1d20-4: */
 	}
-	else	/* Show the output in legacy format. */
-	{
-		g_string_append_printf(str, "Rolls %d %d-sided %s:", dice, sides,
-								(dice == 1) ? "die" : "dice");	/* If we have one die use the singular, else the plural (dice). */
-	}
 
 	for(i = 0; i < dice; i++)	/* For each die... */
 	{
@@ -138,15 +278,16 @@ roll(PurpleConversation *conv, const gch
 	{
 		g_string_append_printf(str, " = %d", accumulator);	/* Append our accumulator */
 	}
+#endif
 
-	if(conv->type == PURPLE_CONV_TYPE_IM)	/* If we're in a one-on-one IM */
-		purple_conv_im_send(PURPLE_CONV_IM(conv), str->str);	/* Send our output as an IM */
-	else if(conv->type == PURPLE_CONV_TYPE_CHAT)	/* If we're in a chat room */
-		purple_conv_chat_send(PURPLE_CONV_CHAT(conv), str->str);	/* Send our output to the channel */
+	if(conv->type == PURPLE_CONV_TYPE_IM)
+		purple_conv_im_send(PURPLE_CONV_IM(conv), str);
+	else if(conv->type == PURPLE_CONV_TYPE_CHAT)
+		purple_conv_chat_send(PURPLE_CONV_CHAT(conv), str);
 
-	g_string_free(str, TRUE);	/* Free our output string, as we're done with it now. */
+	g_free(str);
 
-	return PURPLE_CMD_RET_OK;	/* Never give up!  Never surrender! */
+	return PURPLE_CMD_RET_OK;
 }
 
 static gboolean
@@ -154,7 +295,9 @@ plugin_load(PurplePlugin *plugin)
 {
 	const gchar *help;
 
-	help = _("dice [dice] [sides]:  rolls dice number of sides sided dice OR\ndice XdY+-Z:  rolls X number of Y sided dice, giving a Z bonus/penalty to each.  e.g. 1d20+2");
+	help = _("dice [dice] [sides]:  rolls dice number of sides sided dice OR\n"
+			 "dice [XdY+-Z]:  rolls X number of Y sided dice, giving a Z "
+			 "bonus/penalty to each.  e.g. 1d20+2");
 
 	dice_cmd_id = purple_cmd_register("dice", "wws", PURPLE_CMD_P_PLUGIN,
 									PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
@@ -162,6 +305,13 @@ plugin_load(PurplePlugin *plugin)
 									NULL, PURPLE_CMD_FUNC(roll),
 									help, NULL);
 
+	/* we only want to seed this off of the seconds since the epoch once.  If
+	 * we do it every time, we'll give the same results for each time we
+	 * process a roll within the same second.  This is bad because it's not
+	 * really random then.
+	 */
+	srand(time(NULL));
+
 	return TRUE;
 }
 
@@ -175,35 +325,35 @@ static PurplePluginInfo info =
 
 static PurplePluginInfo info =
 {
-	PURPLE_PLUGIN_MAGIC,								/**< magic			*/
-	PURPLE_MAJOR_VERSION,								/**< major version	*/
-	PURPLE_MINOR_VERSION,								/**< minor version	*/
-	PURPLE_PLUGIN_STANDARD,								/**< type			*/
-	NULL,												/**< ui_requirement	*/
-	0,													/**< flags			*/
-	NULL,												/**< dependencies	*/
-	PURPLE_PRIORITY_DEFAULT,							/**< priority		*/
+	PURPLE_PLUGIN_MAGIC,
+	PURPLE_MAJOR_VERSION,
+	PURPLE_MINOR_VERSION,
+	PURPLE_PLUGIN_STANDARD,	
+	NULL,
+	0,
+	NULL,
+	PURPLE_PRIORITY_DEFAULT,
 
-	"core-plugin_pack-dice",							/**< id				*/
-	NULL,												/**< name			*/
-	PP_VERSION,											/**< version		*/
-	NULL,												/**  summary		*/
-	NULL,												/**  description	*/
-	"Gary Kramlich <grim at reaperworld.com>",				/**< author			*/
-	PP_WEBSITE,											/**< homepage		*/
+	"core-plugin_pack-dice",
+	NULL,
+	PP_VERSION,	
+	NULL,
+	NULL,
+	"Gary Kramlich <grim at reaperworld.com>",	
+	PP_WEBSITE,	
 
-	plugin_load,										/**< load			*/
-	plugin_unload,										/**< unload			*/
-	NULL,												/**< destroy		*/
+	plugin_load,
+	plugin_unload,
+	NULL,
 
-	NULL,												/**< ui_info		*/
-	NULL,												/**< extra_info		*/
-	NULL,												/**< prefs_info		*/
-	NULL,												/**< actions		*/
-	NULL,												/**< reserved 1		*/
-	NULL,												/**< reserved 2		*/
-	NULL,												/**< reserved 3		*/
-	NULL												/**< reserved 4		*/
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL
 };
 
 static void


More information about the Plugins-commits mailing list