/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// *
* -----------------------------------------------------------| (0...0) *
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( *
* -----------------------------------------------------------| {o o} *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~*
* Tricops and Fireblade | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* ------------------------------------------------------------------------ *
* Player skills module *
****************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"
/* from makeobjs.c */
extern OBJ_DATA *make_ore( int number );
/* from handler.c */
extern char *munch_colors(char *word);
/* from talent.c */
void player_echo( CHAR_DATA *ch, sh_int AT_COLOR, char *argument, sh_int tar );
char * const spell_flag[] =
{ "water", "earth", "air", "astral", "area", "distant", "reverse",
"noself", "ground", "accumulative", "recastable", "noscribe",
"nobrew", "group", "object", "character", "secretskill", "pksensitive",
"stoponfail", "nofight", "nodispel", "instant", "r2", "r3", "r4", "r5",
"r6",
"r7", "r8", "r9", "r10", "r11"
};
char * const spell_damage[] =
{ "none", "fire", "cold", "electricity", "energy", "acid", "poison", "drain" };
char * const spell_action[] =
{ "none", "create", "destroy", "resist", "suscept", "divinate", "obscure",
"change" };
char * const spell_power[] =
{ "none", "minor", "greater", "major" };
char * const spell_class[] =
{ "none", "lunar", "solar", "travel", "summon", "life", "death", "illusion" };
char * const target_type[] =
{ "ignore", "offensive", "defensive", "self", "objinv" };
void show_char_to_char( CHAR_DATA *list, CHAR_DATA *ch );
void show_list_to_char( OBJ_DATA *list, CHAR_DATA *ch, bool fShort,
bool fShowN );
int ris_save( CHAR_DATA *ch, int chance, int ris );
bool check_illegal_psteal( CHAR_DATA *ch, CHAR_DATA *victim );
char *scramble( const char *argument, int modifier );
/* from magic.c */
void failed_casting( struct skill_type *skill, CHAR_DATA *ch,
CHAR_DATA *victim, OBJ_DATA *obj );
/*
* Dummy function
*/
void skill_notfound( CHAR_DATA *ch, char *argument )
{
huh(ch);
return;
}
int get_starget( char *name )
{
int x;
for ( x = 0; x < sizeof(target_type) / sizeof(target_type[0]); x++ )
if ( !str_cmp( name, target_type[x] ) )
return x;
return -1;
}
int get_sflag( char *name )
{
int x;
for ( x = 0; x < sizeof(spell_flag) / sizeof(spell_flag[0]); x++ )
if ( !str_cmp( name, spell_flag[x] ) )
return x;
return -1;
}
int get_sdamage( char *name )
{
int x;
for ( x = 0; x < sizeof(spell_damage) / sizeof(spell_damage[0]); x++ )
if ( !str_cmp( name, spell_damage[x] ) )
return x;
return -1;
}
int get_saction( char *name )
{
int x;
for ( x = 0; x < sizeof(spell_action) / sizeof(spell_action[0]); x++ )
if ( !str_cmp( name, spell_action[x] ) )
return x;
return -1;
}
int get_spower( char *name )
{
int x;
for ( x = 0; x < sizeof(spell_power) / sizeof(spell_power[0]); x++ )
if ( !str_cmp( name, spell_power[x] ) )
return x;
return -1;
}
int get_sclass( char *name )
{
int x;
for ( x = 0; x < sizeof(spell_class) / sizeof(spell_class[0]); x++ )
if ( !str_cmp( name, spell_class[x] ) )
return x;
return -1;
}
bool is_legal_kill(CHAR_DATA *ch, CHAR_DATA *vch)
{
if ( IS_NPC(ch) || IS_NPC(vch) )
return TRUE;
if ( !IS_PKILL(ch) || !IS_PKILL(vch) )
return FALSE;
return TRUE;
}
extern char *target_name; /* from magic.c */
/* Figure out the current maximum the char can get a skill to -- Scion */
int get_adept(CHAR_DATA *ch, int sn) {
int stat1;
int stat2;
switch (skill_table[sn]->stat1) {
case 1:
stat1 = get_curr_str(ch);
break;
case 2:
stat1 = get_curr_int(ch);
break;
case 3:
stat1 = get_curr_wil(ch);
break;
case 4:
stat1 = get_curr_dex(ch);
break;
case 5:
stat1 = get_curr_con(ch);
break;
case 6:
stat1 = get_curr_per(ch);
break;
case 7:
stat1 = get_curr_lck(ch);
break;
default:
stat1 = 0;
break;
}
switch (skill_table[sn]->stat2) {
case 1:
stat2 = get_curr_str(ch);
break;
case 2:
stat2 = get_curr_int(ch);
break;
case 3:
stat2 = get_curr_wil(ch);
break;
case 4:
stat2 = get_curr_dex(ch);
break;
case 5:
stat2 = get_curr_con(ch);
break;
case 6:
stat2 = get_curr_per(ch);
break;
case 7:
stat2 = get_curr_lck(ch);
break;
default:
stat2 = stat1;
break;
}
/* Average the two stats for the skill cap */
return UMIN(((stat1 + stat2)/2) *3, 95);
}
/*
* Perform a binary search on a section of the skill table
* Each different section of the skill table is sorted alphabetically
* Only match skills player knows -Thoric
*/
bool check_skill( CHAR_DATA *ch, char *command, char *argument )
{
int sn;
int first = gsn_first_skill;
int top = gsn_top_sn-1;
int mana;
struct timeval time_used;
/* bsearch for the skill */
for (;;)
{
sn = (first + top) >> 1;
if (sn < 0)
return FALSE;
if ( LOWER(command[0]) == LOWER(skill_table[sn]->name[0])
&& !str_prefix(command, skill_table[sn]->name)
&& (skill_table[sn]->skill_fun || skill_table[sn]->spell_fun != spell_null)
&& ( can_use_skill(ch, 0, sn ) ) )
break;
if (first >= top)
return FALSE;
if (strcmp( command, skill_table[sn]->name) < 1)
top = sn - 1;
else
first = sn + 1;
}
if ( !check_pos( ch, skill_table[sn]->minimum_position ) )
return TRUE;
if ( IS_NPC(ch)
&& (IS_AFFECTED( ch, AFF_CHARM ) || IS_AFFECTED( ch, AFF_POSSESS )) )
{
send_to_char( "For some reason, you seem unable to perform that...\n\r", ch );
act( AT_GREY,"$n wanders around aimlessly.", ch, NULL, NULL, TO_ROOM );
return TRUE;
}
/* check if mana is required */
if ( skill_table[sn]->min_mana )
{
mana = IS_NPC(ch) ? 0 : UMAX(skill_table[sn]->min_mana,
100 / ( 100 - skill_table[sn]->skill_level[get_best_talent(ch, sn)] ) );
if ( !IS_NPC(ch) && ch->mana < mana )
{
send_to_char( "You don't have enough mana.\n\r", ch );
return TRUE;
}
}
else
{
mana = 0;
}
/*
* Is this a real do-fun, or a really a spell?
*/
if ( !skill_table[sn]->skill_fun )
{
ch_ret retcode = rNONE;
void *vo = NULL;
CHAR_DATA *victim = NULL;
OBJ_DATA *obj = NULL;
target_name = "";
switch ( skill_table[sn]->target )
{
default:
bug( "Check_skill: bad target for sn %d.", sn );
send_to_char( "Something went wrong...\n\r", ch );
return TRUE;
case TAR_IGNORE:
vo = NULL;
if ( argument[0] == '\0' )
{
if ( (victim=ch->last_hit) != NULL )
target_name = victim->name;
}
else
target_name = argument;
break;
case TAR_CHAR_OFFENSIVE:
if ( argument[0] == '\0'
&& (victim=ch->last_hit) == NULL )
{
ch_printf( ch, "Confusion overcomes you as your '%s' has no target.\n\r", skill_table[sn]->name );
return TRUE;
}
else
if ( argument[0] != '\0'
&& (victim=get_char_room(ch, argument)) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return TRUE;
}
if (!IS_SAME_PLANE(ch, victim))
{
ch_printf(ch, "Your %s passes right through them!\n\r", skill_table[sn]->name);
return TRUE;
}
if ( ch == victim && SPELL_FLAG(skill_table[sn], SF_NOSELF))
{
send_to_char( "You can't target yourself!\n\r", ch);
return TRUE;
}
if ( !IS_NPC(ch) )
{
if ( !IS_NPC(victim) ) {
if ( get_timer( ch, TIMER_PKILLED ) > 0 )
{
send_to_char( "You have been killed in the last 5 minutes.\n\r", ch);
return TRUE;
}
if ( get_timer( victim, TIMER_PKILLED ) > 0 )
{
send_to_char( "This player has been killed in the last 5 minutes.\n\r", ch );
return TRUE;
}
}
if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
{
send_to_char( "You can't do that on your own follower.\n\r", ch );
return TRUE;
}
}
vo = (void *) victim;
break;
case TAR_CHAR_DEFENSIVE:
if ( argument[0] != '\0'
&& (victim=get_char_room(ch, argument)) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return TRUE;
}
if ( !victim )
victim = ch;
if (!IS_SAME_PLANE(ch, victim))
{
ch_printf(ch, "Your %s passes right through them!\n\r", skill_table[sn]->name);
return TRUE;
}
if ( ch == victim && SPELL_FLAG(skill_table[sn], SF_NOSELF))
{
send_to_char( "You can't target yourself!\n\r", ch);
return TRUE;
}
vo = (void *) victim;
break;
case TAR_CHAR_SELF:
vo = (void *) ch;
break;
case TAR_OBJ_INV:
if ( (obj=get_obj_carry(ch, argument)) == NULL )
{
send_to_char( "You can't find that.\n\r", ch );
return TRUE;
}
vo = (void *) obj;
break;
}
/* waitstate */
WAIT_STATE( ch, skill_table[sn]->beats );
/* check for failure */
if ( (number_percent( ) + skill_table[sn]->difficulty * 5)
> (IS_NPC(ch) ? 75 : LEARNED(ch, sn)) )
{
failed_casting( skill_table[sn], ch, vo, obj );
learn_from_failure( ch, sn );
if ( mana )
{
ch->mana -= mana/2;
ch->in_room->area->weather->mana += (int)mana/10;
}
return TRUE;
}
if ( mana )
{
ch->mana -= mana;
ch->in_room->area->weather->mana += (int)mana/10;
}
start_timer(&time_used);
retcode = (*skill_table[sn]->spell_fun) (sn,get_curr_wil(ch), ch, vo );
end_timer(&time_used);
update_userec(&time_used, &skill_table[sn]->userec);
if ( retcode == rCHAR_DIED || retcode == rERROR )
return TRUE;
if ( char_died(ch) )
return TRUE;
if ( retcode == rSPELL_FAILED )
{
learn_from_failure( ch, sn );
retcode = rNONE;
}
else {
learn_from_success( ch, sn );
}
return TRUE;
}
if ( mana )
{
ch->mana -= mana;
ch->in_room->area->weather->mana += (int)mana/10;
}
/* waitstate */
WAIT_STATE( ch, skill_table[sn]->beats );
ch->prev_cmd = ch->last_cmd; /* haus, for automapping */
ch->last_cmd = skill_table[sn]->skill_fun;
start_timer(&time_used);
(*skill_table[sn]->skill_fun) ( ch, argument );
end_timer(&time_used);
update_userec(&time_used, &skill_table[sn]->userec);
tail_chain( );
return TRUE;
}
void do_skin( CHAR_DATA *ch, char *argument) {
OBJ_DATA *corpse;
OBJ_DATA *obj;
OBJ_DATA *skin;
bool found;
char *name;
char buf[MAX_STRING_LENGTH];
found = FALSE;
if ( argument[0] == '\0' )
{
send_to_char( "Whose corpse do you wish to decapitate?\n\r", ch );
return;
}
if ( (corpse=get_obj_here(ch, argument)) == NULL )
{
send_to_char( "You cannot find that here.\n\r", ch );
return;
}
if ( (obj=get_eq_char(ch, WEAR_HAND)) == NULL
&& !can_use_bodypart(ch, BP_CLAWS) )
{
send_to_char( "You have no weapon with which to perform this deed.\n\r", ch );
return;
}
if ( corpse->item_type != ITEM_CORPSE_PC )
{
send_to_char( "You can only decapitate the bodies of player characters.\n\r", ch);
return;
}
if ( obj && obj->value[3] != 1 &&
obj->value[3] != 2 &&
obj->value[3] != 3 &&
obj->value[3] != 11 )
{
send_to_char( "There is nothing you can do with this corpse.\n\r", ch );
return;
}
if ( corpse->value[5] == 1 ) {
send_to_char( "That corpse seems to have been skinned already.\r\n", ch );
return;
}
if ( get_obj_index( OBJ_VNUM_SKIN ) == NULL )
{
bug( "Vnum 23 (OBJ_VNUM_SKIN) not found for do_skin!", 0);
return;
}
skin = create_object( get_obj_index(OBJ_VNUM_SKIN), 0 );
name = corpse->short_descr;
sprintf( buf, skin->short_descr, name );
STRFREE( skin->short_descr );
skin->short_descr = STRALLOC( buf );
sprintf( buf, skin->description, name );
STRFREE( skin->description );
skin->description = STRALLOC( buf );
act( AT_BLOOD, "$n decapitates $p.", ch, corpse, NULL, TO_ROOM);
act( AT_BLOOD, "You decapitate $p.", ch, corpse, NULL, TO_CHAR);
corpse->value[5]=1;
obj_to_char( skin, ch );
return;
}
/*
* Lookup a skills information
* High god command
*/
void do_slookup( CHAR_DATA *ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
int sn;
int iRace;
SKILLTYPE *skill = NULL;
one_argument( argument, arg );
if ( arg[0] == '\0' )
{
send_to_char( "Slookup what?\n\r", ch );
return;
}
if ( !str_cmp( arg, "all" ) )
{
for ( sn = 0; sn < top_sn && skill_table[sn] && skill_table[sn]->name; sn++ )
pager_printf( ch, "Sn: %4d Slot: %4d Skill/spell: '%-20s' Damtype: %s\n\r",
sn, skill_table[sn]->slot, skill_table[sn]->name,
spell_damage[SPELL_DAMAGE( skill_table[sn] )] );
}
else
if ( !str_cmp( arg, "nostat" ) ) {
for (sn = 0; sn < top_sn && skill_table[sn] && skill_table[sn]->name; sn++ )
if (skill_table[sn]->stat1==0)
pager_printf( ch, "Sn: %4d Slot: %4d Skill/spell: '%-20s'\r\n",
sn, skill_table[sn]->slot, skill_table[sn]->name);
}
else
if ( !str_cmp( arg, "herbs" ) )
{
for ( sn = 0; sn < top_herb && herb_table[sn] && herb_table[sn]->name; sn++ )
pager_printf( ch, "%d) %s\n\r", sn, herb_table[sn]->name );
}
else
{
SMAUG_AFF *aff;
int cnt = 0;
if ( arg[0] == 'h' && is_number(arg+1) )
{
sn = atoi(arg+1);
if ( !IS_VALID_HERB(sn) )
{
send_to_char( "Invalid herb.\n\r", ch );
return;
}
skill = herb_table[sn];
}
else
if ( is_number(arg) )
{
sn = atoi(arg);
if ( (skill=get_skilltype(sn)) == NULL )
{
send_to_char( "Invalid sn.\n\r", ch );
return;
}
sn %= 1000;
}
else
if ( ( sn = skill_lookup( arg ) ) >= 0 )
skill = skill_table[sn];
else
if ( ( sn = herb_lookup( arg ) ) >= 0 )
skill = herb_table[sn];
else
{
send_to_char( "No such skill, spell, proficiency or tongue.\n\r", ch );
return;
}
if ( !skill )
{
send_to_char( "Not created yet.\n\r", ch );
return;
}
ch_printf( ch, "Sn: %4d Slot: %4d %s: '%-20s'\n\r",
sn, skill->slot, skill_tname[skill->type], skill->name );
if ( skill->info )
ch_printf( ch, "DamType: %s ActType: %s ClassType: %s PowerType: %s\n\r",
spell_damage[SPELL_DAMAGE(skill)],
spell_action[SPELL_ACTION(skill)],
spell_class[SPELL_CLASS(skill)],
spell_power[SPELL_POWER(skill)] );
if ( skill->flags )
{
int x;
strcpy( buf, "Flags:" );
for ( x = 0; x < 32; x++ )
if ( SPELL_FLAG( skill, 1 << x ) )
{
strcat( buf, " " );
strcat( buf, spell_flag[x] );
}
strcat( buf, "\n\r" );
send_to_char( buf, ch );
}
if ( skill->difficulty != '\0' )
ch_printf( ch, "Difficulty: %d\n\r", (int) skill->difficulty );
ch_printf( ch, "Type: %s Target: %s Minpos: %d Mana: %d Beats: %d Range: %d\n\r",
skill_tname[skill->type],
target_type[URANGE(TAR_IGNORE, skill->target, TAR_OBJ_INV)],
skill->minimum_position,
skill->min_mana, skill->beats, skill->range );
ch_printf( ch, "Flags: %d Club: %d Value: %d Info: %d Code: %s\n\r",
skill->flags,
skill->guild,
skill->value,
skill->info,
skill->skill_fun ? skill_name(skill->skill_fun)
: spell_name(skill->spell_fun));
ch_printf( ch, "Dammsg: %s\n\rWearoff: %s\n",
skill->noun_damage,
skill->msg_off ? skill->msg_off : "(none set)" );
if ( skill->dice && skill->dice[0] != '\0' )
ch_printf( ch, "Dice: %s\n\r", skill->dice );
if ( skill->teachers && skill->teachers[0] != '\0' )
ch_printf( ch, "Teachers: %s\n\r", skill->teachers );
if ( skill->components && skill->components[0] != '\0' )
ch_printf( ch, "Components: %s\n\r", skill->components );
if ( skill->participants )
ch_printf( ch, "Participants: %d\n\r", (int) skill->participants );
if ( skill->userec.num_uses )
send_timer(&skill->userec, ch);
for ( aff = skill->affects; aff; aff = aff->next )
{
if ( aff == skill->affects )
send_to_char( "\n\r", ch );
sprintf( buf, "Affect %d", ++cnt );
if ( aff->location )
{
strcat( buf, " modifies " );
strcat( buf, a_types[aff->location % REVERSE_APPLY] );
strcat( buf, " by '" );
strcat( buf, aff->modifier );
if ( aff->bitvector != -1 )
strcat( buf, "' and" );
else
strcat( buf, "'" );
}
if ( aff->bitvector != -1 )
{
strcat( buf, " applies " );
strcat( buf, a_flags[aff->bitvector] );
}
if ( aff->duration[0] != '\0' && aff->duration[0] != '0' )
{
strcat( buf, " for '" );
strcat( buf, aff->duration );
strcat( buf, "' rounds" );
}
if ( aff->location >= REVERSE_APPLY )
strcat( buf, " (affects caster only)" );
strcat( buf, "\n\r" );
send_to_char( buf, ch );
if ( !aff->next )
send_to_char( "\n\r", ch );
}
if ( skill->hit_char && skill->hit_char[0] != '\0' )
ch_printf( ch, "Hitchar : %s\n\r", skill->hit_char );
if ( skill->hit_vict && skill->hit_vict[0] != '\0' )
ch_printf( ch, "Hitvict : %s\n\r", skill->hit_vict );
if ( skill->hit_room && skill->hit_room[0] != '\0' )
ch_printf( ch, "Hitroom : %s\n\r", skill->hit_room );
if ( skill->hit_dest && skill->hit_dest[0] != '\0' )
ch_printf( ch, "Hitdest : %s\n\r", skill->hit_dest );
if ( skill->miss_char && skill->miss_char[0] != '\0' )
ch_printf( ch, "Misschar : %s\n\r", skill->miss_char );
if ( skill->miss_vict && skill->miss_vict[0] != '\0' )
ch_printf( ch, "Missvict : %s\n\r", skill->miss_vict );
if ( skill->miss_room && skill->miss_room[0] != '\0' )
ch_printf( ch, "Missroom : %s\n\r", skill->miss_room );
if ( skill->die_char && skill->die_char[0] != '\0' )
ch_printf( ch, "Diechar : %s\n\r", skill->die_char );
if ( skill->die_vict && skill->die_vict[0] != '\0' )
ch_printf( ch, "Dievict : %s\n\r", skill->die_vict );
if ( skill->die_room && skill->die_room[0] != '\0' )
ch_printf( ch, "Dieroom : %s\n\r", skill->die_room );
if ( skill->imm_char && skill->imm_char[0] != '\0' )
ch_printf( ch, "Immchar : %s\n\r", skill->imm_char );
if ( skill->imm_vict && skill->imm_vict[0] != '\0' )
ch_printf( ch, "Immvict : %s\n\r", skill->imm_vict );
if ( skill->imm_room && skill->imm_room[0] != '\0' )
ch_printf( ch, "Immroom : %s\n\r", skill->imm_room );
if ( skill->type != SKILL_HERB )
{
const char *stat_table[] = {
"None",
"Strength",
"Intelligence",
"Willpower",
"Dexterity",
"Constitution",
"Perception",
"Luck"
};
send_to_char( "--------------------------[STAT USE]--------------------------\n\r",ch);
if (skill->stat1 < 8)
ch_printf(ch, "Stat 1: %s\r\n", stat_table[skill->stat1]);
if (skill->stat2 < 8 && skill->stat2 != skill->stat1)
ch_printf(ch, "Stat 2: %s\r\n", stat_table[skill->stat2]);
if (skill->type == SKILL_SPELL) {
DEITY_DATA *talent;
int i=0;
send_to_char( "--------------------------[ TALENT ]--------------------------\n\r",ch);
for ( talent = first_deity; talent; talent = talent->next ) {
sprintf( buf, "(%-3d:%-5s", talent->index, talent->name );
sprintf(buf+9, ") lvl: %3d",
skill->skill_level[talent->index] );
if ( i % 3 == 2 )
strcat(buf, "\n\r" );
else
strcat(buf, " " );
send_to_char( buf, ch );
i++;
}
} else {
send_to_char( "\n\r--------------------------[RACE USE]--------------------------\n\r",ch);
for ( iRace = 0; iRace < MAX_RACE; iRace++ ) {
sprintf(buf, "%-3d): %8.8s",
iRace,
(skill->race_level[iRace] == 1 ? "innate" : (skill->race_level[iRace] == 2 ? "learn" : "no learn")) );
if ( (iRace>0) && (iRace % 3 == 1 ))
strcat(buf, "\n\r" );
else
strcat(buf, " " );
send_to_char( buf, ch );
}
}
}
send_to_char( "\n\r", ch );
}
return;
}
/*
* Set a skill's attributes or what skills a player has.
* High god command, with support for creating skills/spells/herbs/etc
*/
void do_sset( CHAR_DATA *ch, char *argument )
{
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
CHAR_DATA *victim;
int value;
int sn,i;
bool fAll;
argument = one_argument( argument, arg1 );
argument = one_argument( argument, arg2 );
if ( arg1[0] == '\0' || arg2[0] == '\0' || argument[0] == '\0' ) {
send_to_char( "Syntax: sset <victim> <skill> <value>\n\r", ch );
send_to_char( "or: sset <victim> all <value>\n\r", ch );
send_to_char( "or: sset save skill table\n\r", ch );
send_to_char( "or: sset save herb table\n\r", ch );
send_to_char( "or: sset create skill 'new skill'\n\r", ch );
send_to_char( "or: sset create herb 'new herb'\n\r", ch );
send_to_char( "or: sset create ability 'new ability'\n\r",ch );
send_to_char( "or: sset delete <sn> really\r\n", ch);
if (IS_SET(ch->pcdata->permissions, PERMIT_ADMIN))
send_to_char( "or: sset copy <from talent#> <to talent#>\n\r",ch );
send_to_char( "or: sset <sn> <field> <value>\n\r", ch );
send_to_char( "\n\rField being one of:\n\r", ch );
send_to_char( " name code target minpos slot mana beats dammsg wearoff club minlevel\n\r", ch );
send_to_char( " type damtype acttype classtype powertype seffect flag dice value difficulty\n\r", ch );
send_to_char( " affect rmaffect level adept hit miss die imm (char/vict/room)\n\r", ch );
send_to_char( " components teachers racelevel raceadept talent\n\r",ch );
send_to_char( "Affect having the fields: <location> <modfifier> [duration] [bitvector]\n\r", ch );
send_to_char( "(See AFFECTTYPES for location, and AFFECTED_BY for bitvector)\n\r", ch );
send_to_char( "Skill being any skill or spell.\n\r", ch );
return;
}
/* Scion's code! */
if ( IS_SET(ch->pcdata->permissions, PERMIT_ADMIN)
&& !str_cmp( arg1, "copy" ) ) {
char arg3[MAX_INPUT_LENGTH];
int class1, class2, index;
argument = one_argument( argument, arg3 );
if (arg3[0]=='\0' || arg2[0]=='\0') {
send_to_char("Syntax: sset copy <from talent#> <to talent#>\r\n",ch);
return;
}
class1 = atoi( arg2 );
class2 = atoi( arg3 );
if ( class1 >= MAX_DEITY || class1 < 0 ) {
send_to_char("Source class invalid.\r\n",ch);
return;
}
if ( class2 >= MAX_DEITY || class2 < 0 ) {
send_to_char("Destination class invalid.\r\n",ch);
return;
}
for (index=0; index < top_sn; index++)
skill_table[index]->skill_level[class2] =
(skill_table[index]->skill_level[class1]<=100 ?
skill_table[index]->skill_level[class1] : 101);
send_to_char("Skill table copied.\r\n",ch);
save_skill_table();
return;
}
if ( !str_cmp( arg1, "delete" ) ) {
int i=0;
if (str_cmp(argument, "really")) {
send_to_char("You must specify 'really' as the last argument to confirm that you want to delete this skill.\r\n", ch);
return;
}
if (is_number(arg2))
i = atoi(arg2);
else {
send_to_char("Please specify the sn to delete.\r\n", ch);
return;
}
if (i > top_sn || i < 0) {
send_to_char("That is an invalid sn.\r\n", ch);
return;
}
STRFREE(skill_table[i]->name);
skill_table[i]->name = STRALLOC("deleted_skill");
save_skill_table();
send_to_char("Please reboot the MUD as soon as possible to enact the changes to the skill table.\r\n", ch);
return;
}
if (!str_cmp( arg1, "save" )
&& !str_cmp( argument, "table" ) )
{
if ( !str_cmp( arg2, "skill" ) )
{
send_to_char( "Saving skill table...\n\r", ch );
save_skill_table();
return;
}
if ( !str_cmp( arg2, "herb" ) )
{
send_to_char( "Saving herb table...\n\r", ch );
save_herb_table();
return;
}
}
if (!str_cmp( arg1, "create" )
&& (!str_cmp( arg2, "skill" ) || !str_cmp( arg2, "herb" ) || !str_cmp( arg2, "ability" )) )
{
struct skill_type *skill;
sh_int type = SKILL_UNKNOWN;
if ( !str_cmp( arg2, "herb" ) )
{
type = SKILL_HERB;
if ( top_herb >= MAX_HERB )
{
ch_printf( ch, "The current top herb is %d, which is the maximum. "
"To add more herbs,\n\rMAX_HERB will have to be "
"raised in mud.h, and the mud recompiled.\n\r",
top_sn );
return;
}
}
else
if ( top_sn >= MAX_SKILL )
{
ch_printf( ch, "The current top sn is %d, which is the maximum. "
"To add more skills,\n\rMAX_SKILL will have to be "
"raised in mud.h, and the mud recompiled.\n\r",
top_sn );
return;
}
CREATE( skill, struct skill_type, 1 );
skill->slot = 0;
if ( type == SKILL_HERB )
{
int max, x;
herb_table[top_herb++] = skill;
for ( max = x = 0; x < top_herb-1; x++ )
if ( herb_table[x] && herb_table[x]->slot > max )
max = herb_table[x]->slot;
skill->slot = max+1;
}
else
skill_table[top_sn++] = skill;
skill->min_mana = 0;
skill->name = str_dup( argument );
skill->noun_damage = str_dup( "" );
skill->msg_off = str_dup( "" );
skill->spell_fun = spell_smaug;
skill->type = type;
if (!str_cmp( arg2, "ability" ) )
skill->type = SKILL_RACIAL;
for(i=0;i<MAX_RACE;i++)
{
skill->race_level[i]= 3;
}
send_to_char( "Done.\n\r", ch );
return;
}
if ( arg1[0] == 'h' )
sn = atoi( arg1+1 );
else
sn = atoi( arg1 );
if (((arg1[0] == 'h' && is_number(arg1+1) && (sn=atoi(arg1+1))>=0)
|| (is_number(arg1) && (sn=atoi(arg1)) >= 0)) )
{
struct skill_type *skill;
if ( arg1[0] == 'h' )
{
if ( sn >= top_herb )
{
send_to_char( "Herb number out of range.\n\r", ch );
return;
}
skill = herb_table[sn];
}
else
{
if ( (skill=get_skilltype(sn)) == NULL )
{
send_to_char( "Skill number out of range.\n\r", ch );
return;
}
sn %= 1000;
}
if ( !str_cmp( arg2, "difficulty" ) )
{
skill->difficulty = atoi( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "participants" ) )
{
skill->participants = atoi( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "damtype" ) )
{
int x = get_sdamage( argument );
if ( x == -1 )
send_to_char( "Not a spell damage type.\n\r", ch );
else
{
SET_SDAM( skill, x );
send_to_char( "Ok.\n\r", ch );
}
return;
}
if ( !str_cmp( arg2, "acttype" ) )
{
int x = get_saction( argument );
if ( x == -1 )
send_to_char( "Not a spell action type.\n\r", ch );
else
{
SET_SACT( skill, x );
send_to_char( "Ok.\n\r", ch );
}
return;
}
if ( !str_cmp( arg2, "classtype" ) )
{
int x = get_sclass( argument );
if ( x == -1 )
send_to_char( "Not a spell class type.\n\r", ch );
else
{
SET_SCLA( skill, x );
send_to_char( "Ok.\n\r", ch );
}
return;
}
if ( !str_cmp( arg2, "powertype" ) )
{
int x = get_spower( argument );
if ( x == -1 )
send_to_char( "Not a spell power type.\n\r", ch );
else
{
SET_SPOW( skill, x );
send_to_char( "Ok.\n\r", ch );
}
return;
}
if ( !str_cmp( arg2, "flag" ) )
{
int x = get_sflag( argument );
if ( x == -1 )
send_to_char( "Not a spell flag.\n\r", ch );
else
{
TOGGLE_BIT( skill->flags, 1 << x );
send_to_char( "Ok.\n\r", ch );
}
return;
}
if ( !str_cmp( arg2, "code" ) )
{
SPELL_FUN *spellfun;
DO_FUN *dofun;
if ( (spellfun=spell_function(argument)) != spell_notfound )
{
skill->spell_fun = spellfun;
skill->skill_fun = NULL;
}
else
if ( (dofun=skill_function(argument)) != skill_notfound )
{
skill->skill_fun = dofun;
skill->spell_fun = NULL;
}
else
{
send_to_char( "Not a spell or skill.\n\r", ch );
return;
}
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "target" ) )
{
int x = get_starget( argument );
if ( x == -1 )
send_to_char( "Not a valid target type.\n\r", ch );
else
{
skill->target = x;
send_to_char( "Ok.\n\r", ch );
}
return;
}
if ( !str_cmp( arg2, "minpos" ) )
{
skill->minimum_position = URANGE( POS_DEAD, atoi( argument ), POS_DRAG );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "minlevel" ) )
{
skill->min_level = atoi( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "slot" ) )
{
skill->slot = URANGE( 0, atoi( argument ), 30000 );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "mana" ) )
{
skill->min_mana = URANGE( 0, atoi( argument ), 2000 );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "beats" ) )
{
skill->beats = URANGE( 0, atoi( argument ), 120 );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "range" ) )
{
skill->range = URANGE( 0, atoi( argument ), 20 );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "club" ) )
{
skill->guild = atoi( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "value" ) )
{
skill->value = atoi( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "type" ) )
{
skill->type = get_skill( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "rmaffect" ) )
{
SMAUG_AFF *aff = skill->affects;
SMAUG_AFF *aff_next;
int num = atoi( argument );
int cnt = 1;
if ( !aff )
{
send_to_char( "This spell has no special affects to remove.\n\r", ch );
return;
}
if ( num == 1 )
{
skill->affects = aff->next;
DISPOSE( aff->duration );
DISPOSE( aff->modifier );
DISPOSE( aff );
send_to_char( "Removed.\n\r", ch );
return;
}
for ( ; aff; aff = aff->next )
{
if ( ++cnt == num && (aff_next=aff->next) != NULL )
{
aff->next = aff_next->next;
DISPOSE( aff_next->duration );
DISPOSE( aff_next->modifier );
DISPOSE( aff_next );
send_to_char( "Removed.\n\r", ch );
return;
}
}
send_to_char( "Not found.\n\r", ch );
return;
}
/*
* affect <location> <modifier> <duration> <bitvector>
*/
if ( !str_cmp( arg2, "affect" ) )
{
char location[MAX_INPUT_LENGTH];
char modifier[MAX_INPUT_LENGTH];
char duration[MAX_INPUT_LENGTH];
/* char bitvector[MAX_INPUT_LENGTH]; */
int loc, bit, tmpbit;
SMAUG_AFF *aff;
argument = one_argument( argument, location );
argument = one_argument( argument, modifier );
argument = one_argument( argument, duration );
if ( location[0] == '!' )
loc = get_atype( location+1 ) + REVERSE_APPLY;
else
loc = get_atype( location );
if ( (loc % REVERSE_APPLY) < 0
|| (loc % REVERSE_APPLY) >= MAX_APPLY_TYPE )
{
send_to_char( "Unknown affect location. See AFFECTTYPES.\n\r", ch );
return;
}
bit = -1;
if ( argument[0] != 0 )
{
if ( (tmpbit=get_aflag(argument)) == -1 )
ch_printf( ch, "Unknown bitvector: %s. See AFFECTED_BY\n\r", argument );
else
bit = tmpbit;
}
CREATE( aff, SMAUG_AFF, 1 );
if ( !str_cmp( duration, "0" ) )
duration[0] = '\0';
if ( !str_cmp( modifier, "0" ) )
modifier[0] = '\0';
aff->duration = str_dup( duration );
aff->location = loc;
aff->modifier = str_dup( modifier );
aff->bitvector = bit;
aff->next = skill->affects;
skill->affects = aff;
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "level" ) )
{
char arg3[MAX_INPUT_LENGTH];
int num;
argument = one_argument( argument, arg3 );
num = atoi( arg3 );
if (skill->type == SKILL_SPELL) {
if ( !get_talent_by_index( num ) )
send_to_char( "Not a valid talent.\n\r", ch );
else
skill->skill_level[num] = atoi(argument);
} else {
if (num >= MAX_RACE || num < -1)
send_to_char( "Not a valid race.\n\r", ch );
else if (num == -1) {
for (num = 0; num < MAX_RACE; num++)
skill->race_level[num] = atoi(argument);
} else
skill->race_level[num] = atoi(argument);
}
return;
}
if ( !str_cmp( arg2, "stat1" ) ) {
char arg3[MAX_INPUT_LENGTH];
int stat;
argument = one_argument( argument, arg3 );
if (!str_prefix(arg3, "strength"))
stat = 1;
else if (!str_prefix(arg3, "intelligence"))
stat = 2;
else if (!str_prefix(arg3, "willpower"))
stat = 3;
else if (!str_prefix(arg3, "dexterity"))
stat = 4;
else if (!str_prefix(arg3, "constitution"))
stat = 5;
else if (!str_prefix(arg3, "perception"))
stat = 6;
else if (!str_prefix(arg3, "luck"))
stat = 7;
else
stat = 0;
skill->stat1 = stat;
return;
}
if ( !str_cmp( arg2, "stat2" ) ) {
char arg3[MAX_INPUT_LENGTH];
int stat;
argument = one_argument( argument, arg3 );
if (!str_prefix(arg3, "strength"))
stat = 1;
else if (!str_prefix(arg3, "intelligence"))
stat = 2;
else if (!str_prefix(arg3, "willpower"))
stat = 3;
else if (!str_prefix(arg3, "dexterity"))
stat = 4;
else if (!str_prefix(arg3, "constitution"))
stat = 5;
else if (!str_prefix(arg3, "perception"))
stat = 6;
else if (!str_prefix(arg3, "luck"))
stat = 7;
else
stat = 0;
skill->stat2 = stat;
return;
}
if ( !str_cmp( arg2, "name" ) )
{
DISPOSE(skill->name);
skill->name = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "dammsg" ) )
{
DISPOSE(skill->noun_damage);
if ( !str_cmp( argument, "clear" ) )
skill->noun_damage = str_dup( "" );
else
skill->noun_damage = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "wearoff" ) )
{
DISPOSE(skill->msg_off);
if ( str_cmp( argument, "clear" ) )
skill->msg_off = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "hitchar" ) )
{
if ( skill->hit_char )
DISPOSE(skill->hit_char);
if ( str_cmp( argument, "clear" ) )
skill->hit_char = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "hitvict" ) )
{
if ( skill->hit_vict )
DISPOSE(skill->hit_vict);
if ( str_cmp( argument, "clear" ) )
skill->hit_vict = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "hitroom" ) )
{
if ( skill->hit_room )
DISPOSE(skill->hit_room);
if ( str_cmp( argument, "clear" ) )
skill->hit_room = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "hitdest" ) )
{
if ( skill->hit_dest )
DISPOSE(skill->hit_dest);
if ( str_cmp( argument, "clear" ) )
skill->hit_dest = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "misschar" ) )
{
if ( skill->miss_char )
DISPOSE(skill->miss_char);
if ( str_cmp( argument, "clear" ) )
skill->miss_char = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "missvict" ) )
{
if ( skill->miss_vict )
DISPOSE(skill->miss_vict);
if ( str_cmp( argument, "clear" ) )
skill->miss_vict = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "missroom" ) )
{
if ( skill->miss_room )
DISPOSE(skill->miss_room);
if ( str_cmp( argument, "clear" ) )
skill->miss_room = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "diechar" ) )
{
if ( skill->die_char )
DISPOSE(skill->die_char);
if ( str_cmp( argument, "clear" ) )
skill->die_char = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "dievict" ) )
{
if ( skill->die_vict )
DISPOSE(skill->die_vict);
if ( str_cmp( argument, "clear" ) )
skill->die_vict = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "dieroom" ) )
{
if ( skill->die_room )
DISPOSE(skill->die_room);
if ( str_cmp( argument, "clear" ) )
skill->die_room = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "immchar" ) )
{
if ( skill->imm_char )
DISPOSE(skill->imm_char);
if ( str_cmp( argument, "clear" ) )
skill->imm_char = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "immvict" ) )
{
if ( skill->imm_vict )
DISPOSE(skill->imm_vict);
if ( str_cmp( argument, "clear" ) )
skill->imm_vict = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "immroom" ) )
{
if ( skill->imm_room )
DISPOSE(skill->imm_room);
if ( str_cmp( argument, "clear" ) )
skill->imm_room = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "dice" ) )
{
if ( skill->dice )
DISPOSE(skill->dice);
if ( str_cmp( argument, "clear" ) )
skill->dice = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "components" ) )
{
if ( skill->components )
DISPOSE(skill->components);
if ( str_cmp( argument, "clear" ) )
skill->components = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
if ( !str_cmp( arg2, "teachers" ) )
{
if ( skill->teachers )
DISPOSE(skill->teachers);
if ( str_cmp( argument, "clear" ) )
skill->teachers = str_dup( argument );
send_to_char( "Ok.\n\r", ch );
return;
}
do_sset( ch, "" );
return;
}
if ( ( victim = get_char_world( ch, arg1 ) ) == NULL )
{
if ( (sn = skill_lookup(arg1)) >= 0 )
{
sprintf(arg1, "%d %s %s", sn, arg2, argument);
do_sset(ch, arg1);
}
else
send_to_char( "They aren't here.\n\r", ch );
return;
}
if ( IS_NPC(victim) )
{
send_to_char( "Not on NPC's.\n\r", ch );
return;
}
fAll = !str_cmp( arg2, "all" );
sn = 0;
if ( !fAll && ( sn = skill_lookup( arg2 ) ) < 0 )
{
send_to_char( "No such skill or spell.\n\r", ch );
return;
}
/*
* Snarf the value.
*/
if ( !is_number( argument ) )
{
send_to_char( "Value must be numeric.\n\r", ch );
return;
}
value = atoi( argument );
if ( value < 0 || value > 100 )
{
send_to_char( "Value range is 0 to 100.\n\r", ch );
return;
}
if ( fAll )
{
for ( sn = 0; sn < top_sn; sn++ )
{
/* Fix by Narn to prevent ssetting skills the player shouldn't have. */
if ( skill_table[sn]->name
&& ( skill_available(victim, sn) == TRUE
|| value == 0 ) )
{
victim->pcdata->learned[sn] = value;
}
}
}
else
victim->pcdata->learned[sn] = value;
return;
}
void learn_from_success( CHAR_DATA *ch, int sn )
{
int gain, learn, percent, chance, i;
if ( IS_NPC(ch) || LEARNED(ch, sn) <= 0 )
return;
i = get_best_talent(ch, sn);
if (i > -1 && skill_table[sn]->type == SKILL_SPELL)
learn_talent(ch, i);
if ( LEARNED(ch, sn) < GET_ADEPT(ch, sn) ) {
chance = LEARNED(ch, sn) + (5 * skill_table[sn]->difficulty);
percent = number_percent();
if ( percent >= chance )
learn = 2;
else
if ( chance - percent > 25 )
return;
else
learn = 1;
ch->pcdata->learned[sn] = UMIN( GET_ADEPT(ch, sn), LEARNED(ch, sn) + learn );
if ( LEARNED(ch, sn) == GET_ADEPT(ch, sn) ) /* fully learned already, no xp! */
return;
else {
gain = 50 * number_range(1, 2000);
}
gain_exp( ch, gain );
}
}
void learn_from_failure( CHAR_DATA *ch, int sn )
{
int adept, chance;
if ( IS_NPC(ch) || LEARNED(ch, sn) <= 0 )
return;
chance = LEARNED(ch, sn) + (5 * skill_table[sn]->difficulty);
if ( chance - number_percent() > 25 )
return;
adept = GET_ADEPT(ch, sn);
if ( LEARNED(ch, sn) < (adept-1) )
ch->pcdata->learned[sn] = UMIN( adept, ch->pcdata->learned[sn] + 1 );
}
void do_detrap (CHAR_DATA *ch, char *argument) {
char arg [MAX_INPUT_LENGTH];
OBJ_DATA *obj;
OBJ_DATA *trap;
int percent;
bool found = FALSE;
switch( ch->substate )
{
default:
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
argument = one_argument( argument, arg );
if ( !can_use_skill(ch, 0, gsn_detrap ) )
{
send_to_char("You do not yet know of this skill.\n\r", ch );
return;
}
if ( arg[0] == '\0' )
{
send_to_char( "Detrap what?\n\r", ch );
return;
}
if ( ms_find_obj(ch) )
return;
found = FALSE;
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if ( !ch->in_room->first_content )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
for ( obj = ch->in_room->first_content; obj; obj = obj->next_content )
{
if ( can_see_obj( ch, obj ) && nifty_is_name( arg, obj->name ) )
{
found = TRUE;
break;
}
}
if ( !found )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
act( AT_ACTION, "You carefully begin your attempt to remove a trap from $p...", ch, obj, NULL, TO_CHAR );
act( AT_ACTION, "$n carefully attempts to remove a trap from $p...", ch, obj, NULL, TO_ROOM );
ch->alloc_ptr = str_dup( obj->name );
add_timer( ch, TIMER_DO_FUN, 3, do_detrap, 1 );
return;
case 1:
if ( !ch->alloc_ptr )
{
send_to_char( "Your detrapping was interrupted!\n\r", ch );
bug( "do_detrap: ch->alloc_ptr NULL!", 0 );
return;
}
strcpy( arg, ch->alloc_ptr );
DISPOSE( ch->alloc_ptr );
ch->alloc_ptr = NULL;
ch->substate = SUB_NONE;
break;
case SUB_TIMER_DO_ABORT:
DISPOSE(ch->alloc_ptr);
ch->substate = SUB_NONE;
send_to_char( "You carefully stop what you were doing.\n\r", ch );
return;
}
if ( !ch->in_room->first_content )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
for ( obj = ch->in_room->first_content; obj; obj = obj->next_content )
{
if ( can_see_obj( ch, obj ) && nifty_is_name( arg, obj->name ) )
{
found = TRUE;
break;
}
}
if ( !found )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
if ( (trap = get_trap( obj )) == NULL )
{
send_to_char( "You find no trap on that.\n\r", ch );
return;
}
percent = number_percent() - (get_curr_lck(ch) + get_curr_dex(ch)/4);
separate_obj(obj);
if ( can_use_skill( ch, percent, gsn_detrap ) )
{
send_to_char( "Oops!\n\r", ch );
spring_trap( ch, trap );
learn_from_failure( ch, gsn_detrap );
return;
}
extract_obj( trap );
send_to_char( "You successfully remove a trap.\n\r", ch );
learn_from_success( ch, gsn_detrap );
return;
}
void do_dig( CHAR_DATA *ch, char *argument )
{
char arg [MAX_INPUT_LENGTH];
OBJ_DATA *obj;
OBJ_DATA *startobj;
bool found, shovel;
EXIT_DATA *pexit;
switch( ch->substate )
{
default:
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if (IS_AFFECTED(ch, AFF_FLYING)) {
send_to_char( "You are flying high above the ground.\n\r", ch);
return;
}
one_argument( argument, arg );
if ( arg[0] != '\0' )
{
if ( ( pexit = find_door( ch, arg, TRUE ) ) == NULL
&& get_dir(arg) == -1 )
{
send_to_char( "What direction is that?\n\r", ch );
return;
}
if ( pexit )
{
if ( !IS_SET(pexit->exit_info, EX_DIG)
&& !IS_SET(pexit->exit_info, EX_CLOSED) )
{
send_to_char( "There is no need to dig out that exit.\n\r", ch );
return;
}
}
}
else
{
switch( ch->in_room->sector_type )
{
case SECT_CITY:
case SECT_INSIDE:
send_to_char( "The floor is too hard to dig through.\n\r", ch );
return;
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
case SECT_UNDERWATER:
send_to_char( "You cannot dig here.\n\r", ch );
return;
case SECT_AIR:
send_to_char( "What? In the air?!\n\r", ch );
return;
}
}
add_timer( ch, TIMER_DO_FUN, UMIN(skill_table[gsn_dig]->beats / 10, 3), do_dig, 1);
ch->alloc_ptr = str_dup( arg );
send_to_char( "You begin digging...\n\r", ch );
act( AT_PLAIN, "$n begins digging...", ch, NULL, NULL, TO_ROOM );
return;
case 1:
if ( !ch->alloc_ptr )
{
send_to_char( "Your digging was interrupted!\n\r", ch );
act( AT_PLAIN, "$n's digging was interrupted!", ch, NULL, NULL, TO_ROOM );
bug( "do_dig: alloc_ptr NULL", 0 );
return;
}
strcpy( arg, ch->alloc_ptr );
DISPOSE( ch->alloc_ptr );
break;
case SUB_TIMER_DO_ABORT:
DISPOSE( ch->alloc_ptr );
ch->substate = SUB_NONE;
send_to_char( "You stop digging...\n\r", ch );
act( AT_PLAIN, "$n stops digging...", ch, NULL, NULL, TO_ROOM );
return;
}
ch->substate = SUB_NONE;
/* not having a shovel makes it harder to succeed */
shovel = FALSE;
for ( obj = ch->first_carrying; obj; obj = obj->next_content )
if ( obj->item_type == ITEM_SHOVEL )
{
shovel = TRUE;
break;
}
/* dig out an EX_DIG exit... */
if ( arg[0] != '\0' )
{
if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL
&& IS_SET( pexit->exit_info, EX_DIG )
&& IS_SET( pexit->exit_info, EX_CLOSED ) )
{
/* 4 times harder to dig open a passage without a shovel */
if ( can_use_skill( ch, (number_percent() * (shovel ? 1 : 4)),
gsn_dig ) )
{
REMOVE_BIT( pexit->exit_info, EX_CLOSED );
send_to_char( "You dig open a passageway!\n\r", ch );
act( AT_PLAIN, "$n digs open a passageway!", ch, NULL, NULL, TO_ROOM );
learn_from_success( ch, gsn_dig );
return;
}
}
learn_from_failure( ch, gsn_dig );
send_to_char( "Your dig did not discover any exit...\n\r", ch );
act( AT_PLAIN, "$n's dig did not discover any exit...", ch, NULL, NULL, TO_ROOM );
return;
}
startobj = ch->in_room->first_content;
found = FALSE;
for ( obj = startobj; obj; obj = obj->next_content )
{
/* twice as hard to find something without a shovel */
if ( IS_OBJ_STAT( obj, ITEM_BURIED )
&& ( can_use_skill( ch, (number_percent () * (shovel ? 1 : 2)),
gsn_dig ) ) )
{
found = TRUE;
break;
}
}
learn_noncombat(ch, SK_MINING);
if (!found && number_range(1,300) < ch->in_room->curr_resources
+ get_curr_per(ch) + ch->pcdata->noncombat[SK_MINING]
&& ch->in_room->curr_resources > 0) {
MATERIAL_DATA *material;
for (material=first_material; material; material=material->next) {
if (((!shovel && number_percent() < 50) || (shovel)) && (material->sector == ch->in_room->sector_type) && (number_percent() < material->rarity)) {
/* Can't find magical ore in mana dead areas */
if (xIS_SET(material->extra_flags, ITEM_MAGIC)
&& ch->in_room->area->weather->mana < -100)
continue;
obj=make_ore(material->number);
if (obj) {
obj_to_room(obj, ch->in_room);
ch->in_room->curr_resources--;
xSET_BIT(obj->extra_flags, ITEM_BURIED);
found = TRUE;
break;
}
}
}
}
if ( !found )
{
send_to_char( "Your dig uncovered nothing.\n\r", ch );
act( AT_PLAIN, "$n's dig uncovered nothing.", ch, NULL, NULL, TO_ROOM );
if (ch->in_room->curr_resources < 10)
send_to_char("There doesn't seem to be much left here.\r\n", ch);
learn_from_failure( ch, gsn_dig );
return;
}
separate_obj(obj);
xREMOVE_BIT( obj->extra_flags, ITEM_BURIED );
act( AT_SKILL, "Your dig uncovered $p!", ch, obj, NULL, TO_CHAR );
act( AT_SKILL, "$n's dig uncovered $p!", ch, obj, NULL, TO_ROOM );
learn_from_success( ch, gsn_dig );
return;
}
void do_search( CHAR_DATA *ch, char *argument )
{
char arg [MAX_INPUT_LENGTH];
OBJ_DATA *obj;
OBJ_DATA *container;
OBJ_DATA *startobj;
int percent, door;
door = -1;
switch( ch->substate )
{
default:
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
argument = one_argument( argument, arg );
if ( arg[0] != '\0' && (door = get_door( arg )) == -1 )
{
container = get_obj_here( ch, arg );
if ( !container )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
if ( container->item_type != ITEM_CONTAINER )
{
send_to_char( "You can't search in that!\n\r", ch );
return;
}
if ( IS_SET(container->value[1], CONT_CLOSED) )
{
send_to_char( "It is closed.\n\r", ch );
return;
}
}
add_timer( ch, TIMER_DO_FUN, UMIN(skill_table[gsn_search]->beats / 10, 3),
do_search, 1 );
send_to_char( "You begin your search...\n\r", ch );
ch->alloc_ptr = str_dup( arg );
return;
case 1:
if ( !ch->alloc_ptr )
{
send_to_char( "Your search was interrupted!\n\r", ch );
bug( "do_search: alloc_ptr NULL", 0 );
return;
}
strcpy( arg, ch->alloc_ptr );
DISPOSE( ch->alloc_ptr );
break;
case SUB_TIMER_DO_ABORT:
DISPOSE( ch->alloc_ptr );
ch->substate = SUB_NONE;
send_to_char( "You stop your search...\n\r", ch );
return;
}
ch->substate = SUB_NONE;
if ( arg[0] == '\0' )
startobj = ch->in_room->first_content;
else
{
if ( (door = get_door( arg )) != -1 )
startobj = NULL;
else
{
container = get_obj_here( ch, arg );
if ( !container )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
startobj = container->first_content;
}
}
percent = number_percent( ) + number_percent( ) - ( get_curr_per(ch) / 10 );
if ( door != -1 )
{
EXIT_DATA *pexit;
if ( (pexit = get_exit( ch->in_room, door )) != NULL
&& IS_SET( pexit->exit_info, EX_SECRET )
&& IS_SET( pexit->exit_info, EX_xSEARCHABLE )
&& can_use_skill( ch, percent, gsn_search ) )
{
act( AT_SKILL, "Your search reveals the $d!", ch, NULL, pexit->keyword, TO_CHAR );
act( AT_SKILL, "$n finds the $d!", ch, NULL, pexit->keyword, TO_ROOM );
REMOVE_BIT( pexit->exit_info, EX_SECRET );
learn_from_success( ch, gsn_search );
return;
}
}
else
for ( obj = startobj; obj; obj = obj->next_content )
{
if ( IS_OBJ_STAT( obj, ITEM_HIDDEN )
&& can_use_skill(ch, percent, gsn_search ) )
{
separate_obj(obj);
xREMOVE_BIT( obj->extra_flags, ITEM_HIDDEN );
act( AT_SKILL, "Your search reveals $p!", ch, obj, NULL, TO_CHAR );
act( AT_SKILL, "$n finds $p!", ch, obj, NULL, TO_ROOM );
learn_from_success( ch, gsn_search );
return;
}
}
learn_noncombat(ch, SK_NATURE);
if (number_range(1,300) < ch->in_room->curr_vegetation
+ get_curr_per(ch) + ch->pcdata->noncombat[SK_NATURE]
&& ch->in_room->curr_vegetation > 0) {
INGRED_DATA *ingred;
for (ingred=first_ingred; ingred; ingred=ingred->next) {
if (ingred->sector != ch->in_room->sector_type) continue;
if (ingred->moisture > ch->in_room->curr_water) continue;
if (ingred->elevation > ch->in_room->curr_elevation) continue;
if (ingred->precip > 0
&& ingred->precip < ch->in_room->area->weather->precip) continue;
if (ingred->precip < 0
&& ingred->precip > ch->in_room->area->weather->precip) continue;
if (ingred->temp > 0
&& ingred->temp < ch->in_room->area->weather->temp) continue;
if (ingred->temp < 0
&& ingred->temp > ch->in_room->area->weather->temp) continue;
if (ingred->mana > 0
&& ingred->mana < ch->in_room->area->weather->mana) continue;
if (number_percent() > ingred->rarity) continue;
if (!get_obj_index(ingred->vnum)) {
bug("Do_search: can't find vnum for ingredient %d!",
ingred->vnum);
send_to_char("You thought you saw something, but it disappeared...\n\r", ch);
return;
}
obj = create_object( get_obj_index( ingred->vnum ), 0 );
if (obj) {
obj_to_room(obj, ch->in_room);
ch->in_room->curr_vegetation--;
act(AT_SKILL, "You have found $p!", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n has found $p!", ch, obj, NULL, TO_ROOM);
return;
}
}
}
send_to_char( "You find nothing.\n\r", ch );
learn_from_failure( ch, gsn_search );
return;
}
void do_steal( CHAR_DATA *ch, char *argument ) {
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
CHAR_DATA *victim, *mst;
OBJ_DATA *obj;
int gp;
argument = one_argument( argument, arg1 );
argument = one_argument( argument, arg2 );
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if ( arg1[0] == '\0' || arg2[0] == '\0' )
{
send_to_char( "Steal what from whom?\n\r", ch );
return;
}
if ( ms_find_obj(ch) )
return;
if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if ( victim == ch )
{
send_to_char( "That's pointless.\n\r", ch );
return;
}
if ( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) )
{
set_char_color( AT_MAGIC, ch );
send_to_char( "A magical force interrupts you.\n\r", ch );
return;
}
if ( check_illegal_psteal( ch, victim ) )
{
send_to_char( "You can't steal from that player.\n\r", ch );
return;
}
if (IS_NPC(victim) && xIS_SET(victim->act, ACT_PACIFIST) ) /* Gorog */
{
send_to_char( "They are a pacifist - Shame on you!\n\r", ch);
return;
}
if (!IS_SAME_PLANE(ch, victim)) {
send_to_char( "Your hands pass right through them!\n\r", ch);
return;
}
learn_noncombat(ch, SK_STEALTH);
learn_noncombat(victim, SK_STREET);
if ( !IS_NPC(ch) &&
number_range(1, ch->pcdata->noncombat[SK_STEALTH]*2
+ get_curr_dex(ch)) < (IS_NPC(victim) ? 50 :
number_range(1, victim->pcdata->noncombat[SK_STREET]*2
+ get_curr_per(victim)) )) {
/*
* Failure.
*/
send_to_char( "Oops...\n\r", ch );
act( AT_ACTION, "$n tries to steal from you!", ch, NULL, victim, TO_VICT );
act( AT_ACTION, "$n tries to steal from $N.", ch, NULL, victim, TO_NOTVICT );
learn_from_failure( ch, gsn_steal );
if ( IS_NPC( ch ) )
{
if ( (mst = ch->master) == NULL )
return;
}
return;
}
if ( !str_cmp( arg1, "coin" )
|| !str_cmp( arg1, "coins" )
|| !str_cmp( arg1, "gold" )
|| !str_cmp( arg1, "money" ) )
{
int amount;
amount = (int) (victim->gold * number_range(1, 10) / 100);
if ( amount <= 0 )
{
send_to_char( "You couldn't get any coins.\n\r", ch );
learn_from_failure( ch, gsn_steal );
return;
}
ch->gold += amount;
victim->gold -= amount;
gp = amount;
ch_printf( ch, "You steal &w%dmithril, ", (int)gp/1000000 );
gp = gp % 1000000;
ch_printf( ch, "&Y%dgold, ", (int)gp/10000 );
gp = gp % 10000;
ch_printf( ch, "&W%dsilver, ", (int)gp/100 );
gp = gp % 100;
ch_printf( ch, "and &O%dcopper&w coins.\n\r", gp);
learn_from_success( ch, gsn_steal );
return;
}
if ( ( obj = get_obj_carry( victim, arg1 ) ) == NULL )
{
send_to_char( "You can't seem to find it.\n\r", ch );
learn_from_failure( ch, gsn_steal );
return;
}
if ( !can_drop_obj( ch, obj )
|| IS_OBJ_STAT(obj, ITEM_INVENTORY)
|| IS_OBJ_STAT(obj, ITEM_PROTOTYPE)
|| obj == victim->main_hand
|| obj == victim->off_hand )
{
send_to_char( "You can't manage to pry it away.\n\r", ch );
learn_from_failure( ch, gsn_steal );
return;
}
if ( ch->carry_number + (get_obj_number(obj)/obj->count) >
can_carry_n( ch ) )
{
send_to_char( "You have your hands full.\n\r", ch );
learn_from_failure( ch, gsn_steal );
return;
}
if ( ch->carry_weight + (get_obj_weight(obj)/obj->count) >
can_carry_w( ch ) )
{
send_to_char( "You can't carry that much weight.\n\r", ch );
learn_from_failure( ch, gsn_steal );
return;
}
if (IS_OBJ_STAT(obj, ITEM_ARTIFACT)
&& IS_AFFECTED(ch, AFF_HAS_ARTI)) {
act(AT_MAGIC, "$p evades your grasp.", ch, obj, NULL, TO_CHAR);
return;
}
separate_obj( obj );
obj_from_char( obj );
obj_to_char( obj, ch );
send_to_char( "Got it!\n\r", ch );
learn_from_success( ch, gsn_steal );
return;
}
void do_feed( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *victim;
if (!IS_VAMPIRE(ch)) {
huh(ch);
return;
}
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if ( ( victim = get_char_room( ch, argument ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
global_retcode = rNONE;
return;
}
if (!IS_SAME_PLANE(ch, victim)) {
send_to_char( "You pass right through them!\n\r", ch);
return;
}
if (IS_NPC(victim)) {
send_to_char( "They are not worthy of being embraced.\n\r",ch);
return;
}
if (( victim->hit ) > (victim->max_hit / 3))
{
send_to_char("They are not low enough on blood to feed.\n\r", ch);
return;
}
if (IS_AFFECTED(ch, AFF_COLDBLOOD)) {
send_to_char("Their blood is incompatable.\n\r", ch);
return;
}
if (!IS_CONSENTING(victim, ch)) {
send_to_char("You do not have their consent to do that.\n\r", ch);
return;
}
victim->hit += (int) ch->hit/2;
ch->hit -= (int) ch->hit/2;
act(AT_BLOOD, "You slash open your wrist and feed blood to $N.",
ch, NULL, victim, TO_CHAR);
act(AT_BLOOD, "$n slashes open $s wrist and feeds you blood.",
ch, NULL, victim, TO_VICT);
act(AT_BLOOD, "$n slashes open $s wrist and feeds blood to $N.",
ch, NULL, victim, TO_NOTVICT);
if (!IS_SET(victim->pcdata->flags, PCFLAG_VAMPIRE)) {
SET_BIT(victim->pcdata->flags, PCFLAG_VAMPIRE);
victim->pcdata->condition[COND_FULL]= -1;
victim->pcdata->condition[COND_THIRST] = -1;
STRFREE(victim->pcdata->parent);
victim->pcdata->parent = STRALLOC(ch->name);
if (ch->pcdata->family) {
STRFREE(victim->pcdata->family);
victim->pcdata->family = STRALLOC(ch->pcdata->family);
}
victim->pcdata->gen = ch->pcdata->gen + 1;
STRFREE(victim->pcdata->type);
victim->pcdata->type = STRALLOC("vampire");
}
return;
}
/*
* Disarm a creature.
* Caller must check for successful attack.
* Check for loyalty flag (weapon disarms to inventory) for pkillers -Blodkai
*/
void disarm( CHAR_DATA *ch, CHAR_DATA *victim )
{
OBJ_DATA *obj, *tmpobj;
if ( ( obj = victim->main_hand ) == NULL )
return;
if ( ( tmpobj = victim->off_hand ) != NULL
&& number_bits( 1 ) == 0 )
obj = tmpobj;
if ( IS_NPC( ch ) && !can_see_obj( ch, obj ) && number_bits( 1 ) == 0)
{
learn_from_failure( ch, gsn_disarm );
return;
}
if ( check_grip( ch, victim ) ) {
learn_from_failure( ch, gsn_disarm );
return;
}
act( AT_SKILL, "$n DISARMS you!", ch, NULL, victim, TO_VICT );
act( AT_SKILL, "You disarm $N!", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n disarms $N!", ch, NULL, victim, TO_NOTVICT );
learn_from_success( ch, gsn_disarm );
obj_from_char( obj );
if ( IS_OBJ_STAT(obj, ITEM_LOYAL) ) {
act( AT_MAGIC, "Your weapon returns to your hand!", ch, NULL, victim, TO_VICT);
act( AT_MAGIC, "$N\'s weapon returns to $s hand!", ch, NULL, victim, TO_CHAR);
act( AT_MAGIC, "$N\'s weapon returns to $s hand!", ch, NULL, victim, TO_NOTVICT);
obj_to_char( obj, victim );
} else
obj_to_room( obj, victim->in_room );
return;
}
void do_disarm( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *obj;
int percent;
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
if ( !skill_available(ch, gsn_disarm) )
{
send_to_char( "You don't know how to disarm opponents.\n\r", ch );
return;
}
if ( ( victim = get_char_room(ch, argument) ) == NULL ) {
send_to_char( "Disarm who?\n\r", ch );
return;
}
if ( ( obj = victim->main_hand ) == NULL
&& ( obj = victim->off_hand ) == NULL ) {
send_to_char( "Your opponent is not wielding a weapon.\n\r", ch );
return;
}
percent = number_percent( ) - (get_curr_dex(ch)/10) + (get_curr_dex(victim)/10)
+ victim->weight + get_curr_str(victim) - ch->weight - get_curr_dex(ch);
if ( !can_see_obj( ch, obj ) )
percent += 10;
if ( can_use_skill(ch, (percent*3/2), gsn_disarm ) ) {
if (IS_OBJ_STAT(obj, ITEM_LOYAL)) {
act( AT_SKILL, "$n DISARMS you, but $p returns to your hand!", ch, obj, victim, TO_VICT );
act( AT_SKILL, "You disarm $N, but $p returns to $s hand!", ch, obj, victim, TO_CHAR );
act( AT_SKILL, "$n disarms $N, but $p returns to $s hand!", ch, obj, victim, TO_NOTVICT );
learn_from_success( ch, gsn_disarm );
return;
}
disarm( ch, victim );
} else
{
send_to_char( "You failed.\n\r", ch );
learn_from_failure( ch, gsn_disarm );
}
return;
}
/*
* Trip a creature.
* Caller must check for successful attack.
*/
void trip( CHAR_DATA *ch, CHAR_DATA *victim )
{
if ( IS_AFFECTED( victim, AFF_FLYING )
|| IS_AFFECTED( victim, AFF_FLOATING ) )
return;
if ( victim->mount )
{
if ( IS_AFFECTED( victim->mount, AFF_FLYING )
|| IS_AFFECTED( victim->mount, AFF_FLOATING ) )
return;
act( AT_SKILL, "$n trips your mount and you fall off!", ch, NULL, victim, TO_VICT );
act( AT_SKILL, "You trip $N's mount and $N falls off!", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n trips $N's mount and $N falls off!", ch, NULL, victim, TO_NOTVICT );
if (IS_NPC(victim->mount))
xREMOVE_BIT( victim->mount->affected_by, AFF_MOUNTED );
else
xREMOVE_BIT( victim->mount->pcdata->perm_aff, AFF_MOUNTED);
victim->mount = NULL;
WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
victim->position = POS_RESTING;
return;
}
if ( victim->wait == 0 )
{
act( AT_SKILL, "$n trips you and you go down!", ch, NULL, victim, TO_VICT );
act( AT_SKILL, "You trip $N and $N goes down!", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n trips $N and $N goes down!", ch, NULL, victim, TO_NOTVICT );
WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
victim->position = POS_RESTING;
}
return;
}
/* locksmith <door> <lock> <key> */
void do_locksmith(CHAR_DATA *ch, char *argument) {
char arg[MAX_INPUT_LENGTH];
char buf[MAX_INPUT_LENGTH];
char door[MAX_INPUT_LENGTH];
OBJ_DATA *key;
OBJ_DATA *lock;
EXIT_DATA *pexit;
if (IS_NPC(ch) && IS_AFFECTED(ch, AFF_CHARM)) {
send_to_char("You can't concentrate enough for that.\r\n", ch);
return;
}
argument = one_argument(argument, door);
argument = one_argument(argument, arg);
argument = one_argument(argument, buf);
if (door[0] == '\0') {
send_to_char("Syntax: locksmith <door> <lock> <key>\r\n", ch);
return;
}
if (arg[0] == '\0') {
send_to_char("What lock would you like to use?\r\n", ch);
return;
}
if (buf[0] == '\0') {
send_to_char("What would you like to use as a key to your lock?\r\n", ch);
return;
}
if ((key = get_obj_carry(ch, buf)) == NULL) {
send_to_char("You don't seem to have that key.\r\n", ch);
return;
}
if ((lock = get_obj_carry(ch, arg)) == NULL || key == lock) {
send_to_char("You don't have a lock by that name.\r\n", ch);
return;
}
if (key->item_type != ITEM_KEY) {
send_to_char("That is not a key.\r\n", ch);
return;
}
if (lock->item_type != ITEM_LOCK) {
send_to_char("That is not a lock.\r\n", ch);
return;
}
if ( ms_find_obj(ch) )
return;
if ( ch->mount ) {
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if ( ( pexit = find_door( ch, door, TRUE ) ) != NULL ) {
EXIT_DATA *pexit_rev;
if ( !IS_SET(pexit->exit_info, EX_CLOSED) ) {
send_to_char( "It's not closed.\n\r", ch );
return;
}
if (IS_SET(pexit->exit_info, EX_BASHED)) {
send_to_char("That door has been bashed off its hinges!\r\n", ch);
return;
}
if ( pexit->key >= 0) {
send_to_char( "It already has a lock.\r\n", ch);
return;
}
if ( IS_SET(pexit->exit_info, EX_LOCKED) ) {
send_to_char( "It's already locked.\n\r", ch );
return;
}
if ( !can_use_skill(ch, number_percent(), gsn_locksmith ) ) {
send_to_char( "You fail to install the lock.\n\r", ch);
learn_from_failure( ch, gsn_locksmith );
separate_obj(lock);
obj_from_char(lock);
extract_obj(lock);
return;
}
SET_BIT(pexit->exit_info, EX_LOCKED);
pexit->key = number_range(1, 9999);
key->value[0] = pexit->key;
send_to_char( "You install a sturdy lock.\n\r", ch );
act( AT_SKILL, "$n installs a lock in the $d.", ch, NULL, pexit->keyword, TO_ROOM );
separate_obj(lock);
obj_from_char(lock);
extract_obj(lock);
learn_from_success( ch, gsn_locksmith );
/* lock the other side */
if ( ( pexit_rev = pexit->rexit ) != NULL
&& pexit_rev->to_room == ch->in_room ) {
SET_BIT( pexit_rev->exit_info, EX_LOCKED );
pexit_rev->key = pexit->key;
}
fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE);
if (pexit->to_room->area != ch->in_room->area)
fold_area(pexit->to_room->area, pexit->to_room->area->filename, FALSE);
WAIT_STATE(ch, skill_table[gsn_locksmith]->beats);
return;
}
ch_printf( ch, "You see no %s here.\n\r", arg );
}
void do_pick( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *gch;
OBJ_DATA *obj;
EXIT_DATA *pexit;
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
one_argument( argument, arg );
if ( arg[0] == '\0' )
{
send_to_char( "Pick what?\n\r", ch );
return;
}
if ( ms_find_obj(ch) )
return;
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
/* look for guards */
for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
{
if ( IS_AWAKE(gch) && IS_AFFECTED(gch, AFF_GUARD) )
{
act( AT_PLAIN, "$N is standing too close to the lock.",
ch, NULL, gch, TO_CHAR );
return;
}
}
if ( !can_use_skill(ch, number_percent(), gsn_pick_lock ) )
{
send_to_char( "You fail to pick the lock.\n\r", ch);
learn_from_failure( ch, gsn_pick_lock );
return;
}
if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
{
/* 'pick door' */
EXIT_DATA *pexit_rev;
if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
{ send_to_char( "It's not closed.\n\r", ch ); return; }
if ( !IS_SET(pexit->exit_info, EX_LOCKED) )
{ send_to_char( "It's already unlocked.\n\r", ch ); return; }
if ( IS_SET(pexit->exit_info, EX_PICKPROOF) )
{
send_to_char( "You fail to pick the lock.\n\r", ch );
learn_from_failure( ch, gsn_pick_lock );
check_room_for_traps( ch, TRAP_PICK | trap_door[pexit->vdir] );
return;
}
REMOVE_BIT(pexit->exit_info, EX_LOCKED);
send_to_char( "You spring the lock.\n\r", ch );
act( AT_ACTION, "$n picks the $d.", ch, NULL, pexit->keyword, TO_ROOM );
learn_from_success( ch, gsn_pick_lock );
/* pick the other side */
if ( ( pexit_rev = pexit->rexit ) != NULL
&& pexit_rev->to_room == ch->in_room )
{
REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED );
}
check_room_for_traps( ch, TRAP_PICK | trap_door[pexit->vdir] );
return;
}
if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
{
/* 'pick object' */
if ( obj->item_type != ITEM_CONTAINER )
{ send_to_char( "That's not a container.\n\r", ch ); return; }
if ( !IS_SET(obj->value[1], CONT_CLOSED) )
{ send_to_char( "It's not closed.\n\r", ch ); return; }
if ( !IS_SET(obj->value[1], CONT_LOCKED) )
{ send_to_char( "It's already unlocked.\n\r", ch ); return; }
if ( IS_SET(obj->value[1], CONT_PICKPROOF) )
{
send_to_char( "You failed.\n\r", ch );
learn_from_failure( ch, gsn_pick_lock );
check_for_trap( ch, obj, TRAP_PICK );
return;
}
separate_obj( obj );
REMOVE_BIT(obj->value[1], CONT_LOCKED);
send_to_char( "*Click*\n\r", ch );
act( AT_ACTION, "$n picks $p.", ch, obj, NULL, TO_ROOM );
learn_from_success( ch, gsn_pick_lock );
return;
}
ch_printf( ch, "You see no %s here.\n\r", arg );
return;
}
void do_sneak( CHAR_DATA *ch, char *argument ) {
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if (!IS_NPC(ch)) {
send_to_char( "You attempt to move silently.\n\r", ch );
xSET_BIT(ch->pcdata->perm_aff, AFF_SNEAK);
}
return;
}
void do_hide( CHAR_DATA *ch, char *argument )
{
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
send_to_char( "You attempt to hide.\n\r", ch );
if ( can_use_skill(ch, number_percent(), gsn_hide ) )
{
if (IS_NPC(ch))
xSET_BIT(ch->affected_by, AFF_HIDE);
else
xSET_BIT(ch->pcdata->perm_aff, AFF_HIDE);
learn_from_success( ch, gsn_hide );
}
else
learn_from_failure( ch, gsn_hide );
return;
}
void do_emerge(CHAR_DATA *ch, char *argument) {
if (!IS_NPC(ch)) {
xREMOVE_BIT(ch->pcdata->perm_aff, AFF_SNEAK);
xREMOVE_BIT(ch->pcdata->perm_aff, AFF_HIDE);
}
xREMOVE_BIT(ch->affected_by, AFF_SNEAK);
xREMOVE_BIT(ch->affected_by, AFF_HIDE);
act(AT_DGREY, "You emerge from hiding.\n\r", ch, NULL, NULL, TO_CHAR);
act(AT_DGREY, "$n emerges from the shadows.\n\r", ch, NULL, NULL, TO_ROOM);
}
void do_aid( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
int percent;
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
one_argument( argument, arg );
if ( arg[0] == '\0' )
{
send_to_char( "Aid whom?\n\r", ch );
return;
}
if ( ( victim = get_char_room( ch, arg ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if ( IS_NPC(victim) ) /* Gorog */
{
send_to_char( "Not on mobs.\n\r", ch );
return;
}
if (!can_use_bodypart(ch, BP_RHAND)
&& !can_use_bodypart(ch, BP_LHAND)) {
send_to_char("That would be hard without functional hands.\n\r", ch);
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
if ( victim == ch )
{
send_to_char( "Aid yourself?\n\r", ch );
return;
}
if (!IS_SAME_PLANE(victim, ch)) {
send_to_char("Your hands pass right through them!\n\r", ch);
return;
}
if ( victim->position > POS_STUNNED )
{
act( AT_PLAIN, "$N doesn't need your help.", ch, NULL, victim,
TO_CHAR);
return;
}
percent = number_percent( ) - (get_curr_lck(ch)/5);
if ( !can_use_skill( ch, percent, gsn_aid ) )
{
send_to_char( "You fail.\n\r", ch );
learn_from_failure( ch, gsn_aid );
return;
}
act( AT_SKILL, "You aid $N!", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n aids $N!", ch, NULL, victim, TO_NOTVICT );
learn_from_success( ch, gsn_aid );
if ( victim->hit < 10 )
victim->hit = 10;
if ( victim->move < 10 )
victim->move = 10;
update_pos( victim );
act( AT_SKILL, "$n aids you!", ch, NULL, victim, TO_VICT );
return;
}
void do_mount( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *victim;
if ( !skill_available(ch, gsn_mount) )
{
send_to_char(
"I don't think that would be a good idea...\n\r", ch );
return;
}
if ( ch->mount )
{
send_to_char( "You're already mounted!\n\r", ch );
return;
}
if ( ( victim = get_char_room( ch, argument ) ) == NULL )
{
send_to_char( "You can't find that here.\n\r", ch );
return;
}
if ( !IS_AFFECTED(victim, AFF_MOUNTABLE) )
{
send_to_char( "You can't mount that!\n\r", ch );
return;
}
if ( IS_AFFECTED(victim, AFF_MOUNTED ) )
{
send_to_char( "That mount already has a rider.\n\r", ch );
return;
}
if (!IS_NPC(victim) && !IS_CONSENTING(victim, ch)) {
send_to_char("Not without their consent.\n\r", ch);
return;
}
if ( IS_FIGHTING(victim) )
{
send_to_char( "Your mount is moving around too much.\n\r", ch );
return;
}
if (!IS_SAME_PLANE(ch, victim)) {
send_to_char( "You pass right through them!\n\r", ch);
return;
}
if ( can_use_skill(ch, number_percent(), gsn_mount ) )
{
if (IS_NPC(victim))
xSET_BIT(victim->affected_by, AFF_MOUNTED );
else
xSET_BIT(victim->pcdata->perm_aff, AFF_MOUNTED );
ch->mount = victim;
act( AT_SKILL, "You mount $N.", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n skillfully mounts $N.", ch, NULL, victim, TO_NOTVICT );
act( AT_SKILL, "$n mounts you.", ch, NULL, victim, TO_VICT );
learn_from_success( ch, gsn_mount );
ch->position = POS_MOUNTED;
}
else
{
act( AT_SKILL, "You unsuccessfully try to mount $N.", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n unsuccessfully attempts to mount $N.", ch, NULL, victim, TO_NOTVICT );
act( AT_SKILL, "$n tries to mount you.", ch, NULL, victim, TO_VICT );
learn_from_failure( ch, gsn_mount );
}
return;
}
void do_dismount( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *victim;
if ( (victim = ch->mount) == NULL )
{
if (ch->position == POS_MOUNTED)
ch->position = POS_STANDING;
send_to_char( "You're not mounted.\n\r", ch );
return;
}
if ( can_use_skill(ch, number_percent(), gsn_mount ) )
{
act( AT_SKILL, "You dismount $N.", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n skillfully dismounts $N.", ch, NULL, victim, TO_NOTVICT );
act( AT_SKILL, "$n dismounts you. Whew!", ch, NULL, victim, TO_VICT );
if (IS_NPC(victim))
xREMOVE_BIT( victim->affected_by, AFF_MOUNTED );
else
xREMOVE_BIT( victim->pcdata->perm_aff, AFF_MOUNTED);
ch->mount = NULL;
ch->position = POS_STANDING;
learn_from_success( ch, gsn_mount );
}
else
{
act( AT_SKILL, "You fall off while dismounting $N. Ouch!", ch, NULL, victim, TO_CHAR );
act( AT_SKILL, "$n falls off of $N while dismounting.", ch, NULL, victim, TO_NOTVICT );
act( AT_SKILL, "$n falls off your back.", ch, NULL, victim, TO_VICT );
learn_from_failure( ch, gsn_mount );
if (IS_NPC(victim))
xREMOVE_BIT( victim->affected_by, AFF_MOUNTED );
else
xREMOVE_BIT( victim->pcdata->perm_aff, AFF_MOUNTED );
ch->mount = NULL;
ch->position = POS_SITTING;
}
return;
}
/**************************************************************************/
/*
* Check for parry.
*/
bool check_parry( CHAR_DATA *ch, CHAR_DATA *victim )
{
int chances;
if ( !IS_AWAKE(victim) )
return FALSE;
chances = UMIN( 60, 100 );
if ( get_eq_char(victim, WEAR_HAND) == NULL )
return FALSE;
if ( !chance( victim, chances - (get_curr_str(ch)+get_curr_dex(ch)) + (get_curr_str(victim)+get_curr_dex(victim)) ))
{
learn_from_failure( victim, gsn_parry );
return FALSE;
}
if ( !IS_NPC(victim)
&& !IS_SET( victim->pcdata->flags, PCFLAG_GAG) ) /*SB*/
act( AT_SKILL, "You parry $n's attack.", ch, NULL, victim, TO_VICT );
if ( !IS_NPC(ch)
&& !IS_SET( ch->pcdata->flags, PCFLAG_GAG) ) /* SB */
act( AT_SKILL, "$N parries your attack.", ch, NULL, victim, TO_CHAR );
learn_from_success( victim, gsn_parry );
return TRUE;
}
/*
* Check for dodge.
*/
bool check_dodge( CHAR_DATA *ch, CHAR_DATA *victim )
{
int chances;
if ( !IS_AWAKE(victim) )
return FALSE;
if ( IS_NPC(victim) && !xIS_SET(victim->defenses, DFND_DODGE) )
return FALSE;
chances = UMIN( 60, get_curr_dex(victim) );
chances += get_curr_dex(victim)+20;
chances -= GET_HITROLL(ch);
if (chances < 0) chances = 20;
if (IS_SET(victim->mood, MOOD_DEFENSE))
chances *= 2;
if (IS_SET(victim->mood, MOOD_RELAXED))
chances = 0;
if (number_range(1, chances) < number_range(1, get_curr_dex(ch))) {
learn_from_failure( victim, gsn_dodge );
return FALSE;
}
if ( !IS_NPC(victim) && !IS_SET( victim->pcdata->flags, PCFLAG_GAG) )
act( AT_SKILL, "You dodge $n's attack.", ch, NULL, victim, TO_VICT );
if ( !IS_NPC(ch) && !IS_SET( ch->pcdata->flags, PCFLAG_GAG) )
act( AT_SKILL, "$N dodges your attack.", ch, NULL, victim, TO_CHAR );
gain_exp(ch, get_exp_worth(victim));
gain_exp(victim, get_exp_worth(ch));
learn_from_success( victim, gsn_dodge );
return TRUE;
}
bool check_tumble( CHAR_DATA *ch, CHAR_DATA *victim )
{
int chances;
if (!IS_AWAKE(victim))
return FALSE;
if ( !IS_NPC( victim )
&& !LEARNED(victim, gsn_tumble) > 0 )
return FALSE;
chances = UMIN( 60, get_curr_dex(victim) );
chances += get_curr_dex(victim)+25;
chances -= GET_HITROLL(ch);
if (chances < 0) chances = 20;
if (IS_SET(victim->mood, MOOD_DEFENSE))
chances *= 2;
if (IS_SET(victim->mood, MOOD_RELAXED))
chances = 0;
if (number_range(1, chances) < number_range(1, get_curr_dex(ch))) {
learn_from_failure( victim, gsn_tumble );
return FALSE;
}
if ( !IS_NPC(victim) && !IS_SET( victim->pcdata->flags, PCFLAG_GAG ) )
act( AT_SKILL, "You tumble away from $n's attack.", ch, NULL, victim, TO_VICT );
if ( !IS_NPC(ch) && !IS_SET( ch->pcdata->flags, PCFLAG_GAG ) )
act( AT_SKILL, "$N tumbles away from your attack.", ch, NULL, victim, TO_CHAR );
gain_exp(ch, get_exp_worth(victim));
gain_exp(victim, get_exp_worth(ch));
learn_from_success( victim, gsn_tumble );
return TRUE;
}
/*
* Check for counterspell.
*/
bool check_counterspell( CHAR_DATA *ch, CHAR_DATA *victim )
{
int chances;
if (victim == NULL)
return FALSE;
if ( !IS_AWAKE(victim) )
return FALSE;
if ( ch->curr_talent[TAL_CATALYSM] < 50 )
return FALSE;
if (victim->mana < 50)
return FALSE;
chances = (int) (LEARNED(victim, gsn_counterspell) / 4 );
if ( !chance( victim, chances - (get_curr_int(ch)+get_curr_wil(ch)) +
(get_curr_int(victim)+get_curr_wil(victim)) ))
{
learn_from_failure( victim, gsn_counterspell );
return FALSE;
}
act( AT_MAGIC, "Thinking fast, you utter a quick counterspell.", ch, NULL, victim, TO_VICT );
act( AT_MAGIC, "$N utters a quick counterspell.", ch, NULL, victim, TO_CHAR );
act( AT_MAGIC, "$N utters a quick counterspell.", ch, NULL, victim, TO_NOTVICT );
victim->mana -= 5;
victim->in_room->area->weather->mana += 1;
learn_from_success( victim, gsn_counterspell );
return TRUE;
}
void do_poison_weapon( CHAR_DATA *ch, char *argument )
{
OBJ_DATA *obj;
OBJ_DATA *pobj;
OBJ_DATA *wobj;
char arg [ MAX_INPUT_LENGTH ];
int percent;
if ( !skill_available(ch, gsn_poison_weapon) )
{
send_to_char( "What do you think you are, a thief?\n\r", ch );
return;
}
one_argument( argument, arg );
if ( arg[0] == '\0' )
{
send_to_char( "What are you trying to poison?\n\r", ch );
return;
}
if ( IS_FIGHTING(ch) )
{
send_to_char( "While you're fighting? Nice try.\n\r", ch );
return;
}
if ( ms_find_obj(ch) )
return;
if ( !( obj = get_obj_carry( ch, arg ) ) )
{
send_to_char( "You do not have that weapon.\n\r", ch );
return;
}
if ( obj->item_type != ITEM_WEAPON )
{
send_to_char( "That item is not a weapon.\n\r", ch );
return;
}
if ( IS_OBJ_STAT( obj, ITEM_POISONED ) )
{
send_to_char( "That weapon is already poisoned.\n\r", ch );
return;
}
/* Now we have a valid weapon...check to see if we have the powder. */
for ( pobj = ch->first_carrying; pobj; pobj = pobj->next_content )
{
if ( pobj->pIndexData->vnum == OBJ_VNUM_BLACK_POWDER )
break;
}
if ( !pobj )
{
send_to_char( "You do not have the black poison powder.\n\r", ch );
return;
}
/* Okay, we have the powder...do we have water? */
for ( wobj = ch->first_carrying; wobj; wobj = wobj->next_content )
{
if ( wobj->item_type == ITEM_DRINK_CON
&& wobj->value[1] > 0
&& wobj->value[2] == 0 )
break;
}
if ( !wobj )
{
send_to_char( "You have no water to mix with the powder.\n\r", ch );
return;
}
/* Great, we have the ingredients...but is the thief smart enough? */
if ( !IS_NPC( ch ) && number_percent() > get_curr_wil( ch ) )
{
send_to_char( "You can't quite remember what to do...\n\r", ch );
return;
}
/* And does the thief have steady enough hands? */
if ( !IS_NPC( ch )
&& ( (number_percent() > get_curr_dex(ch)) || ch->pcdata->condition[COND_DRUNK] > 0 ) )
{
send_to_char("Your hands aren't steady enough to properly mix the poison.\n\r", ch );
return;
}
percent = (number_percent( ) - get_curr_lck(ch)/100);
/* Check the skill percentage */
separate_obj( pobj );
separate_obj( wobj );
if (!can_use_skill(ch, percent, gsn_poison_weapon ) )
{
set_char_color( AT_RED, ch );
send_to_char( "You failed and spill some on yourself. Ouch!\n\r", ch );
set_char_color( AT_GREY, ch );
act(AT_RED, "$n spills the poison all over!", ch, NULL, NULL, TO_ROOM );
extract_obj( pobj );
extract_obj( wobj );
learn_from_failure( ch, gsn_poison_weapon );
return;
}
separate_obj( obj );
/* Well, I'm tired of waiting. Are you? */
act(AT_RED, "You mix $p in $P, creating a deadly poison!", ch, pobj, wobj, TO_CHAR );
act(AT_RED, "$n mixes $p in $P, creating a deadly poison!",ch, pobj, wobj, TO_ROOM );
act(AT_GREEN, "You pour the poison over $p, which glistens wickedly!",ch, obj, NULL, TO_CHAR );
act(AT_GREEN, "$n pours the poison over $p, which glistens wickedly!",ch, obj, NULL, TO_ROOM );
xSET_BIT( obj->extra_flags, ITEM_POISONED );
/* Set an object timer. Don't want proliferation of poisoned weapons */
obj->timer = number_range( 1, 20 );
if ( IS_OBJ_STAT( obj, ITEM_BLESS ) )
obj->timer *= 2;
if ( IS_OBJ_STAT( obj, ITEM_MAGIC ) )
obj->timer *= 2;
/* WHAT? All of that, just for that one bit? How lame. ;) */
act(AT_BLUE, "The remainder of the poison eats through $p.", ch, wobj, NULL, TO_CHAR );
act(AT_BLUE, "The remainder of the poison eats through $p.", ch, wobj, NULL, TO_ROOM );
extract_obj( pobj );
extract_obj( wobj );
learn_from_success( ch, gsn_poison_weapon );
return;
}
void do_scribe( CHAR_DATA *ch, char *argument )
{
OBJ_DATA *scroll;
OBJ_DATA *pen;
int sn;
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char buf3[MAX_STRING_LENGTH];
int mana;
bool found;
if ( IS_NPC(ch) )
return;
if ( !skill_available(ch, gsn_scribe) )
{
send_to_char( "A skill such as this requires more magical ability than you have.\n\r", ch );
return;
}
if ( argument[0] == '\0' || !str_cmp(argument, "") )
{
send_to_char( "Scribe what?\n\r", ch );
return;
}
if ( ms_find_obj(ch) )
return;
if ( (sn = find_spell( ch, argument, TRUE )) < 0 )
{
send_to_char( "You have not learned that spell.\n\r", ch );
return;
}
if ( skill_table[sn]->spell_fun == spell_null )
{
send_to_char( "That's not a spell!\n\r", ch );
return;
}
if ( SPELL_FLAG(skill_table[sn], SF_NOSCRIBE) )
{
send_to_char( "You cannot scribe that spell.\n\r", ch );
return;
}
mana = IS_NPC(ch) ? 0 : UMAX(skill_table[sn]->min_mana,
100 / ( 100 - skill_table[sn]->skill_level[get_best_talent(ch, sn)] ));
mana *=5;
if ( !IS_NPC(ch) && ch->mana < mana )
{
send_to_char( "You don't have enough mana.\n\r", ch );
return;
}
if ( ( scroll = get_eq_char( ch, WEAR_HAND ) ) == NULL )
{
send_to_char( "You must be holding a blank scroll to scribe it.\n\r", ch );
return;
}
if( scroll->pIndexData->vnum != OBJ_VNUM_SCROLL_SCRIBING )
{
send_to_char( "You must be holding a blank scroll to scribe it.\n\r", ch );
return;
}
if ( ( scroll->value[1] != -1 )
&& ( scroll->pIndexData->vnum == OBJ_VNUM_SCROLL_SCRIBING ) )
{
send_to_char( "That scroll has already been inscribed.\n\r", ch);
return;
}
found = FALSE;
for (pen = ch->first_carrying; pen; pen=pen->next_content)
if ((pen->item_type == ITEM_PEN) && (IS_OBJ_STAT(pen, ITEM_MAGIC))) {
found = TRUE;
break;
}
if (!found) {
send_to_char( "You must have a magical pen to scribe.\n\r", ch);
return;
}
if ( !process_spell_components( ch, sn ) )
{
learn_from_failure( ch, gsn_scribe );
ch->mana -= (mana / 2);
ch->in_room->area->weather->mana += (int)mana/10;
return;
}
if ( !can_use_skill(ch, number_percent(), gsn_scribe ) )
{
set_char_color ( AT_MAGIC, ch );
send_to_char("You failed.\n\r", ch);
learn_from_failure( ch, gsn_scribe );
ch->mana -= (mana / 2);
ch->in_room->area->weather->mana += (int)mana/10;
return;
}
scroll->value[1] = sn;
sprintf(buf1, "%s scroll", skill_table[sn]->name);
STRFREE(scroll->short_descr);
scroll->short_descr = STRALLOC( aoran(buf1) );
sprintf(buf2, "A glowing scroll inscribed '%s' lies in the dust.",
skill_table[sn]->name);
STRFREE(scroll->description);
scroll->description = STRALLOC(buf2);
sprintf(buf3, "scroll scribing %s", skill_table[sn]->name);
STRFREE(scroll->name);
scroll->name = STRALLOC(buf3);
act( AT_MAGIC, "$n magically scribes $p.", ch,scroll, NULL, TO_ROOM );
act( AT_MAGIC, "You magically scribe $p.", ch,scroll, NULL, TO_CHAR );
learn_from_success( ch, gsn_scribe );
ch->mana -= mana;
ch->in_room->area->weather->mana += (int)mana/10;
}
void do_brew( CHAR_DATA *ch, char *argument )
{
OBJ_DATA *potion;
OBJ_DATA *fire;
int sn;
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char buf3[MAX_STRING_LENGTH];
int mana;
bool found;
if ( IS_NPC(ch) )
return;
if ( !skill_available(ch, gsn_brew) )
{
send_to_char( "A skill such as this requires more magical ability than you have.\n\r", ch );
return;
}
if ( argument[0] == '\0' || !str_cmp(argument, "") )
{
send_to_char( "Brew what?\n\r", ch );
return;
}
if ( ms_find_obj(ch) )
return;
if ( (sn = find_spell( ch, argument, TRUE )) < 0 )
{
send_to_char( "You have not learned that spell.\n\r", ch );
return;
}
if ( skill_table[sn]->spell_fun == spell_null )
{
send_to_char( "That's not a spell!\n\r", ch );
return;
}
if ( SPELL_FLAG(skill_table[sn], SF_NOBREW) )
{
send_to_char( "You cannot brew that spell.\n\r", ch );
return;
}
mana = IS_NPC(ch) ? 0 : UMAX(skill_table[sn]->min_mana,
100 / ( 100 - skill_table[sn]->skill_level[get_best_talent(ch, sn)] ));
mana *=4;
if ( !IS_NPC(ch) && ch->mana < mana )
{
send_to_char( "You don't have enough mana.\n\r", ch );
return;
}
found = FALSE;
for ( fire = ch->in_room->first_content; fire;
fire = fire->next_content )
{
if( fire->item_type == ITEM_FIRE)
{
found = TRUE;
break;
}
}
if ( !found )
{
send_to_char(
"There must be a fire in the room to brew a potion.\n\r", ch );
return;
}
if ( ( potion = get_eq_char( ch, WEAR_HAND ) ) == NULL )
{
send_to_char(
"You must be holding an empty flask to brew a potion.\n\r", ch );
return;
}
if( potion->pIndexData->vnum != OBJ_VNUM_EMPTY_FLASK )
{
send_to_char( "You must be holding an empty flask to brew a potion.\n\r", ch );
return;
}
if ( ( potion->value[1] != -1 )
&& ( potion->pIndexData->vnum == OBJ_VNUM_EMPTY_FLASK ) )
{
send_to_char( "That's not an empty flask.\n\r", ch);
return;
}
if ( !process_spell_components( ch, sn ) )
{
learn_from_failure( ch, gsn_brew );
ch->mana -= (mana / 2);
ch->in_room->area->weather->mana += (int)mana/10;
return;
}
if ( !can_use_skill(ch, number_percent(), gsn_brew ) )
{
set_char_color ( AT_MAGIC, ch );
send_to_char("You failed.\n\r", ch);
learn_from_failure( ch, gsn_brew );
ch->mana -= (mana / 2);
ch->in_room->area->weather->mana += (int)mana/10;
return;
}
potion->value[1] = sn;
sprintf(buf1, "%s potion", skill_table[sn]->name);
STRFREE(potion->short_descr);
potion->short_descr = STRALLOC( aoran(buf1) );
sprintf(buf2, "A strange potion labelled '%s' sizzles in a glass flask.",
skill_table[sn]->name);
STRFREE(potion->description);
potion->description = STRALLOC(buf2);
sprintf(buf3, "flask potion %s", skill_table[sn]->name);
STRFREE(potion->name);
potion->name = STRALLOC(buf3);
act( AT_MAGIC, "$n brews up $p.", ch,potion, NULL, TO_ROOM );
act( AT_MAGIC, "You brew up $p.", ch,potion, NULL, TO_CHAR );
learn_from_success( ch, gsn_brew );
ch->mana -= mana;
ch->in_room->area->weather->mana += (int)mana/10;
}
bool check_grip( CHAR_DATA *ch, CHAR_DATA *victim )
{
int chance;
if ( !IS_AWAKE(victim) )
return FALSE;
if ( IS_NPC(victim) && !xIS_SET(victim->defenses, DFND_GRIP) )
return FALSE;
if ( IS_NPC(victim) )
chance = UMIN( 60,100 );
else
chance = (int) (LEARNED(victim, gsn_grip) / 2);
/* Consider luck as a factor */
chance += (2 * (get_curr_lck(victim) /10 ) );
if ( number_percent( ) >= chance + number_percent() )
{
learn_from_failure( victim, gsn_grip );
return FALSE;
}
act( AT_SKILL, "You evade $n's attempt to disarm you.", ch, NULL, victim, TO_VICT );
act( AT_SKILL, "$N holds $S weapon strongly, and is not disarmed.",
ch, NULL, victim, TO_CHAR );
learn_from_success( victim, gsn_grip );
return TRUE;
}
bool check_illegal_psteal( CHAR_DATA *ch, CHAR_DATA *victim )
{
if (!IS_NPC (victim) && !IS_NPC(ch))
{
if (xIS_SET(ch->act, PLR_AFK))
{
/*sprintf( log_buf, "%s illegally stealing from %s at %d",
(IS_NPC(ch) ? ch->short_descr : ch->name),
victim->name,
victim->in_room->vnum );
log_string( log_buf );
to_channel( log_buf, CHANNEL_MONITOR, "Monitor", PERMIT_SECURITY );
xSET_BIT(ch->act, PLR_THIEF);
*/
return TRUE;
}
}
return FALSE;
}
void do_guard( CHAR_DATA *ch, char *argument )
{
if (!IS_SET(ch->mood, MOOD_GUARD)) {
SET_BIT(ch->mood, MOOD_GUARD);
act( AT_SKILL, "You stand in a ready posture, prepared to defend against intruders.", ch, NULL, NULL, TO_CHAR);
act( AT_SKILL, "$n stands in a ready posture, prepared to defend against intruders.", ch, NULL, NULL, TO_ROOM);
} else {
REMOVE_BIT(ch->mood, MOOD_GUARD);
act( AT_SKILL, "You stand down from your defensive posture.", ch, NULL, NULL, TO_CHAR);
act( AT_SKILL, "$n stands down from $s defensive posture.", ch, NULL, NULL, TO_ROOM);
}
}
void do_scan( CHAR_DATA *ch, char *argument )
{
ROOM_INDEX_DATA *was_in_room;
EXIT_DATA *pexit;
sh_int dir = -1;
sh_int dist;
sh_int max_dist = 8;
set_char_color( AT_ACTION, ch );
if ( IS_AFFECTED(ch, AFF_BLIND) && !IS_AFFECTED(ch, AFF_TRUESIGHT) )
{
send_to_char( "Not very effective when you can't see...\n\r", ch );
return;
}
if ( argument[0] == '\0' )
{
send_to_char( "Scan in a direction...\n\r", ch );
return;
}
if ( ( dir = get_door( argument ) ) == -1 )
{
send_to_char( "Scan in WHAT direction?\n\r", ch );
return;
}
was_in_room = ch->in_room;
act( AT_GREY, "Scanning $t...", ch, dir_name[dir], NULL, TO_CHAR );
act( AT_GREY, "$n scans $t.", ch, dir_name[dir], NULL, TO_ROOM );
if ( !can_use_skill(ch, number_percent(), gsn_scan ) )
{
act( AT_GREY, "You stop scanning $t as your vision blurs.", ch,
dir_name[dir], NULL, TO_CHAR );
learn_from_failure( ch, gsn_scan );
return;
}
if ( ( pexit = get_exit( ch->in_room, dir ) ) == NULL )
{
act( AT_GREY, "You can't see $t.", ch, dir_name[dir], NULL, TO_CHAR );
return;
}
max_dist -= (100 - get_curr_per(ch))/10;
for ( dist = 1; dist <= max_dist; )
{
if ( IS_SET(pexit->exit_info, EX_CLOSED) )
{
if ( IS_SET(pexit->exit_info, EX_SECRET)
|| IS_SET(pexit->exit_info, EX_DIG) )
act( AT_GREY, "Your view $t is blocked by a wall.", ch,
dir_name[dir], NULL, TO_CHAR );
else
act( AT_GREY, "Your view $t is blocked by a door.", ch,
dir_name[dir], NULL, TO_CHAR );
break;
}
if ( room_is_private( pexit->to_room ) )
{
act( AT_GREY, "Your view $t is blocked by a private room.", ch,
dir_name[dir], NULL, TO_CHAR );
break;
}
char_from_room( ch );
char_to_room( ch, pexit->to_room );
set_char_color( AT_WHITE, ch );
send_to_char( ch->in_room->name, ch );
send_to_char( "\n\r", ch );
show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE );
show_char_to_char( ch->in_room->first_person, ch );
switch( ch->in_room->sector_type )
{
default: dist++; break;
case SECT_AIR:
if ( number_percent() < 80 ) dist++; break;
case SECT_INSIDE:
case SECT_FIELD:
case SECT_UNDERGROUND:
dist++; break;
case SECT_FOREST:
case SECT_CITY:
case SECT_DESERT:
case SECT_HILLS:
dist += 2; break;
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
dist += 3; break;
case SECT_MOUNTAIN:
case SECT_UNDERWATER:
case SECT_OCEANFLOOR:
dist += 4; break;
}
if ( dist >= max_dist )
{
act( AT_GREY, "Your vision blurs with distance and you see no "
"farther $t.", ch, dir_name[dir], NULL, TO_CHAR );
break;
}
if ( ( pexit = get_exit( ch->in_room, dir ) ) == NULL )
{
act( AT_GREY, "Your view $t is blocked by a wall.", ch,
dir_name[dir], NULL, TO_CHAR );
break;
}
}
char_from_room( ch );
char_to_room( ch, was_in_room );
learn_from_success( ch, gsn_scan );
return;
}
/*
* Basically the same guts as do_scan() from above (please keep them in
* sync) used to find the victim we're firing at. -Thoric
*/
CHAR_DATA *scan_for_victim( CHAR_DATA *ch, EXIT_DATA *pexit, char *name )
{
CHAR_DATA *victim;
ROOM_INDEX_DATA *was_in_room;
sh_int dist, dir;
sh_int max_dist = 8;
if ( IS_AFFECTED(ch, AFF_BLIND) || !pexit )
return NULL;
was_in_room = ch->in_room;
/* Keo wanted a perception stat.. I now see why :) -- Scion */
max_dist -= (100 - get_curr_per(ch)) / 10;
for ( dist = 1; dist <= max_dist; )
{
if ( IS_SET(pexit->exit_info, EX_CLOSED) )
break;
if ( room_is_private( pexit->to_room ) )
break;
char_from_room( ch );
char_to_room( ch, pexit->to_room );
if ( (victim=get_char_room(ch, name)) != NULL )
{
char_from_room(ch);
char_to_room(ch, was_in_room);
return victim;
}
switch( ch->in_room->sector_type )
{
default: dist++; break;
case SECT_AIR:
if ( number_percent() < 80 ) dist++; break;
case SECT_INSIDE:
case SECT_FIELD:
case SECT_UNDERGROUND:
dist++; break;
case SECT_FOREST:
case SECT_CITY:
case SECT_DESERT:
case SECT_HILLS:
dist += 2; break;
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
dist += 3; break;
case SECT_MOUNTAIN:
case SECT_UNDERWATER:
case SECT_OCEANFLOOR:
dist += 4; break;
}
if ( dist >= max_dist )
break;
dir = pexit->vdir;
if ( (pexit=get_exit(ch->in_room, dir)) == NULL )
break;
}
char_from_room(ch);
char_to_room(ch, was_in_room);
return NULL;
}
/*
* Search inventory for an appropriate projectile to fire.
* Also search open quivers. -Thoric
*/
OBJ_DATA *find_projectile( CHAR_DATA *ch, int type )
{
OBJ_DATA *obj, *obj2;
for ( obj = ch->last_carrying; obj; obj = obj->prev_content )
{
if ( can_see_obj(ch, obj) )
{
if ( obj->item_type == ITEM_QUIVER && !IS_SET(obj->value[1], CONT_CLOSED) )
{
for ( obj2 = obj->last_content; obj2; obj2 = obj2->prev_content )
{
if ( obj2->item_type == ITEM_PROJECTILE
&& obj2->value[3] == type )
return obj2;
}
}
if ( obj->item_type == ITEM_PROJECTILE && obj->value[3] == type )
return obj;
}
}
return NULL;
}
ch_ret spell_attack( int, int, CHAR_DATA *, void * );
/*
* Perform the actual attack on a victim -Thoric
*/
ch_ret ranged_got_target( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *weapon,
OBJ_DATA *projectile, sh_int dist, sh_int dt, char *stxt, sh_int color )
{
if ( IS_SET(ch->in_room->room_flags, ROOM_SAFE) )
{
/* safe room, bubye projectile */
if ( projectile )
{
ch_printf(ch, "Your %s is blasted from existence by a mystical force.",
myobj(projectile) );
act( color, "A mystical force smites $p!", ch, projectile, NULL, TO_ROOM );
extract_obj(projectile);
}
else
{
ch_printf(ch, "Your %s is blasted from existence by a mystical force.",
stxt );
act( color, "A mystical force smites $t!", ch, aoran(stxt), NULL, TO_ROOM );
}
return rNONE;
}
if (victim == ch) {
act(AT_MAGIC, "Your magic fizzles.", ch, NULL, NULL, TO_CHAR);
return rNONE;
}
if ( number_percent() > 50 || (projectile && weapon
&& can_use_skill(ch, number_percent(), 100)) )
{
global_retcode = spell_attack( dt, get_curr_wil(ch),ch, victim );
}
else
{
if ( projectile )
{
/* 50% chance of getting lost */
if ( number_percent() < 50 && projectile->item_type == ITEM_PROJECTILE)
extract_obj(projectile);
else
{
if ( projectile->in_obj )
obj_from_obj(projectile);
if ( projectile->carried_by )
obj_from_char(projectile);
obj_to_room(projectile, victim->in_room);
}
}
}
return global_retcode;
}
/* New check to see if you can use skills to support morphs --Shaddai */
bool can_use_skill( CHAR_DATA *ch, int percent, int gsn )
{
bool check = FALSE;
if ( IS_NPC(ch) && percent < 85 ) check = TRUE;
else if ( !IS_NPC(ch) && percent < LEARNED(ch, gsn) ) check = TRUE;
return check;
}
/* Alchemy: Mix two items together to produce a third item -keo */
void do_mix(CHAR_DATA *ch, char *argument) {
OBJ_DATA *first;
OBJ_DATA *second;
OBJ_DATA *obj;
RECIPE_DATA *recipe;
char arg1[MAX_INPUT_LENGTH];
bool found;
OBJ_DATA *drinkcon = NULL;
argument = one_argument(argument, arg1);
/* Do we have the ingredients? */
first = get_obj_carry(ch, arg1);
if (!first) {
send_to_char("You don't have that.\n\r", ch);
return;
}
second = get_obj_carry(ch, argument);
if (!second) {
send_to_char("You don't have that.\n\r", ch);
return;
}
/* Now that we have the ingredients, see if there's a recipe to match */
recipe = first_recipe;
while (recipe) {
if (recipe->ingred1 == first->pIndexData->vnum
&& recipe->ingred2 == second->pIndexData->vnum)
break;
if (recipe == last_recipe) {
send_to_char("Nothing happens.\n\r", ch);
return;
}
recipe = recipe->next;
}
if (!recipe) return;
/* We found the recipe, now make sure we have anything we need */
/* Check non obvious ones first, so they think there isn't a recipe */
if (IS_SET(recipe->flags, RECIPE_LIGHT)) {
if (get_light_room(ch->in_room) < 10) {
send_to_char("Nothing happens.\n\r", ch);
return;
}
}
if (IS_SET(recipe->flags, RECIPE_DARK)) {
if (get_light_room(ch->in_room) > -10) {
send_to_char("Nothing happens.\n\r", ch);
return;
}
}
/* Now check obvious ones */
if (IS_SET(recipe->flags, RECIPE_FIRE)) {
found = FALSE;
for (obj = ch->in_room->first_content; obj;
obj = obj->next_content) {
if (obj->item_type == ITEM_FIRE) {
found = TRUE;
break;
}
}
if (!found) {
send_to_char(
"There must be a fire in the room to use this recipe.\n\r", ch);
return;
}
}
if (IS_SET(recipe->flags, RECIPE_WATER)) {
found = FALSE;
if (ch->in_room->curr_water > 50)
found = TRUE;
else
for (obj = ch->in_room->first_content; obj;
obj = obj->next_content) {
if (obj->item_type == ITEM_FOUNTAIN) {
found = TRUE;
break;
}
}
if (!found) {
send_to_char(
"There must be a source of water in the room to use this recipe.\n\r", ch);
return;
}
}
if (IS_SET(recipe->flags, RECIPE_BLOOD)) {
found = FALSE;
for (obj = ch->in_room->first_content; obj;
obj = obj->next_content) {
if (obj->item_type == ITEM_BLOOD) {
found = TRUE;
break;
}
}
if (!found) {
send_to_char(
"There must fresh blood spilled in the room to use this recipe.\n\r", ch);
return;
}
}
if (IS_SET(recipe->flags, RECIPE_DRINKCON)) {
found = FALSE;
for (obj = ch->first_carrying; obj;
obj = obj->next_content) {
if (obj->item_type == ITEM_DRINK_CON) {
found = TRUE;
drinkcon = obj;
break;
}
}
if (!found) {
send_to_char(
"You must have a drink container to mix this recipe in.\n\r", ch);
return;
}
}
if (IS_SET(recipe->flags, RECIPE_ICE)) {
if (ch->in_room->area->weather->temp > -200
&& ch->curr_talent[TAL_FROST] < 20) {
send_to_char(
"You must have ice available to make this recipe.\n\r", ch);
return;
}
}
if (IS_SET(recipe->flags, RECIPE_KNIFE)) {
found = FALSE;
if (can_use_bodypart(ch, BP_CLAWS))
found = TRUE;
else
for (obj = ch->first_carrying; obj;
obj = obj->next_content) {
if (obj->item_type == ITEM_WEAPON
&& (obj->value[5] == 1
|| obj->value[5] == 2)) {
found = TRUE;
break;
}
}
if (!found) {
send_to_char(
"You must have a cutting implement to use this recipe.\n\r", ch);
return;
}
}
/* Everything in check, now put them together and give you the result */
if (!get_obj_index(recipe->result)) {
bug("Do_mix: can't find vnum for result on recipe %d", recipe->number);
send_to_char("Something went wrong somewhere...\n\r", ch);
return;
}
separate_obj(first);
separate_obj(second);
if (drinkcon) separate_obj(drinkcon);
learn_noncombat(ch, SK_ALCHEMY);
/* Did it work or not? */
if ( number_range(1,30) < number_range(1,ch->pcdata->noncombat[SK_ALCHEMY])) {
obj = create_object( get_obj_index( recipe->result ), 0 );
act(AT_SKILL, "$n mixes some ingredients to create $p.", ch, obj, NULL, TO_ROOM);
ch_printf(ch, "&GYou mix %s and %s, to create %s!\n\r",
first->short_descr, second->short_descr,
obj->short_descr);
obj_to_char(obj, ch);
if (drinkcon) extract_obj(drinkcon);
learn_from_success(ch, gsn_mix);
} else {
act(AT_SKILL, "$n messes up a recipe.", ch, NULL, NULL, TO_ROOM);
act(AT_SKILL, "You screw up the recipe somewhere and end up with an awful mess.", ch, NULL, NULL, TO_CHAR);
learn_from_failure(ch, gsn_mix);
}
obj_from_char(first);
obj_from_char(second);
extract_obj(first);
extract_obj(second);
}
void do_engrave(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
char arg[MAX_STRING_LENGTH];
char buf[MAX_STRING_LENGTH];
extern sh_int gsn_engrave;
/* engrave <obj> <string> */
argument=one_argument(argument, arg);
obj=get_obj_carry(ch, arg);
if (!obj) {
send_to_char("What object do you want to engrave?\r\n", ch);
return;
}
separate_obj(obj);
if (strlen(argument) > obj->weight*3) {
send_to_char("That won't fit on that item, please try something shorter.\r\n", ch);
return;
}
if (strlen(argument) < 2) {
send_to_char("What do you want to engrave on your item?\r\n", ch);
return;
}
if (!IS_OBJ_STAT(obj, ITEM_METAL)) {
send_to_char("You can only engrave metal items.\r\n", ch);
return;
}
if (IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
send_to_char("There is no way you can even leave a scratch on that item!\r\n", ch);
return;
}
if (nifty_is_name("named", obj->short_descr)) {
send_to_char("That item has already been engraved.\r\n", ch);
return;
}
/* Scramble their text if they fail their skill roll. Mwahaha! -- Scion */
if (!IS_NPC(ch) && number_percent() + skill_table[gsn_engrave]->difficulty * 5 > LEARNED(ch, gsn_engrave)) {
argument = scramble(argument, LEARNED(ch, gsn_engrave));
learn_from_failure(ch, gsn_engrave);
}
act(AT_SKILL, "You engrave $p.", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n engraves $p.", ch, obj, NULL, TO_ROOM);
/* change the namelist */
strcpy(buf, obj->name);
strcat(buf, " ");
strcat(buf, argument);
STRFREE(obj->name);
obj->name = STRALLOC(buf);
/* change the short desc */
strcpy(buf, obj->short_descr);
strcat(buf, " named '");
strcat(buf, argument);
strcat(buf, "&w'");
STRFREE(obj->short_descr);
obj->short_descr=STRALLOC(buf);
learn_from_success(ch, gsn_engrave);
}
void do_combine(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
OBJ_DATA *obj2;
char arg[MAX_STRING_LENGTH];
char arg2[MAX_STRING_LENGTH];
char buf[MAX_STRING_LENGTH];
AFFECT_DATA *paf;
extern sh_int gsn_combine;
int div;
STRFREE(ch->last_taken);
ch->last_taken = STRALLOC("combining ores");
if (!can_use_bodypart(ch, BP_RHAND)) {
send_to_char("That would be hard without functional hands.\n\r", ch);
return;
}
/* combine <ore> <other ore> */
argument=one_argument(argument, arg);
argument=one_argument(argument, arg2);
obj=get_obj_carry(ch, arg);
if (!obj) {
send_to_char("Which raw materials do you want to combine?\r\n", ch);
return;
}
separate_obj(obj);
obj_from_char(obj); /* in case arg and arg2 are the same */
obj2=get_obj_carry(ch, arg2);
if (!obj2) {
send_to_char("What raw material do you want to add to the first one?\r\n", ch);
obj_to_char(obj, ch);
return;
}
if (obj->item_type != ITEM_TREASURE
|| obj2->item_type != ITEM_TREASURE) {
send_to_char("You may only combine raw materials.\r\n", ch);
obj_to_char(obj, ch);
return;
}
if (IS_OBJ_STAT(obj, ITEM_GEM) || IS_OBJ_STAT(obj2, ITEM_GEM)) {
send_to_char("Use AFFIX to affix gems to items.\n\r", ch);
obj_to_char(obj, ch);
return;
}
if ((IS_OBJ_STAT(obj, ITEM_METAL) && (IS_OBJ_STAT(obj2, ITEM_ORGANIC)))
|| (IS_OBJ_STAT(obj, ITEM_ORGANIC) && (IS_OBJ_STAT(obj2, ITEM_METAL)))) {
send_to_char("You can only combine metals with metals, or nonmetals with nonmetals.\r\n", ch);
obj_to_char(obj, ch);
return;
}
if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD)
|| IS_OBJ_STAT(obj2, ITEM_DREAMWORLD)) {
send_to_char("Your ore is too insubstantial!\n\r", ch);
return;
}
if (obj==obj2) {
send_to_char("You cannot combine a material with itself.\r\n", ch);
obj_to_char(obj, ch);
return;
}
separate_obj(obj2);
obj_from_char(obj2);
if (IS_OBJ_STAT(obj, ITEM_METAL)) {
learn_noncombat(ch, SK_SMITH);
WAIT_STATE(ch, (100 - ch->pcdata->noncombat[SK_SMITH])/5);
} else {
learn_noncombat(ch, SK_TAILOR);
WAIT_STATE(ch, (100 - ch->pcdata->noncombat[SK_TAILOR])/5);
}
/* Take away their ore if they fail their skill roll. Mwahaha! -- Scion */
if (!IS_NPC(ch) && number_percent() +
skill_table[gsn_combine]->difficulty * 5 > LEARNED(ch, gsn_combine)) {
act(AT_SKILL, "You fail to combine your raw materials properly, rendering the alloy unusable.", ch, NULL, NULL, TO_CHAR);
learn_from_failure(ch, gsn_combine);
extract_obj(obj);
extract_obj(obj2);
return;
} else {
act(AT_SKILL, "You combine your two materials.", ch, obj, NULL, TO_CHAR);
}
act(AT_SKILL, "$n combines some materials.", ch, obj, NULL, TO_ROOM);
/* combine the stats of the two ores if they're different kinds */
if (obj->weight < obj2->weight) {
strcpy(buf, obj2->name);
STRFREE(obj->name);
obj->name=STRALLOC(buf);
strcpy(buf, obj2->short_descr);
STRFREE(obj->short_descr);
obj->short_descr=STRALLOC(buf);
strcpy(buf, obj2->description);
STRFREE(obj->description);
obj->description=STRALLOC(buf);
obj->extra_flags=obj2->extra_flags;
obj->material=obj2->material;
}
div = (obj->weight + obj2->weight) / obj->weight;
obj->weight += obj2->weight;
obj->cost += obj2->cost;
obj->condition = number_fuzzy(obj->weight*50);
if (div <= 1) div = 2;
for (paf = obj->first_affect;paf;) {
AFFECT_DATA *npaf;
npaf = paf->next;
if (paf->location != APPLY_RESISTANT
&& paf->location != APPLY_AFFECT) {
int oldmod;
oldmod = paf->modifier;
paf->modifier /= div;
obj->cost -= 50000 * oldmod - paf->modifier;
if (paf->modifier == 0) {
UNLINK(paf, obj->first_affect, obj->last_affect, next, prev);
DISPOSE(paf);
}
}
paf=npaf;
}
div = obj->weight / obj2->weight;
if (div <= 1) div = 2;
for (paf = obj2->first_affect;paf;) {
AFFECT_DATA *npaf;
npaf = paf->next;
if (paf->location != APPLY_RESISTANT
&& paf->location != APPLY_AFFECT) {
paf->modifier /= div;
if (paf->modifier == 0) {
UNLINK(paf, obj2->first_affect, obj2->last_affect, next, prev);
DISPOSE(paf);
}
}
paf=npaf;
}
/* transfer obj2's aff list to obj and clear the pointers off obj2 */
if (!obj->last_affect && obj2->last_affect) {
obj->first_affect = obj2->first_affect;
obj->last_affect = obj2->last_affect;
obj2->first_affect = NULL;
obj2->last_affect = NULL;
} else if (obj->last_affect && obj2->first_affect) {
obj->last_affect->next = obj2->first_affect;
obj2->first_affect->prev = obj->last_affect;
obj->last_affect = obj2->last_affect;
obj2->first_affect = NULL;
obj2->last_affect = NULL;
}
obj->mana += obj2->mana;
obj->raw_mana += obj2->raw_mana;
/* Balancing: Weaken the effects on the ore based off weight
* instead of a random roll.
*/
obj->mana /= div;
obj->raw_mana /= div;
obj_to_char(obj, ch);
extract_obj(obj2);
if (obj->cost < 1) obj->cost = 1;
obj->cost += obj->material->cost / obj->material->weight * obj->weight;
learn_from_success(ch, gsn_combine);
}
void do_spike(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj = NULL;
OBJ_DATA *obj2 = NULL;
AFFECT_DATA *paf;
char arg[MAX_STRING_LENGTH];
char arg2[MAX_STRING_LENGTH];
extern int top_affect;
extern sh_int gsn_spike;
/* spike <obj> <ore> */
argument=one_argument(argument, arg);
argument=one_argument(argument, arg2);
obj=get_obj_carry(ch, arg);
if (!obj) {
send_to_char("Which piece of equipment do you want to add spikes to?\r\n", ch);
return;
}
separate_obj(obj);
obj2=get_obj_carry(ch, arg2);
if (!obj2) {
obj_to_char(obj, ch);
send_to_char("What raw material do you want to use to make the spikes?\r\n", ch);
return;
}
separate_obj(obj2);
if (nifty_is_name("spiked", obj->short_descr)) {
send_to_char("That item already has spikes.\r\n", ch);
return;
}
if (!nifty_is_name("_material_", obj2->name)) {
send_to_char("You must use a raw material to make spikes with.\r\n", ch);
return;
}
if (IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
send_to_char("You cannot seem to make the spikes stick to that.\r\n", ch);
return;
}
if (!IS_OBJ_STAT(obj2, ITEM_METAL)) {
send_to_char("You can only make spikes out of metal.\r\n", ch);
return;
}
if (obj->item_type != ITEM_ARMOR
&& (obj->item_type == ITEM_WEAPON
&& obj->value[3] != DAM_HIT
&& obj->value[3] != DAM_POUND
&& obj->value[3] != DAM_CRUSH
&& obj->value[3] != DAM_GREP
)) {
send_to_char("You can't add spikes to that.\r\n",ch);
return;
}
if (obj==obj2) {
send_to_char("You need two objects to add spikes to armor.\r\n", ch);
return;
}
obj_from_char(obj);
obj_from_char(obj2);
/* Take away their ore if they fail their skill roll. Mwahaha! -- Scion */
if (!IS_NPC(ch) && number_percent() + skill_table[gsn_spike]->difficulty * 5 > LEARNED(ch, gsn_spike)) {
act(AT_SKILL, "You cannot seem to form spikes from $p.", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n fails to add spikes to $p.", ch, obj, NULL, TO_ROOM);
learn_from_failure(ch, gsn_spike);
obj->weight++; /* residue left over from botched spikes, no condition bonus */
obj_to_char(obj, ch);
extract_obj(obj2);
return;
}
act(AT_SKILL, "You add spikes to $p.", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n adds spikes to $p.", ch, obj, NULL, TO_ROOM);
/* add +1 dr to obj and the word 'spiked' to the names */
if (!nifty_is_name("spiked", obj->name)) {
char name_string[MAX_STRING_LENGTH];
strcpy(name_string, obj->name);
strcat(name_string, " spiked");
STRFREE(obj->name);
obj->name = STRALLOC(name_string);
obj->short_descr = one_argument(obj->short_descr, name_string);
if (!strcmp(name_string, "some"))
strcpy(name_string, "some spiked ");
else
strcpy(name_string, "spiked ");
strcat(name_string, obj->short_descr);
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC(aoran(name_string));
obj->description = one_argument(obj->description, name_string);
if (!strcmp(name_string, "some"))
strcpy(name_string, "some spiked ");
else
strcpy(name_string, "spiked ");
strcat(name_string, obj->description);
STRFREE(obj->description);
obj->description = STRALLOC(capitalize(aoran(name_string)));
}
/* Transfer affects if skill rolls succeed and diff material types */
if (obj->material != NULL && obj2->material != NULL
&& obj->material != obj2->material ) {
for (paf=obj2->first_affect; paf; paf=paf->next) {
if (number_percent() < LEARNED(ch, gsn_combine)) {
UNLINK(paf, obj2->first_affect, obj2->last_affect, next, prev);
LINK(paf, obj->first_affect, obj->last_affect, next, prev);
}
}
}
/* Success: Add +1 dr affect and -1 dex */
if (number_percent() + skill_table[gsn_spike]->difficulty * 5 <= LEARNED(ch, gsn_spike)) {
bool found=FALSE;
/* Success: Add +1 dr affect */
for (paf = obj->first_affect; paf; paf=paf->next) {
if (paf->location == APPLY_DAMROLL && !found) {
paf->modifier++;
found=TRUE;
}
}
if (!found) {
CREATE(paf, AFFECT_DATA, 1);
paf->type = -1;
paf->duration = -1;
paf->location = APPLY_DAMROLL;
paf->modifier = 1;
xCLEAR_BITS(paf->bitvector);
paf->next = NULL;
LINK(paf, obj->first_affect, obj->last_affect, next, prev);
++top_affect;
}
found = FALSE;
for (paf = obj->first_affect; paf; paf=paf->next) {
if (paf->location == APPLY_DEX && !found) {
paf->modifier--;
if (paf->modifier==0) {
UNLINK(paf, obj->first_affect, obj->last_affect, next, prev);
DISPOSE(paf);
}
found=TRUE;
}
}
if (!found) {
CREATE(paf, AFFECT_DATA, 1);
paf->type = -1;
paf->duration = -1;
paf->location = APPLY_DEX;
paf->modifier = -1;
xCLEAR_BITS(paf->bitvector);
paf->next = NULL;
LINK(paf, obj->first_affect, obj->last_affect, next, prev);
++top_affect;
}
}
obj->weight++; /* Always add to weight.. spikes are heavy :) */
obj_to_char(obj, ch);
extract_obj(obj2);
learn_from_success(ch, gsn_spike);
}
void do_dye(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
char arg[MAX_STRING_LENGTH];
char arg2[MAX_STRING_LENGTH];
char buf[MAX_STRING_LENGTH];
int color;
extern sh_int gsn_dye;
/* spike <obj> <ore> */
argument=one_argument(argument, arg);
argument=one_argument(argument, arg2);
obj=get_obj_carry(ch, arg);
if (!obj) {
send_to_char("Which piece of clothing do you want to change the color of?\r\n", ch);
return;
}
color=0;
if (!strcmp(arg2, "red"))
color = 1;
else if (!strcmp(arg2, "yellow"))
color = 2;
else if (!strcmp(arg2, "blue"))
color = 3;
else if (!strcmp(arg2, "black"))
color = 4;
else if (!strcmp(arg2, "white"))
color = 5;
if (color==0) {
send_to_char("Valid colors are: red, yellow, blue, black, and white.\r\n", ch);
return;
}
separate_obj(obj);
if (IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
send_to_char("That's colorful enough as it is.\r\n", ch);
return;
}
if (!IS_OBJ_STAT(obj, ITEM_ORGANIC)) {
send_to_char("You can only dye cloth.\r\n", ch);
return;
}
/* Produce unpredictable results for a failed roll! -- Scion */
if (!IS_NPC(ch) && number_percent() + skill_table[gsn_dye]->difficulty * 5 > LEARNED(ch, gsn_dye)) {
act(AT_SKILL, "You seem to have mixed the dyes incorrectly.", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n seems to have mixed $s dyes incorrectly.", ch, obj, NULL, TO_ROOM);
/* Get rid of the color codes in the object's description, if any */
strcpy(buf, munch_colors(obj->short_descr));
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC(buf);
color = number_range(1,16);
switch (color) {
case 1:
strcpy(buf, "&z");
break;
case 2:
strcpy(buf, "&g");
break;
case 3:
strcpy(buf, "&b");
break;
case 4:
strcpy(buf, "&c");
break;
case 5:
strcpy(buf, "&z");
break;
case 6:
strcpy(buf, "&G");
break;
case 7:
strcpy(buf, "&B");
break;
case 8:
strcpy(buf, "&C");
break;
case 9:
strcpy(buf, "&r");
break;
case 10:
strcpy(buf, "&O");
break;
case 11:
strcpy(buf, "&p");
break;
case 12:
strcpy(buf, "&w");
break;
case 13:
strcpy(buf, "&R");
break;
case 14:
strcpy(buf, "&Y");
break;
case 15:
strcpy(buf, "&P");
break;
case 16:
strcpy(buf, "&W");
break;
}
strcat(buf, obj->short_descr);
strcat(buf, "&w");
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC(buf);
learn_from_failure(ch, gsn_dye);
return;
}
act(AT_SKILL, "You dye $p.", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n dyes $p.", ch, obj, NULL, TO_ROOM);
/* If there's no color code already, just add one. Otherwise mix the colors!! */
if (obj->short_descr[0] != '&') {
/* Get rid of the color codes in the object's description, if any */
strcpy(buf, munch_colors(obj->short_descr));
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC(buf);
switch (color) {
case 1:
strcpy(buf, "&R");
break;
case 2:
strcpy(buf, "&Y");
break;
case 3:
strcpy(buf, "&B");
break;
case 4:
strcpy(buf, "&z");
break;
case 5:
strcpy(buf, "&W");
break;
}
strcat(buf, obj->short_descr);
strcat(buf, "&w");
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC(buf);
} else {
/*
&x - Black &r - Red (blood)
&g - Green &O - Orange (brown)
&b - Dark Blue &p - Purple
&c - Cyan &w - Gray (default color)
&z - Dark Grey &R - Light Red
&G - Light Green &Y - Yellow
&B - Blue &P - Pink
&C - Light Blue &W - White
*/
if (obj->short_descr[1] == 'g') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='O'; break;
case 2: /* yellow */
obj->short_descr[1]='G'; break;
case 3: /* blue */
obj->short_descr[1]='O'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='G'; break;
}
}
else if (obj->short_descr[1] == 'b') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='p'; break;
case 2: /* yellow */
obj->short_descr[1]='B'; break;
case 3: /* blue */
obj->short_descr[1]='b'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='B'; break;
}
}
else if (obj->short_descr[1] == 'c') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='P'; break;
case 2: /* yellow */
obj->short_descr[1]='G'; break;
case 3: /* blue */
obj->short_descr[1]='C'; break;
case 4: /* black */
obj->short_descr[1]='b'; break;
case 5: /* white */
obj->short_descr[1]='C'; break;
}
}
else if (obj->short_descr[1] == 'z') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='r'; break;
case 2: /* yellow */
obj->short_descr[1]='O'; break;
case 3: /* blue */
obj->short_descr[1]='b'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='w'; break;
}
}
else if (obj->short_descr[1] == 'G') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='O'; break;
case 2: /* yellow */
obj->short_descr[1]='Y'; break;
case 3: /* blue */
obj->short_descr[1]='C'; break;
case 4: /* black */
obj->short_descr[1]='g'; break;
case 5: /* white */
obj->short_descr[1]='G'; break;
}
}
else if (obj->short_descr[1] == 'B') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='p'; break;
case 2: /* yellow */
obj->short_descr[1]='G'; break;
case 3: /* blue */
obj->short_descr[1]='b'; break;
case 4: /* black */
obj->short_descr[1]='b'; break;
case 5: /* white */
obj->short_descr[1]='C'; break;
}
}
else if (obj->short_descr[1] == 'C') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='P'; break;
case 2: /* yellow */
obj->short_descr[1]='G'; break;
case 3: /* blue */
obj->short_descr[1]='B'; break;
case 4: /* black */
obj->short_descr[1]='b'; break;
case 5: /* white */
obj->short_descr[1]='C'; break;
}
}
else if (obj->short_descr[1] == 'r') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='r'; break;
case 2: /* yellow */
obj->short_descr[1]='R'; break;
case 3: /* blue */
obj->short_descr[1]='p'; break;
case 4: /* black */
obj->short_descr[1]='r'; break;
case 5: /* white */
obj->short_descr[1]='R'; break;
}
}
if (obj->short_descr[1] == 'O') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='O'; break;
case 2: /* yellow */
obj->short_descr[1]='O'; break;
case 3: /* blue */
obj->short_descr[1]='O'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='Y'; break;
}
}
else if (obj->short_descr[1] == 'p') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='r'; break;
case 2: /* yellow */
obj->short_descr[1]='P'; break;
case 3: /* blue */
obj->short_descr[1]='p'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='P'; break;
}
}
else if (obj->short_descr[1] == 'w') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='r'; break;
case 2: /* yellow */
obj->short_descr[1]='O'; break;
case 3: /* blue */
obj->short_descr[1]='b'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='w'; break;
}
}
else if (obj->short_descr[1] == 'R') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='r'; break;
case 2: /* yellow */
obj->short_descr[1]='O'; break;
case 3: /* blue */
obj->short_descr[1]='p'; break;
case 4: /* black */
obj->short_descr[1]='r'; break;
case 5: /* white */
obj->short_descr[1]='P'; break;
}
}
else if (obj->short_descr[1] == 'Y') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='O'; break;
case 2: /* yellow */
obj->short_descr[1]='Y'; break;
case 3: /* blue */
obj->short_descr[1]='G'; break;
case 4: /* black */
obj->short_descr[1]='O'; break;
case 5: /* white */
obj->short_descr[1]='Y'; break;
}
}
else if (obj->short_descr[1] == 'P') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='O'; break;
case 2: /* yellow */
obj->short_descr[1]='G'; break;
case 3: /* blue */
obj->short_descr[1]='O'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='G'; break;
}
}
else if (obj->short_descr[1] == 'W') {
switch (color) {
case 1: /* red */
obj->short_descr[1]='R'; break;
case 2: /* yellow */
obj->short_descr[1]='Y'; break;
case 3: /* blue */
obj->short_descr[1]='B'; break;
case 4: /* black */
obj->short_descr[1]='z'; break;
case 5: /* white */
obj->short_descr[1]='W'; break;
}
}
}
learn_from_success(ch, gsn_dye);
}
void do_affix(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
OBJ_DATA *gem;
char arg[MAX_STRING_LENGTH];
extern sh_int gsn_affix;
if (!can_use_bodypart(ch, BP_RHAND)) {
send_to_char("That would be hard without functional hands.\n\r", ch);
return;
}
/* affix <gem> <obj> */
argument=one_argument(argument, arg);
gem=get_obj_carry(ch, arg);
if (!gem) {
send_to_char("What gem do you want to affix?\r\n", ch);
return;
}
separate_obj(gem);
argument=one_argument(argument, arg);
obj=get_obj_carry(ch, arg);
if (!obj || obj == gem) {
send_to_char("What object do you want to affix gems to?\r\n", ch);
return;
}
separate_obj(obj);
if (!IS_OBJ_STAT(obj, ITEM_METAL)) {
send_to_char("You can only attach gems to metal items.\r\n", ch);
return;
}
if (obj->gem) {
send_to_char("That object already has a gem.\n\r", ch);
return;
}
if (!IS_OBJ_STAT(gem, ITEM_GEM)) {
send_to_char("You can only affix gems.\r\n", ch);
return;
}
if (IS_OBJ_STAT(gem, ITEM_DREAMWORLD)
&& !IS_OBJ_STAT(obj, ITEM_DREAMWORLD)) {
send_to_char("Your gem is insubstantial!\n\r", ch);
return;
}
if (obj->item_type == ITEM_TREASURE) {
send_to_char("You can only affix gems to the finished product.\n\r", ch);
return;
}
if (IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
send_to_char("The gem won't stick to that artifact.\r\n", ch);
return;
}
obj_from_char(gem);
obj_from_char(obj);
learn_noncombat(ch, SK_JEWEL);
/* Damage the object if they fail their skill roll. Mwahaha! -- Scion */
if (number_range(1,20) > LEARNED(ch, gsn_affix)) {
act(AT_SKILL, "The gem breaks!", ch, NULL, NULL, TO_CHAR);
act(AT_SKILL, "$n tries to affix a gem to $p, but it breaks.", ch, obj, NULL, TO_ROOM);
damage_obj(obj);
if (!obj_extracted(obj))
obj_to_char(obj, ch);
extract_obj(gem);
learn_from_failure(ch, gsn_affix);
return;
}
act(AT_SKILL, "You affix a gem to $p.", ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$n affixes a gem to $p.", ch, obj, NULL, TO_ROOM);
obj->gem = gem;
gem->in_obj = obj;
obj->cost += gem->cost;
obj_to_char(obj, ch);
learn_from_success(ch, gsn_affix);
}
void do_pry (CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
OBJ_DATA *gem;
obj = get_obj_carry(ch, argument);
if (!obj) {
send_to_char("You have nothing like that.\n\r", ch);
return;
}
if (!obj->gem) {
send_to_char("That object has no gem.\n\r", ch);
return;
}
gem = obj->gem;
obj->gem = NULL;
gem->in_obj = NULL;
obj->cost -= gem->cost;
obj_to_char(gem, ch);
learn_noncombat(ch, SK_JEWEL);
act(AT_SKILL, "You pry $p loose from $P.", ch, gem, obj, TO_CHAR);
act(AT_SKILL, "$n pries $p loose from $P.", ch, gem, obj, TO_ROOM);
}
/* Return the best talent for a char to use for a given sn */
int get_best_talent( CHAR_DATA *ch, int sn ) {
int i, best;
best = -1;
for (i = 0; i < MAX_DEITY; i++) {
if (ch->curr_talent[i] >= skill_table[sn]->skill_level[i]) {
if (ch->curr_talent[i] - skill_table[sn]->skill_level[i] > best)
best = i;
}
}
return best;
}
bool skill_available( CHAR_DATA *ch, int sn ) {
int talent;
if (sn < 0)
return FALSE;
talent = get_best_talent(ch, sn);
if ((skill_table[sn]->type != SKILL_SPELL
&& (skill_table[sn]->race_level[ch->race] == 1 /* innate */
|| skill_table[sn]->race_level[ch->race] == 2) /* can learn */
)
|| (skill_table[sn]->type == SKILL_SPELL && (talent > -1) && (skill_table[sn]->skill_level[talent] <= ch->curr_talent[talent]))
)
return TRUE;
else
return FALSE;
}
/* Trains another player up to 1/4 of your percentage in a skill -- Scion
train <victim> <skill>
*/
void do_train(CHAR_DATA *ch, char *argument) {
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
CHAR_DATA *victim;
int sn;
argument = one_argument(argument, arg1);
argument = one_argument(argument, arg2);
/* Find victim */
if ((victim = get_char_room(ch, arg1)) == NULL) {
send_to_char("They're not here.\r\n", ch);
return;
}
/* Look up skill */
if ((sn = bsearch_skill_prefix(arg2, gsn_first_spell, gsn_first_skill-1)) < 0) {
if ((sn = bsearch_skill_prefix(arg2, gsn_first_skill, gsn_top_sn-1)) < 0) {
send_to_char("That is not a skill or a spell.\r\n", ch);
return;
}
}
/* Does ch have skill, and does victim -not- have skill? */
if (LEARNED(ch, sn) < 1) {
send_to_char("You do not know that skill.\r\n", ch);
return;
}
if (LEARNED(victim, sn) > 0) {
send_to_char("They already know that skill.\r\n", ch);
return;
}
/* Can victim actually have this skill? */
if (skill_table[sn]->type == SKILL_SPELL) {
if (get_best_talent(ch, sn) == -1 || skill_table[sn]->race_level[victim->race] == 3) {
send_to_char("They are physically unable to do that.\r\n", ch);
return;
}
}
/* Give 1 to 1/4 LEARNED(ch, sn) to victim */
victim->pcdata->learned[sn] = number_range(1, (int)LEARNED(ch, sn) / 4);
/* Lower ch's mentalstate */
worsen_mental_state(ch, number_range(1, 25));
/* Print messages */
sprintf(buf, "You teach $N the art of %s.", skill_table[sn]->name);
act(AT_SKILL, buf, ch, NULL, victim, TO_CHAR);
sprintf(buf, "$n teaches you the art of %s.", skill_table[sn]->name);
act(AT_SKILL, buf, ch, NULL, victim, TO_VICT);
sprintf(buf, "$n teaches $N the art of %s.", skill_table[sn]->name);
act(AT_SKILL, buf, ch, NULL, victim, TO_NOTVICT);
send_to_char("You are a bit tired after the long lesson.\r\n", ch);
}
int learned(CHAR_DATA *ch, int sn) {
if (IS_NPC(ch))
return 80;
if (sn < 0)
return 0;
if (skill_available(ch, sn) == FALSE)
return 0;
if (skill_table[sn]->type == SKILL_SPELL)
return URANGE(0, ch->pcdata->learned[sn], 100);
else
switch (skill_table[sn]->race_level[ch->race]) {
case 1:
return 100;
break;
case 2:
return URANGE(0, ch->pcdata->learned[sn],100);
break;
default:
return 0;
}
}
void do_consent(CHAR_DATA *ch, char *argument) {
CHAR_DATA *victim;
if (IS_NPC(ch)) {
send_to_char("Mobs can't consent.\n\r", ch);
return;
}
if ( ( victim = get_char_world( ch, argument ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if (IS_NPC(victim)) {
send_to_char("They are not worthy of your consent.\n\r", ch);
return;
}
if (ch->pcdata->consenting && ch->pcdata->consenting != NULL) {
act(AT_PLAIN, "$n no longer consents to you.",
ch, NULL, ch->pcdata->consenting, TO_VICT);
act(AT_PLAIN, "You no longer consent to $N.",
ch, NULL, ch->pcdata->consenting, TO_CHAR);
ch->pcdata->consenting = NULL;
}
ch->pcdata->consenting = victim;
act(AT_PLAIN, "$n has given you $s consent.",
ch, NULL, victim, TO_VICT);
act(AT_PLAIN, "You give your consent to $N.",
ch, NULL, victim, TO_CHAR);
}