/**************************************************************************
* # # # ## # # ### ## ## ### 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);
}