empiremud/cnf/
empiremud/doc/
empiremud/lib/boards/
empiremud/lib/etc/
empiremud/lib/misc/
empiremud/lib/plralias/F-J/
empiremud/lib/plralias/K-O/
empiremud/lib/plralias/P-T/
empiremud/lib/plralias/U-Z/
empiremud/lib/plrobjs/
empiremud/lib/plrobjs/F-J/
empiremud/lib/plrobjs/K-O/
empiremud/lib/plrobjs/P-T/
empiremud/lib/plrobjs/U-Z/
empiremud/lib/world/
empiremud/lib/world/mob/
empiremud/lib/world/obj/
empiremud/log/
/* ************************************************************************
*   File: weather.c                                      EmpireMUD AD 1.0 *
*  Usage: functions handling time and the weather                         *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Code base by Paul Clarke.  EmpireMUD Project, a tbgMUD Production.     *
*  Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson.        *
*                                                                         *
*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "handler.h"
#include "interpreter.h"
#include "db.h"

extern struct time_info_data time_info;

void weather_and_time(int mode) {
	void another_hour(int mode);
	void weather_change();
	void save_exp_cycle();
	extern int exp_cycle;
	extern time_t last_exp_cycle;
	char *tmstr;
	time_t ct;

	/* Check to see if it's a new real day */
	/* Get the current time into buf */
	ct = time(0);
	tmstr = (char *) asctime(localtime(&ct));
	*(tmstr + strlen(tmstr) - 1) = '\0';
	sprintf(buf, "%6.10s", tmstr);

	/* Get the last exp cycle update into buf1 */
	ct = last_exp_cycle;
	tmstr = (char *) asctime(localtime(&ct));
	*(tmstr + strlen(tmstr) - 1) = '\0';
	sprintf(buf1, "%6.10s", tmstr);

	if (str_cmp(buf, buf1)) {
		exp_cycle++;
		last_exp_cycle = time(0);
		save_exp_cycle();
		}

	another_hour(mode);
	if (mode)
		weather_change();
	}


void another_hour(int mode) {
	void perform_noon_update(void);

	Descr d;
	room_rnum r;

	time_info.hours++;

	if (mode) {
		switch (time_info.hours) {
			case 7:
				weather_info.sunlight = SUN_RISE;
				for (d = descriptor_list; d; d = d->next)
					if (STATE(d) == CON_PLAYING && !HAS_INFRA(d->character) && !PRF_FLAGGED(d->character, PRF_HOLYLIGHT) && AWAKE(d->character) && IS_OUTDOORS(d->character) && !IS_WRITING(d->character)) {
						look_at_room(d->character);
						msg_to_char(d->character, "\r\n");
						}
				send_to_outdoor("The sun rises in the east.\r\n");
				break;
			case 8:
				weather_info.sunlight = SUN_LIGHT;
				send_to_outdoor("The day has begun.\r\n");
				break;
			case 12:
				/* Noon: Heal mortals, take blood from vampires */
				perform_noon_update();
				break;
			case 19:
				weather_info.sunlight = SUN_SET;
				send_to_outdoor("The sun slowly disappears in the west.\r\n");
				break;
			case 20:
				weather_info.sunlight = SUN_DARK;
				for (d = descriptor_list; d; d = d->next)
					if (STATE(d) == CON_PLAYING && !HAS_INFRA(d->character) && !PRF_FLAGGED(d->character, PRF_HOLYLIGHT) &&  AWAKE(d->character) && IS_OUTDOORS(d->character) && !IS_WRITING(d->character)) {
						look_at_room(d->character);
						msg_to_char(d->character, "\r\n");
						}
				send_to_outdoor("The night has begun.\r\n");
				break;
			}
		}
	if (time_info.hours > 23) {	/* Changed by HHS due to bug ??? */
		time_info.hours -= 24;
		time_info.day++;

		if (time_info.day > 29) {
			time_info.day = 0;
			time_info.month++;

			if (time_info.month > 11) {
				time_info.month = 0;
				time_info.year++;

				/* For fun, we'll refill all the mines now (with random metal. */
				/* This ONLY happens if the mud is up when it adds a year... */
				for (r = 0; r <= top_of_world; r++)
					if (SECT(r) == SECT_MOUNTAIN) {
						world[r].spare = 0;
						world[r].type2 = 0;
					}
				}
			}
		}
	}


void weather_change(void) {
	int diff, change;
	if ((time_info.month >= 4) && (time_info.month <= 8))
		diff = (weather_info.pressure > 985 ? -2 : 2);
	else
		diff = (weather_info.pressure > 1015 ? -2 : 2);

	weather_info.change += (dice(1, 4) * diff + dice(2, 6) - dice(2, 6));

	weather_info.change = MIN(weather_info.change, 12);
	weather_info.change = MAX(weather_info.change, -12);

	weather_info.pressure += weather_info.change;

	weather_info.pressure = MIN(weather_info.pressure, 1040);
	weather_info.pressure = MAX(weather_info.pressure, 960);

	change = 0;

	switch (weather_info.sky) {
		case SKY_CLOUDLESS:
			if (weather_info.pressure < 990)
				change = 1;
			else if (weather_info.pressure < 1010)
				if (!dice(0, 3))
					change = 1;
			break;
		case SKY_CLOUDY:
			if (weather_info.pressure < 970)
				change = 2;
			else if (weather_info.pressure < 990) {
				if (!dice(0, 3))
					change = 2;
				else
					change = 0;
				}
			else if (weather_info.pressure > 1030)
				if (!dice(0, 3))
					change = 3;
			break;
		case SKY_RAINING:
			if (weather_info.pressure < 970) {
				if (!dice(0, 3))
					change = 4;
				else
					change = 0;
				}
			else if (weather_info.pressure > 1030)
				change = 5;
			else if (weather_info.pressure > 1010)
				if (!dice(0, 3))
					change = 5;
			break;
		case SKY_LIGHTNING:
			if (weather_info.pressure > 1010)
				change = 6;
			else if (weather_info.pressure > 990)
				if (!dice(0, 3))
					change = 6;
			break;
		default:
			change = 0;
			weather_info.sky = SKY_CLOUDLESS;
			break;
		}

	switch (change) {
		case 1:
			send_to_outdoor("The sky starts to get cloudy.\r\n");
			weather_info.sky = SKY_CLOUDY;
			break;
		case 2:
			send_to_outdoor("It starts to rain.\r\n");
			weather_info.sky = SKY_RAINING;
			break;
		case 3:
			send_to_outdoor("The clouds disappear.\r\n");
			weather_info.sky = SKY_CLOUDLESS;
			break;
		case 4:
			send_to_outdoor("Lightning starts to show in the sky.\r\n");
			weather_info.sky = SKY_LIGHTNING;
			break;
		case 5:
			send_to_outdoor("The rain stops.\r\n");
			weather_info.sky = SKY_CLOUDY;
			break;
		case 6:
			send_to_outdoor("The lightning stops.\r\n");
			weather_info.sky = SKY_RAINING;
			break;
		}
	}


/*
 * Season code
 *  by Paul S. Clarke, 12/1/2001
 */

int get_season(void) {
	int day = time_info.month * 30 + time_info.day + 1;

	/* this takes a month number 1-12 + a day in the month (1-30) and plots it vs day*/
	#define Month_Day(m, d)		((m - 1) * 30 + d)

	if (day >= Month_Day(3, 21) && day < Month_Day(6, 21))
		return SEASON_SPRING;
	else if (day >= Month_Day(6, 21) && day < Month_Day(9, 22))
		return SEASON_SUMMER;
	else if (day >= Month_Day(9, 22) && day < Month_Day(12, 21))
		return SEASON_AUTUMN;
	return SEASON_WINTER;
	}


/*
 *  Empire Moons 1.0
 *   by Paul Clarke, 10/19/2k
 *
 *  To add a moon: increase NUM_OF_MOONS by 1 and add a line in moons[]
 *  to correspond with your new moon.  Reboot and it's all done for you.
 */

#define NUM_OF_MOONS		1

#define PHASE_NEW				0	/*								*/
#define PHASE_WAXING			1	/*								*/
#define PHASE_FIRST_QUARTER		2	/*  Phases of the moon			*/
#define PHASE_FULL				3	/*								*/
#define PHASE_LAST_QUARTER		4	/*								*/
#define PHASE_WANING			5	/*								*/

struct moon_data {
	char *name;
	byte cycle;			/* Days between full moons */
	} moons[NUM_OF_MOONS] = {
		{ "Moon",			28 }
		};


/* Retrieve the current phase of a specific moon */
byte get_phase(int M) {
	int total_time = time_info.day;
	int diff;

	total_time += time_info.month * 30;		/* 30 days in a month	*/
	total_time += time_info.year * 12 * 30;	/* 12 months in a year	*/

	total_time %= moons[M].cycle;

	diff = 100 * total_time / moons[M].cycle;		/* diff is a percentage of the rotation */

	if (diff <= 2 || diff >= 98)
		return PHASE_NEW;
	if (diff >= 23 && diff <= 27)
		return PHASE_FIRST_QUARTER;
	if (diff >= 73 && diff <= 77)
		return PHASE_LAST_QUARTER;
	if (diff >= 48 && diff <= 52)
		return PHASE_FULL;
	if (diff < 50)
		return PHASE_WAXING;
	else
		return PHASE_WANING;
	}


void list_moons_to_char(Creature ch) {
	int M, i;
	char moon_str[112];

	if (NUM_OF_MOONS == 0)
		return;

	*buf = '\0';

	for (M = 0; M < NUM_OF_MOONS; M++) {
		*moon_str = '\0';
		switch(get_phase(M)) {
			case PHASE_WAXING:			sprintf(moon_str, "waxing");				break;
			case PHASE_FIRST_QUARTER:	sprintf(moon_str, "in its first quarter");	break;
			case PHASE_FULL:			sprintf(moon_str, "full");					break;
			case PHASE_LAST_QUARTER:	sprintf(moon_str, "in its last quarter");	break;
			case PHASE_WANING:			sprintf(moon_str, "waning");				break;
			}
		if (*buf)
			strcat(buf, ", ");
		if (*moon_str)
			sprintf(buf+strlen(buf), "%s is %s", moons[M].name, moon_str);
		}

	if (!*buf)
		sprintf(buf, "You can't see the moon%s right now", NUM_OF_MOONS > 1 ? "s" : "");

	strcat(buf, ".\r\n");

	/* This will find the last comma and replace it with an "and" */
	for (i = strlen(buf)-1; i > 0; i--)
		if (buf[i] == ',') {
			sprintf(buf1, buf + i+1);
			buf[i] = '\0';
			strcat(buf, " and");
			strcat(buf, buf1);
			break;
			}
	msg_to_char(ch, buf);
	}


byte distance_can_see(Creature ch) {
	int M, p, a = 0, b = 0, c = 0;

	for (M = 0; M < NUM_OF_MOONS; M++) {
		switch (get_phase(M)) {
			case PHASE_FULL:			c = 4;		break;
			case PHASE_FIRST_QUARTER:
			case PHASE_LAST_QUARTER:	c = 3;		break;
			case PHASE_WAXING:
			case PHASE_WANING:			c = 2;		break;
			default:					c = 1;		break;
			}
		if (c > a)
			a = c;
		else if (c > b)
			b = c;
		}
	p = a + b;
	p = MIN(5, p);

	if (DSC_FLAGGED(ch, DSC_WITNESS_OF_DARKNESS))
		p *= 4;
	else if (DSC_FLAGGED(ch, DSC_HEIGHTENED_SENSES))
		p *= 2;

	if (IS_LIGHT(ch->in_room))
		p++;

	return p;
	}