/*****************************************************************************
* Interface for group spell casting. *
* -- Altrag *
*****************************************************************************/
#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"
/*
* Local functions
*/
void add_gspell args ( ( CHAR_DATA *ch, int sn, int level, void *vo ) );
int gslot_lookup args ( ( int sn ) );
bool is_same_gspell args ( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
bool is_same_gspell( CHAR_DATA *ch, CHAR_DATA *victim )
{
if ( !is_same_group( ch, victim ) )
return FALSE;
if ( !ch->gspell || !victim->gspell )
return FALSE;
if ( ch->gspell->sn != victim->gspell->sn )
return FALSE;
if ( ch->gspell->victim != victim->gspell->victim )
return FALSE;
return TRUE;
}
void set_gspell( CHAR_DATA *ch, GSPELL_DATA *gsp )
{
GSPELL_DATA *gsp_new;
gsp_new = alloc_mem( sizeof(*gsp_new) );
*gsp_new = *gsp;
ch->gspell = gsp_new;
}
void end_gspell( CHAR_DATA *ch )
{
if ( !ch->gspell )
{
bug( "end_gspell: no gspell", 0 );
return;
}
free_mem( ch->gspell, sizeof(*ch->gspell) );
ch->gspell = NULL;
}
/*
* Implementation stuff
*/
void check_gcast( CHAR_DATA *ch )
{
CHAR_DATA *gch;
int looper;
int casters[MAX_CLASS];
int sn;
int level = 0;
int total = 0;
if ( !ch->gspell || ch->gspell->timer <= 0 )
return;
sn = ch->gspell->sn;
for ( looper = 0; looper < MAX_CLASS; looper++ )
casters[looper] = 0;
for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
{
if ( is_same_gspell( ch, gch ) )
{
casters[prime_class(gch)]++;
total++;
level = (level / 4) + gch->gspell->level;
}
}
for ( looper = 0; looper < MAX_CLASS; looper++ )
if ( casters[looper] < gskill_table[gslot_lookup(sn)].casters[looper] )
{
send_to_char(AT_BLUE, "Ok.\n\r", ch );
return;
}
sn = slot_lookup(sn);
(* skill_table[sn].spell_fun) ( sn, level, ch->leader ? ch->leader : ch,
ch->gspell->victim );
for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
{
if ( is_same_gspell( ch, gch ) && ch != gch )
end_gspell( gch );
}
switch (skill_table[sn].target)
{
case TAR_GROUP_OFFENSIVE:
{
CHAR_DATA *victim = (CHAR_DATA *)ch->gspell->victim;
rprog_cast_sn_trigger( ch->in_room, ch, sn, victim );
if ( !victim->fighting )
if ( IS_NPC( victim ) || (ch->leader ? ch->leader : ch) == victim )
multi_hit( victim, ch->leader ? ch->leader : ch, TYPE_UNDEFINED );
}
break;
case TAR_GROUP_DEFENSIVE:
rprog_cast_sn_trigger( ch->in_room, ch, sn, ch->gspell->victim );
break;
case TAR_GROUP_ALL:
rprog_cast_sn_trigger( ch->in_room, ch, sn, ch );
break;
case TAR_GROUP_IGNORE:
rprog_cast_sn_trigger( ch->in_room, ch, sn,
(ch->gspell->victim ? ch->gspell->victim : ch) );
break;
case TAR_GROUP_OBJ:
if ( ch->gspell->victim )
{
oprog_cast_sn_trigger( ch->gspell->victim, ch, sn, ch->gspell->victim );
rprog_cast_sn_trigger( ch->in_room, ch, sn, ch->gspell->victim );
}
break;
}
end_gspell( ch );
return;
}
int gslot_lookup( int sn )
{
int count;
for ( count = 0; count < MAX_GSPELL; count++ )
if ( gskill_table[count].slot == sn )
return count;
bug( "Gslot_lookup: sn not found #%d", sn );
return 0;
}
void add_gspell( CHAR_DATA *ch, int sn, int level, void *vo )
{
CHAR_DATA *gch;
GSPELL_DATA gsp;
for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
{
if ( gch == ch || !gch->gspell || gch->gspell->timer <= 0 )
continue;
if ( is_same_group( ch, gch ) && gch->gspell->sn == sn )
{
switch ( skill_table[sn].target )
{
case TAR_GROUP_DEFENSIVE:
case TAR_GROUP_OFFENSIVE:
case TAR_GROUP_OBJ:
case TAR_GROUP_IGNORE:
if ( gch->gspell->victim != vo )
continue;
break;
}
break;
}
}
sn = skill_table[sn].slot;
gsp.sn = sn;
gsp.victim = vo;
gsp.level = level;
if ( !gch || !gch->gspell )
gsp.timer = gskill_table[gslot_lookup(sn)].wait;
else
gsp.timer = gch->gspell->timer;
set_gspell( ch, &gsp );
check_gcast( ch );
return;
}
void group_cast( int sn, int level, CHAR_DATA *ch, char *argument )
{
CHAR_DATA *victim = NULL;
OBJ_DATA *obj = NULL;
int mana;
if ( IS_NPC(ch) )
return;
if ( ch->gspell && ch->gspell->timer > 0 )
{
send_to_char(AT_BLUE,"You already have a group spell in progress.\n\r",ch);
return;
}
mana = SPELL_COST(ch,sn);
if ( number_percent( ) > ch->pcdata->learned[sn] )
{
send_to_char(AT_BLUE, "You lost your concentration.\n\r",ch);
MT( ch ) -= mana / 2;
return;
}
MT( ch ) -= mana;
update_skpell( ch, sn );
switch ( skill_table[sn].target )
{
default:
bug( "group_cast: non-group target on sn #%d.", sn );
return;
case TAR_GROUP_DEFENSIVE:
if ( argument[0] == '\0' )
{
victim = ch;
break;
}
if ( !( victim = get_char_room( ch, argument ) ) )
{
send_to_char( AT_BLUE, "They aren't here.\n\r", ch );
return;
}
add_gspell( ch, sn, level, (void *) victim );
break;
case TAR_GROUP_OFFENSIVE:
if ( argument[0] == '\0' )
{
if ( ch->fighting )
victim = ch->fighting;
else
{
send_to_char(AT_BLUE, "Cast the spell on whom?\n\r",ch);
return;
}
}
else
{
if ( !( victim = get_char_room( ch, argument ) ) )
{
send_to_char( AT_BLUE, "They aren't here.\n\r", ch );
return;
}
}
add_gspell( ch, sn, level, (void *) victim );
break;
case TAR_GROUP_ALL:
add_gspell( ch, sn, level, NULL );
break;
case TAR_GROUP_OBJ:
if ( !( obj = get_obj_list( ch, argument, ch->in_room->contents ) ) )
{
send_to_char( AT_WHITE, "You don't see that.\n\r", ch );
return;
}
add_gspell( ch, sn, level, (void *) obj );
break;
case TAR_IGNORE:
add_gspell( ch, sn, level, (void *) argument );
break;
}
return;
}
void gspell_flamesphere( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
dam = dice(20, level);
if ( saves_spell( level, victim ) )
dam /= 2;
damage( ch, victim, dam, sn );
return;
}
void gspell_mass_shield( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *vch;
for ( vch = ch->in_room->people; vch; vch = vch->next_in_room )
{
if ( !is_same_group( ch, vch ) )
continue;
switch ( number_range( 1, 6 ) )
{
case 1:
spell_fireshield( skill_lookup( "fireshield" ), level, vch, vch );
break;
case 2:
spell_shockshield( skill_lookup( "shockshield" ), level, vch, vch );
break;
case 3:
spell_iceshield( skill_lookup( "iceshield" ), level, vch, vch );
break;
case 4:
spell_chaosfield( skill_lookup( "chaos field" ), level, vch, vch );
break;
case 5:
spell_vibrate( skill_lookup( "vibrate" ), level, vch, vch );
break;
case 6:
spell_sanctuary( skill_lookup( "sanctuary" ), level, vch, vch );
break;
}
}
return;
}