/****************************************************************************
* [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. *
* ------------------------------------------------------------------------ *
* "Special procedure" 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 elkandu.c */
extern void ch_harm(CHAR_DATA *victim, CHAR_DATA *ch, int dam, int type, bool dont_wait);
/*
* The following special functions are available for mobiles.
*/
DECLARE_SPEC_FUN( spec_cast_fire );
DECLARE_SPEC_FUN( spec_cast_wind );
DECLARE_SPEC_FUN( spec_cast_water );
DECLARE_SPEC_FUN( spec_cast_earth );
DECLARE_SPEC_FUN( spec_cast_drain );
DECLARE_SPEC_FUN( spec_cast_mind );
DECLARE_SPEC_FUN( spec_cast_lightning );
DECLARE_SPEC_FUN( spec_cast_frost );
DECLARE_SPEC_FUN( spec_cast_poison );
DECLARE_SPEC_FUN( spec_cast_light );
DECLARE_SPEC_FUN( spec_cast_healing );
DECLARE_SPEC_FUN( spec_cast_all );
DECLARE_SPEC_FUN( spec_fido );
DECLARE_SPEC_FUN( spec_guard );
DECLARE_SPEC_FUN( spec_janitor );
DECLARE_SPEC_FUN( spec_poison );
DECLARE_SPEC_FUN( spec_thief );
DECLARE_SPEC_FUN( spec_catalyst );
DECLARE_SPEC_FUN( spec_miner );
DECLARE_SPEC_FUN( spec_farmer );
/*
* Given a name, return the appropriate spec fun.
*/
SPEC_FUN *spec_lookup( const char *name )
{
if ( !str_cmp( name, "spec_cast_healing" ) ) return spec_cast_healing;
if ( !str_cmp( name, "spec_cast_fire" ) ) return spec_cast_fire;
if ( !str_cmp( name, "spec_cast_wind" ) ) return spec_cast_wind;
if ( !str_cmp( name, "spec_cast_frost" ) ) return spec_cast_frost;
if ( !str_cmp( name, "spec_cast_lightning" ) ) return spec_cast_lightning;
if ( !str_cmp( name, "spec_cast_water" ) ) return spec_cast_water;
if ( !str_cmp( name, "spec_cast_earth" ) ) return spec_cast_earth;
if ( !str_cmp( name, "spec_cast_drain" ) ) return spec_cast_drain;
if ( !str_cmp( name, "spec_cast_mind" ) ) return spec_cast_mind;
if ( !str_cmp( name, "spec_cast_poison" ) ) return spec_cast_poison;
if ( !str_cmp( name, "spec_cast_light" ) ) return spec_cast_light;
if ( !str_cmp( name, "spec_cast_all" ) ) return spec_cast_all;
if ( !str_cmp( name, "spec_fido" ) ) return spec_fido;
if ( !str_cmp( name, "spec_guard" ) ) return spec_guard;
if ( !str_cmp( name, "spec_janitor" ) ) return spec_janitor;
if ( !str_cmp( name, "spec_poison" ) ) return spec_poison;
if ( !str_cmp( name, "spec_thief" ) ) return spec_thief;
if ( !str_cmp( name, "spec_catalyst" ) ) return spec_catalyst;
if ( !str_cmp( name, "spec_miner" ) ) return spec_miner;
if ( !str_cmp( name, "spec_farmer" ) ) return spec_farmer;
return 0;
}
/*
* Given a pointer, return the appropriate spec fun text.
*/
char *lookup_spec( SPEC_FUN *special )
{
if ( special == spec_cast_healing ) return "spec_cast_healing";
if ( special == spec_cast_fire ) return "spec_cast_fire";
if ( special == spec_cast_wind ) return "spec_cast_wind";
if ( special == spec_cast_water ) return "spec_cast_water";
if ( special == spec_cast_frost ) return "spec_cast_frost";
if ( special == spec_cast_lightning ) return "spec_cast_lightning";
if ( special == spec_cast_mind ) return "spec_cast_mind";
if ( special == spec_cast_poison ) return "spec_cast_poison";
if ( special == spec_cast_drain ) return "spec_cast_drain";
if ( special == spec_cast_earth ) return "spec_cast_earth";
if ( special == spec_cast_light ) return "spec_cast_light";
if ( special == spec_cast_all ) return "spec_cast_all";
if ( special == spec_fido ) return "spec_fido";
if ( special == spec_guard ) return "spec_guard";
if ( special == spec_janitor ) return "spec_janitor";
if ( special == spec_poison ) return "spec_poison";
if ( special == spec_thief ) return "spec_thief";
if ( special == spec_catalyst ) return "spec_catalyst";
if ( special == spec_miner ) return "spec_miner";
if ( special == spec_farmer ) return "spec_farmer";
return "";
}
bool spec_cast_healing( CHAR_DATA *ch )
{
CHAR_DATA *victim;
CHAR_DATA *v_next;
if ( !IS_AWAKE(ch) || IS_FIGHTING(ch) )
return FALSE;
for ( victim = ch->in_room->first_person; victim; victim = v_next )
{
v_next = victim->next_in_room;
if ( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 )
break;
}
if ( !victim )
return FALSE;
switch ( number_range(0,7)) {
case 0:
act( AT_MAGIC, "$n utters the word 'sikana'.", ch, NULL, NULL, TO_ROOM);
spell_smaug( skill_lookup( "security magic" ), get_curr_wil(ch), ch, victim);
return TRUE;
case 1:
act( AT_MAGIC, "$n utters the word 'nambreh'.", ch, NULL, NULL, TO_ROOM );
spell_smaug( skill_lookup( "motion magic" ), get_curr_wil(ch), ch, victim);
return TRUE;
case 2:
act( AT_MAGIC, "$n utters the word 'anomis'.", ch, NULL, NULL, TO_ROOM );
spell_cure_blindness( skill_lookup( "cure blindness" ),
get_curr_wil(ch), ch, victim );
return TRUE;
case 3:
act( AT_MAGIC, "$n utters the word 'neosporin'.", ch, NULL, NULL, TO_ROOM );
spell_smaug( skill_lookup( "cure light" ),
get_curr_wil(ch), ch, victim );
return TRUE;
case 4:
act( AT_MAGIC, "$n utters the word 'ahpla'.", ch, NULL, NULL, TO_ROOM);
spell_cure_poison( skill_lookup( "cure poison" ),
get_curr_wil(ch), ch, victim );
return TRUE;
case 5:
act( AT_MAGIC, "$n utters the word 'gatorade'.", ch, NULL, NULL, TO_ROOM );
spell_smaug( skill_lookup( "refresh" ), get_curr_wil(ch), ch,victim );
return TRUE;
case 6:
act( AT_MAGIC, "$n utters the word 'haloek'.", ch, NULL, NULL, TO_ROOM );
spell_smaug( skill_lookup( "cure serious" ), get_curr_wil(ch), ch, victim );
return TRUE;
case 7:
act( AT_MAGIC, "$n utters the word 'noics'.", ch, NULL, NULL, TO_ROOM );
spell_remove_curse( skill_lookup( "remove curse" ),get_curr_wil(ch), ch, victim );
return TRUE;
}
return FALSE;
}
bool spec_cast_fire( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_FIRE, FALSE);
return TRUE;
}
bool spec_cast_wind( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_WIND, FALSE);
return TRUE;
}
bool spec_cast_water( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_WATER, FALSE);
return TRUE;
}
bool spec_cast_earth( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_EARTH, FALSE);
return TRUE;
}
bool spec_cast_frost( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_COLD, FALSE);
return TRUE;
}
bool spec_cast_lightning( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_ELECTRICITY, FALSE);
return TRUE;
}
bool spec_cast_mind( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_PSIONIC, FALSE);
return TRUE;
}
bool spec_cast_poison( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_POISON, FALSE);
return TRUE;
}
bool spec_cast_drain( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_DRAIN, FALSE);
return TRUE;
}
bool spec_cast_light( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), MAG_LIGHT, FALSE);
return TRUE;
}
bool spec_cast_all( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch) || !ch->in_room || char_died(ch))
return FALSE;
victim = ch->last_hit;
if ( !victim || victim == ch )
return FALSE;
ch_harm(victim, ch, get_curr_int(ch), number_range(MAG_NONE, MAG_ALL), FALSE);
return TRUE;
}
bool spec_fido( CHAR_DATA *ch )
{
OBJ_DATA *corpse;
OBJ_DATA *c_next;
OBJ_DATA *obj;
OBJ_DATA *obj_next;
if ( !IS_AWAKE(ch) )
return FALSE;
for ( corpse = ch->in_room->first_content; corpse; corpse = c_next )
{
c_next = corpse->next_content;
if ( corpse->item_type != ITEM_CORPSE_NPC )
continue;
act( AT_ACTION, "$n savagely devours a corpse.", ch, NULL, NULL, TO_ROOM );
for ( obj = corpse->first_content; obj; obj = obj_next )
{
obj_next = obj->next_content;
obj_from_obj( obj );
obj_to_room( obj, ch->in_room );
}
extract_obj( corpse );
return TRUE;
}
return FALSE;
}
bool spec_guard( CHAR_DATA *ch ) {
CHAR_DATA *victim;
CHAR_DATA *v_next;
CHAR_DATA *ech;
char *crime;
if ( !IS_AWAKE(ch) || ch->last_hit )
return FALSE;
ech = NULL;
crime = "";
for ( victim = ch->in_room->first_person; victim; victim = v_next )
{
v_next = victim->next_in_room;
if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_KILLER) )
{ crime = "KILLER"; break; }
if ( !IS_NPC(victim) && xIS_SET(victim->act, PLR_THIEF) )
{ crime = "THIEF"; break; }
}
return FALSE;
}
bool spec_janitor( CHAR_DATA *ch )
{
OBJ_DATA *trash;
OBJ_DATA *trash_next;
if ( !IS_AWAKE(ch) )
return FALSE;
for ( trash = ch->in_room->first_content; trash; trash = trash_next )
{
trash_next = trash->next_content;
if ( IS_OBJ_STAT( trash, ITEM_NO_TAKE )
|| IS_OBJ_STAT( trash, ITEM_BURIED )
|| trash->item_type == ITEM_MONEY
|| trash->item_type == ITEM_CORPSE_NPC )
continue;
if ( trash->item_type == ITEM_DRINK_CON
|| trash->item_type == ITEM_TRASH
|| trash->cost < 1000
|| (trash->pIndexData->vnum == OBJ_VNUM_SHOPPING_BAG
&& !trash->first_content) )
{
act( AT_ACTION, "$n picks up some trash.", ch, NULL, NULL, TO_ROOM );
obj_from_room( trash );
extract_obj( trash );
return TRUE;
}
}
return FALSE;
}
bool spec_poison( CHAR_DATA *ch )
{
CHAR_DATA *victim;
if (!IS_FIGHTING(ch))
return FALSE;
if ( ( victim = ch->last_hit ) == NULL
|| number_percent( ) > get_curr_dex(ch) )
return FALSE;
act( AT_HIT, "You bite $N!", ch, NULL, victim, TO_CHAR );
act( AT_ACTION, "$n bites $N!", ch, NULL, victim, TO_NOTVICT );
act( AT_POISON, "$n bites you!", ch, NULL, victim, TO_VICT );
spell_poison( gsn_poison, get_curr_end(ch), ch, victim );
return TRUE;
}
bool spec_thief( CHAR_DATA *ch )
{
CHAR_DATA *victim;
CHAR_DATA *v_next;
char buf[MAX_STRING_LENGTH];
char name[MAX_STRING_LENGTH];
if ( ch->position != POS_STANDING )
return FALSE;
for ( victim = ch->in_room->first_person; victim; victim = v_next )
{
v_next = victim->next_in_room;
if ( IS_NPC(victim)
|| number_bits( 2 ) != 0
|| !can_see( ch, victim ) ) /* Thx Glop */
continue;
if (number_percent() < 80 || victim->last_carrying==NULL) {
sprintf(buf, "coins %s", victim->name);
do_steal(ch, buf);
return TRUE;
} else {
one_argument(victim->last_carrying->name, name);
sprintf(buf, "%s %s", name, victim->name);
do_steal(ch, buf);
return TRUE;
}
}
return FALSE;
}
bool spec_catalyst( CHAR_DATA *ch ) {
OBJ_DATA *obj;
CHAR_DATA *victim;
unsigned long oldgold;
oldgold = ch->gold;
if ( !IS_AWAKE(ch) )
return FALSE;
if (ch->gold == 0) {
for (victim = ch->in_room->first_person;victim;victim = victim->next_in_room) {
if (victim == ch) continue;
for (obj = ch->first_carrying;obj;obj = obj->next_content) {
if (obj->obj_by && !str_cmp(obj->obj_by, victim->name)) {
do_say(ch, "Your funneling is done, Master");
do_drop(ch, "all");
return TRUE;
}
}
}
return FALSE;
}
for (obj = ch->first_carrying;obj;obj = obj->next_content) {
obj->mana += 1;
if (xIS_SET(obj->extra_flags, ITEM_MAGIC)) obj->mana += 1;
if (obj->material) {
ch->gold -= obj->material->magic * obj->weight*20;
} else {
ch->gold -= 100 * obj->weight*20;
}
}
if (ch->gold < 0) ch->gold = 0;
if (ch->gold > oldgold) ch->gold = 0;
return TRUE;
}
bool spec_miner( CHAR_DATA *ch ) {
CHAR_DATA *victim;
OBJ_DATA *obj;
MATERIAL_DATA *material;
if ( !IS_AWAKE(ch) )
return FALSE;
if (ch->gold <= 40000) {
for (victim = ch->in_room->first_person;victim;victim = victim->next_in_room) {
if (victim == ch) continue;
for (obj = ch->first_carrying;obj;obj = obj->next_content) {
if (obj->obj_by && !str_cmp(obj->obj_by, victim->name)) {
do_say(ch, "Your mining is done, Master");
do_mpjunk(ch, "receipt");
do_drop(ch, "all");
return TRUE;
}
}
}
return FALSE;
}
if (!ch->first_carrying) {
for (victim = ch->in_room->first_person;victim;victim = victim->next_in_room) {
if (victim == ch) continue;
obj = create_object(get_obj_index(OBJ_VNUM_SCROLL_SCRIBING), 0);
STRFREE(obj->obj_by);
obj->obj_by = STRALLOC(victim->name);
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC("receipt");
STRFREE(obj->name);
obj->name = STRALLOC("receipt");
obj_to_char(obj, ch);
return TRUE;
}
return FALSE;
}
for (material = first_material;material;material = material->next) {
if (material->sector != ch->in_room->sector_type) continue;
if (material->cost < 100) continue; /* only get "good" ores */
if (xIS_SET(material->extra_flags, ITEM_MAGIC)
&& ch->in_room->area->weather->mana < -100) continue;
if (number_percent() > material->rarity) continue;
obj = make_ore(material->number);
obj_to_char(obj, ch);
ch->gold = UMAX(ch->gold - 50000, 0);
return TRUE;
}
return FALSE;
}
bool spec_farmer( CHAR_DATA *ch ) {
CHAR_DATA *victim;
OBJ_DATA *obj;
INGRED_DATA *ingred;
if ( !IS_AWAKE(ch) )
return FALSE;
if (ch->gold <= 500) {
for (victim = ch->in_room->first_person;victim;victim = victim->next_in_room) {
if (victim == ch) continue;
for (obj = ch->first_carrying;obj;obj = obj->next_content) {
if (obj->obj_by && !str_cmp(obj->obj_by, victim->name)) {
do_say(ch, "Your harvesting is done, Master");
do_mpjunk(ch, "receipt");
do_drop(ch, "all");
return TRUE;
}
}
}
return FALSE;
}
if (!ch->first_carrying) {
for (victim = ch->in_room->first_person;victim;victim = victim->next_in_room) {
if (victim == ch) continue;
obj = create_object(get_obj_index(OBJ_VNUM_SCROLL_SCRIBING), 0);
STRFREE(obj->obj_by);
obj->obj_by = STRALLOC(victim->name);
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC("receipt");
STRFREE(obj->name);
obj->name = STRALLOC("receipt");
obj_to_char(obj, ch);
return TRUE;
}
return FALSE;
}
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("Spec_farmer: can't find vnum for ingredient %d!",
ingred->vnum);
continue;
}
obj = create_object( get_obj_index( ingred->vnum), 0);
obj_to_char(obj, ch);
ch->gold = UMAX(ch->gold - 1000, 0);
return TRUE;
}
return FALSE;
}