/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David * * Love, Guilherme 'Willie' Arnold, and Mitchell Tse. * * * * In order to use any part of this Envy Diku Mud, you must comply with * * the original Diku license in 'license.doc', the Merc license in * * 'license.txt', as well as the Envy license in 'license.nvy'. * * In particular, you may not remove either of these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*$Id: skills.c,v 1.25 2005/03/22 21:17:16 ahsile Exp $*/ #if defined( macintosh ) #include <types.h> #else #include <sys/types.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "merc.h" /* * Local functions */ bool long_range_skill( int sn ); /* * External functions. */ bool is_safe args( ( CHAR_DATA *ch, CHAR_DATA *victim ) ); /* * Local functions. */ void set_fighting args( ( CHAR_DATA *ch, CHAR_DATA *victim ) ); int slot_lookup args( ( int slot ) ); /* * The kludgy global is for spells who want more stuff from command line. */ char *target_name; void do_use( CHAR_DATA *ch, char *argument ) { void *vo; OBJ_DATA *obj; CHAR_DATA *victim; char arg1 [ MAX_INPUT_LENGTH ]; char arg2 [ MAX_INPUT_LENGTH ]; char arg3 [ MAX_INPUT_LENGTH ]; int move; int sn = 0; char buf [ MAX_STRING_LENGTH ]; argument = target_name = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); argument = one_argument( argument, arg3 ); if ( arg1[0] == '\0' ) { send_to_char(AT_BLUE, "Use which what where?\n\r", ch ); return; } if ( !IS_NPC( ch ) ) if ( IS_AFFECTED4( ch, AFF_BURROW ) ) { send_to_char(AT_RED, "You cannot use skills while burrowed!\n\r", ch); return; } if ( IS_NPC( ch ) ) if ( IS_SET( ch->affected_by, AFF_CHARM ) ) return; if ( ( sn = skill_lookup( arg1 ) ) < 0 ) { send_to_char(AT_BLUE, "You can't do that.\n\r", ch ); return; } if ( !IS_NPC( ch ) ) { if ( ( ch->level < skill_table[sn].skill_level[ch->class] && ch->level < skill_table[sn].skill_level[ch->multied] ) ) { send_to_char(AT_BLUE, "You can't do that.\n\r", ch ); return; } } if (skill_table[sn].is_spell) { send_to_char(AT_WHITE, "Using a spell? Try casting...\n\r", ch); return; } if( !IS_NPC( ch ) ) { /* 286 = quickburst */ /* 395 = multiburst */ if (skill_table[sn].spell_fun == spell_null && sn != 286 && sn != 395) { send_to_char(AT_WHITE,"You can't use passive skills.\n\r",ch); sprintf( buf, "Do use: passive use of skill attempted by %s for skill: %s sn: %d ", ch->name, skill_table[sn].name, sn ); bug( buf,0 ); return; } } if ( IS_NPC( ch ) ) if ( ( sn = skill_lookup( arg1 ) ) < 0 ) return; if ( ch->position < skill_table[sn].minimum_position ) { send_to_char(AT_BLUE, "You can't concentrate enough.\n\r", ch ); return; } if ( IS_STUNNED( ch, STUN_MAGIC ) ) { send_to_char(AT_LBLUE, "You're too stunned to use skills.\n\r", ch ); return; } move = 0; if(!IS_NPC( ch ) && ch->level >= skill_table[sn].skill_level[ch->multied] ) { move = MANA_COST_MULTI(ch, sn ); } if(!IS_NPC( ch ) && ch->level >= skill_table[sn].skill_level[ch->class] ) { move = MANA_COST( ch, sn ); } /* * Locate targets. */ victim = NULL; obj = NULL; vo = NULL; switch ( skill_table[sn].target ) { default: bug( "Do_use: bad target for sn %d.", sn ); return; case TAR_IGNORE: break; case TAR_CHAR_OFFENSIVE: if (!ch->in_room) { bug("do_use: ch->in_room is NULL!",0); return; } if ( IS_SET( ch->in_room->room_flags, ROOM_NO_OFFENSIVE ) ) { send_to_char( AT_BLUE, "You failed.\n\r", ch ); return; } if ( arg2[0] == '\0' ) { if ( !( victim = ch->fighting ) ) { send_to_char(AT_BLUE, "Use that skill on whom?\n\r", ch ); return; } } else { if ( !( victim = get_char_room( ch, arg2 ) ) ) { if ( arg3[0] == '\0' || !long_range_skill(sn) || !(victim = get_char_world( ch, arg3 ) ) ) { send_to_char(AT_BLUE, "They aren't here.\n\r", ch ); return; } } } if( !is_pkillable(ch, victim ) ) { return; } if (!IS_NPC(victim)) ch->pkill_timer = 0; if ( IS_AFFECTED(victim, AFF_PEACE) ) { send_to_char(AT_WHITE, "A wave of peace overcomes you.\n\r", ch); return; } if ( IS_AFFECTED2( ch, AFF_SHADOW_PLANE) ) { send_to_char(AT_WHITE, "You must exit the shadow realm.\n\r", ch); return; } if ( IS_AFFECTED2( victim, AFF_SHADOW_PLANE) ) { send_to_char(AT_WHITE, "You can not attack someone who is in the shadow realm.\n\r", ch); return; } if ( IS_AFFECTED4( ch, AFF_BURROW) ) { send_to_char(AT_WHITE, "You must wait for the earth to heal you!\n\r", ch); return; } if ( IS_AFFECTED4( victim, AFF_BURROW) ) { send_to_char(AT_WHITE, "You can not attack someone who is burrowed.\n\r", ch); return; } if ( IS_AFFECTED( ch, AFF_PEACE) ) { affect_strip( ch, skill_lookup("aura of peace") ); REMOVE_BIT( ch->affected_by, AFF_PEACE ); } if (is_safe(ch, victim ) ) { send_to_char( AT_BLUE, "You failed.\n\r",ch); return; } if (!pk_combat_check(ch, victim)) return; vo = (void *) victim; break; case TAR_CHAR_DEFENSIVE: if ( arg2[0] == '\0' ) { victim = ch; } else { if ( !( victim = get_char_room( ch, arg2 ) ) ) { send_to_char(AT_BLUE, "They aren't here.\n\r", ch ); return; } } vo = (void *) victim; if (!pk_combat_check(ch, victim)) return; break; case TAR_CHAR_SELF: if ( arg2[0] != '\0' && !is_name( arg2, ch->name ) ) { send_to_char(AT_BLUE, "You cannot use this skill on another.\n\r", ch ); return; } vo = (void *) ch; break; case TAR_OBJ_INV: if ( arg2[0] == '\0' ) { send_to_char(AT_BLUE, "What should the skill be used upon?\n\r", ch ); return; } if ( !(obj = get_obj_here( ch, arg2 ) ) ) { send_to_char( AT_BLUE, "You can't find that.\n\r", ch ); return; } vo = (void *) obj; break; } if ( !IS_NPC( ch ) ) { if ( ch->move <move ) { send_to_char(AT_BLUE, "You are too tired to do that.\n\r", ch ); return; } } if ( ( IS_SET( ch->in_room->room_flags, ROOM_NO_OFFENSIVE ) ) && ( skill_table[sn].target == TAR_CHAR_OFFENSIVE ) ) { send_to_char( AT_BLUE, "You failed.\n\r", ch ); return; } if( !IS_NPC ( ch ) ) { WAIT_STATE( ch, skill_table[sn].beats ); } if ( !IS_NPC( ch ) ) { if ( number_percent( ) > ( ch->pcdata->learned[sn] / 10 ) ) { send_to_char(AT_BLUE, "You lost your concentration.\n\r", ch ); ch->move -= move / 2; if( ch->pcdata->learned[sn] <= 750 ) update_skpell( ch, sn, 0 ); } else { int dmg = 0; ch->move -= move; if ( ( IS_AFFECTED2( ch, AFF_CONFUSED ) && number_percent( ) < 10 ) ) { act(AT_YELLOW, "$n looks around confused at what's going on.", ch, NULL, NULL, TO_ROOM ); send_to_char( AT_YELLOW, "You become confused and fumble your skill.\n\r", ch ); return; } dmg = (*skill_table[sn].spell_fun) ( sn, URANGE( 1, ch->level, LEVEL_DEMIGOD ), ch, vo ); if (dmg > SKPELL_NO_DAMAGE) { /* Insert level adjustment code here */ if (victim && !victim->deleted && victim->position!=POS_DEAD) damage(ch, victim, dmg, sn); } else if (dmg == SKPELL_BOTCHED || dmg == SKPELL_MISSED) { //send_to_char(C_DEFAULT, skill_table[sn].msg_fail, ch); /* do something */ } if (dmg >= SKPELL_NO_DAMAGE) update_skpell( ch, sn, 0 ); } } if ( IS_NPC( ch ) ) { int dmg = 0; if ( (dmg = (*skill_table[sn].spell_fun) ( sn, URANGE( 1, ch->level, LEVEL_DEMIGOD ), ch, vo )) > SKPELL_NO_DAMAGE ) damage( ch, victim, dmg, sn); } if ( skill_table[sn].target == TAR_CHAR_OFFENSIVE && victim->master != ch && victim != ch && IS_AWAKE( victim ) ) { CHAR_DATA *vch; for ( vch = ch->in_room->people; vch; vch = vch->next_in_room ) { if ( vch->deleted ) continue; if ( victim == vch && !victim->fighting ) { multi_hit( victim, ch, TYPE_UNDEFINED ); break; } } } return; } /* Sort of a clone of spell_null * this will replace old skills in interp.c * * - Ahsile * */ void do_null( CHAR_DATA *ch, char *argument ) { send_to_char(C_DEFAULT, "You meant to USE that skill? Right?\n\r", ch); } void do_null_dis( CHAR_DATA* ch, char* argument ) { do_null( ch, argument); } void do_skills ( CHAR_DATA *ch, char *argument ) { char buf [ MAX_STRING_LENGTH ]; int sn; int col; int mana; if ( IS_NPC( ch ) ) { send_to_char ( AT_BLUE, "You do not know how to do that!\n\r", ch ); return; } col = 0; mana = 0; for ( sn = 0; skill_table[sn].name[0] != '\0'; sn++ ) { if ( !skill_table[sn].name ) break; if ( ch->level < skill_table[sn].skill_level[ch->class] && ch->level < skill_table[sn].skill_level[ch->multied] ) continue; if ( skill_table[sn].is_spell ) continue; if ( ch->level >= skill_table[sn].skill_level[ch->class ] ) { mana = MANA_COST( ch, sn ); } if ( ch->level >= skill_table[sn].skill_level[ch->multied ] ) { mana = MANA_COST_MULTI( ch, sn ); } sprintf ( buf, "%26s %3dpts ", skill_table[sn].name, mana ); send_to_char( AT_BLUE, buf, ch ); if ( ++col % 2 == 0 ) send_to_char( AT_BLUE, "\n\r", ch ); } if ( col % 2 != 0 ) send_to_char( AT_BLUE, "\n\r", ch ); return; } bool long_range_skill( int sn ) { if (sn == skill_lookup("lightning arrow")) return TRUE; return FALSE; }