/***************************************************************************
* 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 Envy Diku Mud, you must comply with *
* the original Diku license in 'license.doc', the Merc license in *
* 'license.txt', as well as the Envy license in 'license.nvy'. *
* In particular, you may not remove either of these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
* *
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
* *
* Code Adapted and Improved by Abandoned Realms Mud *
* and Aabahran: The Forsaken Lands Mud by Virigoth *
* *
* Continued Production of this code is available at www.flcodebase.com *
***************************************************************************/
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "magic.h"
#include "song.h"
#include "recycle.h"
#include "interp.h"
extern char *target_name;
extern int eq_positions[24];
/* Contains the tattoo spells/functions */
/* PALISON */
void tattoo_tick_palison(CHAR_DATA* ch, OBJ_DATA* tattoo){
CHAR_DATA* vch = ch->fighting;
/* All we do here is cast sear at 11/12/13 hours if we are fighting. */
if (vch == NULL || mud_data.time_info.hour < 11 || mud_data.time_info.hour > 13)
return;
if ( !IS_OUTSIDE(ch) || IS_SET(ch->in_room->room_flags, ROOM_DARK))
return;
act("$p flares brightly as sun's rays fall upon its surface!", ch, tattoo, vch, TO_ALL);
spell_sear(skill_lookup("sear"), ch->level, ch, vch, TARGET_CHAR);
}
/* Virigoth */
CHAR_DATA* undead_check_guard(CHAR_DATA* ch, CHAR_DATA* mob)
{
const int MAX_CHS = 12;
CHAR_DATA* och;
CHAR_DATA* och_next;
AFFECT_DATA af;
CHAR_DATA* chs[MAX_CHS];
int tot_chs = 0;
/* Put all avaliable saving chars in an array */
for ( och = ch->in_room->people; och != NULL; och = och_next ){
och_next = och->next_in_room;
if (!IS_NPC(och) || !IS_UNDEAD(och)
|| !can_see(och, ch)
|| och->level > ch->level
|| och->fighting == ch
|| ch->fighting == och
|| och == mob
|| (och->master != NULL && och->master != ch)
)
continue;
chs[tot_chs++] = och;
}//end for
/* now we pick one character out of all possible choices */
if (tot_chs == 0)
return NULL;
/* we return a random pick */
och = chs[number_range(0, UMAX(0, tot_chs - 1))];
//set temporary charm flag to prevent from fleeing.
af.type = gsn_charm_person;
af.level = ch->level;
af.duration = 1 + number_fuzzy(1);
af.where = TO_AFFECTS;
af.bitvector = AFF_CHARM;
af.location = APPLY_NONE;
af.modifier = 0;
if (!IS_AFFECTED(och, AFF_CHARM))
affect_to_char(och, &af);
return och;
}
/* Tatto spell for Virigoth tattoo, not usuable by normal means */
void spell_darklife( int sn, int level, CHAR_DATA *ch, void *vo,int target )
{
//This is basicly a shadowstalk spell except it lasts only a single combat round.
CHAR_DATA* victim = ch->fighting;
CHAR_DATA *shadow;
OBJ_DATA *wield;
int i;
char buf[MSL];
char *name;
if (victim == NULL)
{
send_to_char("You must be in combat.\n\r", ch);
return;
}
if (ch->fighting != victim)
{
send_to_char("You must be in combat.\n\r", ch);
return;
}
if (ch->class == class_lookup("vampire")
|| ch->class == class_lookup("necromancer")){
spell_weaken( gsn_weaken, level, ch, ch->fighting, target );
return;
}
if (room_has_sun(ch->in_room))
{
send_to_char("The light banishes your shadow as it takes life of its own.\n\r", ch);
return;
}
send_to_char("Your shadow seems to take on a life of its own!\n\r", ch);
act("$n's shadow takes on a life of its own!",ch,NULL,NULL,TO_ROOM);
shadow = create_mobile( get_mob_index(MOB_VNUM_SHADOW) );
for (i=0;i < MAX_STATS; i++)
shadow->perm_stat[i] = ch->perm_stat[i];
shadow->max_hit = ch->max_hit;
shadow->hit = shadow->max_hit;
shadow->max_mana = ch->max_mana;
shadow->mana = shadow->max_mana;
shadow->level = ch->level - 2;
for (i=0; i < 3; i++)
shadow->armor[i] = ch->armor[i];
shadow->armor[3] =ch->armor[3];
shadow->sex = ch->sex;
shadow->gold = 0;
//Now we copy over little things like weapon stats.
shadow->damroll = ch->damroll;
shadow->hitroll = ch->hitroll;
if ( (wield = get_eq_char(ch,WEAR_WIELD)) != NULL)
{
shadow->damage[DICE_NUMBER] = wield->value[1];
shadow->damage[DICE_TYPE] = wield->value[2];
shadow->dam_type = wield->value[3];
}
name = IS_NPC(ch) ? ch->short_descr : ch->name;
sprintf( buf, shadow->short_descr, name );
free_string( shadow->short_descr );
shadow->short_descr = str_dup( buf );
sprintf( buf, shadow->long_descr, name );
free_string( shadow->long_descr );
shadow->long_descr = str_dup( buf );
sprintf( buf, shadow->description, name );
free_string( shadow->description );
shadow->description = str_dup( buf );
char_to_room(shadow,ch->in_room);
//set char flags so mobs dont flee from it.
SET_BIT(shadow->affected_by, AFF_CHARM);
//stripsome usless flags that come with the shadowstalk mob
affect_strip ( shadow, gsn_invis );
affect_strip ( shadow, gsn_mass_invis );
REMOVE_BIT ( shadow->affected_by, AFF_INVISIBLE );
affect_strip( shadow, gsn_hide );
REMOVE_BIT ( shadow->affected_by, AFF_HIDE );
//we make the shadow attack and disappear.
//add a leader/charm here to give exp on kills
shadow->leader = ch;
SET_BIT(shadow->affected_by, AFF_CHARM);
multi_hit(shadow, victim, shadow->dam_type + TYPE_HIT);
extract_char(shadow, TRUE);
}//end spell.
/* Over lay to beckon social */
void do_beckon(CHAR_DATA *ch, char *argument){
char arg[MIL];
CHAR_DATA *victim;
bool fFol = TRUE;
/* Now check if the target should follow */
one_argument(argument,arg);
if (ch->tattoo != deity_lookup("cycle"))
fFol = FALSE;
if (arg[0] == '\0')
fFol = FALSE;
if ((victim = get_char_room(ch, NULL, arg)) == NULL){
fFol = FALSE;
check_social(ch, "beckon", argument);
return;
}
if (victim->fighting != NULL
|| !IS_NPC(victim)
|| !IS_UNDEAD(victim)
|| IS_SET(victim->act, ACT_TOO_BIG)
|| victim->level > 4 * ch->level / 5)
fFol = FALSE;
if (!fFol)
{
check_social(ch, "beckon", argument);
return;
}
if ( (IS_EVIL(ch) && IS_GOOD(victim))
|| (IS_EVIL(victim) && IS_GOOD(ch)) ){
send_to_char("You have a feeling that your align forbids them from following you.\n\r", ch);
return;
}
//message
act("You beckon for $N to follow.", ch, NULL, victim, TO_CHAR);
act("$n beckons $N to follow...hmmm what's going on?", ch, NULL, victim, TO_NOTVICT);
act("$n beckons for you to follow.", ch, NULL, victim, TO_VICT);
//make the character a follower
if (ch->pet)
{
if (ch->pet->in_room == victim->in_room){
if (ch->pet == victim)
act("$n points at $mself obviously confused.", victim, NULL, NULL, TO_ROOM);
else
act("$n glances meaningfully at $N and turns away.", victim, NULL, ch->pet, TO_ROOM);
}
else
act("$n mumbles something about $N then turns away.", victim, NULL, ch->pet, TO_ROOM);
return;
}
else if (!IS_NPC(ch) && ch->pcdata->familiar)
{
if (ch->pcdata->familiar->in_room == victim->in_room){
if (ch->pcdata->familiar == victim)
act("$n points at $mself obviously confused.", victim, NULL, NULL, TO_ROOM);
else
act("$n glances meaningfully at $N and turns away.", victim, NULL, ch->pcdata->familiar, TO_ROOM);
}
else
act("$n mumbles something about $N then turns away.", victim, NULL, ch->pcdata->familiar, TO_ROOM);
return;
}
else if ( victim->master){
if (victim->master->in_room == victim->in_room)
act("$n glances meaningfully at $N and turns away.", victim, NULL, victim->master, TO_ROOM);
else
act("$n mumbles something about $N then turns away.", victim, NULL, victim->master, TO_ROOM);
return;
}
act("$N glances at $n's tattoo and obediently follows $m.", ch, NULL, victim, TO_ROOM);
act("$N glances at your tattoo and $S eyes widen in fear.", ch, NULL, victim, TO_CHAR);
SET_BIT(victim->affected_by, AFF_CHARM);
victim->comm = COMM_NOTELL|COMM_NOYELL|COMM_NOCHANNELS;
SET_BIT(victim->act, ACT_PET);
REMOVE_BIT(victim->act, ACT_AGGRESSIVE);
victim->hunting = NULL;
add_follower(victim,ch);
victim->leader = ch;
ch->pet = victim;
}//end beckon
/* summons a demon for 1 tick */
void spell_demon_summon( int sn, int level, CHAR_DATA *ch, void *vo, int target )
{
CHAR_DATA *demon;
AFFECT_DATA af;
int i;
if (is_affected(ch,sn))
return;
if (get_control(ch, MOB_VNUM_DEMON) > 0)
return;
act("A demon comes to your aid!",ch,NULL,NULL,TO_CHAR);
act("A demon comes to $n's aid!",ch,NULL,NULL,TO_ROOM);
demon = create_mobile( get_mob_index(MOB_VNUM_DEMON) );
for (i=0;i < MAX_STATS; i++)
demon->perm_stat[i] = ch->perm_stat[i];
demon->max_hit = IS_NPC(ch)? URANGE(ch->max_hit,1 * ch->max_hit,30000) : URANGE(ch->pcdata->perm_hit,1*ch->pcdata->perm_hit,30000);
demon->hit = demon->max_hit;
demon->max_mana = IS_NPC(ch)? ch->max_mana : ch->pcdata->perm_mana;
demon->mana = demon->max_mana;
demon->level = ch->level / 2;
for (i=0; i < 3; i++)
demon->armor[i] = interpolate(demon->level,100,-100);
demon->armor[3] = interpolate(demon->level,100,0);
demon->comm = COMM_NOTELL|COMM_NOYELL|COMM_NOCHANNELS;
demon->summoner = ch;
char_to_room(demon,ch->in_room);
af.type = gsn_timer;
af.level = level;
af.duration = 0;
af.bitvector = 0;
af.modifier = 0;
af.location = APPLY_NONE;
affect_to_char(demon, &af);
SET_BIT(demon->affected_by, AFF_CHARM);
add_follower(demon,ch);
demon->leader = ch;
}
/* if in forest mountain field, vegetaion lags the person for 2 ticks. */
void spell_verdigar_tat( int sn, int level, CHAR_DATA *ch, void *vo, int target ){
CHAR_DATA* victim = (CHAR_DATA*) vo;
int sector = ch->in_room->sector_type;
/* Viri: Give same funcionatliy to all calsses
with added bonus of pet -hide for rangers */
if (ch->class == class_lookup("ranger"))
return;
if (sector != SECT_FOREST && sector != SECT_FIELD
&& sector != SECT_HILLS && sector != SECT_MOUNTAIN){
act("Few tiny roots sprout from the soil then wither on the hard ground.\n\r", ch, NULL, NULL, TO_ALL);
return;
}
act("Roots and plants lash at you binding you to the ground!", victim, NULL, NULL, TO_CHAR);
act("Roots and plants lash at $n binding $m to the ground!", victim, NULL, NULL, TO_ROOM);
if (IS_AFFECTED(victim, AFF_FLYING) && !is_affected(victim, gsn_thrash)){
AFFECT_DATA af;
af.where = TO_AFFECTS;
af.type = gsn_thrash;
af.level = ch->level;
af.duration = 0;
af.modifier = 0;
af.location = 0;
af.bitvector = 0;
affect_to_char(victim,&af);
act("You can't seem to get back into the air",victim,NULL,NULL,TO_CHAR);
act("$n can't seem to get back into the air",victim,NULL,NULL,TO_ROOM);
WAIT_STATE2(victim, skill_table[sn].beats);
}
}
/* Eirik tattoo spell, makes person always visible to the one who marked them */
void spell_mark_prey( int sn, int level, CHAR_DATA *ch, void *vo,int target )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af, *paf;
if (is_affected(victim, gsn_mark_prey))
return;
if ( saves_spell( level, victim,DAM_OTHER,skill_table[sn].spell_type) ){
return;
}
af.where = TO_AFFECTS;
af.type = gsn_mark_prey;
af.level = level;
af.duration = number_range(4, 6);
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = 0;
paf = affect_to_char( victim, &af );
string_to_affect(paf, ch->name);
act_new( "You sense you have been marked somehow.", victim, NULL, NULL, TO_CHAR, POS_DEAD );
act( "$n has been marked by $G's power.", victim, NULL, ch, TO_ROOM );
}
/* Tattoo spell for Sirantnot usable otherwise */
void spell_swords_to_plows( int sn, int level, CHAR_DATA *ch, void *vo,int target ){
/*
spell takes a difference between the caster's and victims rares
if the difference is positive it gets a chance based on quadratic
increase on the difference, and if chance roll paces a single rare
on the victim gets turned into a relativly worthless item.
Description of the worthless item is based on item type.
*/
const int max_rare = 25;
CHAR_DATA* victim = (CHAR_DATA*) vo;
OBJ_DATA* obj;
OBJ_DATA* rares[max_rare];
int chance = 0;
int ch_rare = 0;
int ch_worn = 0;
int vch_rare = 0;
int i = 0;
if (victim == NULL || IS_NPC(victim)
|| IS_IMMORTAL(victim))
return;
/* check if the ch is not near naked to prevent abuse */
for (i = 0; i < sizeof(eq_positions)/sizeof(eq_positions[0]); i++){
if ( ( obj = get_eq_char( ch, eq_positions[i] ) ) != NULL )
ch_worn ++;
}
if (ch_worn < (2 * (sizeof(eq_positions)/sizeof(eq_positions[0])) / 3)
&& !IS_IMMORTAL(ch))
return;
/* count rares on ch */
for ( obj = ch->carrying; obj != NULL; obj = obj->next_content ){
if (IS_LIMITED(obj) && !IS_SET(obj->wear_flags, ITEM_HAS_OWNER))
ch_rare ++;
}
/* count rares on victim and prep them for selection */
for ( obj = victim->carrying; obj != NULL; obj = obj->next_content ){
if (IS_LIMITED(obj) && !IS_SET(obj->wear_flags, ITEM_HAS_OWNER)){
rares[++vch_rare] = obj;
}
}
/* get the chance */
chance = (vch_rare - ch_rare) * (vch_rare - ch_rare) / 2;
chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);
if (number_percent() > chance)
return;
/* get a random rare to convert */
if (vch_rare)
obj = rares[number_range(1, vch_rare)];
else
return;
act("Before your eyes $p shimmers and changes.", victim, obj, NULL, TO_ALL);
/* now we start converting it */
{
AFFECT_DATA* paf;
obj->enchanted = TRUE;
for (paf = obj->affected; paf != NULL; paf = paf->next)
free_affect(paf);
/* get rid of rare etc. */
REMOVE_BIT(obj->wear_flags, ITEM_RARE);
REMOVE_BIT(obj->wear_flags, ITEM_UNIQUE);
/* extras*/
obj->extra_flags = 0;
/* reset the values */
if (obj->item_type != ITEM_SCROLL
&& obj->item_type != ITEM_STAFF
&& obj->item_type != ITEM_POTION){
obj->value[1] = 5;
obj->value[2] = 5;
}
/* set name short and long desc. */
{
char* name = item_name(obj->item_type);
char shield[] = "shield";
char buf[MIL];
if (obj->item_type == ITEM_WEAPON)
name = weapon_name(obj->value[0]);
else if (obj->item_type == ITEM_ARMOR){
if (CAN_WEAR(obj, ITEM_WEAR_SHIELD))
name = shield;
}
/* name */
sprintf(buf, "copper %s", name);
free_string(obj->name);
obj->name = str_dup(buf);
/* short */
sprintf(buf, "a copper %s", name);
free_string(obj->short_descr);
obj->short_descr = str_dup(buf);
/* long */
sprintf(buf, "A copper %s is here", name);
free_string(obj->description);
obj->description = str_dup(buf);
/* material */
sprintf(buf, "copper");
free_string(obj->material);
obj->material = str_dup(buf);
}
}
}