/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* _/ _/_/_/ _/ _/ _/ ACK! MUD is modified *
* _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code *
* _/ _/ _/ _/_/ _/ (c)Stephen Dooley 1994 *
* _/_/_/_/ _/ _/ _/ "This mud has not been *
* _/ _/ _/_/_/ _/ _/ _/ tested on animals." *
* *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "tables.h"
#include <math.h>
void reset_gain_stats( CHAR_DATA * ch )
{
sh_int index = 0;
sh_int index2 = 0;
sh_int add_move = 0;
sh_int add_mana = 0;
sh_int add_hp = 0;
ch->pcdata->mana_from_gain = 100;
ch->pcdata->hp_from_gain = 25;
ch->pcdata->move_from_gain = 0;
for ( index = 0; index < MAX_CLASS; index++ )
{
if ( ch->lvl[index] > 0 )
for ( index2 = 1; index2 <= ch->lvl[index]; index2++ )
{
add_hp = con_app[ch->pcdata->max_con].hitp + number_range(
class_table[index].hp_min,
class_table[index].hp_max );
add_mana = class_table[index2].fMana
? number_range(2, (2*ch->pcdata->max_int+ch->pcdata->max_wis)/16)
: 0;
add_move = number_range( 2, (ch->pcdata->max_con+ch->pcdata->max_dex)/5 );
add_hp = UMAX( 1, add_hp );
add_mana = UMAX( 0, add_mana );
add_move = UMAX( 7, add_move );
ch->pcdata->mana_from_gain += add_mana;
ch->pcdata->hp_from_gain += add_hp;
ch->pcdata->move_from_gain += add_move;
}
if ( ch->lvl2[index] > 0 )
for ( index2 = 1; index2 <= ch->lvl2[index]; index2++ )
{
add_hp = con_app[ch->pcdata->max_con].hitp + number_range(
remort_table[index].hp_min,
remort_table[index].hp_max );
add_mana = remort_table[index].fMana
? number_range(2, (2*ch->pcdata->max_int+ch->pcdata->max_wis)/16)
: 0;
add_move = number_range( 2, (ch->pcdata->max_con+ch->pcdata->max_dex)/5 );
add_hp = UMAX( 1, add_hp );
add_mana = UMAX( 0, add_mana );
add_move = UMAX( 7, add_move );
ch->pcdata->mana_from_gain += add_mana;
ch->pcdata->hp_from_gain += add_hp;
ch->pcdata->move_from_gain += add_move;
}
}
if ( ch->adept_level > 0 )
for ( index2 = 1; index2 <= ch->adept_level; index2++ )
{
add_hp = con_app[ch->pcdata->max_con].hitp + number_range(10, 50);
add_mana = number_range(10, (3 * ch->pcdata->max_int+ch->pcdata->max_wis)/4);
add_hp = UMAX( 1, add_hp );
add_mana = UMAX( 0, add_mana );
ch->pcdata->mana_from_gain += add_mana;
ch->pcdata->hp_from_gain += add_hp;
}
}
sh_int get_remort_level( CHAR_DATA *ch )
{
sh_int index;
sh_int max_remort_level = 0;
if ( !is_remort( ch ) )
return 0;
for ( index = 0; index < MAX_CLASS; index++ )
if ( ch->lvl2[index] > max_remort_level )
max_remort_level = ch->lvl2[index];
return max_remort_level;
}
sh_int get_psuedo_level( CHAR_DATA *ch )
{
sh_int psuedo_level = 0;
sh_int index, total_remort_level = 0;
if ( !is_remort( ch ) || IS_NPC( ch ) )
return ch->level;
else
{
for ( index = 0; index < MAX_CLASS; index++ )
if ( ch->lvl2[index] > 0 )
total_remort_level += ch->lvl2[index];
psuedo_level = ( ch->level + ( total_remort_level / 4 ) );
}
return psuedo_level;
}
bool ok_to_use( CHAR_DATA *ch, int value )
{
if ( value == NO_USE
&& get_trust(ch) < 85 )
{
send_to_char( "Only Creators may use this value.\n\r", ch );
return FALSE;
}
return TRUE;
}
bool check_level_use( CHAR_DATA *ch, int level )
{
char buf[MAX_STRING_LENGTH];
char out[MAX_STRING_LENGTH];
if ( get_trust(ch) >= level )
return TRUE;
sprintf( out, "This option limited to " );
switch ( level )
{
case 85:
strcat( out, "Creators only.\n\r" );
break;
case 84:
strcat( out, "Supremes or higher.\n\r" );
break;
case 83:
strcat( out, "Dieties or higher.\n\r" );
break;
case 82:
strcat( out, "Immortals or higher.\n\r" );
break;
case 81:
strcat( out, "Adepts or higher.\n\r" );
break;
default:
sprintf( buf, "level %d players and higher.\n\r", level );
strcat( out, buf );
}
send_to_char( out, ch );
return FALSE;
}
char *learnt_name( int learnt )
{
/* For skills/spells. Return a string indicating how well the
skill is learnt. */
if ( learnt < 1 ) return "Unknown";
else if ( learnt < 15 ) return "Awful";
else if ( learnt < 30 ) return "Weak";
else if ( learnt < 40 ) return "Poor";
else if ( learnt < 50 ) return "Average";
else if ( learnt < 60 ) return "Fair";
else if ( learnt < 70 ) return "Good";
else if ( learnt < 80 ) return "Great";
else if ( learnt < 85 ) return "Superb";
else if ( learnt < 90 ) return "Amazing";
else if ( learnt < 101 ) return "Godlike";
else if ( learnt < 102 ) return "RACE";
else return "Godlike";
}
long_int exp_to_level_adept( CHAR_DATA * ch )
{
long_int exp;
exp = ( 30000 + ( ch->adept_level * 5000 ) );
exp = UMAX( exp, exp * ch->adept_level/2 );
return exp;
}
char *get_adept_name( CHAR_DATA * ch )
{
/* this is weak for now..will eventually have like 200 total names, based on the remort
classes the adept has */
switch ( ch->adept_level )
{
case 1: return "@@W Mystic @@N";
break;
case 2: return "@@a Templar @@N";
break;
case 3: return "@@l Illusionist @@N";
break;
case 4: return "@@e Crusader @@N";
break;
case 5: return "@@d Warlock @@N";
break;
case 6: return "@@a Paladin @@N";
case 7: return "@@r Ranger @@N";
break;
case 8: return "@@c Gladiator @@N";
break;
case 9: return "@@l Shogun @@N";
break;
case 10: return "@@e Shamen @@N";
break;
case 11: return "@@r Druid @@N";
break;
case 12: return "@@b Conjurer @@N";
case 13: return "@@l Elementalist @@N";
break;
case 14: return "@@m Runemaster @@N";
case 15: return "@@d Shadowmaster @@N";
break;
case 16: return "@@b Beastmaster @@N";
break;
case 17: return "@@R Warlord @@N";
break;
case 18: return "@@e Dragonlord @@N";
break;
case 19: return "@@d Demonlord @@N";
break;
case 20: return "@@m Realm Lord @@N";
}
return "@@W Adept @@N";
}
long_int exp_to_level( CHAR_DATA *ch, int class, int index)
{
/* To get remort costs, call with index==5 */
int max_level = 0;
int mult;
int level, next_level_index;
int totlevels=0,diff;
long_int cost;
int a;
if ( ( index == 5 )
&& ( ch->lvl2[class] <= 0 ) )
return 0;
for ( a = 0; a < MAX_CLASS; a++ )
if ( ch->lvl[a] > max_level )
max_level = ch->lvl[a];
/* Okay, here, we are setting up a cheat to have float mulitpliers..we will devide the total exp by 4 to get
the proper values later. */
switch( index )
{
case 0:
mult=3;
break;
case 1:
mult=4;
break;
case 2:
mult=5;
break;
case 3:
mult=6;
break;
case 4:
mult=7;
break;
default:
mult = 23; /* i.e. remort class */
break;
}
if ( index == 5 )
level = UMAX( 0, ch->lvl2[class] );
else
level = UMAX( 0, ch->lvl[class]);
/* Adjust level to make costs higher */
for (a=0; a < MAX_CLASS; a++)
{
totlevels+= ch->lvl[a];
if ( ch->lvl2[a] > 0 )
totlevels += ch->lvl2[a];
}
if ( index != 5 )
next_level_index = ch->lvl[class];
else
next_level_index = UMIN( ch->lvl2[class]+ 20, 79 );
if ( next_level_index < 0 )
next_level_index = 0;
cost = exp_table[next_level_index].exp_base[class];
/* Now multiply by a factor dependant on total number of levels */
diff= ( totlevels / MAX_CLASS) - ( level + 20 );
if ( index == 5)
diff -= 30;
if ( diff < 10 )
diff = 10 ;
/* Discourage uneven levelling */
cost *= ( diff / 10 );
/* REALLY discourage uneven levelling :P */
if ( ( index != 5 ) && ( ( ch->level - ch->lvl[class] ) > 25 ) )
cost *= (diff / 7 );
/* Now multiply by order index/remort index...other factors will come here later, like race mod, etc. */
cost *= mult;
/* now refudge the order multiplier... divide by some factor..6 works right now.. */
cost /= 5.4;
return( cost );
}
int exp_to_level_vamp( int level )
{
int exp = 0;
switch ( level )
{
case 0 :
case 1 :
case 3 :
case 4 :
case 5 :
exp = ( 250 + level * 5 );
break;
case 6 :
case 7 :
case 8 :
case 9 :
exp = ( 300 + level * 6);
break;
case 10 :
case 11 :
case 12 :
exp = ( 350 + level * 5 );
break;
case 13 :
case 14 :
case 15 :
case 16 :
exp = ( 450 + level * 6 );
break;
case 17 :
case 18 :
case 19 :
case 20 :
exp = ( 500 + level * 5 );
break;
}
return ( exp );
}
int exp_to_level_wolf( int level )
{
int exp = 0;
switch ( level )
{
case 0 :
case 1 :
case 3 :
case 4 :
case 5 :
exp = ( 250 + level * 5 );
break;
case 6 :
case 7 :
case 8 :
case 9 :
exp = ( 300 + level * 6);
break;
case 10 :
case 11 :
case 12 :
exp = ( 400 + level * 6 );
break;
case 13 :
case 14 :
case 15 :
case 16 :
exp = ( 550 + level * 6.5 );
break;
case 17 :
case 18 :
case 19 :
case 20 :
exp = ( 500 + level * 7 );
break;
}
return ( exp );
}
long_int exp_for_mobile( int level, CHAR_DATA *mob )
{
long_int value, base_value;
base_value = exp_table[level].mob_base;
value = base_value;
/* now we have the base for the mobs level..let's add multipliers based on the skills it has
thse multpliers should add up to no more than 150% of the base, for a total of 2.5 times base
max exp for the mob--that's with EVERY skill in the book :) */
if ( IS_SET( mob->skills, MOB_SECOND ) )
value += .05 * base_value;
if ( IS_SET( mob->skills, MOB_THIRD ) )
value += .200 * base_value;
if ( IS_SET( mob->skills, MOB_FOURTH ) )
value += .1 * base_value;
if ( IS_SET( mob->skills, MOB_FIFTH ) )
value += .200 * base_value;
if ( IS_SET( mob->skills, MOB_SIXTH ) )
value += .1 * base_value;
if ( IS_SET( mob->skills, MOB_PUNCH ) )
value += .050 * base_value;
if ( IS_SET( mob->skills, MOB_HEADBUTT ) )
value += .100 * base_value;
if ( IS_SET( mob->skills, MOB_KNEE ) )
value += .050 * base_value;
if ( IS_SET( mob->skills, MOB_DISARM ) )
value += .050 * base_value;
if ( IS_SET( mob->skills, MOB_TRIP ) )
value += .050 * base_value;
if ( IS_SET( mob->skills, MOB_NODISARM ) )
value += .150 * base_value;
if ( IS_SET( mob->skills, MOB_DODGE ) )
value += .150 * base_value;
if ( IS_SET( mob->skills, MOB_PARRY ) )
value += .05 * base_value;
if ( IS_SET( mob->skills, MOB_MARTIAL ) )
value += .200 * base_value;
if ( IS_SET( mob->skills, MOB_ENHANCED ) )
value += .300 * base_value;
if ( IS_SET( mob->skills, MOB_NOTRIP ) )
value += .100 * base_value;
if ( IS_SET( mob->skills, MOB_DUALWIELD) )
value += .050 * base_value;
if ( IS_SET( mob->skills, MOB_DIRT ) )
value += .150 * base_value;
if ( IS_SET( mob->skills, MOB_CHARGE ) )
value += .050 * base_value;
if ( IS_AFFECTED( mob, AFF_SANCTUARY ) )
value += .400 * base_value;
if ( IS_AFFECTED( mob, AFF_INVISIBLE ) )
value += .050 * base_value;
if ( IS_AFFECTED( mob, AFF_DETECT_INVIS) )
value += .100 * base_value;
if ( IS_AFFECTED( mob, AFF_BESERK ) )
value += .300 * base_value;
if ( IS_AFFECTED( mob, AFF_ANTI_MAGIC) )
value += .350 * base_value;
if ( IS_AFFECTED( mob, AFF_CLOAK_FLAMING) )
value += .600 * base_value;
if ( IS_AFFECTED( mob, AFF_CLOAK_ABSORPTION ) )
value += .150 * base_value;
if ( IS_AFFECTED( mob, AFF_CLOAK_REFLECTION ) )
value += .350 * base_value;
if ( ( IS_AFFECTED( mob, AFF_CLOAK_REFLECTION ) )
&& ( IS_AFFECTED( mob, AFF_CLOAK_ABSORPTION ) )
&& ( IS_AFFECTED( mob, AFF_CLOAK_FLAMING ) ) )
value += .200 * base_value;
if ( IS_SET( mob->def, DEF_CURE_LIGHT ) )
value += .100 * base_value;
if ( IS_SET( mob->def, DEF_CURE_SERIOUS ) )
value += .200 * base_value;
if ( IS_SET( mob->def, DEF_CURE_CRITIC ) )
value += .350 * base_value;
if ( IS_SET( mob->def, DEF_CURE_HEAL ) )
value += .400 * base_value;
if ( IS_SET( mob->def, DEF_SHIELD_FIRE ) )
value += .300 * base_value;
if ( IS_SET( mob->def, DEF_SHIELD_SHOCK ) )
value += .200 * base_value;
if ( IS_SET( mob->def, DEF_SHIELD_ICE ) )
value += .100 * base_value;
if ( IS_SET( mob->act, ACT_SOLO ) )
value += .500 * base_value;
return( value );
}
/*
* We need a replacement for strlen() which will take the colour
* codes into account when reporting a string's length.
* -- Stephen
*/
int my_strlen( char *text )
{
char c;
int i;
int status;
int length;
int strlen_size;
status = 0;
length = 0;
strlen_size = strlen( text );
for ( i = 0; i < strlen_size; i++ )
{
c = text[i];
length++;
switch( status )
{
case 0:
case 1:
if ( c == '@' )
status++;
else
status = 0;
break;
case 2:
length -= 3; /* Subtract for '@@x' */
status=0;
break;
}
}
return( length );
}
/*
* Functions to return details regarding a PC and skill_table
* Uses 2 #defined values in merc.h to determine what to return
* These also make adapting to remort classes a lot easier - all
* the code goes here instead of in all the skills and do_cast()
*
* skill_table[] now includes flags to determine if for mortals
* or remortals, so use that here, and use correct array.
*/
int skill_table_lookup( CHAR_DATA *ch, int sn, int return_type )
{
int best_class = -1;
int best_level = -1;
int return_value;
int cnt;
if ( IS_NPC( ch ) )
{
best_class = ch->class;
best_level = ch->level;
}
else
{
/* Check normal classes first */
switch( skill_table[sn].flag1 )
{
case MORTAL:
for ( cnt = 0; cnt < MAX_CLASS; cnt++ )
{
if ( ch->lvl[cnt] >= skill_table[sn].skill_level[cnt]
&& ch->lvl[cnt] > best_level )
{
best_level = ch->lvl[cnt];
best_class = cnt;
}
}
break;
case REMORT:
for ( cnt = 0; cnt < MAX_CLASS; cnt++ )
{
if ( ch->lvl2[cnt] >= skill_table[sn].skill_level[cnt]
&& ch->lvl2[cnt] > best_level )
{
best_level = ch->lvl2[cnt];
best_class = cnt;
}
}
break;
}
}
switch ( return_type )
{
case RETURN_BEST_CLASS: return_value = best_class; break;
case RETURN_BEST_LEVEL: return_value = best_level; break;
default:
bug( "skill_table_lookup: invalid return_type:%d", return_type );
return_value = -1; break;
}
return( return_value );
}
bool is_remort( CHAR_DATA *ch )
{
int cnt;
if ( IS_NPC( ch ) )
return FALSE;
for ( cnt = 0; cnt < MAX_CLASS; cnt++ )
if ( ch->lvl2[cnt] != -1 )
return TRUE;
return FALSE;
}
int get_item_value( OBJ_DATA * obj )
{
AFFECT_DATA * this_aff;
int ac_mod = 0;
int dr_mod = 0;
int hp_mod = 0;
int hr_mod = 0;
int mana_mod = 0;
/* int move_mod = 0; */
int save_mod = 0;
int cost = 0;
sh_int wear_loc = WEAR_NONE;
char buf[MSL];
/* fix this up to use apply_ac by getting the wear loc */
for (wear_loc = 1; wear_loc < MAX_WEAR ; wear_loc ++ )
{
if ( CAN_WEAR( obj, ( 1 << wear_loc ) ) )
break;
}
if ( wear_loc == MAX_WEAR )
{
/* sprintf( buf, "Object has no wear loc" );
monitor_chan( buf, MONITOR_OBJ ); */
ac_mod = 0;
}
else
ac_mod = apply_ac( obj, 1 << wear_loc );
for ( this_aff = obj->first_apply ; this_aff != NULL; this_aff = this_aff->next )
{
switch (this_aff->location )
{
default:
bug( "Get_item_value: unknown location %d.", this_aff->location );
sprintf( buf, "Get_item_value called for unknown location %d.",
this_aff->location );
monitor_chan( buf, MONITOR_OBJ );
break;
case APPLY_NONE: break;
case APPLY_STR: break;
case APPLY_DEX: break;
case APPLY_INT: break;
case APPLY_WIS: break;
case APPLY_CON: break;
case APPLY_SEX: break;
case APPLY_CLASS: break;
case APPLY_LEVEL: break;
case APPLY_AGE: break;
case APPLY_HEIGHT: break;
case APPLY_WEIGHT: break;
case APPLY_MANA: mana_mod += this_aff->modifier; break;
case APPLY_HIT: hp_mod += this_aff->modifier; break;
case APPLY_MOVE: break;
case APPLY_GOLD: break;
case APPLY_EXP: break;
case APPLY_AC: ac_mod += this_aff->modifier; break;
case APPLY_HITROLL: hr_mod += this_aff->modifier; break;
case APPLY_DAMROLL: dr_mod += this_aff->modifier; break;
case APPLY_SAVING_PARA:
case APPLY_SAVING_ROD:
case APPLY_SAVING_PETRI:
case APPLY_SAVING_BREATH:
case APPLY_SAVING_SPELL: save_mod += this_aff->modifier; break;
}
}
cost =
obj->level * 1 +
ac_mod * -8 +
dr_mod * 5 +
hr_mod * 5 +
save_mod * 2 +
hp_mod * 4 +
mana_mod * 3;
if ( IS_SET( obj->item_apply, ITEM_APPLY_ENHANCED ) )
cost = cost * 1.3;
if ( IS_SET( obj->item_apply, ITEM_APPLY_SANC ) )
cost = cost * 1.3;
sprintf( buf, "Cost computed for item %d.", cost );
/* monitor_chan( buf, MONITOR_OBJ ); */
if ( obj->item_type == ITEM_ENCHANTMENT )
cost = abs( obj->value[1] * 100 );
return UMAX( 10, cost );
return -1;
}
char *get_tribe_standing_name( int standing )
{
switch ( standing )
{
case 0: return "@@mEternal@@N";
break;
case 1: return "@@rEldest@@N";
break;
case 2: return "@@rMate@@N";
break;
case 3: return "@@eWarder@@N";
break;
case 4: return "@@GGuardian@@N";
break;
case 5: return "@@aSentry@@N";
break;
case 6: return "@@yElder@@N";
case 7: return "@@rAdult@@N";
break;
case 8: return "@@RYounger@@N";
break;
case 9: return "@@bCub@@N";
break;
}
return "@@WCUB@@N";
}
char *get_moon_phase_name( void )
{
switch ( weather_info.moon_phase )
{
case MOON_NEW : return "@@bDark@@N";
break;
case MOON_WAX_CRE : return "@@aWaxing @@dCresent@@N";
break;
case MOON_WAX_HALF: return "@@aWaxing @@gHalf@@N";
break;
case MOON_WAX_GIB : return "@@aWaxing @@WGibbous@@N";
break;
case MOON_FULL : return "@@WFULL@@N";
break;
case MOON_WAN_GIB : return "@@cWaning @@WGibbous@@N";
break;
case MOON_WAN_HALF: return "@@cWaning @@gHalf@@N";
break;
case MOON_WAN_CRE : return "@@cWaning @@dCrescent@@N";
break;
}
return "@@eDESTROYED!!!@@N";
}