/***************************************************************************
* 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. *
* *
* 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. *
***************************************************************************/
#include <glib.h>
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <merc.h>
#include <recycle.h>
#include <olc.h>
#include <interp.h>
#include <fight.h>
#include <tables.h>
extern GMemChunk *affect_mem_chunk;
AFFECT_DATA *affect_free;
/*
* Create new Instance of "affect"
*/
AFFECT_DATA *new_affect(void)
{
static AFFECT_DATA af_zero;
AFFECT_DATA *af;
if (affect_free == NULL)
af = g_chunk_new (AFFECT_DATA, affect_mem_chunk);
else
{
af = affect_free;
affect_free = affect_free->next;
}
*af = af_zero;
VALIDATE(af);
return af;
}
void free_affect(AFFECT_DATA *af)
{
if (!IS_VALID(af))
return;
INVALIDATE(af);
af->next = affect_free;
affect_free = af;
}
/*
* Find the ac value of an obj, including position effect.
*/
int apply_ac( OBJ_DATA *obj, int iWear )
{
if ( obj->item_type != ITEM_ARMOR )
return 0;
switch ( iWear )
{
case WEAR_BODY: return 3 * obj->value[0];
case WEAR_HEAD: return 2 * obj->value[0];
case WEAR_LEGS: return 2 * obj->value[0];
case WEAR_FEET: return obj->value[0];
case WEAR_HANDS: return obj->value[0];
case WEAR_ARMS: return obj->value[0];
case WEAR_SHIELD: return obj->value[0];
case WEAR_FINGER_L: return obj->value[0];
case WEAR_FINGER_R: return obj->value[0];
case WEAR_NECK_1: return obj->value[0];
case WEAR_NECK_2: return obj->value[0];
case WEAR_ABOUT: return 2 * obj->value[0];
case WEAR_WAIST: return obj->value[0];
case WEAR_WRIST_L: return obj->value[0];
case WEAR_WRIST_R: return obj->value[0];
case WEAR_HOLD: return obj->value[0];
case WEAR_FACE: return obj->value[0];
case WEAR_SCABBARD_L:return 0;
case WEAR_SCABBARD_R:return 0;
}
return 0;
}
/*
* Apply or remove an affect to a character.
*/
void affect_modify( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd )
{
OBJ_DATA *wield;
int mod;
mod = paf->modifier;
if ( fAdd )
{
SET_BIT( ch->affected_by, paf->bitvector );
}
else
{
REMOVE_BIT( ch->affected_by, paf->bitvector );
mod = 0 - mod;
}
if ( IS_NPC(ch) )
{
switch ( paf->location )
{
default: break;
case APPLY_NONE: break;
case APPLY_MANA: ch->max_mana += mod; break;
case APPLY_HIT: ch->max_hit += mod; break;
case APPLY_MOVE: ch->max_move += mod; break;
case APPLY_AC: ch->armor += mod; break;
case APPLY_HITROLL: ch->hitroll += mod; break;
case APPLY_DAMROLL: ch->damroll += mod; break;
case APPLY_SAVING_PARA: ch->saving_throw += mod; break;
case APPLY_SAVING_ROD: ch->saving_throw += mod; break;
case APPLY_SAVING_PETRI: ch->saving_throw += mod; break;
case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
case APPLY_SAVING_SPELL: ch->saving_throw += mod; break;
case APPLY_POLY: ch->polyaff += mod; break;
case APPLY_BLOOD_MAX: ch->pcdata->stats[UNI_BLOOD_MAX] += mod; break;
case APPLY_BLOOD_POT: ch->pcdata->stats[UNI_BLOOD_POT] += mod; break;
}
return;
}
if ( IS_CLASS(ch, CLASS_HIGHLANDER) )
{
switch ( paf->location )
{
default: break;
case APPLY_NONE: break;
}
return;
}
switch ( paf->location )
{
default:
bug( "Affect_modify: unknown location %d.", paf->location );
return;
case APPLY_NONE: break;
case APPLY_STR: ch->pcdata->mod_str += mod; break;
case APPLY_DEX: ch->pcdata->mod_dex += mod; break;
case APPLY_INT: ch->pcdata->mod_int += mod; break;
case APPLY_WIS: ch->pcdata->mod_wis += mod; break;
case APPLY_CON: ch->pcdata->mod_con += mod; break;
/*
case APPLY_SEX: ch->sex += mod; 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: ch->max_mana += mod; break;
case APPLY_HIT: ch->max_hit += mod; break;
case APPLY_MOVE: ch->max_move += mod; break;
case APPLY_GOLD: break;
case APPLY_EXP: break;
case APPLY_AC: ch->armor += mod; break;
case APPLY_HITROLL: ch->hitroll += mod; break;
case APPLY_DAMROLL: ch->damroll += mod; break;
case APPLY_SAVING_PARA: ch->saving_throw += mod; break;
case APPLY_SAVING_ROD: ch->saving_throw += mod; break;
case APPLY_SAVING_PETRI: ch->saving_throw += mod; break;
case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
case APPLY_SAVING_SPELL: ch->saving_throw += mod; break;
case APPLY_POLY: ch->polyaff += mod; break;
case APPLY_BLOOD_MAX: ch->pcdata->stats[UNI_BLOOD_MAX] += mod; break;
}
/*
* Check for weapon wielding.
* Guard against recursion (for weapons with affects).
*/
if ( ( wield = get_eq_char( ch, WEAR_WIELD ) ) != NULL
&& wield->item_type == ITEM_WEAPON
&& get_obj_weight(wield) > str_app[get_curr_str(ch)].wield )
{
static int depth;
if ( depth == 0 )
{
depth++;
act( "You drop $p.", ch, wield, NULL, TO_CHAR );
act( "$n drops $p.", ch, wield, NULL, TO_ROOM );
obj_from_char( wield );
obj_to_room( wield, ch->in_room );
depth--;
}
}
return;
}
void affect_remove_obj( OBJ_DATA *obj, AFFECT_DATA *paf)
{
int where, vector;
if ( obj->affected == NULL )
{
bug( "Affect_remove_object: no affect.", 0 );
return;
}
obj->value[0] = 0;
if (obj->carried_by != NULL && obj->wear_loc != -1)
affect_modify( obj->carried_by, paf, FALSE );
where = paf->where;
vector = paf->bitvector;
/* remove flags from the object if needed */
if (paf->bitvector)
switch( paf->where)
{
case TO_OBJECT:
REMOVE_BIT(obj->extra_flags,paf->bitvector);
break;
case TO_WEAPON:
if (obj->item_type == ITEM_WEAPON)
REMOVE_BIT(obj->value[4],paf->bitvector);
obj->value[0] = 0;
break;
}
if ( paf == obj->affected )
{
obj->affected = paf->next;
}
else
{
AFFECT_DATA *prev;
for ( prev = obj->affected; prev != NULL; prev = prev->next )
{
if ( prev->next == paf )
{
prev->next = paf->next;
break;
}
}
if ( prev == NULL )
{
bug( "Affect_remove_object: cannot find paf.", 0 );
return;
}
}
free_affect(paf);
if (obj->carried_by != NULL && obj->wear_loc != -1)
return;
}
/* give an affect to an object */
void affect_to_obj(OBJ_DATA *obj, AFFECT_DATA *paf)
{
AFFECT_DATA *paf_new;
paf_new = new_affect();
*paf_new = *paf;
paf_new->next = obj->affected;
obj->affected = paf_new;
/* apply any affect vectors to the object's extra_flags
if (paf->bitvector)
switch (paf->where)
{
case TO_OBJECT:
SET_BIT(obj->extra_flags,paf->bitvector);
break;
case TO_WEAPON:
if (obj->item_type == ITEM_WEAPON)
SET_BIT(obj->value[4],paf->bitvector);
break;
}
*/
return;
}
/*
* Give an affect to a char.
*/
void affect_to_char( CHAR_DATA *ch, AFFECT_DATA *paf )
{
AFFECT_DATA *paf_new;
paf_new = new_affect();
*paf_new = *paf;
paf_new->next = ch->affected;
ch->affected = paf_new;
affect_modify( ch, paf_new, TRUE );
return;
}
void affect_modify_room( ROOM_INDEX_DATA *room, AFFECT_DATA *paf, bool fAdd )
{
if ( fAdd )
SET_BIT( room->affected_by, paf->bitvector );
else
REMOVE_BIT( room->affected_by, paf->bitvector );
return;
}
/*give affect to room YEA BUDDIE! Spiral in da HOUSE! */
void affect_to_room( ROOM_INDEX_DATA *room, AFFECT_DATA *paf )
{
AFFECT_DATA *paf_new;
paf_new = new_affect();
*paf_new = *paf;
paf_new->next = room->affected;
room->affected = paf_new;
affect_modify_room( room, paf_new, TRUE );
return;
}
void affect_remove_room( ROOM_INDEX_DATA *room, AFFECT_DATA *paf )
{
if ( room->affected == NULL )
{
bug( "Affect_remove: no affect.", 0 );
return;
}
affect_modify_room( room, paf, FALSE );
if ( paf == room->affected )
{
room->affected = paf->next;
}
else
{
AFFECT_DATA *prev;
for ( prev = room->affected; prev != NULL; prev = prev->next )
{
if ( prev->next == paf )
{
prev->next = paf->next;
break;
}
}
if ( prev == NULL )
{
bug( "Affect_remove: cannot find paf.", 0 );
return;
}
}
free_affect(paf);
return;
}
/*
* Remove an affect from a char.
*/
void affect_remove( CHAR_DATA *ch, AFFECT_DATA *paf )
{
if ( ch->affected == NULL )
{
bug( "Affect_remove: no affect.", 0 );
return;
}
affect_modify( ch, paf, FALSE );
if ( paf == ch->affected )
{
ch->affected = paf->next;
}
else
{
AFFECT_DATA *prev;
for ( prev = ch->affected; prev != NULL; prev = prev->next )
{
if ( prev->next == paf )
{
prev->next = paf->next;
break;
}
}
if ( prev == NULL )
{
bug( "Affect_remove: cannot find paf.", 0 );
return;
}
}
free_affect(paf);
return;
}
/*
* Strip all affects of a given sn.
*/
void affect_strip( CHAR_DATA *ch, int sn )
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
for ( paf = ch->affected; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if ( paf->type == sn )
affect_remove( ch, paf );
}
return;
}
/*
* Return true if a char is affected by a spell.
*/
bool is_affected( CHAR_DATA *ch, int sn )
{
AFFECT_DATA *paf;
for ( paf = ch->affected; paf != NULL; paf = paf->next )
{
if ( paf->type == sn )
return TRUE;
}
return FALSE;
}
/*
* Add or enhance an affect.
*/
void affect_join( CHAR_DATA *ch, AFFECT_DATA *paf )
{
AFFECT_DATA *paf_old;
bool found;
found = FALSE;
for ( paf_old = ch->affected; paf_old != NULL; paf_old = paf_old->next )
{
if ( paf_old == NULL )
return;
if ( paf_old->type == paf->type )
{
paf->duration += paf_old->duration;
paf->modifier += paf_old->modifier;
affect_remove( ch, paf_old );
break;
}
}
affect_to_char( ch, paf );
return;
}
/*
* Return ascii name of an item type.
*/
char *item_type_name( OBJ_DATA *obj )
{
switch ( obj->item_type )
{
case ITEM_LIGHT: return "light";
case ITEM_SCROLL: return "scroll";
case ITEM_WAND: return "wand";
case ITEM_STAFF: return "staff";
case ITEM_WEAPON: return "weapon";
case ITEM_TREASURE: return "treasure";
case ITEM_ARMOR: return "armor";
case ITEM_POTION: return "potion";
case ITEM_FURNITURE: return "furniture";
case ITEM_TRASH: return "trash";
case ITEM_CONTAINER: return "container";
case ITEM_DRINK_CON: return "drink container";
case ITEM_KEY: return "key";
case ITEM_FOOD: return "food";
case ITEM_MONEY: return "money";
case ITEM_BOAT: return "boat";
case ITEM_CORPSE_NPC: return "npc corpse";
case ITEM_CORPSE_PC: return "pc corpse";
case ITEM_FOUNTAIN: return "fountain";
case ITEM_PILL: return "pill";
case ITEM_PORTAL: return "portal";
case ITEM_EGG: return "egg";
case ITEM_VOODOO: return "voodoo doll";
case ITEM_STAKE: return "stake";
case ITEM_MISSILE: return "missile";
case ITEM_AMMO: return "ammo";
case ITEM_QUEST: return "quest token";
case ITEM_QUESTCARD: return "quest card";
case ITEM_QUESTMACHINE: return "quest generator";
case ITEM_SYMBOL: return "magical symbol";
case ITEM_BOOK: return "book";
case ITEM_PAGE: return "page";
case ITEM_TOOL: return "tool";
case ITEM_COOKIE: return "cookie";
case ITEM_TFILET: return "filet";
case ITEM_FIRE: return "fire";
}
bug( "Item_type_name: unknown type %d.", obj->item_type );
return "(unknown)";
}
/*
* Return ascii name of an affect location.
*/
char *affect_loc_name( int location )
{
switch ( location )
{
case APPLY_NONE: return "none";
case APPLY_STR: return "strength";
case APPLY_DEX: return "dexterity";
case APPLY_INT: return "intelligence";
case APPLY_WIS: return "wisdom";
case APPLY_CON: return "constitution";
case APPLY_SEX: return "sex";
case APPLY_CLASS: return "class";
case APPLY_LEVEL: return "level";
case APPLY_AGE: return "age";
case APPLY_MANA: return "mana";
case APPLY_HIT: return "hp";
case APPLY_MOVE: return "moves";
case APPLY_GOLD: return "gold";
case APPLY_EXP: return "experience";
case APPLY_AC: return "armor class";
case APPLY_HITROLL: return "hit roll";
case APPLY_DAMROLL: return "damage roll";
case APPLY_SAVING_PARA: return "save vs paralysis";
case APPLY_SAVING_ROD: return "save vs rod";
case APPLY_SAVING_PETRI: return "save vs petrification";
case APPLY_SAVING_BREATH: return "save vs breath";
case APPLY_SAVING_SPELL: return "save vs spell";
case APPLY_POLY: return "polymorph form";
case APPLY_BLOOD_MAX: return "Blood Max";
case APPLY_BLOOD_POT: return "Blood Potence";
}
bug( "Affect_location_name: unknown location %d.", location );
return "(unknown)";
}
AFFECT_DATA *find_affect( CHAR_DATA *ch, int bitvector)
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
for ( paf = ch->affected; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if ( paf->bitvector == bitvector )
return paf;
}
return NULL;
}