From 198f3e83b147259e9e7d7c909655c34dee21f5ea Mon Sep 17 00:00:00 2001 From: "kts of kettek (nyaa)" Date: Fri, 29 Jun 2018 17:56:58 -0700 Subject: [PATCH] Add throwable alchemist vials support --- common/item.c | 5 ++++- include/spells.h | 1 + include/sproto.h | 1 + lib/formulae | 30 ++++++++++++++++++++++++++++++ server/alchemy.c | 9 +++++++-- server/apply.c | 8 ++++++++ server/attack.c | 24 +++++++++++++++++++++++- server/player.c | 2 ++ server/skills.c | 4 +++- server/spell_attack.c | 18 +++++++++++++++--- server/spell_util.c | 19 ++++++++++++++++++- types/potion/potion.c | 13 +++++++++++-- 12 files changed, 123 insertions(+), 11 deletions(-) diff --git a/common/item.c b/common/item.c index bd79b01..6b0233d 100644 --- a/common/item.c +++ b/common/item.c @@ -579,6 +579,7 @@ void query_short_name(const object *op, char *buf, size_t size) { case SCROLL: case WAND: case ROD: + case POTION: if (QUERY_FLAG(op, FLAG_IDENTIFIED)||QUERY_FLAG(op, FLAG_BEEN_APPLIED)) { if (!op->title) { safe_strcat(buf, " of ", &len, size); @@ -784,6 +785,7 @@ void query_base_name(const object *op, int plural, char *buf, size_t size) { case SCROLL: case WAND: case ROD: + case POTION: if (QUERY_FLAG(op, FLAG_IDENTIFIED)||QUERY_FLAG(op, FLAG_BEEN_APPLIED)) { if (!op->title) { safe_strcat(buf, " of ", &len, size); @@ -1471,7 +1473,8 @@ void identify(object *op) { if (QUERY_FLAG(op, FLAG_BLESSED)) SET_FLAG(op, FLAG_KNOWN_BLESSED); - if (op->type == POTION) { + /* we ignore POT_THROW since those have levels assigned */ + if (op->type == POTION && op->subtype != POT_THROW) { if (op->inv && op->randomitems) { if (op->title) free_string(op->title); diff --git a/include/spells.h b/include/spells.h index b7d8b7d..48f1fb7 100644 --- a/include/spells.h +++ b/include/spells.h @@ -160,6 +160,7 @@ extern const char *const spellpathnames[NRSPELLPATHS]; #define POT_DUST 2 #define POT_FIGURINE 3 #define POT_BALM 4 +#define POT_THROW 5 /*@}*/ /** diff --git a/include/sproto.h b/include/sproto.h index 4e4ea26..664d66f 100644 --- a/include/sproto.h +++ b/include/sproto.h @@ -529,6 +529,7 @@ int pray(object *pl, object *skill); void meditate(object *pl, object *skill); int write_on_item(object *pl, const char *params, object *skill); int skill_throw(object *op, object *part, int dir, const char *params, object *skill); +int do_throw(object *op, object *part, object *toss_item, int dir, object *skill); /* skill_util.c */ void init_skills(void); void link_player_skills(object *op); diff --git a/lib/formulae b/lib/formulae index 4f39996..0c5e69a 100644 --- a/lib/formulae +++ b/lib/formulae @@ -1052,7 +1052,37 @@ cauldron cauldron ingred booze,balm of first aid,red rose # # -- attack potion. Drinker/target is effected adversely +# -- @@ new vials of throwing that are probably better than anything below +Object NONE +arch vial_burning_hands +chance 4 +diff 2 +exp 250 +yield 1 +skill alchemy +cauldron cauldron +ingred empty vial,pile of cinnabar,pile of salt,pile of phosphorus,pile of sulphur # +Object NONE +arch vial_explosion +chance 4 +diff 3 +exp 350 +yield 1 +skill alchemy +cauldron cauldron +ingred empty vial,pile of salt,pile of phosphorus,pile of sulphur +# +Object NONE +arch vial_sparkshower +chance 4 +diff 1 +exp 150 +yield 1 +skill alchemy +cauldron cauldron +ingred empty vial,pile of pyrite,pile of salt,pile of phosphorus,pile of sulphur +# -- old stuff # -- sm. lightning Object electric shock arch potion_generic diff --git a/server/alchemy.c b/server/alchemy.c index c7fde37..fba16d3 100644 --- a/server/alchemy.c +++ b/server/alchemy.c @@ -194,7 +194,7 @@ static void attempt_do_alchemy(object *caster, object *cauldron) { /* create the object **FIRST**, then decide whether to keep it. */ if ((item = attempt_recipe(caster, cauldron, ability, rp, formula/rp->index, attempt_shadow_alchemy)) != NULL) { /* compute base chance of recipe success */ - success_chance = ((float)ability/(float)(rp->diff*(item->level+2))); + success_chance = ((float)(ability*2)/(float)(rp->diff*(item->level+2))); if (ave_chance == 0) ave_chance = 1; @@ -344,7 +344,7 @@ static object *attempt_recipe(object *caster, object *cauldron, int ability, rec if ((item = make_item_from_recipe(cauldron, rp)) != NULL) { remove_contents(cauldron->inv, item); - /* adj lvl, nrof on caster level */ + /* adj lvl, nrof, and enhancement on caster level */ adjust_product(item, ability, rp->yield ? (rp->yield*batches) : batches); if (!item->env && (item = insert_ob_in_ob(item, cauldron)) == NULL) { draw_ext_info(NDI_UNIQUE, 0, caster, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, @@ -383,6 +383,11 @@ static void adjust_product(object *item, int lvl, int yield) { nrof = yield; item->nrof = nrof; } + // @@ We're also adding the player's level to the item so that potions and similar can level over time. + if (item->type == POTION && item->subtype == POT_THROW) { + LOG(llevError, "making alchemy with %d\n", lvl); + item->level = lvl; + } } /** diff --git a/server/apply.c b/server/apply.c index f58c9dc..904b1c8 100644 --- a/server/apply.c +++ b/server/apply.c @@ -1835,6 +1835,14 @@ void apply_changes_to_player(object *pl, object *change) { pl->slaying = join_strings(pl->slaying, change->slaying, ","); } + /* modify the player's attunement */ + if (change->path_attuned) { + if (pl->path_attuned) + pl->path_attuned |= change->path_attuned; + else + pl->path_attuned = change->path_attuned; + } + /* set up the face, for some races. */ /* first, look for the force object banning changing the diff --git a/server/attack.c b/server/attack.c index 5ac1aae..e311dcd 100644 --- a/server/attack.c +++ b/server/attack.c @@ -741,6 +741,7 @@ static int abort_attack(object *target, object *hitter, int simple_attack) { } static void thrown_item_effect(object *, object *); +static void thrown_potion_effect(object *); /** * Handles simple attack cases. @@ -2435,8 +2436,10 @@ static void thrown_item_effect(object *hitter, object *victim) { */ switch (hitter->type) { case POTION: + if (hitter->subtype == POT_THROW) { + thrown_potion_effect(hitter); /* should player get a save throw instead of checking magic protection? */ - if (QUERY_FLAG(victim, FLAG_ALIVE) + } else if (QUERY_FLAG(victim, FLAG_ALIVE) && !QUERY_FLAG(victim, FLAG_UNDEAD) && (victim->resist[ATNR_MAGIC] < 60)) (void)ob_apply(hitter, victim, 0); @@ -2459,6 +2462,25 @@ static void thrown_item_effect(object *hitter, object *victim) { } } +static void thrown_potion_effect(object *throw_ob) { + LOG(llevError, "OKAY, HERE IS POTION EFFECT\n"); + object *op, *spob; + + spob = throw_ob->inv; + op = get_owner(throw_ob); + if (op->type == PLAYER && spob) + draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS, + "Your vial releases %s.", + "Your vial releases %s.", + spob->name); + + cast_spell(op, throw_ob, throw_ob->direction, spob, NULL); + + if (!QUERY_FLAG(throw_ob, FLAG_REMOVED)) + remove_ob(throw_ob); + free_object(throw_ob); +} + /** * Adjustments to attack rolls by various conditions * @param hitter diff --git a/server/player.c b/server/player.c index d31211b..c898d5a 100644 --- a/server/player.c +++ b/server/player.c @@ -758,6 +758,8 @@ void give_initial_items(object *pl, treasurelist *items) { SET_FLAG(op, FLAG_CAN_USE_SKILL); op->stats.exp = 0; op->level = 1; + } else if (op->type == POTION && op->subtype == POT_THROW) { + /* don't lock, etc. */ } /* lock all 'normal items by default */ else diff --git a/server/skills.c b/server/skills.c index 17b4edb..899eef5 100644 --- a/server/skills.c +++ b/server/skills.c @@ -1903,7 +1903,7 @@ static object *make_throw_ob(object *orig) { * skill was successfully used. * @todo this messy function should probably be simplified. */ -static int do_throw(object *op, object *part, object *toss_item, int dir, object *skill) { +int do_throw(object *op, object *part, object *toss_item, int dir, object *skill) { object *throw_ob = toss_item, *left = NULL; tag_t left_tag; int eff_str = 0, maxc, str = op->stats.Str, dam = 0; @@ -2027,6 +2027,8 @@ static int do_throw(object *op, object *part, object *toss_item, int dir, object return 1; } + /* record the direction it was thrown in */ + throw_ob->direction = dir; /* Make a thrown object -- insert real object in a 'carrier' object. * If unsuccessfull at making the "thrown_obj", we just reinsert * the original object back into inventory and exit diff --git a/server/spell_attack.c b/server/spell_attack.c index 05faa39..d157102 100644 --- a/server/spell_attack.c +++ b/server/spell_attack.c @@ -454,16 +454,28 @@ int cast_cone(object *op, object *caster, int dir, object *spell) { continue; } - x = op->x+freearr_x[d]; - y = op->y+freearr_y[d]; + /* Special handling for making the spell emit from a thrown + * potion's location + */ + if (caster->type == POTION && caster->subtype == POT_THROW) { + x = caster->x+freearr_x[d]; + y = caster->y+freearr_y[d]; - if (get_map_flags(op->map, &m, x, y, &sx, &sy)&P_OUT_OF_MAP) + if (get_map_flags(caster->map, &m, x, y, &sx, &sy)&P_OUT_OF_MAP) continue; + } else { + x = op->x+freearr_x[d]; + y = op->y+freearr_y[d]; + if (get_map_flags(op->map, &m, x, y, &sx, &sy)&P_OUT_OF_MAP) + continue; + } + if ((movetype&GET_MAP_MOVE_BLOCK(m, sx, sy)) == movetype) continue; success = 1; + tmp = arch_to_object(spell->other_arch); set_owner(tmp, op); set_spell_skill(op, caster, spell, tmp); diff --git a/server/spell_util.c b/server/spell_util.c index e7505b8..26d5889 100644 --- a/server/spell_util.c +++ b/server/spell_util.c @@ -333,6 +333,11 @@ int SP_level_dam_adjust(const object *caster, const object *spob) { int level = caster_level(caster, spob); int adj = level-min_casting_level(caster, spob); + /* do 25% more damage with thrown potions */ + if (caster->type == POTION && caster->subtype == POT_THROW) { + adj *= 1.25f; + } + if (adj < 0) adj = 0; if (spob->dam_modifier) @@ -358,6 +363,11 @@ int SP_level_duration_adjust(const object *caster, const object *spob) { int level = caster_level(caster, spob); int adj = level-min_casting_level(caster, spob); + /* last 50% longer with thrown potions */ + if (caster->type == POTION && caster->subtype == POT_THROW) { + adj *= 1.50f; + } + if (adj < 0) adj = 0; if (spob->duration_modifier) @@ -384,6 +394,11 @@ int SP_level_range_adjust(const object *caster, const object *spob) { int level = caster_level(caster, spob); int adj = level-min_casting_level(caster, spob); + /* go -25% further with thrown potions */ + if (caster->type == POTION && caster->subtype == POT_THROW) { + adj *= .75f; + } + if (adj < 0) adj = 0; if (spob->range_modifier) @@ -1525,7 +1540,6 @@ int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stri } else if (caster->type == WAND || caster->type == HORN || caster->type == ROD - || caster->type == POTION || caster->type == SCROLL) { op->speed_left -= 2*FABS(op->speed); } @@ -1568,6 +1582,9 @@ int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stri skill = find_skill_by_name(owner, caster->skill); } + if (caster->type == POTION && caster->subtype == POT_THROW) { + } + if (confusion_effect) { /* If we get here, the confusion effect was 'random effect', so do it and bail out. */ draw_ext_info_format(NDI_UNIQUE, 0, op, diff --git a/types/potion/potion.c b/types/potion/potion.c index f2a631f..8ff253b 100644 --- a/types/potion/potion.c +++ b/types/potion/potion.c @@ -171,8 +171,17 @@ static method_ret potion_type_apply(ob_methods *context, object *potion, fball->x = applier->x; fball->y = applier->y; insert_ob_in_map(fball, applier->map, NULL, 0); - } else - cast_spell(applier, potion, applier->facing, potion->inv, NULL); + } else if (potion->subtype == POT_THROW) { + /* FIXME: This doesn't really work. We want vials to automatically + * be thrown when the player applies them. + */ + object* skop = find_skill_by_name(applier, skill_names[SK_THROWING]); + if (skop) { + do_throw(applier, applier, potion, applier->direction, skop); + } + } else { + cast_spell(applier, potion, potion->direction, potion->inv, NULL); + } decrease_ob(potion); /* if youre dead, no point in doing this... */