/************************************************************************ Realms of Aurealis James Rhone aka Vall of RoA bard.c Code dealing with the fully original bard class, complete with spells/songs/skills. Conceptual design: Mouseglove Implementation : Vall ******** 100% completely original code ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** 100% completely original code ******** All rights reserved henceforth. Please note that no guarantees are associated with any code from Realms of Aurealis. All code which has been released to the general public has been done so with an 'as is' pretense. RoA is based on both Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well as the RoA license. *** Read, Learn, Understand, Improve *** *************************************************************************/ /* Bards: As told by the Lord of Intrigue, Mouseglove Bards are a traditionally a group of wandering storytellers and singers. They collect the tales and lore of the realms, and perform for all sorts, from peasants to kings, and everyone inbetween. They are rather roguish, and are infamous for their sexual exploits, and their lack of propriaty when it comes to someone's property, be that living or non-living. Bards advance on a similar same scale to thieves, but in actuality taking only slightly longer than their rogue associates. They gain very few combat skills, but can use all weapons, armor and magic items usable by warriors, thieves or mages. They possess magical abilities which manifest themselves through their songs, which may be sung to shelter and heal the bard, to motivate companions in travel or combat, or to hinder one's foes in the heat of battle. Class: Bard Races allowed: Human, Elven, Half-Elven, Drow, Dwarven. */ #include "conf.h" #include "sysdep.h" #include "structures.h" #include "utils.h" #include "db.h" #include "comm.h" #include "handler.h" #include "mudlimits.h" #include "magic.h" #include "interpreter.h" #include "acmd.h" #include "bard.h" #include "affect.h" #include "fight.h" #include "lists.h" #include "global.h" #include "darkenelf.h" /* extern variables mon */ extern struct song_type song_types[]; extern char *inst_names[]; extern char *song_names[]; extern char *song_names_cap[]; // internal variables char *perform_type[2] = { "play", "sing" }; // show the list of available songs to the player void show_songs(chdata *ch) { int i; BOOL line = TRUE; send_to_char("These are the %6songs%0 you know:\n\r",ch); send_to_char("%B%6-=-=-=-=-=-=-=-=-=-=-=-=-=-=-%0\n\r",ch); for(i = 1; *song_names_cap[i] != '\n'; i++) if (GET_LEVEL(ch) >= song_types[i].min_level) { sprintf(buf, "%%6%-20.20s%%0 ", song_names_cap[i]); if ((line = !line)) str_cat(buf, "\n\r", MAX_STRING_LENGTH, "show_songs"); S2C(); } if (!line) send_to_char("\n\r",ch); } /* special song affect functions for certain songs which have song length durations on all who are affected by it */ /* is ch affected by a certain song_affect */ BOOL affected_by_song(chdata *ch, int song) { struct song_affect *sg; for (sg = ch->specials.songs; sg; sg=sg->next) if (sg->song == song) return TRUE; /* now for the special affected songs */ if (song >= 250 && affected_by_spell(ch, song)) return TRUE; return FALSE; } /* add and remove song affects based on song number RoA*/ void song_affect_modify(chdata *ch, int song, BOOL add) { if (add) switch (song) { default: break; } else /* remove this affect */ switch (song) { case 15: /* calys sleep */ if (affected_by_spell(ch, SPELL_SLEEP)) { send_to_char("The sleepy song has ended along with your slumber!\n\r",ch); affect_from_char(ch, SPELL_SLEEP); affect_total(ch); } break; case 18: /* bog march */ if (affected_by_spell(ch, SPELL_SONG_BOG)) { send_to_char("The song has ended and you feel quicker!\n\r",ch); affect_from_char(ch, SPELL_SONG_BOG); affect_total(ch); } break; case 20: /* beguiling */ if (affected_by_spell(ch, SPELL_CHARM_PERSON)) { send_to_char("That charming song has ended!\n\r",ch); affect_from_char(ch, SPELL_CHARM_PERSON); stop_follower(ch); affect_total(ch); } break; case 21: /* amitar */ if (affected_by_spell(ch, SPELL_SONG_AMITAR)) { send_to_char("The song has ended and you feel vulnerable!\n\r",ch); affect_from_char(ch, SPELL_SONG_AMITAR); affect_total(ch); } break; case 22: /* triumph of heroes */ if (affected_by_spell(ch, SPELL_HASTE)) { send_to_char("The song has ended and you feel slower!\n\r",ch); affect_from_char(ch, SPELL_HASTE); affect_total(ch); } break; case 24: /* goddess balm */ if (affected_by_spell(ch, SPELL_SONG_BALM)) { send_to_char("The song has ended and you feel vulnerable!\n\r",ch); affect_from_char(ch, SPELL_SONG_BALM); affect_total(ch); } break; default: break; } } /* Insert an song_type in a char_data structure -RoA */ void song_to_char(chdata *ch, struct song_affect *sg) { struct song_affect *song_alloc; CREATE(song_alloc, struct song_affect, 1); *song_alloc = *sg; song_alloc->next = ch->specials.songs; ch->specials.songs = song_alloc; song_affect_modify(ch, song_alloc->song, TRUE); } /* Remove a song_affect structure from a char (called when duration reaches 0 or the performer stops performing). Pointer *sg must never be NULL! Frees mem James Rhone RoA */ void song_from_char(chdata *ch, struct song_affect *sg ) { struct song_affect *temp; assert(ch->specials.songs); song_affect_modify(ch, sg->song, FALSE); REMOVE_FROM_LIST(sg, ch->specials.songs, next); FREENULL(sg); } /* called when a character stops singing/playing to unaffect everything that was affected by his/her song */ void remove_song_from_world(chdata *ch, sh_int song) { chdata *k; struct song_affect *sg; for (k = character_list; k; k = k->next) for(sg = k->specials.songs; sg; sg=sg->next) if (sg->performer == ch && sg->song == song) { song_from_char(k, sg); break; } } // for those room specific songs when character enters/leaves void remove_song_from_room(chdata *ch, sh_int song, int room) { chdata *k; struct song_affect *sg; for (k = world[room].people; k; k = k->next_in_room) for(sg = k->specials.songs; sg; sg=sg->next) if (sg->performer == ch && sg->song == song) { song_from_char(k, sg); break; } } // for those room specific songs when character enters/leaves BOOL bard_song_near_char(chdata *ch, sh_int song) { chdata *k; if (INVALID_ROOM(ch->in_room)) return FALSE; if (SINGING(ch) == song || PLAYING(ch) == song) return TRUE; for (k = world[ch->in_room].people; k; k = k->next_in_room) if (SINGING(k) == song || PLAYING(k) == song) return TRUE; return FALSE; } // avoid duped code, just send messages to char/room // and set up SINGING or PLAYING and durations -roa void setup_song(chdata *ch, int sing, int song) { sprintf(buf, "$n begins to %s %%B%%6%s%%0.", perform_type[sing], song_names_cap[song]); act(buf, FALSE, ch, 0, 0, TO_ROOM); sprintf(buf, "You begin to %s %%B%%6%s%%0.\n\r", perform_type[sing], song_names_cap[song]); S2C(); if (sing) { SINGING(ch) = song; SONG_TIME(ch) = song_types[song].song_duration; } else { PLAYING(ch) = song; PLAY_TIME(ch) = song_types[song].song_duration; } } /******************************************************************* following are specific songs and the procs specific to them called by do_sing *******************************************************************/ /* Gullem's Shelter : As per mages armor spell. */ ASONG(do_gullems) { chdata *vict = 0, *k = 0; struct affected_type af; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!affected_by_spell(ch, SPELL_ARMOR) && !affected_by_spell(ch, SPELL_STONE_SKIN) && !affected_by_spell(ch, SPELL_BARKSKIN)) { af.type = SPELL_ARMOR; af.duration = 10 + GET_LEVEL(ch)/2; af.modifier = -GET_LEVEL(ch); af.location = APPLY_AC; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You feel protected.\n\r", ch); } else { send_to_char("You are already protected.\n\r",ch); return SONG_FAILURE; } } else if (!str_cmp(argu, "group")) { if (!IS_AFFECTED(ch, AFF_GROUP)) { send_to_char("You are not a member of any group.\n\r",ch); return SONG_FAILURE; } act("You protect your party with your song.", FALSE, ch,0,0,TO_CHAR); while ((k = group_member(ch, TRUE))) { if (!affected_by_spell(k, SPELL_ARMOR) && !affected_by_spell(k, SPELL_STONE_SKIN) && !affected_by_spell(ch, SPELL_BARKSKIN)) { af.type = SPELL_ARMOR; af.duration = 10 + GET_LEVEL(ch)/2; af.modifier = -GET_LEVEL(ch); af.location = APPLY_AC; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(k, &af); send_to_char("You feel protected.\n\r",k); } } } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_ARMOR) && !affected_by_spell(vict, SPELL_STONE_SKIN) && !affected_by_spell(ch, SPELL_BARKSKIN)) { af.type = SPELL_ARMOR; af.duration = 10 + GET_LEVEL(ch)/2; af.modifier = -GET_LEVEL(ch); af.location = APPLY_AC; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You feel protected.\n\r", vict); if (ch != vict) act("You protect $N with your song.",TRUE,ch,0,vict,TO_CHAR); } else { send_to_char("You are already protected.\n\r",vict); return SONG_FAILURE; } } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Sylune's Sling : As per mages magic missile spell.*/ ASONG(do_sylunes) { chdata *victim; int dam = 0, num_missile = 0, missile_cnt = 0; victim = FIGHTING(ch); if (!*argu && !victim) { send_to_char("%6Sylune's Sling%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!victim) if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; num_missile = (GET_LEVEL(ch)/10) + 1; for (missile_cnt=1; missile_cnt <= num_missile; missile_cnt++) dam += number(1,4); /* Half Damage */ if ( saves_spell(victim, SPELL_MAGIC_MISSILE) ) dam >>= 1; damage(ch, victim, dam, SPELL_MAGIC_MISSILE, FALSE); WAIT_STATE(ch, spell_info[SPELL_MAGIC_MISSILE].beats); return SONG_SUCCESS; } /*Spirit Eyes : As per mages detect invisibility spell.*/ ASONG(do_spirit) { chdata *vict = 0; struct affected_type af; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!affected_by_spell(ch, SPELL_DETECT_INVISIBLE) && !affected_by_spell(ch, SPELL_FORESTEYES)) { af.type = SPELL_DETECT_INVISIBLE; af.duration = GET_LEVEL(ch) + 5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_INVISIBLE; af.bitvector2 = 0; affect_join(ch, &af, TRUE, FALSE); send_to_char("Your eyes tingle.\n\r", ch); } else send_to_char("Your eyes tingle for a moment.\n\r",ch); } else if (!str_cmp(argu, "group")) { send_to_char("This song cannot be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_DETECT_INVISIBLE) && !affected_by_spell(vict, SPELL_FORESTEYES)) { af.type = SPELL_DETECT_INVISIBLE; af.duration = GET_LEVEL(ch) + 5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_INVISIBLE; af.bitvector2 = 0; affect_join(vict, &af, TRUE, FALSE); act("Your eyes tingle.", FALSE, ch, 0, vict, TO_VICT); if (ch != vict) act("You offer $N enhanced sight with your song.", TRUE, ch, 0, vict, TO_CHAR); } else send_to_char("Your eyes tingle for a brief moment.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Glad Revelations : 10% +1%/level to identify item or mob (see some stats).*/ ASONG(do_glad) { chdata *victim; obdata *obj; if (IN_NOWHERE(ch)) return SONG_FAILURE; if (!*argu) { send_to_char("%6Glad Revelation%0 needs a target to be successful.\n\r",ch); return SONG_FAILURE; } victim = get_char_room_vis(ch, argu); obj = get_obj_in_list_vis(ch, argu, ch->carrying); if (!obj) obj = get_obj_in_list_vis(ch, argu, world[ch->in_room].contents); if (!victim && !obj) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); // have them cast the spell (*spell_info[SPELL_IDENTIFY].spell_pointer) (ch, "", victim, obj); return SONG_SUCCESS; } /*The Hound's Nose : As per mages detect magic spell ("sniff" out magic).*/ ASONG(do_hounds) { chdata *vict = 0, *k = 0; struct affected_type af; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) { if (!affected_by_spell(ch, SPELL_DETECT_MAGIC)) { af.type = SPELL_DETECT_MAGIC; af.duration = GET_LEVEL(ch) + 5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_MAGIC; af.bitvector2 = 0; affect_join(ch, &af, TRUE, FALSE); send_to_char("Your eyes tingle with magical awareness.\n\r", ch); } else send_to_char("Your eyes tingle for a moment.\n\r",ch); } else if (!str_cmp(argu, "group")) { if (!IS_AFFECTED(ch, AFF_GROUP)) { send_to_char("You are not a member of any group.\n\r",ch); return SONG_FAILURE; } act("You song provides your party with enhanced sight.", FALSE,ch,0,0,TO_CHAR); while ((k = group_member(ch, TRUE))) { if (!affected_by_spell(k, SPELL_DETECT_MAGIC)) { af.type = SPELL_DETECT_MAGIC; af.duration = GET_LEVEL(ch) + 5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_MAGIC; af.bitvector2 = 0; affect_join(k, &af, TRUE, FALSE); send_to_char("Your eyes tingle with magical awareness.\n\r", k); } } } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_DETECT_MAGIC)) { af.type = SPELL_DETECT_MAGIC; af.duration = GET_LEVEL(ch) + 5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_MAGIC; af.bitvector2 = 0; affect_join(vict, &af, TRUE, FALSE); send_to_char("Your eyes tingle with magical awareness.\n\r", vict); if (ch != vict) act("You offer $N magical awareness with your song.",TRUE,ch,0,vict,TO_CHAR); } else send_to_char("Your eyes tingle for a brief moment.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*The Inner Spirit : As per the shaman heartsight ability.*/ ASONG(do_inner) { chdata *vict = 0; struct affected_type af; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!IS_AFFECTED(ch, AFF_DETECT_ALIGN)) { af.type = SKILL_TRUESIGHT; af.duration = song_types[song].song_duration; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_ALIGN; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You are now able to see into the hearts of others!\n\r",ch); } else { send_to_char("You are already affected by heartsight.\n\r",ch); return SONG_FAILURE; } } else if (!str_cmp(argu, "group")) { send_to_char("This song may not be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, argu))) { if (!IS_AFFECTED(vict, AFF_DETECT_ALIGN)) { af.type = SKILL_TRUESIGHT; af.duration = song_types[song].song_duration; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_ALIGN; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You are now able to see into the hearts of others!\n\r",vict); if (ch != vict) act("You offer heartsight to $N with your song.",TRUE,ch,0,vict,TO_CHAR); } else { send_to_char("You are already affected by heartsight.\n\r",vict); return SONG_FAILURE; } } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Sunset Serenade : As per mages blindness spell.*/ ASONG(do_sunset) { chdata *victim; struct affected_type af; victim = FIGHTING(ch); if (!*argu && !(victim)) { send_to_char("%6Sunset Serenade%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!victim) if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; if (saves_spell(victim, SPELL_BLINDNESS) || affected_by_spell(victim, SPELL_BLINDNESS)) return SONG_SUCCESS; act("$n seems to be blinded!", TRUE, victim, 0, 0, TO_ROOM); send_to_char("You have been blinded!\n\r", victim); af.type = SPELL_BLINDNESS; af.location = APPLY_HITROLL; af.modifier = -4; /* Make hitroll worse */ af.duration = 1; af.bitvector = AFF_BLIND; af.bitvector2 = 0; affect_to_char(victim, &af); af.location = APPLY_AC; af.modifier = + 40; /* Make AC Worse! */ affect_to_char(victim, &af); return SONG_SUCCESS; } /*Serpent's Gaze : Puts target into trance (like grappled) for 2 rounds.*/ ASONG(do_serpent) { chdata *victim = 0; if (!(victim = FIGHTING(ch))) { send_to_char("You need to be fighting to invoke the %B%2Serpent's Gaze%0.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; if (saves_spell(victim, SPELL_HOLD_PERSON)) { act("The %B%2Serpent's Gaze%0 has no affect on $N!", TRUE, ch, 0, victim, TO_ROOM); return SONG_SUCCESS; } act("The %B%2Serpent's Gaze%0 places $N in a trans!", TRUE, ch, 0, victim, TO_ROOM); VWAIT(victim) = 2; return SONG_SUCCESS; } /*Azurel's Balm : As per cleric's cure serious wounds spell.*/ ASONG(do_azurels) { chdata *vict = NULL; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { vict = ch; GET_HIT(vict) += dice(4, 8) + 3; GET_HIT(vict) = MIN(GET_HIT(vict), GET_MAX_HIT(vict)); update_pos(vict); send_to_char("You feel better!\n\r", vict); } else if (!str_cmp(argu, "group")) { send_to_char("This song may not be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, argu))) { GET_HIT(vict) += dice(4, 8) + 3; GET_HIT(vict) = MIN(GET_HIT(vict), GET_MAX_HIT(vict)); update_pos(vict); send_to_char("You feel better!\n\r", vict); if (ch != vict) act("You offer healing to $N with your song.", TRUE, ch, 0, vict, TO_CHAR); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /* Harsh Dissonance : Inflicts lvl/2 damage in addition to all else per round.*/ // look in fight.c ASONG(do_harsh) { if (*argu) { send_to_char("You may only use this song on yourself.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); return SONG_SUCCESS; } /*Hero's Feast : Set group/individual's hunger/thirst to level/2.*/ ASONG(do_heroes) { chdata *vict = 0, *k = 0; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) { if (!IS_IMMORTAL(ch) && IS_PC(ch)) GET_COND(ch, FULL) = MIN(24, GET_LEVEL(ch)/2); send_to_char("You have been fed the feast of heroes.\n\r", ch); return SONG_SUCCESS; } else if (!str_cmp(argu, "group")) { if (!IS_AFFECTED(ch, AFF_GROUP)) { send_to_char("You are not a member of any group.\n\r",ch); return SONG_FAILURE; } act("You offer the %B%6Hero's Feast%0 to your party with your song.", FALSE, ch, 0, 0, TO_CHAR); while ((k = group_member(ch, TRUE))) { if (!IS_IMMORTAL(k) && IS_PC(k)) GET_COND(k, FULL) = MIN(24, GET_LEVEL(ch)/2); send_to_char("You have been fed the feast of heroes.\n\r",k); } } else if ((vict = get_char_room_vis(ch, argu))) { if (!IS_IMMORTAL(vict) && IS_PC(vict)) GET_COND(vict, FULL) = MIN(24, GET_LEVEL(ch)/2); act("$n has fed you the feast of heroes.", TRUE, ch, 0, vict, TO_VICT); if (ch != vict) act("You offer the %B%6Hero's Feast%0 to $N with your song.", TRUE, ch, 0, vict, TO_CHAR); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Winter's Storm : Conjures an ice shaft, doing lvl<d>4 damage to foe.*/ ASONG(do_winters) { chdata *victim; int dam = 0; victim = FIGHTING(ch); if (!*argu && !(victim)) { send_to_char("%6Winter's Storm%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!victim) if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; dam = dice(GET_LEVEL(ch), 4); if ( saves_spell(victim, SPELL_ICE_SHAFT) ) dam >>= 1; damage(ch, victim, dam, SPELL_ICE_SHAFT, FALSE); WAIT_STATE(ch, spell_info[SPELL_ICE_SHAFT].beats); return SONG_SUCCESS; } /*Shades Seclusion : As per thieves hide skill, until stopped.*/ ASONG(do_shades) { setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { SET_BIT(AFF_FLAGS(ch), AFF_HIDE); send_to_char("Your song blends you in with the shadows!\n\r", ch); return SONG_SUCCESS; } else { send_to_char("This song only affects the performer.\n\r",ch); return SONG_FAILURE; } } /* song id 14 */ /* use mage bless spell*/ /*Storm Shielded : Grant +lvl/10 to group's saving throw vs. spells.*/ ASONG(do_storm) { chdata *vict = 0, *k = 0; struct affected_type af; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!affected_by_spell(ch, SPELL_BLESS)) { af.type = SPELL_BLESS; af.duration = 10 + GET_LEVEL(ch)/2; af.modifier = 10; af.location = SV_MAGIC; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You feel magically protected.\n\r", ch); } else { send_to_char("You are already magically protected.\n\r",ch); return SONG_FAILURE; } } else if (!str_cmp(argu, "group")) { if (!IS_AFFECTED(ch, AFF_GROUP)) { send_to_char("You are not a member of any group.\n\r",ch); return SONG_FAILURE; } act("You magically protect your party with your song.",FALSE,ch,0,0,TO_CHAR); while ((k = group_member(ch, TRUE))) { if (!affected_by_spell(k, SPELL_BLESS)) { af.type = SPELL_BLESS; af.duration = 10 + GET_LEVEL(ch)/2; af.modifier = 10; af.location = APPLY_SV_MAGIC; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(k, &af); send_to_char("You feel magically protected.\n\r",k); } } } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_BLESS)) { af.type = SPELL_BLESS; af.duration = 10 + GET_LEVEL(ch)/2; af.modifier = 10; af.location = APPLY_SV_MAGIC; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You feel magically protected.\n\r", vict); if (ch != vict) act("You magically protect $N with your song.",TRUE,ch,0,vict,TO_CHAR); } else { send_to_char("You are already protected versus magic.\n\r",vict); return SONG_FAILURE; } } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Calypso's Lullaby: As per mage spell Sleep, but stays asleep for duration.*/ ASONG(do_calys) { chdata *victim; struct affected_type af; struct song_affect sg; victim = FIGHTING(ch); if (!*argu && !(victim)) { send_to_char("%6Calypso's Lullaby%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!victim) if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; if (IS_AFFECTED(victim, AFF_SLEEP)) { send_to_char("Your victim is already sleeping.\n\r",ch); return SONG_FAILURE; } if (!saves_spell(victim, SPELL_SLEEP)) { af.type = SPELL_SLEEP; af.duration = song_types[song].song_duration; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_SLEEP; af.bitvector2 = 0; affect_join(victim, &af, FALSE, FALSE); /* testing this song_affect to char RoA*/ sg.performer = ch; sg.song = song; sg.next = 0; song_to_char(victim, &sg); if (GET_POS(victim) > POS_SLEEPING) { act("$n falls asleep!", TRUE, victim, 0, 0, TO_ROOM); send_to_char("You have fallen asleep!\n\r", victim); GET_POS(victim) = POS_SLEEPING; } } else send_to_char("Your song has no affect!\n\r",ch); return SONG_SUCCESS; } /* use bless again? yes James Rhone (same type of spell affect) */ /* NO lets use the spell_song thing -jtrhone */ /* God's Favor : Increase one stat by 2 points. dur: lvl/2 ST*/ ASONG(do_gods) { chdata *vict = 0; struct affected_type af; byte stat; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; if (!*argu) { send_to_char("Usage: sing god's favor <self | (target)> <stat>.\n\r",ch); return SONG_FAILURE; } half_chop(argu, arg1, arg2); if (!*arg1 || !*arg2) { send_to_char("Usage: sing god's favor <self | (target)> <stat>.\n\r",ch); return SONG_FAILURE; } if (is_abbrev(arg2, "strength")) stat = APPLY_STR; else if (is_abbrev(arg2, "intelligence")) stat = APPLY_INT; else if (is_abbrev(arg2, "wisdom")) stat = APPLY_WIS; else if (is_abbrev(arg2, "dexterity")) stat = APPLY_DEX; else if (is_abbrev(arg2, "constitution")) stat = APPLY_CON; else { send_to_char("Unknown attribute. <str | int | wis | dex | con>.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!*arg1 || !str_cmp(arg1, "self") || !str_cmp(arg1, "me")) /* self */ { if (!affected_by_spell(ch, SKILL_SING)) { af.type = SKILL_SING; af.duration = GET_LEVEL(ch)/2; af.modifier = 2; af.location = stat; /* whichever stat ch chose */ af.bitvector = 0; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You feel magically affected by a song!\n\r",ch); } else send_to_char("You are already magically affected by a song.\n\r",ch); } else if (!str_cmp(arg1, "group")) { send_to_char("This song may not be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, arg1))) { if (!affected_by_spell(vict, SKILL_SING)) { af.type = SKILL_SING; af.duration = GET_LEVEL(ch)/2; af.modifier = 2; af.location = stat; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You feel magically affected by a song!\n\r",vict); if (ch != vict) act("You offer magical affection to $N with your song.",TRUE,ch,0,vict,TO_CHAR); } else send_to_char("You are already magically affected by a song.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Spring's Tempest : As per mages lightning bolt spell.*/ ASONG(do_springs) { chdata *victim; int dam; victim = FIGHTING(ch); if (!*argu && !(victim)) { send_to_char("%6Spring's Tempest%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!victim) if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; dam = number(16,48); if (saves_spell(victim, SPELL_LIGHTNING_BOLT)) dam >>= 1; damage(ch, victim, dam, SPELL_LIGHTNING_BOLT, FALSE); WAIT_STATE(ch, spell_info[SPELL_LIGHTNING_BOLT].beats); return SONG_SUCCESS; } /* song 18 */ /* use song_bog */ /* The Bog March : Reduce the target's attacks per round by one. (Min: 1) */ ASONG(do_bog) { chdata *victim; struct affected_type af; struct song_affect sg; if (!*argu) { send_to_char("%6Bog's March%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; if (saves_spell(victim, SPELL_HOLD_PERSON)) { act("$N resists your song!",TRUE,ch,0,victim,TO_CHAR); return SONG_SUCCESS; } if (!affected_by_spell(victim, SPELL_SONG_BOG)) { af.type = SPELL_SONG_BOG; af.duration = song_types[song].song_duration; af.modifier = -3; af.location = APPLY_DEX; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(victim, &af); send_to_char("You feel bogged down!\n\r",victim); sprintf(buf, "$n staggers as $e is bogged down!"); act(buf, FALSE, victim, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; /* 18 for bog march */ sg.next = 0; song_to_char(victim, &sg); } else send_to_char("Your song has no affect!\n\r",ch); WAIT_STATE(ch, spell_info[SPELL_HOLD_PERSON].beats); return SONG_SUCCESS; } /*Trial's Transfer : Energy drain, but singer gets 10% of all mana drained*/ ASONG(do_trials) { int gain_exp(chdata *ch, int gain); chdata *victim = 0; int dam, xp, mana; victim = FIGHTING(ch); if (!*argu && !victim) { send_to_char("%6Trial's Transfer%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!victim) if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; if (!saves_spell(victim, SPELL_ENERGY_DRAIN)) { GET_ALIGNMENT(ch) = MAX(-1000, GET_ALIGNMENT(ch) - 200); if (GET_LEVEL(victim) <= 5) damage(ch, victim, 100, SPELL_ENERGY_DRAIN, FALSE); else { xp = number(GET_LEVEL(ch) >> 1, GET_LEVEL(ch)) * 1000; gain_exp(victim, -xp); dam = dice(1, 10); mana = GET_MANA(victim) >> 1; GET_MOVE(victim) >>= 1; GET_MANA(victim) = mana; GET_MANA(ch) += mana >> 1; GET_HIT(ch) += dam; send_to_char("Your life energy is drained!\n\r", victim); damage(ch, victim, dam, SPELL_ENERGY_DRAIN, FALSE); } } else damage(ch, victim, 0, SPELL_ENERGY_DRAIN, FALSE); /* Miss */ WAIT_STATE(ch, spell_info[SPELL_ENERGY_DRAIN].beats); return SONG_SUCCESS; } /* 20 */ /* use song_baan */ /* Baan's Beguiling : Charm Person, but costs each round to maintain.*/ ASONG(do_baans) { chdata *victim; struct affected_type af; struct song_affect sg; if (!*argu) { send_to_char("%6Baan's Beguiling%0 needs an enemy target to be successful.\n\r",ch); return SONG_FAILURE; } if (!(victim = get_char_room_vis(ch, argu))) { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); if (!check_truce(ch, victim)) return SONG_FAILURE; if (!check_mortal_combat(ch, victim)) return SONG_FAILURE; if (IS_PC(victim) || MOB_FLAGGED(victim, MOB_NO_CHARM)) { send_to_char("Your song has no affect!\n\r",ch); return SONG_SUCCESS; } if (GET_LEVEL(victim) > GET_LEVEL(ch)) { act("$N is too powerful for you to charm!",TRUE,ch,0,victim,TO_CHAR); return SONG_SUCCESS; } if (MOB_FLAGGED(victim, MOB_NO_CHARM) || IS_AFFECTED(victim, AFF_SANCTUARY) || saves_spell(victim, SPELL_CHARM_PERSON)) { act("$N resists your song!",TRUE,ch,0,victim,TO_CHAR); return SONG_SUCCESS; } if (CHARMED(ch)) { send_to_char("You cannot charm if you are charmed yourself.\n\r",ch); return SONG_FAILURE; } if(circle_follow(victim, ch)) { send_to_char("Sorry, following in circles is not allowed.\n\r", ch); return SONG_FAILURE; } if (!CHARMED(victim)) { if (victim->master) stop_follower(victim); add_follower(victim, ch); af.type = SPELL_CHARM_PERSON; af.duration = song_types[song].song_duration; af.modifier = 0; af.location = 0; af.bitvector = AFF_CHARM; af.bitvector2 = 0; affect_to_char(victim, &af); send_to_char("You feel charmed!\n\r",victim); /* testing this song_affect to char RoA*/ sg.performer = ch; sg.song = song; sg.next = 0; song_to_char(victim, &sg); } else send_to_char("Your song has no affect!\n\r",ch); WAIT_STATE(ch, spell_info[SPELL_CHARM_PERSON].beats); return SONG_SUCCESS; } /* 21 */ /* song amitar */ /* Amitar's Asylum : Single target able to ignore all damage from attacks.*/ ASONG(do_amitars) { chdata *vict = 0; struct affected_type af; struct song_affect sg; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!affected_by_spell(ch, SPELL_SONG_AMITAR)) { af.type = SPELL_SONG_AMITAR; af.duration = song_types[song].song_duration; af.modifier = 1; af.location = APPLY_DEX; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You feel protected by a magical asylum!\n\r",ch); sprintf(buf, "$n is suddenly surrounded by a magical orb!"); act(buf, FALSE, ch, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; /* 21 for amitars asylum */ sg.next = 0; song_to_char(ch, &sg); } else send_to_char("You are already under Amitar's Asylum.\n\r",ch); } else if (!str_cmp(argu, "group")) { send_to_char("This song cannot be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_SONG_AMITAR)) { af.type = SPELL_SONG_AMITAR; af.duration = song_types[song].song_duration; af.modifier = 1; af.location = APPLY_DEX; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(vict, &af); sg.performer = ch; sg.song = song; /* 21 for amitars asylum */ sg.next = 0; song_to_char(vict, &sg); send_to_char("You feel protected by a magical asylum!\n\r",vict); sprintf(buf, "$n is suddenly surrounded by a magical orb!"); if (ch != vict) act(buf, FALSE, vict, 0, 0, TO_ROOM); } else send_to_char("You are already under Amitar's Asylum.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /* use mages spell_haste */ /* Hero's Triumph : As per mages haste spell.*/ ASONG(do_triumph) { chdata *vict = 0; struct affected_type af; struct song_affect sg; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!affected_by_spell(ch, SPELL_HASTE)) { af.type = SPELL_HASTE; af.duration = 4; af.modifier = 2; af.location = APPLY_DEX; af.bitvector = AFF_HASTE; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You feel your body sizzling with energy.\n\r", ch); act("$n's body starts to sizzle with energy.", FALSE, ch, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; sg.next = 0; song_to_char(ch, &sg); } else send_to_char("You are already affected by haste.\n\r",ch); } else if (!str_cmp(argu, "group")) { send_to_char("This song may not be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_HASTE)) { af.type = SPELL_HASTE; af.duration = 4; af.modifier = 2; af.location = APPLY_DEX; af.bitvector = AFF_HASTE; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You feel your body sizzling with energy.\n\r", vict); if (ch != vict) act("$n's body starts to sizzle with energy.", FALSE, vict, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; sg.next = 0; song_to_char(ch, &sg); } else send_to_char("You are already affected by haste.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Tortured Soul : Damage target for level<d>4 per round.*/ ASONG(do_tortured) { if (*argu) { send_to_char("You may only use this song on yourself.\n\r",ch); return SONG_FAILURE; } setup_song(ch, sing, song); return SONG_SUCCESS; } /* 24 */ /* song balm */ /* A Goddess' Balm : Subtract lvl from all damage taken by target/group.*/ ASONG(do_goddess) { chdata *vict = 0, *k = 0; struct affected_type af; struct song_affect sg; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) { if (!affected_by_spell(ch, SPELL_SONG_BALM)) { af.type = SPELL_SONG_BALM; af.duration = song_types[song].song_duration; af.modifier = 1; af.location = APPLY_DEX; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You feel protected by a magical balm!\n\r",ch); sprintf(buf, "$n is suddenly surrounded by a magical orb!"); act(buf, FALSE, ch, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; /* 24 for goddess balm */ sg.next = 0; song_to_char(ch, &sg); } else send_to_char("You are already affected by that song.\n\r",ch); } else if (!str_cmp(argu, "group")) { if (!IS_AFFECTED(ch, AFF_GROUP)) { send_to_char("You are not a member of any group.\n\r",ch); return SONG_FAILURE; } act("You provide your party with the protection of your song.",FALSE,ch,0,0,TO_CHAR); while ((k = group_member(ch, TRUE))) { if (!affected_by_spell(k, SPELL_SONG_BALM)) { af.type = SPELL_SONG_BALM; af.duration = song_types[song].song_duration; af.modifier = 1; af.location = APPLY_DEX; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(k, &af); send_to_char("You feel protected by a magical balm!\n\r",k); sprintf(buf, "$n is suddenly surrounded by a magical orb!"); act(buf, FALSE, k, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; sg.next = 0; song_to_char(k, &sg); } } } else if ((vict = get_char_room_vis(ch, argu))) { if (!affected_by_spell(vict, SPELL_SONG_BALM)) { af.type = SPELL_SONG_BALM; af.duration = song_types[song].song_duration; af.modifier = 1; af.location = APPLY_DEX; af.bitvector = 0; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You feel protected by a magical balm!\n\r",vict); sprintf(buf, "$n is suddenly surrounded by a magical orb!"); if (ch != vict) act(buf, FALSE, vict, 0, 0, TO_ROOM); sg.performer = ch; sg.song = song; /* 24 for goddess balm */ sg.next = 0; song_to_char(vict, &sg); } else send_to_char("You are already protected by that song.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Jemidon's Pact : Affect target as per the shaman truce ritual.*/ ASONG(do_jemidon) { chdata *vict = 0; struct affected_type af; setup_song(ch, sing, song); if (!*argu || !str_cmp(argu, "self") || !str_cmp(argu, "me")) /* self */ { if (!IS_AFFECTED(ch, AFF_TRUCE)) { af.type = SKILL_TRUCE; af.duration = song_types[song].song_duration; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_TRUCE; af.bitvector2 = 0; affect_to_char(ch, &af); send_to_char("You are now affected by the shaman truce!\n\r",ch); } else send_to_char("You are already affected by the shaman truce.\n\r",ch); } else if (!str_cmp(argu, "group")) { send_to_char("This song may not be used on a group.\n\r",ch); return SONG_FAILURE; } else if ((vict = get_char_room_vis(ch, argu))) { if (!IS_AFFECTED(vict, AFF_TRUCE)) { af.type = SKILL_TRUCE; af.duration = song_types[song].song_duration; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_TRUCE; af.bitvector2 = 0; affect_to_char(vict, &af); send_to_char("You are now protected by the shaman truce!\n\r",vict); if (ch != vict) act("You offer the shaman truce to $N with your song.",TRUE,ch,0,vict,TO_CHAR); } else send_to_char("You are already affected by the shaman truce.\n\r",vict); } else { send_to_char("Your target is not here.\n\r",ch); return SONG_FAILURE; } return SONG_SUCCESS; } /*Song of Creation : Imbue a created instrument with +3 hitroll & Damroll.*/ ASONG(do_creation) { obdata *tmp_obj; int i, tnum; skip_spaces(&argu); if (!*argu || ((tnum = search_block(argu, inst_names, FALSE)) == -1)) { send_to_char("Usage: <sing/play> song of creation <instrument type>\n\r",ch); send_to_char("Available types are: \n\r",ch); for (i=0; *inst_names[i] != '\n'; i++) { sprintf(buf, " %%6%s%%0\n\r",inst_names[i]); S2C(); } return SONG_FAILURE; } setup_song(ch, sing, song); /* 116 is creation song instrument template */ if (!(tmp_obj = read_object(116, VIRTUAL))) { send_to_char("Something went wrong! Notify an Immortal.\n\r",ch); return SONG_FAILURE; } sprintf(buf, "inst instrument magic magical %s", inst_names[tnum]); tmp_obj->name = str_dup(buf); sprintf(buf, "%s's %%Bmagical%%0 %s is lying here.", GET_NAME(ch), inst_names[tnum]); tmp_obj->description = str_dup(buf); sprintf(buf, "%s's %%Bmagical%%0 %s", GET_NAME(ch), inst_names[tnum]); tmp_obj->shdesc = str_dup(buf); // also add actdesc 5/30/98 -jtrhone tmp_obj->actdesc = str_dup(buf); act("$n has crafted $p!", TRUE, ch, tmp_obj, 0, TO_ROOM); act("You have crafted $p!", TRUE, ch, tmp_obj, 0, TO_CHAR); // now assign owner to this object 5/30/98 -jtrhone tmp_obj->owner_of = GET_IDNUM(ch); OBJ_ID(tmp_obj) = tnum; obj_to_char(tmp_obj, ch); return SONG_SUCCESS; } ACMD(do_songlist) { int i; if (IS_NPC(ch) || !IS_BARD(ch)) { send_to_char("You know of no songs...\n\r",ch); return; } strcpy(buf, "%B%6Bard songlist%0:\n\r" "%B%6--------------%0\n\r"); for (i = 1; i <= NUM_SONGS; i++) sprintf(buf+strlen(buf), "%%6%-17.17s%%0 - %%6Minlevel%%0: %d, %%6Initial Mana%%0: %d.\n\r", song_names_cap[i], song_types[i].min_level, song_types[i].initial_mana); page_string(ch->desc, buf, TRUE); } /* main bard user interface */ ACMD(do_sing) { int song; char argu[MAX_INPUT_LENGTH]; if (strlen(argument) > MAX_INPUT_LENGTH) { send_to_char("Argument too long, please shorten.\n\r",ch); return; } if (!IS_BARD(ch)) { send_to_char("You raise your clear voice (?) to the sky.\n\r",ch); return; } if (IS_NPC(ch)) return; half_chop(argument, arg, argu); if (!*arg || ((song = search_block(arg, song_names, FALSE)) == -1)) { show_songs(ch); return; } if (GET_SKILL(ch, SKILL_SING) < number(1, 110)) /* do the social sing */ { send_to_char("You raise your clear voice (?) to the sky.\n\r",ch); return; } if (GET_COND(ch, THIRST) == 0) { send_to_char("You cannot sing while thirsty!\n\r",ch); return; } if (GET_LEVEL(ch) < song_types[song].min_level) { send_to_char("You do not know that song well yet.\n\r",ch); return; } if (GET_MANA(ch) < song_types[song].initial_mana) { send_to_char("You need more mana to sing that song.\n\r",ch); return; } if (FIGHTING(ch) && !song_types[song].combat) { send_to_char("That song is too difficult to sing while fighting!\n\r",ch); return; } if (SINGING(ch)) { sprintf(buf, "You are already singing %%B%%6%s%%0.\n\r", song_names_cap[SINGING(ch)]); S2C(); return; } if (spell_affects_room(ch->in_room, SPELL_SILENCE)) { send_to_char("This area is strangely %Bsilent%0!\n\r",ch); return; } if ((*song_types[song].song_fn)(ch, song, argu, TRUE) == SONG_SUCCESS) GET_MANA(ch) -= song_types[song].initial_mana; } ACMD(do_finish) { if (IS_NPC(ch)) return; if (strlen(argument) > MAX_INPUT_LENGTH) { send_to_char("Argument too long, please shorten.\n\r",ch); return; } one_argument(argument, arg); if (!*arg) { send_to_char("Usage: finish <song || tune>.\n\r",ch); return; } if (str_cmp(arg, "song") && str_cmp(arg, "tune")) { send_to_char("Usage: finish <song || tune>.\n\r",ch); return; } if (!str_cmp(arg, "song")) { if (!SINGING(ch)) { send_to_char("You are not singing anything!\n\r",ch); return; } sprintf(buf, "You stop singing %%B%%6%s%%0.\n\r", song_names_cap[SINGING(ch)]); S2C(); remove_song_from_world(ch, SINGING(ch)); SINGING(ch) = 0; SONG_TIME(ch) = 0; } if (!str_cmp(arg, "tune")) { if (!PLAYING(ch)) { send_to_char("You are not playing anything!\n\r",ch); return; } sprintf(buf, "You stop playing %%B%%6%s%%0.\n\r", song_names_cap[PLAYING(ch)]); S2C(); remove_song_from_world(ch, PLAYING(ch)); PLAYING(ch) = 0; PLAY_TIME(ch) = 0; } } ACMD(do_play) { int song; char argu[MAX_INPUT_LENGTH]; if (strlen(argument) > MAX_INPUT_LENGTH) { send_to_char("Argument too long, please shorten.\n\r",ch); return; } if (!IS_BARD(ch) || GET_SKILL(ch, SKILL_PLAY) < number(1, 110)) /* do the social sing */ { send_to_char("You raise your clear voice (?) to the sky.\n\r",ch); return; } if (IS_NPC(ch)) return; half_chop(argument, arg, argu); if (!*arg || ((song = search_block(arg, song_names, FALSE)) == -1)) { show_songs(ch); return; } if (GET_COND(ch, THIRST) == 0) { send_to_char("You cannot play while thirsty!\n\r",ch); return; } if (GET_LEVEL(ch) < song_types[song].min_level) { send_to_char("You do not know that song well yet.\n\r",ch); return; } if (GET_MANA(ch) < song_types[song].initial_mana) { send_to_char("You need more mana to play that song.\n\r",ch); return; } if (FIGHTING(ch) && !song_types[song].combat) { send_to_char("That song is too difficult to play while fighting!\n\r",ch); return; } if (PLAYING(ch)) { sprintf(buf, "You are already playing %%B%%6%s%%0.\n\r", song_names_cap[PLAYING(ch)]); S2C(); return; } // accomodate weapon-instruments 08/13/98 -callahan (fixed infinite loop 8/16/98 -jtrhone) if (!EQ(ch, W_HOLD) || !OBJ_FLAGGED(EQ(ch, W_HOLD), ITEM_INSTRUM)) if (!EQ(ch, W_WIELD) || !OBJ_FLAGGED(EQ(ch, W_WIELD), ITEM_INSTRUM)) { SendChar("You need to be holding an instrument to play!\n\r", ch); return; } if (spell_affects_room(ch->in_room, SPELL_SILENCE)) { send_to_char("This area is strangely %Bsilent%0!\n\r",ch); return; } if ((*song_types[song].song_fn)(ch, song, argu, FALSE) == SONG_SUCCESS) GET_MANA(ch) -= song_types[song].initial_mana; } /*effects on instruments: Infravision, Bless and Sense Life.*/ ACMD(do_craft) { obdata *tmp_obj; int i, tnum; char *argu = argument; if (strlen(argument) > MAX_INPUT_LENGTH) { send_to_char("Argument too long, please shorten.\n\r",ch); return; } if (!IS_BARD(ch) || IS_NPC(ch)) { send_to_char("You know not how to craft an instrument.\n\r",ch); return; } skip_spaces(&argu); if (!*argu || ((tnum = search_block(argu, inst_names, FALSE)) == -1)) { send_to_char("Usage: craft <instrument type>\n\r",ch); send_to_char("Available types are: \n\r",ch); for (i=0; *inst_names[i] != '\n'; i++) { sprintf(buf, " %%6%s%%0\n\r",inst_names[i]); S2C(); } return; } if (GET_SKILL(ch, SKILL_CRAFT) < number(1,110)) { send_to_char("You made an error crafting your instrument! It's ruined!\n\r",ch); return; } if (GET_GOLD(ch) < 100000) /* less than 100k */ { sprintf(buf, "You need at least 100k %s to craft a fine instrument.\n\r", currency_name_plural); S2C(); return; } if (GET_MANA(ch) < 500) { send_to_char("You do not have enough %Bmana%0 to create an instrument right now.\n\r",ch); return; } /* 115 is instrument template */ if (!(tmp_obj = read_object(115, VIRTUAL))) { send_to_char("Something went wrong! Notify an Immortal.\n\r",ch); return; } GET_MANA(ch) -= 500; GET_GOLD(ch) -= 100000; sprintf(buf, "inst instrument %s", inst_names[tnum]); tmp_obj->name = str_dup(buf); sprintf(buf, "%s's %s is lying here.", GET_NAME(ch), inst_names[tnum]); tmp_obj->description = str_dup(buf); sprintf(buf, "%s's %s", GET_NAME(ch), inst_names[tnum]); tmp_obj->shdesc = str_dup(buf); // also add actdesc 5/30/98 -jtrhone tmp_obj->actdesc = str_dup(buf); act("$n has crafted $p!", TRUE, ch, tmp_obj, 0, TO_ROOM); act("You have crafted $p!", TRUE, ch, tmp_obj, 0, TO_CHAR); // now assign owner to this object 5/30/98 -jtrhone tmp_obj->owner_of = GET_IDNUM(ch); OBJ_ID(tmp_obj) = tnum; obj_to_char(tmp_obj, ch); }