/*
SillyMUD Distribution V1.1b (c) 1993 SillyMUD Developement
See license.doc for distribution terms. SillyMUD is based on DIKUMUD
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "protos.h"
extern struct time_info_data time_info; /* In db.c */
extern unsigned char moontype;
extern struct weather_data weather_info;
extern int gSunSet, gSunRise, gMoonRise, gMoonSet; /* weather.c */
struct PolyType DruidList[17] = {
{"bear", 10, 9024},
{"spider", 10, 20010},
{"lamia", 10, 3648},
{"lizard", 10, 6822},
{"bear", 12, 9056}, /* 5 */
{"gator", 12, 9054},
{"basilisk", 13, 7043},
{"snog", 14, 27008},
{"snake", 15, 6517},
{"spider", 15, 6113}, /* 10 */
{"lizard", 16, 6505},
{"allosaurus", 18, 21801},
{"tiger", 28, 9027},
{"mulichort", 30, 15830},
{"tiger", 35, 9055}, /* 15 */
{"lion", 35, 13718},
{"salamander", 35, 25506} /* 17 */
};
/* #define LAST_DRUID_MOB 16, moved to poly.h */
#define VAMPIRE_BAT 3066
void do_changeform(struct char_data *ch, char *argument, int cmd)
{
char buf[80];
int mobn, X=LAST_DRUID_MOB, found=FALSE, level;
struct char_data *mob;
struct affected_type af;
level = GET_LEVEL(ch, DRUID_LEVEL_IND) ;
level = (level ? level : GetMaxLevel(ch)); /* for vampires */
sprintf(buf,"Level %d thing doing a changeform.",level);
log(buf);
one_argument(argument,buf);
if(!*buf) {
if (HasClass(ch, CLASS_DRUID)) {
send_to_char("You are able to change into the following forms:\n\r",ch);
send_to_char("Format: <level> - <name>\n\r",ch);
send_to_char(" ", ch);
for(mobn=1; LAST_DRUID_MOB+1 >= mobn && level >= DruidList[mobn].level;
mobn++) {
sprintf(buf,"%2d - %-15s ",DruidList[mobn].level,DruidList[mobn].name);
if(!(mobn%3))
strcat(buf,"\n\r ");
send_to_char(buf, ch);
}
send_to_char("\n\rIn order to change into one of these forms enter:\n\r",ch);
send_to_char("changeform <name>\n\r",ch);
} else if( GET_RACE(ch) == RACE_VAMPIRE) {
send_to_char("Vampires may only change into bats.\n\r", ch);
} else {
send_to_char("Ack, you can't change into anything!\n\r", ch);
}
return;
}
if (IS_NPC(ch)) {
send_to_char("You don't really want to do that.\n\r",ch);
return;
}
if (affected_by_spell(ch, SKILL_CHANGE_FORM)) {
send_to_char("You can only change form once every 8 hours.\n\r", ch);
return;
}
if (HasClass(ch, CLASS_DRUID)) {
if(IS_EVIL(ch) || IS_GOOD(ch)) {
send_to_char("You unable to change your form. You have strayed too\n\r",
ch);
send_to_char("far from nature's path to be one with her.\n\r",ch);
return;
}
while (!found) {
if (DruidList[X].level > level) {
X--;
} else {
if (!str_cmp(DruidList[X].name, buf)) {
mobn = DruidList[X].number;
found = TRUE;
} else {
X--;
}
if (X < 0) {
break;
}
}
}
if (!found) {
send_to_char("You couldn't summon an image of that creature.\n\r", ch);
return;
} else {
mob = read_mobile(mobn, VIRTUAL);
if (mob) {
af.type = SKILL_CHANGE_FORM;
af.duration = 8;
af.modifier = 0;
af.location = APPLY_NONE;
af.bitvector = 0;
affect_to_char(ch, &af);
spell_poly_self(level, ch, mob, 0);
} else {
send_to_char("You couldn't summon an image of that creature.\n\r", ch);
return;
}
}
} else if(GET_RACE(ch) == RACE_VAMPIRE) {
mob = read_mobile(VAMPIRE_BAT, VIRTUAL);
if(mob) {
mob->points.max_hit += level*2;
GET_HIT(mob) = GET_MAX_HIT(mob);
GET_RACE(ch) = RACE_VAMPIRE;
SET_BIT(mob->specials.affected_by, AFF_INFRAVISION);
if(level > 5)
SET_BIT(mob->specials.affected_by, AFF_SENSE_LIFE);
if(level > 10)
SET_BIT(mob->specials.affected_by2, AFF2_ANIMAL_INVIS);
if(level > 15)
SET_BIT(mob->specials.affected_by, AFF_TREE_TRAVEL);
if(level > 20)
SET_BIT(mob->specials.affected_by, AFF_INVISIBLE);
if(level > 25)
SET_BIT(mob->specials.affected_by, AFF_DETECT_INVISIBLE);
if(level > 30)
SET_BIT(mob->specials.affected_by, AFF_DETECT_MAGIC);
if(level > 35)
SET_BIT(mob->specials.affected_by, AFF_SNEAK);
if(level > 40)
SET_BIT(mob->specials.affected_by, AFF_TRUE_SIGHT);
if(level > 45)
SET_BIT(mob->specials.affected_by, AFF_GROWTH);
af.type = SKILL_CHANGE_FORM;
af.duration = 8;
af.modifier = 0;
af.location = APPLY_NONE;
af.bitvector = 0;
affect_to_char(ch, &af);
spell_poly_self(level, ch, mob, 0);
GET_AC(ch) -= level*2;
} else {
send_to_char("Ack, the bat form is acting screwy, not bats! Bug an imp!\n\r", ch);
return;
}
} else {
send_to_char("Try as you might, your body does not alter its shape.\n\r",
ch);
}
}
void do_bite(struct char_data *ch, char *argument, int cmd)
{
char arg[80];
struct char_data *victim;
if(GET_RACE(ch) != RACE_VAMPIRE) {
do_action(ch, argument, cmd);
return;
}
if (check_peaceful(ch, "You feel too peaceful to contemplate feeding.\n\r"))
return;
only_argument(argument, arg);
if (*arg) {
victim = get_char_room_vis(ch, arg);
if (victim) {
if(GetMaxLevel(victim) >= LOW_IMMORTAL) {
send_to_char("Immortals should not be considered food.\n\r", ch);
send_to_char("You think someone is eyeing you for lunch.\n\r", victim);
return;
} else if (!IsHumanoid(victim) || IsUndead(victim)) {
send_to_char("How on earth could you consider feeding on such a thing?\n\r", ch);
return;
} else if (victim == ch) {
send_to_char("Suck your own blood? I think not.\n\r", ch);
act("$n contemplates feeding on $mself but decides against it.",
TRUE, ch, 0, victim, TO_ROOM);
return;
} else if(IS_AFFECTED(ch, AFF_CHARM) && (ch->master == victim)) {
send_to_char("Your master would be very unpleased if you tried that!\n\r", ch);
return;
}
if( (!ch->specials.fighting) ) {
if( (!victim->specials.fighting) ) {
if (GET_POS(ch)>=POSITION_STANDING) {
if (!ch->equipment[WIELD]) {
SET_BIT(ch->specials.affected_by2, AFF2_FEEDING);
hit(ch, victim, TYPE_UNDEFINED);
} else
send_to_char("You can't be wielding anything to feed!\n\r", ch);
} else
send_to_char("Hey, why don't you try doing this when on your feet!\n\r", ch);
} else
send_to_char("You can't do this when they are fighting!\n\r", ch);
} else
send_to_char("How can you think about your stomach at a time like this?!?!\n\r", ch);
} else
send_to_char("Sink your fangs into who?\n\r", ch);
} else
send_to_char("Sink your fangs into who?\n\r", ch);
}
void MindflayerAttack(struct char_data *ch, struct char_data *v)
{
int loss;
if(ch->specials.bitten)
return;
if(number(1,100) > (GetMaxLevel(ch)) + GET_DEX(ch))
return;
if (v->equipment[WEAR_HEAD]) { /* hey, this bozo has headgear! */
if(number(1,10) >= (v->equipment[WEAR_HEAD]->obj_flags.value[0])) {
/* I figure steel (plate) helm = 30% chance of hitting head */
act("$n almost sucked you with $s tentacles, your headgear blocked it!",
FALSE, ch, 0, v, TO_VICT);
act("Your tentacles are blocked by $N's headgear!", FALSE, ch, 0,
v, TO_CHAR);
act("$N's tentacles are blocked by $n's headgear!", FALSE, ch, 0,
v, TO_NOTVICT);
return;
}
}
if(HitOrMiss(ch, v, CalcThaco(ch)) && GetMaxLevel(v) < LOW_IMMORTAL) {
/* ha ha, we suck them */
act("$N screams out in pain as $n's tentacles suck $S energies!", FALSE,
ch, 0, v, TO_NOTVICT);
act("$n's tentacles momentarily wrap themselves around your head!", FALSE,
ch, 0, v, TO_VICT);
send_to_char("Blinding pain fills your head, and flashes of red dot your vision.\n\r",v);
if(IS_SET(v->player.class, CLASS_MAGIC_USER | CLASS_CLERIC | CLASS_DRUID))
send_to_char("You feel weaker.\n\r", v);
act("You wrap your tentacles around $N's head.", FALSE, ch, 0, v,
TO_CHAR);
loss = number(1,GetMaxLevel(ch));
if(GET_MANA(v) > 0) {
GET_MANA(ch) += loss;
GET_MANA(v) -= loss;
act("You suck away some of $S magical energies!", FALSE, ch, 0, v,
TO_CHAR);
} else {
act("Blech, $E has no more magical energies for you to drain.", FALSE,
ch, 0, v, TO_CHAR);
}
GET_HIT(v) -= loss/2;
update_pos(v);
if(GET_POS(v) == POSITION_DEAD)
DamageEpilog(ch,v);
}
}
void VampireBite(struct char_data *ch, struct char_data *v)
{
bool to_bite = FALSE;
float chance;
/* when a vampire attempts to feed I think that they should not */
/* go about pummeling their victims with their fists. Nor should */
/* they kill someone and eat their corpse. They should not be armed, */
/* again, they are trying to subdue and bite. So, here's the biting */
/* part :) */
if(v->specials.bitten) { /* vampire's victim */
chance = GET_STR(v) - GET_STR(ch);
chance *= 3.4; /* chance from +51 to -51 */
chance += GetMaxLevel(v) - GetMaxLevel(ch);
/* chance is now some # from +100 to -100 */
/* we bite better at night :) */
if(time_info.hours < gSunRise && time_info.hours > gSunSet -1)
chance += number(1,50); /* chance from +150 to -50 */
/* for avg str diff of 5, 17%, if same level, chance = 17% + [1->50] */
/* or, about 42% */
/* for str diff of 8, 27%, if 10 level dif., 37%, chance averages 62% */
/* NOTE: This is the chance for the vampire to keep ahold of v */
if(GetMaxLevel(ch) < GetMaxLevel(v)-5) /* life seemed too easy */
chance+=25;
if(chance > number(1,100)) {
act("$N struggles violently and breaks free of $n's grasp!", FALSE,
ch, 0, v, TO_NOTVICT);
act("$N struggles violently and breaks free of your grasp!", FALSE,
ch, 0, v, TO_CHAR);
act("You struggle violently and break free of $n's grasp!", FALSE,
ch, 0, v, TO_VICT);
v->specials.bitten = FALSE;
return;
} else {
act("$N limply struggles in your grasp.", FALSE, ch, 0, v, TO_CHAR);
act("$N limply struggles in $n's clutches.",FALSE, ch, 0, v, TO_NOTVICT);
act("You struggle to free yourself of $n's grasp, but can't.", FALSE,
ch, 0, v, TO_VICT);
to_bite = TRUE;
}
} else { /* attemp to bite */
if(HitOrMiss(ch, v, CalcThaco(ch))) {
to_bite = TRUE;
} else {
to_bite = FALSE;
act("$n bares $s long, sharp fangs and almost bites you!", FALSE, ch,
0, v, TO_VICT);
act("$N avoids your fangs!", FALSE, ch, 0, v, TO_CHAR);
act("$N narrowly avoids $n's bared fangs!", FALSE, ch, 0, v, TO_NOTVICT);
}
}
if(to_bite) {
int loss, ammt;
v->specials.bitten = TRUE;
loss = number(1,MAX(10, GetMaxLevel(ch)));
if(GET_HIT(v) > 0) {
act("You savor the salty taste of $N's blood as you drain it.", FALSE,
ch, 0, v, TO_CHAR);
act("$n sinks $s fangs into $N's neck and drinks deeply.", FALSE, ch, 0,
v, TO_NOTVICT);
act("$n sinks $s fangs into your neck drains away your essence.", FALSE,
ch, 0, v, TO_VICT);
gain_condition(ch,FULL, MAX(loss/10,3));
ammt = number(1,loss);
if(GET_HIT(v) - ammt <= 0)
ammt = ammt = GET_HIT(v);
(ammt > 0) ? ammt : 0;
GET_HIT(v) -= ammt;
GET_HIT(ch) += ammt;
loss -= ammt;
if(loss > 0) {
ammt = number(1, loss);
if(GET_MOVE(v) - ammt <= 0)
ammt = GET_MOVE(v);
ammt = (ammt > 0) ? ammt : 0;
GET_MOVE(ch) += ammt;
GET_MOVE(v) -= ammt;
loss -= ammt;
}
if(loss > 0) {
if(GET_MANA(v) - loss <= 0)
loss = GET_MANA(v);
loss = (loss > 0) ? loss : 0;
GET_MANA(v) -= loss;
GET_MANA(ch) += loss;
}
} else {
send_to_char("You cannot drain anything more from this lifeless husk.\n\r", ch);
act("You put $N out of $S misery.", FALSE, ch, 0, v, TO_CHAR);
act("$n rips out your throat.", FALSE, ch, 0, v, TO_VICT);
act("$n rips out $N's throat and drops the lifeless body to the ground.",
TRUE, ch, 0, v, TO_NOTVICT);
GET_HIT(v) -= 20;
update_pos(v);
if(GET_POS(v) == POSITION_DEAD) /* and it damn well better be */
DamageEpilog(ch,v);
}
}
}
int veggie_gain_mods(struct char_data *ch, int gain, bool msgs)
{
int bonus=0;
if(time_info.hours > gSunRise && time_info.hours < gSunSet) { /* daylight */
if(weather_info.sky < 2) { /* partly cloudy & sunny */
if(!IS_SET(real_roomp(ch->in_room)->room_flags, INDOORS)) {
if(!IS_SET(real_roomp(ch->in_room)->room_flags, DARK)) {
if(real_roomp(ch->in_room)->sector_type != SECT_INSIDE &&
real_roomp(ch->in_room)->sector_type != SECT_CITY &&
real_roomp(ch->in_room)->sector_type != SECT_DESERT) {
/* we are now outdoors in good weather with sun! */
bonus += gain>>1;
if(msgs)
send_to_char("Ahh, this weather is most invigorating.\n\r",ch);
} else if( real_roomp(ch->in_room)->sector_type == SECT_DESERT) {
bonus -= gain>>2;
if(msgs)
send_to_char("The heat and dry wind parch your skin.\n\r", ch);
}
} else {
if(msgs)
send_to_char("You wish the sun were caressing your limbs once again.\n\r", ch);
}
} else { /* we are indoors */
if(msgs)
send_to_char("You yearn to return outside once again.\n\r", ch);
}
} /* is raining or worse */
} else if(time_info.hours < gSunRise || time_info.hours > gSunSet) {
if(msgs)
send_to_char("Your metabolism slows from lack of sunlight.\n\r", ch);
bonus -= gain>>2;
}
return(bonus);
}
int vamp_gain_mods(struct char_data *ch, int gain, bool msgs)
{
/* hierarchy of vampire problems in the world: */
/* 1st: gain in sunlight is -1. */
/* 2nd: gain elsewhere is normal */
/* gain during nightimes at 3/4ths or better moons better regen */
if(time_info.hours > gSunRise && time_info.hours < gSunSet - 1) {
if(OUTSIDE(ch) && IS_LIGHT(ch->in_room)) {
/* we are outside in daylight! nuke the gain! */
if(msgs)
send_to_char("You cower in the sunlight.\n\r", ch);
return(-gain);
}
} else if(time_info.hours < gSunRise || time_info.hours > gSunSet) {
if(moontype > 20 && moontype < 28 ) { /* 3/4ths or better moon */
if(msgs)
send_to_char("The energy of the moon fills your veins.\n\r", ch);
return(10);
}
}
return(0);
}