From accffbbb25dce6294e8e6063467746b7c95705c4 Mon Sep 17 00:00:00 2001 From: GickerLDS Date: Wed, 24 Apr 2024 20:43:23 +0000 Subject: [PATCH] You should now be able to see and manipulate your inventory even when you can't see (darkness, blinded). Added the kapak draconian advanced race Added ability for charmies to perform more abilities and commands that were previously not performable my NPCs, grapple being one of them. Race restrictions removed from arcane archer Created a new object database for builder info and for players to find gear: https://krynn.d20mud.com/objectdb/ Functions that enable searching for players and mobs will prioritize players over mobs now --- act.h | 10 +-- act.informative.c | 25 +++++- act.other.c | 89 +++++++++++++++++++ act.wizard.c | 7 ++ class.c | 6 +- constants.c | 5 +- db.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++ depend | 2 +- feats.c | 44 ++++++---- fight.c | 6 +- grapple.c | 26 +++--- handler.c | 22 ++++- interpreter.c | 2 + limits.c | 31 ++++++- magic.c | 45 ++++++++-- players.c | 5 ++ race.c | 66 +++++++++++++-- spell_parser.c | 9 ++ spells.h | 6 +- structs.h | 20 +++-- utils.c | 28 ++++-- utils.h | 5 +- 22 files changed, 600 insertions(+), 71 deletions(-) diff --git a/act.h b/act.h index 1f31c45c..e079ee6a 100755 --- a/act.h +++ b/act.h @@ -76,11 +76,7 @@ bool is_locked_race(int race); /** Check if character is not a NPC. */ #define PREREQ_NOT_NPC() \ - if (IS_NPC(ch)) \ - { \ - send_to_char(ch, "But you don't know how!\r\n"); \ - return; \ - } + if (!can_npc_command(ch)) return; /** Check if character is in a peaceful room. */ #define PREREQ_NOT_PEACEFUL_ROOM() \ @@ -268,6 +264,7 @@ ACMD_DECL(do_bane); ACMD_DECL(do_slayer); ACMD_DECL(do_true_judgement); ACMD_DECL(do_flightlist); +ACMD_DECL(do_kapak_saliva); int max_judgements_active(struct char_data *ch); int num_judgements_active(struct char_data *ch); @@ -321,6 +318,7 @@ void list_consumables(struct char_data *ch, int type); void sort_object_bag(struct char_data *ch, char *objname, int subcmd, int bagnum); /* do_look, do_inventory utility functions */ void list_obj_to_char(struct obj_data *list, struct char_data *ch, int mode, int show, int mxp_type); +void list_obj_to_char_full(struct obj_data *list, struct char_data *ch, int mode, int show, int mxp_type, bool can_see_always); /* functions with subcommands */ /* do_drop */ @@ -861,6 +859,7 @@ void snoop_check(struct char_data *ch); bool change_player_name(struct char_data *ch, struct char_data *vict, char *new_name); bool AddRecentPlayer(char *chname, char *chhost, bool newplr, bool cpyplr); int get_eq_score(obj_rnum a); +void save_objects_to_database(struct char_data *ch); /* Functions with subcommands */ /* do_date */ ACMD_DECL(do_date); @@ -982,6 +981,7 @@ ACMD_DECL(do_resetpassword); ACMD_DECL(do_holyweapon); ACMD_DECL(do_award); ACMD_DECL(do_show_blockers); +ACMD_DECL(do_save_objects_to_database); // encounters.c ACMD_DECL(do_encounterinfo); diff --git a/act.informative.c b/act.informative.c index 7034da8c..905649f8 100755 --- a/act.informative.c +++ b/act.informative.c @@ -497,8 +497,12 @@ static void show_obj_modifiers(struct obj_data *obj, struct char_data *ch) send_to_char(ch, " \tD(burned out)\tn"); } -void list_obj_to_char(struct obj_data *list, struct char_data *ch, - int mode, int show, int mxp_type) +void list_obj_to_char(struct obj_data *list, struct char_data *ch, int mode, int show, int mxp_type) +{ + list_obj_to_char_full(list, ch, mode, show, mxp_type, false); +} + +void list_obj_to_char_full(struct obj_data *list, struct char_data *ch, int mode, int show, int mxp_type, bool can_see_always) { struct obj_data *i = NULL, *j = NULL, *display = NULL; bool found = FALSE; @@ -525,7 +529,7 @@ void list_obj_to_char(struct obj_data *list, struct char_data *ch, /* This if-clause should be exactly the same as the one in the loop above */ if ((j->short_description == i->short_description && j->name == i->name) || (!strcmp(j->short_description, i->short_description) && !strcmp(j->name, i->name))) - if (CAN_SEE_OBJ(ch, j) /*|| (!AFF_FLAGGED(ch, AFF_BLIND) && OBJ_FLAGGED(j, ITEM_GLOW))*/) + if (CAN_SEE_OBJ(ch, j) || can_see_always /*|| (!AFF_FLAGGED(ch, AFF_BLIND) && OBJ_FLAGGED(j, ITEM_GLOW))*/) { /* added the ability for players to see glowing items in their inventory in the dark * as long as they are not blind! maybe add this to CAN_SEE_OBJ macro? */ @@ -1460,6 +1464,12 @@ void look_at_room(struct char_data *ch, int ignore_brief) (!IS_SET_AR(ROOM_FLAGS(target_room), ROOM_FOG) || GET_LEVEL(ch) >= LVL_IMMORT)) do_auto_exits(ch); + if (ROOM_AFFECTED(ch->in_room, RAFF_KAPAK_ACID)) + { + send_to_char(ch, "\tMA pool of acid covers the area.\tn\r\n"); + return; + } + /* now list characters & objects */ list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE, 0); list_char_to_char(world[IN_ROOM(ch)].people, ch); @@ -2051,6 +2061,8 @@ void perform_cooldowns(struct char_data *ch, struct char_data *k) send_to_char(ch, "Incorporeal Form (Undead Bloodline) Cooldown - Duration: %d seconds\r\n", INCORPOREAL_FORM_TIMER(ch) * 6); if (GET_MISSION_COOLDOWN(k) > 0) send_to_char(ch, "Mission Ready Cooldown - Duration: %d seconds\r\n", GET_MISSION_COOLDOWN(k) * 6); + if (GET_KAPAK_SALIVA_HEALING_COOLDOWN(k) > 0) + send_to_char(ch, "Kapak Saliva Healing - Duration: %d seconds\r\n", GET_KAPAK_SALIVA_HEALING_COOLDOWN(k) * 6); send_to_char(ch, "\tC"); draw_line(ch, 80, '-', '-'); @@ -3476,7 +3488,7 @@ ACMD(do_score) ACMD(do_inventory) { send_to_char(ch, "You are carrying:\r\n"); - list_obj_to_char(ch->carrying, ch, SHOW_OBJ_SHORT, TRUE, 1); + list_obj_to_char_full(ch->carrying, ch, SHOW_OBJ_SHORT, TRUE, 1, true); if (!IS_NPC(ch)) if (ch->desc) @@ -3669,7 +3681,12 @@ ACMD(do_equipment) if (GET_EQ(ch, eq_ordering_1[i])) { found = TRUE; +#if defined(CAMPAIGN_DL) + // In Dragonlance, we always want to be able to see our equipment unless it's invis and we can't see invis + if (!OBJ_FLAGGED(GET_EQ(ch, eq_ordering_1[i]), ITEM_INVISIBLE) || AFF_FLAGGED(ch, AFF_DETECT_INVIS) || AFF_FLAGGED(ch, AFF_TRUE_SIGHT)) +#else if (CAN_SEE_OBJ(ch, GET_EQ(ch, eq_ordering_1[i]))) +#endif { send_to_char(ch, "%s", wear_where[eq_ordering_1[i]]); /* added this as a clue to players */ diff --git a/act.other.c b/act.other.c index 30e736bd..08a72209 100755 --- a/act.other.c +++ b/act.other.c @@ -1342,6 +1342,9 @@ ACMD(do_applypoison) return; } + if (is_abbrev(arg1, "kapak") && HAS_FEAT(ch, FEAT_KAPAK_SALIVA)) + poison = read_object(OBJ_VNUM_KAPAK_POISON, VIRTUAL); + poison = get_obj_in_list_vis(ch, arg1, NULL, ch->carrying); if (!poison) @@ -9088,6 +9091,92 @@ ACMDU(do_borrow) } } + +ACMD(do_kapak_saliva) +{ + + char arg[200]; + struct char_data *vict = NULL; + int healing = 0; + + if (!is_action_available(ch, atSWIFT, TRUE)) + { + send_to_char(ch, "You need a swift action to use this ability.\r\n"); + return; + } + + if (!HAS_FEAT(ch, FEAT_KAPAK_SALIVA)) + { + send_to_char(ch, "Only Kapak Draconians can use this ability"); + return; + } + + if (GET_SEX(ch) == SEX_MALE) + { + send_to_char(ch, "Male Kapaks can apply poison to their weapons using the command: applypoison kapak (weapon name)\r\n"); + return; + } + + one_argument(argument, arg, sizeof(arg)); + + if (!*arg) + vict = ch; + else + { + if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) + { + send_to_char(ch, "There's no one here by that description.\r\n"); + return; + } + } + + if (GET_HIT(vict) >= GET_MAX_HIT(vict)) + { + send_to_char(ch, "They are already fully healed.\r\n"); + return; + } + + if (GET_KAPAK_SALIVA_HEALING_COOLDOWN(vict) > 0) + { + if (vict == ch) + { + act("You lick your wounds, but feel only numbness as residues of your saliva still remain.", TRUE, ch, 0, vict, TO_CHAR); + act("$n licks $s wounds with healing saliva.", TRUE, ch, 0, vict, TO_ROOM); + } + else + { + act("You lick $N's wounds, but see no effect as residues of kapak saliva still remain.", TRUE, ch, 0, vict, TO_CHAR); + act("$n licks Your wounds, but there is no effect as residues of kapak saliva still remain.", TRUE, ch, 0, vict, TO_VICT); + act("$n licks $N's wounds with healing saliva.", TRUE, ch, 0, vict, TO_NOTVICT); + } + return; + } + + GET_KAPAK_SALIVA_HEALING_COOLDOWN(vict) = 60; + healing = dice(GET_LEVEL(ch), 4) + 20; + if ((GET_HIT(vict) + healing) > GET_MAX_HIT(vict)) + { + healing = GET_MAX_HIT(vict) - GET_HIT(vict); + } + + if (vict == ch) + { + act("You lick your wounds and feel healing relief from your kapak saliva.", TRUE, ch, 0, vict, TO_CHAR); + act("$n licks $s wounds with healing saliva.", TRUE, ch, 0, vict, TO_ROOM); + send_to_char(ch, "You are healed for %d hp.\r\n", healing); + } + else + { + act("You lick $N's wounds and they feel healing relief from your kapak saliva.", TRUE, ch, 0, vict, TO_CHAR); + act("$n licks Your wounds and you feel healing relief from the kapak saliva.", TRUE, ch, 0, vict, TO_VICT); + act("$n licks $N's wounds with healing saliva.", TRUE, ch, 0, vict, TO_NOTVICT); + send_to_char(vict, "You are healed for %d hp.\r\n", healing); + send_to_char(ch, "They are healed for %d hp.\r\n", healing); + } + + USE_SWIFT_ACTION(ch); + +} /* undefines */ #undef DEBUG_MODE diff --git a/act.wizard.c b/act.wizard.c index 162b6108..8b55be14 100755 --- a/act.wizard.c +++ b/act.wizard.c @@ -9602,4 +9602,11 @@ ACMD(do_show_blockers) } +ACMD(do_save_objects_to_database) +{ + send_to_char(ch, "Saving objects to database...\r\n"); + save_objects_to_database(ch); + send_to_char(ch, "Objects successfully exported to database.\r\n"); +} + /* EOF */ diff --git a/class.c b/class.c index 2c34f769..efe362a0 100755 --- a/class.c +++ b/class.c @@ -6587,10 +6587,12 @@ void load_class_list(void) /* no spell assignment */ /* class prereqs */ class_prereq_bab(CLASS_ARCANE_ARCHER, 5); + #if !defined(CAMPAIGN_DL) /* elf, half-elf, drow only */ class_prereq_race(CLASS_ARCANE_ARCHER, RACE_DROW); class_prereq_race(CLASS_ARCANE_ARCHER, RACE_ELF); class_prereq_race(CLASS_ARCANE_ARCHER, RACE_HALF_ELF); + #endif class_prereq_feat(CLASS_ARCANE_ARCHER, FEAT_POINT_BLANK_SHOT, 1); class_prereq_feat(CLASS_ARCANE_ARCHER, FEAT_PRECISE_SHOT, 1); class_prereq_spellcasting(CLASS_ARCANE_ARCHER, CASTING_TYPE_ARCANE, @@ -7091,7 +7093,7 @@ void load_class_list(void) /* class-number name abrv clr-abrv menu-name*/ classo(CLASS_KNIGHT_OF_THE_CROWN, "knightofthecrown", "KCr", "\tWKCr\tn", "g) \tWKnight of the Crown\tn", /* max-lvl lock? prestige? BAB HD psp move trains in-game? unlkCst, eFeatp*/ - 5, N, Y, H, 12, 0, 1, 2, Y, 0, 0, + 5, Y, Y, H, 12, 0, 1, 2, Y, 2500, 0, /*prestige spell progression*/ "none", /*primary attributes*/ "Strength, Con/Dex for survivability", /*descrip*/ @@ -7243,7 +7245,7 @@ void load_class_list(void) /* class-number name abrv clr-abrv menu-name*/ classo(CLASS_KNIGHT_OF_THE_SWORD, "knightofthesword", "KSw", "\tWKSw\tn", "g) \tWKnight of the Sword\tn", /* max-lvl lock? prestige? BAB HD psp move trains in-game? unlkCst, eFeatp*/ - 5, Y, Y, H, 10, 0, 1, 2, Y, 5000, 0, + 5, Y, Y, H, 10, 0, 1, 2, Y, 2500, 0, /*prestige spell progression*/ "none", /*primary attributes*/ "Strength, Con/Dex for survivability, Cha for class abilities", /*descrip*/ diff --git a/constants.c b/constants.c index 93ef31c4..2789cfd4 100755 --- a/constants.c +++ b/constants.c @@ -1222,6 +1222,7 @@ const char *room_affections[] = { "Obscuring-Mist", "Difficult-Terrain", "Sacred-Space", + "Kapak-Acid", "\n"}; CHECK_TABLE_SIZE(room_affections, NUM_RAFF + 1); @@ -2253,7 +2254,7 @@ const char *item_types[] = { "Armor/Shield", "Potion", // 10 "Wearable", - "OTHER", + "Other", "Trash", "Ammo", "Container", // 15 @@ -3811,7 +3812,7 @@ const char *languages[] = "gnome", "goblin", "gullytalk", - "halfling", + "kenderspeak", "minotaur", "nerakese", "ogre", diff --git a/db.c b/db.c index 9014a319..e4bdd437 100755 --- a/db.c +++ b/db.c @@ -63,6 +63,7 @@ #include "hunts.h" #include "evolutions.h" #include "treasure.h" +#include "assign_wpn_armor.h" /* declarations of most of the 'global' variables */ struct config_data config_info; /* Game configuration list. */ @@ -6539,4 +6540,215 @@ void set_db_happy_hour(int status) } } +void save_objects_to_database(struct char_data *ch) +{ + int j, i; + int zone_num = 0; + int obj_idnum = 0; + struct obj_data *obj = NULL; + struct obj_special_ability *specab; + + char query[MAX_STRING_LENGTH] = {'\0'}; + char temp[255] = {'\0'}; + char bonus[255] = {'\0'}; + char object_name[255] = {'\0'}; + char specific_type[255] = {'\0'}; + char weapon_spell_1[255] = {'\0'}; + char weapon_spell_2[255] = {'\0'}; + char weapon_spell_3[255] = {'\0'}; + char weapon_special_ability[255] = {'\0'}; + char notes[LONG_STRING] = {'\0'}; + char zone_name[255] = {'\0'}; + + mysql_ping(conn); + + snprintf(query, sizeof(query), "TRUNCATE TABLE object_database_items"); + if (mysql_query(conn, query)) log("SYSERR: Unable to TRUNCATE TABLE object_database_items: %s", mysql_error(conn)); + snprintf(query, sizeof(query), "TRUNCATE TABLE object_database_bonuses"); + if (mysql_query(conn, query)) log("SYSERR: Unable to TRUNCATE TABLE object_database_bonuses: %s", mysql_error(conn)); + snprintf(query, sizeof(query), "TRUNCATE TABLE object_database_wear_slots"); + if (mysql_query(conn, query)) log("SYSERR: Unable to TRUNCATE TABLE object_database_wear_slots: %s", mysql_error(conn)); + snprintf(query, sizeof(query), "TRUNCATE TABLE object_database_obj_flags"); + if (mysql_query(conn, query)) log("SYSERR: Unable to TRUNCATE TABLE object_database_obj_flags: %s", mysql_error(conn)); + snprintf(query, sizeof(query), "TRUNCATE TABLE object_database_perm_affects"); + if (mysql_query(conn, query)) log("SYSERR: Unable to TRUNCATE TABLE object_database_perm_affects: %s", mysql_error(conn)); + + // We have to do this loop in multiple stages to prevent the MUD from crashing + + for (j = 0; j < top_of_objt; j++) + { + // we have issues with obj vnums above this number. + // all zones that are made should be below these vnums anyway. + if (obj_index[j].vnum >= 60000) continue; + + obj = read_object(obj_index[j].vnum, VIRTUAL); + + if (!obj) continue; + + specific_type[0] = '\0'; + switch (GET_OBJ_TYPE(obj)) + { + case ITEM_WEAPON: snprintf(specific_type, sizeof(specific_type), "%s", weapon_list[GET_OBJ_VAL(obj, 0)].name); break; + case ITEM_ARMOR: snprintf(specific_type, sizeof(specific_type), "%s", armor_list[GET_OBJ_VAL(obj, 1)].name); break; + } + + weapon_spell_1[0] = '\0'; + if (GET_WEAPON_SPELL(obj, 0)) + { + snprintf(weapon_spell_1, sizeof(weapon_spell_1), "Spell: %s, Level: %d, Percent: %d, Procs in combat?: %s\r\n", + spell_info[GET_WEAPON_SPELL(obj, 0)].name, GET_WEAPON_SPELL_LVL(obj, 0), + GET_WEAPON_SPELL_PCT(obj, 0), GET_WEAPON_SPELL_AGG(obj, 0) ? "Yes" : "No"); + } + weapon_spell_2[0] = '\0'; + if (GET_WEAPON_SPELL(obj, 1)) + { + snprintf(weapon_spell_2, sizeof(weapon_spell_2), "Spell: %s, Level: %d, Percent: %d, Procs in combat?: %s\r\n", + spell_info[GET_WEAPON_SPELL(obj, 1)].name, GET_WEAPON_SPELL_LVL(obj, 1), + GET_WEAPON_SPELL_PCT(obj, 1), GET_WEAPON_SPELL_AGG(obj, 1) ? "Yes" : "No"); + } + weapon_spell_3[0] = '\0'; + if (GET_WEAPON_SPELL(obj, 2)) + { + snprintf(weapon_spell_3, sizeof(weapon_spell_3), "Spell: %s, Level: %d, Percent: %d, Procs in combat?: %s\r\n", + spell_info[GET_WEAPON_SPELL(obj, 2)].name, GET_WEAPON_SPELL_LVL(obj, 2), + GET_WEAPON_SPELL_PCT(obj, 2), GET_WEAPON_SPELL_AGG(obj, 2) ? "Yes" : "No"); + } + weapon_special_ability[0] = '\0'; + if ((specab = obj->special_abilities) != NULL) + { + if (specab->ability == WEAPON_SPECAB_BANE) + { + if (specab->value[1]) + { + snprintf(weapon_special_ability, sizeof(weapon_special_ability), "Ability: %s Bane Race: %s Bane Subrace: %s ", + special_ability_info[specab->ability].name, race_family_types[specab->value[0]], npc_subrace_types[specab->value[1]]); + } + else + { + snprintf(weapon_special_ability, sizeof(weapon_special_ability), "Ability: %s Bane Race: %s", + special_ability_info[specab->ability].name, race_family_types[specab->value[0]]); + } + } + else + { + snprintf(weapon_special_ability, sizeof(weapon_special_ability), "Ability: %s ", special_ability_info[specab->ability].name); + } + } + snprintf(notes, sizeof(notes), " "); + snprintf(temp, sizeof(temp), "%s", obj_proto[j].short_description); + snprintf(zone_name, sizeof(zone_name), "%s", zone_table[real_zone_by_thing(obj_index[j].vnum)].name); + mysql_real_escape_string(conn, object_name, temp, strlen(temp)); + strip_colors(object_name); + zone_num = zone_table[real_zone_by_thing(obj_index[j].vnum)].number; + + snprintf(query, sizeof(query), "INSERT INTO object_database_items (`idnum`, `object_vnum`, `object_name`, `object_type`, " + "`material`, `weight`, `object_size`, `cost`, `specific_type`, `weapon_spell_1`, `weapon_spell_2`, `weapon_spell_3`, " + "`weapon_special_ability`, `minimum_level`, `zone_num`, `zone_name`, `notes`, `enhancement_bonus`) VALUES (NULL," + "%d," // A object_vnum + "\"%s\"," // B object_name + "\"%s\"," // C object_type + "\"%s\"," // D material + "%d," // E weight + "\"%s\"," // F object_size + "%d," // G cost + "\"%s\"," // H specific_type + "\"%s\"," // I weapon_spell_1 + "\"%s\"," // J weapon_spell_2 + "\"%s\"," // K weapon_spell_3 + "\"%s\"," // L weapon_special_ability + "%d," // M minimum_level + "%d," // N zone_num + "\"%s\"," // O zone_name + "\"%s\"," // P notes + "%d" // Q enhancement + ")", + obj_index[j].vnum, // A + object_name, // B + item_types[obj_proto[j].obj_flags.type_flag], // C + material_name[obj_proto[j].obj_flags.material],// D + obj_proto[j].obj_flags.weight, // E + sizes[obj_proto[j].obj_flags.size], // F + obj_proto[j].obj_flags.cost, // G + specific_type, // H + weapon_spell_1, // I + weapon_spell_2, // J + weapon_spell_3, // K + weapon_special_ability, // L + obj_proto[j].obj_flags.level, // M + zone_num, // N + zone_name, // O + notes, // P + GET_ENHANCEMENT_BONUS(obj) // Q + ); + if (mysql_query(conn, query)) + { + log("SYSERR: Unable to INSERT into object_database_items: %s\nQUERY: %s", mysql_error(conn), query); + } + else + { + obj_idnum = mysql_insert_id(conn); + + for (i = 0; i < NUM_ITEM_WEARS; i++) + { + if (i == ITEM_WEAR_TAKE) continue; + if (CAN_WEAR(obj, i)) { + snprintf(query, sizeof(query), "INSERT INTO object_database_wear_slots (idnum,object_idnum,worn_slot) VALUES(NULL,%d,\"%s\")", + obj_idnum, wear_bits[i]); + if (mysql_query(conn, query)) + { + log("SYSERR: Unable to INSERT into object_database_wear_slots: %s\nQUERY: %s", mysql_error(conn), query); + } + } + } + for (i = 0; i < NUM_ITEM_FLAGS; i++) + { + if (OBJ_FLAGGED(obj, i)) { + snprintf(query, sizeof(query), "INSERT INTO object_database_obj_flags (idnum,object_idnum,obj_flag) VALUES(NULL,%d,\"%s\")", + obj_idnum, extra_bits[i]); + if (mysql_query(conn, query)) + { + log("SYSERR: Unable to INSERT into object_database_obj_flags: %s\nQUERY: %s", mysql_error(conn), query); + } + } + } + for (i = 0; i < NUM_ITEM_FLAGS; i++) + { + if (OBJAFF_FLAGGED(obj, i)) { + snprintf(query, sizeof(query), "INSERT INTO object_database_perm_affects (idnum,object_idnum,perm_affect) VALUES(NULL,%d,\"%s\")", + obj_idnum, affected_bits[i]); + if (mysql_query(conn, query)) + { + log("SYSERR: Unable to INSERT into object_database_perm_affects: %s\nQUERY: %s", mysql_error(conn), query); + } + } + } + for (i = 0; i < 6; i++) + { + if (obj->affected[i].location != APPLY_NONE && obj->affected[i].modifier != 0) + { + switch (obj->affected[i].location) + { + case APPLY_FEAT: + snprintf(bonus, sizeof(bonus), "%s", feat_list[obj->affected[i].modifier].name); + break; + case APPLY_SKILL: + snprintf(bonus, sizeof(bonus), "%s", ability_names[obj->affected[i].specific]); + break; + default: + bonus[0] = '\0'; + break; + } + snprintf(query, sizeof(query), "INSERT INTO object_database_bonuses (idnum,object_idnum,bonus_location,bonus_type,bonus_modifier,bonus_specific) " + "VALUES(NULL,%d,\"%s\",\"%s\",%d,\"%s\")", + obj_idnum, apply_types[obj->affected[i].location], bonus_types[obj->affected[i].bonus_type], obj->affected[i].modifier, bonus); + if (mysql_query(conn, query)) + { + log("SYSERR: Unable to INSERT into object_database_bonuses: %s\nQUERY: %s", mysql_error(conn), query); + } + } + } + } + } +} + /* EOF */ diff --git a/depend b/depend index 13f072e5..1925dd91 100644 --- a/depend +++ b/depend @@ -142,7 +142,7 @@ db.o: db.c conf.h sysdep.h structs.h bool.h protocol.h lists.h campaign.h \ msgedit.h craft.h hlquest.h mudlim.h spec_abilities.h perlin.h \ wilderness.h mysql.h feats.h actionqueues.h domains_schools.h grapple.h \ race.h spell_prep.h crafts.h trails.h premadebuilds.h encounters.h \ - hunts.h evolutions.h + hunts.h evolutions.h assign_wpn_armor.h deities.o: deities.c conf.h sysdep.h structs.h bool.h protocol.h lists.h \ campaign.h utils.h db.h helpers.h perfmon.h spells.h interpreter.h \ deities.h diff --git a/feats.c b/feats.c index 08a1624a..0c7c1bca 100644 --- a/feats.c +++ b/feats.c @@ -1118,24 +1118,38 @@ feato(FEAT_MOON_ELF_RACIAL_ADJUSTMENT, "moon elf racial adjustment", TRUE, FALSE feato(FEAT_BAAZ_DEATH_THROES, "baaz death throes", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, "Upon death, all enemies will be paralyzed.", "When a Baaz Draconian dies, it turns to stone and let's out a puff of gas that will paralyze all enemies in the room."); - feato(FEAT_DRACONIAN_CONTROLLED_FALL, "baaz controlled fall", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + feato(FEAT_DRACONIAN_CONTROLLED_FALL, "draconian controlled fall", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, "Divide fall damge in half.", "When falling, a Baaz Draconian can spread his wings to halve any fall damage they might take."); - feato(FEAT_BAAZ_DRACONIC_DEVOTION, "", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + feato(FEAT_DRACONIC_DEVOTION, "draconic devotion", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, "+2 to attack rolls when grouped with another draconian or dragon.", - "Baaz Draconians receive a +2 to attack rolls whenever they are groluped with another draconian or a dragon of any type."); - feato(FEAT_DRACONIAN_GALLOP, "", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, - "", - ""); - feato(FEAT_BAAZ_DISEASE_IMMUNITY, "", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, - "", - ""); - feato(FEAT_BAAZ_DRACONIAN_SCALES, "", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, - "", - ""); - feato(FEAT_DRACONIAN_BITE, "", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, - "", - ""); + "Draconians receive a +2 to attack rolls whenever they are groluped with another draconian or a dragon of any type."); + feato(FEAT_DRACONIAN_GALLOP, "draconian gallop", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Gains additional move points when advancing in level.", + "Gains additional move points when advancing in level."); + feato(FEAT_DRACONIAN_DISEASE_IMMUNITY, "draconian disease immunity", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Immune to all disease.", + "Immune to all disease."); + feato(FEAT_BAAZ_DRACONIAN_SCALES, "baaz draconian scales", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Gains +1 to Natural Armor Class bonus.", + "Gains +1 to Natural Armor Class bonus."); + feato(FEAT_DRACONIAN_BITE, "draconian bite", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Able to make a bite attack in combat with a swift action. Uses bite command.", + "Able to make a bite attack in combat with a swift action. Uses bite command."); + + // kapak draconian + feato(FEAT_KAPAK_DRACONIAN_SCALES, "kapak draconian scales", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Gains +2 to Natural Armor Class bonus.", + "Gains +2 to Natural Armor Class bonus."); + feato(FEAT_KAPAK_DEATH_THROES, "kapak death throes", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Upon death, a pool of acid will appear in the room, damaging anyone who is not flying or levitating.", + "When a Kapak Draconian dies, it dissolves into a pool of acid that will damage anyone in the room who is not flying or levitating."); + feato(FEAT_KAPAK_SALIVA, "kapak saliva", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Male kapaks can poison their weapons with their saliva. Females can heal wounds with their saliva.", + "Male kapaks can poison their weapons with their saliva. Females can heal wounds with their saliva. Uses the kapaksaliva command."); + feato(FEAT_KAPAK_SPELL_RESISTANCE, "kapak spell resistance", TRUE, FALSE, FALSE, FEAT_TYPE_INNATE_ABILITY, + "Gains spell resistance equal to 10 + character level.", + "Gains spell resistance equal to 10 + character level."); /* End Racial ability feats */ diff --git a/fight.c b/fight.c index e66d0f54..efc11876 100755 --- a/fight.c +++ b/fight.c @@ -752,6 +752,10 @@ int compute_armor_class(struct char_data *attacker, struct char_data *ch, { bonuses[BONUS_TYPE_NATURALARMOR] += 1; } + else if (HAS_FEAT(ch, FEAT_KAPAK_DRACONIAN_SCALES)) + { + bonuses[BONUS_TYPE_NATURALARMOR] += 2; + } if (HAS_EVOLUTION(ch, EVOLUTION_IMPROVED_NATURAL_ARMOR)) { bonuses[BONUS_TYPE_NATURALARMOR] += HAS_EVOLUTION(ch, EVOLUTION_IMPROVED_NATURAL_ARMOR) * 2; @@ -8197,7 +8201,7 @@ int compute_attack_bonus(struct char_data *ch, /* Attacker */ } } - if (HAS_FEAT(ch, FEAT_BAAZ_DRACONIC_DEVOTION) && is_grouped_with_dragon(ch)) + if (HAS_FEAT(ch, FEAT_DRACONIC_DEVOTION) && is_grouped_with_dragon(ch)) bonuses[BONUS_TYPE_MORALE] += 2; /* if the victim is using 'come and get me' then they will be vulnerable */ diff --git a/grapple.c b/grapple.c index 5e13496a..30d2ccfe 100644 --- a/grapple.c +++ b/grapple.c @@ -212,11 +212,7 @@ ACMD(do_grapple) struct char_data *vict = NULL; int grapple_mod = 0; - if (IS_NPC(ch)) - { - send_to_char(ch, "You have no idea how.\r\n"); - return; - } + if (!can_npc_command(ch)) return; if (ROOM_FLAGGED(IN_ROOM(ch), ROOM_PEACEFUL)) { @@ -252,6 +248,13 @@ ACMD(do_grapple) else if (HAS_EVOLUTION(ch, EVOLUTION_TENTACLE)) grapple_mod = 4; + if (HAS_EVOLUTION(vict, EVOLUTION_PINCERS) && HAS_EVOLUTION(ch, EVOLUTION_PINCERS)) + grapple_mod = 0; + else if (HAS_EVOLUTION(vict, EVOLUTION_PINCERS)) + grapple_mod = -4; + else if (HAS_EVOLUTION(ch, EVOLUTION_PINCERS)) + grapple_mod = 4; + /* try for reversale? */ if (GRAPPLE_ATTACKER(ch) && GRAPPLE_ATTACKER(ch) == vict && AFF_FLAGGED(ch, AFF_GRAPPLED)) @@ -424,11 +427,8 @@ ACMD(do_free_grapple) /* as a standard action, try to pin grappled opponent */ ACMD(do_pin) { - if (IS_NPC(ch)) - { - send_to_char(ch, "You have no idea how.\r\n"); - return; - } + + if (!can_npc_command(ch)) return; if (GRAPPLE_ATTACKER(ch)) { @@ -501,11 +501,7 @@ ACMD(do_pin) /* as a standard action, try to bind pinned opponent */ ACMD(do_bind) { - if (IS_NPC(ch)) - { - send_to_char(ch, "You have no idea how.\r\n"); - return; - } + if (!can_npc_command(ch)) return; send_to_char(ch, "Under construction.\r\n"); return; } diff --git a/handler.c b/handler.c index 61274768..1150921c 100755 --- a/handler.c +++ b/handler.c @@ -2645,10 +2645,22 @@ struct char_data *get_char_world_vis(struct char_data *ch, char *name, int *numb struct char_data *get_char_vis(struct char_data *ch, char *name, int *number, int where) { + if (where == FIND_CHAR_ROOM) - return get_char_room_vis(ch, name, number); + { + if (get_player_vis(ch, name, number, FIND_CHAR_ROOM) == NULL) + return get_char_room_vis(ch, name, number); + else + return get_player_vis(ch, name, number, FIND_CHAR_ROOM); + + } else if (where == FIND_CHAR_WORLD) - return get_char_world_vis(ch, name, number); + { + if (get_player_vis(ch, name, number, FIND_CHAR_WORLD) == NULL) + return get_char_world_vis(ch, name, number); + else + return get_player_vis(ch, name, number, FIND_CHAR_WORLD); + } else return (NULL); } @@ -2657,6 +2669,10 @@ struct obj_data *get_obj_in_list_vis(struct char_data *ch, char *name, int *numb { struct obj_data *i; int num; + int can_see_inv = false; + + if (ch->carrying == list) + can_see_inv = true; if (!number) { @@ -2669,7 +2685,7 @@ struct obj_data *get_obj_in_list_vis(struct char_data *ch, char *name, int *numb for (i = list; i && *number; i = i->next_content) if (isname(name, i->name)) - if (CAN_SEE_OBJ(ch, i)) + if (CAN_SEE_OBJ(ch, i) || can_see_inv) if (--(*number) == 0) return (i); diff --git a/interpreter.c b/interpreter.c index cabbf496..1d8d3dc6 100755 --- a/interpreter.c +++ b/interpreter.c @@ -497,6 +497,7 @@ cpp_extern const struct command_info cmd_info[] = { /* {"command", "sort_as", minimum_position, *command_pointer, minimum_level, subcmd, ignore_wait, actions_required, {action_cooldowns}, *command_check_pointer},*/ {"kill", "k", POS_FIGHTING, do_kill, 0, 0, FALSE, ACTION_STANDARD, {6, 0}, NULL}, + {"kapaksaliva", "kapaksaliva", POS_FIGHTING, do_kapak_saliva, 0, 0, FALSE, ACTION_SWIFT, {6, 0}, NULL}, {"kick", "ki", POS_FIGHTING, do_process_attack, 1, AA_KICK, FALSE, ACTION_NONE, {6, 0}, can_kick}, {"keycheck", "keycheck", POS_STANDING, do_keycheck, LVL_IMMORT, 0, TRUE, ACTION_NONE, {0, 0}, NULL}, {"knighthoodsflower", "knighthoodsflower", POS_STANDING, do_knighthoods_flower, 0, 0, TRUE, ACTION_NONE, {0, 0}, NULL}, @@ -714,6 +715,7 @@ cpp_extern const struct command_info cmd_info[] = { {"'", "'", POS_RECLINING, do_say, 0, 0, TRUE, ACTION_NONE, {0, 0}, NULL}, {"save", "sav", POS_SLEEPING, do_save, 0, 0, TRUE, ACTION_NONE, {0, 0}, NULL}, {"saveall", "saveall", POS_DEAD, do_saveall, LVL_BUILDER, 0, TRUE, ACTION_NONE, {0, 0}, NULL}, + {"saveobjstodb", "saveobjstodb", POS_DEAD, do_save_objects_to_database, LVL_IMPL, 0, TRUE, ACTION_NONE, {0, 0}, NULL}, // { "savemobs" , "savemobs" , POS_DEAD , do_savemobs , LVL_IMPL, 0, FALSE, ACTION_NONE, {0, 0}, NULL}, {"search", "sea", POS_STANDING, do_search, 1, 0, FALSE, ACTION_NONE, {0, 0}, NULL}, {"sell", "sell", POS_STANDING, do_not_here, 0, 0, FALSE, ACTION_NONE, {0, 0}, NULL}, diff --git a/limits.c b/limits.c index de7c1ca5..1dc766b0 100755 --- a/limits.c +++ b/limits.c @@ -105,6 +105,24 @@ void room_aff_tick(struct raff_node *raff) } } break; + case ABILITY_KAPAK_DRACONIAN_DEATH_THROES: + caster = read_mobile(DG_CASTER_PROXY, VIRTUAL); + caster_room = &world[raff->room]; + if (!caster) + { + script_log("comm.c: Cannot load the caster mob (kapak acid)!"); + return; + } + + /* set the caster's name */ + caster->player.short_descr = strdup("The room"); + caster->next_in_room = caster_room->people; + caster_room->people = caster; + caster->in_room = real_room(caster_room->number); + call_magic(caster, NULL, NULL, ABILITY_KAPAK_DRACONIAN_DEATH_THROES, 0, DG_SPELL_LEVEL, CAST_SPELL); + extract_char(caster); + break; + case SPELL_BLADE_BARRIER: caster = read_mobile(DG_CASTER_PROXY, VIRTUAL); caster_room = &world[raff->room]; @@ -1002,6 +1020,7 @@ int gain_exp(struct char_data *ch, int gain, int mode) } gain *= leadership_exp_multiplier(ch); + gain /= 100; /* newbie bonus */ if (GET_LEVEL(ch) <= NEWBIE_LEVEL) @@ -1453,6 +1472,15 @@ void proc_d20_round(void) for (i = character_list; i; i = i->next) { + if (GET_KAPAK_SALIVA_HEALING_COOLDOWN(i) > 0) + { + GET_KAPAK_SALIVA_HEALING_COOLDOWN(i)--; + if (GET_KAPAK_SALIVA_HEALING_COOLDOWN(i) == 0) + { + send_to_char(i, "You can now be healed with kapak saliva again.\r\n"); + } + } + if (GET_PUSHED_TIMER(i) > 0) { GET_PUSHED_TIMER(i)--; @@ -1826,7 +1854,8 @@ void point_update(void) else core_dump(); } - extract_obj(j); + if (j) + extract_obj(j); continue; } } diff --git a/magic.c b/magic.c index 42e5d927..c8f98dda 100755 --- a/magic.c +++ b/magic.c @@ -118,6 +118,9 @@ int compute_spell_res(struct char_data *ch, struct char_data *vict, int modifier if (IS_DRAGON(vict)) resist = MAX(resist, 25); + if (HAS_FEAT(vict, FEAT_KAPAK_SPELL_RESISTANCE)) + resist = MAX(resist, 10 + GET_LEVEL(vict)); + // adjustments passed to mag_resistance resist += modifier; @@ -986,6 +989,7 @@ int mag_damage(int level, struct char_data *ch, struct char_data *victim, case POISON_TYPE_WASP_WEAK: case POISON_TYPE_FUNGAL_WEAK: case POISON_TYPE_COCKATRICE: + case POISON_TYPE_KAPAK: if (!can_poison(victim)) return 0; save = SAVING_FORT; @@ -2127,13 +2131,19 @@ int mag_damage(int level, struct char_data *ch, struct char_data *victim, break; case SPELL_ACID: // acid fog (conjuration) + if (is_flying(victim) || AFF_FLAGGED(victim, AFF_LEVITATE)) + { + act("You avoid being burned by the pool of acid as you are not touching the ground.", TRUE, victim, 0, 0, TO_CHAR); + act("$n avoids being burned by the pool of acid as $e is not touching the ground.", TRUE, victim, 0, 0, TO_ROOM); + return (0); + } // AoE save = SAVING_FORT; mag_resist = TRUE; element = DAM_ACID; - num_dice = MAX(6, level); - size_dice = 2; - bonus = 10; + num_dice = 2; + size_dice = 10; + bonus = 5; break; case SPELL_CHAIN_LIGHTNING: // evocation @@ -3194,6 +3204,21 @@ void mag_affects(int level, struct char_data *ch, struct char_data *victim, accum_duration = TRUE; break; + case POISON_TYPE_KAPAK: + if (!can_poison(victim) || mag_savingthrow_full(ch, victim, SAVING_FORT, 0, casttype, level, ENCHANTMENT, spellnum)) + { + return; + } + af[0].location = APPLY_DEX; + af[0].duration = 10; + if (KNOWS_DISCOVERY(ch, ALC_DISC_MALIGNANT_POISON)) + af[0].duration *= 1.5; + af[0].modifier = -(dice(1, 6)); + to_vict = "You feel very sick."; + to_room = "$n gets violently ill!"; + accum_duration = TRUE; + break; + // misc case SPELL_MINOR_RAPID_BUFF: @@ -7560,8 +7585,8 @@ void mag_affects(int level, struct char_data *ch, struct char_data *victim, af[0].modifier = 2; af[0].duration = 300; af[0].bonus_type = BONUS_TYPE_SHIELD; - to_vict = "You feel someone protecting you."; - to_room = "$n is surrounded by magical armor!"; + to_vict = "A magical shield of force appears in front of you."; + to_room = "A magical shield of force appears in front of $n."; break; case SPELL_SHRINK_PERSON: // transmutation @@ -8720,6 +8745,9 @@ void mag_masses(int level, struct char_data *ch, struct obj_data *obj, case SPELL_ACID: isDamage = true; break; + case ABILITY_KAPAK_ACID: + isDamage = true; + break; case SPELL_BLADES: isDamage = true; break; @@ -11476,6 +11504,13 @@ void mag_room(int level, struct char_data *ch, struct obj_data *obj, aff = RAFF_ACID_FOG; rounds = MAX(4, MAGIC_LEVEL(ch)); break; + + case ABILITY_KAPAK_DRACONIAN_DEATH_THROES: // conjuration + to_char = "You dissolve into a pool of acid!"; + to_room = "$n dissolves into a pool of acid!"; + aff = RAFF_KAPAK_ACID; + rounds = dice(2, 4); + break; case SPELL_ANTI_MAGIC_FIELD: // illusion to_char = "You create an anti-magic field!"; diff --git a/players.c b/players.c index 4158c82f..927c00e3 100755 --- a/players.c +++ b/players.c @@ -524,6 +524,7 @@ int load_char(const char *name, struct char_data *ch) CASTING_SPELLNUM(ch) = 0; CASTING_METAMAGIC(ch) = 0; CASTING_CLASS(ch) = 0; + GET_KAPAK_SALIVA_HEALING_COOLDOWN(ch) = 0; for (i = 0; i < MAX_BUFFS; i++) { GET_BUFF(ch, i, 0) = 0; @@ -948,6 +949,8 @@ int load_char(const char *name, struct char_data *ch) case 'K': if (!strcmp(tag, "KnSp")) load_known_spells(fl, ch); + else if (!strcmp(tag, "KpkS")) + GET_KAPAK_SALIVA_HEALING_COOLDOWN(ch) = atoi(line); else if (!strcmp(tag, "KEvo")) load_known_evolutions(fl, ch); break; @@ -1864,6 +1867,8 @@ void save_char(struct char_data *ch, int mode) fprintf(fl, "Slyr: %d\n", GET_SLAYER_JUDGEMENT(ch)); if (GET_BANE_TARGET_TYPE(ch) != 0) fprintf(fl, "Bane: %d\n", GET_BANE_TARGET_TYPE(ch)); + if (GET_KAPAK_SALIVA_HEALING_COOLDOWN(ch) != 0) + fprintf(fl, "KpkS: %d\n", GET_KAPAK_SALIVA_HEALING_COOLDOWN(ch)); if (SCRIPT(ch)) { for (t = TRIGGERS(SCRIPT(ch)); t; t = t->next) diff --git a/race.c b/race.c index f0c35617..d2d5f868 100755 --- a/race.c +++ b/race.c @@ -1097,13 +1097,69 @@ void assign_races(void) feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_ULTRAVISION, 1, N); feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_BAAZ_DEATH_THROES, 1, N); feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_DRACONIAN_CONTROLLED_FALL, 1, N); - feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_BAAZ_DRACONIC_DEVOTION, 1, N); + feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_DRACONIC_DEVOTION, 1, N); feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_DRACONIAN_GALLOP, 1, N); - feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_BAAZ_DISEASE_IMMUNITY, 1, N); + feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_DRACONIAN_DISEASE_IMMUNITY, 1, N); feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_BAAZ_DRACONIAN_SCALES, 1, N); feat_race_assignment(DL_RACE_BAAZ_DRACONIAN, FEAT_DRACONIAN_BITE, 1, N); race_list[DL_RACE_BAAZ_DRACONIAN].racial_language = SKILL_LANG_DRACONIC; + /****************************************************************************/ + /****************************************************************************/ + /* simple-name, no-color-name, color-name, abbrev, color-abbrev*/ + add_race(DL_RACE_KAPAK_DRACONIAN, "kapak draconian", "Kapak Draconian", "\tWKapak Draconian\tn", "Kapk", "\tWKapk\tn", + /* race-family, size-class, Is PC?, Lvl-Adj, Unlock, Epic? */ + RACE_TYPE_HUMANOID, SIZE_MEDIUM, TRUE, 2, 5000, IS_ADVANCE); + set_race_details(DL_RACE_KAPAK_DRACONIAN, + // desc + "Kapak draconians are known for stealth, vicious" + "cunning, and for licking their blades with their" + "venom-soaked tongues before battle. While not" + "known for original thinking, kapaks exhibit cruel" + "creativity in carrying out assigned missions of" + "espionage and murder. Kapaks like structure in their" + "lives, and the military lifestyle suits them. Their" + "natural talents for stealth and butchery belie their" + "need for order. Many become assassins, because" + "they are adept at handling dangerous and constantly" + "changing situations. Female kapaks also" + "like structure, but they tend to be more nurturing," + "using their inborn healing abilities to aid" + "other draconians. Kapaks are larger" + "and more draconic than baaz, with elongated" + "reptilian snouts, sharp-toothed maws, and" + "horned heads. They possess two large glands in" + "their mouths that produce either poison (males)" + "or a magical healing saliva (females). They have" + "scaly, green-tinged coppery hide, and sport a" + "pair of wings that extend 6 feet to each side" + "when outstretched.", + /*morph to-char*/ "Your body twists and contorts painfully until your form becomes a Kapak Draconian.", + /*morph to-room*/ "$n's body twists and contorts painfully until $s form becomes a Kapak Draconian."); + set_race_abilities(DL_RACE_KAPAK_DRACONIAN, 0, 2, 0, 0, 4, 0); /* str con int wis dex cha */ + set_race_alignments(DL_RACE_KAPAK_DRACONIAN, Y, Y, Y, Y, Y, Y, Y, Y, Y); /* law-good -> cha-evil */ + set_race_attack_types(DL_RACE_KAPAK_DRACONIAN, + /* hit sting whip slash bite bludgeon crush pound claw maul thrash pierce */ + Y, N, N, N, N, N, N, N, N, N, N, N, + /* blast punch stab slice thrust hack rake peck smash trample charge gore */ + N, N, N, N, N, N, N, N, N, N, N, N); + /* feat assignment */ + /* race-num feat lvl stack */ + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_ULTRAVISION, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_KAPAK_DEATH_THROES, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_DRACONIAN_CONTROLLED_FALL, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_DRACONIC_DEVOTION, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_DRACONIAN_GALLOP, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_DRACONIAN_DISEASE_IMMUNITY, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_KAPAK_DRACONIAN_SCALES, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_DRACONIAN_BITE, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_KAPAK_SALIVA, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_SNEAK_ATTACK, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_APPLY_POISON, 1, N); + feat_race_assignment(DL_RACE_KAPAK_DRACONIAN, FEAT_KAPAK_SPELL_RESISTANCE, 1, N); + + race_list[DL_RACE_BAAZ_DRACONIAN].racial_language = SKILL_LANG_DRACONIC; + /****************************************************************************/ /* simple-name, no-color-name, color-name, abbrev, color-abbrev*/ add_race(RACE_LICH, "lich", "Lich", "\tLLich\tn", "Lich", "\tLLich\tn", @@ -4413,9 +4469,9 @@ int parse_race_long(const char *arg_in) if (is_abbrev(arg, "baazdraconian")) return DL_RACE_BAAZ_DRACONIAN; if (is_abbrev(arg, "goblin")) return DL_RACE_GOBLIN; if (is_abbrev(arg, "hobgoblin")) return DL_RACE_HOBGOBLIN; - // if (is_abbrev(arg, "kapak draconian")) return DL_RACE_KAPAK_DRACONIAN; - // if (is_abbrev(arg, "kapak-draconian")) return DL_RACE_KAPAK_DRACONIAN; - // if (is_abbrev(arg, "kapakdraconian")) return DL_RACE_KAPAK_DRACONIAN; + if (is_abbrev(arg, "kapak draconian")) return DL_RACE_KAPAK_DRACONIAN; + if (is_abbrev(arg, "kapak-draconian")) return DL_RACE_KAPAK_DRACONIAN; + if (is_abbrev(arg, "kapakdraconian")) return DL_RACE_KAPAK_DRACONIAN; // if (is_abbrev(arg, "bozak draconian")) return DL_RACE_BOZAK_DRACONIAN; // if (is_abbrev(arg, "bozak-draconian")) return DL_RACE_BOZAK_DRACONIAN; // if (is_abbrev(arg, "bozakdraconian")) return DL_RACE_BOZAK_DRACONIAN; diff --git a/spell_parser.c b/spell_parser.c index 1066b00b..02911ada 100755 --- a/spell_parser.c +++ b/spell_parser.c @@ -4760,6 +4760,13 @@ void mag_assign_spells(void) TAR_IGNORE, TRUE, MAG_AREAS, NULL, 5, 9, TRANSMUTATION, FALSE); + spello(ABILITY_KAPAK_DRACONIAN_DEATH_THROES, "kapak draconian death throes", 0, 0, 0, POS_FIGHTING, + TAR_IGNORE, FALSE, MAG_ROOM, + "The pool of acid in the room dissolves to nothingness.", 5, 9, TRANSMUTATION, FALSE); + spello(ABILITY_KAPAK_ACID, "!UNUSED!", 79, 64, 1, POS_DEAD, + TAR_IGNORE, TRUE, MAG_MASSES, + NULL, 8, 12, EVOCATION, FALSE); + /* spello(SPELL_IDENTIFY, "!UNUSED!", 0, 0, 0, 0, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, @@ -4896,6 +4903,8 @@ spello(SPELL_IDENTIFY, "!UNUSED!", 0, 0, 0, 0, "The purple worm poison fully passes through your system.", 1, 1, NOSCHOOL, FALSE); spello(POISON_TYPE_COCKATRICE, "cockatrice poison", 1, 1, 1, POS_FIGHTING, TAR_CHAR_ROOM | TAR_NOT_SELF, TRUE, MAG_DAMAGE | MAG_AFFECTS, "The cockatrice poison fully passes through your system.", 1, 1, NOSCHOOL, FALSE); + spello(POISON_TYPE_KAPAK, "kapak draconian poison", 1, 1, 1, POS_FIGHTING, TAR_CHAR_ROOM | TAR_NOT_SELF, TRUE, MAG_DAMAGE | MAG_AFFECTS, + "The kapak draconian poison fully passes through your system.", 1, 1, NOSCHOOL, FALSE); spello(ABILITY_PARALYZING_TOUCH, "paralyzing touch", 0, 0, 0, POS_FIGHTING, TAR_CHAR_ROOM | TAR_NOT_SELF, TRUE, MAG_AFFECTS, "Your paralysis subsides.", 0, 1, NECROMANCY, FALSE); diff --git a/spells.h b/spells.h index a22a41a4..fc8aa7f4 100755 --- a/spells.h +++ b/spells.h @@ -672,6 +672,9 @@ #define AFFECT_FINAL_STAND 1270 #define AFFECT_KNIGHTHOODS_FLOWER 1271 #define AFFECT_INSPIRE_GREATNESS 1272 +#define ABILITY_KAPAK_DRACONIAN_DEATH_THROES 1273 +#define ABILITY_KAPAK_ACID 1274 + // 1470 to 1493 are poisons with room saved for more poisons up to 1498 @@ -700,7 +703,8 @@ #define POISON_TYPE_WYVERN 1491 #define POISON_TYPE_PURPLE_WORM 1492 #define POISON_TYPE_COCKATRICE 1493 -#define POISON_TYPE_END 1493 +#define POISON_TYPE_KAPAK 1494 +#define POISON_TYPE_END 1494 /** we're going to start psionic powers at 1500. * most psionic stuff is either in psionics.c or spell_parser.c diff --git a/structs.h b/structs.h index 0b7a7271..0362c728 100755 --- a/structs.h +++ b/structs.h @@ -230,8 +230,9 @@ #define RAFF_OBSCURING_MIST (1 << 12) #define RAFF_DIFFICULT_TERRAIN (1 << 13) #define RAFF_SACRED_SPACE (1 << 14) +#define RAFF_KAPAK_ACID (1 << 15) /** The total number of Room Affections */ -#define NUM_RAFF 15 +#define NUM_RAFF 16 /* Zone info: Used in zone_data.zone_flags */ #define ZONE_CLOSED 0 /**< Zone is closed - players cannot enter */ @@ -1142,6 +1143,8 @@ #endif +#define OBJ_VNUM_KAPAK_POISON 20872 + /**********************/ /* misc defines */ #define SHAPE_AFFECTS 3 @@ -2585,9 +2588,9 @@ #define FEAT_MINOTAUR_GORE 1026 #define FEAT_BAAZ_DEATH_THROES 1027 // not coded yet #define FEAT_DRACONIAN_CONTROLLED_FALL 1028 -#define FEAT_BAAZ_DRACONIC_DEVOTION 1029 +#define FEAT_DRACONIC_DEVOTION 1029 #define FEAT_DRACONIAN_GALLOP 1030 -#define FEAT_BAAZ_DISEASE_IMMUNITY 1031 +#define FEAT_DRACONIAN_DISEASE_IMMUNITY 1031 #define FEAT_BAAZ_DRACONIAN_SCALES 1032 #define FEAT_DRACONIAN_BITE 1033 #define FEAT_DEATHLESS_VIGOR 1034 @@ -2637,12 +2640,17 @@ #define FEAT_WISDOM_OF_THE_MEASURE 1075 #define FEAT_FINAL_STAND 1076 #define FEAT_KNIGHTHOODS_FLOWER 1077 +// Kapak Draconians +#define FEAT_KAPAK_DEATH_THROES 1078 +#define FEAT_KAPAK_DRACONIAN_SCALES 1079 +#define FEAT_KAPAK_SALIVA 1080 +#define FEAT_KAPAK_SPELL_RESISTANCE 1081 /**************/ /** reserved above feat# + 1**/ -#define FEAT_LAST_FEAT 1078 +#define FEAT_LAST_FEAT 1082 /** FEAT_LAST_FEAT + 1 ***/ -#define NUM_FEATS 1079 +#define NUM_FEATS 1083 /** absolute cap **/ #define MAX_FEATS 1500 /*****/ @@ -4329,6 +4337,8 @@ struct char_special_data_saved int eidolon_evolutions[NUM_EVOLUTIONS]; //active eidolon evolutions int known_evolutions[NUM_EVOLUTIONS]; // known eidolon evolutions int eidolon_base_form; // Eidolon base form determines their starting stats and evolutions + + int kapak_healing_cooldown; // number of ticks before able to benefit from kapak healing saliva }; /* not saved player data used for condensed combat */ diff --git a/utils.c b/utils.c index 12831268..1429995f 100755 --- a/utils.c +++ b/utils.c @@ -5406,9 +5406,9 @@ bool has_aura_of_courage(struct char_data *ch) return has_aura; } -float leadership_exp_multiplier(struct char_data *ch) +int leadership_exp_multiplier(struct char_data *ch) { - float exp_mult = 100.00; + int exp_mult = 100; if (!ch) return exp_mult; @@ -5425,7 +5425,7 @@ float leadership_exp_multiplier(struct char_data *ch) continue; if (HAS_FEAT(tch, FEAT_LEADERSHIP)) { - exp_mult = (float) MAX((int) exp_mult, 100 + ((HAS_FEAT(tch, FEAT_LEADERSHIP) + 1) * 5)); + exp_mult = MAX(exp_mult, 100 + ((HAS_FEAT(tch, FEAT_LEADERSHIP) + 1) * 5)); } } remove_iterator(&Iterator); @@ -5515,6 +5515,9 @@ void perform_draconian_death_throes(struct char_data *ch) case DL_RACE_BAAZ_DRACONIAN: call_magic(ch, 0, 0, ABILITY_BAAZ_DRACONIAN_DEATH_THROES, 0, GET_LEVEL(ch), CAST_INNATE); return; + case DL_RACE_KAPAK_DRACONIAN: + call_magic(ch, 0, 0, ABILITY_KAPAK_DRACONIAN_DEATH_THROES, 0, GET_LEVEL(ch), CAST_INNATE); + return; } } @@ -6526,14 +6529,14 @@ bool can_disease(struct char_data *ch) return false; if (HAS_FEAT(ch, FEAT_PLAGUE_BRINGER)) return false; + if (HAS_FEAT(ch, FEAT_DRACONIAN_DISEASE_IMMUNITY)) + return false; if (IS_CONSTRUCT(ch)) return false; if (IS_UNDEAD(ch)) return false; if (HAS_EVOLUTION(ch, EVOLUTION_CELESTIAL_APPEARANCE) && get_evolution_appearance_save_bonus(ch) == 100) return false; - if (HAS_FEAT(ch, FEAT_BAAZ_DISEASE_IMMUNITY)) - return false; return true; } @@ -7882,6 +7885,7 @@ bool is_poison_spell(int spell) case POISON_TYPE_WYVERN: case POISON_TYPE_PURPLE_WORM: case POISON_TYPE_COCKATRICE: + case POISON_TYPE_KAPAK: case SPELL_POISON: case WEAPON_POISON_BLACK_ADDER_VENOM: case SPELL_POISON_BREATHE: @@ -9144,4 +9148,18 @@ int min_dice(int num, int size, int min) return amount; } +bool can_npc_command(struct char_data *ch) +{ + +#if !defined(CAMPAIGN_DL) + if (IS_NPC(ch)) + { + send_to_char(ch, "You have no idea how.\r\n"); + return FALSE; + } +#endif + + return TRUE; +} + /* EoF */ diff --git a/utils.h b/utils.h index 80b7062c..c15153a1 100755 --- a/utils.h +++ b/utils.h @@ -133,6 +133,7 @@ bool can_study_known_spells(struct char_data *ch); bool can_study_known_psionics(struct char_data *ch); int compute_bonus_caster_level(struct char_data *ch, int class); int compute_arcane_level(struct char_data *ch); +bool can_npc_command(struct char_data *ch); int compute_divine_level(struct char_data *ch); bool compute_has_combat_feat(struct char_data *ch, int cfeat, int weapon); int compute_dexterity_bonus(struct char_data *ch); @@ -266,7 +267,7 @@ int file_head(FILE *file, char *buf, size_t bufsize, int lines_to_read); int file_tail(FILE *file, char *buf, size_t bufsize, int lines_to_read); size_t file_sizeof(FILE *file); int file_numlines(FILE *file); -float leadership_exp_multiplier(struct char_data *ch); +int leadership_exp_multiplier(struct char_data *ch); void clear_misc_cooldowns(struct char_data *ch); IDXTYPE atoidx(const char *str_to_conv); char *strfrmt(char *str, int w, int h, int justify, int hpad, int vpad); @@ -2579,6 +2580,8 @@ bool has_reach(struct char_data *ch); #define IS_DRAGONBONE(material) (material == MATERIAL_DRAGONBONE) #define IS_DRAGON_CRAFT_MATERIAL(material) (IS_DRAGONHIDE(material) || IS_DRAGONSCALE(material) || IS_DRAGONBONE(material)) +#define GET_KAPAK_SALIVA_HEALING_COOLDOWN(ch) (ch->char_specials.saved.kapak_healing_cooldown) + #endif /* _UTILS_H_ */ /*EOF*/