/*****************************************************************************
* Room affect stuff. *
* Put skills that use room affects in here. *
* -- Hannibal *
*****************************************************************************/
#define unix 1
#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "merc.h"
/* Globals */
ROOM_AFFECT_DATA * raffect_free;
POWERED_DATA * pd_free;
/*
* Slap a rAffect on a room and update ch->powered.
*/
void raffect_to_room( ROOM_INDEX_DATA *room,
CHAR_DATA *ch, ROOM_AFFECT_DATA *raf )
{
ROOM_AFFECT_DATA *raf_new;
POWERED_DATA *pd;
if ( !raffect_free )
raf_new = alloc_perm( sizeof( *raf_new ) );
else
{
raf_new = raffect_free;
raffect_free = raffect_free->next;
}
if ( !pd_free )
pd = alloc_perm( sizeof( *pd ) );
else
{
pd = pd_free;
pd_free = pd_free->next;
}
*raf_new = *raf;
raf_new->next = room->rAffect;
room->rAffect = raf_new;
pd->room = room;
pd->raf = raf_new;
pd->next = ch->powered;
pd->type = raf_new->type;
pd->cost = SPELL_COST( ch, pd->type );
if ( ch->race == RACE_ELDER || ch->race == RACE_ELF )
pd->cost *= .75;
ch->powered = pd;
obj_to_room( raf->material, room );
if ( raf_new->location != ROOM_NONE )
TOGGLE_BIT( room->room_flags, raf->location );
return;
}
/*
* Remove and delete a rAffect and update ch->powered.
*/
void raffect_remove( ROOM_INDEX_DATA *room,
CHAR_DATA *ch, ROOM_AFFECT_DATA *raf )
{
ROOM_AFFECT_DATA *rAf, *prAf;
POWERED_DATA *pd, *ppd;
char buf[ MAX_STRING_LENGTH ];
if ( !room->rAffect )
{
bug( "rAffect_remove: no affect.", 0 );
return;
}
if ( raf->location != ROOM_NONE )
TOGGLE_BIT( room->room_flags, raf->location );
sprintf( buf, "%s", skill_table[raf->type].room_msg_off );
if ( ch->in_room == room )
act( AT_CYAN, buf, ch, NULL, NULL, TO_ROOM );
else if ( room->people )
act( AT_CYAN, buf, room->people, NULL, NULL, TO_ROOM );
ppd = NULL;
for ( pd = ch->powered; pd; ppd = pd, pd = pd->next )
{
if ( pd->room == room && pd->raf == raf )
{
if ( !ppd )
ch->powered = pd->next;
else
ppd->next = pd->next;
if ( MT( ch ) < pd->cost )
{
sprintf( buf, "%s %s.\n\r", skill_table[raf->type].msg_off,
raf->room->name );
send_to_char( AT_CYAN, buf, ch );
}
break;
}
}
prAf = NULL;
for ( rAf = room->rAffect; rAf; prAf = rAf, rAf = rAf->next )
{
if ( raf == rAf )
{
if ( !prAf )
room->rAffect = rAf->next;
else
prAf->next = rAf->next;
break;
}
}
extract_obj( raf->material );
free_mem( raf, sizeof( *raf ) );
free_mem( pd, sizeof( *pd ) );
return;
}
/*
* Check if room is rAffected by something.
*/
bool is_raffected( ROOM_INDEX_DATA *room, int sn )
{
ROOM_AFFECT_DATA *raf;
for ( raf = room->rAffect; raf; raf = raf->next )
{
if ( raf->type == sn )
return TRUE;
}
return FALSE;
}
/*
* To see what you're powering ( imms see room's rAffects as well ).
*/
void do_raffect( CHAR_DATA *ch, char *argument )
{
POWERED_DATA *pd;
ROOM_AFFECT_DATA *raf;
char buf[ MAX_INPUT_LENGTH ];
if ( IS_NPC( ch ) )
return;
if ( !ch->powered )
send_to_char( AT_CYAN, "You are not powering any room affects.\n\r", ch );
for ( pd = ch->powered; pd; pd = pd->next )
{
sprintf( buf, "%s&w, &cMana Cost&w: &R%d&w, &cRoom&w: &W%s&w.\n\r",
skill_table[pd->type].name,
pd->cost,
pd->room->name );
buf[0] = UPPER(buf[0]);
send_to_char( AT_WHITE, buf, ch );
}
if ( ch->level >= L_APP )
{
send_to_char(AT_CYAN, "This room is affected by:\n\r", ch );
for ( raf = ch->in_room->rAffect; raf; raf = raf->next )
{
sprintf( buf, "%s &cpowered by&w: &W%s&w.\n\r",
skill_table[raf->type].name,
raf->powered_by->name );
buf[0] = UPPER(buf[0]);
send_to_char(AT_WHITE, buf, ch );
}
}
return;
}
/*
* Remove all rAffects ch is powering. (mostly for quitting)
*/
void raffect_remall( CHAR_DATA *ch )
{
POWERED_DATA *pd, *pd_next;
for ( pd = ch->powered; pd; pd = pd_next )
{
if ( !pd )
return;
pd_next = pd->next;
raffect_remove( pd->room, ch, pd->raf );
}
return;
}
/*
* Toggle a room's rAffect location. (for asave_area)
*/
void toggle_raffects( ROOM_INDEX_DATA *room )
{
ROOM_AFFECT_DATA *raf;
for ( raf = room->rAffect; raf; raf = raf->next )
{
if ( !raf )
break;
if ( raf->location != ROOM_NONE )
TOGGLE_BIT( room->room_flags, raf->location );
}
return;
}
/*
* Locate or turn off a specific type of rAffect skill.
*/
void loc_off_raf( CHAR_DATA *ch, int gsn_raf, bool rOff )
{
POWERED_DATA *pd;
char buf [ MAX_STRING_LENGTH ];
bool found = FALSE;
if ( !rOff ) /* Locate a rAffect of type gsn_raf. */
{
for ( pd = ch->powered; pd; pd = pd->next )
{
if ( pd->type == gsn_raf )
{
sprintf( buf, "%s&w, &W%s&w; &cCost&w: &R%d&w.\n\r",
skill_table[gsn_raf].name, pd->room->name, pd->cost );
send_to_char( AT_WHITE, buf, ch );
found = TRUE;
}
}
if ( !found )
{
sprintf( buf, "You are not sustaining any %s&w.\n\r",
skill_table[gsn_raf].name );
send_to_char( AT_CYAN, buf, ch );
}
return;
}
/* Delete a rAffect of gsn_raf from room. */
if ( !is_raffected( ch->in_room, gsn_raf ) )
{
sprintf( buf, "There is no %s &cin this room.\n\r",
skill_table[gsn_raf].name );
send_to_char( AT_CYAN, buf, ch );
return;
}
for ( pd = ch->powered; pd; pd = pd->next )
{
if ( !pd )
break;
if ( pd->type == gsn_raf )
{
found = TRUE;
if ( pd->room == ch->in_room )
{
sprintf( buf, "%s\n\r", skill_table[gsn_raf].noun_damage );
send_to_char( AT_WHITE, buf, ch );
raffect_remove( ch->in_room, ch, pd->raf );
return;
}
}
}
if ( !found )
{
sprintf( buf, "You are not sustaining any %s&w.\n\r",
skill_table[gsn_raf].name );
return;
}
sprintf( buf, "You are not powering the %s &cin this room.\n\r",
skill_table[gsn_raf].name );
send_to_char( AT_CYAN, buf, ch );
return;
}
/*
* Main ward skill. Does NOTHING if no ward is known by ch.
*/
void do_ward( CHAR_DATA *ch, char *argument )
{
ROOM_AFFECT_DATA raf;
OBJ_DATA *ward;
char arg1[ MAX_INPUT_LENGTH ];
char buf[ MAX_STRING_LENGTH ];
char *wname, *shortd, *longd;
int type = 0;
int location = ROOM_NONE;
if ( IS_NPC( ch ) )
return;
if ( argument[0] == '\0' )
{
send_to_char( AT_WHITE, "Syntax: ward <type> <on|off|locate>\n\r", ch );
return;
}
wname = shortd = longd = "";
argument = one_argument( argument, arg1 );
if ( !str_cmp( arg1, "safety" ) )
{
type = gsn_ward_safe;
location = ROOM_SAFE;
wname = "ward safety";
shortd = "some Wards of Safety";
longd = "Some wards of safety have been raised in this room.";
}
if ( !str_cmp( arg1, "healing" ) )
{
type = gsn_ward_heal;
location = ROOM_NONE;
wname = "ward heal";
shortd = "some Wards of Healing";
longd = "Some wards of healing have been raised in this room.";
}
if ( type == 0 )
{
send_to_char(AT_GREY, "No such ward.\n\r", ch );
return;
}
if ( !can_use_skpell( ch, type ) )
{
sprintf( buf, "You aren't skilled in the ward of %s.\n\r", arg1 );
send_to_char(AT_GREY, buf, ch );
return;
}
if ( !str_cmp( argument, "locate" ) )
{
loc_off_raf( ch, type, FALSE );
return;
}
if ( !str_cmp( argument, "off" ) )
{
loc_off_raf( ch, type, TRUE );
return;
}
if ( str_cmp( argument, "on" ) )
{
do_ward( ch, "" );
return;
}
if ( ch->pcdata->learned[type] < number_percent( ) )
{
sprintf( buf, "You fail in raising your ward of %s.\n\r", arg1 );
send_to_char(AT_GREY, buf, ch );
return;
}
if ( type == gsn_ward_safe
&& IS_SET( ch->in_room->room_flags, ROOM_SAFE ) )
{
send_to_char(AT_WHITE, "This room is already safe.\n\r", ch );
return;
}
if ( type == gsn_ward_heal
&& is_raffected( ch->in_room, gsn_ward_heal ) )
{
send_to_char( AT_WHITE, "This room is already warded to heal.\n\r", ch );
return;
}
ward = create_object( get_obj_index( OBJ_VNUM_WARD_PHYS ), 1 );
free_string( ward->short_descr );
free_string( ward->description );
free_string( ward->name );
ward->name = str_dup( wname );
ward->short_descr = str_dup( shortd );
ward->description = str_dup( longd );
raf.type = type;
raf.location = location;
raf.material = ward;
raf.room = ch->in_room;
raf.powered_by = ch;
raffect_to_room( ch->in_room, ch, &raf );
sprintf( buf, "You raise a %s.\n\r", skill_table[type].name );
send_to_char( AT_WHITE, buf, ch );
act( AT_WHITE, "$n raises a $t.",
ch, (char *)skill_table[type].name, NULL, TO_ROOM );
if ( type == gsn_ward_heal )
update_skpell( ch, gsn_ward_heal );
if ( type == gsn_ward_safe )
update_skpell( ch, gsn_ward_safe );
return;
}