Lyonesse/bin/
Lyonesse/doc/eng/
Lyonesse/doc/ita/
Lyonesse/lib/
Lyonesse/lib/buildings/
Lyonesse/lib/clans/
Lyonesse/lib/data/
Lyonesse/lib/etc/
Lyonesse/lib/house/
Lyonesse/lib/misc/
Lyonesse/lib/plralias/A-E/
Lyonesse/lib/plralias/F-J/
Lyonesse/lib/plralias/K-O/
Lyonesse/lib/plralias/P-T/
Lyonesse/lib/plralias/U-Z/
Lyonesse/lib/plralias/ZZZ/
Lyonesse/lib/plrobjs/A-E/
Lyonesse/lib/plrobjs/F-J/
Lyonesse/lib/plrobjs/K-O/
Lyonesse/lib/plrobjs/P-T/
Lyonesse/lib/plrobjs/U-Z/
Lyonesse/lib/plrobjs/ZZZ/
Lyonesse/lib/plrsave/A-E/
Lyonesse/lib/plrsave/F-J/
Lyonesse/lib/plrsave/K-O/
Lyonesse/lib/plrsave/P-T/
Lyonesse/lib/plrsave/U-Z/
Lyonesse/lib/plrsave/ZZZ/
Lyonesse/lib/ships/
Lyonesse/lib/stables/
Lyonesse/lib/text/help/
Lyonesse/lib/world/
Lyonesse/lib/world/bld/
Lyonesse/lib/world/ship/
Lyonesse/lib/world/shp/
Lyonesse/lib/world/wls/
Lyonesse/lib/world/wls/Life/
Lyonesse/lib/world/wls/Map/
Lyonesse/log/
/**************************************************************************
 * #   #   #   ##   #  #  ###   ##   ##  ###       http://www.lyonesse.it *
 * #    # #   #  #  ## #  #    #    #    #                                *
 * #     #    #  #  # ##  ##    #    #   ##   ## ##  #  #  ##             *
 * #     #    #  #  # ##  #      #    #  #    # # #  #  #  # #            *
 * ###   #     ##   #  #  ###  ##   ##   ###  #   #  ####  ##    Ver. 1.0 *
 *                                                                        *
 * -Based on CircleMud v3.0-    Copyright (c) 1996-2001 by Fabrizio Baldi *
 **************************************************************************/
/**************************************************************************
 * File: room_trigger.c               Intended to be used with CircleMUD  *
 *                                                                        *
 * Usage: code for triggered events on rooms				  *
 *                                                                        *
 * Copyright (C) 1999, 2000 by Fabrizio Baldi                             *
 *                                                                        *
 * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
 * CircleMUD (C) 1993, 94 by the Trustees of the Johns Hopkins University *
 **************************************************************************/

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

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

/* external functions */
ROOM_DATA *create_wild_room( COORD_DATA *coord, bool Static );
bitvector_t asciiflag_conv(char *flag);

/* functions in this file */
void activate_teleport(CHAR_DATA *ch, int delay, ROOM_DATA *target_room, char *to_char, char *to_room);
void teleport_char(CHAR_DATA *ch, ROOM_DATA *target_room, char *to_char, char *to_room);
void trigger_teleport(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger);

void activate_heal(CHAR_DATA *ch, int delay, char *to_char, char *to_room);
void heal_char(CHAR_DATA *ch, char *to_char, char *to_room);
void trigger_heal(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger);

void trigger_collapse(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger);
void trigger_explosion(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger);

EVENTFUNC(teleport_event);
EVENTFUNC(heal_event);

/* ========================================================================= */

/*
 * Explanation of TRIGGER TYPE:
 *
 * TELEPORT:  teleport pc/npc from room to: 1) another room 2) to coord
 * COLLAPSE:  room collapse, making the specified damage to everybody, and
 *            restore itself after the time specified
 *            (usually tunnels or underground rooms)
 * EXPLOSION: room explode, making the specified damage
 *            (usually magic rooms)
 * HEAL:      room heals everybody
 *            (usually holy rooms)
 */

/* ========================================================================= */

int parse_trig_type( char *trigname )
{
	if ( !str_cmp(trigname, "teleport") )
		return (TRIG_TELEPORT);
	if ( !str_cmp(trigname, "collapse") )
		return (TRIG_COLLAPSE);
	if ( !str_cmp(trigname, "explosion") )
		return (TRIG_EXPLOSION);
	if ( !str_cmp(trigname, "heal") )
		return (TRIG_HEAL);

	return (TRIG_NONE);
}

/*
 * Room Trigger event
 *
 * Format:
 *
 * T
 * <type name> <who trig> <timer>
 * <action bitv> <random> <active>
 * <value0> <value1> <value2> <value3>
 *
 * Details:
 *
 * <type name>	 : the name type of trigger, ( es "teleport", "collapse" ) NO "
 * <who trig>    : 1 (Everybody); 2 (PCs); 3 (Mobs)
 * <timer>       : range from 1 (immediately) to MAX_TEL_DELAY
 * <action bitv> : see structs.h & constants.c
 * <random>		 : 0 for an always trigger, otherwise a 1-100 value for random %
 * <active>      : 0 (Not Active); 1 (Active)
 *
 * Details of Value fields:
 *
 * Trigger Type		Value1		Value2		Value3		Value4
 * -----------------------------------------------------------------------------
 * TRIG_TELEPORT 	<room vnum>	<coord y>	<coord x>	<unused>
 * TRIG_COLLAPSE	<room vnum>	<damage>	<timer>		<unused>
 * TRIG_EXPLOSION	<damage>	<unused>	<unused>	<unused>
 * TRIG_HEAL		<unused>	<unused>	<unused>	<unused>
 * -----------------------------------------------------------------------------
 *
 * <room vnum> is the destination room VNUM for teleport
 * <coord y & x> are the destination coords for teleport in wilderness
 * <damage> is the amount of damage suffered by every pc/npc in rooms
 *
 * NOTE: when coords are specified, <room vnum> MUST BE 0
 *       when <room vnum> is specified, <coord y> & <coord x> are IGNORED
 *
 *
 * Example:
 *
 * "Always teleport to room 3001 everybody who rest in room, 4 seconds delayed"
 * T
 * teleport 1 4
 * h 0 1
 * 3001 0 0 0
 *
 * "Heal players (no mobs) that sleep in room, immediately, 50% probs"
 * T
 * heal 2 1
 * i 50 1
 * 0 0 0 0
 *
 */
void setup_trigger( ROOM_DATA *pRoom, FILE *fl )
{
	TRIGGER_DATA *trig;
	char line[256], f1[128], tbuf[MAX_STRING_LENGTH];
	int retval, t[10];
	
	CREATE(trig, TRIGGER_DATA, 1);
	trig->text			= NULL;
	trig->next			= NULL;

	if (!get_line(fl, line))
	{
		log("SYSERR: Expecting trigger data of room #%d but file ended!", pRoom->number);
		DISPOSE(trig);
		exit(1);
	}
	
	if ( (retval = sscanf(line, " %s %d %d ", f1, t, t+1)) != 3)
	{
		log("SYSERR: Format error in first line of room trigger data of room #%d", pRoom->number );
		DISPOSE(trig);
		exit(1);
	}

	trig->type			= parse_trig_type( f1 );
	if ( trig->type == TRIG_NONE )
	{
		log("SYSERR: Unknown trigger type in room trigger data of room #%d", pRoom->number );
		DISPOSE(trig);
		exit(1);
	}
	trig->whotrig		= URANGE(0, t[0], MAX_TRIG_WHO);
	trig->timer			= URANGE(1, t[1], MAX_TRIG_DELAY);

	if (!get_line(fl, line))
	{
		log("SYSERR: Expecting trigger data of room #%d but file ended!", pRoom->number);
		DISPOSE(trig);
		exit(1);
	}
	
	if ( (retval = sscanf(line, " %s %d %d ", f1, t, t+1)) != 3)
	{
		log("SYSERR: Format error in second line of room trigger data of room #%d", pRoom->number );
		DISPOSE(trig);
		exit(1);
	}

	trig->action		= asciiflag_conv(f1);
	if ( t[0] )
		trig->random	= URANGE(1, t[0], 100);
	else
		trig->random	= 101;
	trig->active		= URANGE(0, t[1], 1);

	if (!get_line(fl, line))
	{
		log("SYSERR: Expecting trigger data of room #%d but file ended!", pRoom->number);
		DISPOSE(trig);
		exit(1);
	}
	
	if ( (retval = sscanf(line, " %d %d %d %d ", t, t+1, t+2, t+3)) != 4)
	{
		log("SYSERR: Format error in third line of room trigger data of room #%d", pRoom->number );
		DISPOSE(trig);
		exit(1);
	}

	switch ( trig->type )
	{
	case TRIG_TELEPORT:
		if ( t[0] )
		{
			trig->value[0]	= t[0];		// room vnum
			trig->value[1]	= 0;
			trig->value[2]	= 0;
			trig->value[3]	= 0;
		}
		else
		{
			if ( !check_coord(t[1], t[2]) )
			{
				log("SYSERR: Invalid coord values in room trigger data of room #%d", pRoom->number );
				DISPOSE(trig);
				exit(1);
			}
			trig->value[0]	= 0;
			trig->value[1]	= t[1];		// y coord
			trig->value[2]	= t[2];		// x coord
			trig->value[3]	= 0;
		}
		break;
	case TRIG_COLLAPSE:
		if ( !t[0] )
		{
			log("SYSERR: Missing room vnum in room trigger data of room #%d", pRoom->number );
			DISPOSE(trig);
			exit(1);
		}
		trig->value[0]		= t[0];						// room vnum
		trig->value[1]		= URANGE(1, t[1], 1000);	// max 1000 dam points
		trig->value[2]		= URANGE(1, t[2], 10);		// restore in ? 
		trig->value[3]		= 0;
		break;
	case TRIG_EXPLOSION:
		trig->value[0]		= URANGE(1, t[0], 1000);	// max 1000 dam points
		trig->value[1]		= 0;
		trig->value[2]		= 0;
		trig->value[3]		= 0;
		break;
	case TRIG_HEAL:
	default:
		trig->value[0]		= 0;
		trig->value[1]		= 0;
		trig->value[2]		= 0;
		trig->value[3]		= 0;
		break;
	}

	if ( !trig->text )
	{
		sprintf( tbuf, "%s trigger", trig_type_descr[trig->type]);
		trig->text		= str_dup(tbuf);
	}
	
	/* add to the room list */
	trig->next			= pRoom->trigger;
	pRoom->trigger		= trig;
}

/* ========================================================================= */

/*
 * Core function of the room trigger events
 */
bool check_room_trigger(CHAR_DATA *ch, int trigger)
{
	ROOM_DATA *pRoom;
	bool okwho = TRUE;

	/* no ch? no party! :-)) */
	if ( !ch )
		return (FALSE);

	pRoom = ch->in_room;

	if ( !pRoom->trigger )
		return (FALSE);

	/* trigger is active? */
	if ( !pRoom->trigger->active )
		return (FALSE);

	/* trigger is activate by THIS action? */
	if ( !IS_SET(pRoom->trigger->action, trigger) )
		return (FALSE);

	/* can ch activate the trigger? */
	switch ( pRoom->trigger->whotrig )
	{
	default:
	case 0:
		break;
	case 1:
		if (IS_NPC(ch))		okwho = FALSE;
		break;
	case 2:
		if (!IS_NPC(ch))	okwho = FALSE;
		break;
	}

	if ( !okwho )
		return (FALSE);

	/* nothing happens if number is greater than chance of the trigger */
	if ( number(0, 100) > pRoom->trigger->random )
		return (FALSE);

	switch ( pRoom->trigger->type )
	{
	default:
		log( "SYSERR: check_room_trigger() : unknown room trigger type." );
		return (FALSE);
	case TRIG_TELEPORT:
		trigger_teleport(ch, pRoom, trigger);
		break;
	case TRIG_HEAL:
		trigger_heal(ch, pRoom, trigger);
		break;
	case TRIG_COLLAPSE:
	case TRIG_EXPLOSION:
		return (FALSE);
	}
	
	return (TRUE);
}

/* ========================================================================= */

void activate_teleport(CHAR_DATA *ch, int delay, ROOM_DATA *target_room, char *to_char, char *to_room)
{
	ROOM_TELEPORT *rte = NULL;

	CREATE(rte, ROOM_TELEPORT, 1);

	rte->ch				= ch;
	rte->orig_room		= ch->in_room;
	rte->delay			= delay;
	rte->target			= target_room;
	rte->msg_to_char	= str_dup(to_char);
	rte->msg_to_room	= str_dup(to_room);

	event_create(teleport_event, rte, 1);
}


void teleport_char(CHAR_DATA *ch, ROOM_DATA *target_room, char *to_char, char *to_room)
{
	send_to_char(to_char, ch);
	act(to_room, TRUE, ch, NULL, NULL, TO_ROOM);

	char_from_room(ch);
	char_to_room(ch, target_room);

	/* # TODO # should teleport away horse and vehicles too... */
	look_at_room( ch, TRUE );
}


void trigger_teleport(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger)
{
	ROOM_DATA *target_room;
	COORD_DATA *coord;
	char *to_char, *to_room;

	if ( pRoom->trigger->value[0] )
		target_room = get_room( pRoom->trigger->value[0] );
	else
	{
		CREATE(coord, COORD_DATA, 1);
		coord->y = pRoom->trigger->value[1];
		coord->x = pRoom->trigger->value[2];
		target_room = create_wild_room( coord, FALSE );
	}

	if ( !target_room )
		return;

	/* setup the message for ch and room */
	switch (trigger)
	{
	case TRIG_ACT_ENTER:
		to_char = str_dup("As you enter in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n enter in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_EXIT:
		to_char = str_dup("As you approach the exit of the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n try to exit from the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_CAST:
		to_char = str_dup("As you cast a spell in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n casts a spell in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_FIGHT_START:
		to_char = str_dup("As you start fighting in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n start to fight in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_FIGHT_END:
		to_char = str_dup("As you stop fighting in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n stop to fight in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_GET:
		to_char = str_dup("As you get something from the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n get something in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_DROP:
		to_char = str_dup("As you drop an item in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n drops an item in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_REST:
		to_char = str_dup("As you sit down in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n sits down in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_SLEEP:
		to_char = str_dup("As you start sleeping in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n start sleeping in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	case TRIG_ACT_SPEAK:
		to_char = str_dup("As you speak in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n speaks in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	default:
		to_char = str_dup("As you enter in the room, a flash of light blind you for a moment\r\nand you feel transported elsewhere.\r\n");
		to_room = str_dup("As $n enter in the room, a flash of light surrounds $m,\r\nand $e is no longer there.");
		break;
	}

	if (trigger == TRIG_ACT_EXIT)
		teleport_char(ch, target_room, to_char, to_room);
	else
		activate_teleport(ch, pRoom->trigger->timer, target_room, to_char, to_room);
}

/* ========================================================================= */

void trigger_collapse(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger)
{
	/* TODO */
}

/* ========================================================================= */

void trigger_explosion(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger)
{
	/* TODO */
}

/* ========================================================================= */

void activate_heal(CHAR_DATA *ch, int delay, char *to_char, char *to_room)
{
	ROOM_HEAL *rhe;

	CREATE(rhe, ROOM_HEAL, 1);

	rhe->ch				= ch;
	rhe->orig_room		= ch->in_room;
	rhe->delay			= delay;
	rhe->msg_to_char	= to_char;
	rhe->msg_to_room	= to_room;

	event_create(heal_event, rhe, 1);
}


void heal_char(CHAR_DATA *ch, char *to_char, char *to_room)
{
	send_to_char(to_char, ch);
	act(to_room, TRUE, ch, NULL, NULL, TO_ROOM);

	GET_HIT(ch)		= GET_MAX_HIT(ch);
	GET_MANA(ch)	= GET_MAX_MANA(ch);
	GET_MOVE(ch)	= GET_MAX_MOVE(ch);
}


void trigger_heal(CHAR_DATA *ch, ROOM_DATA *pRoom, int trigger)
{
	char *to_char, *to_room;

	/* setup the message for ch and room */
	switch (trigger)
	{
	case TRIG_ACT_ENTER:
		to_char = str_dup("As you enter in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n enter in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_EXIT:
		to_char = str_dup("As you approach the exit of the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n try to exit from the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_CAST:
		to_char = str_dup("As you cast a spell in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n casts a spell in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_FIGHT_START:
		to_char = str_dup("As you start fighting in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n start to fight in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_FIGHT_END:
		to_char = str_dup("As you stop fighting in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n stop to fight in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_GET:
		to_char = str_dup("As you get something from the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n get something in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_DROP:
		to_char = str_dup("As you drop an item in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n drops an item in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_REST:
		to_char = str_dup("As you sit down in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n sits down in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_SLEEP:
		to_char = str_dup("As you start sleeping in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n start sleeping in the room, a flash of light surrounds $m.");
		break;
	case TRIG_ACT_SPEAK:
		to_char = str_dup("As you speak in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n speaks in the room, a flash of light surrounds $m.");
		break;
	default:
		to_char = str_dup("As you enter in the room, a flash of light blind you for a moment\r\nand you feel better.\r\n");
		to_room = str_dup("As $n enter in the room, a flash of light surrounds $m.");
		break;
	}

	if (trigger == TRIG_ACT_EXIT)
		heal_char(ch, to_char, to_room);
	else
		activate_heal(ch, pRoom->trigger->timer, to_char, to_room);
}


/* ========================================================================= */
/* EVENTS																	 */
/* ========================================================================= */

EVENTFUNC(teleport_event)
{
	ROOM_TELEPORT *rte = (ROOM_TELEPORT *) event_obj;
	CHAR_DATA *ch = NULL;
	ROOM_DATA *telep_room, *target_room;
	char to_char[MAX_STRING_LENGTH], to_room[MAX_STRING_LENGTH];

	/* extract data */
	ch			= rte->ch;
	telep_room	= rte->orig_room;
	target_room	= rte->target;

	strcpy(to_char, rte->msg_to_char);
	strcpy(to_room, rte->msg_to_room);

	/* make sure we're supposed to be here */
	if (!ch)
	{
		DISPOSE(event_obj);
		return (0);
	}

	if ( !target_room )
	{
		log("SYSERR: target room for teleport for %s no longer exist.", GET_NAME(ch));
		DISPOSE(event_obj);
		return (0);
	}

	if (rte->delay-- > 0)
		return (1);

	/*
	 * ch is no longer in the teleport room...
	 */
	if (ch->in_room != telep_room)
	{
		DISPOSE(event_obj);
		return (0);
	}

	teleport_char(ch, target_room, to_char, to_room);

	DISPOSE(event_obj);
	return (0);
}


EVENTFUNC(heal_event)
{
	ROOM_HEAL *rhe = (ROOM_HEAL *) event_obj;
	CHAR_DATA *ch = NULL;
	ROOM_DATA *orig_room = NULL;
	char to_char[MAX_STRING_LENGTH], to_room[MAX_STRING_LENGTH];

	/* extract data */
	ch			= rhe->ch;
	orig_room	= rhe->orig_room;

	strcpy(to_char, rhe->msg_to_char);
	strcpy(to_room, rhe->msg_to_room);

	/* make sure we're supposed to be here */
	if (!ch)
	{
		DISPOSE(event_obj);
		return (0);
	}

	if (rhe->delay-- > 0)
		return (1);

	/*
	 * ch is no longer in the healing room...
	 */
	if (ch->in_room != orig_room)
	{
		DISPOSE(event_obj);
		return (0);
	}

	heal_char(ch, to_char, to_room);

	DISPOSE(event_obj);
	return (0);
}