asgard/
asgard/.settings/
asgard/area/
asgard/data/clans/
asgard/data/clans/history/
asgard/data/rosters/
asgard/src/notice/
/*
 * expmod.c
 *
 *  Created on: 4 Feb 2011
 *      Author: Nico
 *
 *  Variable experience modifier.
 */

#include <stdlib.h>
#include <stdio.h>
#include "merc.h"

#define EXPMOD_FILE		"expmod.txt"

void do_announce(CHAR_DATA *ch, char *argument);

static int expmod_num = 1;				// Exp modifier numerator.
static int expmod_denom = 1;			// Exp modifier denominator.
static int expmod_min_level = 1;		// Minimum level of players affected.
static int expmod_max_level = LEVEL_HERO;		// Maximum level of players affected.
static int expmod_timer = -1;			// How long left on the timer in minutes.
static int expmod_last_update = 0;		// Last update for expmod.

// We will assume that any change to the exp_mod_denom field will handle zeroes.

bool expmod_is_enabled() {
	return expmod_timer != 0
		&& expmod_num != expmod_denom;
}

char *expmod_multiplier() {
	static char buf[MAX_STRING_LENGTH];

	if (expmod_denom == 1)
		sprintf(buf, "%d", expmod_num);
	else
		sprintf(buf, "%.3f", ((float)expmod_num)/((float)expmod_denom));

	return buf;
}

char *expmod_level_range() {
	static char buf[MAX_STRING_LENGTH];

	if (expmod_min_level == expmod_max_level)
		sprintf(buf, "%d", expmod_min_level);
	else
		sprintf(buf, "%d-%d", expmod_min_level, expmod_max_level);

	return buf;
}

char *expmod_duration() {
	static char buf[MAX_STRING_LENGTH];

	if (expmod_timer < 0)
		return "forever";

	sprintf(buf, "%d minute%s", expmod_timer, expmod_timer != 1 ? "s" : "");
	return buf;
}

bool expmod_applies(CHAR_DATA *ch) {
	return expmod_is_enabled()
		&& ch->level >= expmod_min_level
		&& ch->level <= expmod_max_level;
}

int expmod_calc(int exp) {
	return exp * expmod_num / expmod_denom;
}

void expmod_save() {
	FILE *fp;

	if ((fp = get_temp_file()) == NULL) {
		printf_debug("expmod_save: could not open temporary file.");
		return;
	}

	fprintf(fp, "%d %d %d %d %d",
		expmod_num, expmod_denom, expmod_min_level, expmod_max_level, expmod_timer);

	if (!close_write_file(EXPMOD_FILE))
		printf_debug("expmod_save: could not save file as "EXPMOD_FILE".");
}

void expmod_load() {
	FILE *fp;

	if ((fp = fopen(EXPMOD_FILE, "r")) == NULL) {
		printf_debug("expmod_load: could not open "EXPMOD_FILE".");
		return;
	}

	expmod_num = fread_number(fp);
	expmod_num = UMAX(expmod_num, 1);

	expmod_denom = fread_number(fp);
	if (expmod_denom == 0)
		expmod_denom = 1;

	expmod_min_level = fread_number(fp);
	expmod_min_level = UMAX(expmod_min_level, 1);

	expmod_max_level = fread_number(fp);
	expmod_max_level = UMIN(expmod_max_level, LEVEL_HERO);

	expmod_timer = fread_number(fp);
	fclose(fp);
}

void do_expmod(CHAR_DATA *ch, char *argument) {
	char buf[MAX_STRING_LENGTH];

	if (argument[0] == '\0') {
		send_to_char(
			"Syntax: {wexpmod level <min level> <max level>\r\n"
			"        {y - Set the level range affected by the modifier\r\n"
			"        {wexpmod duration <minutes>|forever\r\n"
			"        {y - Set the duration for the modifier to last\r\n"
			"        {wexpmod multiplier <numerator> [denominator]\r\n"
			"        {y - Set the modifier multiplier (numerator/denominator fraction)\r\n"
			"        {wexpmod default level|all [duration]\r\n"
			"        {y - Set the default expmod for levellers or everyone with an optional duration\r\n"
			"        {wexpmod status\r\n"
			"        {y - See the current status of the experience modifier.\r\n\r\n"
			"        {wThe experience modifier only takes effect if the duration != 0\r\n"
			"        and the multiplier != 0\r\n{x",
			ch);
		return;
	}

	argument = one_argument(argument, buf);

	bool pre_change = expmod_is_enabled();

	if (!str_prefix(buf, "level")) {
		argument = one_argument(argument, buf);

		if (buf[0] == '\0' || argument[0] == '\0') {
			send_to_char("Please specify both the minimum level and maximum level.\r\n", ch);
			return;
		}

		int min_level, max_level;
		if ((min_level = atoi(buf)) < 1
		||	(max_level = atoi(argument)) < 1
		||	min_level > max_level
		||  max_level > LEVEL_HERO) {
			sprintf(buf, "Please specify the levels as numbers between 1 and %d, with the minimum level first.\r\n", LEVEL_HERO);
			send_to_char(buf, ch);
			return;
		}

		sprintf(buf, "Level range set to %d-%d.\r\n", min_level, max_level);
		send_to_char(buf, ch);
		expmod_min_level = min_level;
		expmod_max_level = max_level;
	} else if (!str_prefix(buf, "duration")) {
		if (argument[0] == '\0') {
			send_to_char("Please specify a length in minutes or \"forever\".\r\n", ch);
			return;
		}

		if (is_number(argument)) {
			int duration = atoi(argument);
			if (duration <= 0)
				send_to_char("The length must be a positive number.\r\n", ch);
			else {
				sprintf(buf, "Duration set to %d minutes.\r\n", duration);
				send_to_char(buf, ch);
				expmod_timer = duration;
			}
		} else if (!str_cmp(argument, "forever")) {
			expmod_timer = -1;
			send_to_char("Timer set to forever.\r\n", ch);
		} else
			send_to_char("Invalid length of time.\r\n", ch);
	} else if (!str_prefix(buf, "multiplier")) {
		int numerator, denominator = 1;

		argument = one_argument(argument, buf);

		if (buf[0] == '\0' || (numerator = atoi(buf)) < 1) {
			send_to_char("Please specify a multiplier greater than zero.\r\n", ch);
			return;
		}

		if (argument[0] != '\0' && (denominator = atoi(argument)) < 1) {
			send_to_char("Please specify a divisor greater than zero.\r\n", ch);
			return;
		}

		if (denominator > numerator) {
			send_to_char("The divisor must be less than the multiplier.\r\n", ch);
			return;
		}

		if (numerator / denominator > 10) {
			send_to_char("No more than 10x multiplier, please.\r\n", ch);
			return;
		}

		// TODO, reduce fraction using gcf, rather than just this.
		if (numerator % denominator == 0) {
			numerator = numerator/denominator;
			denominator = 1;
		}

		expmod_num = numerator;
		expmod_denom = denominator;
		sprintf(buf, "Experience multiplier set to %s.\r\n", expmod_multiplier());
		send_to_char(buf, ch);
	} else if (!str_prefix(buf, "default")) {
		argument = one_argument(argument, buf);

		if (buf[0] == '\0') {
			send_to_char("Please specify \"level\" or \"all\".\r\n", ch);
			return;
		}

		int duration = -1;

		if (argument[0] != '\0') {
			if ((duration = atoi(argument)) <= 0) {
				send_to_char("Either don't specify a duration for forever, or specify a positive duration in minutes.\r\n", ch);
				return;
			}
		}

		if (!str_cmp(buf, "level")) {
			send_to_char("Enabling leveller experience mod.\r\n", ch);
			expmod_max_level = LEVEL_HERO-1;
			expmod_num = 5;
			expmod_denom = 4;
		} else if (!str_prefix(buf, "all")) {
			send_to_char("Enabling global 2x experience mod.\r\n", ch);
			expmod_max_level = LEVEL_HERO;
			expmod_num = 2;
			expmod_denom = 1;
		} else {
			do_expmod(ch, "default");
			return;
		}

		if (duration > 0) {
			sprintf(buf, "This will last for %d minutes.\r\n", duration);
			send_to_char(buf, ch);
		}

		expmod_min_level = 1;
		expmod_timer = duration;

	} else if (!str_prefix(buf, "status")) {
		sprintf(buf,
			"Experience modifier status:\r\n"
			" Multiplier:  %s\r\n"
			" Level range: %s\r\n"
			" Duration:    %s\r\n"
			" Enabled:     %s\r\n",
			expmod_multiplier(), expmod_level_range(),
			expmod_duration(), expmod_is_enabled() ? "yes" : "no");
		send_to_char(buf, ch);
	} else
		do_expmod(ch, "");

	// Change enabled experience modifier.
	if (!pre_change && expmod_is_enabled()) {
		sprintf(buf, "An experience modifier of %s has been enabled for levels %s lasting %s!",
			expmod_multiplier(), expmod_level_range(), expmod_duration());
		do_announce(ch, buf);
	} else if (pre_change) {
		if (expmod_is_enabled()) {
			sprintf(buf, "Experience modifier changed to %s for levels %s, lasting %s.",
				expmod_multiplier(), expmod_level_range(), expmod_duration());
			do_announce(ch, buf);
		} else
			do_announce(ch, "Experience modifier returned to normal.");
	}

	expmod_save();
}

void expmod_update() {
	if (!expmod_is_enabled()) {
		expmod_last_update = current_time;
		return;
	}
	if (expmod_timer > 0 && current_time - expmod_last_update >= 60) {
		expmod_last_update = current_time;
		if (--expmod_timer == 0) {
//			do_announce(NULL, "Experience modifier returned to normal.");
			do_expmod(NULL, "default level");
		}
		expmod_save();
	}
}