Add throwable alchemist vials support
parent
fc24270545
commit
198f3e83b1
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
30
lib/formulae
30
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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... */
|
||||
|
|
Loading…
Reference in New Issue